diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2024-11-14 02:19:09 -0700 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2024-11-14 02:19:09 -0700 |
commit | d1ebd3bd806f4b4e1f74703f682ca64994c79a28 (patch) | |
tree | 248a6a35a3b7c5232bcdafe6a6bfbe556be8ad0f | |
parent | c9402e5a5d67ef877fa7f5f67c07a794574ded35 (diff) | |
download | ch573-d1ebd3bd806f4b4e1f74703f682ca64994c79a28.tar.gz ch573-d1ebd3bd806f4b4e1f74703f682ca64994c79a28.tar.bz2 ch573-d1ebd3bd806f4b4e1f74703f682ca64994c79a28.zip |
Get a good, basic framework for ISRs and properly handle the data sections.
-rw-r--r-- | CMakeLists.txt | 9 | ||||
-rw-r--r-- | cmake/fiddle.cmake | 32 | ||||
-rw-r--r-- | include/isr_vector.h | 51 | ||||
-rw-r--r-- | linker/ls.ld | 22 | ||||
-rw-r--r-- | src/blinky.c | 74 | ||||
-rw-r--r-- | src/init.c | 129 | ||||
-rw-r--r-- | src/isr.s | 54 |
7 files changed, 189 insertions, 182 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 09a39d9..792547f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) include(cmake/fiddle.cmake) -project (ch537) +project (ch537 LANGUAGES C ASM) # Configure for Bare Metal. set(CMAKE_SYSTEM_NAME Generic) @@ -12,9 +12,11 @@ set(CMAKE_SYSTEM_PROCESSOR riscv32) set(TC_PREFIX riscv32-unknown-elf-) include_directories(include linker ${CMAKE_BINARY_DIR}/generated/fdl) -file(GLOB SOURCES "src/*.c" "src/*.s") +file(GLOB_RECURSE SOURCES "src/*.c" "src/*.s") file(GLOB LINKER_SCRIPT "linker/*.ld") +message("Sources ${SOURCES}") + file(REAL_PATH "ch-flash/" CH_FLASH_DIR) # Set compiler and tools @@ -24,7 +26,8 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Set compiler and linker flags -set(CMAKE_C_FLAGS "-ffreestanding -march=rv32imac -mabi=ilp32 -lgcc -static -nostartfiles -O -std=gnu99" CACHE INTERNAL "C Compiler options") +set(CMAKE_C_FLAGS "-ffreestanding -march=rv32imac_zicsr -mabi=ilp32 -lgcc -static -nostartfiles -O -std=gnu99" CACHE INTERNAL "C Compiler options") +set(CMAKE_ASM_FLAGS "-ffreestanding -march=rv32imac_zicsr -mabi=ilp32 -lgcc -static -nostartfiles -O -std=gnu99" CACHE INTERNAL "C Compiler options") set(CMAKE_EXE_LINKER_FLAGS "--xref -static -T ${LINKER_SCRIPT}" CACHE INTERNAL "Linker options") # Add executable with custom linking commands diff --git a/cmake/fiddle.cmake b/cmake/fiddle.cmake new file mode 100644 index 0000000..6b151a2 --- /dev/null +++ b/cmake/fiddle.cmake @@ -0,0 +1,32 @@ +function(add_fiddle_source header_out fdl_file) + get_filename_component(dir_path ${fdl_file} DIRECTORY) + get_filename_component(file_name_without_extension ${fdl_file} NAME_WE) + set(path_without_extension "${dir_path}/${file_name_without_extension}") + + # Define the output path based on the input `.fdl` file's name + set(output_header "${CMAKE_BINARY_DIR}/generated/${path_without_extension}.h") + get_filename_component(output_dir ${output_header} DIRECTORY) + + # Define the custom command to generate the header + add_custom_command( + OUTPUT ${output_header} + DEPENDS ${fdl_file} + COMMENT "Fiddle compile ${fdl_file} -> ${output_header}" + COMMAND ${CMAKE_COMMAND} -E make_directory "${output_dir}" + COMMAND fiddlec -Lc -h ${output_header} -I ${CMAKE_SOURCE_DIR}/fdl/ --intf-dir ${CMAKE_BINARY_DIR}/fdli/ ${CMAKE_SOURCE_DIR}/${fdl_file} + ) + + # Make the output header file available as a source file for the target + set_source_files_properties(${output_header} PROPERTIES GENERATED TRUE) + set(${header_out} ${output_header} PARENT_SCOPE) +endfunction() + +function(fiddle_sources headers_out files) + set(headers) + foreach (fdl_file ${files}) + file(RELATIVE_PATH rel_path "${CMAKE_SOURCE_DIR}" "${fdl_file}") + add_fiddle_source(header_out ${rel_path}) + list(APPEND headers "${header_out}") + endforeach() + set(${headers_out} "${headers}" PARENT_SCOPE) +endfunction() diff --git a/include/isr_vector.h b/include/isr_vector.h index d916db0..bd5786a 100644 --- a/include/isr_vector.h +++ b/include/isr_vector.h @@ -2,55 +2,8 @@ #include <stdint.h> -/* Type def to a void function to make things mor ereadable. */ -typedef void (*isr_routine)(void); - -typedef struct { - // What NULL points to. nothing useful. - uint32_t reserved__; - // Called when the device boots or reset is pressed. - isr_routine reset_cb; - isr_routine nmi_cb; - isr_routine exc_cb; - - uint32_t _reserved_1[8]; - - isr_routine systick_cb; - - uint32_t _reserved_2; - - isr_routine swi_cb; - - uint32_t _reserved_3; - - isr_routine tmr0_cb; - isr_routine gpio_a_cb; - isr_routine gpio_b_cb; - isr_routine spi0_cb; - isr_routine blel_cb; - isr_routine bleb_cb; - isr_routine usb_cb; - - uint32_t _reserved_4; - - isr_routine tmr1_cb; - isr_routine tmr2_cb; - isr_routine uart0_cb; - isr_routine uart1_cb; - isr_routine rtc_cb; - isr_routine adc_cb; - - uint32_t _reserved_5; - - isr_routine pwmx_cb; - isr_routine tmr3_cb; - isr_routine uart2_cb; - isr_routine uart3_cb; - isr_routine wdog_bat_cb; -} isr_vector_t; - /** Reference to the global ISR vector. */ -extern isr_vector_t isr_vector; +extern char isr_vector; /** Default IRQ handler. This is weakly defined and can be overridden. */ void default_irq_handler(void); @@ -79,3 +32,5 @@ void irq_on_tmr3(void); void irq_on_uart2(void); void irq_on_uart3(void); void irq_on_wdog_bat(void); + +#define IRQ(name) void __attribute__((__section__(".isr_vector"))) name(void) diff --git a/linker/ls.ld b/linker/ls.ld index e4cc0af..18ee181 100644 --- a/linker/ls.ld +++ b/linker/ls.ld @@ -7,22 +7,36 @@ MEMORY SECTIONS { . = ORIGIN(flash); + .text : ALIGN(0x04) { - *(.isr_vector); - . = ALIGN(0x100); + *(.sinit); + + /* The ch573 starts execution at address 0x0000, so we have to make sure the + * on_reset function is put at the beginning of the flash. */ + *(.isr_routines.on_reset); + + /* The rest of the code. */ *(.text); } >flash AT>flash - DATA_VALUES_IN_FLASH = LOADADDR(.data); + ISR_VECTOR_IN_FLASH = LOADADDR(.isr_vector); + .isr_vector : ALIGN(0x04) { + ISR_VECTOR_START = .; + *(.isr_vector); + ISR_VECTOR_STOP = .; + } >sram AT>flash + DATA_VALUES_IN_FLASH = LOADADDR(.data); .data : ALIGN(0x04) { . = ALIGN(0x04); DATA_SEGMENT_START = .; *(.data); *(.data.*); + *(.sdata); *(.rodata.*); - DATA_SEGMENT_STOP = .; + *(.srodata.*); . = ALIGN(0x04); + DATA_SEGMENT_STOP = .; } >sram AT>flash .bss : ALIGN(0x04) { diff --git a/src/blinky.c b/src/blinky.c index d8a29bd..9f89238 100644 --- a/src/blinky.c +++ b/src/blinky.c @@ -1,50 +1,19 @@ #include <stdint.h> +#include "isr_vector.h" #include "ch573/gpio.h" #define GPIO_PORT_A ch573_gpio__gpio_port_a #define GPIO_PORT CH573_GPIO__GPIO_PORT_T_INTF -static void start(void); - -/* - * Function (or really pointer to code) for the reset interrupt handler. - */ -void on_reset(void); - /* * Function which delays for a bit. */ void delay(void); -/* Type def to a void function to make things mor ereadable. */ -typedef void (*isr_routine)(void); - -/** The ISR Vector structure. This is linked to starting at address 0. */ -// __attribute((__section__(".isr_vector"))) volatile struct { -// // What NULL points to. nothing useful. -// uint32_t reserved__; -// // Called when the device boots or reset is pressed. -// isr_routine reset_cb; -// isr_routine nmi_cb; -// isr_routine exc_cb; -// } isr_vectors = {.reset_cb = on_reset}; - -/* - * The reset callback.This has to be a naked function because the stack pointer - * may not be initialized!!. - */ -__attribute((naked)) void on_reset(void) -{ - // Set up the stack pointer to point to the end of SRAM. - asm volatile( - "li sp,0x20008000\n" - "addi sp,sp,-4\n" - "jalr %0\n" - "spin:\n" - "j spin\n" - : - : "r"(start)); +void main(void); +IRQ(irq_on_systick) { + main(); } uint32_t collatz(uint32_t n) @@ -77,38 +46,35 @@ void blink_n(int n) void delay(void) { - for (volatile uint32_t i = 0; i < 10000; ++i); + for (volatile uint32_t i = 0; i < 10000; ++i) { + asm volatile(""); + } } +volatile uint32_t deadbeef = 0xdeadbeef; + +// Memory-mapped address of the data values in flash. +extern uint32_t DATA_VALUES_IN_FLASH; + +// Where the data is located in sram. +extern uint32_t DATA_SEGMENT_START; +extern uint32_t DATA_SEGMENT_STOP; + /* Main routine. This is called on_reset once everything else has been set up. */ -static void start(void) +void main(void) { GPIO_PORT.dir.set(GPIO_PORT_A, DIR_OUT, 8); GPIO_PORT.pd_drv.set(GPIO_PORT_A, PD_DRV_OPEN_DRAIN, 8); for (;;) { - GPIO_PORT.out.set(GPIO_PORT_A, ON, 8); + if (deadbeef == 0xdeadbeef) { + GPIO_PORT.out.set(GPIO_PORT_A, ON, 8); + } delay(); delay(); delay(); GPIO_PORT.out.set(GPIO_PORT_A, OFF, 8); delay(); } - - // uint32_t i; - // for (i = 1;; ++i) { - // uint32_t c = collatz(i); - // blink_n(c); - - // delay(); - // delay(); - // delay(); - // delay(); - // delay(); - // delay(); - // delay(); - // delay(); - // delay(); - // } } @@ -2,34 +2,19 @@ #include <stdint.h> #include "isr_vector.h" -#include "ch573/gpio.h" - -_Static_assert(offsetof(typeof(isr_vector_t), nmi_cb) == 0x8, "Offset wrong"); - -_Static_assert( - offsetof(typeof(isr_vector_t), systick_cb) == 0x30, "Offset wrong "); - -_Static_assert( - offsetof(typeof(isr_vector_t), tmr0_cb) == 0x40, "Offset wrong "); - -_Static_assert( - offsetof(typeof(isr_vector_t), tmr1_cb) == 0x60, "Offset wrong "); - -_Static_assert( - offsetof(typeof(isr_vector_t), pwmx_cb) == 0x7c, "Offset wrong "); - -_Static_assert( - offsetof(typeof(isr_vector_t), wdog_bat_cb) == 0x8c, "Offset wrong "); void on_reset(void); -void __attribute__((weak, interrupt)) default_irq_handler(void) +void __attribute__((weak, interrupt, __section__(".isr_vector"))) +default_irq_handler(void) { return; } -#define WEAK_IRQ(irq) \ - void __attribute__((weak, alias("default_irq_handler"))) irq(void) +#define WEAK_IRQ(irq) \ + void __attribute__(( \ + weak, alias("default_irq_handler"), __section__(".isr_vector"))) \ + irq(void) WEAK_IRQ(irq_on_nmi); WEAK_IRQ(irq_on_exc); @@ -54,43 +39,28 @@ WEAK_IRQ(irq_on_uart2); WEAK_IRQ(irq_on_uart3); WEAK_IRQ(irq_on_wdog_bat); -/** The ISR Vector structure. This is linked to starting at address 0. */ -__attribute((__section__(".isr_vector"))) volatile isr_vector_t isr_vectors = { - .reset_cb = on_reset, - .nmi_cb = irq_on_nmi, - .exc_cb = irq_on_exc, - .systick_cb = irq_on_systick, - .swi_cb = irq_on_swi, - .tmr0_cb = irq_on_tmr0, - .gpio_a_cb = irq_on_gpio_a, - .gpio_b_cb = irq_on_gpio_b, - .spi0_cb = irq_on_spi0, - .blel_cb = irq_on_blel, - .bleb_cb = irq_on_bleb, - .usb_cb = irq_on_usb, - .tmr1_cb = irq_on_tmr1, - .tmr2_cb = irq_on_tmr2, - .uart0_cb = irq_on_uart0, - .uart1_cb = irq_on_uart1, - .rtc_cb = irq_on_rtc, - .adc_cb = irq_on_adc, - .pwmx_cb = irq_on_pwmx, - .tmr3_cb = irq_on_tmr3, - .uart2_cb = irq_on_uart2, - .uart3_cb = irq_on_uart3, - .wdog_bat_cb = irq_on_wdog_bat, -}; +// Memory-mapped address of the data values in flash. +extern uint32_t ISR_VECTOR_IN_FLASH; + +// Where the data is located in sram. +extern uint32_t ISR_VECTOR_START; +extern uint32_t ISR_VECTOR_STOP; // Memory-mapped address of the data values in flash. -extern uint32_t* DATA_VALUES_IN_FLASH; +extern uint32_t DATA_VALUES_IN_FLASH; // Where the data is located in sram. -extern uint32_t* DATA_SEGMENT_START; -extern uint32_t* DATA_SEGMENT_STOP; +extern uint32_t DATA_SEGMENT_START; +extern uint32_t DATA_SEGMENT_STOP; // Where 0-initialized data is in sram. -extern uint32_t* BSS_START; -extern uint32_t* BSS_STOP; +extern uint32_t BSS_START; +extern uint32_t BSS_STOP; + +static inline void set_mtvec(void* vector_table) +{ + asm volatile("csrw mtvec, %0" : : "r"(vector_table)); +} /* * Initialize the data segment and the bss segment. @@ -100,15 +70,23 @@ extern uint32_t* BSS_STOP; */ void init_data_segments(void) { - uint32_t* src = DATA_VALUES_IN_FLASH; - uint32_t* dest = DATA_SEGMENT_START; + /* Copy the data from the flash to memory. */ + uint32_t* src = &DATA_VALUES_IN_FLASH; + uint32_t* dest = &DATA_SEGMENT_START; + while (dest != &DATA_SEGMENT_STOP) { + *(dest++) = *(src++); + } - while (dest != DATA_SEGMENT_STOP) { + /* Copy the ISR vector to memory. This makes it possible to still recieve + * interrupts even when the flash is powered down. */ + src = &ISR_VECTOR_IN_FLASH; + dest = &ISR_VECTOR_START; + while (dest != &ISR_VECTOR_STOP) { *(dest++) = *(src++); } - dest = BSS_START; - while (dest != BSS_STOP) { + dest = &BSS_START; + while (dest != &BSS_STOP) { *(dest++) = 0; } } @@ -118,26 +96,31 @@ void init_data_segments(void) */ extern void main(void); -#define GPIO_PORT_A ch573_gpio__gpio_port_a -#define GPIO_PORT CH573_GPIO__GPIO_PORT_T_INTF /* Start function. Responsible for initializing the system and jumping to the * main function. */ -// static void start(void) -// { -// // init_data_segments(); -// GPIO_PORT.dir.set(GPIO_PORT_A, DIR_OUT, 8); -// GPIO_PORT.pd_drv.set(GPIO_PORT_A, PD_DRV_OPEN_DRAIN, 8); -// GPIO_PORT.out.set(GPIO_PORT_A, OFF, 8); -// -// main(); -// } - -/* - * The reset callback.This has to be a naked function because the stack pointer - * may not be initialized!!. - */ +static void start(void) +{ + /* Initialize the data segments. */ + init_data_segments(); + /* Set the mtvec to the isr_vector. */ + set_mtvec(&isr_vector); + /* Jump to main */ + main(); +} /* * The reset callback.This has to be a naked function because the stack pointer * may not be initialized!!. */ +__attribute((naked, __section__(".isr_routines.on_reset"))) void on_reset(void) +{ + // Set up the stack pointer to point to the end of SRAM. + asm volatile( + "li sp,0x20008000\n" + "addi sp,sp,-4\n" + "jalr %0\n" + "spin:\n" + "j spin\n" + : + : "r"(start)); +} diff --git a/src/isr.s b/src/isr.s new file mode 100644 index 0000000..6a9e6cf --- /dev/null +++ b/src/isr.s @@ -0,0 +1,54 @@ + +.section .sinit +_start: +j on_reset /* first instruction. Should jump directly to on_reset */ + +.section .isr_vector +.global isr_vector +isr_vector: +.align 4 +.word 0 + j irq_on_nmi + j irq_on_exc + +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 + + j irq_on_systick + +.word 0 + + j irq_on_swi + +.word 0 + + j irq_on_tmr0 + j irq_on_gpio_a + j irq_on_gpio_b + j irq_on_spi0 + j irq_on_blel + j irq_on_bleb + j irq_on_usb + +.word 0 + + j irq_on_tmr1 + j irq_on_tmr2 + j irq_on_uart0 + j irq_on_uart1 + j irq_on_rtc + j irq_on_adc + +.word 0 + + j irq_on_pwmx + j irq_on_tmr3 + j irq_on_uart2 + j irq_on_uart3 + j irq_on_wdog_bat |