With the naked attribute, this no longer causes gcc to push stuff onto the stack.
77 lines
1.5 KiB
C
77 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)
|
|
|
|
//#define ENABLE_STACK
|
|
|
|
#ifdef ENABLE_STACK
|
|
// Set up stack pointer
|
|
asm("_start:\
|
|
xor sp, sp, sp;\
|
|
lui sp, 0x40100;\
|
|
j main;\
|
|
");
|
|
#else
|
|
#define main() _start()
|
|
#endif /* ifdef ENABLE_STACK */
|
|
|
|
__attribute__((noreturn, naked)) void main() {
|
|
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)();
|
|
__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();
|
|
}
|