Skip to content

Commit

Permalink
rtl+sw: implement single core FreeRTOS demo
Browse files Browse the repository at this point in the history
  • Loading branch information
NikLeberg committed Jan 7, 2024
1 parent 608df4f commit a023a6d
Show file tree
Hide file tree
Showing 7 changed files with 278 additions and 47 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ stderr
*.elf
*.o
sw/*.vhd
sw/*.asm
# ignore build artifacts of hardware
build/*
!build/makefile
107 changes: 107 additions & 0 deletions sw/include/FreeRTOSConfig.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* FreeRTOS V202212.00
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/

#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H

/* NEORV32 HAL */
#include <neorv32.h>

/*-----------------------------------------------------------
* Application specific definitions.
*
* Adapted for the NEORV32 RISC-V Processor.
*
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
*
* See http://www.freertos.org/a00110.html.
*----------------------------------------------------------*/
#define configMTIME_BASE_ADDRESS ( 0xF0000000UL + 0xBFF8 )
#define configMTIMECMP_BASE_ADDRESS ( 0xF0000000UL + 0x4000 )
#define configISR_STACK_SIZE_WORDS ( 128 )
#define configUSE_PREEMPTION ( 1 )
#define configUSE_IDLE_HOOK ( 1 )
#define configUSE_TICK_HOOK ( 0 )
#define configCPU_CLOCK_HZ ( 50000000 )
#define configTICK_RATE_HZ ( (TickType_t)(100) )
#define configMAX_PRIORITIES ( 5 )
#define configMINIMAL_STACK_SIZE ( (unsigned short)(128) )
#define configTOTAL_HEAP_SIZE ( (size_t)(4194304) )
#define configMAX_TASK_NAME_LEN ( 16 )
#define configUSE_TRACE_FACILITY ( 0 )
#define configUSE_16_BIT_TICKS ( 0 )
#define configIDLE_SHOULD_YIELD ( 0 )
#define configUSE_MUTEXES ( 1 )
#define configQUEUE_REGISTRY_SIZE ( 8 )
#define configCHECK_FOR_STACK_OVERFLOW ( 0 )
#define configUSE_RECURSIVE_MUTEXES ( 1 )
#define configUSE_MALLOC_FAILED_HOOK ( 0 )
#define configUSE_APPLICATION_TASK_TAG ( 0 )
#define configUSE_COUNTING_SEMAPHORES ( 1 )
#define configGENERATE_RUN_TIME_STATS ( 0 )
#define configUSE_PORT_OPTIMISED_TASK_SELECTION ( 1 )
#define configUSE_QUEUE_SETS ( 0 )
#define configTASK_NOTIFICATION_ARRAY_ENTRIES ( 4 )

/* Co-routine definitions. */
#define configUSE_CO_ROUTINES ( 0 )
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )

/* Software timer definitions. */
#define configUSE_TIMERS ( 1 )
#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
#define configTIMER_QUEUE_LENGTH ( 8 )
#define configTIMER_TASK_STACK_DEPTH ( 160 )

/* Task priorities. Allow these to be overridden. */
#ifndef uartPRIMARY_PRIORITY
#define uartPRIMARY_PRIORITY ( configMAX_PRIORITIES - 3 )
#endif

/* Set the following definitions to 1 to include the API function, or zero to exclude the API function. */
#define INCLUDE_vTaskPrioritySet ( 1 )
#define INCLUDE_uxTaskPriorityGet ( 1 )
#define INCLUDE_vTaskDelete ( 1 )
#define INCLUDE_vTaskCleanUpResources ( 1 )
#define INCLUDE_vTaskSuspend ( 1 )
#define INCLUDE_vTaskDelayUntil ( 1 )
#define INCLUDE_vTaskDelay ( 1 )
#define INCLUDE_eTaskGetState ( 1 )
#define INCLUDE_xTimerPendFunctionCall ( 1 )
#define INCLUDE_xTaskAbortDelay ( 1 )
#define INCLUDE_xTaskGetHandle ( 1 )
#define INCLUDE_xSemaphoreGetMutexHolder ( 1 )

/* Normal assert() semantics without relying on the provision of an assert.h header file. */
void
vAssertCalled(void);
#define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled()

/* Map to the platform's write function. */
#define configPRINT_STRING( pcString ) vSendString( pcString )

#endif /* FREERTOS_CONFIG_H */
62 changes: 62 additions & 0 deletions sw/include/freertos_risc_v_chip_specific_extensions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/

