feat: publish FreeRTOS C FC07 card
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
.section .text
|
||||
.global _start
|
||||
.type _start, @function
|
||||
|
||||
_start:
|
||||
.option push
|
||||
.option norelax
|
||||
la gp, __global_pointer$
|
||||
.option pop
|
||||
|
||||
/* Hazard3 init.S has already installed the bootstrap stack. */
|
||||
la a0, __bss_start
|
||||
la a1, __bss_end
|
||||
1:
|
||||
bgeu a0, a1, 2f
|
||||
sb zero, 0(a0)
|
||||
addi a0, a0, 1
|
||||
j 1b
|
||||
2:
|
||||
call main
|
||||
tail _exit
|
||||
|
||||
.size _start, .-_start
|
||||
@@ -0,0 +1,27 @@
|
||||
.section .text.hazard3_freertos_traps, "ax", @progbits
|
||||
|
||||
/*
|
||||
* Hazard3 init.S owns mtvec and exposes weak vector targets. Strong symbols
|
||||
* below route exceptions (including ecall/yield) and the machine timer IRQ to
|
||||
* the official FreeRTOS RISC-V trap handler.
|
||||
*/
|
||||
.global handle_exception
|
||||
.type handle_exception, @function
|
||||
handle_exception:
|
||||
j freertos_risc_v_trap_handler
|
||||
.size handle_exception, .-handle_exception
|
||||
|
||||
.global isr_machine_timer
|
||||
.type isr_machine_timer, @function
|
||||
isr_machine_timer:
|
||||
j freertos_risc_v_trap_handler
|
||||
.size isr_machine_timer, .-isr_machine_timer
|
||||
|
||||
/* Route a real machine-external interrupt through the FreeRTOS full-context
|
||||
* trap path. The application handler runs on xISRStack and may request a
|
||||
* context switch before portcontextRESTORE_CONTEXT selects the next task. */
|
||||
.global isr_external_irq
|
||||
.type isr_external_irq, @function
|
||||
isr_external_irq:
|
||||
j freertos_risc_v_trap_handler
|
||||
.size isr_external_irq, .-isr_external_irq
|
||||
@@ -0,0 +1,48 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "lab_freertos.h"
|
||||
#include "lab_io.h"
|
||||
|
||||
/* Official heap_4.c uses this application-owned arena. */
|
||||
__attribute__( ( aligned( 16 ) ) ) uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
|
||||
volatile uint32_t g_failure_code;
|
||||
|
||||
int lab_address_in_heap( const volatile void * address )
|
||||
{
|
||||
const uintptr_t value = ( uintptr_t ) address;
|
||||
const uintptr_t first = ( uintptr_t ) &ucHeap[ 0 ];
|
||||
const uintptr_t past_last = ( uintptr_t ) &ucHeap[ configTOTAL_HEAP_SIZE ];
|
||||
|
||||
return ( value >= first ) && ( value < past_last );
|
||||
}
|
||||
|
||||
void lab_heap_initialize( void )
|
||||
{
|
||||
void * probe = pvPortMalloc( 1U );
|
||||
|
||||
if( probe == NULL )
|
||||
{
|
||||
lab_fail( 0xA6000002UL );
|
||||
}
|
||||
vPortFree( probe );
|
||||
}
|
||||
|
||||
void lab_fail( uint32_t code )
|
||||
{
|
||||
g_failure_code = code;
|
||||
lab_puts( "FAIL\n" );
|
||||
lab_put_u32( code );
|
||||
lab_exit( code );
|
||||
}
|
||||
|
||||
void lab_assert_fail( const char * file, int line )
|
||||
{
|
||||
( void ) file;
|
||||
lab_fail( 0xA5000000UL | ( ( uint32_t ) line & 0xFFFFUL ) );
|
||||
}
|
||||
|
||||
void vApplicationMallocFailedHook( void )
|
||||
{
|
||||
lab_fail( 0xA6000001UL );
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef LAB_FREERTOS_H
|
||||
#define LAB_FREERTOS_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
|
||||
extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
|
||||
extern volatile uint32_t g_failure_code;
|
||||
|
||||
int lab_address_in_heap( const volatile void * address );
|
||||
void lab_heap_initialize( void );
|
||||
void lab_fail( uint32_t code ) __attribute__( ( noreturn ) );
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "lab_io.h"
|
||||
|
||||
#define H3_IO_BASE ( 0xC0000000UL )
|
||||
#define H3_IO_PRINT_CHAR ( *( ( volatile uint32_t * ) ( H3_IO_BASE + 0x0UL ) ) )
|
||||
#define H3_IO_PRINT_U32 ( *( ( volatile uint32_t * ) ( H3_IO_BASE + 0x4UL ) ) )
|
||||
#define H3_IO_EXIT ( *( ( volatile uint32_t * ) ( H3_IO_BASE + 0x8UL ) ) )
|
||||
|
||||
void lab_puts( const char * text )
|
||||
{
|
||||
while( *text != '\0' )
|
||||
{
|
||||
H3_IO_PRINT_CHAR = ( uint32_t ) ( unsigned char ) *text;
|
||||
++text;
|
||||
}
|
||||
}
|
||||
void lab_put_u32( uint32_t value )
|
||||
{
|
||||
H3_IO_PRINT_U32 = value;
|
||||
}
|
||||
|
||||
void lab_exit( uint32_t code )
|
||||
{
|
||||
H3_IO_EXIT = code;
|
||||
for( ; ; )
|
||||
{
|
||||
__asm volatile ( "wfi" );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef LAB_IO_H
|
||||
#define LAB_IO_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void lab_puts( const char * text );
|
||||
void lab_put_u32( uint32_t value );
|
||||
void lab_exit( uint32_t code ) __attribute__( ( noreturn ) );
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,34 @@
|
||||
#include <stddef.h>
|
||||
|
||||
void * memcpy( void * destination, const void * source, size_t count )
|
||||
{
|
||||
unsigned char * out = ( unsigned char * ) destination;
|
||||
const unsigned char * in = ( const unsigned char * ) source;
|
||||
|
||||
for( size_t index = 0; index < count; ++index )
|
||||
{
|
||||
out[ index ] = in[ index ];
|
||||
}
|
||||
return destination;
|
||||
}
|
||||
void * memset( void * destination, int value, size_t count )
|
||||
{
|
||||
unsigned char * out = ( unsigned char * ) destination;
|
||||
|
||||
for( size_t index = 0; index < count; ++index )
|
||||
{
|
||||
out[ index ] = ( unsigned char ) value;
|
||||
}
|
||||
return destination;
|
||||
}
|
||||
|
||||
size_t strlen( const char * text )
|
||||
{
|
||||
size_t length = 0;
|
||||
|
||||
while( text[ length ] != '\0' )
|
||||
{
|
||||
++length;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "semphr.h"
|
||||
#include "task.h"
|
||||
#include "hazard3_irq.h"
|
||||
#include "lab_freertos.h"
|
||||
#include "lab_io.h"
|
||||
#include "task01_isr_semaphore.h"
|
||||
|
||||
#define H3_IO_BASE 0xC0000000UL
|
||||
#define H3_IO_SET_IRQ ( *( ( volatile uint32_t * ) ( H3_IO_BASE + 0x020UL ) ) )
|
||||
#define H3_IO_CLR_IRQ ( *( ( volatile uint32_t * ) ( H3_IO_BASE + 0x030UL ) ) )
|
||||
|
||||
#define FC07_ACTOR_MAIN 1U
|
||||
#define FC07_ACTOR_WAITER 2U
|
||||
#define FC07_ACTOR_STIMULUS 3U
|
||||
#define FC07_ACTOR_ISR 4U
|
||||
#define FC07_ACTOR_VERIFIER 5U
|
||||
|
||||
IsrExperiment g_fc07;
|
||||
IsrEvidence g_fc07_events[ FC07_EVENT_CAPACITY ];
|
||||
volatile uint32_t g_fc07_event_count;
|
||||
volatile uint32_t g_fc07_last_checkpoint;
|
||||
volatile uint32_t g_fc07_pass;
|
||||
|
||||
static uintptr_t read_sp( void )
|
||||
{
|
||||
uintptr_t value;
|
||||
__asm__ volatile( "mv %0, sp" : "=r"( value ) );
|
||||
return value;
|
||||
}
|
||||
|
||||
static uint32_t read_mcause( void )
|
||||
{
|
||||
uint32_t value;
|
||||
__asm__ volatile( "csrr %0, mcause" : "=r"( value ) );
|
||||
return value;
|
||||
}
|
||||
|
||||
__attribute__( ( noinline, used ) )
|
||||
void fc07_checkpoint_committed( uint32_t point, const void * subject )
|
||||
{
|
||||
( void ) point;
|
||||
( void ) subject;
|
||||
__asm__ volatile( "" ::: "memory" );
|
||||
}
|
||||
|
||||
static void fc07_publish_task( uint32_t point,
|
||||
uint32_t actor,
|
||||
uint32_t value,
|
||||
const void * subject )
|
||||
{
|
||||
UBaseType_t state = taskENTER_CRITICAL_FROM_ISR();
|
||||
uint32_t index = g_fc07_event_count;
|
||||
IsrEvidence * event;
|
||||
if( index >= FC07_EVENT_CAPACITY )
|
||||
{
|
||||
taskEXIT_CRITICAL_FROM_ISR( state );
|
||||
lab_fail( 0xFC070001U );
|
||||
}
|
||||
event = &g_fc07_events[ index ];
|
||||
event->sequence = index + 1U;
|
||||
event->event = point;
|
||||
event->tick = ( uint32_t ) xTaskGetTickCount();
|
||||
event->actor = actor;
|
||||
event->value = value;
|
||||
__asm__ volatile( "" ::: "memory" );
|
||||
event->committed = 0xFC070000U | ( index + 1U );
|
||||
g_fc07_event_count = index + 1U;
|
||||
g_fc07_last_checkpoint = point;
|
||||
taskEXIT_CRITICAL_FROM_ISR( state );
|
||||
fc07_checkpoint_committed( point, subject );
|
||||
}
|
||||
|
||||
static void fc07_publish_isr( uint32_t point, uint32_t value )
|
||||
{
|
||||
uint32_t index = g_fc07_event_count;
|
||||
IsrEvidence * event;
|
||||
if( index >= FC07_EVENT_CAPACITY )
|
||||
{
|
||||
return;
|
||||
}
|
||||
event = &g_fc07_events[ index ];
|
||||
event->sequence = index + 1U;
|
||||
event->event = point;
|
||||
event->tick = ( uint32_t ) xTaskGetTickCountFromISR();
|
||||
event->actor = FC07_ACTOR_ISR;
|
||||
event->value = value;
|
||||
__asm__ volatile( "" ::: "memory" );
|
||||
event->committed = 0xFC070000U | ( index + 1U );
|
||||
g_fc07_event_count = index + 1U;
|
||||
g_fc07_last_checkpoint = point;
|
||||
fc07_checkpoint_committed( point, &g_fc07 );
|
||||
}
|
||||
|
||||
__attribute__( ( noinline, used ) )
|
||||
void freertos_risc_v_application_interrupt_handler( void )
|
||||
{
|
||||
BaseType_t higher_priority_task_woken = pdFALSE;
|
||||
|
||||
g_fc07.mcause = read_mcause();
|
||||
g_fc07.isr_sp = read_sp();
|
||||
fc07_publish_isr( 4U, g_fc07.mcause );
|
||||
|
||||
H3_IO_CLR_IRQ = FC07_IRQ_MASK;
|
||||
g_fc07.irq_source_after_clear = H3_IO_CLR_IRQ;
|
||||
fc07_publish_isr( 5U, g_fc07.irq_source_after_clear );
|
||||
|
||||
if( xSemaphoreGiveFromISR( g_fc07.semaphore,
|
||||
&higher_priority_task_woken ) != pdPASS )
|
||||
{
|
||||
lab_fail( 0xFC070101U );
|
||||
}
|
||||
g_fc07.higher_priority_task_woken = higher_priority_task_woken;
|
||||
fc07_publish_isr( 6U, ( uint32_t ) higher_priority_task_woken );
|
||||
portYIELD_FROM_ISR( higher_priority_task_woken );
|
||||
}
|
||||
|
||||
__attribute__( ( noinline, used ) )
|
||||
void fc07_waiter_entry( void * context )
|
||||
{
|
||||
IsrExperiment * experiment = ( IsrExperiment * ) context;
|
||||
if( experiment == NULL )
|
||||
{
|
||||
lab_fail( 0xFC070201U );
|
||||
}
|
||||
experiment->waiter_sp = read_sp();
|
||||
fc07_publish_task( 2U, FC07_ACTOR_WAITER, 0U, experiment );
|
||||
if( xSemaphoreTake( experiment->semaphore, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
lab_fail( 0xFC070202U );
|
||||
}
|
||||
experiment->waiter_ran = 1U;
|
||||
fc07_publish_task( 7U,
|
||||
FC07_ACTOR_WAITER,
|
||||
experiment->stimulus_after,
|
||||
experiment );
|
||||
experiment->waiter = NULL;
|
||||
vTaskDelete( NULL );
|
||||
lab_fail( 0xFC070203U );
|
||||
}
|
||||
|
||||
__attribute__( ( noinline, used ) )
|
||||
void fc07_stimulus_entry( void * context )
|
||||
{
|
||||
IsrExperiment * experiment = ( IsrExperiment * ) context;
|
||||
if( experiment == NULL )
|
||||
{
|
||||
lab_fail( 0xFC070301U );
|
||||
}
|
||||
experiment->stimulus_sp = read_sp();
|
||||
vTaskDelay( 1U );
|
||||
fc07_publish_task( 3U, FC07_ACTOR_STIMULUS, FC07_IRQ_MASK, experiment );
|
||||
H3_IO_SET_IRQ = FC07_IRQ_MASK;
|
||||
__asm__ volatile( "nop" ::: "memory" );
|
||||
experiment->stimulus_after = 1U;
|
||||
fc07_publish_task( 8U,
|
||||
FC07_ACTOR_STIMULUS,
|
||||
experiment->waiter_ran,
|
||||
experiment );
|
||||
experiment->stimulus = NULL;
|
||||
vTaskDelete( NULL );
|
||||
lab_fail( 0xFC070302U );
|
||||
}
|
||||
|
||||
__attribute__( ( noinline, used ) )
|
||||
void fc07_verifier_entry( void * context )
|
||||
{
|
||||
IsrExperiment * experiment = ( IsrExperiment * ) context;
|
||||
TickType_t started;
|
||||
if( experiment == NULL )
|
||||
{
|
||||
lab_fail( 0xFC070401U );
|
||||
}
|
||||
started = xTaskGetTickCount();
|
||||
while( experiment->stimulus_after == 0U || experiment->waiter_ran == 0U )
|
||||
{
|
||||
if( ( xTaskGetTickCount() - started ) > FC07_TIMEOUT_TICKS )
|
||||
{
|
||||
lab_fail( 0xFC070402U );
|
||||
}
|
||||
vTaskDelay( 1U );
|
||||
}
|
||||
experiment->pass =
|
||||
experiment->mcause == 0x8000000bU &&
|
||||
experiment->irq_source_after_clear == 0U &&
|
||||
experiment->higher_priority_task_woken == pdTRUE &&
|
||||
experiment->waiter_ran == 1U &&
|
||||
experiment->stimulus_after == 1U &&
|
||||
experiment->isr_sp != experiment->stimulus_sp &&
|
||||
experiment->isr_sp != experiment->waiter_sp;
|
||||
|
||||
/* E07 must precede E08: the ISR-requested context switch runs waiter
|
||||
* before the interrupted stimulus continues past the trigger store. */
|
||||
experiment->pass = experiment->pass != 0U &&
|
||||
g_fc07_events[ 6 ].actor == FC07_ACTOR_WAITER &&
|
||||
g_fc07_events[ 6 ].value == 0U &&
|
||||
g_fc07_events[ 7 ].actor == FC07_ACTOR_STIMULUS &&
|
||||
g_fc07_events[ 7 ].value == 1U;
|
||||
g_fc07_pass = experiment->pass;
|
||||
fc07_publish_task( 9U,
|
||||
FC07_ACTOR_VERIFIER,
|
||||
experiment->pass,
|
||||
experiment );
|
||||
experiment->digest = fc07_digest( g_fc07_events, g_fc07_event_count );
|
||||
if( experiment->pass == 0U ||
|
||||
fc07_order_is_valid( g_fc07_events, g_fc07_event_count ) == 0 )
|
||||
{
|
||||
lab_fail( 0xFC070403U );
|
||||
}
|
||||
lab_puts( "PASS FC07: real external IRQ, FromISR semaphore, immediate yield\n" );
|
||||
lab_put_u32( experiment->digest );
|
||||
lab_exit( 0U );
|
||||
}
|
||||
|
||||
static TaskHandle_t fc07_create_task( TaskFunction_t entry,
|
||||
const char * name,
|
||||
UBaseType_t priority )
|
||||
{
|
||||
TaskHandle_t handle = NULL;
|
||||
if( xTaskCreate( entry,
|
||||
name,
|
||||
FC07_TASK_STACK_WORDS,
|
||||
&g_fc07,
|
||||
priority,
|
||||
&handle ) != pdPASS )
|
||||
{
|
||||
lab_fail( 0xFC070501U + priority );
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
int main( void )
|
||||
{
|
||||
lab_heap_initialize();
|
||||
fc07_publish_task( 1U, FC07_ACTOR_MAIN, FC07_IRQ_NUMBER, &g_fc07 );
|
||||
g_fc07.semaphore = xSemaphoreCreateBinary();
|
||||
if( g_fc07.semaphore == NULL )
|
||||
{
|
||||
lab_fail( 0xFC070505U );
|
||||
}
|
||||
h3irq_enable( FC07_IRQ_NUMBER, true );
|
||||
h3irq_set_priority( FC07_IRQ_NUMBER, 8U );
|
||||
g_fc07.waiter = fc07_create_task( fc07_waiter_entry,
|
||||
"irq-waiter",
|
||||
FC07_WAITER_PRIORITY );
|
||||
g_fc07.stimulus = fc07_create_task( fc07_stimulus_entry,
|
||||
"irq-source",
|
||||
FC07_STIMULUS_PRIORITY );
|
||||
g_fc07.verifier = fc07_create_task( fc07_verifier_entry,
|
||||
"verifier",
|
||||
FC07_VERIFIER_PRIORITY );
|
||||
vTaskStartScheduler();
|
||||
lab_fail( 0xFC070506U );
|
||||
}
|
||||
Reference in New Issue
Block a user