2 This is a tiny program loader that takes it's input through the
6 typedef void (*func_t
)(void);
10 asm(" .globl _start ");
12 asm("_start: la $28,_gp ");
13 asm(" la $29,_gp+8192 ");/* + 8KiB */
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());
50 while (SER_OUTBUSY());
52 while (SER_OUTBUSY());
58 void serial_out(unsigned ch
)
72 unsigned char serial_in(void)
74 unsigned char tag
, ch
;
78 while (serial_buffer_wp
== serial_buffer_rp
);
80 ch
= serial_buffer
[serial_buffer_rp
++];
81 serial_buffer_rp
&= BUF_SIZE
-1;
88 #define store4(addr, v) (*(volatile unsigned *)(addr) = (v))
89 #define load4(addr) (*(volatile unsigned *)(addr))
93 void init_serial(void) { }
94 void serial_out(unsigned ch
) { putchar(ch
); }
95 unsigned char serial_in(void) {
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])
107 unsigned char serial_in_lowercase(void)
109 unsigned char ch
= serial_in();
114 if ('A' <= ch
&& ch
<= 'Z')
120 unsigned char c
, chk
;
123 void print_hex2(unsigned char);
125 static void out4(unsigned ch4
)
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);
143 void print_hex8(unsigned v
)
147 for (i
= 8; i
; --i
) {
148 print_hex1((v
>> 28) & 0xF);
153 void print_dec(unsigned v
)
157 serial_out((v
% 10) + '0');
160 unsigned get_hexnum(void)
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);
172 c
= serial_in_lowercase();
178 unsigned d85(unsigned v
)
188 if (c
< '(' || '|' < c
)
191 unsigned nv
= v
*85 + c
- '(';
193 // Check for overflow
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;
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!
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.
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
263 unsigned char cmd
, chk_ext
;
264 unsigned char error_code
= ' ';
274 c
= serial_in_lowercase();
275 while (c
== '\r' || c
== ' ');
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();
286 c
= serial_in_lowercase();
292 c
= serial_in_lowercase();
295 unsigned char good_chk
= chk
;
296 // Non-interactive use
298 chk_ext
= get_hexnum();
300 if (good_chk
!= chk_ext
) {
302 print_hex2(good_chk
);
313 c
= serial_in_lowercase();
321 if (in_error
&& cmd
!= 'c' && cmd
!= 't')
327 addr
= (unsigned *) arg
;
329 else if (cmd
== 'w') {
331 if (load4(addr
) != arg
) {
338 else if (cmd
== 'r') {
339 print_hex8(load4(addr
++));
342 else if (cmd
== 'e') {
344 #if defined(HOSTTEST)
345 printf("Execute from %08x\n", arg
);
350 } else if (cmd
== 'x') {
351 unsigned *end
= addr
+ arg
;
356 for (k
= 1; addr
!= end
; addr
+= 1, ++k
) {
357 unsigned w
= get_base85_word();
365 if (((unsigned) addr
& (1 << 12) - 1) == 0)
366 serial_out('\r'), print_dec(100 * k
/ arg
), serial_out('%');
373 k
= get_base85_word();
375 #if defined(HOSTTEST)
377 tinymon_encode_word_base85(k
);
379 tinymon_encode_word_base85(-chk
);
381 while (~0 != (k
= getchar()))
388 } else if (cmd
== 't') {
393 /* Simple memory tester */
394 for (addr
= (unsigned *) 0x40000000;
395 addr
!= (unsigned *) 0x400E0000;
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;
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)) {
422 print_hex8((unsigned) addr
);
437 serial_out(error_code
);
441 c
= serial_in_lowercase();