/*
* 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
* RISC-V ISA), and code that tailors the port to a specific RISC-V chip:
*
* + FreeRTOS\Source\portable\GCC\RISC-V-RV32\portASM.S contains the code that
* is common to all currently supported RISC-V chips. There is only one
* portASM.S file because the same file is built for all RISC-V target chips.
*
* + Header files called freertos_risc_v_chip_specific_extensions.h contain the
* code that tailors the FreeRTOS kernel's RISC-V port to a specific RISC-V
* chip. There are multiple freertos_risc_v_chip_specific_extensions.h files
* as there are multiple RISC-V chip implementations.
*/

/*
* NEORV32 chip-specific extensions
*/

#ifndef __FREERTOS_RISC_V_EXTENSIONS_H__
#define __FREERTOS_RISC_V_EXTENSIONS_H__

#define portasmHAS_MTIME ( 1 )
#define portasmADDITIONAL_CONTEXT_SIZE ( 0 )

.macro portasmSAVE_ADDITIONAL_REGISTERS
/* No additional registers to save, so this macro does nothing. */
.endm

.macro portasmRESTORE_ADDITIONAL_REGISTERS
/* No additional registers to restore, so this macro does nothing. */
.endm

#endif /* __FREERTOS_RISC_V_EXTENSIONS_H__ */
15 changes: 14 additions & 1 deletion sw/makefile.sw
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@ NEORV32_HOME = ../lib/neorv32
RISCV_PREFIX = riscv32-unknown-elf-

# CPU architecture
MARCH = rv32ima_zicsr
MARCH = rv32imac_zicsr

# FreeRTOS kernel home folder
FREERTOS_HOME = ../lib/FreeRTOS/FreeRTOS/Source

# User flags for additional configuration (will be added to compiler flags)
USER_FLAGS := $(CLI_FLAGS)
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16K
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=32M
USER_FLAGS += -Wl,--defsym,__neorv32_stack_size=8K
USER_FLAGS += -Wl,--defsym,__neorv32_num_harts=4
USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=4M
USER_FLAGS += -Og

