view src/nucleus/gcc/tct.S @ 303:f76436d19a7a default tip

!GPRS config: fix long-standing AT+COPS chance hanging bug There has been a long-standing bug in FreeCalypso going back years: sometimes in the AT command bring-up sequence of an ACI-only MS, the AT+COPS command would produce only a power scan followed by cessation of protocol stack activity (only L1 ADC traces), instead of the expected network search sequence. This behaviour was seen in different FC firmware versions going back to Citrine, and seemed to follow some law of chance, not reliably repeatable. This bug has been tracked down and found to be specific to !GPRS configuration, stemming from our TCS2/TCS3 hybrid and reconstruction of !GPRS support that was bitrotten in TCS3.2/LoCosto version. ACI module psa_mms.c, needed only for !GPRS, was missing in the TCS3 version and had to be pulled from TCS2 - but as it turns out, there is a new field in the MMR_REG_REQ primitive that needs to be set correctly, and that psa_mms.c module is the place where this initialization needed to be added.
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 08 Jun 2023 08:23:37 +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