* '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_RECV_NEW 1
/* TODO:
- * - use different read/write functions for instr and data space
- * - need absolute jump for program entry?
+ * - need jump to register value
+ * - 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(!(UART_STATUS & (1 << UART_TRANS_EMPTY)));
- write8(UART_TRANS, x);
+ while(!(dread32(UART_STATUS) & (1 << UART_TRANS_EMPTY)));
+ dwrite8(UART_TRANS, x);
}
void send_word(u32 x)
u8 recv_byte(void)
{
u8 ret;
- while(!(UART_STATUS & (1 << UART_RECV_NEW)));
- ret = read8(UART_RECV);
+ while(!(dread32(UART_STATUS) & (1 << UART_RECV_NEW)));
+ ret = dread8(UART_RECV);
}
u32 recv_word(void)
addr = recv_word();
instr = recv_word();
/* write to programm space */
- write32(addr, instr);
+ iwrite32(addr, instr);
send_byte('D');
break;
case 'R':
addr = recv_word();
- instr = read32(addr);
+ 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);
u32 to = TIMEOUT_START;
u8 rec;
- /* until to overflows */
+ /* until to is zeros */
while(to != 0) {
- /* noob timeout hack */
- to++;
- if(UART_STATUS & (1 << UART_RECV_NEW)) {
+ to--;
+ if(dread32(UART_STATUS) & (1 << UART_RECV_NEW)) {
rec = read8(UART_RECV);
if(rec == 'H') {
send_byte('O');
--- /dev/null
+ .data
+
+ .text
+ ; r0 .. param0
+ ; r1 .. param1
+ ; r2 .. param2
+ ; r15 .. stackpointer
+ ; r0 .. return
+
+ ; TODO: will the assembler be able to evaluate these expressions?
+ UART_BASE=0x1000
+ UART_STATUS=(UART_BASE+0x4)
+ UART_RECV=(UART_BASE+0x8)
+ UART_TRANS=(UART_BASE+0xC)
+ UART_BAUD=(UART_BAUD+0x10)
+
+ UART_TRANS_EMPTY=0
+ UART_RECV_NEW=1
+
+send_byte:
+ ldil r3, UART_STATUS@lo
+ ldih r3, UART_STATUS@hi
+ andi r3, r3, 1 << UART_TRANS_EMPTY
+ jumpzs+ send_byte ; jump if zero
+ ldil r3, UART_TRANS@lo
+ ldih r3, UART_TRANS@hi
+ stb r0, 0(r3)
+ ret
+
+send_word:
+ ; TODO: loop? (less codesize...)
+ branch send_byte
+ lrs r0, r0, 8
+ branch send_byte
+ lrs r0, r0, 8
+ branch send_byte
+ lrs r0, r0, 8
+ branch send_byte
+ ret
+
+recv_byte:
+ ldil r3, UART_STATUS@lo
+ ldih r3, UART_STATUS@hi
+ andi r3, r3, 1 << UART_RECV_NEW
+ jumpzs+ send_byte ; jump if zero
+ ldil r3, UART_RECV@lo
+ ldih r3, UART_RECV@hi
+ lwb r0, 0(r3)
+ ret
+
+recv_word:
+ ldil r1, 0x0
+ branch recv_byte
+ or r1, r1, r0
+
+ branch recv_byte
+ sll r0, r0, 8
+ or r1, r1, r0
+
+ branch recv_byte
+ sll r0, r0, 16
+ or r1, r1, r0
+
+ branch recv_byte
+ sll r0, r0, 24
+ or r1, r1, r0
+
+ addi r0, r1, 0x0
+ ret
+
+
+bootrom:
+ branch recv_byte
+
+ cmpi r0, 0x57 ; 'W'
+ jumpeq- bt_W
+
+ cmpi r0, 0x52 ; 'R'
+ jumpeq- bt_R
+
+ cmpi r0, 0x51 ; 'Q'
+ jumpeq- bt_Q
+
+ cmpi r0, 0x54 ; 'T'
+ jumpeq- bt_T
+
+ cmpi r0, 0x4a ; 'J'
+ jumpeq- bt_J
+
+ ; cmpi r0, 0x48 ; 'H'
+ ; jumpeq bt_H
+ ; FALL THROUGH ;)
+
+bt_H:
+ ldisl r0, 0x4f ; 'O'
+ branch send_byte
+ jump bootrom
+
+bt_W:
+ branch recv_word ; receive addr
+ addi r6, r0, 0x0
+ branch recv_word ; receive instr
+ stx r0, 0(r6)
+ ldisl r0, 0x44 ; 'D'
+ branch send_byte
+ jump bootrom
+
+bt_R:
+ branch recv_word ; receive addr
+ ldx r1, 0(r0)
+ ldisl r0, 0x46 ; 'F'
+ branch send_byte
+ addi r0, r1, 0x0
+ branch send_word
+ jump bootrom
+
+bt_Q:
+ branch recv_word ; receive addr
+ addi r6, r0, 0x0
+ branch recv_word ; receive data
+ stw r0, 0(r6)
+ ldisl r0, 0x41 ; 'A'
+ branch send_byte
+ jump bootrom
+
+bt_T:
+ branch recv_word ; receive addr
+ ldw r1, 0(r0)
+ ldisl r0, 0x47 ; 'G'
+ branch send_byte
+ addi r0, r1, 0x0
+ branch send_word
+ jump bootrom
+
+bt_J:
+ branch recv_word
+ jumpreg r0
+
+
+ TIMEOUT_START=0x13371337
+ DEFAULT_PROG_START=0x200
+ STACKSTART=0x500 ; FIXME
+main:
+ ; setup stackframe
+ ldil r15, STACKSTART@lo
+ ldih r15, STACKSTART@hi
+
+ ldil r3, TIMEOUT_START@lo
+ ldih r3, TIMEOUT_START@hi
+
+timeout_loop:
+ ldil r3, UART_STATUS@lo
+ ldih r3, UART_STATUS@hi
+ andi r3, r3, 1 << UART_RECV_NEW
+ jumpzs+ next; jump if zero
+
+ branch recv_byte
+ ; we received the enter bootrom sign
+ cmp r0, 0x48 ; 'H'
+ jumpeq- bt_H
+
+next:
+ subi r3, r3, 1
+ jumpnz+ timeout_loop
+
+ ; branch to default entry point
+ ldil r0, DEFAULT_PROG_START@lo
+ ldih r0, DEFAULT_PROG_START@hi
+ jumpreg r0
+
+; 99 instr. please update after modification