CORE: suppress some warnings
[yari.git] / shared / firmware / tinymon.c
blob7f72040053c7067633d62204bc3a24774e608ab8
1 /*
2 This is a tiny program loader that takes it's input through the
3 serial port.
4 */
6 typedef void (*func_t)(void);
8 #if !defined(HOSTTEST)
10 asm(" .globl _start ");
11 asm("_init: ");
12 asm("_start: la $28,_gp ");
13 asm(" la $29,_gp+8192 ");/* + 8KiB */
14 asm(" jal main ");
15 asm(" nop ");
16 asm(" break ");
18 extern void set_leds(unsigned v);
19 asm(".globl set_leds;set_leds: mtlo $4;jr $31");
21 #define RS232IN_DATA (*(volatile unsigned *) 0xFF000004)
22 #define RS232IN_TAG (*(volatile unsigned *) 0xFF000008)
23 #define TSC (*(volatile unsigned *) 0xFF00000C)
24 #define SER_OUTBUSY() (*(volatile unsigned *)0xFF000000 != 0)
25 #define SER_OUT(data) (*(volatile unsigned *)0xFF000000 = (data))
27 #define BUF_SIZE 1024 // must be a power of two
29 unsigned last_serial_tag;
30 char serial_buffer[BUF_SIZE];
31 unsigned serial_buffer_wp;
32 unsigned serial_buffer_rp;
34 void init_serial(void)
36 last_serial_tag = RS232IN_TAG;
37 serial_buffer_rp = serial_buffer_wp = 1;
40 void check_serial_input(void)
42 unsigned char tag = RS232IN_TAG;
43 if (tag != last_serial_tag) {
44 serial_buffer[serial_buffer_wp++] = RS232IN_DATA;
45 serial_buffer_wp &= BUF_SIZE-1;
46 last_serial_tag = tag;
47 if (serial_buffer_wp == serial_buffer_rp) {
48 while (SER_OUTBUSY());
49 SER_OUT('<');
50 while (SER_OUTBUSY());
51 SER_OUT('#');
52 while (SER_OUTBUSY());
53 SER_OUT('>');
58 void serial_out(unsigned ch)
60 check_serial_input();
62 if (ch == '\n')
63 serial_out('\r');
65 check_serial_input();
66 while (SER_OUTBUSY())
67 check_serial_input();
68 SER_OUT(ch);
69 set_leds(ch);
72 unsigned char serial_in(void)
74 unsigned char tag, ch;
77 check_serial_input();
78 while (serial_buffer_wp == serial_buffer_rp);
80 ch = serial_buffer[serial_buffer_rp++];
81 serial_buffer_rp &= BUF_SIZE-1;
83 set_leds(ch);
85 return ch;
88 #define store4(addr, v) (*(volatile unsigned *)(addr) = (v))
89 #define load4(addr) (*(volatile unsigned *)(addr))
91 #else
93 void init_serial(void) { }
94 void serial_out(unsigned ch) { putchar(ch); }
95 unsigned char serial_in(void) {
96 int c = getchar();
97 if (c < 0)
98 exit(0);
101 unsigned memory[1024*1024/4];
102 #define store4(addr, v) (memory[(unsigned) (addr) / 4 & (1 << 18) - 1] = (v))
103 #define load4(addr) (memory[(unsigned) (addr) / 4 & (1 << 18) - 1])
105 #endif
107 unsigned char serial_in_lowercase(void)
109 unsigned char ch = serial_in();
111 if (ch == '\r')
112 ch = '\n';
114 if ('A' <= ch && ch <= 'Z')
115 ch = ch - 'A' + 'a';
117 return ch;
120 unsigned char c, chk;
121 unsigned in_error;
123 void print_hex2(unsigned char);
125 static void out4(unsigned ch4)
127 if (ch4 >> 8)
128 out4(ch4 >> 8);
129 serial_out(ch4 & 0xFF);
132 static inline void print_hex1(unsigned d)
134 serial_out(d + (d < 10 ? '0' : 'A' - 10));
137 void print_hex2(unsigned char v)
139 print_hex1((v >> 4) & 15);
140 print_hex1(v & 15);
143 void print_hex8(unsigned v)
145 int i;
147 for (i = 8; i; --i) {
148 print_hex1((v >> 28) & 0xF);
149 v <<= 4;
153 void print_dec(unsigned v)
155 if (v >= 10)
156 print_dec(v / 10);
157 serial_out((v % 10) + '0');
160 unsigned get_hexnum(void)
162 unsigned arg;
164 for (arg = 0;;) {
165 if ('0' <= c && c <= '9')
166 arg = (arg << 4) + c - '0';
167 else if ('a' <= c && c <= 'f')
168 arg = (arg << 4) + c - ('a' - 10);
169 else
170 break;
171 chk += c;
172 c = serial_in_lowercase();
175 return arg;
178 unsigned d85(unsigned v)
180 if (in_error)
181 goto fail;
183 unsigned char c;
185 c = serial_in();
186 while (c <= ' ');
188 if (c < '(' || '|' < c)
189 goto fail;
191 unsigned nv = v*85 + c - '(';
193 // Check for overflow
194 if (nv < v)
195 goto fail;
197 return nv;
199 fail:
200 in_error = 1;
201 return 0;
204 unsigned get_base85_word(void)
206 return d85(d85(d85(d85(d85(0)))));
209 #if defined(HOSTTEST)
210 void tinymon_encode_word_base85(unsigned w)
212 unsigned e = w % 85; w /= 85;
213 unsigned d = w % 85; w /= 85;
214 unsigned c = w % 85; w /= 85;
215 unsigned b = w % 85; w /= 85;
216 unsigned a = w % 85; w /= 85;
217 putchar(a + '(');
218 putchar(b + '(');
219 putchar(c + '(');
220 putchar(d + '(');
221 putchar(e + '(');
223 #endif
225 int main()
227 restart: ;
229 unsigned *addr = 0;
230 in_error = 0;
232 /* This is run out of the I$, which in practice means a ROM
233 * that cannot even be read. We must manually initialize all
234 * data and we can't use strings!
237 init_serial();
239 serial_out('\n');
240 serial_out('\n');
243 * Very simple protocol
245 * <cmd> <hex8> ' ' <hex2> '\n'
247 * The <hex2> byte is the checksum of <cmd> + each byte of
248 * <hex8>. If a mismatch is detected all input is ignored
249 * until a clear command is seen.
251 * Commands
252 * C - clear the error state (arg ignored)
253 * L - set the load address
254 * W - write a word to the current load address and move it forwards
255 * R - read a word from the current load address and move it forwards
256 * E - execute starting at the given address
257 * X - receive a block of binary data in base85 encoding
260 for (;;) {
261 unsigned arg = 0;
262 unsigned i;
263 unsigned char cmd, chk_ext;
264 unsigned char error_code = ' ';
266 do {
267 out4('Tiny');
268 out4('mon ');
269 out4('2010');
270 out4('-09-');
271 out4('03\n');
274 c = serial_in_lowercase();
275 while (c == '\r' || c == ' ');
276 } while (c == '\n');
278 /* Skip cruft until a command is encountered. */
279 while (c != 'c' && c != 'l' && c != 'w' && c != 'r' && c != 'e' &&
280 c != 't' && c != 'x')
281 c = serial_in_lowercase();
283 chk = cmd = c;
286 c = serial_in_lowercase();
287 while (c == ' ');
289 arg = get_hexnum();
291 while (c == ' ')
292 c = serial_in_lowercase();
294 if (c != '\n') {
295 unsigned char good_chk = chk;
296 // Non-interactive use
298 chk_ext = get_hexnum();
300 if (good_chk != chk_ext) {
301 serial_out('<');
302 print_hex2(good_chk);
303 serial_out('!');
304 serial_out('=');
305 print_hex2(chk_ext);
306 serial_out('>');
308 error_code = '1';
309 goto error;
312 while (c == ' ')
313 c = serial_in_lowercase();
315 if (c != '\n') {
316 error_code = '2';
317 goto error;
321 if (in_error && cmd != 'c' && cmd != 't')
322 continue;
324 if (cmd == 'c')
325 in_error = 0;
326 else if (cmd == 'l')
327 addr = (unsigned *) arg;
328 #if 0
329 else if (cmd == 'w') {
330 store4(addr, arg);
331 if (load4(addr) != arg) {
332 serial_out('!');
333 goto error;
335 addr++;
337 #endif
338 else if (cmd == 'r') {
339 print_hex8(load4(addr++));
340 serial_out('\n');
342 else if (cmd == 'e') {
343 out4('\nE!\n');
344 #if defined(HOSTTEST)
345 printf("Execute from %08x\n", arg);
346 #else
347 ((func_t)arg)();
348 #endif
349 goto restart;
350 } else if (cmd == 'x') {
351 unsigned *end = addr + arg;
352 unsigned chk = 0;
353 unsigned k = 0;
355 serial_out('\n');
356 for (k = 1; addr != end; addr += 1, ++k) {
357 unsigned w = get_base85_word();
358 if (in_error) {
359 error_code = '8';
360 goto error;
362 chk += w;
363 store4(addr, w);
365 if (((unsigned) addr & (1 << 12) - 1) == 0)
366 serial_out('\r'), print_dec(100 * k / arg), serial_out('%');
368 serial_out('\r');
369 print_dec(100);
370 serial_out('%');
371 serial_out('\n');
373 k = get_base85_word();
374 if (k != -chk) {
375 #if defined(HOSTTEST)
376 printf("Got:");
377 tinymon_encode_word_base85(k);
378 printf("\nWanted:");
379 tinymon_encode_word_base85(-chk);
380 printf("\nRest: ");
381 while (~0 != (k = getchar()))
382 putchar(k);
383 #endif
384 error_code = '7';
385 goto error;
387 #if 0
388 } else if (cmd == 't') {
389 out4('Mem ');
390 out4('test');
391 serial_out('\n');
393 /* Simple memory tester */
394 for (addr = (unsigned *) 0x40000000;
395 addr != (unsigned *) 0x400E0000;
396 addr += 4) {
398 store4(addr, ((unsigned) addr >> 13) ^~ (unsigned) addr);
399 store4(addr + 1, ~ (unsigned) addr);
400 store4(addr + 2, 42 + (unsigned) addr);
401 store4(addr + 3, - (unsigned) addr);
404 for (addr = (unsigned *) 0x40000000;
405 addr != (unsigned *) 0x400E0000;
406 addr += 4) {
408 unsigned a, b, c, d;
409 a = ((unsigned) addr >> 13) ^~ (unsigned) addr;
410 b = ~ (unsigned) addr;
411 c = 42 + (unsigned) addr;
412 d = - (unsigned) addr;
414 if (a != load4(addr) ||
415 b != load4(addr + 1) ||
416 c != load4(addr + 2) ||
417 d != load4(addr + 3)) {
418 out4('Memo');
419 out4('ry e');
420 out4('rror');
421 out4(' at ');
422 print_hex8((unsigned) addr);
423 serial_out('\n');
424 goto restart;
427 out4('Ok!\n');
428 continue;
429 #endif
432 serial_out('.');
433 continue;
435 error:
436 serial_out('<');
437 serial_out(error_code);
438 serial_out('>');
439 in_error = 1;
440 while (c != '\n')
441 c = serial_in_lowercase();