s3e: fix build break
[calu.git] / 2_isa / src / bootrom.c
1 /* bootROM, a very small bootloader for $NAME
2  *
3  * protocol details:
4  * abbrv: H = Host, CPU = C
5  *
6  * value/cmd              | direction | comment
7  * ------------------------------------------------------------
8  * 'H'                    | H -> C    | enter bootROM ("HI")
9  * 'O'                    | C -> H    | ack bootROM entry ("OH HAI")
10  *
11  * 'W'0xZZZZZZZZ0xYYYYYYYY| H -> C    | write instr (0xYY...Y) to
12  *                                    | address (0xZZ...Z)
13  * 'D'                    | C -> H    | instr write done
14  *
15  * 'R'0xZZZZZZZZ          | H -> C    | read instr from address (0xZZ..Z)
16  * 'F'0xYYYYYYYY          | C -> H    | instr read done and return instr
17  *
18  * 'Q'0xZZZZZZZZ0xYYYYYYYY| H -> C    | write data (0xYY...Y) to
19  *                                    | address (0xZZ...Z)
20  * 'A'                    | C -> H    | data write done
21  *
22  * 'T'0xZZZZZZZZ          | H -> C    | read data from address (0xZZ..Z)
23  * 'G'0xYYYYYYYY          | C -> H    | read done and return data
24  *
25  * 'J'0xZZZZZZZZ          | H -> C    | jump to address (0xZZ...Z)
26  */
27
28 #define UART_BASE 0x1000
29 #define UART_STATUS (UART_BASE+0x4)
30 #define UART_RECV (UART_BASE+0x8)
31 #define UART_TRANS (UART_BASE+0xC)
32 #define UART_BAUD (UART_BAUD+0x10)
33
34 #define UART_TRANS_EMPTY 0
35 #define UART_RECV_NEW 1
36
37 /* TODO:
38  * - uart: clear new_receive bit after the byte is copied?
39  *   (implementation issue...)
40  */
41
42 /* {d,i}{read,write}{8,32}:
43  * d ... data space
44  * i ... instruction space
45  */
46
47 typedef unsigned char u8;
48 typedef unsigned int u32;
49
50 void send_byte(u8 x)
51 {
52         while(!(dread32(UART_STATUS) & (1 << UART_TRANS_EMPTY)));
53         dwrite8(UART_TRANS, x);
54 }
55
56 void send_word(u32 x)
57 {
58         send_byte((x >> 0) & 0xff);
59         send_byte((x >> 8) & 0xff);
60         send_byte((x >> 16) & 0xff);
61         send_byte((x >> 24) & 0xff);
62 }
63
64 u8 recv_byte(void)
65 {
66         u8 ret;
67         while(!(dread32(UART_STATUS) & (1 << UART_RECV_NEW)));
68         ret = dread8(UART_RECV);
69 }
70
71 u32 recv_word(void)
72 {
73         u32 ret = 0;
74         ret |= recv_byte() << 0;
75         ret |= recv_byte() << 8;
76         ret |= recv_byte() << 16;
77         ret |= recv_byte() << 24;
78 }
79
80 void bootrom(void)
81 {
82         u8 cmd;
83         u32 addr, instr;
84         for(;;) {
85                 cmd = recv_byte();
86                 switch(cmd) {
87                         case 'W':
88                                 addr = recv_word();
89                                 instr = recv_word();
90                                 /* write to programm space */
91                                 iwrite32(addr, instr);
92                                 send_byte('D');
93                                 break;
94                         case 'R':
95                                 addr = recv_word();
96                                 instr = iread32(addr);
97                                 send_byte('F');
98                                 send_word(instr);
99                                 break;
100                         case 'Q':
101                                 addr = recv_word();
102                                 instr = recv_word();
103                                 /* write to data space */
104                                 dwrite32(addr, instr);
105                                 send_byte('A');
106                                 break;
107                         case 'T':
108                                 addr = recv_word();
109                                 instr = dread32(addr);
110                                 send_byte('G');
111                                 send_word(instr);
112                                 break;
113                         case 'J':
114                                 addr = recv_word();
115                                 jump_to_instr_mem(addr);
116                                 /* this should never return ;) */
117                                 break;
118                         case 'H':
119                         default:
120                                 /* OH HAI */
121                                 send_byte('O');
122                                 break;
123                 }
124         }
125 }
126
127 #define TIMEOUT_START 0x13371337
128 #define DEFAULT_PROG_START 0x200
129
130 void main(void)
131 {
132         /* wait for timeout */
133         u32 to = TIMEOUT_START;
134         u8 rec;
135
136         /* until to is zeros */
137         while(to != 0) {
138                 to--;
139                 if(dread32(UART_STATUS) & (1 << UART_RECV_NEW)) {
140                         rec = read8(UART_RECV);
141                         if(rec == 'H') {
142                                 send_byte('O');
143                                 bootrom();
144                         }
145                 }
146         }
147
148         /* after timeout jump to instr. mem plz */
149         jump_to_instr_mem(DEFAULT_PROG_START);
150 }