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
)
67 while (SER_OUTBUSY()) {
76 unsigned char serial_in(void)
78 unsigned char tag
, ch
;
82 while (serial_buffer_wp
== serial_buffer_rp
);
84 ch
= serial_buffer
[serial_buffer_rp
++];
85 serial_buffer_rp
&= BUF_SIZE
-1;
92 #define store4(addr, v) (*(volatile unsigned *)(addr) = (v))
93 #define load4(addr) (*(volatile unsigned *)(addr))
97 void init_serial(void) { }
98 void serial_out(unsigned ch
) { putchar(ch
); }
99 unsigned char serial_in(void) {
105 unsigned memory
[1024*1024/4];
106 #define store4(addr, v) (memory[(unsigned) (addr) / 4 & (1 << 18) - 1] = (v))
107 #define load4(addr) (memory[(unsigned) (addr) / 4 & (1 << 18) - 1])
111 unsigned char serial_in_lowercase(void)
113 unsigned char ch
= serial_in();
118 if ('A' <= ch
&& ch
<= 'Z')
124 unsigned char c
, chk
;
127 void print_hex2(unsigned char);
129 static int puts(const char *s
)
137 static inline void print_hex1(unsigned d
)
139 serial_out(d
+ (d
< 10 ? '0' : 'A' - 10));
142 void print_hex2(unsigned char v
)
144 print_hex1((v
>> 4) & 15);
148 void print_hex8(unsigned v
)
152 for (i
= 8; i
; --i
) {
153 print_hex1((v
>> 28) & 0xF);
158 void print_dec(unsigned v
)
162 serial_out((v
% 10) + '0');
165 unsigned get_hexnum(void)
170 if ('0' <= c
&& c
<= '9')
171 arg
= (arg
<< 4) + c
- '0';
172 else if ('a' <= c
&& c
<= 'f')
173 arg
= (arg
<< 4) + c
- ('a' - 10);
177 c
= serial_in_lowercase();
183 unsigned d85(unsigned v
)
193 if (c
< '(' || '|' < c
)
196 unsigned nv
= v
*85 + c
- '(';
198 // Check for overflow
209 unsigned get_base85_word(void)
211 return d85(d85(d85(d85(d85(0)))));
214 #if defined(HOSTTEST)
215 void tinymon_encode_word_base85(unsigned w
)
217 unsigned e
= w
% 85; w
/= 85;
218 unsigned d
= w
% 85; w
/= 85;
219 unsigned c
= w
% 85; w
/= 85;
220 unsigned b
= w
% 85; w
/= 85;
221 unsigned a
= w
% 85; w
/= 85;
232 puts("Here we will tell about commands and "
233 "statistics (like available memory and frequency\n");
243 /* This is run out of the I$, which in practice means a ROM
244 * that cannot even be read. We must manually initialize all
245 * data and we can't use strings!
252 * Very simple protocol
254 * <cmd> <hex8> ' ' <hex2> '\n'
256 * The <hex2> byte is the checksum of <cmd> + each byte of
257 * <hex8>. If a mismatch is detected all input is ignored
258 * until a clear command is seen.
261 * C - clear the error state (arg ignored)
262 * L - set the load address
263 * W - write a word to the current load address and move it forwards
264 * R - read a word from the current load address and move it forwards
265 * E - execute starting at the given address
266 * X - receive a block of binary data in base85 encoding
272 unsigned char cmd
, chk_ext
;
273 unsigned char error_code
= ' ';
276 puts("Tinymon 2010-11-10 (Use 'h' for help)\n");
279 c
= serial_in_lowercase();
280 while (c
== '\r' || c
== ' ');
283 /* Skip cruft until a command is encountered. */
284 while (c
!= 'c' && c
!= 'l' && c
!= 'w' && c
!= 'r' && c
!= 'e' &&
285 c
!= 't' && c
!= 'x' && c
!= 'h')
286 c
= serial_in_lowercase();
291 c
= serial_in_lowercase();
297 c
= serial_in_lowercase();
300 unsigned char good_chk
= chk
;
301 // Non-interactive use
303 chk_ext
= get_hexnum();
305 if (good_chk
!= chk_ext
) {
307 print_hex2(good_chk
);
318 c
= serial_in_lowercase();
326 if (in_error
&& cmd
!= 'c' && cmd
!= 't')
334 addr
= (unsigned *) arg
;
336 else if (cmd
== 'w') {
338 if (load4(addr
) != arg
) {
345 else if (cmd
== 'r') {
346 print_hex8(load4(addr
++));
349 else if (cmd
== 'e') {
350 puts("\nExecute!\n");
351 #if defined(HOSTTEST)
352 printf("Execute from %08x\n", arg
);
357 } else if (cmd
== 'x') {
358 unsigned *end
= addr
+ arg
;
363 for (k
= 1; addr
!= end
; addr
+= 1, ++k
) {
364 unsigned w
= get_base85_word();
372 if (((unsigned) addr
& (1 << 10) - 1) == 0)
373 serial_out('\r'), print_dec(100 * k
/ arg
), serial_out('%');
380 k
= get_base85_word();
382 #if defined(HOSTTEST)
384 tinymon_encode_word_base85(k
);
386 tinymon_encode_word_base85(-chk
);
388 while (~0 != (k
= getchar()))
395 } else if (cmd
== 't') {
400 /* Simple memory tester */
401 for (addr
= (unsigned *) 0x40000000;
402 addr
!= (unsigned *) 0x400E0000;
405 store4(addr
, ((unsigned) addr
>> 13) ^~ (unsigned) addr
);
406 store4(addr
+ 1, ~ (unsigned) addr
);
407 store4(addr
+ 2, 42 + (unsigned) addr
);
408 store4(addr
+ 3, - (unsigned) addr
);
411 for (addr
= (unsigned *) 0x40000000;
412 addr
!= (unsigned *) 0x400E0000;
416 a
= ((unsigned) addr
>> 13) ^~ (unsigned) addr
;
417 b
= ~ (unsigned) addr
;
418 c
= 42 + (unsigned) addr
;
419 d
= - (unsigned) addr
;
421 if (a
!= load4(addr
) ||
422 b
!= load4(addr
+ 1) ||
423 c
!= load4(addr
+ 2) ||
424 d
!= load4(addr
+ 3)) {
429 print_hex8((unsigned) addr
);
444 serial_out(error_code
);
448 c
= serial_in_lowercase();