/**
 * @file tpl_machine_arm_generic.c
 *
 * @section descr File description
 *
 * common routines and variables for generic ARM platform
 *
 * @section copyright Copyright
 *
 * Trampoline OS
 *
 * Trampoline is copyright (c) IRCCyN 2005+
 * Copyright ESEO for function and data structures documentation and ARM port
 * Trampoline is protected by the French intellectual property law.
 *
 * This software is distributed under the Lesser GNU Public Licence
 *
 * @section infos File informations
 *
 * $Date$
 * $Rev$
 * $Author$
 * $URL$
 */
#include "tpl_machine.h"
#include "tpl_machine_interface.h"
#include "tpl_os_application_def.h"
#include "tpl_os_definitions.h"
#include "tpl_os.h"
#include "tpl_os_timeobj_kernel.h"

#if WITH_AUTOSAR == YES
#include "tpl_as_definitions.h"
#endif
#include "tpl_os_interrupt.h"

#define ARM_MAX_CMD_STR_SIZE	256

#define OS_START_SEC_VAR_UNSPECIFIED
#include "tpl_memmap.h"
/**
 * Stack for the idle task
 */
VAR(tpl_stack_word, OS_VAR) idle_stack[SIZE_OF_IDLE_STACK/sizeof(tpl_stack_word)];

/**
 * Context for the idle task
 */
VAR (arm_context, OS_VAR) idle_task_context;

/**
 * Kernel entry counter
 */
volatile VAR (uint32, OS_VAR) nested_kernel_entrance_counter;
#define OS_STOP_SEC_VAR_UNSPECIFIED
#include "tpl_memmap.h"

#define API_START_SEC_CODE
#include "tpl_memmap.h"

#if TASK_COUNT > 0
extern FUNC(void, OS_CODE) CallTerminateTask(void);
#endif

#if ISR_COUNT > 0
extern FUNC(void, OS_CODE) CallTerminateISR2(void);
#endif

#define API_STOP_SEC_CODE
#include "tpl_memmap.h"

#define OS_START_SEC_CODE
#include "tpl_memmap.h"

FUNC (void, OS_CODE) tpl_init_machine_generic (void)
{
  nested_kernel_entrance_counter = 0;
#if WITH_MEMORY_PROTECTION == YES
  tpl_init_mp();
#endif
  tpl_set_systick_timer();
  // tpl_init_external_interrupts();
}

/*
 * tpl_sleep is used by the idle task
 */
void idle_function(void)
{
  while(1) {
  };
}

/**
 * Call Terminate Task function when no TerminateTask hasn't been called
 * or when TerminateTask didn't success because of resource hold or
 * interrupts disabled.
 *
 */
extern FUNC(void, OS_CODE) CallTerminateTask(void);


/**
 * Call Terminate ISR2 function when TerminateISR didn't success doing it
 * because of resource hold or interrupts disabled.
 *
 */
extern FUNC(void, OS_CODE) CallTerminateISR2(void);

/*
 * As kernel mode is non-interruptible, these function does nothing
 */
FUNC(void, OS_CODE) tpl_get_task_lock (void)
{
}

FUNC(void, OS_CODE) tpl_release_task_lock (void)
{
}

/**
 * Enable interrupts
 */
void tpl_enable_interrupts(void)
{
  /* unlock is scheduled to next switch back to task */
  __asm__
  (
  "mrs r0, spsr ;"
  "bic r0, r0, #0b11000000 ;"
  "msr spsr, r0 ;"
  : : : "r0" // clobbered register
  );

}

/**
 * Disable interrupts
 */
void tpl_disable_interrupts(void)
{

  __asm__
  (
  "mrs r0, cpsr ;"
  "orr r0, r0, #0b11000000 ;"
  "msr cpsr, r0 ;"
  "mrs r0, spsr ;" // interrupts remain locked in user space
  "orr r0, r0, #0b11000000 ;"
  "msr spsr, r0"
  : : : "r0" // clobbered register
  );

}

/*
 * tpl_init_context initialize a context to prepare a task to run.
 * It sets up the stack and the entry point
 */
FUNC(void, OS_CODE) tpl_init_context(
    CONST(tpl_proc_id, OS_APPL_DATA) proc_id)
{
  struct ARM_CONTEXT *core_context;
  const tpl_proc_static *the_proc;

  /* initialize shortcuts */
  the_proc = tpl_stat_proc_table[proc_id];
  core_context = the_proc->context;

  // trace_var((const unsigned char*)"proc_id", (uint32)proc_id);
  // trace_var((const unsigned char*)"the_proc->stack.stack_zone", (uint32)the_proc->stack.stack_zone);
  // trace_var((const unsigned char*)"the_proc->stack.stack_size", (uint32)the_proc->stack.stack_size);
  /* setup entry point */
  core_context->r[armreg_pc] = (uint32)(the_proc->entry);
  /* setup initial stack pointer */
  core_context->r[armreg_sp] = ((uint32)the_proc->stack.stack_zone)
      + the_proc->stack.stack_size;
  /* task runs at a defined processor mode */
  core_context->psr = USER_TASKS_ARM_MODE; /* macro defined into subarch part */

  /*
   * set the return address of the task/isr. This is usefull in case the
   * user forgets to call TerminateTask/TerminateISR
   * MISRA RULE 1,45,85 VIOLATION: the function pointer is used and stored
   * in a 32bits variable, but as the Os is dependant on the target,
   * the behaviour is controled
   */
  core_context->r[armreg_lr] = (IS_ROUTINE == the_proc->type) ?
                                (uint32)(CallTerminateISR2) :
                                (uint32)(CallTerminateTask); /*  lr  */

  // tracecontext(proc_id);
  /* TODO: initialize stack footprint */
}

FUNC(uint8, OS_CODE) tpl_check_stack_footprint (
    CONST(tpl_proc_id, OS_APPL_DATA) proc_id)
{
  uint8 tmp;
  /*to do*/
  tmp=0;
  return tmp;
}

#define OS_STOP_SEC_CODE
#include "tpl_memmap.h"

/* End of file tpl_machine_arm_generic.c */