Move the RISC-V pxPortInitialiseStack() implementation to the assembly port file from the C port file so it can have access to the number of chip specific registers it needs to save space for on the stack.

This commit is contained in:
Richard Barry 2018-12-30 20:00:43 +00:00
parent 911a1de273
commit 60b133b2c6
6 changed files with 195 additions and 149 deletions

View File

@ -107,6 +107,7 @@
#define configUSE_APPLICATION_TASK_TAG 0
#define configUSE_COUNTING_SEMAPHORES 1
#define configGENERATE_RUN_TIME_STATS 0
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
/* Co-routine definitions. */
#define configUSE_CO_ROUTINES 0
@ -142,7 +143,4 @@ to exclude the API function. */
header file. */
#define configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); __asm volatile( "ebreak" ); for( ;; ); }
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
#endif /* FREERTOS_CONFIG_H */

View File

@ -57,6 +57,6 @@
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="4"/>
</listAttribute>
<stringAttribute key="org.eclipse.dsf.launch.MEMORY_BLOCKS" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;memoryBlockExpressionList context=&quot;Context string&quot;&gt;&#13;&#10; &lt;memoryBlockExpression address=&quot;2147525816&quot; label=&quot;0x8000a4b8&quot;/&gt;&#13;&#10;&lt;/memoryBlockExpressionList&gt;&#13;&#10;"/>
<stringAttribute key="org.eclipse.dsf.launch.MEMORY_BLOCKS" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;memoryBlockExpressionList context=&quot;Context string&quot;&gt;&#13;&#10; &lt;memoryBlockExpression address=&quot;2147504144&quot; label=&quot;0x80005010&quot;/&gt;&#13;&#10;&lt;/memoryBlockExpressionList&gt;&#13;&#10;"/>
<stringAttribute key="process_factory_id" value="org.eclipse.cdt.dsf.gdb.GdbProcessFactory"/>
</launchConfiguration>

View File

@ -44,7 +44,7 @@
* base set of RISC-V registers. There are additional
* freertos_risc_v_port_specific_extensions.h files for RISC-V implementations
* that do not include a standard CLINT or do add to the base set of RISC-V
* regiters.
* registers.
*
* CARE MUST BE TAKEN TO INCLDUE THE CORRECT
* freertos_risc_v_port_specific_extensions.h HEADER FILE FOR THE CHIP
@ -62,5 +62,15 @@
#define __FREERTOS_RISC_V_EXTENSIONS_H__
#define portasmHAS_CLINT 1
#define portasmADDITIONAL_CONTEXT_SIZE 0 /* Must be even number on 32-bit cores. */
.macro portasmSAVE_ADDITIONAL_REGISTERS
/* No additional registers to save, so this macro does nothing. */
.endm
/* Restore the additional registers found on the Pulpino. */
.macro portasmRESTORE_ADDITIONAL_REGISTERS
/* No additional registers to restore, so this macro does nothing. */
.endm
#endif /* __FREERTOS_RISC_V_EXTENSIONS_H__ */

View File

