Skip to content

Commit f789a0e

Browse files
mingyue86010dachalcoaggargalfred2g
authored
Update RISC-V IAR port to support vector mode. (#458)
* Update RISC-V IAR port to support vector mode. * uncrustify Co-authored-by: David Chalco <david@chalco.io> Co-authored-by: Gaurav-Aggarwal-AWS <33462878+aggarg@users.noreply.github.com> Co-authored-by: alfred gedeon <28123637+alfred2g@users.noreply.github.com>
1 parent 49777e3 commit f789a0e

File tree

4 files changed

+629
-478
lines changed

4 files changed

+629
-478
lines changed

portable/IAR/RISC-V/port.c

Lines changed: 146 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727
*/
2828

2929
/*-----------------------------------------------------------
30-
* Implementation of functions defined in portable.h for the RISC-V RV32 port.
31-
*----------------------------------------------------------*/
30+
* Implementation of functions defined in portable.h for the RISC-V port.
31+
*----------------------------------------------------------*/
3232

3333
/* Scheduler includes. */
3434
#include "FreeRTOS.h"
@@ -39,175 +39,203 @@
3939
#include "string.h"
4040

4141
#ifdef configCLINT_BASE_ADDRESS
42-
#warning The configCLINT_BASE_ADDRESS constant has been deprecated. configMTIME_BASE_ADDRESS and configMTIMECMP_BASE_ADDRESS are currently being derived from the (possibly 0) configCLINT_BASE_ADDRESS setting. Please update to define configMTIME_BASE_ADDRESS and configMTIMECMP_BASE_ADDRESS dirctly in place of configCLINT_BASE_ADDRESS. See https://www.FreeRTOS.org/Using-FreeRTOS-on-RISC-V.html
42+
#warning The configCLINT_BASE_ADDRESS constant has been deprecated. configMTIME_BASE_ADDRESS and configMTIMECMP_BASE_ADDRESS are currently being derived from the (possibly 0) configCLINT_BASE_ADDRESS setting. Please update to define configMTIME_BASE_ADDRESS and configMTIMECMP_BASE_ADDRESS dirctly in place of configCLINT_BASE_ADDRESS. See https: /*www.FreeRTOS.org/Using-FreeRTOS-on-RISC-V.html */
4343
#endif
4444

4545
#ifndef configMTIME_BASE_ADDRESS
46-
#warning configMTIME_BASE_ADDRESS must be defined in FreeRTOSConfig.h. If the target chip includes a memory-mapped mtime register then set configMTIME_BASE_ADDRESS to the mapped address. Otherwise set configMTIME_BASE_ADDRESS to 0. See https://www.FreeRTOS.org/Using-FreeRTOS-on-RISC-V.html
46+
#warning configMTIME_BASE_ADDRESS must be defined in FreeRTOSConfig.h. If the target chip includes a memory-mapped mtime register then set configMTIME_BASE_ADDRESS to the mapped address. Otherwise set configMTIME_BASE_ADDRESS to 0. See https: /*www.FreeRTOS.org/Using-FreeRTOS-on-RISC-V.html */
4747
#endif
4848

4949
#ifndef configMTIMECMP_BASE_ADDRESS
50-
#warning configMTIMECMP_BASE_ADDRESS must be defined in FreeRTOSConfig.h. If the target chip includes a memory-mapped mtimecmp register then set configMTIMECMP_BASE_ADDRESS to the mapped address. Otherwise set configMTIMECMP_BASE_ADDRESS to 0. See https://www.FreeRTOS.org/Using-FreeRTOS-on-RISC-V.html
50+
#warning configMTIMECMP_BASE_ADDRESS must be defined in FreeRTOSConfig.h. If the target chip includes a memory-mapped mtimecmp register then set configMTIMECMP_BASE_ADDRESS to the mapped address. Otherwise set configMTIMECMP_BASE_ADDRESS to 0. See https: /*www.FreeRTOS.org/Using-FreeRTOS-on-RISC-V.html */
5151
#endif
5252

5353
/* Let the user override the pre-loading of the initial LR with the address of
54-
prvTaskExitError() in case it messes up unwinding of the stack in the
55-
debugger. */
54+
* prvTaskExitError() in case it messes up unwinding of the stack in the
55+
* debugger. */
5656
#ifdef configTASK_RETURN_ADDRESS
57-
#define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS
57+
#define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS
5858
#else
59-
#define portTASK_RETURN_ADDRESS prvTaskExitError
59+
#define portTASK_RETURN_ADDRESS prvTaskExitError
6060
#endif
6161

6262
/* The stack used by interrupt service routines. Set configISR_STACK_SIZE_WORDS
63-
to use a statically allocated array as the interrupt stack. Alternative leave
64-
configISR_STACK_SIZE_WORDS undefined and update the linker script so that a
65-
linker variable names __freertos_irq_stack_top has the same value as the top
66-
of the stack used by main. Using the linker script method will repurpose the
67-
stack that was used by main before the scheduler was started for use as the
68-
interrupt stack after the scheduler has started. */
63+
* to use a statically allocated array as the interrupt stack. Alternative leave
64+
* configISR_STACK_SIZE_WORDS undefined and update the linker script so that a
65+
* linker variable names __freertos_irq_stack_top has the same value as the top
66+
* of the stack used by main. Using the linker script method will repurpose the
67+
* stack that was used by main before the scheduler was started for use as the
68+
* interrupt stack after the scheduler has started. */
6969
#ifdef configISR_STACK_SIZE_WORDS
70-
static __attribute__ ((aligned(16))) StackType_t xISRStack[ configISR_STACK_SIZE_WORDS ] = { 0 };
71-
const StackType_t xISRStackTop = ( StackType_t ) &( xISRStack[ configISR_STACK_SIZE_WORDS & ~portBYTE_ALIGNMENT_MASK ] );
70+
static __attribute__( ( aligned( 16 ) ) ) StackType_t xISRStack[ configISR_STACK_SIZE_WORDS ] = { 0 };
71+
const StackType_t xISRStackTop = ( StackType_t ) &( xISRStack[ configISR_STACK_SIZE_WORDS & ~portBYTE_ALIGNMENT_MASK ] );
7272

73-
/* Don't use 0xa5 as the stack fill bytes as that is used by the kernerl for
74-
the task stacks, and so will legitimately appear in many positions within
75-
the ISR stack. */
76-
#define portISR_STACK_FILL_BYTE 0xee
73+
/* Don't use 0xa5 as the stack fill bytes as that is used by the kernerl for
74+
* the task stacks, and so will legitimately appear in many positions within
75+
* the ISR stack. */
76+
#define portISR_STACK_FILL_BYTE 0xee
7777
#else
78-
extern const uint32_t __freertos_irq_stack_top[];
79-
const StackType_t xISRStackTop = ( StackType_t ) __freertos_irq_stack_top;
78+
extern const uint32_t __freertos_irq_stack_top[];
79+
const StackType_t xISRStackTop = ( StackType_t ) __freertos_irq_stack_top;
8080
#endif
8181

82+
/**
83+
* @brief Used to catch tasks that attempt to return from their implementing
84+
* function.
85+
*/
86+
static void prvTaskExitError( void );
87+
8288
/*
8389
* Setup the timer to generate the tick interrupts. The implementation in this
8490
* file is weak to allow application writers to change the timer used to
8591
* generate the tick interrupt.
8692
*/
87-
void vPortSetupTimerInterrupt( void ) __attribute__(( weak ));
93+
void vPortSetupTimerInterrupt( void ) __attribute__( ( weak ) );
8894

8995
/*-----------------------------------------------------------*/
9096

9197
/* Used to program the machine timer compare register. */
9298
uint64_t ullNextTime = 0ULL;
93-
const uint64_t *pullNextTime = &ullNextTime;
99+
const uint64_t * pullNextTime = &ullNextTime;
94100
const size_t uxTimerIncrementsForOneTick = ( size_t ) ( ( configCPU_CLOCK_HZ ) / ( configTICK_RATE_HZ ) ); /* Assumes increment won't go over 32-bits. */
95101
uint32_t const ullMachineTimerCompareRegisterBase = configMTIMECMP_BASE_ADDRESS;
96102
volatile uint64_t * pullMachineTimerCompareRegister = NULL;
97103

98-
/* Set configCHECK_FOR_STACK_OVERFLOW to 3 to add ISR stack checking to task
99-
stack checking. A problem in the ISR stack will trigger an assert, not call the
100-
stack overflow hook function (because the stack overflow hook is specific to a
101-
task stack, not the ISR stack). */
102-
#if defined( configISR_STACK_SIZE_WORDS ) && ( configCHECK_FOR_STACK_OVERFLOW > 2 )
103-
#warning This path not tested, or even compiled yet.
104+
/* Holds the critical nesting value - deliberately non-zero at start up to
105+
* ensure interrupts are not accidentally enabled before the scheduler starts. */
106+
size_t xCriticalNesting = ( size_t ) 0xaaaaaaaa;
107+
size_t * pxCriticalNesting = &xCriticalNesting;
104108

105-
static const uint8_t ucExpectedStackBytes[] = {
106-
portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \
107-
portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \
108-
portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \
109-
portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \
110-
portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE }; \
109+
/* Used to catch tasks that attempt to return from their implementing function. */
110+
size_t xTaskReturnAddress = ( size_t ) portTASK_RETURN_ADDRESS;
111111

112-
#define portCHECK_ISR_STACK() configASSERT( ( memcmp( ( void * ) xISRStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) == 0 ) )
113-
#else
114-
/* Define the function away. */
115-
#define portCHECK_ISR_STACK()
112+
/* Set configCHECK_FOR_STACK_OVERFLOW to 3 to add ISR stack checking to task
113+
* stack checking. A problem in the ISR stack will trigger an assert, not call
114+
* the stack overflow hook function (because the stack overflow hook is specific
115+
* to a task stack, not the ISR stack). */
116+
#if defined( configISR_STACK_SIZE_WORDS ) && ( configCHECK_FOR_STACK_OVERFLOW > 2 )
117+
#warning This path not tested, or even compiled yet.
118+
119+
static const uint8_t ucExpectedStackBytes[] =
120+
{
121+
portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \
122+
portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \
123+
portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \
124+
portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \
125+
portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE
126+
}; \
127+
128+
#define portCHECK_ISR_STACK() configASSERT( ( memcmp( ( void * ) xISRStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) == 0 ) )
129+
#else /* if defined( configISR_STACK_SIZE_WORDS ) && ( configCHECK_FOR_STACK_OVERFLOW > 2 ) */
130+
/* Define the function away. */
131+
#define portCHECK_ISR_STACK()
116132
#endif /* configCHECK_FOR_STACK_OVERFLOW > 2 */
117133

118134
/*-----------------------------------------------------------*/
119135

120-
#if( configMTIME_BASE_ADDRESS != 0 ) && ( configMTIMECMP_BASE_ADDRESS != 0 )
136+
static void prvTaskExitError( void )
137+
{
138+
volatile uint32_t ulDummy = 0UL;
139+
140+
/* A function that implements a task must not exit or attempt to return to
141+
* its caller as there is nothing to return to. If a task wants to exit it
142+
* should instead call vTaskDelete( NULL ). Artificially force an assert()
143+
* to be triggered if configASSERT() is defined, then stop here so
144+
* application writers can catch the error. */
145+
configASSERT( xCriticalNesting == ~0UL );
146+
portDISABLE_INTERRUPTS();
147+
148+
while( ulDummy == 0 )
149+
{
150+
/* This file calls prvTaskExitError() after the scheduler has been
151+
* started to remove a compiler warning about the function being
152+
* defined but never called. ulDummy is used purely to quieten other
153+
* warnings about code appearing after this function is called - making
154+
* ulDummy volatile makes the compiler think the function could return
155+
* and therefore not output an 'unreachable code' warning for code that
156+
* appears after it. */
157+
}
158+
}
159+
/*-----------------------------------------------------------*/
160+
161+
#if ( configMTIME_BASE_ADDRESS != 0 ) && ( configMTIMECMP_BASE_ADDRESS != 0 )
162+
163+
void vPortSetupTimerInterrupt( void )
164+
{
165+
uint32_t ulCurrentTimeHigh, ulCurrentTimeLow;
166+
volatile uint32_t * const pulTimeHigh = ( uint32_t * ) ( ( configMTIME_BASE_ADDRESS ) + 4UL ); /* 8-byte type so high 32-bit word is 4 bytes up. */
167+
volatile uint32_t * const pulTimeLow = ( uint32_t * ) ( configMTIME_BASE_ADDRESS );
168+
volatile uint32_t ulHartId;
121169

122-
void vPortSetupTimerInterrupt( void )
123-
{
124-
uint32_t ulCurrentTimeHigh, ulCurrentTimeLow;
125-
volatile uint32_t * const pulTimeHigh = ( uint32_t * ) ( ( configMTIME_BASE_ADDRESS ) + 4UL ); /* 8-byte typer so high 32-bit word is 4 bytes up. */
126-
volatile uint32_t * const pulTimeLow = ( uint32_t * ) ( configMTIME_BASE_ADDRESS );
127-
volatile uint32_t ulHartId;
170+
__asm volatile ( "csrr %0, 0xf14" : "=r" ( ulHartId ) ); /* 0xf14 is hartid. */
128171

129-
__asm volatile( "csrr %0, 0xf14" : "=r"( ulHartId ) ); /* 0xf14 is hartid. */
130-
pullMachineTimerCompareRegister = ( volatile uint64_t * ) ( ullMachineTimerCompareRegisterBase + ( ulHartId * sizeof( uint64_t ) ) );
172+
pullMachineTimerCompareRegister = ( volatile uint64_t * ) ( ullMachineTimerCompareRegisterBase + ( ulHartId * sizeof( uint64_t ) ) );
131173

132-
do
133-
{
134-
ulCurrentTimeHigh = *pulTimeHigh;
135-
ulCurrentTimeLow = *pulTimeLow;
136-
} while( ulCurrentTimeHigh != *pulTimeHigh );
174+
do
175+
{
176+
ulCurrentTimeHigh = *pulTimeHigh;
177+
ulCurrentTimeLow = *pulTimeLow;
178+
} while( ulCurrentTimeHigh != *pulTimeHigh );
137179

138-
ullNextTime = ( uint64_t ) ulCurrentTimeHigh;
139-
ullNextTime <<= 32ULL; /* High 4-byte word is 32-bits up. */
140-
ullNextTime |= ( uint64_t ) ulCurrentTimeLow;
141-
ullNextTime += ( uint64_t ) uxTimerIncrementsForOneTick;
142-
*pullMachineTimerCompareRegister = ullNextTime;
180+
ullNextTime = ( uint64_t ) ulCurrentTimeHigh;
181+
ullNextTime <<= 32ULL; /* High 4-byte word is 32-bits up. */
182+
ullNextTime |= ( uint64_t ) ulCurrentTimeLow;
183+
ullNextTime += ( uint64_t ) uxTimerIncrementsForOneTick;
184+
*pullMachineTimerCompareRegister = ullNextTime;
143185

144-
/* Prepare the time to use after the next tick interrupt. */
145-
ullNextTime += ( uint64_t ) uxTimerIncrementsForOneTick;
146-
}
186+
/* Prepare the time to use after the next tick interrupt. */
187+
ullNextTime += ( uint64_t ) uxTimerIncrementsForOneTick;
188+
}
147189

148190
#endif /* ( configMTIME_BASE_ADDRESS != 0 ) && ( configMTIME_BASE_ADDRESS != 0 ) */
149191
/*-----------------------------------------------------------*/
150192

151193
BaseType_t xPortStartScheduler( void )
152194
{
153-
extern void xPortStartFirstTask( void );
154-
155-
#if( configASSERT_DEFINED == 1 )
156-
{
157-
volatile uint32_t mtvec = 0;
158-
159-
/* Check the least significant two bits of mtvec are 00 - indicating
160-
single vector mode. */
161-
__asm volatile( "csrr %0, 0x305" : "=r"( mtvec ) ); /* 0x305 is mtvec. */
162-
configASSERT( ( mtvec & 0x03UL ) == 0 );
163-
164-
/* Check alignment of the interrupt stack - which is the same as the
165-
stack that was being used by main() prior to the scheduler being
166-
started. */
167-
configASSERT( ( xISRStackTop & portBYTE_ALIGNMENT_MASK ) == 0 );
168-
169-
#ifdef configISR_STACK_SIZE_WORDS
170-
{
171-
memset( ( void * ) xISRStack, portISR_STACK_FILL_BYTE, sizeof( xISRStack ) );
172-
}
173-
#endif /* configISR_STACK_SIZE_WORDS */
174-
}
175-
#endif /* configASSERT_DEFINED */
176-
177-
/* If there is a CLINT then it is ok to use the default implementation
178-
in this file, otherwise vPortSetupTimerInterrupt() must be implemented to
179-
configure whichever clock is to be used to generate the tick interrupt. */
180-
vPortSetupTimerInterrupt();
181-
182-
#if( ( configMTIME_BASE_ADDRESS != 0 ) && ( configMTIMECMP_BASE_ADDRESS != 0 ) )
183-
{
184-
/* Enable mtime and external interrupts. 1<<7 for timer interrupt, 1<<11
185-
for external interrupt. _RB_ What happens here when mtime is not present as
186-
with pulpino? */
187-
__asm volatile( "csrs 0x304, %0" :: "r"(0x880) ); /* 0x304 is mie. */
188-
}
189-
#else
190-
{
191-
/* Enable external interrupts. */
192-
__asm volatile( "csrs 0x304, %0" :: "r"(0x800) ); /* 304 is mie. */
193-
}
194-
#endif /* ( configMTIME_BASE_ADDRESS != 0 ) && ( configMTIMECMP_BASE_ADDRESS != 0 ) */
195-
196-
xPortStartFirstTask();
197-
198-
/* Should not get here as after calling xPortStartFirstTask() only tasks
199-
should be executing. */
200-
return pdFAIL;
195+
extern void xPortStartFirstTask( void );
196+
197+
#if ( configASSERT_DEFINED == 1 )
198+
{
199+
/* Check alignment of the interrupt stack - which is the same as the
200+
* stack that was being used by main() prior to the scheduler being
201+
* started. */
202+
configASSERT( ( xISRStackTop & portBYTE_ALIGNMENT_MASK ) == 0 );
203+
204+
#ifdef configISR_STACK_SIZE_WORDS
205+
{
206+
memset( ( void * ) xISRStack, portISR_STACK_FILL_BYTE, sizeof( xISRStack ) );
207+
}
208+
#endif /* configISR_STACK_SIZE_WORDS */
209+
}
210+
#endif /* configASSERT_DEFINED */
211+
212+
/* If there is a CLINT then it is ok to use the default implementation
213+
* in this file, otherwise vPortSetupTimerInterrupt() must be implemented to
214+
* configure whichever clock is to be used to generate the tick interrupt. */
215+
vPortSetupTimerInterrupt();
216+
217+
#if ( ( configMTIME_BASE_ADDRESS != 0 ) && ( configMTIMECMP_BASE_ADDRESS != 0 ) )
218+
{
219+
/* Enable mtime and external interrupts. 1<<7 for timer interrupt,
220+
* 1<<11 for external interrupt. _RB_ What happens here when mtime is
221+
* not present as with pulpino? */
222+
__asm volatile ( "csrs 0x304, %0" ::"r" ( 0x880 ) ); /* 0x304 is mie. */
223+
}
224+
#endif /* ( configMTIME_BASE_ADDRESS != 0 ) && ( configMTIMECMP_BASE_ADDRESS != 0 ) */
225+
226+
xPortStartFirstTask();
227+
228+
/* Should not get here as after calling xPortStartFirstTask() only tasks
229+
* should be executing. */
230+
return pdFAIL;
201231
}
202232
/*-----------------------------------------------------------*/
203233

204234
void vPortEndScheduler( void )
205235
{
206-
/* Not implemented. */
207-
for( ;; );
236+
/* Not implemented. */
237+
for( ; ; )
238+
{
239+
}
208240
}
209-
210-
211-
212-
213-
241+
/*-----------------------------------------------------------*/

0 commit comments

Comments
 (0)