# HG changeset patch # User Mychaela Falconia # Date 1532065233 0 # Node ID d076885a06693d795d716ad9be062531fa463c5f # Parent 0f466af1eaf0e3d6d20b0ba06d5c3aedb79f3c78 src/nucleus/gcc: initial import from Citrine diff -r 0f466af1eaf0 -r d076885a0669 src/nucleus/gcc/asm_defs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/nucleus/gcc/asm_defs.h Fri Jul 20 05:40:33 2018 +0000 @@ -0,0 +1,88 @@ +/* + ************************************************************************ + * + * Copyright Mentor Graphics Corporation 2002 + * All Rights Reserved. + * + * THIS WORK CONTAINS TRADE SECRET AND PROPRIETARY INFORMATION WHICH IS + * THE PROPERTY OF MENTOR GRAPHICS CORPORATION OR ITS LICENSORS AND IS + * SUBJECT TO LICENSE TERMS. + * + ************************************************************************ + ************************************************************************ + * + * FILE NAME VERSION + * + * asm_defs.inc Nucleus PLUS\ARM925\Code Composer 1.14.1 + * + * COMPONENT + * + * IN - Initialization + * + * DESCRIPTION + * + * This file contains the target processor dependent initialization + * values used in int.s, tct.s, and tmt.s + * + * HISTORY + * + * NAME DATE REMARKS + * + * B. Ronquillo 08-28-2002 Released version 1.13.1 + * + ************************************************************************ + */ + +/* + ********************************** + * BOARD INITIALIZATION CONSTANTS * + ********************************** + * Begin define constants used in low-level initialization. + */ + +/* CPSR control byte definitions */ +#define LOCKOUT 0xC0 /* Interrupt lockout value */ +#define LOCK_MSK 0xC0 /* Interrupt lockout mask value */ +#define MODE_MASK 0x1F /* Processor Mode Mask */ +#define SUP_MODE 0x13 /* Supervisor Mode (SVC) */ +#define IRQ_MODE 0x12 /* Interrupt Mode (IRQ) */ +#define IRQ_MODE_OR_LOCKOUT 0xD2 /* Combined IRQ_MODE OR'ed with */ + /* LOCKOUT */ +#define FIQ_MODE 0x11 /* Fast Interrupt Mode (FIQ) */ +#define IRQ_BIT 0x80 /* Interrupt bit of CPSR and SPSR */ +#define FIQ_BIT 0x40 /* Interrupt bit of CPSR and SPSR */ +#define IRQ_BIT_OR_FIQ_BIT 0xC0 /* IRQ or FIQ interrupt bit of CPSR */ + /* and SPSR */ +#define ABORT_MODE 0x17 +#define UNDEF_MODE 0x1B + +/* + ******************************************** + * TC_TCB and TC_HCB STRUCT OFFSET DEFINES * + ******************************************** + */ +#define TC_CREATED 0x00 /* Node for linking to created task */ + /* list */ +#define TC_ID 0x0C /* Internal TCB ID */ +#define TC_NAME 0x10 /* Task name */ +#define TC_STATUS 0x18 /* Task status */ +#define TC_DELAYED_SUSPEND 0x19 /* Delayed task suspension */ +#define TC_PRIORITY 0x1A /* Task priority */ +#define TC_PREEMPTION 0x1B /* Task preemption enable */ +#define TC_SCHEDULED 0x1C /* Task scheduled count */ +#define TC_CUR_TIME_SLICE 0x20 /* Current time slice */ +#define TC_STACK_START 0x24 /* Stack starting address */ +#define TC_STACK_END 0x28 /* Stack ending address */ +#define TC_STACK_POINTER 0x2C /* Task stack pointer */ +#define TC_STACK_SIZE 0x30 /* Task stack's size */ +#define TC_STACK_MINIMUM 0x34 /* Minimum stack size */ +#define TC_CURRENT_PROTECT 0x38 /* Current protection */ +#define TC_SAVED_STACK_PTR 0x3C /* Previous stack pointer */ +#define TC_ACTIVE_NEXT 0x3C /* Next activated HISR */ +#define TC_TIME_SLICE 0x40 /* Task time slice value */ +#define TC_ACTIVATION_COUNT 0x40 /* Activation counter */ +#define TC_HISR_ENTRY 0x44 /* HISR entry function */ +#define TC_HISR_SU_MODE 0x58 /* Sup/User mode indicator for HISRs */ +#define TC_HISR_MODULE 0x5C /* Module identifier for HISR's */ +#define TC_SU_MODE 0xA8 /* Sup/User mode indicator for Tasks */ +#define TC_MODULE 0xAC /* Module identifier for Tasks */ diff -r 0f466af1eaf0 -r d076885a0669 src/nucleus/gcc/tct.S --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/nucleus/gcc/tct.S Fri Jul 20 05:40:33 2018 +0000 @@ -0,0 +1,3004 @@ +/* + ************************************************************************ + * + * Copyright Mentor Graphics Corporation 2002 + * All Rights Reserved. + * + * THIS WORK CONTAINS TRADE SECRET AND PROPRIETARY INFORMATION WHICH IS + * THE PROPERTY OF MENTOR GRAPHICS CORPORATION OR ITS LICENSORS AND IS + * SUBJECT TO LICENSE TERMS. + * + ************************************************************************ + ************************************************************************ + * + * FILE NAME VERSION + * + * tct.s Nucleus PLUS\ARM925\Code Composer 1.14.1 + * + * COMPONENT + * + * TC - Thread Control + * + * DESCRIPTION + * + * This file contains the target processor dependent routines for + * performing target-dependent scheduling functions. + * + * FUNCTIONS + * + * TCT_Control_Interrupts Enable / disable interrupts + * by changing + * TCD_Interrupt_Level + * TCT_Local_Control_Interrupts Enable/disable interrupts + * by not changing + * TCD_Interrupt_Level + * TCT_Restore_Interrupts Restores interrupts to the + * level in TCD_Interrupt_Level + * TCT_Build_Task_Stack Build initial task stack + * TCT_Build_HISR_Stack Build initial HISR stack + * TCT_Build_Signal_Frame Build signal handler frame + * TCT_Check_Stack Check current stack + * TCT_Schedule Schedule the next thread + * TCT_Control_To_Thread Transfer control to a thread + * TCT_Control_To_System Transfer control from thread + * TCT_Signal_Exit Exit from signal handler + * TCT_Current_Thread Returns a pointer to current + * thread + * TCT_Set_Execute_Task Sets TCD_Execute_Task under + * protection from interrupts + * TCT_Protect Protect critical section + * TCT_Unprotect Unprotect critical section + * TCT_Unprotect_Specific Release specific protection + * TCT_Set_Current_Protect Set the thread's current + * protection field + * TCT_Protect_Switch Switch to protected thread + * TCT_Schedule_Protected Schedule the protected thread + * TCT_Interrupt_Context_Save Save interrupted context + * TCT_Interrupt_Context_Restore Restore interrupted context + * TCT_Activate_HISR Activate a HISR + * TCT_HISR_Shell HISR execution shell + * + * DEPENDENCIES + * + * cs_extr.h Common Service functions + * tc_extr.h Thread Control functions + * + * HISTORY + * + * NAME DATE REMARKS + * + * B. Ronquillo 08-28-2002 Released version 1.14.1 + * + ************************************************************************ + */ + +#define NU_SOURCE_FILE + +/* + ****************************** + * INCLUDE ASSEMBLY CONSTANTS * + ****************************** + * Define constants used in low-level initialization. + */ + +#include "asm_defs.h" +#include "../include/config.h" + + .code 32 + +/* TCT_System_Limit is a global variable defined in this module */ + + .comm TCT_System_Limit,4,4 + + .text + +/* + ********************************** + * LOCAL VARIABLE DECLARATIONS * + ********************************** + * Define pointers to system variables so their addresses may be obtained in a + * pc-relative manner. + */ + +System_Limit: + .word TCT_System_Limit + +Int_Level: + .word TCD_Interrupt_Level + +Task_Shell: + .word TCC_Task_Shell + +HISR_Shell: + .word TCT_HISR_Shell + +Signal_Shell: + .word TCC_Signal_Shell + +Current_Thread: + .word TCD_Current_Thread + +Execute_HISR: + .word TCD_Execute_HISR + +Execute_Task: + .word TCD_Execute_Task + +Time_Slice: + .word TMD_Time_Slice + +Slice_State: + .word TMD_Time_Slice_State + +System_Stack: + .word TCD_System_Stack + +Int_Count: + .word TCD_Interrupt_Count + +HISR_Tails: + .word TCD_Active_HISR_Tails + +HISR_Heads: + .word TCD_Active_HISR_Heads + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Control_Interrupts + * + * DESCRIPTION + * + * This function enables and disables interrupts as specified by + * the caller. Interrupts disabled by this call are left disabled + * until the another call is made to enable them. + * + * CALLED BY + * + * Application + * + * CALLS + * + * None + * + * INPUTS + * + * new_level New interrupt enable level + * + * OUTPUTS + * + * old_level Previous interrupt enable + * level + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * C. Meredith 03-01-1994 Lockout interrupts while setting + * up the new level, resutling in + * version 1.1 + * D. Lamie 03-18-1994 Verified version 1.1 + * M. Trippi 02-03-1997 Masked the return value to only + * return the interrupt bits. + * (SPR0252) + * + ************************************************************************ + */ + +@INT TCT_Control_Interrupts (INT new_level) +@{ + + .globl TCT_Control_Interrupts +TCT_Control_Interrupts: + +@INT old_level; Old interrupt level + +@ lock out all interrupts before any checking or changing + +@ Obtain the current interrupt lockout posture. +@ old_level = TCD_Interrupt_Level; + +@ Setup new interrupt lockout posture. +@ TCD_Interrupt_Level = new_level; + +@ renable interrupts for the specified lockout + +@ Return old interrupt lockout level. +@ return(old_level); + + MRS r2,CPSR @ Pickup current CPSR + ORR r2,r2,#LOCKOUT @ Build lockout CPSR + MSR CPSR,r2 @ Lockout interrupts temporarily + LDR r1, Int_Level @ Pickup interrupt level + LDR r3,[r1, #0] @ Pickup current interrupt lockout + BIC r2,r2,#LOCK_MSK @ Clear lockout mask + ORR r2,r2,r0 @ Build new CPSR with appropriate + @ interrupts locked out + STR r0,[r1,#0] @ Save current lockout + MSR CPSR,r2 @ Setup new CPSR lockout bits + AND r0,r3,#LOCK_MSK @ Return previous lockout (SPR0252) + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Local_Control_Interrupts + * + * DESCRIPTION + * + * This function enables and disables interrupts as specified by + * the caller. + * + * CALLED BY + * + * Application + * + * CALLS + * + * None + * + * INPUTS + * + * new_level New interrupt enable level + * + * OUTPUTS + * + * old_level Previous interrupt enable + * level + * + * HISTORY + * + * NAME DATE REMARKS + * + * C. Meredith 03-01-1994 Created initial version 1.1 + * D. Lamie 03-18-1994 Verified version 1.1 + * M. Trippi 02-03-1997 Masked the return value to only + * return the interrupt bits. + * (SPR0252) + * + ************************************************************************ + */ + +@INT TCT_Local_Control_Interrupts (INT new_level) +@{ + + .globl TCT_Local_Control_Interrupts +TCT_Local_Control_Interrupts: + +@INT old_level; Old interrupt level + +@ read in the old level +@ old_level = current interrupt level of processor; + + MRS r2,CPSR @ Pickup current CPSR + MOV r3,r2 @ save the old level + +@ clear out the old level and set the new level +@ current interrupt level of processor &= ~LOCKOUT; +@ current interrupt level of processor |= new_level; + + BIC r2,r2,#LOCK_MSK @ Clear all current interrupts + ORR r2,r2,r0 @ Build new CPSR with new + @ interrupt level + MSR CPSR,r2 @ Setup new CPSR interrupt bits + +@ Return old interrupt lockout level. +@ return(old_level); + + AND r0,r3,#LOCK_MSK @ Return previous lockout (SPR0252) + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Restore_Interrupts + * + * DESCRIPTION + * + * This function restores interrupts to that specified in the global + * TCD_Interrupt_Level variable. + * + * CALLED BY + * + * Application + * + * CALLS + * + * None + * + * INPUTS + * + * None. + * + * OUTPUTS + * + * None. + * + * HISTORY + * + * NAME DATE REMARKS + * + * C. Meredith 03-01-1994 Created initial version 1.1 + * D. Lamie 03-18-1994 Verified version 1.1 + * + ************************************************************************ + */ + +@VOID TCT_Restore_Interrupts (VOID) +@{ + + .globl TCT_Restore_Interrupts +TCT_Restore_Interrupts: + +@ Lock out all interrupts before any checking or changing +@ Obtain the current interrupt lockout posture. +@ Reload the level base on the TCD_Interrupt_Level variable + + MRS r1,CPSR @ Pickup current CPSR + MOV r2,r1 @ save the CPSR value + ORR r1,r1,#LOCKOUT @ Build lockout CPSR + MSR CPSR,r1 @ Lockout interrupts temporarily + BIC r2,r2,#LOCK_MSK @ Clear current interrupt levels + LDR r1,Int_Level @ Load address of TCD_Interrupt_Level + LDR r0,[r1, #0] @ Pickup current interrupt lockout + ORR r2,r2,r0 @ Build new CPSR with appropriate + @ interrupts locked out + MSR CPSR,r2 @ Setup new CPSR lockout bits + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Build_Task_Stack + * + * DESCRIPTION + * + * This function builds an initial stack frame for a task. The + * initial stack contains information concerning initial values of + * registers and the task's point of entry. Furthermore, the + * initial stack frame is in the same form as an interrupt stack + * frame. + * + * CALLED BY + * + * TCC_Create_Task Create a new task + * TCC_Reset_Task Reset the specified task + * + * CALLS + * + * None + * + * INPUTS + * + * task Task control block pointer + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@VOID TCT_Build_Task_Stack(TC_TCB *task) +@{ + + .globl TCT_Build_Task_Stack +TCT_Build_Task_Stack: + + @ Pickup the stack base. +@ REG_Stack_Base = (BYTE_PTR) task -> tc_stack_start; + + LDR r2,[r0,#0x24] @ Pickup the stack starting address + + @ Pickup the stack size. +@ REG_Stack_Size = task -> tc_stack_size; + + LDR r1,[r0,#0x30] @ Pickup the stack size in bytes + + @ Calculate the stack ending address. +@ REG_Stack_End = REG_Stack_Base + REG_Stack_Size - 1; + + ADD r3,r1,r2 @ Compute the beginning of stack + BIC r3,r3,#3 @ Insure word alignment + SUB r3,r3,#4 @ Reserve a word + + @ Save the stack ending address. +@ task -> tc_stack_end = REG_Stack_End; + + STR r3,[r0,#0x28] @ Save the stack ending address + + @ Reference the task shell. +@ REG_Function_Ptr = (VOID *) TCC_Task_Shell; + +@ Build an initial stack. This initial stack frame facilitates an +@ interrupt return to the TCC_Task_Shell function, which in turn +@ invokes the application task. The initial stack frame has the +@ following format: + +@ (Lower Address) Stack Top -> 1 (Interrupt stack type) +@ CPSR Saved CPSR +@ r0 Saved r0 +@ r1 Saved r1 +@ r2 Saved r2 +@ r3 Saved r3 +@ r4 Saved r4 +@ r5 Saved r5 +@ r6 Saved r6 +@ r7 Saved r7 +@ r8 Saved r8 +@ r9/sb Saved r9/sl +@ r10/sl Saved r10/sl +@ fp Saved fp +@ r12 Saved r12 +@ r13 Saved r13 +@ r14 Saved r14 +@ (Higher Address) Stack Bottom-> r15 Saved r15 + + + LDR r2, Task_Shell @ Pickup address of shell entry + STR r2,[r3], #-4 @ Store entry address on stack + MOV r2,#0 @ Clear value for initial registers + STR r2,[r3], #-4 @ Store initial r14 + ADD r2,r3,#8 @ Compute initial r13 + STR r2,[r3], #-4 @ Store initial r13 (Stack Bottom) + STR r2,[r3], #-4 @ Store initial r12 + STR r2,[r3], #-4 @ Store initial fp + LDR r2,[r0,#0x24] @ Pickup the stack starting address + STR r2,[r3], #-4 @ Store initial r10/sl + MOV r2,#0 @ Clear value for initial registers + STR r2,[r3], #-4 @ Store initial r9/sb + STR r2,[r3], #-4 @ Store initial r8 + STR r2,[r3], #-4 @ Store initial r7 + STR r2,[r3], #-4 @ Store initial r6 + STR r2,[r3], #-4 @ Store initial r5 + STR r2,[r3], #-4 @ Store initial r4 + STR r2,[r3], #-4 @ Store initial r3 + STR r2,[r3], #-4 @ Store initial r2 + STR r2,[r3], #-4 @ Store initial r1 + STR r2,[r3], #-4 @ Store initial r0 + MSR CPSR_f,r2 @ Clear the flags + MRS r2,CPSR @ Pickup the CPSR + BIC r2,r2,#LOCK_MSK @ Clear initial interrupt lockout + STR r2,[r3], #-4 @ Store CPSR on the initial stack + MOV r2,#1 @ Build interrupt stack type (1) + STR r2,[r3, #0] @ Store stack type on the top + + @ Save the minimum amount of remaining stack memory. +@ task -> tc_stack_minimum = REG_Stack_Size - 72; + + MOV r2,#72 @ Size of interrupt stack frame + SUB r1,r1,r2 @ Compute minimum available bytes + STR r1,[r0, #0x34] @ Save in minimum stack area + + @ Save the new stack pointer into the task's control block. +@ task -> tc_stack_pointer = (VOID *) Stack_Top; + + STR r3,[r0, #0x2C] @ Save stack pointer + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Build_HISR_Stack + * + * DESCRIPTION + * + * This function builds an HISR stack frame that allows quick + * scheduling of the HISR. + * + * CALLED BY + * + * TCC_Create_HISR Create HISR function + * + * CALLS + * + * None + * + * INPUTS + * + * hisr HISR control block pointer + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@VOID TCT_Build_HISR_Stack(TC_HCB *hisr) +@{ + + .globl TCT_Build_HISR_Stack +TCT_Build_HISR_Stack: + + @ Pickup the stack base. +@ REG_Stack_Base = (BYTE_PTR) hisr -> tc_stack_start; + + LDR r2,[r0,#0x24] @ Pickup the stack starting address + + @ Pickup the stack size. +@ REG_Stack_Size = hisr -> tc_stack_size; + + LDR r1,[r0,#0x30] @ Pickup the stack size in bytes + + @ Calculate the stack ending address. +@ REG_Stack_End = REG_Stack_Base + REG_Stack_Size; + + ADD r3,r1,r2 @ Compute the beginning of stack + BIC r3,r3,#3 @ Insure word alignment + SUB r3,r3,#4 @ Reserve a word + + @ Save the stack ending address. +@ hisr -> tc_stack_end = REG_Stack_End; + + STR r3,[r0,#0x28] @ Save the stack ending address + + @ Reference the HISR shell. +@ REG_Function_Ptr = (VOID *) TCT_HISR_Shell; + +@ Build an initial stack. This initial stack frame facilitates an +@ solicited return to the TCT_HISR_Shell function, which in turn +@ invokes the appropriate HISR. The initial HISR stack frame has the +@ following format: + +@ (Lower Address) Stack Top -> 0 (Solicited stack type) +@ !!FOR THUMB ONLY!! 0/0x20 Saved state mask +@ r4 Saved r4 +@ r5 Saved r5 +@ r6 Saved r6 +@ r7 Saved r7 +@ r8 Saved r8 +@ r9/sb Saved r9/sl +@ r10/sl Saved r10/sl +@ fp Saved fp +@ r12 Saved r12 +@ (Higher Address) Stack Bottom-> r15 Saved r15 + + + LDR r2,HISR_Shell @ Pickup address of shell entry + STR r2,[r3], #-4 @ Store entry address on stack + ADD r2,r3,#4 @ Compute initial r13 + STR r2,[r3], #-4 @ Store initial r12 + STR r2,[r3], #-4 @ Store initial fp + LDR r2,[r0,#0x24] @ Pickup the stack starting address + STR r2,[r3], #-4 @ Store initial r10/sl + MOV r2,#0 @ Clear value for initial registers + STR r2,[r3], #-4 @ Store initial r9/sb + STR r2,[r3], #-4 @ Store initial r8 + STR r2,[r3], #-4 @ Store initial r7 + STR r2,[r3], #-4 @ Store initial r6 + STR r2,[r3], #-4 @ Store initial r5 + STR r2,[r3], #-4 @ Store initial r4 +#if 1 /* was .if THUMB */ + STR r2,[r3], #-4 @ Store initial state mask +#endif + STR r2,[r3, #0] @ Store solicited stack type on the + @ top of the stack + + @ Save the minimum amount of remaining stack memory. +@ hisr -> tc_stack_minimum = REG_Stack_Size - (ARM)44 or (THUMB)48; + +#if 1 /* was .if THUMB */ + MOV r2,#48 @ Size of solicited stack frame +#else + MOV r2,#44 @ Size of solicited stack frame +#endif + + SUB r1,r1,r2 @ Compute minimum available bytes + STR r1,[r0, #0x34] @ Save in minimum stack area + + @ Save the new stack pointer into the task's control block. +@ hisr -> tc_stack_pointer = (VOID *) Stack_Top; + + STR r3,[r0, #0x2C] @ Save stack pointer + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Build_Signal_Frame + * + * DESCRIPTION + * + * This function builds a frame on top of the task's stack to + * cause the task's signal handler to execute the next time + * the task is executed. + * + * CALLED BY + * + * TCC_Send_Signals Send signals to a task + * + * CALLS + * + * None + * + * INPUTS + * + * task Task control block pointer + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@VOID TCT_Build_Signal_Frame(TC_TCB *task) +@{ + + .globl TCT_Build_Signal_Frame +TCT_Build_Signal_Frame: + + @ Pickup the stack pointer. +@ REG_Stack_Ptr = (BYTE_PTR) task -> tc_stack_pointer; + + LDR r3,[r0,#0x2c] @ Pickup the current stack pointer + + @ Reference the Signal shell. +@ REG_Function_Ptr = (VOID *) TCC_Signal_Shell; + +@ Build a signal stack. This signal stack frame facilitates an +@ solicited return to the TCC_Signal_Shell function, which in turn +@ invokes the appropriate signal handler. The initial HISR stack frame +@ has the following format: + +@ (Lower Address) Stack Top -> 0 (Solicited stack type) +@ !!FOR THUMB ONLY!! 0/0x20 Saved state mask +@ r4 Saved r4 +@ r5 Saved r5 +@ r6 Saved r6 +@ r7 Saved r7 +@ r8 Saved r8 +@ r9/sb Saved r9/sl +@ r10/sl Saved r10/sl +@ fp Saved fp +@ r12 Saved r12 +@ (Higher Address) Stack Bottom-> r15 Saved r15 + + + LDR r2,Signal_Shell @ Pickup address of shell entry + SUB r3,r3,#4 + STR r2,[r3], #-4 @ Store entry address on stack + ADD r2,r3,#4 @ Compute initial r13 + STR r2,[r3], #-4 @ Store initial r12 + STR r2,[r3], #-4 @ Store initial fp + LDR r2,[r0,#0x24] @ Pickup the stack starting address + STR r2,[r3], #-4 @ Store initial r10/sl + MOV r2,#0 @ Clear value for initial registers + STR r2,[r3], #-4 @ Store initial r9/sb + STR r2,[r3], #-4 @ Store initial r8 + STR r2,[r3], #-4 @ Store initial r7 + STR r2,[r3], #-4 @ Store initial r6 + STR r2,[r3], #-4 @ Store initial r5 + STR r2,[r3], #-4 @ Store initial r4 +#if 0 + MOV r1,#0x20 @ Get initial state mask + STR r1,[r3], #-4 @ Store initial state mask +#else + STR r2,[r3], #-4 @ TCC_Signal_Shell is an ARM proc +#endif + + STR r2,[r3, #0] @ Store solicited stack type on the + @ top of the stack + + @ Save the new stack pointer into the task's control block. +@ task -> tc_stack_pointer = (VOID *) (REG_Stack_Ptr - REG_Stack_Size); + + STR r3,[r0, #0x2C] @ Save stack pointer + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Check_Stack + * + * DESCRIPTION + * + * This function checks the current stack for overflow conditions. + * Additionally, this function keeps track of the minimum amount + * of stack space for the calling thread and returns the current + * available stack space. + * + * CALLED BY + * + * TCC_Send_Signals Send signals to a task + * + * CALLS + * + * ERC_System_Error System error handler + * + * INPUTS + * + * None + * + * OUTPUTS + * + * available bytes in stack + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@UNSIGNED TCT_Check_Stack(void) +@{ + + .globl TCT_Check_Stack +TCT_Check_Stack: + +@TC_TCB *thread; +@UNSIGNED remaining; + + @ Pickup the current task/HISR pointer. +@ thread = (TC_TCB *) TCD_Current_Thread; + + LDR r0,Current_Thread @ Pickup address of thread pointer + LDR r0,[r0,#0] @ Pickup thread pointer + + @ Determine if there is a current thread. +@ if (thread) +@ { + + CMP r0,#0 @ Determine if a thread is active + MOV r3,#0 @ Default remaining value + BEQ TCT_Skip_Stack_Check @ If NU_NULL, skip stack checking + + @ Determine if the stack pointers are out of range. +@ if ((thread -> tc_stack_pointer < thread -> tc_stack_start) || +@ (thread -> tc_stack_pointer > thread -> tc_stack_end)) + + LDR r2,[r0,#0x24] @ Pickup start of stack area + CMP r13,r2 @ Compare with current stack ptr + BLT TCT_Stack_Range_Error @ If less, stack is out of range + LDR r1,[r0,#0x28] @ Pickup end of stack area + CMP r13,r1 @ Compare with current stack ptr + BLE TCT_Stack_Range_Okay @ If less, stack range is okay + + @ Stack overflow condition exits. +@ ERC_System_Error(NU_STACK_OVERFLOW); + +TCT_Stack_Range_Error: + + STR r14,[r13, #4]! @ Store r14 on the stack + MOV r0,#3 @ Build NU_STACK_OVERFLOW code + BL ERC_System_Error @ Call system error handler. Note: + @ control is not returned! + @ Examine stack to find return + @ address of this routine. + +TCT_Stack_Range_Okay: + + @ Calculate the amount of available space on the stack. +@ remaining = (BYTE_PTR) thread -> tc_stack_pointer - +@ (BYTE_PTR) thread -> tc_stack_start; + + SUB r3,r13,r2 @ Calculate remaining stack size + + @ Determine if there is enough memory on the stack to save all of the + @ registers. +@ if (remaining < 80) + + CMP r3,#80 @ Is there enough room for an + @ interrupt frame? + BCS TCT_No_Stack_Error @ If so, no stack overflow yet + + @ Stack overflow condition is about to happen. +@ ERC_System_Error(NU_STACK_OVERFLOW); + + STR r14,[r13, #4]! @ Store r14 on the stack + MOV r0,#3 @ Build NU_STACK_OVERFLOW code + BL ERC_System_Error @ Call system error handler. Note: + @ control is not returned! + @ Examine stack to find return + @ address of this routine. + +TCT_No_Stack_Error: + + @ Determine if this is a new minimum amount of stack space. +@ if (remaining < thread -> tc_stack_minimum) + + LDR r2,[r0,#0x34] + CMP r3,r2 + STRCC r3,[r0,#0x34] + + @ Save the new stack minimum. +@ thread -> tc_stack_minimum = remaining; +@ } +@ else + + @ Set the remaining bytes to 0. +@ remaining = 0; + + @ Return the remaining number of bytes on the stack. +@ return(remaining); + +TCT_Skip_Stack_Check: + MOV r0,r3 @ Return remaining bytes + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Schedule + * + * DESCRIPTION + * + * This function waits for a thread to become ready. Once a thread + * is ready, this function initiates a transfer of control to that + * thread. + * + * CALLED BY + * + * INC_Initialize Main initialization routine + * + * CALLS + * + * TCT_Control_To_Thread Transfer control to a thread + * + * INPUTS + * + * TCD_Execute_Task Pointer to task to execute + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@VOID TCT_Schedule(void) +@{ + + .globl TCT_Schedule +TCT_Schedule: + + @ Restore interrupts according to the value contained in +@ TCD_Interrupt_Level. + + LDR r1,Int_Level @ Build address of interrupt level + MRS r0,CPSR @ Pickup current CPSR + LDR r2,[r1, #0] @ Pickup current interrupt lockout + BIC r0,r0,#LOCK_MSK @ Clear the interrupt lockout bits + ORR r0,r0,r2 @ Build new interrupt lockout CPSR + MSR CPSR,r0 @ Setup new CPSR + LDR r2,Execute_HISR @ Pickup TCD_Execute_HISR address + LDR r3,Execute_Task @ Pickup TCD_Execute_Task address + +#ifdef INCLUDE_PROVIEW +@ Nucleus ProView Hook +@ We check if upon entering TCT_Schedule we already have a task to excute. +@ if not, we start IDLE. + LDR r0,[r2, #0] @ Pickup highest priority HISR ptr + CMP r0,#0 @ Is there a HISR active? + BNE TCT_Schedule_Thread @ Found an HISR + LDR r0,[r3, #0] @ Pickup highest priority Task ptr + CMP r0,#0 @ Is there a task active? + BNE TCT_Schedule_Thread @ If not, start IDLE. + STR r2,[r13, #-4]! @ Save r2 on the stack + STR r3,[r13, #-4]! @ Save r3 on the stack + BL _NU_Idle_Hook + LDR r3,[r13], #4 @ Recover r2 + LDR r2,[r13], #4 @ Recover r3 +#endif + + + @ Wait until a thread (task or HISR) is available to execute. +@ do +@ { + .globl TCT_Schedule_Loop +TCT_Schedule_Loop: + +@ } while ((!TCD_Execute_HISR) && (!TCD_Execute_Task)); + + LDR r0,[r2, #0] @ Pickup highest priority HISR ptr + CMP r0,#0 @ Is there a HISR active? + BNE TCT_Schedule_Thread @ Found an HISR + LDR r0,[r3, #0] @ Pickup highest priority Task ptr + CMP r0,#0 @ Is there a task active? +#if CONFIG_INCLUDE_L1 + BEQ _GSM_Small_Sleep +#else + BEQ TCT_Schedule_Loop @ If not, continue the search +#endif + + @ Yes, either a task or an HISR is ready to execute. Lockout + @ interrupts while the thread is transferred to. + +TCT_Schedule_Thread: + MRS r1,CPSR @ Pickup CPSR again + ORR r1,r1,#LOCKOUT @ Build interrupt lockout value + MSR CPSR,r1 @ Lockout interrupts + +@ Transfer control to the thread by falling through to the following +@ routine. +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Control_To_Thread + * + * DESCRIPTION + * + * This function transfers control to the specified thread. Each + * time control is transferred to a thread, its scheduled counter + * is incremented. Additionally, time-slicing for task threads is + * enabled in this routine. The TCD_Current_Thread pointer is + * setup by this function. + * + * CALLED BY + * + * TCT_Schedule Indirectly called + * TCT_Protect Protection task switch + * + * CALLS + * + * None + * + * INPUTS + * + * thread Thread control block pointer + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@VOID TCT_Control_To_Thread(TC_TCB *thread) +@{ +TCT_Control_To_Thread: + + @ Setup the current thread pointer. +@ TCD_Current_Thread = (VOID *) thread; + + LDR r1,Current_Thread @ Pickup current thread ptr address + LDR r2,[r0, #0x1c] @ Pickup scheduled count + STR r0,[r1, #0] @ Setup current thread pointer + + @ Increment the thread scheduled counter. +@ thread -> tc_scheduled++; + + LDR r3,[r0, #0x20] @ Pickup time slice value + ADD r2,r2,#1 @ Increment the scheduled count + STR r2,[r0, #0x1c] @ Store new scheduled count + + @ Check for time slice option. +@ if (thread -> tc_cur_time_slice) +@ { + CMP r3,#0 @ Is there a time slice? + BEQ TCT_No_Start_TS_1 @ If 0, there is no time slice + + @ Start a time slice. +@ TMD_Time_Slice = thread -> tc_cur_time_slice; +@ TMD_Time_Slice_State = 0; + + LDR r2,Time_Slice @ Pickup address of TMD_Time_Slice + LDR r1,Slice_State @ Pickup address of + @ TMD_Time_Slice_State + STR r3,[r2, #0] @ Setup the time slice + MOV r2,#0 @ Build active state flag + STR r2,[r1,#0] @ Set the active flag +@ } +TCT_No_Start_TS_1: +#ifdef INCLUDE_PROVIEW +@ Nucleus ProView Hook + + STR r0,[r13, #-4]! @ Save r0 on the stack + BL _NU_Schedule_Task_Hook @ Branch to RTView + LDR r0,[r13], #4 @ Recover return address +#endif + + + @ Pickup the stack pointer and resume the thread. +@ REG_Stack_Ptr = thread -> tc_stack_pointer; + + LDR r13,[r0, #0x2c] @ Switch to thread's stack pointer + +@ Pop off the saved information associated with the thread. After we +@ determine which type of stack is present. A 1 on the top of the +@ stack indicates an interrupt stack, while a 0 on the top of the +@ stack indicates a solicited type of stack. + +@ Remember that the interrupt level that is restored must represent +@ the interrupt level in TCD_Interrupt_Level. + + LDR r1,[r13], #4 @ Pop off the stack type + CMP r1,#1 @ See if it is an interrupt stack + BEQ TCT_Interrupt_Resume @ If so, an interrupt resume of + @ thread is required + LDR r1, Int_Level @ Pickup address of interrupt + @ lockout + MRS r0,CPSR @ Pickup current CPSR + BIC r0,r0,#LOCK_MSK @ Clear lockout mask + + BIC r0,r0,#0x80000000 + + + LDR r2,[r1, #0] @ Pickup interrupt lockout mask + ORR r0,r0,r2 @ Build new interrupt lockout mask +#if 1 /* was .if THUMB */ + LDR r2,[r13], #4 @ Pop off the state mask + ORR r0,r0,r2 @ Set appropriate state +#endif + MSR SPSR,r0 @ Place it into the SPSR + LDMIA r13!,{r4-r12,r15}^ @ A solicited return is required. + @ This type of return only + @ recovers r4-r13 & r15 +TCT_Interrupt_Resume: + LDR r0,[r13], #4 @ Pop off the CPSR + LDR r1,Int_Level @ Pickup address of interrupt + @ lockout + BIC r0,r0,#LOCK_MSK @ Clear lockout mask + LDR r2,[r1, #0] @ Pickup interrupt lockout mask + ORR r0,r0,r2 @ Build new interrupt lockout mask + MSR SPSR,r0 @ Place it into the SPSR + LDMIA r13,{r0-r15}^ @ Recover all registers and resume + @ at point of interrupt +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Control_To_System + * + * DESCRIPTION + * + * This function returns control from a thread to the system. Note + * that this service is called in a solicited manner, i.e. it is + * not called from an interrupt thread. Registers required by the + * compiler to be preserved across function boundaries are saved by + * this routine. Note that this is usually a sub-set of the total + * number of available registers. + * + * CALLED BY + * + * Other Components + * + * CALLS + * + * TCT_Schedule Schedule the next thread + * + * INPUTS + * + * None + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * C. Meredith 03-01-1994 Corrected problem in time-slice + * reset logic, resulting in + * version 1.1 + * D. Lamie 03-18-1994 Verified version 1.1 + * + ************************************************************************ + */ + +@VOID TCT_Control_To_System(void) +@{ + + .globl TCT_Control_To_System +TCT_Control_To_System: + + @ Lockout interrupts. + + MRS r0,CPSR @ Pickup current CPSR + ORR r0,r0,#LOCKOUT @ Build interrupt lockout value + MSR CPSR,r0 @ Lockout interrupts + + @ Save a minimal context of the thread. + + STMDB r13!,{r4-r12,r14} @ Save minimal context of thread on + @ the current stack +#if 1 /* was .if THUMB */ + MOV r2,r14 @ Determine what state the caller + MOV r2,r2,LSL #31 @ was in and build an + MOV r2,r2,LSR #26 @ appropriate state mask + STR r2,[r13, #-4]! @ Place it on the stack +#endif + + MOV r2,#0 @ Build solicited stack type value + @ and NU_NULL value + STR r2,[r13, #-4]! @ Place it on the top of the stack + + @ Setup a pointer to the thread control block. +@ REG_Thread_Ptr = (TC_TCB *) TCD_Current_Thread; + + LDR r1,Current_Thread @ Pickup current thread ptr address + LDR r0,[r1, #0] @ Pickup current thread pointer + + @ Clear the current thread control block pointer. +@ TCD_Current_Thread = NU_NULL; + + LDR r3,Slice_State @ Pickup time slice state address + STR r2,[r1, #0] @ Set current thread pointer to + @ NU_NULL + +@ Check to see if a time slice is active. If so, copy the original time +@ slice into the current time slice field of the task's control block. +@ if (TMD_Time_Slice_State == 0) +@ { + LDR r1,[r3, #0] @ Pickup time slice state flag + CMP r1,#0 @ Compare with active value + BNE TCT_No_Stop_TS_1 @ If non-active, don't disable + + + @ Insure that the next time the task runs it gets a fresh time + @ slice. +@ REG_Thread_Ptr -> tc_cur_time_slice = REG_Thread_Ptr -> tc_time_slice; + + LDR r1,[r0, #0x40] @ Pickup original time slice + + @ Clear any active time slice by setting the state to NOT_ACTIVE. +@ TMD_Time_Slice_State = 1; + + MOV r2,#1 @ Build disable value + STR r2,[r3, #0] @ Disable time slice + STR r1,[r0, #0x20] @ Reset current time slice +@ } +TCT_No_Stop_TS_1: + + @ Save off the current stack pointer in the control block. +@ REG_Thread_Ptr -> tc_stack_pointer = (VOID *) REG_Stack_Ptr; + + STR r13,[r0, #0x2c] @ Save the thread's stack pointer + + @ Clear the task's current protection. +@ (REG_Thread_Ptr -> tc_current_protect) -> tc_tcb_pointer = NU_NULL; +@ REG_Thread_Ptr -> tc_current_protect = NU_NULL; + + LDR r1,[r0, #0x38] @ Pickup current thread pointer + MOV r2,#0 @ Build NU_NULL value + STR r2,[r0, #0x38] @ Clear the protect pointer field + STR r2,[r1, #0] @ Release the actual protection + + @ Switch to the system stack. +@ REG_Stack_Ptr = TCD_System_Stack; + + LDR r1, System_Stack @ Pickup address of stack pointer + LDR r2, System_Limit @ Pickup address of stack limit ptr + LDR r13,[r1, #0] @ Switch to system stack + LDR r10,[r2, #0] @ Setup system stack limit + + @ Finished, return to the scheduling loop. + + B TCT_Schedule @ Return to scheduling loop +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Signal_Exit + * + * DESCRIPTION + * + * This function exits from a signal handler. The primary purpose + * of this function is to clear the scheduler protection and switch + * the stack pointer back to the normal task's stack pointer. + * + * CALLED BY + * + * TCC_Signal_Shell Signal handling shell func + * + * CALLS + * + * TCT_Schedule Scheduler + * + * INPUTS + * + * None + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * C. Meredith 03-01-1994 Corrected problem in time-slice + * reset logic, resulting in + * version 1.1 + * D. Lamie 03-18-1994 Verified version 1.1 + * + ************************************************************************ + */ + +@VOID TCT_Signal_Exit(void) +@{ + + .globl TCT_Signal_Exit +TCT_Signal_Exit: + + @ Lockout interrupts. + + MRS r3,CPSR @ Pickup current CPSR + ORR r3,r3,#LOCKOUT @ Build lockout value + MSR CPSR,r3 @ Lockout interrupts + + @ Setup a pointer to the thread control block. +@ REG_Thread_Ptr = (TC_TCB *) TCD_Current_Thread; + + LDR r1,Current_Thread @ Pickup address of thread pointer + MOV r2,#0 @ Build NU_NULL value + LDR r0,[r1,#0] @ Pickup current thread pointer + + @ Clear the current thread control block. +@ TCD_Current_Thread = NU_NULL; + + LDR r3,Slice_State @ Pickup time slice state address + STR r2,[r1, #0] @ Clear current thread pointer + + @ Check to see if a time slice is active. If so, copy the original time + @ slice into the current time slice field of the task's control block. +@ if (TMD_Time_Slice_State == 0) +@ { + + LDR r1,[r3, #0] @ Pickup time slice state flag + CMP r1,#0 @ Compare with active value + BNE TCT_No_Stop_TS_2 @ If non-active, don't disable + + @ Insure that the next time the task runs it gets a fresh time + @ slice. +@ REG_Thread_Ptr -> tc_cur_time_slice = REG_Thread_Ptr -> tc_time_slice; + + LDR r1,[r0, #0x40] @ Pickup original time slice + + @ Clear any active time slice by setting the state to NOT_ACTIVE. +@ TMD_Time_Slice_State = 1; + + MOV r2,#1 @ Build disable value + STR r2,[r3, #0] @ Disable time slice + STR r1,[r0, #0x20] @ Reset current time slice +@ } +TCT_No_Stop_TS_2: + + @ Switch back to the saved stack. The saved stack pointer was saved + @ before the signal frame was built. +@ REG_Thread_Ptr -> tc_stack_pointer = +@ REG_Thread_Ptr -> tc_saved_stack_ptr; + + LDR r1,[r0, #0x3c] @ Pickup saved stack pointer + STR r1,[r0, #0x2c] @ Place in current stack pointer + + @ Clear the task's current protection. +@ (REG_Thread_Ptr -> tc_current_protect) -> tc_tcb_pointer = NU_NULL; +@ REG_Thread_Ptr -> tc_current_protect = NU_NULL; + + LDR r1,[r0, #0x38] @ Pickup current thread pointer + MOV r2,#0 @ Build NU_NULL value + STR r2,[r0, #0x38] @ Clear the protect pointer field + STR r2,[r1, #0] @ Release the actual protection + + @ Switch to the system stack. +@ REG_Stack_Ptr = (BYTE_PTR) TCD_System_Stack; + + LDR r1, System_Stack @ Pickup address of stack pointer + LDR r2, System_Limit @ Pickup address of stack limit ptr + LDR r13,[r1, #0] @ Switch to system stack + LDR r10,[r2, #0] @ Setup system stack limit + + @ Finished, return to the scheduling loop. + + B TCT_Schedule @ Return to scheduling loop +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Current_Thread + * + * DESCRIPTION + * + * This function returns the current thread pointer. + * + * CALLED BY + * + * Application + * System Components + * + * CALLS + * + * None + * + * INPUTS + * + * None + * + * OUTPUTS + * + * Pointer to current thread + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@VOID *TCT_Current_Thread(void) +@{ + + .globl TCT_Current_Thread +TCT_Current_Thread: + + @ Return the current thread pointer. +@ return(TCD_Current_Thread); + + LDR r0, Current_Thread @ Pickup address of thread pointer + LDR r0,[r0, #0] @ Pickup current thread pointer + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Set_Execute_Task + * + * DESCRIPTION + * + * This function sets the current task to execute variable under + * protection against interrupts. + * + * CALLED BY + * + * TCC Scheduling Routines + * + * CALLS + * + * None + * + * INPUTS + * + * task Pointer to task control block + * + * OUTPUTS + * + * TCD_Execute_Task Modified variable + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@VOID TCT_Set_Execute_Task(TC_TCB *task) +@{ + + .globl TCT_Set_Execute_Task +TCT_Set_Execute_Task: + + @ Now setup the TCD_Execute_Task pointer. +@ TCD_Execute_Task = task; + + LDR r1, Execute_Task @ Pickup execute task ptr address + STR r0,[r1,#0] @ Setup new task to execute + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Protect + * + * DESCRIPTION + * + * This function protects against multiple thread access. + * + * CALLED BY + * + * Application + * System Components + * + * CALLS + * + * None + * + * INPUTS + * + * protect Pointer to protection block + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@VOID TCT_Protect(TC_PROTECT *protect) +@{ + + .globl TCT_Protect +TCT_Protect: + + @ Determine if the caller is in a task or HISR thread. +@ if (TCD_Current_Thread) +@ { + + LDR r1,Current_Thread @ Pickup current thread ptr address + LDR r3,[r1, #0] @ Pickup current thread pointer + CMP r3,#0 @ Check to see if it is non-NULL + BEQ TCT_Skip_Protect @ If NULL, skip protection + + @ Lockout interrupts. + + MRS r1,CPSR @ Pickup current CPSR + ORR r1,r1,#LOCKOUT @ Place lockout value in + MSR CPSR,r1 @ Lockout interrupts + + @ Wait until the protect structure is available. +@ while (protect -> tc_tcb_pointer != NU_NULL) +@ { + +TCT_Protect_Loop: + LDR r1,[r0, #0] @ Pickup protection owner field + CMP r1,#0 @ Is there any protection? + BEQ TCT_Protect_Available @ If NU_NULL, no current protection + + @ Protection structure is not available. + + @ Indicate that another thread is waiting. +@ protect -> tc_thread_waiting = 1; + + MOV r2,#1 @ Build thread waiting flag + STR r2,[r0, #4] @ Set waiting field + + @ Directly schedule the thread waiting. +@ TCT_Schedule_Protected(protect -> tc_tcb_pointer); + + STR r0,[r13, #-4]! @ Save r0 on the stack + STR r14,[r13, #-4]! @ Save r14 on the stack + MOV r0,r3 @ Place current thread into r0 + BL TCT_Schedule_Protected @ Call routine to schedule the + @ owner of the thread + + LDR r14,[r13], #4 @ Recover saved r14 + LDR r0,[r13], #4 @ Recover saved r0 + + @ Lockout interrupts. + + LDR r1,Current_Thread @ Pickup current thread ptr address + LDR r3,[r1, #0] @ Pickup current thread pointer + MRS r1,CPSR @ Pickup current CPSR + ORR r1,r1,#LOCKOUT @ Place lockout value in + MSR CPSR,r1 @ Lockout interrupts + B TCT_Protect_Loop @ Examine protect flags again +@ } +TCT_Protect_Available: + + @ Protection structure is available. + + @ Indicate that this thread owns the protection. +@ protect -> tc_tcb_pointer = TCD_Current_Thread; + + STR r3,[r0, #0] @ Indicate calling thread owns this + @ protection + + @ Clear the thread waiting flag. +@ protect -> tc_thread_waiting = 0; + + MOV r2,#0 @ Clear value + STR r2,[r0, #4] @ Clear the thread waiting flag + +@ Save the protection pointer in the thread's control block. Note +@ that both task and HISR threads share the same control block +@ format. +@ REG_Thread_Ptr = (TC_TCB *) TCD_Current_Thread; +@ REG_Thread_Ptr -> tc_current_protect = protect; + + STR r0,[r3, #0x38] @ Setup current protection + + @ Restore interrupts. + + LDR r2,Int_Level @ Pickup address of interrupt level + MRS r1,CPSR @ Pickup current CPSR + LDR r3,[r2, #0] @ Pickup interrupt lockout level + BIC r1,r1,#LOCK_MSK @ Clear lockout bits + ORR r1,r1,r3 @ Build new interrupt lockout + MSR CPSR,r1 @ Setup CPSR appropriately +@ } + +TCT_Skip_Protect: + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Unprotect + * + * DESCRIPTION + * + * This function releases protection of the currently active + * thread. If the caller is not an active thread, then this + * request is ignored. + * + * CALLED BY + * + * Application + * System Components + * + * CALLS + * + * None + * + * INPUTS + * + * None + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@VOID TCT_Unprotect(void) +@{ + + .globl TCT_Unprotect +TCT_Unprotect: + + + @ Determine if the caller is in a task or HISR thread. +@ if (TCD_Current_Thread) +@ { + + LDR r1,Current_Thread @ Pickup current thread ptr address + LDR r3,[r1, #0] @ Pickup current thread pointer + CMP r3,#0 @ Check to see if it is non-NULL + BEQ TCT_Skip_Unprotect @ If NULL, skip unprotection + + @ Setup a thread control block pointer. +@ REG_Thread_Ptr = (TC_TCB *) TCD_Current_Thread; + + @ Determine if there is a currently active protection. +@ if (REG_Thread_Ptr -> tc_current_protect) +@ { + + LDR r0,[r3, #0x38] @ Pickup current protect field + CMP r0,#0 @ Is there a protection in force? + BEQ TCT_Skip_Unprotect @ If not, nothing is protected + + @ Lockout interrupts. + + MRS r1,CPSR @ Pickup current CPSR + ORR r1,r1,#LOCKOUT @ Place lockout value in + MSR CPSR,r1 @ Lockout interrupts + + @ Yes, this thread still has this protection structure. +@ REG_Protect_Ptr = REG_Thread_Ptr -> tc_current_protect; + + @ Is there a higher priority thread waiting for the protection + @ structure? +@ if (REG_Protect_Ptr -> tc_thread_waiting) + + LDR r2,[r0, #4] @ Pickup thread waiting flag + CMP r2,#0 @ Are there any threads waiting? + BEQ TCT_Not_Waiting_Unpr @ If not, just release protection + +@ Transfer control to the system. Note that this +@ automatically clears the current protection and it returns +@ to the caller of this routine instead of this routine. +@ TCT_Control_To_System(); + + B TCT_Control_To_System @ Return control to the system + +@ else +@ { +TCT_Not_Waiting_Unpr: + + @ Clear the protection. +@ REG_Thread_Ptr -> tc_current_protect = NU_NULL; +@ REG_Protect_Ptr -> tc_tcb_pointer = NU_NULL; + + MOV r2,#0 @ Build NU_NULL value + STR r2,[r0, #0] @ Release the protection + STR r2,[r3, #0x38] @ Clear protection pointer in the + @ control block + +@ } + +TCT_Not_Protected: + @ Restore interrupts again. + + LDR r2,Int_Level @ Pickup address of interrupt level + MRS r1,CPSR @ Pickup current CPSR + LDR r3,[r2, #0] @ Pickup interrupt lockout level + BIC r1,r1,#LOCK_MSK @ Clear lockout bits + ORR r1,r1,r3 @ Build new interrupt lockout + MSR CPSR,r1 @ Setup CPSR appropriately + +@ } +@ } +TCT_Skip_Unprotect: + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Unprotect_Specific + * + * DESCRIPTION + * + * This function releases a specific protection structure. + * + * CALLED BY + * + * Application + * System Components + * + * CALLS + * + * None + * + * INPUTS + * + * protect Pointer to protection block + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * C. Meredith 03-01-1994 Corrected problem in time-slice + * reset logic, corrected bug + * using protect ptr, resulting + * in version 1.1 + * D. Lamie 03-18-1994 Verified version 1.1 + * + ************************************************************************ + */ + +@VOID Specific(TC_PROTECT *protect) +@{ + + .globl TCT_Unprotect_Specific +TCT_Unprotect_Specific: + + @ Determine if the caller is in a task or HISR thread. +@ if (TCD_Current_Thread) +@ { + + LDR r1,Current_Thread @ Pickup current thread ptr address + LDR r3,[r1, #0] @ Pickup current thread pointer + CMP r3,#0 @ Check to see if it is non-NULL + BEQ TCT_Skip_Unprot_Spec @ If NULL, skip unprotect specific + + @ Lockout interrupts. + + MRS r1,CPSR @ Pickup current CPSR + ORR r1,r1,#LOCKOUT @ Place lockout value in + MSR CPSR,r1 @ Lockout interrupts + + @ Clear the protection pointer. +@ protect -> tc_tcb_pointer = NU_NULL; + + MOV r2,#0 @ Build NU_NULL value + STR r2,[r0, #0] @ Clear protection ownership + + @ Determine if a thread is waiting. +@ if (protect -> tc_thread_waiting) +@ { + + LDR r1,[r0, #4] @ Pickup the waiting field + CMP r1,#0 @ Is there another thread waiting? + BEQ TCT_Not_Waiting_Unspec @ No, restore interrupts and return + + @ A higher-priority thread is waiting. + + @ Save a minimal context of the thread. + + STMDB r13!,{r4-r12,r14} @ Save minimal context of thread on + @ the current stack + +#if 1 /* was .if THUMB */ + MOV r2,r14 @ Determine what state the caller + MOV r2,r2,LSL #31 @ was in and build an + MOV r2,r2,LSR #26 @ appropriate state mask + STR r2,[r13, #-4]! @ Place it on the stack +#endif + + MOV r2,#0 @ Build solicited stack type value + @ and NU_NULL value + STR r2,[r13, #-4]! @ Place it on the top of the stack + + @ Setup a pointer to the thread control block. +@ REG_Thread_Ptr = (TC_TCB *) TCD_Current_Thread; + + LDR r1,Current_Thread @ Pickup current thread ptr address + LDR r0,[r1, #0] @ Pickup current thread pointer + + @ Clear the current thread control block pointer. +@ TCD_Current_Thread = NU_NULL; + + LDR r3,Slice_State @ Pickup time slice state address + STR r2,[r1, #0] @ Set current thread pointer to + @ NU_NULL + + @ Check to see if a time slice is active. If so, copy the + @ original time slice into the current time slice field of the + @ thread's control block. +@ if (TMD_Time_Slice_State == 0) +@ { + + LDR r1,[r3, #0] @ Pickup time slice state flag + CMP r1,#0 @ Compare with active value + BNE TCT_No_Stop_TS_3 @ If non-active, don't disable + + @ Insure that the next time the task runs it gets a fresh time + @ slice. +@ REG_Thread_Ptr -> tc_cur_time_slice = +@ REG_Thread_Ptr -> tc_time_slice; + + LDR r1,[r0, #0x40] @ Pickup original time slice + + @ Clear any active time slice by setting the state to + @ NOT_ACTIVE. +@ TMD_Time_Slice_State = 1; + + MOV r2,#1 @ Build disable value + STR r2,[r3, #0] @ Disable time slice + STR r1,[r0, #0x20] @ Reset current time slice +@ } + +TCT_No_Stop_TS_3: + + @ Save off the current stack pointer in the control block. +@ REG_Thread_Ptr -> tc_stack_pointer = (VOID *) REG_Stack_Ptr; + + STR r13,[r0, #0x2c] @ Save the thread's stack pointer + + @ Switch to the system stack. +@ REG_Stack_Ptr = TCD_System_Stack; + + LDR r1,System_Stack @ Pickup address of stack pointer + LDR r2,System_Limit @ Pickup address of stack limit ptr + LDR r13,[r1, #0] @ Switch to system stack + LDR r10,[r2, #0] @ Setup system stack limit + + @ Finished, return to the scheduling loop. + + B TCT_Schedule @ Return to scheduling loop + +@ } +@ else +@ { +TCT_Not_Waiting_Unspec: + + @ No higher-priority thread is waiting. + +@ Restore interrupts. + + LDR r2,Int_Level @ Pickup address of interrupt level + MRS r1,CPSR @ Pickup current CPSR + LDR r3,[r2, #0] @ Pickup interrupt lockout level + BIC r1,r1,#LOCK_MSK @ Clear lockout bits + ORR r1,r1,r3 @ Build new interrupt lockout + MSR CPSR,r1 @ Setup CPSR appropriately + +@ } +@ } + +TCT_Skip_Unprot_Spec: + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Set_Current_Protect + * + * DESCRIPTION + * + * This function sets the current protection field of the current + * thread's control block to the specified protection pointer. + * + * CALLED BY + * + * TCC_Resume_Task Resume task function + * + * CALLS + * + * None + * + * INPUTS + * + * protect Pointer to protection block + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@VOID TCT_Set_Current_Protect(TC_PROTECT *protect) +@{ + + .globl TCT_Set_Current_Protect +TCT_Set_Current_Protect: + + @ Determine if the caller is in a task or HISR thread. +@ if (TCD_Current_Thread) +@ { + + LDR r1,Current_Thread @ Pickup current thread ptr address + LDR r3,[r1, #0] @ Pickup current thread pointer + CMP r3,#0 @ Check to see if a thread is + @ active + + @ Point at the current thread control block. +@ REG_Thread_Ptr = (TC_TCB *) TCD_Current_Thread; + + @ Modify the current protection. +@ REG_Thread_Ptr -> tc_current_protect = protect; + + STRNE r0,[r3, #0x38] @ Setup new protection +@ } + + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Protect_Switch + * + * DESCRIPTION + * + * This function waits until a specific task no longer has any + * protection associated with it. This is necessary since task's + * cannot be suspended or terminated unless they have released all + * of their protection. + * + * CALLED BY + * + * System Components + * + * CALLS + * + * None + * + * INPUTS + * + * thread Pointer to thread control blk + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@VOID TCT_Protect_Switch(VOID *thread) +@{ + + .globl TCT_Protect_Switch +TCT_Protect_Switch: + + @ Lockout interrupts. + + MRS r1,CPSR @ Pickup current CPSR + ORR r1,r1,#LOCKOUT @ Place lockout value in + MSR CPSR,r1 @ Lockout interrupts + +@ REG_Thread_Ptr = (TC_TCB *) thread; + + @ Wait until the specified task has no protection associated with it. +@ while (REG_Thread_Ptr -> tc_current_protect) +@ { + + LDR r1,[r0, #0x38] @ Pickup protection of specified + @ thread + CMP r1,#0 @ Does the specified thread have + @ an active protection? + BEQ TCT_Switch_Done @ If not, protect switch is done + + @ Let the task run again in an attempt to clear its protection. + + @ Indicate that a higher priority thread is waiting. +@ (REG_Thread_Ptr -> tc_current_protect) -> tc_thread_waiting = 1; + + MOV r2,#1 @ Build waiting flag value + STR r2,[r1, #4] @ Set waiting flag of the + @ protection owned by the other + @ thread + + @ Directly schedule the thread waiting. +@ TCT_Schedule_Protected((REG_Thread_Ptr -> tc_current_protect) +@ -> tc_tcb_pointer); + + LDR r2,Current_Thread @ Pickup current thread ptr address + STR r0,[r13, #-4]! @ Save r0 on the stack + STR r14,[r13, #-4]! @ Save r14 on the stack + MOV r1,r0 @ Move new thread into r1 + LDR r0,[r2, #0] @ Pickup current thread pointer + BL TCT_Schedule_Protected @ Call routine to schedule the + @ owner of the thread + + LDR r14,[r13], #4 @ Recover saved r14 + LDR r0,[r13], #4 @ Recover saved r0 + + @ Lockout interrupts. + + B TCT_Protect_Switch @ Branch to top of routine and + @ start over +@ } +TCT_Switch_Done: + + @ Restore interrupts. + + LDR r2,Int_Level @ Pickup address of interrupt level + MRS r1,CPSR @ Pickup current CPSR + LDR r3,[r2, #0] @ Pickup interrupt lockout level + BIC r1,r1,#LOCK_MSK @ Clear lockout bits + ORR r1,r1,r3 @ Build new interrupt lockout + MSR CPSR,r1 @ Setup CPSR appropriately + + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Schedule_Protected + * + * DESCRIPTION + * + * This function saves the minimal context of the thread and then + * directly schedules the thread that has protection over the + * the thread that called this routine. + * + * CALLED BY + * + * TCT_Protect + * TCT_Protect_Switch + * + * CALLS + * + * TCT_Control_To_Thread Transfer control to protected + * thread + * + * INPUTS + * + * None + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * C. Meredith 03-01-1994 Corrected problem in time-slice + * reset logic, resulting in + * version 1.1 + * D. Lamie 03-18-1994 Verified version 1.1 + * + ************************************************************************ + */ + +@VOID TCT_Schedule_Protected(VOID *thread) +@{ + + .globl TCT_Schedule_Protected +TCT_Schedule_Protected: + + @ Interrupts are already locked out by the caller. + + @ Save minimal context required by the system. + + STMDB r13!,{r4-r12,r14} @ Save minimal context of thread on + @ the current stack + +#if 1 /* was .if THUMB */ + MOV r2,r14 @ Determine what state the caller + MOV r2,r2,LSL #31 @ was in and build an + MOV r2,r2,LSR #26 @ appropriate state mask + STR r2,[r13, #-4]! @ Place it on the stack +#endif + + MOV r2,#0 @ Build solicited stack type value + @ and NU_NULL value + STR r2,[r13, #-4]! @ Place it on the top of the stack + MOV r4,r1 @ Save thread to schedule + + @ Setup a pointer to the thread control block. +@ REG_Thread_Ptr = (TC_TCB *) TCD_Current_Thread; + + LDR r1,Current_Thread @ Pickup current thread ptr address + + @ Clear the current thread control block. +@ TCD_Current_Thread = NU_NULL; + + LDR r3,Slice_State @ Pickup time slice state address + STR r2,[r1, #0] @ Set current thread pointer to + @ NU_NULL + + @ Check to see if a time slice is active. If so, copy the original time + @ slice into the current time slice field of the task's control block. +@ if (TMD_Time_Slice_State == 0) +@ { + + LDR r1,[r3, #0] @ Pickup time slice state flag + CMP r1,#0 @ Compare with active value + BNE TCT_No_Stop_TS_4 @ If non-active, don't disable + + @ Insure that the next time the task runs it gets a fresh time + @ slice. +@ REG_Thread_Ptr -> tc_cur_time_slice = REG_Thread_Ptr -> tc_time_slice; + + LDR r1,[r0, #0x40] @ Pickup original time slice + + @ Clear any active time slice by setting the state to NOT_ACTIVE. +@ TMD_Time_Slice_State = 1; + + MOV r2,#1 @ Build disable value + STR r2,[r3, #0] @ Disable time slice + STR r1,[r0, #0x20] @ Reset current time slice + +@ } +TCT_No_Stop_TS_4: + + @ Save off the current stack pointer in the control block. +@ REG_Thread_Ptr -> tc_stack_pointer = (VOID *) REG_Stack_Ptr; + + STR r13,[r0, #0x2c] @ Save the thread's stack pointer + + @ Switch to the system stack. +@ TCD_System_Stack = (VOID *) REG_Stack_Ptr; + + LDR r1,System_Stack @ Pickup address of stack pointer + LDR r2,System_Limit @ Pickup address of stack limit ptr + LDR r13,[r1, #0] @ Switch to system stack + LDR r10,[r2, #0] @ Setup system stack limit + + @ Transfer control to the specified thread directly. +@ TCT_Control_To_Thread(thread); + + LDR r2,Int_Level @ Pickup address of interrupt level + MRS r1,CPSR @ Pickup current CPSR + LDR r3,[r2, #0] @ Pickup interrupt lockout level + BIC r1,r1,#LOCK_MSK @ Clear lockout bits + ORR r1,r1,r3 @ Build new interrupt lockout + MOV r0,r4 @ Indicate thread to schedule + MSR CPSR,r1 @ Setup CPSR appropriately + ORR r1,r1,#LOCKOUT @ Build lockout value again + MSR CPSR,r1 @ Lockout interrupts again + B TCT_Control_To_Thread @ Schedule the thread indirectly +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Interrupt_Context_Save + * + * DESCRIPTION + * + * This function saves the interrupted thread's context. Nested + * interrupts are also supported. If a task or HISR thread was + * interrupted, the stack pointer is switched to the system stack + * after the context is saved. + * + * CALLED BY + * + * Application ISRs Assembly language ISRs + * INT_Interrupt_Shell Interrupt handler shell + * + * CALLS + * + * None + * + * INPUTS + * + * vector Interrupt's vector number + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * D. Driscoll 01-04-2002 Released version 1.13.3. + * Updated to handle nested / + * prioritized IRQs + ************************************************************************ + */ + +@VOID TCT_Interrupt_Context_Save(INT vector) +@{ + + .globl TCT_Interrupt_Context_Save +TCT_Interrupt_Context_Save: + @ Determine if this is a nested interrupt. + LDR r1,Int_Count @ Pickup address of interrupt count + LDR r2,[r1, #0] @ Pickup interrupt counter + ADD r2,r2,#1 @ Add 1 to interrupt counter + STR r2,[r1, #0] @ Store new interrupt counter value + CMP r2,#1 @ Is it nested? + BEQ TCT_Not_Nested_Save @ No + +@ Nested interrupt. Save complete context on the current stack. +TCT_Nested_Save: + +/* No longer needed in the FreeCalypso version, as we can use r0 instead. */ +#if 0 +@ 1. Save another register on the exception stack so we have enough to work with + STMDB r13!,{r5} +#endif + +@ 2. Save the necessary exception registers into r1-r3 + MOV r1,r13 @ Put the exception r13 into r1 + MOV r2,r14 @ Move the return address for the caller + @ of this function into r2 + MRS r3,spsr @ Put the exception spsr into r3 + +@ 3. Adjust the exception stack pointer for future exceptions + ADD r13,r13,#20 @ r13 reset to pre-interrupt value + +@ 4. Switch CPU modes to save context on system stack + MRS r0,CPSR @ Pickup the current CPSR + BIC r0,r0,#MODE_MASK @ Clear the mode bits + + ORR r0,r0,#SUP_MODE @ Change to supervisor mode (SVD) + + MSR CPSR,r0 @ Switch modes (IRQ->SVC) + +@ 5. Store the SVC r13 into r5 so the r13 can be saved as is. +@ FreeCalyspo: using r0 instead + MOV r0,r13 + +@ 6. Save the exception return address on the stack (r15). + STMDB r0!,{r4} + +@ 7. Save r5-r14 on stack (used to be r6-r14) + STMDB r0!,{r5-r14} + +@ 8. Switch back to using r13 now that the original r13 has been saved. + MOV r13,r0 + +/* no longer relevant */ +#if 0 +@ 9. Get r5 and exception enable registers off of exception stack and +@ save r5 (stored in r4) back to the system stack. + LDMIA r1!,{r4-r5} + STMDB r13!,{r4} + MOV r4,r5 @ Put exception enable value into r4 +#endif + +@ 10. Get the rest of the registers off the exception stack and +@ save them onto the system stack. + LDMIA r1!,{r5-r8,r11} @ Get r0-r4 off exception stack + STMDB r13!,{r5-r8,r11} @ Put r0-r4 on system stack + +/* no longer relevant */ +#if 0 +@ 11. Store the exception enable value back on the exception stack. + STMDB r1,{r4} +#endif + +@ 12. Save the SPSR on the system stack (CPSR) + STMDB r13!,{r3} + +/* TI's approach to interrupt handling does not support re-enabling here */ +#if 0 +@ 13. Re-enable interrupts + MRS r1,CPSR + BIC r1,r1,#(IRQ_BIT_OR_FIQ_BIT) + MSR CPSR,r1 +#endif + + BX r2 @ Return to calling ISR +@ } +@ else +@ { +TCT_Not_Nested_Save: + + @ Determine if a thread was interrupted. +@ if (TCD_Current_Thread) +@ { + + LDR r1,Current_Thread @ Pickup current thread ptr address + LDR r1,[r1, #0] @ Pickup the current thread pointer + CMP r1,#0 @ Is it NU_NULL? + BEQ TCT_Idle_Context_Save @ If no, no real save is necessary + + + @ Yes, a thread was interrupted. Save complete context on the + @ thread's stack. + +/* No longer needed in the FreeCalypso version, as we can use r0 instead. */ +#if 0 +@ 1. Save another register on the exception stack so we have enough to work with + STMDB r13!,{r5} +#endif + +@ 2. Save the necessary exception registers into r1-r3 + MOV r1,r13 @ Put the exception r13 into r1 + MOV r2,r14 @ Move the return address for the caller + @ of this function into r2 + MRS r3,spsr @ Put the exception spsr into r3 + +@ 3. Adjust the exception stack pointer for future exceptions + ADD r13,r13,#20 @ r13 reset to pre-interrupt value + +@ 4. Switch CPU modes to save context on system stack + MRS r0,CPSR @ Pickup the current CPSR + BIC r0,r0,#MODE_MASK @ Clear the mode bits + + ORR r0,r0,#SUP_MODE @ Change to supervisor mode (SVD) + + MSR CPSR,r0 @ Switch modes (IRQ->SVC) + +@ 5. Store the SVC r13 into r5 so the r13 can be saved as is. +@ FreeCalyspo: using r0 instead + MOV r0,r13 + +@ 6. Save the exception return address on the stack (r15). + STMDB r0!,{r4} + +@ 7. Save r5-r14 on stack (used to be r6-r14) + STMDB r0!,{r5-r14} + +@ 8. Switch back to using r13 now that the original r13 has been saved. + MOV r13,r0 + +/* no longer relevant */ +#if 0 +@ 9. Get r5 and exception enable registers off of exception stack and +@ save r5 (stored in r4) back to the system stack. + LDMIA r1!,{r4-r5} + STMDB r13!,{r4} + MOV r4,r5 @ Put exception enable value into r4 +#endif + +@ 10. Get the rest of the registers off the exception stack and +@ save them onto the system stack. + LDMIA r1!,{r5-r8,r11} @ Get r0-r4 off exception stack + STMDB r13!,{r5-r8,r11} @ Put r0-r4 on system stack + +/* no longer relevant */ +#if 0 +@ 11. Store the exception enable value back on the exception stack. + STMDB r1,{r4} +#endif + +@ 12. Save the SPSR on the system stack (CPSR) + STMDB r13!,{r3} + +@ 13. Save stack type to the task stack (1=interrupt stack) + MOV r1,#1 @ Interrupt stack type + STMDB r13!,{r1} + + @ Save the thread's stack pointer in the control block. +@ REG_Thread_Ptr = (TC_TCB *) TCD_Current_Thread +@ REG_Thread_Ptr -> tc_stack_pointer = (VOID *) REG_Stack_Ptr + + LDR r1,Current_Thread @ Pickup current thread ptr address + LDR r3,[r1, #0] @ Pickup current thread pointer + STR r13,[r3, #TC_STACK_POINTER] @ Save stack pointer + + @ Switch to the system stack. +@ REG_Stack_Ptr = TCD_System_Stack + + LDR r1,System_Stack @ Pickup address of stack pointer + LDR r3,System_Limit @ Pickup address of stack limit ptr + LDR r13,[r1, #0] @ Switch to system stack + LDR r10,[r3, #0] @ Setup system stack limit + +/* TI's approach to interrupt handling does not support re-enabling here */ +#if 0 + @ Re-enable interrupts + MRS r1,CPSR + BIC r1,r1,#(IRQ_BIT_OR_FIQ_BIT) + MSR CPSR,r1 +#endif + +@ Return to caller ISR. + + BX r2 @ Return to caller ISR + +@ } + +TCT_Idle_Context_Save: + + MOV r2,r14 @ Save r14 in r2 +@ LDR r3,[r13] @ Get exception enable value from stack + ADD r13,r13,#20 @ Adjust exception r13 for future interrupts +@ STR r3,[r13] @ Put exception enable value back on stack + + MRS r1,CPSR @ Pickup current CPSR + BIC r1,r1,#MODE_MASK @ Clear the current mode +@ BIC r1,r1,#(IRQ_BIT_OR_FIQ_BIT) @ Re-enable interrupts + + ORR r1,r1,#SUP_MODE @ Prepare to switch to supervisor + @ mode (SVC) + MSR CPSR,r1 @ Switch to supervisor mode (SVC) + + BX r2 @ Return to caller ISR + +@ } +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Interrupt_Context_Restore + * + * DESCRIPTION + * + * This function restores the interrupt context if a nested + * interrupt condition is present. Otherwise, this routine + * transfers control to the scheduling function. + * + * CALLED BY + * + * Application ISRs Assembly language ISRs + * INT_Interrupt_Shell Interrupt handler shell + * + * CALLS + * + * TCT_Schedule Thread scheduling function + * + * INPUTS + * + * None + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * D. Driscoll 01-04-2002 Released version 1.13.3. + * Updated to handle nested / + * prioritized IRQs + * + ************************************************************************ + */ + +@VOID TCT_Interrupt_Context_Restore(void) +@{ + + .globl TCT_Interrupt_Context_Restore +TCT_Interrupt_Context_Restore: + @ It is assumed that anything pushed on the stack by ISRs has been + @ removed upon entry into this routine. + + @ Decrement and check for nested interrupt conditions. +@ if (--TCD_Interrupt_Count) +@ { + + LDR r1,Int_Count @ Pickup address of interrupt count + LDR r2,[r1, #0] @ Pickup interrupt counter + SUB r2,r2,#1 @ Decrement interrupt counter + STR r2,[r1, #0] @ Store interrupt counter + CMP r2,#0 + BEQ TCT_Not_Nested_Restore + + @ Restore previous context. + + LDR r1,[r13], #4 @ Pickup the saved CPSR + + MSR SPSR,r1 @ Place into saved SPSR + LDMIA r13,{r0-r15}^ @ Return to the point of interrupt + +@ } +@ else +@ { + +TCT_Not_Nested_Restore: + + @ Determine if a thread is active. +@ if (TCD_Current_Thread) +@ { + + LDR r1,Current_Thread @ Pickup current thread ptr address + LDR r0,[r1, #0] @ Pickup current thread pointer + CMP r0,#0 @ Determine if a thread is active + BEQ TCT_Idle_Context_Restore @ If not, idle system restore + + @ Clear the current thread pointer. +@ TCD_Current_Thread = NU_NULL + + MOV r2,#0 @ Build NU_NULL value + STR r2,[r1, #0] @ Set current thread ptr to NU_NULL + + @ Determine if a time slice is active. If so, the remaining + @ time left on the time slice must be saved in the task's + @ control block. +@ if (TMD_Time_Slice_State == 0) +@ { + + LDR r3,Slice_State @ Pickup time slice state address + LDR r1,[r3, #0] @ Pickup time slice state + CMP r1,#0 @ Determine if time slice active + BNE TCT_Idle_Context_Restore @ If not, skip time slice reset + + @ Pickup the remaining portion of the time slice and save it + @ in the task's control block. +@ REG_Thread_Ptr -> tc_cur_time_slice = TMD_Time_Slice +@ TMD_Time_Slice_State = 1 + + LDR r2,Time_Slice @ Pickup address of time slice left + MOV r1,#1 @ Build disable time slice value + LDR r2,[r2, #0] @ Pickup remaining time slice + STR r1,[r3, #0] @ Disable time slice + STR r2,[r0, #TC_CUR_TIME_SLICE] @ Store remaining time slice + +@ } +@ } +TCT_Idle_Context_Restore: + + @ Reset the system stack pointer. + LDR r1,System_Stack @ Pickup address of stack pointer + LDR r2,System_Limit @ Pickup address of stack limit ptr + LDR r13,[r1, #0] @ Switch to system stack + LDR r10,[r2, #0] @ Setup system stack limit + + @ Return to scheduler. + + B TCT_Schedule @ Return to scheduling loop + +@ } +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_Activate_HISR + * + * DESCRIPTION + * + * This function activates the specified HISR. If the HISR is + * already activated, the HISR's activation count is simply + * incremented. Otherwise, the HISR is placed on the appropriate + * HISR priority list in preparation for execution. + * + * CALLED BY + * + * Application LISRs + * + * CALLS + * + * None + * + * INPUTS + * + * hisr Pointer to HISR to activate + * + * OUTPUTS + * + * NU_SUCCESS Successful completion + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@STATUS TCT_Activate_HISR(TC_HCB *hisr) +@{ + + .globl TCT_Activate_HISR +TCT_Activate_HISR: + +@INT priority; + + + @ Lockout interrupts. + + STR r4,[r13, #-4]! @ Save r4 + MRS r4,CPSR @ Pickup current CPSR + ORR r1,r4,#LOCKOUT @ Build interrupt lockout value + MSR CPSR,r1 @ Lockout interrupts + + @ Determine if the HISR is already active. +@ if (hisr -> tc_activation_count) +@ { + + LDR r1,[r0,#0x40] @ Pickup current activation count + CMP r1,#0 @ Is it the first activation? + BEQ TCT_First_Activate @ Yes, place it on the correct list + + @ Increment the activation count. Make sure that it does not go + @ to zero. +@ hisr -> tc_activation_count++; + + ADDS r1,r1,#1 @ Increment the activation count + STR r1,[r0,#0x40] @ Store new activation count + +@ if (hisr -> tc_activation_count == 0) + +@ hisr -> tc_activation_count = 0xFFFFFFFFUL; + + MVNEQ r1,#0 @ If counter rolled-over reset + STREQ r1,[r0,#0x40] @ Store all ones count + B TCT_Activate_Done @ Finished with activation +@ } +@ else +@ { +TCT_First_Activate: + + + @ Set the activation count to 1. +@ hisr -> tc_activation_count = 1; + + MOV r1,#1 @ Initial activation count + STR r1,[r0,#0x40] @ Store initial activation count + + @ Pickup the HISR's priority. +@ priority = hisr -> tc_priority; + + @ Determine if there is something in the given priority list. +@ if (TCD_Active_HISR_Tails[priority]) +@ { + + LDRB r1,[r0,#0x1a] @ Pickup priority of HISR + LDR r2,HISR_Tails @ Pickup tail pointer base + LDR r3,[r2,r1,LSL #2] @ Pickup tail pointer for priority + CMP r3,#0 @ Is this first HISR at priority? + BEQ TCT_First_HISR @ No, append to end of HISR list + + @ Something is already on this list. Add after the tail. +@ (TCD_Active_HISR_Tails[priority]) -> tc_active_next = hisr; +@ TCD_Active_HISR_Tails[priority] = hisr; + + STR r0,[r3,#0x3c] @ Setup the active next pointer + STR r0,[r2,r1,LSL #2] @ Setup the tail pointer + B TCT_Activate_Done @ Finished with activate processing +@ } +@ else +@ { +TCT_First_HISR: + + @ Nothing is on this list. +@ TCD_Active_HISR_Heads[priority] = hisr; +@ TCD_Active_HISR_Tails[priority] = hisr; + + LDR r3,HISR_Heads @ Pickup address of head pointers + STR r0,[r2,r1,LSL #2] @ Set tail pointer to this HISR + STR r0,[r3,r1,LSL #2] @ Set head pointer to this HISR + + @ Determine the highest priority HISR. +@ if (TCD_Active_HISR_Heads[0]) +@ TCD_Execute_HISR = TCD_Active_HISR_Heads[0]; +@ else if (TCD_Active_HISR_Heads[1]) +@ TCD_Execute_HISR = TCD_Active_HISR_Heads[1]; +@ else +@ TCD_Execute_HISR = TCD_Active_HISR_Heads[2]; + + LDR r1,[r3,#0] @ Pickup priority 0 head pointer + LDR r0,Execute_HISR @ Build address to execute HISR ptr + CMP r1,#0 @ Is priority 0 active? + LDREQ r1,[r3,#4] @ If not, pickup priority 1 head + CMPEQ r1,#0 @ Is priority 1 active? + LDREQ r1,[r3,#8] @ Else, must be priority 2 active + STR r1,[r0,#0] @ Store which ever priority is the + @ active one +@ } +@ } +TCT_Activate_Done: + + MSR CPSR,r4 @ Restore interrupt lockout + LDR r4,[r13], #4 @ Restore corrupted r4 + +@ return(NU_SUCCESS); + + MOV r0,#0 @ Always return NU_SUCCESS + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TCT_HISR_Shell + * + * DESCRIPTION + * + * This function is the execution shell of each and every HISR. If + * the HISR has completed its processing, this shell routine exits + * back to the system. Otherwise, it sequentially calls the HISR + * routine until the activation count goes to zero. + * + * CALLED BY + * + * HISR Scheduling + * + * CALLS + * + * hisr -> tc_entry Actual entry function of HISR + * + * INPUTS + * + * None + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@VOID TCT_HISR_Shell(void) +@{ + .globl TCT_HISR_Shell +TCT_HISR_Shell: + + @ Point at the HISR. +@ REG_HISR_Ptr = (TC_HCB *) TCD_Current_Thread; + + LDR r0,Current_Thread @ Build address of thread pointer + LDR r5,[r0, #0] @ Pickup control block pointer + +@ do +@ { +TCT_HISR_Loop: + + @ Call the HISR's entry routine. +@ (*(REG_HISR_Ptr -> tc_entry)) (); + +/* old TMS470 code: + + .if THUMB = 0 + + MOV r14,r15 ; Setup return value + LDR r15,[r5,#44h] ; Call HISR entry function + .else + LDR r4,[r5,#44h] ; Get HISR entry function + TST r4,#1 ; See if calling Thumb or ARM + BNE Thumbsec + MOV r14,r15 ; Setup return value + BX r4 + B ARMCODE +Thumbsec: + ADD r14, r15, #1 + BX r4 + .state16 +ThumbAfterHisr + MOV r1, r15 + BX r1 + .state32 + .endif +*/ + + /* new code for the GNU style of ARM/Thumb interworking */ + ldr r4, [r5, #TC_HISR_ENTRY] + mov lr, pc + bx r4 + + @ Lockout interrupts. + + MRS r1,CPSR @ Pickup current CPSR + ORR r1,r1,#LOCKOUT @ Build interrupt lockout + MSR CPSR,r1 @ Lockout interrupts + + @ On return, decrement the activation count and check to see if + @ it is 0. Once it reaches 0, the HISR should be made inactive. +@ REG_HISR_Ptr -> tc_activation_count--; + + + LDR r0,[r5, #0x40] @ Pickup current activation count + SUBS r0,r0,#1 @ Subtract and set condition codes + STR r0,[r5, #0x40] @ Store new activation count + BEQ TCT_HISR_Finished @ Finished processing HISR + + @ Restore interrupts. + + LDR r2,Int_Level @ Pickup address of interrupt level + MRS r1,CPSR @ Pickup current CPSR + LDR r3,[r2, #0] @ Pickup interrupt lockout level + BIC r1,r1,#LOCK_MSK @ Clear lockout bits + ORR r1,r1,r3 @ Build new interrupt lockout + MSR CPSR,r1 @ Setup CPSR appropriately + B TCT_HISR_Loop @ Return to HISR loop +@ } +@ while (REG_HISR_Ptr -> tc_activation_count); + +TCT_HISR_Finished: + + @ At this point, the HISR needs to be made inactive. + + @ Determine if this is the only HISR on the given priority list. +@ if (REG_HISR_Ptr == TCD_Active_HISR_Tails[REG_HISR_Ptr -> tc_priority]) +@ { + + LDR r14,HISR_Tails @ Pickup tail pointers address + LDRB r3,[r5,#0x1a] @ Pickup priority + LDR r6,[r14,r3,LSL #2] @ Pickup this priority tail pointer + LDR r2,Execute_HISR @ Build address to execute HISR ptr + MOV r12,#0 @ Clear r12 + LDR r1,HISR_Heads @ Pickup head pointers address + CMP r6,r5 @ Is this priority tail the same as + @ the current HISR? + BNE TCT_More_HISRs @ If not, more HISRs at this + @ priority + + @ The only HISR on the list. Clean up the list and check for the + @ highest priority HISR. +@ TCD_Active_HISR_Heads[REG_HISR_Ptr -> tc_priority] = NU_NULL; +@ TCD_Active_HISR_Tails[REG_HISR_Ptr -> tc_priority] = NU_NULL; + + STR r12,[r1,r3,LSL #2] @ Set head pointer to NU_NULL + STR r12,[r14,r3,LSL #2] @ Set tail pointer to NU_NULL + + @ Determine the highest priority HISR. +@ if (TCD_Active_HISR_Heads[0]) +@ TCD_Execute_HISR = TCD_Active_HISR_Heads[0]; +@ else if (TCD_Active_HISR_Heads[1]) +@ TCD_Execute_HISR = TCD_Active_HISR_Heads[1]; +@ else +@ TCD_Execute_HISR = TCD_Active_HISR_Heads[2]; + + LDR r3,[r1,#0] @ Pickup priority 0 head pointer + CMP r3,#0 @ Is there an HISR active? + LDREQ r3,[r1,#4] @ If not, pickup priority 1 pointer + CMPEQ r3,#0 @ Is there an HISR active? + LDREQ r3,[r1,#8] @ If not, pickup priority 2 pointer + STR r3,[r2,#0] @ Setup execute HISR pointer + B TCT_HISR_Exit @ Exit HISR processing +@ } +@ else +@ { + +TCT_More_HISRs: + + @ Move the head pointer to the next HISR in the list. +@ TCD_Active_HISR_Heads[REG_HISR_Ptr -> tc_priority] = +@ REG_HISR_Ptr -> tc_active_next; + + @ Also set the TCD_Execute_HISR pointer. +@ TCD_Execute_HISR = REG_HISR_Ptr -> tc_active_next; + + LDR r14,[r5,#0x3c] @ Pickup next HISR to activate + STR r14,[r1,r3,LSL #2] @ Setup new head pointer + STR r14,[r2, #0] @ Setup execute HISR pointer +@ } + +TCT_HISR_Exit: + + @ Build fake return to the top of this loop. The next time the HISR + @ is activated, it will return to the top of this function. + + LDR r14,HISR_Shell @ Pickup address of shell entry + STMDB r13!,{r4-r12,r14} @ Save minimal context of thread on + @ the current stack + MOV r2,#0 @ Build solicited stack type value + @ and NU_NULL value +#if 1 /* was .if THUMB */ + STR r2,[r13, #-4]! @ Save state mask +#endif + STR r2,[r13, #-4]! @ Place it on the top of the stack + + @ Clear the current thread control block. +@ TCD_Current_Thread = NU_NULL; + + LDR r1,Current_Thread @ Pickup current thread ptr address + STR r2,[r1, #0] @ Set current thread pointer to + @ NU_NULL + + @ Save off the current stack pointer in the control block. +@ REG_HISR_Ptr -> tc_stack_pointer = (VOID *) REG_Stack_Ptr; + + + STR r13,[r5, #0x2c] @ Save the thread's stack pointer + + + @ Switch to the system stack. +@ REG_Stack_Ptr = (BYTE_PTR) TCD_System_Stack; + + LDR r1,System_Stack @ Pickup address of stack pointer + LDR r2,System_Limit @ Pickup address of stack limit ptr + LDR r13,[r1, #0] @ Switch to system stack + LDR r10,[r2, #0] @ Setup system stack limit + + @ Transfer control to the main scheduling loop. + + B TCT_Schedule @ Return to main scheduling loop +@} + +/* FreeCalypso addition, used by riviera/rvf/rvf_task.c: */ + .globl INT_Check_IRQ_Mask +INT_Check_IRQ_Mask: + MRS r0,CPSR + BX lr + diff -r 0f466af1eaf0 -r d076885a0669 src/nucleus/gcc/tmt.S --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/nucleus/gcc/tmt.S Fri Jul 20 05:40:33 2018 +0000 @@ -0,0 +1,679 @@ +/* + ************************************************************************ + * + * Copyright Mentor Graphics Corporation 2002 + * All Rights Reserved. + * + * THIS WORK CONTAINS TRADE SECRET AND PROPRIETARY INFORMATION WHICH IS + * THE PROPERTY OF MENTOR GRAPHICS CORPORATION OR ITS LICENSORS AND IS + * SUBJECT TO LICENSE TERMS. + * + ************************************************************************ + ************************************************************************ + * + * FILE NAME VERSION + * + * tmt.s Nucleus PLUS\ARM925\Code Composer 1.14.1 + * + * COMPONENT + * + * TM - Timer Management + * + * DESCRIPTION + * + * This file contains the target dependent routines of the timer + * management component. + * + * FUNCTIONS + * + * TMT_Set_Clock Set system clock + * TMT_Retrieve_Clock Retrieve system clock + * TMT_Read_Timer Read count-down timer + * TMT_Enable_Timer Enable count-down timer + * TMT_Adjust_Timer Adjust count-down timer + * TMT_Disable_Timer Disable count-down timer + * TMT_Retrieve_TS_Task Retrieve time-sliced task ptr + * TMT_Timer_Interrupt Process timer interrupt + * + * DEPENDENCIES + * + * tc_extr.h Thread Control functions + * tm_extr.h Timer functions + * + * HISTORY + * + * NAME DATE REMARKS + * + * B. Ronquillo 08-28-2002 Released version 1.14.1 + * + * + ************************************************************************ + */ + +#define NU_SOURCE_FILE + +/* + ****************************** + * INCLUDE ASSEMBLY CONSTANTS * + ****************************** + * Define constants used in low-level initialization. + */ + +#include "asm_defs.h" + + .code 32 + + .text + +/* + ********************************** + * LOCAL VARIABLE DECLARATIONS * + ********************************** + * Define various data structure pointers so their addresses + * can be obtained in a PC-relative manner. + */ + +System_Clock: + .word TMD_System_Clock + +Timer: + .word TMD_Timer + +Timer_State: + .word TMD_Timer_State + +Slice_State: + .word TMD_Time_Slice_State + +Time_Slice: + .word TMD_Time_Slice + +Current_Thread: + .word TCD_Current_Thread + +Slice_Task: + .word TMD_Time_Slice_Task + +HISR: + .word TMD_HISR + +Int_Level: + .word TCD_Interrupt_Level + +/* + ************************************************************************ + * + * FUNCTION + * + * TMT_Set_Clock + * + * DESCRIPTION + * + * This function sets the system clock to the specified value. + * + * CALLED BY + * + * Application + * + * CALLS + * + * None + * + * INPUTS + * + * new_value New value for the clock + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@VOID TMT_Set_Clock(UNSIGNED new_value) +@{ + + .globl TMT_Set_Clock +TMT_Set_Clock: + +@ Set the system clock to the specified value. +@ TMD_System_Clock = new_value; + + LDR r1,System_Clock @ Build address of system clock + STR r0,[r1,#0] @ Store new system clock value + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TMT_Retrieve_Clock + * + * DESCRIPTION + * + * This function returns the current value of the system clock. + * + * CALLED BY + * + * Application + * + * CALLS + * + * None + * + * INPUTS + * + * None + * + * OUTPUTS + * + * TMD_System_Clock Value of system clock + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@UNSIGNED TMT_Retrieve_Clock(void) +@{ + + .globl TMT_Retrieve_Clock +TMT_Retrieve_Clock: + +@ Return the current value of the system clock. +@ return(TMD_System_Clock); + + LDR r0,System_Clock @ Build address to system clock + LDR r0,[r0,#0] @ Pickup system clock contents + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TMT_Read_Timer + * + * DESCRIPTION + * + * This function returns the current value of the count-down timer. + * + * CALLED BY + * + * TMC_Start_Timer Start timer function + * + * CALLS + * + * None + * + * INPUTS + * + * None + * + * OUTPUTS + * + * TMD_Timer Value of count-down timer + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@UNSIGNED TMT_Read_Timer(void) +@{ + + .globl TMT_Read_Timer +TMT_Read_Timer: + +@ Return the current value of the count-down timer. +@ return(TMD_Timer); + + LDR r0,Timer @ Build address to timer + LDR r0,[r0,#0] @ Pickup timer contents + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TMT_Enable_Timer + * + * DESCRIPTION + * + * This function enables the count-down timer with the specified + * value. + * + * CALLED BY + * + * TMC_Start_Timer Start timer function + * TMC_Timer_Task Timer expiration task + * + * CALLS + * + * None + * + * INPUTS + * + * time New count-down time + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@VOID TMT_Enable_Timer(UNSIGNED time) +@{ + + .globl TMT_Enable_Timer +TMT_Enable_Timer: + +@ Place the new time value into the count-down timer. +@ TMD_Timer = time; + + LDR r1,Timer @ Build address of timer + STR r0,[r1,#0] @ Store new timer value + +@ Indicate that the timer is active. +@ TMD_Timer_State = TM_ACTIVE; + + MOV r0,#0 @ Build TM_ACTIVE value + LDR r1,Timer_State @ Build address of timer state var + STR r0,[r1,#0] @ Change the state to active + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TMT_Adjust_Timer + * + * DESCRIPTION + * + * This function adjusts the count-down timer with the specified + * value, if the new value is less than the current. + * + * CALLED BY + * + * None + * + * CALLS + * + * None + * + * INPUTS + * + * time New count-down time. + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * C. Meredith 03-01-1994 Created initial version 1.1 + * D. Lamie 03-18-1994 Verified version 1.1 + * C. Meredith 08-27-1994 Corrected bug in new timer + * adjust routine, resulting in + * version 1.1a + * W. Lamie 08-27-1994 Verified version 1.1a + * + ************************************************************************ + */ + +@VOID TMT_Adjust_Timer(UNSIGNED time) +@{ + + .globl TMT_Adjust_Timer +TMT_Adjust_Timer: + +@ Lockout all interrupts +@ TMD_Timer_State = TM_NOT_ACTIVE; + + MRS r3,CPSR @ Pickup current CPSR + ORR r2,r3,#LOCKOUT @ Build lockout CPSR + MSR CPSR,r2 @ Setup new CPSR interrupt bits + +@ Check for the new value is less than the current time value +@ if (time < TMD_Timer) + + LDR r1,Timer @ Build address to timer var + LDR r2,[r1,#0] @ read value of the timer + CMP r2,r0 @ Do Timer - time > 0, means + BLT TMT_No_Adjust @ time < Timer. + +@ Adjust the time +@ TMD_Timer = time; + + STR r0,[r1,#0] @ load passed in timer value + +@ Return to caller after restoring interrupts + +TMT_No_Adjust: + + MSR CPSR,r3 @ Setup new CPSR enable bits + + BX r14 @ Return to caller +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TMT_Disable_Timer + * + * DESCRIPTION + * + * This function disables the count-down timer. + * + * CALLED BY + * + * TMC_Start_Timer Start timer function + * TMC_Timer_Task Timer expiration task + * + * CALLS + * + * None + * + * INPUTS + * + * None + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@VOID TMT_Disable_Timer(void) +@{ + + .globl TMT_Disable_Timer +TMT_Disable_Timer: + +@ Disable the count-down timer. +@ TMD_Timer_State = TM_NOT_ACTIVE; + + MOV r1,#1 @ Build TM_NOT_ACTIVE value + LDR r0,Timer_State @ Build address to timer state var + STR r1,[r0,#0] @ Change timer state to not active + + BX r14 @ Return to caller +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TMT_Retreive_TS_Timer + * + * DESCRIPTION + * + * This function returns the time-sliced task pointer. + * + * CALLED BY + * + * TMC_Timer_HISR Timer HISR + * + * CALLS + * + * None + * + * INPUTS + * + * None + * + * OUTPUTS + * + * TMD_Time_Slice_Task Time sliced task pointer + * + * HISTORY + * + * NAME DATE REMARKS + * + * C. Meredith 03-01-1994 Created initial version 1.1 + * D. Lamie 03-18-1994 Verified version 1.1 + * + ************************************************************************ + */ + +@NU_TASK TMT_Retrieve_TS_Task (VOID) +@{ + + .globl TMT_Retrieve_TS_Task +TMT_Retrieve_TS_Task: + +@ Read the current TMD_Time_Slice_Task variable and load for +@ return to caller. + + LDR r1,Slice_Task @ Build address to timer slice var + LDR r0,[r1,#0] @ Get task pointer to be returned + +@ Return to caller time slice value back to caller + + BX r14 @ Return to caller + +@} + +/* + ************************************************************************ + * + * FUNCTION + * + * TMT_Timer_Interrupt + * + * DESCRIPTION + * + * This function processes the actual hardware interrupt. + * Processing includes updating the system clock and the count- + * down timer and the time-slice timer. If one or both of the + * timers expire, the timer HISR is activated. + * + * CALLED BY + * + * Interrupt Vector + * + * CALLS + * + * TCT_Activate_HISR Activate timer HISR + * TCT_Interrupt_Context_Save Save interrupted context + * TCT_Interrupt_Context_Restore Restore interrupted context + * + * INPUTS + * + * None + * + * OUTPUTS + * + * None + * + * HISTORY + * + * NAME DATE REMARKS + * + * W. Lamie 02-15-1994 Created initial version 1.0 + * D. Lamie 02-15-1994 Verified version 1.0 + * + ************************************************************************ + */ + +@VOID TMT_Timer_Interrupt(void) +@{ + .globl TMT_Timer_Interrupt +TMT_Timer_Interrupt: + + MRS r1,CPSR @ Pickup current CPSR + ORR r1,r1,#LOCKOUT @ Set the interrupt lockout bits + MSR CPSR,r1 @ Lockout interrupts + +@ Increment the system clock. +@ TMD_System_Clock++; + + LDR r0,System_Clock @ Pickup system clock address + LDR r1,[r0,#0] @ Pickup system clock contents + ADD r1,r1,#1 @ Increment system clock + STR r1,[r0,#0] @ Store new system clock value + +@ Determine if the count-down timer is active. +@ if (TMD_Timer_State == TM_ACTIVE) +@ { + + LDR r1,Timer_State @ Build address to timer state flag + LDR r0,[r1,#0] @ Pickup timer state + MOV r3,#2 @ Build expired value + CMP r0,#0 @ Is there a timer active? + BNE TMT_No_Timer_Active @ No, skip timer processing + +@ Decrement the count-down timer. +@ TMD_Timer--; + + LDR r0,Timer @ Build timer address + LDR r2,[r0,#0] @ Pickup the current timer value + +@ Test if the Timer is at 0 and if so skip the decrement + cmp r2,#1 + beq EXPIRED + + SUBS r2,r2,#1 @ Decrement the timer value + STR r2,[r0,#0] @ Store the new timer value + + bne TMT_No_Timer_Active @ Skip over the Set Timer State + +@ Determine if the timer has expired. If so, modify the state +@ to indicate that it has expired. +@ if (TMD_Timer == 0) + +@ TMD_Timer_State = TM_EXPIRED; + +EXPIRED: + STREQ r3,[r1,#0] @ Change the timer state to + @ expired + +@ } +TMT_No_Timer_Active: + +@ Determine if the time-slice timer is active. Note that the parameters +@ for the time-slice are controlled by the Thread Control (TC) +@ component. +@ if (TMD_Time_Slice_State == TM_ACTIVE) +@ { + LDR r0,Slice_State @ Build time slice state address + LDR r2,[r0,#0] @ Pickup time slice state + CMP r2,#0 @ Is there a time slice active? + BNE TMT_No_Time_Slice_Active @ No, skip time slice processing + +@ Decrement the time slice counter. +@ TMD_Time_Slice--; + + LDR r2,Time_Slice @ Build time slice address + LDR r3,[r2,#0] @ Pickup the time slice value + SUBS r3,r3,#1 @ Decrement the time slice + STR r3,[r2,#0] @ Store the new time slice value + + @ Determine if the time-slice timer has expired. If so, modify the + @ time-slice state to indicate that it has. +@ if (TMD_Time_Slice == 0) +@ { + + BNE TMT_No_Time_Slice_Active @ Has time slice expired? + +@ TMD_Time_Slice_State = TM_EXPIRED; + + MOV r3,#2 @ Build TM_EXPIRED value + STR r3,[r0,#0] @ Indicate time slice is expired + + @ Copy the current thread into the time-slice task pointer. +@ TMD_Time_Slice_Task = TCD_Current_Thread; + + LDR r2,Current_Thread @ Pickup current thread pointer adr + LDR r2,[r2,#0] @ Pickup current thread pointer + LDR r3,Slice_Task @ Pickup time slice task pointer ad + STR r2,[r3,#0] @ Store current thread pointer + +@ ((TC_TCB *) TCD_Current_Thread) -> tc_cur_time_slice = 1; + + MOV r3,#1 @ For safety, place a minimal time- + STR a4,[a3,#0x20]! @ slice into the task's control + @ block + +@ } +@ } +TMT_No_Time_Slice_Active: + + @ Determine if either of the basic timers have expired. If so, + @ activate the timer HISR. +@ if ((TMD_Timer_State == TM_EXPIRED) || +@ (TMD_Time_Slice_State == TM_EXPIRED)) +@ { + + LDR r1,[r1,#0] @ Pickup timer state + CMP r1,#2 @ Does it indicate expiration? + LDRNE r0,[r0,#0] @ Pickup time slice state + CMPNE r0,#2 @ Does it indicate expiration? + + BXNE r14 @ Return if no expiration + + @ Activate the HISR timer function. +@ TCT_Activate_HISR(&TMD_HISR); + + STR r14,[r13, #-4]! @ Save r14 on the stack + LDR r0,HISR @ Build address of timer HISR + BL TCT_Activate_HISR @ Activate timer HISR + LDR r14,[r13], #4 @ Recover return address +@ } + + BX r14 @ Return to caller + +@}