summaryrefslogtreecommitdiff
path: root/Source/portable/Keil
diff options
context:
space:
mode:
authorrichardbarry <richardbarry@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>2006-05-02 09:39:15 +0000
committerrichardbarry <richardbarry@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>2006-05-02 09:39:15 +0000
commitd7dbc0659d07553731bf22aa298adcf5e5e7774d (patch)
treef263718a33f9a800d8ad8bfae7d7728cc24cff76 /Source/portable/Keil
parent007f75782c094f12e9fb8832dddb6b06bce236f8 (diff)
downloadfreertos-d7dbc0659d07553731bf22aa298adcf5e5e7774d.tar.gz
freertos-d7dbc0659d07553731bf22aa298adcf5e5e7774d.tar.bz2
freertos-d7dbc0659d07553731bf22aa298adcf5e5e7774d.tar.xz
First version under SVN is V4.0.1
git-svn-id: https://freertos.svn.sourceforge.net/svnroot/freertos/trunk@4 1d2547de-c912-0410-9cb9-b8ca96c0e9e2
Diffstat (limited to 'Source/portable/Keil')
-rw-r--r--Source/portable/Keil/ARM7/port.c242
-rw-r--r--Source/portable/Keil/ARM7/portISR.c244
-rw-r--r--Source/portable/Keil/ARM7/portmacro.h224
3 files changed, 710 insertions, 0 deletions
diff --git a/Source/portable/Keil/ARM7/port.c b/Source/portable/Keil/ARM7/port.c
new file mode 100644
index 00000000..8229533f
--- /dev/null
+++ b/Source/portable/Keil/ARM7/port.c
@@ -0,0 +1,242 @@
+/*
+ FreeRTOS V4.0.1 - Copyright (C) 2003-2006 Richard Barry.
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ FreeRTOS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with FreeRTOS; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ A special exception to the GPL can be applied should you wish to distribute
+ a combined work that includes FreeRTOS, without being obliged to provide
+ the source code for any proprietary components. See the licensing section
+ of http://www.FreeRTOS.org for full details of how and when the exception
+ can be applied.
+
+ ***************************************************************************
+ See http://www.FreeRTOS.org for documentation, latest information, license
+ and contact details. Please ensure to read the configuration and relevant
+ port sections of the online documentation.
+ ***************************************************************************
+*/
+
+
+/*-----------------------------------------------------------
+ * Implementation of functions defined in portable.h for the ARM7 port
+ * using the Keil compiler.
+ *
+ * Components that can be compiled to either ARM or THUMB mode are
+ * contained in this file. The ISR routines, which can only be compiled
+ * to ARM mode are contained in portISR.c.
+ *----------------------------------------------------------*/
+
+/*
+ Changes from V3.2.2
+
+ + Bug fix - The prescale value for the timer setup is now written to T0PR
+ instead of T0PC. This bug would have had no effect unless a prescale
+ value was actually used.
+*/
+
+/* Standard includes. */
+#include <stdlib.h>
+
+/* Scheduler includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+
+/* Constants required to setup the initial task context. */
+#define portINITIAL_SPSR ( ( portSTACK_TYPE ) 0x1f ) /* System mode, ARM mode, interrupts enabled. */
+#define portTHUMB_MODE_BIT ( ( portSTACK_TYPE ) 0x20 )
+#define portINSTRUCTION_SIZE ( ( portSTACK_TYPE ) 4 )
+#define portNO_CRITICAL_SECTION_NESTING ( ( portSTACK_TYPE ) 0 )
+
+/* Constants required to setup the tick ISR. */
+#define portENABLE_TIMER ( ( unsigned portCHAR ) 0x01 )
+#define portPRESCALE_VALUE 0x00
+#define portINTERRUPT_ON_MATCH ( ( unsigned portLONG ) 0x01 )
+#define portRESET_COUNT_ON_MATCH ( ( unsigned portLONG ) 0x02 )
+
+/* Constants required to setup the VIC for the tick ISR. */
+#define portTIMER_VIC_CHANNEL ( ( unsigned portLONG ) 0x0004 )
+#define portTIMER_VIC_CHANNEL_BIT ( ( unsigned portLONG ) 0x0010 )
+#define portTIMER_VIC_ENABLE ( ( unsigned portLONG ) 0x0020 )
+
+/*-----------------------------------------------------------*/
+
+/* Setup the timer to generate the tick interrupts. */
+static void prvSetupTimerInterrupt( void );
+
+/*
+ * The scheduler can only be started from ARM mode, so
+ * vPortISRStartFirstSTask() is defined in portISR.c.
+ */
+extern void vPortISRStartFirstTask( void );
+
+/*-----------------------------------------------------------*/
+
+/*
+ * See header file for description.
+ */
+portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )
+{
+portSTACK_TYPE *pxOriginalTOS;
+
+ /* Setup the initial stack of the task. The stack is set exactly as
+ expected by the portRESTORE_CONTEXT() macro.
+
+ Remember where the top of the (simulated) stack is before we place
+ anything on it. */
+ pxOriginalTOS = pxTopOfStack;
+
+ /* First on the stack is the return address - which in this case is the
+ start of the task. The offset is added to make the return address appear
+ as it would within an IRQ ISR. */
+ *pxTopOfStack = ( portSTACK_TYPE ) pxCode + portINSTRUCTION_SIZE;
+ pxTopOfStack--;
+
+ *pxTopOfStack = ( portSTACK_TYPE ) 0xaaaaaaaa; /* R14 */
+ pxTopOfStack--;
+ *pxTopOfStack = ( portSTACK_TYPE ) pxOriginalTOS; /* Stack used when task starts goes in R13. */
+ pxTopOfStack--;
+ *pxTopOfStack = ( portSTACK_TYPE ) 0x12121212; /* R12 */
+ pxTopOfStack--;
+ *pxTopOfStack = ( portSTACK_TYPE ) 0x11111111; /* R11 */
+ pxTopOfStack--;
+ *pxTopOfStack = ( portSTACK_TYPE ) 0x10101010; /* R10 */
+ pxTopOfStack--;
+ *pxTopOfStack = ( portSTACK_TYPE ) 0x09090909; /* R9 */
+ pxTopOfStack--;
+ *pxTopOfStack = ( portSTACK_TYPE ) 0x08080808; /* R8 */
+ pxTopOfStack--;
+ *pxTopOfStack = ( portSTACK_TYPE ) 0x07070707; /* R7 */
+ pxTopOfStack--;
+ *pxTopOfStack = ( portSTACK_TYPE ) 0x06060606; /* R6 */
+ pxTopOfStack--;
+ *pxTopOfStack = ( portSTACK_TYPE ) 0x05050505; /* R5 */
+ pxTopOfStack--;
+ *pxTopOfStack = ( portSTACK_TYPE ) 0x04040404; /* R4 */
+ pxTopOfStack--;
+ *pxTopOfStack = ( portSTACK_TYPE ) 0x03030303; /* R3 */
+ pxTopOfStack--;
+ *pxTopOfStack = ( portSTACK_TYPE ) 0x02020202; /* R2 */
+ pxTopOfStack--;
+ *pxTopOfStack = ( portSTACK_TYPE ) 0x01010101; /* R1 */
+ pxTopOfStack--;
+ *pxTopOfStack = ( portSTACK_TYPE ) pvParameters; /* R0 */
+ pxTopOfStack--;
+
+ /* The last thing onto the stack is the status register, which is set for
+ system mode, with interrupts enabled. */
+ *pxTopOfStack = ( portSTACK_TYPE ) portINITIAL_SPSR;
+
+ #ifdef KEIL_THUMB_INTERWORK
+ {
+ /* We want the task to start in thumb mode. */
+ *pxTopOfStack |= portTHUMB_MODE_BIT;
+ }
+ #endif
+
+ pxTopOfStack--;
+
+ /* The code generated by the Keil compiler does not maintain separate
+ stack and frame pointers. The portENTER_CRITICAL macro cannot therefore
+ use the stack as per other ports. Instead a variable is used to keep
+ track of the critical section nesting. This variable has to be stored
+ as part of the task context and is initially set to zero. */
+ *pxTopOfStack = portNO_CRITICAL_SECTION_NESTING;
+
+ return pxTopOfStack;
+}
+/*-----------------------------------------------------------*/
+
+portBASE_TYPE xPortStartScheduler( void )
+{
+ /* Start the timer that generates the tick ISR. */
+ prvSetupTimerInterrupt();
+
+ /* Start the first task. This is done from portISR.c as ARM mode must be
+ used. */
+ vPortISRStartFirstTask();
+
+ /* Should not get here! */
+ return 0;
+}
+/*-----------------------------------------------------------*/
+
+void vPortEndScheduler( void )
+{
+ /* It is unlikely that the ARM port will require this function as there
+ is nothing to return to. If this is required - stop the tick ISR then
+ return back to main. */
+}
+/*-----------------------------------------------------------*/
+
+static void prvSetupTimerInterrupt( void )
+{
+unsigned portLONG ulCompareMatch;
+
+ /* A 1ms tick does not require the use of the timer prescale. This is
+ defaulted to zero but can be used if necessary. */
+ T0PR = portPRESCALE_VALUE;
+
+ /* Calculate the match value required for our wanted tick rate. */
+ ulCompareMatch = configCPU_CLOCK_HZ / configTICK_RATE_HZ;
+
+ /* Protect against divide by zero. Using an if() statement still results
+ in a warning - hence the #if. */
+ #if portPRESCALE_VALUE != 0
+ {
+ ulCompareMatch /= ( portPRESCALE_VALUE + 1 );
+ }
+ #endif
+
+ T0MR0 = ulCompareMatch;
+
+ /* Generate tick with timer 0 compare match. */
+ T0MCR = portRESET_COUNT_ON_MATCH | portINTERRUPT_ON_MATCH;
+
+ /* Setup the VIC for the timer. */
+ VICIntSelect &= ~( portTIMER_VIC_CHANNEL_BIT );
+ VICIntEnable |= portTIMER_VIC_CHANNEL_BIT;
+
+ /* The ISR installed depends on whether the preemptive or cooperative
+ scheduler is being used. */
+ #if configUSE_PREEMPTION == 1
+ {
+ #ifdef KEIL_THUMB_INTERWORK
+ extern void ( vPreemptiveTick )( void ) __arm __task;
+ #else
+ extern void ( vPreemptiveTick )( void ) __task;
+ #endif
+
+ VICVectAddr0 = ( unsigned portLONG ) vPreemptiveTick;
+ }
+ #else
+ {
+ extern void ( vNonPreemptiveTick )( void ) __irq;
+
+ VICVectAddr0 = ( portLONG ) vNonPreemptiveTick;
+ }
+ #endif
+
+ VICVectCntl0 = portTIMER_VIC_CHANNEL | portTIMER_VIC_ENABLE;
+
+ /* Start the timer - interrupts are disabled when this function is called
+ so it is okay to do this here. */
+ T0TCR = portENABLE_TIMER;
+}
+/*-----------------------------------------------------------*/
+
+
+
diff --git a/Source/portable/Keil/ARM7/portISR.c b/Source/portable/Keil/ARM7/portISR.c
new file mode 100644
index 00000000..d8140df1
--- /dev/null
+++ b/Source/portable/Keil/ARM7/portISR.c
@@ -0,0 +1,244 @@
+/*
+ FreeRTOS V4.0.1 - Copyright (C) 2003-2006 Richard Barry.
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ FreeRTOS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with FreeRTOS; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ A special exception to the GPL can be applied should you wish to distribute
+ a combined work that includes FreeRTOS, without being obliged to provide
+ the source code for any proprietary components. See the licensing section
+ of http://www.FreeRTOS.org for full details of how and when the exception
+ can be applied.
+
+ ***************************************************************************
+ See http://www.FreeRTOS.org for documentation, latest information, license
+ and contact details. Please ensure to read the configuration and relevant
+ port sections of the online documentation.
+ ***************************************************************************
+*/
+
+
+/*-----------------------------------------------------------
+ * Components that can be compiled to either ARM or THUMB mode are
+ * contained in port.c The ISR routines, which can only be compiled
+ * to ARM mode, are contained in this file.
+ *----------------------------------------------------------*/
+
+/* This file must always be compiled to ARM mode as it contains ISR
+definitions. */
+#pragma ARM
+
+/* Scheduler includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+
+/* Constants required to handle interrupts. */
+#define portTIMER_MATCH_ISR_BIT ( ( unsigned portCHAR ) 0x01 )
+#define portCLEAR_VIC_INTERRUPT ( ( unsigned portLONG ) 0 )
+
+/*-----------------------------------------------------------*/
+
+/* The code generated by the Keil compiler does not maintain separate
+stack and frame pointers. The portENTER_CRITICAL macro cannot therefore
+use the stack as per other ports. Instead a variable is used to keep
+track of the critical section nesting. This variable has to be stored
+as part of the task context and must be initialised to a non zero value. */
+
+#define portNO_CRITICAL_NESTING ( ( unsigned portLONG ) 0 )
+volatile unsigned portLONG ulCriticalNesting = 9999UL;
+
+/*-----------------------------------------------------------*/
+
+/* ISR to handle manual context switches (from a call to taskYIELD()). */
+void vPortYieldProcessor( void );
+
+/*
+ * The scheduler can only be started from ARM mode, hence the inclusion of this
+ * function here.
+ */
+void vPortISRStartFirstTask( void );
+
+/*-----------------------------------------------------------*/
+
+void vPortISRStartFirstTask( void )
+{
+ /* Simply start the scheduler. This is included here as it can only be
+ called from ARM mode. */
+ portRESTORE_CONTEXT();
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * Interrupt service routine for the SWI interrupt. The vector table is
+ * configured within startup.s.
+ *
+ * vPortYieldProcessor() is used to manually force a context switch. The
+ * SWI interrupt is generated by a call to taskYIELD() or portYIELD().
+ */
+void vPortYieldProcessor( void ) __task
+{
+ /* Within an IRQ ISR the link register has an offset from the true return
+ address, but an SWI ISR does not. Add the offset manually so the same
+ ISR return code can be used in both cases. */
+ __asm{ ADD LR, LR, #4 };
+
+ /* Perform the context switch. */
+ portSAVE_CONTEXT();
+ vTaskSwitchContext();
+ portRESTORE_CONTEXT();
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * The ISR used for the scheduler tick depends on whether the cooperative or
+ * the preemptive scheduler is being used.
+ */
+
+#if configUSE_PREEMPTION == 0
+
+ /*
+ * The cooperative scheduler requires a normal IRQ service routine to
+ * simply increment the system tick.
+ */
+ void vNonPreemptiveTick( void );
+ void vNonPreemptiveTick( void ) __irq
+ {
+ /* Increment the tick count - this may make a delaying task ready
+ to run - but a context switch is not performed. */
+ vTaskIncrementTick();
+
+ /* Ready for the next interrupt. */
+ T0IR = portTIMER_MATCH_ISR_BIT;
+ VICVectAddr = portCLEAR_VIC_INTERRUPT;
+ }
+
+#else
+
+ /*
+ * The preemptive scheduler ISR is defined as "naked" as the full context
+ * is saved on entry as part of the context switch.
+ */
+ void vPreemptiveTick( void );
+ void vPreemptiveTick( void ) __task
+ {
+ /* Save the context of the current task. */
+ portSAVE_CONTEXT();
+
+ /* Increment the tick count - this may make a delayed task ready to
+ run. */
+ vTaskIncrementTick();
+
+ /* Find the highest priority task that is ready to run. */
+ vTaskSwitchContext();
+
+ /* Ready for the next interrupt. */
+ T0IR = portTIMER_MATCH_ISR_BIT;
+ VICVectAddr = portCLEAR_VIC_INTERRUPT;
+
+ /* Restore the context of the highest priority task that is ready to
+ run. */
+ portRESTORE_CONTEXT();
+ }
+#endif
+/*-----------------------------------------------------------*/
+
+/*
+ * The interrupt management utilities can only be called from ARM mode. When
+ * KEIL_THUMB_INTERWORK is defined the utilities are defined as functions here
+ * to ensure a switch to ARM mode. When KEIL_THUMB_INTERWORK is not defined
+ * then the utilities are defined as macros in portmacro.h - as per other
+ * ports.
+ */
+#ifdef KEIL_THUMB_INTERWORK
+
+ void vPortDisableInterruptsFromThumb( void ) __task;
+ void vPortEnableInterruptsFromThumb( void ) __task;
+
+ void vPortDisableInterruptsFromThumb( void ) __task
+ {
+ __asm{ STMDB SP!, {R0} }; /* Push R0. */
+ __asm{ MRS R0, CPSR }; /* Get CPSR. */
+ __asm{ ORR R0, R0, #0xC0 }; /* Disable IRQ, FIQ. */
+ __asm{ MSR CPSR_CXSF, R0 }; /* Write back modified value. */
+ __asm{ LDMIA SP!, {R0} }; /* Pop R0. */
+ __asm{ BX R14 }; /* Return back to thumb. */
+ }
+
+ void vPortEnableInterruptsFromThumb( void ) __task
+ {
+ __asm{ STMDB SP!, {R0} }; /* Push R0. */
+ __asm{ MRS R0, CPSR }; /* Get CPSR. */
+ __asm{ BIC R0, R0, #0xC0 }; /* Enable IRQ, FIQ. */
+ __asm{ MSR CPSR_CXSF, R0 }; /* Write back modified value. */
+ __asm{ LDMIA SP!, {R0} }; /* Pop R0. */
+ __asm{ BX R14 }; /* Return back to thumb. */
+ }
+
+#endif /* KEIL_THUMB_INTERWORK */
+
+
+
+/* The code generated by the Keil compiler does not maintain separate
+stack and frame pointers. The portENTER_CRITICAL macro cannot therefore
+use the stack as per other ports. Instead a variable is used to keep
+track of the critical section nesting. This necessitates the use of a
+function in place of the macro. */
+
+void vPortEnterCritical( void )
+{
+ /* Disable interrupts as per portDISABLE_INTERRUPTS(); */
+ __asm{ STMDB SP!, {R0} }; /* Push R0. */
+ __asm{ MRS R0, CPSR }; /* Get CPSR. */
+ __asm{ ORR R0, R0, #0xC0 }; /* Disable IRQ, FIQ. */
+ __asm{ MSR CPSR_CXSF, R0 }; /* Write back modified value. */
+ __asm{ LDMIA SP!, {R0} }; /* Pop R0. */
+
+ /* Now interrupts are disabled ulCriticalNesting can be accessed
+ directly. Increment ulCriticalNesting to keep a count of how many times
+ portENTER_CRITICAL() has been called. */
+ ulCriticalNesting++;
+}
+
+void vPortExitCritical( void )
+{
+ if( ulCriticalNesting > portNO_CRITICAL_NESTING )
+ {
+ /* Decrement the nesting count as we are leaving a critical section. */
+ ulCriticalNesting--;
+
+ /* If the nesting level has reached zero then interrupts should be
+ re-enabled. */
+ if( ulCriticalNesting == portNO_CRITICAL_NESTING )
+ {
+ /* Enable interrupts as per portEXIT_CRITICAL(). */
+ __asm{ STMDB SP!, {R0} }; /* Push R0. */
+ __asm{ MRS R0, CPSR }; /* Get CPSR. */
+ __asm{ BIC R0, R0, #0xC0 }; /* Enable IRQ, FIQ. */
+ __asm{ MSR CPSR_CXSF, R0 }; /* Write back modified value. */
+ __asm{ LDMIA SP!, {R0} }; /* Pop R0. */
+ }
+ }
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/Source/portable/Keil/ARM7/portmacro.h b/Source/portable/Keil/ARM7/portmacro.h
new file mode 100644
index 00000000..dc0b1b79
--- /dev/null
+++ b/Source/portable/Keil/ARM7/portmacro.h
@@ -0,0 +1,224 @@
+/*
+ FreeRTOS V4.0.1 - Copyright (C) 2003-2006 Richard Barry.
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ FreeRTOS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with FreeRTOS; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ A special exception to the GPL can be applied should you wish to distribute
+ a combined work that includes FreeRTOS, without being obliged to provide
+ the source code for any proprietary components. See the licensing section
+ of http://www.FreeRTOS.org for full details of how and when the exception
+ can be applied.
+
+ ***************************************************************************
+ See http://www.FreeRTOS.org for documentation, latest information, license
+ and contact details. Please ensure to read the configuration and relevant
+ port sections of the online documentation.
+ ***************************************************************************
+*/
+
+
+#ifndef PORTMACRO_H
+#define PORTMACRO_H
+
+/*-----------------------------------------------------------
+ * Port specific definitions.
+ *
+ * The settings in this file configure FreeRTOS correctly for the
+ * given hardware and compiler.
+ *
+ * These settings should not be altered.
+ *-----------------------------------------------------------
+ */
+
+/* Type definitions. */
+#define portCHAR char
+#define portFLOAT float
+#define portDOUBLE double
+#define portLONG long
+#define portSHORT short
+#define portSTACK_TYPE unsigned portLONG
+#define portBASE_TYPE portLONG
+
+#if( configUSE_16_BIT_TICKS == 1 )
+ typedef unsigned portSHORT portTickType;
+ #define portMAX_DELAY ( portTickType ) 0xffff
+#else
+ typedef unsigned portLONG portTickType;
+ #define portMAX_DELAY ( portTickType ) 0xffffffff
+#endif
+/*-----------------------------------------------------------*/
+
+/* Hardware specifics. */
+#define portSTACK_GROWTH ( -1 )
+#define portTICK_RATE_MS ( ( portTickType ) 1000 / configTICK_RATE_HZ )
+#define portBYTE_ALIGNMENT 4
+/*-----------------------------------------------------------*/
+
+/* Task utilities. */
+#define portRESTORE_CONTEXT() \
+{ \
+extern volatile unsigned portLONG ulCriticalNesting; \
+extern volatile void * volatile pxCurrentTCB; \
+ \
+ __asm{ LDR R1, =pxCurrentTCB };/* Set the LR to the task stack. The location was ... */ \
+ __asm{ LDR R0, [R1] }; /* ... stored in pxCurrentTCB. */ \
+ __asm{ LDR LR, [R0] }; \
+ \
+ __asm{ LDR R0, =ulCriticalNesting }; /* The critical nesting depth is the first item on ... */ \
+ __asm{ LDMFD LR!, {R1 } } /* ... the stack. Load it into the ulCriticalNesting var. */ \
+ __asm{ STR R1, [R0] } \
+ \
+ __asm{ LDMFD LR!, {R0} }; /* Get the SPSR from the stack. */ \
+ __asm{ MSR SPSR_CXSF, R0 }; \
+ \
+ __asm{ LDMFD LR, {R0-R14}^ }; /* Restore all system mode registers for the task. */ \
+ __asm{ NOP }; \
+ \
+ __asm{ LDR LR, [LR, #+60] }; /* Restore the return address. */ \
+ \
+ /* And return - correcting the offset in the LR to obtain ... */ \
+ __asm{ SUBS PC, LR, #4 }; /* ... the correct address. */ \
+}
+/*----------------------------------------------------------*/
+
+#define portSAVE_CONTEXT() \
+{ \
+extern volatile unsigned portLONG ulCriticalNesting; \
+extern volatile void * volatile pxCurrentTCB; \
+ \
+ __asm{ STMDB SP!, {R0} }; /* Store R0 first as we need to use it. */ \
+ \
+ __asm{ STMDB SP,{SP}^ }; /* Set R0 to point to the task stack pointer. */ \
+ __asm{ NOP }; \
+ __asm{ SUB SP, SP, #4 }; \
+ __asm{ LDMIA SP!,{R0} }; \
+ \
+ __asm{ STMDB R0!, {LR} }; /* Push the return address onto the stack. */ \
+ __asm{ MOV LR, R0 }; /* Now we have saved LR we can use it instead of R0. */ \
+ __asm{ LDMIA SP!, {R0} }; /* Pop R0 so we can save it onto the system mode stack. */ \
+ \
+ __asm{ STMDB LR,{R0-LR}^ }; /* Push all the system mode registers onto the task stack. */ \
+ __asm{ NOP }; \
+ __asm{ SUB LR, LR, #60 }; \
+ \
+ __asm{ MRS R0, SPSR }; /* Push the SPSR onto the task stack. */ \
+ __asm{ STMDB LR!, {R0} }; \
+ \
+ __asm{ LDR R0, =ulCriticalNesting }; \
+ __asm{ LDR R0, [R0] }; \
+ __asm{ STMDB LR!, {R0} }; \
+ \
+ __asm{ LDR R0, =pxCurrentTCB };/* Store the new top of stack for the task. */ \
+ __asm{ LDR R1, [R0] }; \
+ __asm{ STR LR, [R1] }; \
+}
+
+/*-----------------------------------------------------------
+ * ISR entry and exit macros. These are only required if a task switch
+ * is required from an ISR.
+ *----------------------------------------------------------*/
+
+#define portENTER_SWITCHING_ISR() \
+ portSAVE_CONTEXT(); \
+ {
+
+#define portEXIT_SWITCHING_ISR( SwitchRequired ) \
+ /* If a switch is required then we just need to call */ \
+ /* vTaskSwitchContext() as the context has already been */ \
+ /* saved. */ \
+ if( SwitchRequired ) \
+ { \
+ vTaskSwitchContext(); \
+ } \
+ } \
+ /* Restore the context of which ever task is now the highest */ \
+ /* priority that is ready to run. */ \
+ portRESTORE_CONTEXT();
+
+
+/* Yield the processor - force a context switch. */
+#define portYIELD() __asm{ SWI 0 };
+/*-----------------------------------------------------------*/
+
+/* Critical section management. */
+
+/*-----------------------------------------------------------
+ * Interrupt control macros.
+ *
+ * The interrupt management utilities can only be called from ARM mode. When
+ * KEIL_THUMB_INTERWORK is defined the utilities are defined as functions in
+ * portISR.c to ensure a switch to ARM mode. When KEIL_THUMB_INTERWORK is not
+ * defined then the utilities are defined as macros here - as per other ports.
+ *----------------------------------------------------------*/
+
+#ifdef KEIL_THUMB_INTERWORK
+
+ extern void vPortDisableInterruptsFromThumb( void ) __task;
+ extern void vPortEnableInterruptsFromThumb( void ) __task;
+
+ #define portDISABLE_INTERRUPTS() vPortDisableInterruptsFromThumb()
+ #define portENABLE_INTERRUPTS() vPortEnableInterruptsFromThumb()
+
+#else
+
+ /*-----------------------------------------------------------*/
+
+ #define portDISABLE_INTERRUPTS() \
+ __asm{ STMDB SP!, {R0} }; /* Push R0. */ \
+ __asm{ MRS R0, CPSR }; /* Get CPSR. */ \
+ __asm{ ORR R0, R0, #0xC0 }; /* Disable IRQ, FIQ. */ \
+ __asm{ MSR CPSR_CXSF, R0 }; /* Write back modified value. */ \
+ __asm{ LDMIA SP!, {R0} } /* Pop R0. */
+
+ #define portENABLE_INTERRUPTS() \
+ __asm{ STMDB SP!, {R0} }; /* Push R0. */ \
+ __asm{ MRS R0, CPSR }; /* Get CPSR. */ \
+ __asm{ BIC R0, R0, #0xC0 }; /* Enable IRQ, FIQ. */ \
+ __asm{ MSR CPSR_CXSF, R0 }; /* Write back modified value. */ \
+ __asm{ LDMIA SP!, {R0} } /* Pop R0. */
+
+#endif /* KEIL_THUMB_INTERWORK */
+
+/*-----------------------------------------------------------
+ * Critical section control
+ *
+ * The code generated by the Keil compiler does not maintain separate
+ * stack and frame pointers. The portENTER_CRITICAL macro cannot therefore
+ * use the stack as per other ports. Instead a variable is used to keep
+ * track of the critical section nesting. This necessitates the use of a
+ * function in place of the macro.
+ *----------------------------------------------------------*/
+
+extern void vPortEnterCritical( void );
+extern void vPortExitCritical( void );
+
+#define portENTER_CRITICAL() vPortEnterCritical();
+#define portEXIT_CRITICAL() vPortExitCritical();
+/*-----------------------------------------------------------*/
+
+/* Compiler specifics. */
+#define inline
+#define register
+#define portNOP() __asm{ NOP }
+/*-----------------------------------------------------------*/
+
+/* Task function macros as described on the FreeRTOS.org WEB site. */
+#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters ) __task
+#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
+
+#endif /* PORTMACRO_H */
+