# Change flags if we are building for the simulation.
Expand All @@ -24,6 +28,15 @@ endif
# Add application sources
APP_SRC += $(wildcard ./src/*.c) $(wildcard ./src/*.s) $(wildcard ./src/*.cpp) $(wildcard ./src/*.S)
APP_INC += -I ./include
ASM_INC += -I ./include

# Add FreeRTOS sources
APP_SRC += $(wildcard $(FREERTOS_HOME)/*.c)
APP_INC += -I $(FREERTOS_HOME)/include
APP_SRC += $(wildcard $(FREERTOS_HOME)/portable/GCC/RISC-V/*.c)
APP_SRC += $(FREERTOS_HOME)/portable/GCC/RISC-V/portASM.S
APP_INC += -I $(FREERTOS_HOME)/portable/GCC/RISC-V
APP_SRC += $(wildcard $(FREERTOS_HOME)/portable/MemMang/heap_4.c)

# Include the common neorv32 buildsystem. Provides targets like exe, bin etc.
include $(NEORV32_HOME)/sw/common/common.mk
Expand Down
117 changes: 79 additions & 38 deletions sw/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,90 @@
*
*/

#include <FreeRTOS.h>
#include <task.h>

#include <neorv32.h>
#include "smp.h"

void delay_ms(uint32_t time_ms) {
void vAssertCalled(void);
void vApplicationIdleHook(void);

extern void freertos_risc_v_trap_handler(void); // FreeRTOS core
static void setup_port(void);
static void blinky(void *args);
static void delay_ms(uint32_t time_ms);

// void msi_handler(void) {
// smp_reset_ipi_for_hart(smp_get_hart_id());
// }

static smp_mutex_t mutex = SMP_MUTEX_INIT;

/**
* @brief Main function
*
* @return will never return
*/
int main() {
// setup hardware and port software
setup_port();
// create a simple task
xTaskCreate(blinky, "blinky", configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 2, NULL);
// start the scheduler
vTaskStartScheduler();
// will not get here unless something went horribly wrong
for (;;) {
neorv32_gpio_pin_toggle(1);
neorv32_gpio_pin_toggle(2);
delay_ms(100);
}
}

static void setup_port(void) {
// install the freeRTOS kernel trap handler
neorv32_cpu_csr_write(CSR_MTVEC, (uint32_t)&freertos_risc_v_trap_handler);
// // the first HART is responsible to wake up all other cores
// uint32_t hart_id = neorv32_cpu_csr_read(CSR_MHARTID);
// if (hart_id == 0) {
// // enable other cores with msi interrupt aka ipi
// smp_set_ipi_for_hart(1);
// smp_set_ipi_for_hart(2);
// smp_set_ipi_for_hart(3);
// smp_set_ipi_for_hart(4);
// }
}

void vAssertCalled(void) {
/* Flash the lowest 2 LEDs to indicate that assert was hit - interrupts are
off here to prevent any further tick interrupts or context switches, so the
delay is implemented as a busy-wait loop instead of a peripheral timer. */
taskDISABLE_INTERRUPTS();
neorv32_gpio_port_set(0);
while (1) {
for (int i = 0; i < (configCPU_CLOCK_HZ / 100); i++) {
__asm volatile("nop");
}
neorv32_gpio_pin_toggle(0);
neorv32_gpio_pin_toggle(1);
}
}

void vApplicationIdleHook(void) {
// put CPU into sleep mote, it wakes up on any interrupt request
neorv32_cpu_sleep();
}

static void blinky(void *args) {
(void)args;
uint32_t hart_id = neorv32_cpu_csr_read(CSR_MHARTID);
for (;;) {
neorv32_gpio_pin_toggle(0);
vTaskDelay(2);
}
}

void delay_ms(uint32_t time_ms) {
#ifndef SIMULATION
uint32_t clock = 50000000; // clock ticks per second
clock = clock / 1000; // clock ticks per ms
Expand All @@ -38,40 +116,3 @@ void delay_ms(uint32_t time_ms) {
: [cnt_w] "=r"(iterations)
: [cnt_r] "r"(iterations));
}

void msi_handler(void) {
smp_reset_ipi_for_hart(smp_get_hart_id());
}

static smp_mutex_t mutex = SMP_MUTEX_INIT;

/**
* @brief Main function
*
* @return will never return
*/
int main() {

// let each hart blink its own led
uint32_t hart_id = neorv32_cpu_csr_read(CSR_MHARTID);
uint32_t delay = (128 << hart_id);

if (hart_id == 0) {
delay_ms(32);
// enable other cores with msi interrupt aka ipi
smp_set_ipi_for_hart(1);
smp_set_ipi_for_hart(2);
smp_set_ipi_for_hart(3);
smp_set_ipi_for_hart(4);
}

for (;;) {
smp_mutex_take(&mutex);
neorv32_gpio_pin_toggle(hart_id);
smp_mutex_give(&mutex);
delay_ms(delay);
}

// this should never be reached
return 0;
}
2 changes: 1 addition & 1 deletion vhdl/neorv32_cpu_smp/neorv32_cpu_smp.vhdl
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ BEGIN
-- RISC-V CPU Extensions --
CPU_EXTENSION_RISCV_A => true, -- implement atomic memory operations extension?
CPU_EXTENSION_RISCV_B => false, -- implement bit-manipulation extension?
CPU_EXTENSION_RISCV_C => false, -- implement compressed extension?
CPU_EXTENSION_RISCV_C => true, -- implement compressed extension?
CPU_EXTENSION_RISCV_E => false, -- implement embedded RF extension?
CPU_EXTENSION_RISCV_M => true, -- implement mul/div extension?
CPU_EXTENSION_RISCV_U => false, -- implement user mode extension?
Expand Down
21 changes: 14 additions & 7 deletions vhdl/top/tb/top_tb.vhdl
Original file line number Diff line number Diff line change
Expand Up @@ -67,18 +67,25 @@ BEGIN
-- Each hart tries to blink its respective LED on gpio0.
-- Check that hart0 is able to blink it a few times.

FOR i IN 0 TO 3 LOOP
-- Wait for LSB gpio bit to go high.
WAIT UNTIL s_gpio0_o(0) = '1' FOR 100 us;
ASSERT s_gpio0_o(0) = '1'
REPORT "LED0 was not observed to go high, did hart0 run?"
SEVERITY failure;
-- Wait for LSB gpio bit to go high. The SW is first setting up FreeRTOS
-- and requires more time for the first toggle.
WAIT UNTIL s_gpio0_o(0) = '1' FOR 1000 us;
ASSERT s_gpio0_o(0) = '1'
REPORT "LED0 was not observed to go high, did hart0 run?"
SEVERITY failure;

FOR i IN 0 TO 3 LOOP
-- Wait for LSB gpio bit to go low.
WAIT UNTIL s_gpio0_o(0) = '0' FOR 100 us;
WAIT UNTIL s_gpio0_o(0) = '0' FOR 50 us;
ASSERT s_gpio0_o(0) = '0'
REPORT "LED0 was not observed to go low, did hart0 run?"
SEVERITY failure;

-- Wait for LSB gpio bit to go high.
WAIT UNTIL s_gpio0_o(0) = '1' FOR 50 us;
ASSERT s_gpio0_o(0) = '1'
REPORT "LED0 was not observed to go high, did hart0 run?"
SEVERITY failure;
END LOOP;

-- Report successful test.
Expand Down

0 comments on commit a023a6d

Please sign in to comment.