--- /dev/null
+OBJS := main.o entry.o
+
+TRIPLE := riscv64-unknown-elf
+
+CC := $(TRIPLE)-gcc
+AS := $(TRIPLE)-as
+OBJCOPY := $(TRIPLE)-objcopy
+PYTHON := python
+
+CFLAGS := -march=rv32i -mabi=ilp32 -nostdlib -Os -I../../libgram/include
+LDFLAGS := -march=rv32i -mabi=ilp32 -nostdlib -Tlink.ld -L../../libgram -lgram
+
+%.o: %.c
+ $(CC) $(CFLAGS) -c $< -o $@
+
+%.o: %.S
+ $(CC) $(CFLAGS) -c $< -o $@
+
+main.bin: $(OBJS) link.ld ../../libgram/libgram.a
+ $(CC) $(LDFLAGS) $(OBJS) ../../libgram/libgram.a -o main.elf
+ $(OBJCOPY) -O binary main.elf main.bin
+
+main.img.bin: main.bin
+ $(PYTHON) -m lambdasoc.software.bios.util.mkmscimg --little $< -o $@
+
+all: main.img.bin
--- /dev/null
+OUTPUT_FORMAT("elf32-littleriscv")
+ENTRY(_start)
+
+MEMORY
+{
+ rom : ORIGIN = 0x00007000, LENGTH = 0x1000
+ ram : ORIGIN = 0x00004000, LENGTH = 0x1000
+}
+
+SECTIONS
+{
+ .text :
+ {
+ _ftext = .;
+ *entry*.o(.text)
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ _etext = .;
+ } > rom
+
+ .rodata :
+ {
+ . = ALIGN(8);
+ _frodata = .;
+ *(.rodata .rodata.* .gnu.linkonce.r.*)
+ *(.rodata1)
+
+ /* Make sure the file is aligned on disk as well
+ as in memory; CRC calculation requires that. */
+ FILL(0);
+ . = ALIGN(8);
+ _erodata = .;
+ } > rom
+
+ .bss :
+ {
+ . = ALIGN(8);
+ _fbss = .;
+ *(.dynsbss)
+ *(.sbss .sbss.* .gnu.linkonce.sb.*)
+ *(.scommon)
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ . = ALIGN(8);
+ _ebss = .;
+ _end = .;
+ } > ram
+
+ /DISCARD/ :
+ {
+ *(.eh_frame)
+ *(.comment)
+ *(.data .data.* .gnu.linkonce.d.*)
+ *(.data1)
+ *(.sdata .sdata.* .gnu.linkonce.s.*)
+ }
+}
+
+PROVIDE(_fstack = ORIGIN(ram) + LENGTH(ram) - 8);
--- /dev/null
+#include <stdlib.h>
+#include <stdint.h>
+#include <gram.h>
+
+static inline uint32_t read32(const void *addr)
+{
+ return *(volatile uint32_t *)addr;
+}
+
+static inline void write32(void *addr, uint32_t value)
+{
+ *(volatile uint32_t *)addr = value;
+}
+
+struct uart_regs {
+ uint32_t divisor;
+ uint32_t rx_data;
+ uint32_t rx_rdy;
+ uint32_t rx_err;
+ uint32_t tx_data;
+ uint32_t tx_rdy;
+ uint32_t zero0; // reserved
+ uint32_t zero1; // reserved
+ uint32_t ev_status;
+ uint32_t ev_pending;
+ uint32_t ev_enable;
+};
+
+void uart_write(char c)
+{
+ struct uart_regs *regs = 0x5000;
+ while (!read32(®s->tx_rdy));
+ write32(®s->tx_data, c);
+}
+
+void uart_writestr(const char *c) {
+ while (*c) {
+ uart_write(*c);
+ c++;
+ }
+}
+
+void isr(void) {
+
+}
+
+int main(void) {
+ uart_writestr("Firmware launched...\n");
+
+ uart_writestr("DRAM init... ");
+ struct gramCtx ctx;
+ gram_init(&ctx, (void*)0x10000000, (void*)0x00009000, (void*)0x00008000);
+ uart_writestr("done\n");
+
+ uart_writestr("DRAM test... ");
+ volatile uint32_t *ram = 0x10000000;
+ for (size_t i = 0; i < 1000; i++) {
+ ram[i] = 0xdeadbeef << (i%32);
+ }
+
+ for (size_t i = 0; i < 1000; i++) {
+ if (ram[i] != 0xdeadbeef << (i%32)) {
+ uart_writestr("fail\n");
+ }
+ }
+ uart_writestr("done\n");
+
+ return 0;
+}
\ No newline at end of file