sw: Add bootrom

This commit is contained in:
Markus Koch 2024-07-06 19:15:41 +02:00
parent 434a06fa70
commit 4057f5239e
4 changed files with 144 additions and 0 deletions

4
sw/bootrom/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
*.bin
*.elf
*.hex
*.vhex

45
sw/bootrom/boot.ld Normal file
View File

@ -0,0 +1,45 @@
__heap_size = 0x80;
__stack_size = 0x80;
MEMORY
{
ROM (rwx) : ORIGIN = 0x00000000, LENGTH = 0x100
RAM (rwx) : ORIGIN = 0x40000000, LENGTH = 0x400
}
SECTIONS
{
.text :
{
*(.boot)
*(.text)
*(.text)
*(.rodata*)
} > ROM
.data :
{
*(.sbss)
*(.data)
*(.bss)
*(.rela*)
*(COMMON)
} > RAM
.heap :
{
. = ALIGN(4);
PROVIDE ( end = . );
_sheap = .;
. = . + __heap_size;
. = ALIGN(4);
_eheap = .;
} >RAM
.stack :
{
. = ALIGN(4);
_estack = .;
. = . + __stack_size;
. = ALIGN(4);
_sstack = .;
} >RAM
}

8
sw/bootrom/build.sh Executable file
View File

@ -0,0 +1,8 @@
#!/bin/bash
set -e
riscv64-elf-gcc -mabi=ilp32 -march=rv32i -nostdlib -nostartfiles -ffreestanding -T boot.ld -Os -o bootrom.elf main.c
#riscv64-elf-objdump -D bootrom.elf
riscv64-elf-objcopy -O binary bootrom.elf bootrom.bin
od --endian=little -vtx4 -An -w4 bootrom.bin | tr -d ' ' > bootrom.vhex
r2 -A -c 'pdf @ sym._start' -q bootrom.elf

87
sw/bootrom/main.c Normal file
View File

@ -0,0 +1,87 @@
#include <inttypes.h>
#define UART0_BASE 0x81000000
#define UART0_SR (*((volatile uint32_t *) (UART0_BASE + 0x00)))
#define UART0_DR (*((volatile uint32_t *) (UART0_BASE + 0x04)))
#define UART0_SR_RX_DATA_EMPTY (1 << 0)
#define UART0_SR_TX_FULL (1 << 1)
/*
// Set up stack pointer
asm("_start:\
xor sp, sp, sp;\
lui sp, 0x80100;\
j main;\
");
*/
__attribute__((noreturn)) void _start() {
uint8_t state = 0;
uint8_t c;
uint8_t opcode;
uint8_t *ptr;
uint32_t length;
/*while (1) {
while (UART0_SR & UART0_SR_RX_DATA_EMPTY);
c = UART0_DR;
while (UART0_SR & UART0_SR_TX_FULL);
UART0_DR = c;
}*/
while (1) {
while (UART0_SR & UART0_SR_RX_DATA_EMPTY);
c = UART0_DR;
state++;
switch (state) {
case 1: // Opcode
opcode = c;
ptr = 0;
length = 0;
if (c == 0) // NOP
state = 0;
break;
case 2: // Address
case 3:
case 4:
case 5:
ptr = (uint8_t*)(((uint32_t)ptr << 8) | c);
if (state != 5)
break;
if (opcode == 3) { // Jump
//((void (*)()) ptr)();
asm("jalr %0" : : "r"(ptr)); // Not sure why, but the jump above causes GCC to save variables to the stack at the beginning of this function
__builtin_unreachable();
}
break;
case 6: // Length
case 7:
case 8:
case 9:
length = (length << 8) | c;
if (state != 9)
break;
if (opcode == 2) { // Read
for (; length > 0; length--) {
while (UART0_SR & UART0_SR_TX_FULL);
UART0_DR = *(ptr);
ptr++;
}
state = 0;
}
break;
case 10: // Write byte by byte
*(ptr++) = c;
if (--length == 0) {
state = 0;
} else {
state--; // Stay in this state
}
break;
default:
break;
}
}
__builtin_unreachable();
}