-ins ('32', 'branch', 'Branch; save pc+1 in stack, jump to pc+imm', '4 | 5 | 16 | 5 | 1 | 1', 'Conditions | OpCode | Immediate | - | +/- | S');
+ins ('32', 'branch', 'Branch; save pc+4 in stack, jump to pc+imm', '4 | 5 | 16 | 5 | 1 | 1', 'Conditions | OpCode | Immediate | - | +/- | S');
ins ('32', 'jump', 'Jump; jump to pc+imm', '4 | 5 | 16 | 5 | 1 | 1', 'Conditions | OpCode | Immediate | - | +/- | S');
--- /dev/null
+/* 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
+ *
+ * '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:
+ * - use different read/write functions for instr and data space
+ * - need absolute jump for program entry?
+ */
+
+void send_byte(u8 x)
+{
+ while(!(UART_STATUS & (1 << UART_TRANS_EMPTY)));
+ write8(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(!(UART_STATUS & (1 << UART_RECV_NEW)));
+ ret = read8(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 */
+ write32(addr, instr);
+ send_byte('D');
+ break;
+ case 'R':
+ addr = recv_word();
+ instr = read32(addr);
+ send_byte('F');
+ 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 overflows */
+ while(to != 0) {
+ /* noob timeout hack */
+ to++;
+ if(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);
+}