/* bootROM, a very small bootloader for $NAME * * protocol details: * abbrv: H = Host, CPU = C * * value/cmd | direction | comment * ------------------------------------------------------------ * 'H' | H -> C | enter bootROM ("HI") * 'O' | C -> H | ack bootROM entry ("OH HAI") * * 'W'0xZZZZZZZZ0xYYYYYYYY| H -> C | write instr (0xYY...Y) to * | address (0xZZ...Z) * 'D' | C -> H | instr write done * * 'R'0xZZZZZZZZ | H -> C | read instr from address (0xZZ..Z) * 'F'0xYYYYYYYY | C -> H | instr read done and return instr * * 'Q'0xZZZZZZZZ0xYYYYYYYY| H -> C | write data (0xYY...Y) to * | address (0xZZ...Z) * 'A' | C -> H | data write done * * 'T'0xZZZZZZZZ | H -> C | read data from address (0xZZ..Z) * 'G'0xYYYYYYYY | C -> H | read done and return data * * 'J'0xZZZZZZZZ | H -> C | jump to address (0xZZ...Z) */ #define UART_BASE 0x1000 #define UART_STATUS (UART_BASE+0x4) #define UART_RECV (UART_BASE+0x8) #define UART_TRANS (UART_BASE+0xC) #define UART_BAUD (UART_BAUD+0x10) #define UART_TRANS_EMPTY 0 #define UART_RECV_NEW 1 /* TODO: * - uart: clear new_receive bit after the byte is copied? * (implementation issue...) */ /* {d,i}{read,write}{8,32}: * d ... data space * i ... instruction space */ typedef unsigned char u8; typedef unsigned int u32; void send_byte(u8 x) { while(!(dread32(UART_STATUS) & (1 << UART_TRANS_EMPTY))); dwrite8(UART_TRANS, x); } void send_word(u32 x) { send_byte((x >> 0) & 0xff); send_byte((x >> 8) & 0xff); send_byte((x >> 16) & 0xff); send_byte((x >> 24) & 0xff); } u8 recv_byte(void) { u8 ret; while(!(dread32(UART_STATUS) & (1 << UART_RECV_NEW))); ret = dread8(UART_RECV); } u32 recv_word(void) { u32 ret = 0; ret |= recv_byte() << 0; ret |= recv_byte() << 8; ret |= recv_byte() << 16; ret |= recv_byte() << 24; } void bootrom(void) { u8 cmd; u32 addr, instr; for(;;) { cmd = recv_byte(); switch(cmd) { case 'W': addr = recv_word(); instr = recv_word(); /* write to programm space */ iwrite32(addr, instr); send_byte('D'); break; case 'R': addr = recv_word(); instr = iread32(addr); send_byte('F'); send_word(instr); break; case 'Q': addr = recv_word(); instr = recv_word(); /* write to data space */ dwrite32(addr, instr); send_byte('A'); break; case 'T': addr = recv_word(); instr = dread32(addr); send_byte('G'); send_word(instr); break; case 'J': addr = recv_word(); jump_to_instr_mem(addr); /* this should never return ;) */ break; case 'H': default: /* OH HAI */ send_byte('O'); break; } } } #define TIMEOUT_START 0x13371337 #define DEFAULT_PROG_START 0x200 void main(void) { /* wait for timeout */ u32 to = TIMEOUT_START; u8 rec; /* until to is zeros */ while(to != 0) { to--; if(dread32(UART_STATUS) & (1 << UART_RECV_NEW)) { rec = read8(UART_RECV); if(rec == 'H') { send_byte('O'); bootrom(); } } } /* after timeout jump to instr. mem plz */ jump_to_instr_mem(DEFAULT_PROG_START); }