FreeCalypso > hg > fc-tourmaline
view src/nucleus/gcc/tct.S @ 267:10b3a6876273
fc-target.h preprocessor symbols: introduce CONFIG_TARGET_LEO_RFFE
Out of our currently existing supported targets, Leonardo and Tango
use TI's classic Leonardo RFFE wiring. However, we would like to
use the same quadband RFFE with the same classic wiring on our
FreeCalypso Libre Dumbphone handset, and also on the planned
development board that will serve as a stepping stone toward that
goal. Therefore, we introduce the new CONFIG_TARGET_LEO_RFFE
preprocessor symbol, and conditionalize on this symbol in tpudrv12.h,
instead of a growing || of different targets.
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Wed, 09 Jun 2021 07:26:51 +0000 |
parents | 4e78acac3d88 |
children |
line wrap: on
line source
/* ************************************************************************ * * 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" .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 1 /* was CONFIG_INCLUDE_L1 in Citrine */ 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