FreeCalypso > hg > fc-tourmaline
view src/nucleus/gcc/tct.S @ 26:598958aec071
components: switch to new Nucleus
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Fri, 16 Oct 2020 17:26:36 +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