trashernet-soc/sw/bootrom/main.c

74 lines
1.5 KiB
C

#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;
uint32_t sr;
/*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 = (uint8_t)UART0_DR;
sr = (sr << 8) | c;
state++;
switch (state) {
case 1: // Opcode
opcode = c;
if (c == 0) // NOP
state = 0;
break;
case 5: // Address
ptr = (uint8_t*)sr;
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 9: // Data
length = sr;
if (opcode == 2) { // Read
for (; length > 0; length--) {
while (UART0_SR & UART0_SR_TX_FULL);
UART0_DR = *(ptr++);
}
} else { // Write
for (; length > 0; length--) {
while (UART0_SR & UART0_SR_RX_DATA_EMPTY);
*(ptr++) = UART0_DR;
}
}
state = 0;
break;
default:
break;
}
}
__builtin_unreachable();
}