aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2024-11-14 02:19:09 -0700
committerJosh Rahm <joshuarahm@gmail.com>2024-11-14 02:19:09 -0700
commitd1ebd3bd806f4b4e1f74703f682ca64994c79a28 (patch)
tree248a6a35a3b7c5232bcdafe6a6bfbe556be8ad0f
parentc9402e5a5d67ef877fa7f5f67c07a794574ded35 (diff)
downloadch573-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.txt9
-rw-r--r--cmake/fiddle.cmake32
-rw-r--r--include/isr_vector.h51
-rw-r--r--linker/ls.ld22
-rw-r--r--src/blinky.c74
-rw-r--r--src/init.c129
-rw-r--r--src/isr.s54
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();
- // }
}
diff --git a/src/init.c b/src/init.c
index 8d895f5..a81ce1d 100644
--- a/src/init.c
+++ b/src/init.c
@@ -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