aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2024-11-16 13:04:54 -0700
committerJosh Rahm <joshuarahm@gmail.com>2024-11-16 13:04:54 -0700
commitdf8d98fb41a218e41bbf8cdc8a3f89a61cb04f23 (patch)
treea4df370381f4b46e3aa3452d5d15615f17211acc
parentede9bee7f22fd5d0e1bacb7689f1cac23992b70b (diff)
downloadch573-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.txt64
-rw-r--r--linker/ls.ld14
-rw-r--r--src/init.c2
-rw-r--r--src/main.c177
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
diff --git a/src/init.c b/src/init.c
index 5753a13..1d9474a 100644
--- a/src/init.c
+++ b/src/init.c
@@ -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. */
diff --git a/src/main.c b/src/main.c
index 3066123..ae7dab5 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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();
+ }
}