From 6f1890f2a5b581193afc4e6d39f22232c2d6f482 Mon Sep 17 00:00:00 2001 From: richardbarry Date: Wed, 15 Jun 2011 16:42:04 +0000 Subject: [PATCH] Add optional FPU support to the MicroBlaze code. Rearrange the order in which registers are saved to the stack in an interrupt to make it more logical, and introduce #defines for the offset from the stack pointer for each variable. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@1459 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- .../portable/GCC/MicroBlaze/port.c | 27 +- .../portable/GCC/MicroBlaze/portasm.S | 237 +++++++++++------- 2 files changed, 161 insertions(+), 103 deletions(-) diff --git a/Demo/MicroBlaze_Spartan-6_EthernetLite/SDKProjects/RTOSDemoSource/FreeRTOS_Source/portable/GCC/MicroBlaze/port.c b/Demo/MicroBlaze_Spartan-6_EthernetLite/SDKProjects/RTOSDemoSource/FreeRTOS_Source/portable/GCC/MicroBlaze/port.c index 38d271c55..11dc1aedc 100644 --- a/Demo/MicroBlaze_Spartan-6_EthernetLite/SDKProjects/RTOSDemoSource/FreeRTOS_Source/portable/GCC/MicroBlaze/port.c +++ b/Demo/MicroBlaze_Spartan-6_EthernetLite/SDKProjects/RTOSDemoSource/FreeRTOS_Source/portable/GCC/MicroBlaze/port.c @@ -64,6 +64,7 @@ #include /* Hardware includes. */ +#include #include #include #include @@ -78,6 +79,7 @@ to reach zero, so it is initialised to a high value. */ /* The bit within the MSR register that enabled/disables interrupts. */ #define portMSR_IE ( 0x02U ) +#define portINITIAL_FSR ( 0U ) /*-----------------------------------------------------------*/ /* @@ -138,6 +140,18 @@ const unsigned long ulR13 = ( unsigned long ) &_SDA_BASE_; *pxTopOfStack = ( portSTACK_TYPE ) 0x00000000; pxTopOfStack--; + #if XPAR_MICROBLAZE_0_USE_FPU == 1 + /* The FSR value placed in the initial task context is just 0. */ + *pxTopOfStack = portINITIAL_FSR; + pxTopOfStack--; + #endif + + /* The MSR value placed in the initial task context should have interrupts + disabled. Each task will enable interrupts automatically when it enters + the running state for the first time. */ + *pxTopOfStack = mfmsr() & ~portMSR_IE; + pxTopOfStack--; + /* First stack an initial value for the critical section nesting. This is initialised to zero. */ *pxTopOfStack = ( portSTACK_TYPE ) 0x00; @@ -205,13 +219,6 @@ const unsigned long ulR13 = ( unsigned long ) &_SDA_BASE_; pxTopOfStack--; *pxTopOfStack = ( portSTACK_TYPE ) 0x1e; /* R30 - must be saved across function calls. Callee-save. */ pxTopOfStack--; - - /* The MSR is stacked between R30 and R31. This should have interrupts - disabled. Each task will enable interrupts automatically when it enters - the running state for the first time. */ - *pxTopOfStack = mfmsr() & ~portMSR_IE; - pxTopOfStack--; - *pxTopOfStack = ( portSTACK_TYPE ) 0x1f; /* R31 - must be saved across function calls. Callee-save. */ pxTopOfStack--; @@ -230,12 +237,8 @@ extern unsigned long _stack[]; this function is called. */ vApplicationSetupTimerInterrupt(); - /* Reuse the stack from main as the stack for the interrupts/exceptions. - The value is adjusted slightly to allow functions called from the - interrupts/exceptions to write back into the stack of the interrupt/ - exception function itself. */ + /* Reuse the stack from main as the stack for the interrupts/exceptions. */ pulISRStack = ( unsigned long * ) _stack; - pulISRStack -= 2; /* Restore the context of the first task that is going to run. From here on, the created tasks will be executing. */ diff --git a/Demo/MicroBlaze_Spartan-6_EthernetLite/SDKProjects/RTOSDemoSource/FreeRTOS_Source/portable/GCC/MicroBlaze/portasm.S b/Demo/MicroBlaze_Spartan-6_EthernetLite/SDKProjects/RTOSDemoSource/FreeRTOS_Source/portable/GCC/MicroBlaze/portasm.S index ed32a5b28..2621c6ead 100644 --- a/Demo/MicroBlaze_Spartan-6_EthernetLite/SDKProjects/RTOSDemoSource/FreeRTOS_Source/portable/GCC/MicroBlaze/portasm.S +++ b/Demo/MicroBlaze_Spartan-6_EthernetLite/SDKProjects/RTOSDemoSource/FreeRTOS_Source/portable/GCC/MicroBlaze/portasm.S @@ -58,6 +58,50 @@ */ #include "FreeRTOSConfig.h" +#include "xparameters.h" + +/* The context is oversized to allow functions called from the ISR to write +back into the caller stack. */ +#if XPAR_MICROBLAZE_0_USE_FPU == 1 + #define portCONTEXT_SIZE 136 +#else + #define portCONTEXT_SIZE 132 +#endif + +/* Offsets from the stack pointer at which saved registers are placed. */ +#define portR31_OFFSET 4 +#define portR30_OFFSET 8 +#define portR29_OFFSET 12 +#define portR28_OFFSET 16 +#define portR27_OFFSET 20 +#define portR26_OFFSET 24 +#define portR25_OFFSET 28 +#define portR24_OFFSET 32 +#define portR23_OFFSET 36 +#define portR22_OFFSET 40 +#define portR21_OFFSET 44 +#define portR20_OFFSET 48 +#define portR19_OFFSET 52 +#define portR18_OFFSET 56 +#define portR17_OFFSET 60 +#define portR16_OFFSET 64 +#define portR15_OFFSET 68 +#define portR14_OFFSET 72 +#define portR13_OFFSET 76 +#define portR12_OFFSET 80 +#define portR11_OFFSET 84 +#define portR10_OFFSET 88 +#define portR9_OFFSET 92 +#define portR8_OFFSET 96 +#define portR7_OFFSET 100 +#define portR6_OFFSET 104 +#define portR5_OFFSET 108 +#define portR4_OFFSET 112 +#define portR3_OFFSET 116 +#define portR2_OFFSET 120 +#define portCRITICAL_NESTING_OFFSET 124 +#define portMSR_OFFSET 128 +#define portFSR_OFFSET 132 .extern pxCurrentTCB .extern XIntc_DeviceInterruptHandler @@ -73,47 +117,53 @@ .macro portSAVE_CONTEXT /* Make room for the context on the stack. */ - addik r1, r1, -132 - - /* Save r31 so it can then be used as a temporary. */ - swi r31, r1, 4 - - /* Copy the msr into r31 - this is stacked later. */ - mfs r31, rmsr + addik r1, r1, -portCONTEXT_SIZE /* Stack general registers. */ - swi r30, r1, 12 - swi r29, r1, 16 - swi r28, r1, 20 - swi r27, r1, 24 - swi r26, r1, 28 - swi r25, r1, 32 - swi r24, r1, 36 - swi r23, r1, 40 - swi r22, r1, 44 - swi r21, r1, 48 - swi r20, r1, 52 - swi r19, r1, 56 - swi r18, r1, 60 - swi r17, r1, 64 - swi r16, r1, 68 - swi r15, r1, 72 - swi r13, r1, 80 - swi r12, r1, 84 - swi r11, r1, 88 - swi r10, r1, 92 - swi r9, r1, 96 - swi r8, r1, 100 - swi r7, r1, 104 - swi r6, r1, 108 - swi r5, r1, 112 - swi r4, r1, 116 - swi r3, r1, 120 - swi r2, r1, 124 + swi r31, r1, portR31_OFFSET + swi r30, r1, portR30_OFFSET + swi r29, r1, portR29_OFFSET + swi r28, r1, portR28_OFFSET + swi r27, r1, portR27_OFFSET + swi r26, r1, portR26_OFFSET + swi r25, r1, portR25_OFFSET + swi r24, r1, portR24_OFFSET + swi r23, r1, portR23_OFFSET + swi r22, r1, portR22_OFFSET + swi r21, r1, portR21_OFFSET + swi r20, r1, portR20_OFFSET + swi r19, r1, portR19_OFFSET + swi r18, r1, portR18_OFFSET + swi r17, r1, portR17_OFFSET + swi r16, r1, portR16_OFFSET + swi r15, r1, portR15_OFFSET + /* R14 is saved later as it needs adjustment if a yield is performed. */ + swi r13, r1, portR13_OFFSET + swi r12, r1, portR12_OFFSET + swi r11, r1, portR11_OFFSET + swi r10, r1, portR10_OFFSET + swi r9, r1, portR9_OFFSET + swi r8, r1, portR8_OFFSET + swi r7, r1, portR7_OFFSET + swi r6, r1, portR6_OFFSET + swi r5, r1, portR5_OFFSET + swi r4, r1, portR4_OFFSET + swi r3, r1, portR3_OFFSET + swi r2, r1, portR2_OFFSET /* Stack the critical section nesting value. */ - lwi r3, r0, uxCriticalNesting - swi r3, r1, 128 + lwi r18, r0, uxCriticalNesting + swi r18, r1, portCRITICAL_NESTING_OFFSET + + /* Stack MSR. */ + mfs r18, rmsr + swi r18, r1, portMSR_OFFSET + + #if XPAR_MICROBLAZE_0_USE_FPU == 1 + /* Stack FSR. */ + mfs r18, rfsr + swi r18, r1, portFSR_OFFSET + #endif /* Save the top of stack value to the TCB. */ lwi r3, r0, pxCurrentTCB @@ -124,60 +174,66 @@ .macro portRESTORE_CONTEXT /* Load the top of stack value from the TCB. */ - lwi r3, r0, pxCurrentTCB - lw r1, r0, r3 + lwi r18, r0, pxCurrentTCB + lw r1, r0, r18 /* Restore the general registers. */ - lwi r31, r1, 4 - lwi r30, r1, 12 - lwi r29, r1, 16 - lwi r28, r1, 20 - lwi r27, r1, 24 - lwi r26, r1, 28 - lwi r25, r1, 32 - lwi r24, r1, 36 - lwi r23, r1, 40 - lwi r22, r1, 44 - lwi r21, r1, 48 - lwi r20, r1, 52 - lwi r19, r1, 56 - lwi r18, r1, 60 - lwi r17, r1, 64 - lwi r16, r1, 68 - lwi r15, r1, 72 - lwi r14, r1, 76 - lwi r13, r1, 80 - lwi r12, r1, 84 - lwi r11, r1, 88 - lwi r10, r1, 92 - lwi r9, r1, 96 - lwi r8, r1, 100 - lwi r7, r1, 104 - lwi r6, r1, 108 - lwi r5, r1, 112 - lwi r4, r1, 116 - lwi r2, r1, 124 + lwi r31, r1, portR31_OFFSET + lwi r30, r1, portR30_OFFSET + lwi r29, r1, portR29_OFFSET + lwi r28, r1, portR28_OFFSET + lwi r27, r1, portR27_OFFSET + lwi r26, r1, portR26_OFFSET + lwi r25, r1, portR25_OFFSET + lwi r24, r1, portR24_OFFSET + lwi r23, r1, portR23_OFFSET + lwi r22, r1, portR22_OFFSET + lwi r21, r1, portR21_OFFSET + lwi r20, r1, portR20_OFFSET + lwi r19, r1, portR19_OFFSET + lwi r17, r1, portR17_OFFSET + lwi r16, r1, portR16_OFFSET + lwi r15, r1, portR15_OFFSET + lwi r14, r1, portR14_OFFSET + lwi r13, r1, portR13_OFFSET + lwi r12, r1, portR12_OFFSET + lwi r11, r1, portR11_OFFSET + lwi r10, r1, portR10_OFFSET + lwi r9, r1, portR9_OFFSET + lwi r8, r1, portR8_OFFSET + lwi r7, r1, portR7_OFFSET + lwi r6, r1, portR6_OFFSET + lwi r5, r1, portR5_OFFSET + lwi r4, r1, portR4_OFFSET + lwi r3, r1, portR3_OFFSET + lwi r2, r1, portR2_OFFSET /* Reload the rmsr from the stack. */ - lwi r3, r1, 8 - mts rmsr, r3 + lwi r18, r1, portMSR_OFFSET + mts rmsr, r18 + + #if XPAR_MICROBLAZE_0_USE_FPU == 1 + /* Reload the FSR from the stack. */ + lwi r18, r1, portFSR_OFFSET + mts rfsr, r18 + #endif /* Load the critical nesting value. */ - lwi r3, r1, 128 - swi r3, r0, uxCriticalNesting + lwi r18, r1, portCRITICAL_NESTING_OFFSET + swi r18, r0, uxCriticalNesting /* Test the critical nesting value. If it is non zero then the task last exited the running state using a yield. If it is zero, then the task last exited the running state through an interrupt. */ - xori r3, r3, 0 - bnei r3, exit_from_yield + xori r18, r18, 0 + bnei r18, exit_from_yield - /* r3 was being used as a temporary. Now restore its true value from the + /* r18 was being used as a temporary. Now restore its true value from the stack. */ - lwi r3, r1, 120 + lwi r18, r1, portR18_OFFSET /* Remove the stack frame. */ - addik r1, r1, 132 + addik r1, r1, portCONTEXT_SIZE /* Return using rtid so interrupts are re-enabled as this function is exited. */ @@ -186,35 +242,33 @@ .endm - .text - .align 2 - /* This function is used to exit portRESTORE_CONTEXT() if the task being returned to last left the Running state by calling taskYIELD() (rather than being preempted by an interrupt. */ + .text + .align 2 exit_from_yield: - /* r3 was being used as a temporary. Now restore its true value from the + /* r18 was being used as a temporary. Now restore its true value from the stack. */ - lwi r3, r1, 120 + lwi r18, r1, portR18_OFFSET /* Remove the stack frame. */ - addik r1, r1, 132 + addik r1, r1, portCONTEXT_SIZE /* Return to the task. */ rtsd r14, 0 or r0, r0, r0 + .text + .align 2 _interrupt_handler: portSAVE_CONTEXT - /* Stack msr. */ - swi r31, r1, 8 - /* Stack the return address. */ - swi r14, r1, 76 + swi r14, r1, portR14_OFFSET /* Switch to the ISR stack. The pulISRStack value has already been set to leave space for the caller function to write back into the stack of this @@ -232,17 +286,16 @@ _interrupt_handler: portRESTORE_CONTEXT + .text + .align 2 VPortYieldASM: portSAVE_CONTEXT - /* Stack msr. */ - swi r31, r1, 8 - /* Modify the return address so a return is done to the instruction after the call to VPortYieldASM. */ addi r14, r14, 8 - swi r14, r1, 76 + swi r14, r1, portR14_OFFSET /* Switch to use the ISR stack. */ lwi r1, r0, pulISRStack @@ -254,6 +307,8 @@ VPortYieldASM: /* Restore the context of the next task scheduled to execute. */ portRESTORE_CONTEXT + .text + .align 2 vPortStartFirstTask: portRESTORE_CONTEXT -- 2.39.5