diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2024-11-16 13:04:54 -0700 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2024-11-16 13:04:54 -0700 |
commit | df8d98fb41a218e41bbf8cdc8a3f89a61cb04f23 (patch) | |
tree | a4df370381f4b46e3aa3452d5d15615f17211acc | |
parent | ede9bee7f22fd5d0e1bacb7689f1cac23992b70b (diff) | |
download | ch573-df8d98fb41a218e41bbf8cdc8a3f89a61cb04f23.tar.gz ch573-df8d98fb41a218e41bbf8cdc8a3f89a61cb04f23.tar.bz2 ch573-df8d98fb41a218e41bbf8cdc8a3f89a61cb04f23.zip |
Properly link against picolibc.
We now have full access to a c standard library.
-rw-r--r-- | CMakeLists.txt | 64 | ||||
-rw-r--r-- | linker/ls.ld | 14 | ||||
-rw-r--r-- | src/init.c | 2 | ||||
-rw-r--r-- | src/main.c | 177 |
4 files changed, 207 insertions, 50 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 792547f..1fdfa58 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,56 +1,70 @@ cmake_minimum_required(VERSION 3.10) + set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) -include(cmake/fiddle.cmake) +set(TC_PREFIX riscv32-picolibc-elf-) +# Set compiler and tools +set(CMAKE_C_COMPILER "${TC_PREFIX}gcc" CACHE INTERNAL "C Compiler") +set(CMAKE_OBJCOPY "${TC_PREFIX}objcopy" CACHE INTERNAL "Object Copier") +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +file(REAL_PATH "stubs/libgloss_stub.c" LIBGLOSS_STUB) -project (ch537 LANGUAGES C ASM) # Configure for Bare Metal. set(CMAKE_SYSTEM_NAME Generic) set(CMAKE_SYSTEM_PROCESSOR riscv32) -set(TC_PREFIX riscv32-unknown-elf-) +include(cmake/fiddle.cmake) + +project (ch537 LANGUAGES C ASM) + +# Set compiler and linker flags +file(GLOB LINKER_SCRIPT "linker/*.ld") +set(CMAKE_C_FLAGS "-march=rv32imac_zicsr -mabi=ilp32 -lgcc -static -O -std=gnu99" CACHE INTERNAL "C Compiler options") +set(CMAKE_ASM_FLAGS "-march=rv32imac_zicsr -mabi=ilp32 -lgcc -static -O -std=gnu99" CACHE INTERNAL "C Compiler options") +set(CMAKE_EXE_LINKER_FLAGS "-static -L ${CMAKE_BINARY_DIR}/lib -lmain -T ${LINKER_SCRIPT}" CACHE INTERNAL "Linker options") + include_directories(include linker ${CMAKE_BINARY_DIR}/generated/fdl) 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 -set(CMAKE_C_COMPILER "${TC_PREFIX}gcc" CACHE INTERNAL "C Compiler") -set(CMAKE_OBJCOPY "${TC_PREFIX}objcopy" CACHE INTERNAL "Object Copier") -set(CMAKE_EXPORT_COMPILE_COMMANDS ON) - +add_library(libmain STATIC ${SOURCES}) +set_target_properties(libmain PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib + OUTPUT_NAME main +) -# Set compiler and linker flags -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 -add_executable(main.elf ${SOURCES}) -add_dependencies(main.elf fdl_headers) - -# Replace default link command to use `ld` directly without `-Wl,` prefixes. -set_target_properties(main.elf PROPERTIES - LINKER_LANGUAGE C - LINK_FLAGS "-nostdlib -e 0" - # Custom linking command - CMAKE_C_LINK_EXECUTABLE "${TC_PREFIX}ld <LINK_FLAGS> <OBJECTS> -o <TARGET> ${CMAKE_EXE_LINKER_FLAGS}" +add_library(libgloss_stub STATIC ${LIBGLOSS_STUB}) +set_target_properties(libgloss_stub PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib + OUTPUT_NAME gloss ) +add_dependencies(libmain fdl_headers) + set(fdl_headers) file(GLOB_RECURSE fdl_files "${CMAKE_SOURCE_DIR}/fdl/*.fdl") fiddle_sources(fdl_headers "${fdl_files}") add_custom_target( fdl_headers DEPENDS ${fdl_headers}) +add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/main.elf + DEPENDS libmain libgloss_stub + COMMENT "Link main.elf" + COMMAND ${TC_PREFIX}gcc -nostartfiles -lgcc + -static -L ${CMAKE_BINARY_DIR}/lib -lmain -T ${LINKER_SCRIPT} + -o ${CMAKE_BINARY_DIR}/main.elf + ${CMAKE_BINARY_DIR}/lib/libmain.a +) + # Generates the binary with objcopy. add_custom_command( OUTPUT main.bin - DEPENDS main.elf + DEPENDS ${CMAKE_BINARY_DIR}/main.elf COMMENT "objcopy -O binary main.elf main.bin" COMMAND ${CMAKE_OBJCOPY} -O binary main.elf main.bin ) diff --git a/linker/ls.ld b/linker/ls.ld index 916438b..4ecac96 100644 --- a/linker/ls.ld +++ b/linker/ls.ld @@ -1,3 +1,5 @@ +ENTRY(_begin) + MEMORY { flash : org = 0x00000000, len = 512k @@ -18,8 +20,16 @@ SECTIONS /* The rest of the code. */ *(.text); + *(.text.*); } >flash AT>flash + .rodata : ALIGN(0x04) { + *(.rodata); + *(.rodata.*); + *(.srodata); + *(.srodata.*); + } > flash AT>flash + ISR_VECTOR_IN_FLASH = LOADADDR(.isr_vector); .isr_vector : ALIGN(0x04) { ISR_VECTOR_START = .; @@ -35,8 +45,7 @@ SECTIONS *(.data); *(.data.*); *(.sdata); - *(.rodata.*); - *(.srodata.*); + *(.sdata.*); . = ALIGN(0x04); DATA_SEGMENT_STOP = .; } >sram AT>flash @@ -45,6 +54,7 @@ SECTIONS . = ALIGN(0x04); BSS_START = .; *(.bss); + *(.sbss); BSS_STOP = .; HEAP_START = .; } >sram @@ -97,7 +97,7 @@ void init_data_segments(void) /* * External reference to the main() function. */ -extern void main(void); +extern int main(void); /* Start function. Responsible for initializing the system and jumping to the * main function. */ @@ -1,9 +1,10 @@ #include <stdint.h> +#include <stdio.h> +#include <string.h> #include "ch573/gpio.h" -#include "ch573/uart.h" #include "ch573/pwr.h" - +#include "ch573/uart.h" #include "isr_vector.h" #define GPIO_PORT_A ch573_gpio__gpio_port_a @@ -15,12 +16,49 @@ #define PWR1 ch573_pwr__pwr_mgmt #define PWR CH573_PWR__PWR_MGMT_T_INTF +void stack_dump(uint32_t*); +void print_hex(uint32_t x); + +int uart1_FILE_put(char ch, FILE* f) +{ + if (ch == '\n') { + uart1_FILE_put('\r', f); + } + + while (!UART.lsr.thr_empty.get(UART1)); + UART.thr.set(UART1, ch); + return 1; +} + +static int uart1_FILE_get(FILE* f) +{ + return -1; +} + +static int uart1_FILE_flush(FILE* f) +{ + return 0; +} + +FILE _uart1_FILE = (FILE){ + .put = uart1_FILE_put, + .get = uart1_FILE_get, + .flush = uart1_FILE_flush, + .flags = __SWR, +}; + +FILE* const stdout = &_uart1_FILE; + +int my_puts(const char* str); + +// FILE* const stdout = &_uart1_FILE; + /* * Function which delays for a bit. */ void delay(void); -void main(void); +int main(void); uint32_t collatz(uint32_t n) { @@ -59,47 +97,57 @@ void delay(void) 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; - #define gpio_usart1_tx_pin 9 #define gpio_usart1_rx_pin 8 -const char* hello_world = "Hello, World!\r\n"; +const char* hello_world_static = "Hello, World!\r\n"; #define BAUD_RATE 115200 +int test(char ch, ...); + /* Main routine. This is called on_reset once everything else has been set up. */ -void main(void) +int main(void) { GPIO_PORT.dir.set(GPIO_PORT_A, DIR_OUT, gpio_usart1_tx_pin); GPIO_PORT.pd_drv.set(GPIO_PORT_A, 0, gpio_usart1_tx_pin); + GPIO_PORT.dir.set(GPIO_PORT_A, DIR_OUT, 8); + GPIO_PORT.pd_drv.set(GPIO_PORT_A, 0, 8); + UART.div.set(UART1, 1); UART.fcr.set(UART1, 0x07); UART.ier.txd_en.set(UART1, ON); UART.lcr.word_sz.set(UART1, WORD_SZ_8_BITS); - uint32_t dl = (10 * 6400000 / 8 / BAUD_RATE + 5) / 10; + volatile uint32_t dl = (10 * 6400000 / 8 / BAUD_RATE + 5) / 10; UART.dl.set(UART1, dl); - - // PWR.slp_clk_off_0.uart1.set(PWR1, CLK_SOURCE_ENABLED); - const char* ptr = hello_world; + char buf[32] = { 0 }; + volatile uint32_t i = 0xdeadbeef; - while (1) { - if (*ptr == 0) { - ptr = hello_world; - } + stack_dump(&i); + + print_hex(i); + + stdout->put('a', NULL); + stdout->put('\n', NULL); + fputs("bulitin fputs\n", stdout); + my_puts("my_puts\n"); + puts("bulitin puts\n"); - while (!UART.lsr.thr_empty.get(UART1)); - UART.thr.set(UART1, *(ptr++)); + while (1) { + fprintf(stdout, "Hello! %% %s\n", "Josh"); + fputs(buf, &_uart1_FILE); + delay(); } + + // printf("Hello: %s\n", hello_world_static); + // printf("Here's deadbeef: %08x\n", deadbeef); + + for (;;); + return 0; } IRQ(systick) @@ -107,10 +155,95 @@ IRQ(systick) collatz(5); } +#define putch(c) uart1_FILE_put(c, NULL) +void print_binary(uint32_t x) +{ + int i = 0; + while (i < 32) { + int msb = (x & 0x80000000) >> 31; + x <<= 1; + if (msb) { + uart1_FILE_put('1', NULL); + } else { + uart1_FILE_put('0', NULL); + } + i++; + } +} + +void print_hex(uint32_t x) +{ + int i = 0; + while (i < 8) { + int ms = (x & 0xf0000000) >> 28; + x <<= 4; + if (ms < 10) { + putch('0' + ms); + } else { + putch('a' + (ms - 10)); + } + ++i; + } +} + +void stack_dump(uint32_t* sp) +{ + fputs("\n\nstack_dump:\n\n", &_uart1_FILE); + while ((uint32_t) sp < 0x20008000) { + fputs(" 0x", &_uart1_FILE); + print_hex((uint32_t)sp); + fputs(" -> 0x", &_uart1_FILE); + print_hex(*sp); + fputs("\n", &_uart1_FILE); + sp += 1; + } +} + IRQ(exc) { + uint32_t mcause, mepc, mtval, *sp; + asm volatile("csrr %0, mcause" : "=r"(mcause)); + asm volatile("csrr %0, mepc" : "=r"(mepc)); + asm volatile("csrr %0, mtval" : "=r"(mtval)); + + fputs("NMI Detected:\n", &_uart1_FILE); + fputs(" mcause: 0b", &_uart1_FILE); + print_binary(mcause); + fputs("\n mepc: 0b", &_uart1_FILE); + print_binary(mepc); + fputs("\n 0x", &_uart1_FILE); + print_hex(mepc); + fputs("\n mtval: 0b", &_uart1_FILE); + print_binary(mtval); + fputs("\n deadbeef: 0b", &_uart1_FILE); + print_binary(0xdeadbeef); + fputs("\n", &_uart1_FILE); + + stack_dump(__builtin_return_address(0)); + + while (1) { + GPIO_PORT.out.set(GPIO_PORT_A, ON, 8); + delay(); + delay(); + delay(); + delay(); + delay(); + delay(); + delay(); + delay(); + GPIO_PORT.out.set(GPIO_PORT_A, OFF, 8); + delay(); + delay(); + delay(); + } } IRQ(nmi) { + while (1) { + GPIO_PORT.out.set(GPIO_PORT_A, ON, 8); + delay(); + GPIO_PORT.out.set(GPIO_PORT_A, OFF, 8); + delay(); + } } |