diff --git a/firmware/hello_world_c/.gitignore b/firmware/hello_world_c/.gitignore new file mode 100644 index 0000000..c3755eb --- /dev/null +++ b/firmware/hello_world_c/.gitignore @@ -0,0 +1,2 @@ +*.elf +*.bin \ No newline at end of file diff --git a/firmware/hello_world_c/Makefile b/firmware/hello_world_c/Makefile new file mode 100644 index 0000000..d1edfbe --- /dev/null +++ b/firmware/hello_world_c/Makefile @@ -0,0 +1,17 @@ +PREFIX := riscv64-unknown-elf- +CC := $(PREFIX)gcc +OBJCOPY := $(PREFIX)objcopy + +ARGS := -mabi=ilp32 -march=rv32im -ffreestanding -nostdlib -Wl,-Bstatic,-T,memory.ld,--strip-debug + +SOURCES := main.c +INCLUDES := uart.h + +hello_world.bin: hello_world.elf + $(OBJCOPY) -S -O binary hello_world.elf hello_world.bin + +hello_world.elf: $(SOURCES) $(INCLUDES) + $(CC) $(ARGS) $(SOURCES) -o hello_world.elf + +clean: + rm -f hello_world.elf hello_world.bin diff --git a/firmware/hello_world_c/main.c b/firmware/hello_world_c/main.c new file mode 100644 index 0000000..c295dc4 --- /dev/null +++ b/firmware/hello_world_c/main.c @@ -0,0 +1,54 @@ +#include "uart.h" + +#include + +void write_cstring(const char* string); +void write_char(char c); + + +int main() { + for (;;) { + write_char('H'); + write_char('e'); + write_char('l'); + write_char('l'); + write_char('o'); + write_char(' '); + write_char('W'); + write_char('o'); + write_char('r'); + write_char('l'); + write_char('d'); + write_char('!'); + write_char('\n'); + write_char('\r'); + } +} + + +void write_char(char c) { + while (!UART0->TXEMPTY); + + // Wait for room to clear up + if (!UART0->TXFULL) { + UART0->RXTX = c; + } +} +void write_cstring(const char* string) { + int i = 0; + + for (;;) { + // Return at end of string + if (string[i] == 0) { + return; + } + + // Wait for room to clear up + if (!UART0->TXFULL) { + UART0->RXTX = string[i]; + } + + i += 1; + } + +} diff --git a/firmware/hello_world_c/memory.ld b/firmware/hello_world_c/memory.ld new file mode 100644 index 0000000..6b6b310 --- /dev/null +++ b/firmware/hello_world_c/memory.ld @@ -0,0 +1,64 @@ +/* stolen from https://github.com/Obijuan/RISC-V-FPGA/blob/master/firmware/soc-demo/src-c/sections.lds */ + +MEMORY +{ + ROM (rx) : ORIGIN = 0x01000000, LENGTH = 0x1000 /* 4KiB */ + RAM (xrw) : ORIGIN = 0x01001000, LENGTH = 0x1000 /* 4KiB */ +} + +SECTIONS { + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + *(.srodata) /* .rodata sections (constants, strings, etc.) */ + *(.srodata*) /* .rodata* sections (constants, strings, etc.) */ + _etext = .; /* define a global symbol at end of code */ + _sidata = _etext; /* This is used by the startup in order to initialize the .data secion */ + } >ROM + + + /* This is the initialized data section + The program executes knowing that the data is in the RAM + but the loader puts the initial values in the FLASH (inidata). + It is one task of the startup to copy the initial values from FLASH to RAM. */ + .data : AT ( _sidata ) + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start; used by startup code in order to initialise the .data section in RAM */ + _ram_start = .; /* create a global symbol at ram start for garbage collector */ + . = ALIGN(4); + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + *(.sdata) /* .sdata sections */ + *(.sdata*) /* .sdata* sections */ + . = ALIGN(4); + _edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */ + } >RAM + + /* Uninitialized data section */ + .bss : + { + . = ALIGN(4); + _sbss = .; /* define a global symbol at bss start; used by startup code */ + *(.bss) + *(.bss*) + *(.sbss) + *(.sbss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end; used by startup code */ + } >RAM + + /* this is to define the start of the heap, and make sure we have a minimum size */ + .heap : + { + . = ALIGN(4); + _heap_start = .; /* define a global symbol at heap start */ + } >RAM +} \ No newline at end of file diff --git a/firmware/hello_world_c/uart.h b/firmware/hello_world_c/uart.h new file mode 100644 index 0000000..af2ce26 --- /dev/null +++ b/firmware/hello_world_c/uart.h @@ -0,0 +1,21 @@ +#ifndef UART_H_ +#define UART_H_ + +#include + +typedef +__attribute__((packed)) +struct { + uint32_t RXTX; + uint32_t TXFULL; + uint32_t RXEMPTY; + uint32_t EV_STATUS; + uint32_t EV_PENDING; + uint32_t EV_ENABLE; + uint32_t TXEMPTY; + uint32_t RXFULL; +} LiteUART; + +#define UART0 ((LiteUART*)0xF0003000) + +#endif \ No newline at end of file