feat: publish FreeRTOS C FC05 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,18 @@
|
||||
.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
|
||||
@@ -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,288 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "queue.h"
|
||||
#include "task.h"
|
||||
#include "lab_freertos.h"
|
||||
#include "lab_io.h"
|
||||
#include "task01_queue.h"
|
||||
#include "task01_queue_model.h"
|
||||
|
||||
#define FC05_ACTOR_MAIN 1U
|
||||
#define FC05_ACTOR_RECEIVER 2U
|
||||
#define FC05_ACTOR_SENDER 3U
|
||||
#define FC05_ACTOR_VERIFIER 4U
|
||||
|
||||
QueueExperiment g_fc05;
|
||||
QueueEvidence g_fc05_events[ FC05_EVENT_CAPACITY ];
|
||||
volatile uint32_t g_fc05_event_count;
|
||||
volatile uint32_t g_fc05_last_checkpoint;
|
||||
volatile uint32_t g_fc05_pass;
|
||||
|
||||
static uintptr_t read_sp( void )
|
||||
{
|
||||
uintptr_t value;
|
||||
__asm__ volatile( "mv %0, sp" : "=r"( value ) );
|
||||
return value;
|
||||
}
|
||||
|
||||
__attribute__( ( noinline, used ) )
|
||||
void fc05_checkpoint_committed( uint32_t point, const void * subject )
|
||||
{
|
||||
( void ) point;
|
||||
( void ) subject;
|
||||
__asm__ volatile( "" ::: "memory" );
|
||||
}
|
||||
|
||||
static void fc05_publish( uint32_t point,
|
||||
uint32_t actor,
|
||||
uint32_t value,
|
||||
const void * subject )
|
||||
{
|
||||
UBaseType_t critical_state;
|
||||
uint32_t index;
|
||||
QueueEvidence * event;
|
||||
|
||||
critical_state = taskENTER_CRITICAL_FROM_ISR();
|
||||
index = g_fc05_event_count;
|
||||
if( index >= FC05_EVENT_CAPACITY )
|
||||
{
|
||||
taskEXIT_CRITICAL_FROM_ISR( critical_state );
|
||||
lab_fail( 0xFC050001U );
|
||||
}
|
||||
|
||||
event = &g_fc05_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 = 0xFC050000U | ( index + 1U );
|
||||
g_fc05_event_count = index + 1U;
|
||||
g_fc05_last_checkpoint = point;
|
||||
taskEXIT_CRITICAL_FROM_ISR( critical_state );
|
||||
fc05_checkpoint_committed( point, subject );
|
||||
}
|
||||
|
||||
static QueueMessage fc05_message( uint32_t sequence, uint32_t payload )
|
||||
{
|
||||
QueueMessage message;
|
||||
message.sequence = sequence;
|
||||
message.payload = payload;
|
||||
message.checksum = fc05_message_checksum( sequence, payload );
|
||||
return message;
|
||||
}
|
||||
|
||||
__attribute__( ( noinline, used ) )
|
||||
void fc05_receiver_entry( void * context )
|
||||
{
|
||||
QueueExperiment * experiment = ( QueueExperiment * ) context;
|
||||
|
||||
if( experiment == NULL )
|
||||
{
|
||||
lab_fail( 0xFC050101U );
|
||||
}
|
||||
|
||||
experiment->receiver_sp = read_sp();
|
||||
fc05_publish( 2U, FC05_ACTOR_RECEIVER, 0U, experiment );
|
||||
|
||||
if( xQueueReceive( experiment->queue,
|
||||
&experiment->received[ 0 ],
|
||||
portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
lab_fail( 0xFC050102U );
|
||||
}
|
||||
fc05_publish( 4U,
|
||||
FC05_ACTOR_RECEIVER,
|
||||
experiment->received[ 0 ].payload,
|
||||
&experiment->received[ 0 ] );
|
||||
|
||||
vTaskDelay( 2U );
|
||||
experiment->sender_state_when_full =
|
||||
eTaskGetState( experiment->sender_handle );
|
||||
experiment->waiting_when_full =
|
||||
uxQueueMessagesWaiting( experiment->queue );
|
||||
fc05_publish( 6U,
|
||||
FC05_ACTOR_RECEIVER,
|
||||
( uint32_t ) experiment->sender_state_when_full,
|
||||
experiment );
|
||||
|
||||
if( xQueueReceive( experiment->queue,
|
||||
&experiment->received[ 1 ],
|
||||
0U ) != pdPASS )
|
||||
{
|
||||
lab_fail( 0xFC050103U );
|
||||
}
|
||||
fc05_publish( 7U,
|
||||
FC05_ACTOR_RECEIVER,
|
||||
experiment->received[ 1 ].payload,
|
||||
&experiment->received[ 1 ] );
|
||||
|
||||
if( xQueueReceive( experiment->queue,
|
||||
&experiment->received[ 2 ],
|
||||
portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
lab_fail( 0xFC050104U );
|
||||
}
|
||||
fc05_publish( 8U,
|
||||
FC05_ACTOR_RECEIVER,
|
||||
experiment->received[ 2 ].payload,
|
||||
&experiment->received[ 2 ] );
|
||||
|
||||
experiment->receiver_done = 1U;
|
||||
experiment->receiver_handle = NULL;
|
||||
vTaskDelete( NULL );
|
||||
lab_fail( 0xFC050105U );
|
||||
}
|
||||
|
||||
__attribute__( ( noinline, used ) )
|
||||
void fc05_sender_entry( void * context )
|
||||
{
|
||||
QueueExperiment * experiment = ( QueueExperiment * ) context;
|
||||
QueueMessage source;
|
||||
|
||||
if( experiment == NULL )
|
||||
{
|
||||
lab_fail( 0xFC050201U );
|
||||
}
|
||||
|
||||
experiment->sender_sp = read_sp();
|
||||
source = fc05_message( 1U, 0x1111U );
|
||||
fc05_publish( 3U, FC05_ACTOR_SENDER, source.payload, &source );
|
||||
if( xQueueSend( experiment->queue, &source, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
lab_fail( 0xFC050202U );
|
||||
}
|
||||
|
||||
source = fc05_message( 2U, 0x2222U );
|
||||
if( xQueueSend( experiment->queue, &source, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
lab_fail( 0xFC050203U );
|
||||
}
|
||||
source.payload = 0xDEADU;
|
||||
source.checksum = fc05_message_checksum( source.sequence, source.payload );
|
||||
experiment->mutated_source = source;
|
||||
fc05_publish( 5U,
|
||||
FC05_ACTOR_SENDER,
|
||||
uxQueueMessagesWaiting( experiment->queue ),
|
||||
&experiment->mutated_source );
|
||||
|
||||
source = fc05_message( 3U, 0x3333U );
|
||||
if( xQueueSend( experiment->queue, &source, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
lab_fail( 0xFC050204U );
|
||||
}
|
||||
fc05_publish( 9U, FC05_ACTOR_SENDER, source.payload, &source );
|
||||
|
||||
experiment->sender_done = 1U;
|
||||
experiment->sender_handle = NULL;
|
||||
vTaskDelete( NULL );
|
||||
lab_fail( 0xFC050205U );
|
||||
}
|
||||
|
||||
static int fc05_messages_are_correct( const QueueExperiment * experiment )
|
||||
{
|
||||
return fc05_message_is_valid( &experiment->received[ 0 ] ) != 0 &&
|
||||
fc05_message_is_valid( &experiment->received[ 1 ] ) != 0 &&
|
||||
fc05_message_is_valid( &experiment->received[ 2 ] ) != 0 &&
|
||||
experiment->received[ 0 ].sequence == 1U &&
|
||||
experiment->received[ 0 ].payload == 0x1111U &&
|
||||
experiment->received[ 1 ].sequence == 2U &&
|
||||
experiment->received[ 1 ].payload == 0x2222U &&
|
||||
experiment->received[ 2 ].sequence == 3U &&
|
||||
experiment->received[ 2 ].payload == 0x3333U &&
|
||||
experiment->mutated_source.payload == 0xDEADU;
|
||||
}
|
||||
|
||||
__attribute__( ( noinline, used ) )
|
||||
void fc05_verifier_entry( void * context )
|
||||
{
|
||||
QueueExperiment * experiment = ( QueueExperiment * ) context;
|
||||
TickType_t started;
|
||||
|
||||
if( experiment == NULL )
|
||||
{
|
||||
lab_fail( 0xFC050301U );
|
||||
}
|
||||
|
||||
started = xTaskGetTickCount();
|
||||
while( experiment->receiver_done == 0U || experiment->sender_done == 0U )
|
||||
{
|
||||
if( ( xTaskGetTickCount() - started ) > FC05_TIMEOUT_TICKS )
|
||||
{
|
||||
lab_fail( 0xFC050302U );
|
||||
}
|
||||
vTaskDelay( 1U );
|
||||
}
|
||||
|
||||
experiment->pass =
|
||||
fc05_messages_are_correct( experiment ) != 0 &&
|
||||
experiment->sender_state_when_full == eBlocked &&
|
||||
experiment->waiting_when_full == 1U &&
|
||||
experiment->receiver_sp != experiment->sender_sp &&
|
||||
g_fc05_event_count == 9U;
|
||||
g_fc05_pass = experiment->pass;
|
||||
|
||||
fc05_publish( 10U,
|
||||
FC05_ACTOR_VERIFIER,
|
||||
experiment->pass,
|
||||
experiment );
|
||||
experiment->evidence_digest =
|
||||
fc05_digest( g_fc05_events, g_fc05_event_count );
|
||||
|
||||
if( experiment->pass == 0U )
|
||||
{
|
||||
lab_fail( 0xFC050303U );
|
||||
}
|
||||
|
||||
lab_puts( "PASS FC05: queue empty/full blocking, FIFO, byte copy\n" );
|
||||
lab_put_u32( experiment->evidence_digest );
|
||||
lab_exit( 0U );
|
||||
}
|
||||
|
||||
static TaskHandle_t fc05_create_task( TaskFunction_t entry,
|
||||
const char * name,
|
||||
UBaseType_t priority )
|
||||
{
|
||||
TaskHandle_t handle = NULL;
|
||||
if( xTaskCreate( entry,
|
||||
name,
|
||||
FC05_TASK_STACK_WORDS,
|
||||
&g_fc05,
|
||||
priority,
|
||||
&handle ) != pdPASS )
|
||||
{
|
||||
lab_fail( 0xFC050401U + priority );
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
int main( void )
|
||||
{
|
||||
lab_heap_initialize();
|
||||
fc05_publish( 1U, FC05_ACTOR_MAIN, FC05_QUEUE_LENGTH, &g_fc05 );
|
||||
|
||||
g_fc05.queue = xQueueCreate( FC05_QUEUE_LENGTH, sizeof( QueueMessage ) );
|
||||
if( g_fc05.queue == NULL )
|
||||
{
|
||||
lab_fail( 0xFC050402U );
|
||||
}
|
||||
|
||||
g_fc05.receiver_handle =
|
||||
fc05_create_task( fc05_receiver_entry,
|
||||
"receiver",
|
||||
FC05_RECEIVER_PRIORITY );
|
||||
g_fc05.sender_handle =
|
||||
fc05_create_task( fc05_sender_entry,
|
||||
"sender",
|
||||
FC05_SENDER_PRIORITY );
|
||||
g_fc05.verifier_handle =
|
||||
fc05_create_task( fc05_verifier_entry,
|
||||
"verifier",
|
||||
FC05_VERIFIER_PRIORITY );
|
||||
|
||||
vTaskStartScheduler();
|
||||
lab_fail( 0xFC050403U );
|
||||
}
|
||||
Reference in New Issue
Block a user