@ -44,7 +44,7 @@
* base set of RISC-V registers. There are additional
* freertos_risc_v_port_specific_extensions.h files for RISC-V implementations
* that do not include a standard CLINT or do add to the base set of RISC-V
* regiters.
* registers.
*
* CARE MUST BE TAKEN TO INCLDUE THE CORRECT
* freertos_risc_v_port_specific_extensions.h HEADER FILE FOR THE CHIP
@ -62,12 +62,49 @@
#define portasmHAS_CLINT 0
/* Constants to define the additional registers found on the Pulpino RI5KY. */
#define lpstart0 0x7b0
#define lpend0 0x7b1
#define lpcount0 0x7b2
#define lpstart1 0x7b4
#define lpend1 0x7b5
#define lpcount1 0x7b6
/* Six additional registers to save and restore, as per the #defines above. */
#define portasmADDITIONAL_CONTEXT_SIZE 6 /* Must be even number on 32-bit cores. */
/* Save additional registers found on the Pulpino. */
.macro portasmSAVE_ADDITIONAL_REGISTERS
addi sp, sp, -portasmADDITIONAL_CONTEXT_SIZE /* Make room for the additional registers. */
csrr t0, lpstart0 /* Load additional registers into accessable temporary registers. */
csrr t1, lpend0
csrr t2, lpcount0
csrr t3, lpstart1
csrr t4, lpend1
csrr t5, lpcount1
sw t0, 1 * portWORD_SIZE( sp )
sw t1, 2 * portWORD_SIZE( sp )
sw t2, 3 * portWORD_SIZE( sp )
sw t3, 4 * portWORD_SIZE( sp )
sw t4, 5 * portWORD_SIZE( sp )
sw t5, 6 * portWORD_SIZE( sp )
.endm
/* Restore the additional registers found on the Pulpino. */
.macro portasmRESTORE_ADDITIONAL_REGISTERS
/* This file is for use with chips that do not add to the standard RISC-V
* register set, so there is nothing to do here. */
lw t0, 1 * portWORD_SIZE( sp ) /* Load additional registers into accessable temporary registers. */
lw t1, 2 * portWORD_SIZE( sp )
lw t2, 3 * portWORD_SIZE( sp )
lw t3, 4 * portWORD_SIZE( sp )
lw t4, 5 * portWORD_SIZE( sp )
lw t5, 6 * portWORD_SIZE( sp )
csrw lpstart0, t0
csrw lpend0, t1
csrw lpcount0, t2
csrw lpstart1, t3
csrw lpend1, t4
csrw lpcount1, t5
addi sp, sp, -portasmADDITIONAL_CONTEXT_SIZE /* Remove space added for additional registers. */
.endm
#endif /* __FREERTOS_RISC_V_EXTENSIONS_H__ */

View File

@ -34,13 +34,28 @@
#include "task.h"
#include "portmacro.h"
#ifdef configISR_STACK_SIZE
/* The stack used by interrupt service routines. */
static __attribute__ ((aligned(16))) StackType_t xISRStack[ configISR_STACK_SIZE ] = { 0 };
const StackType_t * const xISRStackTop = &( xISRStack[ ( configISR_STACK_SIZE & ~portBYTE_ALIGNMENT_MASK ) - 1 ] );
/* Let the user override the pre-loading of the initial LR with the address of
prvTaskExitError() in case it messes up unwinding of the stack in the
debugger. */
#ifdef configTASK_RETURN_ADDRESS
#define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS
#else
#define portTASK_RETURN_ADDRESS prvTaskExitError
#endif
/* The stack used by interrupt service routines. Set configISR_STACK_SIZE_WORDS
to use a statically allocated array as the interrupt stack. Alternative leave
configISR_STACK_SIZE_WORDS undefined and update the linker script so that a
linker variable names __freertos_irq_stack_top has the same value as the top
of the stack used by main. Using the linker script method will repurpose the
stack that was used by main before the scheduler was started for use as the
interrupt stack after the scheduler has started. */
#ifdef configISR_STACK_SIZE_WORDS
static __attribute__ ((aligned(16))) StackType_t xISRStack[ configISR_STACK_SIZE_WORDS ] = { 0 };
const StackType_t xISRStackTop = ( StackType_t ) &( xISRStack[ ( configISR_STACK_SIZE_WORDS & ~portBYTE_ALIGNMENT_MASK ) - 1 ] );
#else
extern const uint32_t __freertos_irq_stack_top[];
const uint32_t xISRStackTop = ( uint32_t ) __freertos_irq_stack_top;
const StackType_t xISRStackTop = ( StackType_t ) __freertos_irq_stack_top;
#endif
/*
@ -89,10 +104,10 @@ task stack, not the ISR stack). */
/*-----------------------------------------------------------*/
void prvTaskExitError( void )
static void prvTaskExitError( void )
{
volatile uint32_t ulx = 0;
#warning Not currently used
/* A function that implements a task must not exit or attempt to return to
its caller as there is nothing to return to. If a task wants to exit it
should instead call vTaskDelete( NULL ).
@ -105,107 +120,6 @@ volatile uint32_t ulx = 0;
}
/*-----------------------------------------------------------*/
/*
* See header file for description.
*/
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
{
uint32_t mstatus;
const uint32_t ulMPIE_Bit = 0x80, ulMPP_Bits = 0x1800;
/*
X1 to X31 integer registers for the 'I' profile, X1 to X15 for the 'E' profile.
Register ABI Name Description Saver
x0 zero Hard-wired zero -
x1 ra Return address Caller
x2 sp Stack pointer Callee
x3 gp Global pointer -
x4 tp Thread pointer -
x5-7 t0-2 Temporaries Caller
x8 s0/fp Saved register/Frame pointer Callee
x9 s1 Saved register Callee
x10-11 a0-1 Function Arguments/return values Caller
x12-17 a2-7 Function arguments Caller
x18-27 s2-11 Saved registers Callee
x28-31 t3-6 Temporaries Caller
*/
/* Start task with interrupt enabled. */
__asm volatile ("csrr %0, mstatus" : "=r"(mstatus));
mstatus |= ulMPIE_Bit | ulMPP_Bits;
pxTopOfStack--;
*pxTopOfStack = mstatus;
/* Numbers correspond to the x register number. */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 31;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 30;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 29;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 28;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 27;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 26;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 25;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 24;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 23;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 22;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 21;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 20;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 19;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 18;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 17;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 16;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 15;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 14;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 13;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 12;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 11;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) pvParameters;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 9;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 8;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 7;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 6;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 5;
pxTopOfStack--;
// *pxTopOfStack = ( StackType_t ) 4; /* Thread pointer. */
// pxTopOfStack--;
// *pxTopOfStack = ( StackType_t ) 3; /* Global pointer. */
// pxTopOfStack--;
// *pxTopOfStack = ( StackType_t ) 2; /* Stack pointer. */
// pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) prvTaskExitError;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) pxCode;
return pxTopOfStack;
}
/*-----------------------------------------------------------*/
#if( configCLINT_BASE_ADDRESS != 0 )
void vPortSetupTimerInterrupt( void )

View File

@ -25,6 +25,15 @@
* 1 tab == 4 spaces!
*/
#if __riscv_xlen == 64
#error Not implemented yet - change lw to ld, and sw to sd.
#define portWORD_SIZE 8
#elif __riscv_xlen == 32
#define portWORD_SIZE 4
#else
#error Assembler did not define __riscv_xlen
#endif
/*
* The FreeRTOS kernel's RISC-V port is split between the the code that is
* common across all currently supported RISC-V chips (implementations of the
@ -42,7 +51,7 @@
* base set of RISC-V registers. There are additional
* freertos_risc_v_port_specific_extensions.h files for RISC-V implementations
* that do not include a standard CLINT or do add to the base set of RISC-V
* regiters.
* registers.
*
* CARE MUST BE TAKEN TO INCLDUE THE CORRECT
* freertos_risc_v_port_specific_extensions.h HEADER FILE FOR THE CHIP
@ -67,27 +76,6 @@ definitions. */
#error portasmHANDLE_INTERRUPT must be defined to the function to be called to handle external/peripheral interrupts. portasmHANDLE_INTERRUPT can be defined on the assmbler command line or in the appropriate freertos_risc_v_port_specific_extensions.h header file.
#endif
#ifndef portasmSAVE_ADDITIONAL_REGISTERS
/* portasmSAVE_ADDITIONAL_REGISTERS is not defined so assume no additional
registers need to be saved. */
#define portasmSAVE_ADDITIONAL_REGISTERS
#endif
#ifndef portasmRESTORE_ADDITIONAL_REGISTERS
/* portasmRESTORE_ADDITIONAL_REGISTERS is not defined so assume no
additional registers need to be restored. */
#define portasmRESTORE_ADDITIONAL_REGISTERS
#endif
#if __riscv_xlen == 64
#error Not implemented yet - change lw to ld, and sw to sd.
#define portWORD_SIZE 8
#elif __riscv_xlen == 32
#define portWORD_SIZE 4
#else
#error Assembler did not define __riscv_xlen
#endif
/* Only the standard core registers are stored by default. Any additional
registers must be saved by the portasmSAVE_ADDITIONAL_REGISTERS and
portasmRESTORE_ADDITIONAL_REGISTERS macros - which can be defined in a chip
@ -97,6 +85,7 @@ at the top of this file. */
.global xPortStartFirstTask
.global vFreeRTOSPortTrapHandler
.global pxPortInitialiseStack
.extern pxCurrentTCB
.extern ulPortTrapHandler
.extern vTaskSwitchContext
@ -105,11 +94,11 @@ at the top of this file. */
.extern pullNextTime
.extern ulTimerIncrementsForOneTick
.extern xISRStackTop
.extern vPortHandleInterrupt
/*-----------------------------------------------------------*/
.align 16
.align 8
.func
vFreeRTOSPortTrapHandler:
addi sp, sp, -portCONTEXT_SIZE
sw x1, 1 * portWORD_SIZE( sp )
@ -141,11 +130,11 @@ vFreeRTOSPortTrapHandler:
sw x30, 27 * portWORD_SIZE( sp )
sw x31, 28 * portWORD_SIZE( sp )
portasmSAVE_ADDITIONAL_REGISTERS /* Defined in freertos_risc_v_port_specific_extensions.h to save any registers unique to the RISC-V implementation. */
csrr t0, mstatus /* Required for MPIE bit. */
sw t0, 29 * portWORD_SIZE( sp )
portasmSAVE_ADDITIONAL_REGISTERS /* Defined in freertos_risc_v_port_specific_extensions.h to save any registers unique to the RISC-V implementation. */
lw t0, pxCurrentTCB /* Load pxCurrentTCB. */
sw sp, 0( t0 ) /* Write sp to first TCB member. */
@ -217,16 +206,16 @@ processed_source:
lw sp, pxCurrentTCB /* Load pxCurrentTCB. */
lw sp, 0( sp ) /* Read sp from first TCB member. */
/* Load mret with the address of the next task. */
/* Load mret with the address of the next instruction in the task to run next. */
lw t0, 0( sp )
csrw mepc, t0
portasmRESTORE_ADDITIONAL_REGISTERS /* Defined in freertos_risc_v_port_specific_extensions.h to restore any registers unique to the RISC-V implementation. */
/* Load mstatus with the interrupt enable bits used by the task. */
lw t0, 29 * portWORD_SIZE( sp )
csrw mstatus, t0 /* Required for MPIE bit. */
portasmRESTORE_ADDITIONAL_REGISTERS /* Defined in freertos_risc_v_port_specific_extensions.h to restore any registers unique to the RISC-V implementation. */
lw x1, 1 * portWORD_SIZE( sp )
lw x5, 2 * portWORD_SIZE( sp ) /* t0 */
lw x6, 3 * portWORD_SIZE( sp ) /* t1 */
@ -255,12 +244,14 @@ processed_source:
lw x29, 26 * portWORD_SIZE( sp ) /* t4 */
lw x30, 27 * portWORD_SIZE( sp ) /* t5 */
lw x31, 28 * portWORD_SIZE( sp ) /* t6 */
addi sp, sp, portCONTEXT_SIZE
addi sp, sp, portCONTEXT_SIZE
mret
.endfunc
/*-----------------------------------------------------------*/
.align 16
.align 8
.func
xPortStartFirstTask:
#if( portasmHAS_CLINT != 0 )
@ -275,6 +266,12 @@ xPortStartFirstTask:
lw sp, 0( sp ) /* Read sp from first TCB member. */
lw x1, 0( sp ) /* Note for starting the scheduler the exception return address is used as the function return address. */
portasmRESTORE_ADDITIONAL_REGISTERS /* Defined in freertos_risc_v_port_specific_extensions.h to restore any registers unique to the RISC-V implementation. */
lw t0, 29 * portWORD_SIZE( sp ) /* mstatus */
csrrw x0, mstatus, t0 /* Interrupts enabled from here! */
lw x5, 2 * portWORD_SIZE( sp ) /* t0 */
lw x6, 3 * portWORD_SIZE( sp ) /* t1 */
lw x7, 4 * portWORD_SIZE( sp ) /* t2 */
@ -303,8 +300,98 @@ xPortStartFirstTask:
lw x30, 27 * portWORD_SIZE( sp ) /* t5 */
lw x31, 28 * portWORD_SIZE( sp ) /* t6 */
addi sp, sp, portCONTEXT_SIZE
csrs mstatus, 8 /* Enable machine interrupts. */
ret
.endfunc
/*-----------------------------------------------------------*/
/*
* Unlike other ports pxPortInitialiseStack() is written in assembly code as it
* needs access to the portasmADDITIONAL_CONTEXT_SIZE constant. The prototype
* for the function is as per the other ports:
* StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters );
*
* As per the standard RISC-V ABI pxTopcOfStack is passed in in a0, pxCode in
* a1, and pvParameters in a2. The new top of stack is passed out in a0.
*
* RISC-V maps registers to ABI names as follows (X1 to X31 integer registers
* for the 'I' profile, X1 to X15 for the 'E' profile, currently I assumed).
*
* Register ABI Name Description Saver
* x0 zero Hard-wired zero -
* x1 ra Return address Caller
* x2 sp Stack pointer Callee
* x3 gp Global pointer -
* x4 tp Thread pointer -
* x5-7 t0-2 Temporaries Caller
* x8 s0/fp Saved register/Frame pointer Callee
* x9 s1 Saved register Callee
* x10-11 a0-1 Function Arguments/return values Caller
* x12-17 a2-7 Function arguments Caller
* x18-27 s2-11 Saved registers Callee
* x28-31 t3-6 Temporaries Caller
*
* The RISC-V context is saved t FreeRTOS tasks in the following stack frame,
* where the global and thread pointers are currently assumed to be constant so
* are not saved:
*
* mstatus
* x31
* x30
* x29
* x28
* x27
* x26
* x25
* x24
* x23
* x22
* x21
* x20
* x19
* x18
* x17
* x16
* x15
* x14
* x13
* x12
* x11
* pvParameters
* x9
* x8
* x7
* x6
* x5
* portTASK_RETURN_ADDRESS
* pxCode
*/
.align 8
.func
pxPortInitialiseStack:
addi t0, x0, portasmADDITIONAL_CONTEXT_SIZE /* The number of chip specific additional registers. */
chip_specific_stack_frame: /* First add any chip specific registers to the stack frame being created. */
beq t0, x0, standard_stack_frame /* No more chip specific registers to save. */
addi a0, a0, -portWORD_SIZE /* Make space for chip specific register. */
sw x0, 0(a0) /* Give the chip specific register an initial value of zero. */
addi t0, t0, -1 /* Decrement the count of chip specific registers remaining. */
j chip_specific_stack_frame /* Until no more chip specific registers. */
standard_stack_frame: /* Now create the stack frame for the standard registers. */
csrr t0, mstatus /* Obtain current mstatus value. */
addi t1, x0, 0x188 /* Generate the value 0x1880, which are the MPIE and MPP bits to set in mstatus. */
slli t1, t1, 4
or t0, t0, t1 /* Set MPIE and MPP bits in mstatus value. */
addi a0, a0, -portWORD_SIZE
sw t0, 0(a0) /* mstatus onto the stack. */
addi a0, a0, -(22 * portWORD_SIZE) /* Space for registers x11-x31. */
sw a2, 0(a0) /* Task parameters (pvParameters parameter) goes into register X10/a0 on the stack. */
addi a0, a0, -(6 * portWORD_SIZE) /* Space for registers x5-x9. */
sw x0, 0(a0) /* Return address onto the stack, could be portTASK_RETURN_ADDRESS */
addi a0, a0, -portWORD_SIZE
sw a1, 0(a0) /* mret value (pxCode parameter) onto the stack. */
ret
.endfunc
/*-----------------------------------------------------------*/