YARISIM: add a register-use decode map
[yari.git] / yarisim / support.c
blobe6e959c6a78f80e3f982c3bc15e200b592002139
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <assert.h>
6 #include <sys/types.h>
7 #include <netinet/in.h>
8 #include "elf.h"
9 #include <getopt.h>
10 #include "mips32.h"
11 #include "runmips.h"
12 #include <ctype.h>
14 unsigned text_start = ~0;
15 unsigned text_size = 0;
16 unsigned mif_size = 16384;
17 int serial_wait = 0;
18 int rs232in_fd, rs232out_fd;
19 unsigned rs232in_data = 0;
20 unsigned char rs232in_cnt = 0;
21 unsigned rs232in_pending = 0; // last one is simulation only
23 unsigned nsections = 0;
24 unsigned section_start[99];
25 unsigned section_size[99];
26 static int text_segments = 0;
28 extern unsigned TSC;
30 #define H(x) (endian_is_big ? ntohs(x) : x)
31 #define W(x) (endian_is_big ? ntohl(x) : x)
33 void service_rs232(void)
36 * Check the serial port and update rs232in_data and
37 * rs232in_cnt accordingly.
39 if (rs232in_fd >= 0 && !rs232in_pending) {
40 char ch;
41 int count = read(rs232in_fd, &ch, 1);
42 if (count == 1) {
43 rs232in_pending = 3; // Minimum 2
44 rs232in_data = ch;
49 void initialize_memory(void)
51 const unsigned megabyte = 1024 * 1024;
53 // See mymips.ld
54 // ensure_mapped_memory_range(0, megabyte); // XXX Don't !
55 ensure_mapped_memory_range(0x40000000, megabyte);
56 // ensure_mapped_memory_range(0x90000000, megabyte);
57 // ensure_mapped_memory_range(0x80000000-megabyte+1, megabyte-1);
58 ensure_mapped_memory_range(0xBFC00000, megabyte); // Really only 16KiB
60 unsigned p;
61 int k;
63 // Mimick real memory
64 for (p = 0x40000000, k = megabyte; k > 0; p += 4, k -= 4)
65 store(p, 0xe2e1e2e1, 4);
67 for (p = 0x40000000, k = megabyte; k > 0; p += 4, k -= 4)
68 assert(load(p, 4, 0) == 0xe2e1e2e1);
71 void ensure_mapped_memory_range(unsigned addr, unsigned len)
73 unsigned seg;
75 if (enable_disass) {
76 printf("Ensure mapped [%08x; %08x]\n", addr, addr + len - 1);
79 // Split it up
80 while (segment(addr) != segment(addr + len - 1)) {
81 ensure_mapped_memory_range(addr, (1 << OFFSETBITS) - offset(addr));
82 addr += (1 << OFFSETBITS) - offset(addr);
83 assert(len >= (1 << OFFSETBITS) - offset(addr));
84 len -= (1 << OFFSETBITS) - offset(addr);
87 seg = segment(addr);
88 if (!addr_mapped(addr + len - 1)) {
89 memory_segment_size[seg] = 1 + offset(addr + len - 1);
90 memory_segment[seg] =
91 realloc(memory_segment[seg], memory_segment_size[seg]);
93 if (enable_disass) {
94 printf("Segment %2d virt [%08x; %08x] phys [%p; %p]\n",
95 seg,
96 addr, addr + len - 1,
97 memory_segment[seg],
98 memory_segment[seg] + memory_segment_size[seg] - 1);
101 // Make sure it's good
102 *(char*)(memory_segment[seg] + memory_segment_size[seg] - 1) = 0;
105 assert(addr_mapped(addr + len - 1));
108 void exception(char *kind)
110 printf("Exception caught: %s\n", kind);
111 exit(1);
114 void loadsection(FILE *f, unsigned f_offset, unsigned f_len, unsigned m_addr,
115 unsigned m_len)
117 void *phys;
119 // m_len += 0x1000; // XXX Fudge factor? hw writes outside BBS
121 ensure_mapped_memory_range(m_addr, m_len);
123 section_start[nsections] = m_addr;
124 section_size[nsections++] = m_len;
125 assert(nsections < sizeof section_start / sizeof(unsigned));
128 * We clear memory so that BBS doesn't need special
129 * initialization
131 phys = addr2phys(m_addr);
132 memset(phys, 0, m_len);
134 fseek(f, f_offset, SEEK_SET);
135 assert(segment(m_addr) == segment(m_addr + m_len)); // Handle that case later
136 fread(addr2phys(m_addr), f_len, 1, f);
139 void readelf(char *name)
141 static int memory_is_initialized = 0;
143 Elf32_Ehdr ehdr;
144 Elf32_Phdr *ph;
145 int i;
146 unsigned phentsize;
148 FILE *f = fopen(name, "r");
150 if (!f)
151 fatal("Can't open %s\n", name);
153 if (fread(&ehdr, sizeof(ehdr), 1, f) != 1)
154 fatal("Can't read the ELF header of %s", name);
156 if (strncmp((char *) ehdr.e_ident, ELFMAG, SELFMAG))
157 fatal("%s is not an ELF file\n", name);
159 endian_is_big = ehdr.e_ident[EI_DATA] == 2;
162 * We can't initialize memory until we know the endian,
163 * otherwise the RTL view of memory will not match.
165 if (!memory_is_initialized) {
166 initialize_memory();
167 memory_is_initialized = 1;
172 if (H(ehdr.e_type) != ET_EXEC)
173 fatal("%s is not an executable\n", name);
175 if (H(ehdr.e_machine) != EM_MIPS)
176 fatal("%s is not a MIPS executable\n", name);
178 if (enable_verb_elf) {
179 printf("%s:\n", name);
180 printf("%sendian\n", endian_is_big ? "big" : "little");
181 printf("Entry: %08x\n", W(ehdr.e_entry)); /* Entry point virtual address */
182 printf("Proc Flags: %08x\n", W(ehdr.e_flags)); /* Processor-specific flags */
183 printf("Phdr.tbl entry cnt % 8d\n", H(ehdr.e_phnum)); /*Program header table entry count */
184 printf("Shdr.tbl entry cnt % 8d\n", H(ehdr.e_shnum)); /*Section header table entry count */
185 printf("Shdr.str tbl idx % 8d\n", H(ehdr.e_shstrndx)); /*Section header string table index */
187 program_entry = W(ehdr.e_entry);
189 if (H(ehdr.e_ehsize) != sizeof(ehdr)) {
190 fprintf(stderr, "Oops, I can't handle this Elf header size");
191 exit(1);
194 phentsize = H(ehdr.e_phentsize);
196 if (H(ehdr.e_shentsize) != sizeof(Elf32_Shdr)) {
197 fprintf(stderr, "Oops, I can't handle this Elf section header size");
198 exit(1);
201 // Allocate program headers
202 ph = malloc(sizeof(*ph) * H(ehdr.e_phnum));
204 for (i = 0; i < H(ehdr.e_phnum); ++i) {
205 fseek(f, W(ehdr.e_phoff) + i * phentsize, SEEK_SET);
206 if (fread(&ph[i], sizeof(ph[i]), 1, f) != 1)
207 fatal("Can't read a program header");
209 if (enable_verb_elf) {
210 printf("\nProgram header #%d (%lx)\n", i, ftell(f));
211 printf(" type %08x\n", W(ph[i].p_type));
212 printf(" filesz %08x\n", W(ph[i].p_filesz));
213 printf(" offset %08x\n", W(ph[i].p_offset));
214 printf(" vaddr %08x\n", W(ph[i].p_vaddr));
215 printf(" paddr %08x\n", W(ph[i].p_paddr));
216 printf(" memsz %08x\n", W(ph[i].p_memsz));
217 printf(" flags %08x\n", W(ph[i].p_flags));
218 printf(" align %08x\n", W(ph[i].p_align));
221 if (enable_firmware_mode &&
222 (W(ph[i].p_vaddr) & 0xFFFF0000) != 0xBFC00000)
223 // we simulate the bare hardware, we cannot preload
224 // the sram. Thus we'll ignore everything that isn't
225 // for BFC0XXXX
226 continue;
228 if (W(ph[i].p_type) == PT_LOAD) {
229 ensure_mapped_memory_range(W(ph[i].p_vaddr),
230 W(ph[i].p_memsz));
231 if (W(ph[i].p_filesz)) {
232 if (enable_verb_elf)
233 fprintf(stderr, "Loading section [%08x; %08x]\n",
234 W(ph[i].p_vaddr), W(ph[i].p_memsz));
235 loadsection(f, W(ph[i].p_offset), W(ph[i].p_filesz),
236 W(ph[i].p_vaddr), W(ph[i].p_memsz));
240 if (W(ph[i].p_flags) & 1) {
241 // XXX I _think_ this means executable, but I
242 // haven't checked!
243 text_segments++;
244 text_start = W(ph[i].p_vaddr);
245 text_size = W(ph[i].p_memsz);
249 if (enable_verb_elf) {
250 printf("\n");
252 fseek(f, W(ehdr.e_shoff), SEEK_SET);
253 for (i = 0; i < H(ehdr.e_shnum); ++i) {
254 Elf32_Shdr sh;
256 if (fread(&sh, sizeof(sh), 1, f) != 1)
257 fatal("Can't read a section header");
259 printf("\nSection header #%d (%lx)\n", i, ftell(f));
260 printf(" name %08x\n", W(sh.sh_name));
261 printf(" type %08x\n", W(sh.sh_type));
262 printf(" flags %08x\n", W(sh.sh_flags));
263 printf(" addr %08x\n", W(sh.sh_addr));
264 printf(" offset %08x\n", W(sh.sh_offset));
265 printf(" size %08x\n", W(sh.sh_size));
266 printf(" link %08x\n", W(sh.sh_link));
267 printf(" info %08x\n", W(sh.sh_info));
268 printf(" addralign %08x\n", W(sh.sh_addralign));
269 printf(" entsize %08x\n", W(sh.sh_entsize));
271 printf(" (now at %lx)\n", ftell(f));
275 void dis_load_store(char *buf, char *name, inst_t i)
277 if (i.i.imm)
278 sprintf(buf, "%-6s$%d,%d($%d)", name, i.r.rt, i.i.imm, i.r.rs);
279 else
280 sprintf(buf, "%-6s$%d,($%d)", name, i.r.rt, i.r.rs);
283 void dis_load_store_cp1(char *buf, char *name, inst_t i)
285 if (i.i.imm)
286 sprintf(buf, "%-6s$f%d,%d($%d)", name, i.r.rt, i.i.imm, i.r.rs);
287 else
288 sprintf(buf, "%-6s$f%d,($%d)", name, i.r.rt, i.r.rs);
291 void disass(unsigned pc, inst_t i)
293 char buf[999];
294 unsigned npc = pc + 4;
296 switch (i.j.opcode) {
297 default: fatal("Unknown instruction opcode 0d%d", i.j.opcode);
298 case SPECIAL:
299 switch (i.r.funct) {
300 unhandled:
301 default: sprintf(buf,"??0x%x?? $%d,$%d,%d", i.r.funct, i.r.rd, i.r.rt, i.r.sa);
302 break;
303 case SLL:
304 if (i.r.rd | i.r.rt | i.r.sa)
305 sprintf(buf,"%-6s$%d,$%d,%d", "sll", i.r.rd, i.r.rt, i.r.sa);
306 else
307 sprintf(buf,"nop");
308 break;
309 case SRL: sprintf(buf,"%-6s$%d,$%d,%d","srl", i.r.rd, i.r.rt, i.r.sa); break;
310 case SRA: sprintf(buf,"%-6s$%d,$%d,%d","sra", i.r.rd, i.r.rt, i.r.sa); break;
311 case SLLV: sprintf(buf,"%-6s$%d,$%d,$%d","sllv", i.r.rd, i.r.rt, i.r.rs); break;
312 case SRLV: sprintf(buf,"%-6s$%d,$%d,$%d","srlv", i.r.rd, i.r.rt, i.r.rs); break;
313 case SRAV: sprintf(buf,"%-6s$%d,$%d,$%d","srav", i.r.rd, i.r.rt, i.r.rs); break;
314 case JR: sprintf(buf,"%-6s$%d","jr", i.r.rs); break;
315 case JALR:
316 if (i.r.rd == 31)
317 sprintf(buf,"%-6s$%d","jalr", i.r.rs);
318 else
319 sprintf(buf,"%-6s$%d,$%d","jalr", i.r.rs, i.r.rd);
320 break;
322 case SYSCALL: sprintf(buf,"%-6s","syscall"); break;
324 case MFHI: sprintf(buf,"%-6s$%d","mfhi", i.r.rd); break;
325 case MTHI: sprintf(buf,"%-6s$%d","mthi", i.r.rs); break;
326 case MFLO: sprintf(buf,"%-6s$%d","mflo", i.r.rd); break;
327 case MTLO: sprintf(buf,"%-6s$%d","mtlo", i.r.rs); break;
328 case MULT: sprintf(buf,"%-6s$%d,$%d","mult", i.r.rs, i.r.rt); break;
329 case MULTU:sprintf(buf,"%-6s$%d,$%d","multu", i.r.rs, i.r.rt); break;
330 case DIV: sprintf(buf,"%-6s$%d,$%d","div", i.r.rs, i.r.rt); break;
331 case DIVU: sprintf(buf,"%-6s$%d,$%d","divu", i.r.rs, i.r.rt); break;
332 case ADD: sprintf(buf,"%-6s$%d,$%d,$%d","add", i.r.rd, i.r.rs, i.r.rt); break;
333 case ADDU:
334 if (i.r.rt)
335 sprintf(buf,"%-6s$%d,$%d,$%d","addu", i.r.rd, i.r.rs, i.r.rt);
336 else
337 sprintf(buf,"%-6s$%d,$%d","move", i.r.rd, i.r.rs);
338 break;
339 case SUB: sprintf(buf,"%-6s$%d,$%d,$%d","sub", i.r.rd, i.r.rs, i.r.rt); break;
340 case SUBU: sprintf(buf,"%-6s$%d,$%d,$%d","subu", i.r.rd, i.r.rs, i.r.rt); break;
341 case AND: sprintf(buf,"%-6s$%d,$%d,$%d","and", i.r.rd, i.r.rs, i.r.rt); break;
342 case OR:
343 if (i.r.rt)
344 sprintf(buf,"%-6s$%d,$%d,$%d","or",i.r.rd, i.r.rs, i.r.rt);
345 else
346 sprintf(buf,"%-6s$%d,$%d","move",i.r.rd, i.r.rs);
347 break;
348 case XOR: sprintf(buf,"%-6s$%d,$%d,$%d","xor", i.r.rd, i.r.rs, i.r.rt); break;
349 case NOR: sprintf(buf,"%-6s$%d,$%d,$%d","nor", i.r.rd, i.r.rs, i.r.rt); break;
350 case SLT: sprintf(buf,"%-6s$%d,$%d,$%d","slt", i.r.rd, i.r.rs, i.r.rt); break;
351 case SLTU: sprintf(buf,"%-6s$%d,$%d,$%d","sltu", i.r.rd, i.r.rs, i.r.rt); break;
352 case TEQ: sprintf(buf,"%-6s$%d,$%d,%d","teq", i.r.rs, i.r.rt, i.r.sa); break;
353 case BREAK:sprintf(buf,"%-6s","break"); break;
355 break;
356 case REGIMM:
357 switch (i.r.rt) {
358 default: fatal("REGIMM rt=%d", i.r.rt);
359 case BLTZ: sprintf(buf,"%-6s$%d,0x%08x","bltz", i.r.rs, npc + (i.i.imm << 2)); break;
360 case BGEZ: sprintf(buf,"%-6s$%d,0x%08x","bgez", i.r.rs, npc + (i.i.imm << 2)); break;
361 case BLTZAL:sprintf(buf,"%-6s$%d,0x%08x","bltzal", i.r.rs, npc + (i.i.imm << 2)); break;
362 case BGEZAL:
363 if (i.r.rs)
364 sprintf(buf,"%-6s$%d,0x%08x","bgezal", i.r.rs, npc + (i.i.imm << 2));
365 else
366 sprintf(buf,"%-6s0x%08x","bal", npc + (i.i.imm << 2));
367 break;
368 case SYNCI:
369 sprintf(buf, "%-6s%d($%d)", "synci", i.i.imm, i.r.rs);
370 break;
372 break;
373 case J: sprintf(buf,"%-6s0x%08x","j", (npc & ~((1<<28)-1)) | (i.j.offset << 2)); break;
374 case JAL: sprintf(buf,"%-6s0x%08x","jal", (npc & ~((1<<28)-1)) | (i.j.offset << 2)); break;
375 case BEQ:
376 if (i.r.rs | i.r.rt)
377 sprintf(buf,"%-6s$%d,$%d,0x%08x","beq", i.r.rs, i.r.rt, npc + (i.i.imm << 2));
378 else
379 sprintf(buf,"%-6s0x%08x","b", npc + (i.i.imm << 2));
380 break;
381 case BNE: sprintf(buf,"%-6s$%d,$%d,0x%08x","bne", i.r.rs, i.r.rt, npc + (i.i.imm << 2)); break;
382 case BLEZ: sprintf(buf,"%-6s$%d,$%d,0x%08x","blez", i.r.rs, i.r.rt, npc + (i.i.imm << 2)); break;
383 case BGTZ: sprintf(buf,"%-6s$%d,$%d,0x%08x","bgtz", i.r.rs, i.r.rt, npc + (i.i.imm << 2)); break;
384 case ADDI: sprintf(buf,"%-6s$%d,$%d,%d","addi", i.r.rt, i.r.rs, i.i.imm); break;
385 case ADDIU:
386 if (i.r.rs)
387 sprintf(buf,"%-6s$%d,$%d,%d","addiu", i.r.rt, i.r.rs, i.i.imm);
388 else
389 sprintf(buf,"%-6s$%d,%d","li", i.r.rt, i.i.imm);
390 break;
391 case SLTI: sprintf(buf,"%-6s$%d,$%d,%d","slti", i.r.rt, i.r.rs, i.i.imm); break;
392 case SLTIU:sprintf(buf,"%-6s$%d,$%d,%d","sltiu", i.r.rt, i.r.rs, i.i.imm); break;
393 case ANDI: sprintf(buf,"%-6s$%d,$%d,0x%04x","andi", i.r.rt, i.r.rs, i.u.imm); break;
394 case ORI: sprintf(buf,"%-6s$%d,$%d,0x%04x","ori", i.r.rt, i.r.rs, i.u.imm); break;
395 case XORI: sprintf(buf,"%-6s$%d,$%d,0x%04x","xori", i.r.rt, i.r.rs, i.u.imm); break;
396 case LUI: sprintf(buf,"%-6s$%d,0x%x","lui", i.r.rt, i.u.imm); break;
397 case CP0:
398 /* Two possible formats */
399 if (i.r.rs & 0x10) {
400 /* C1 format */
401 sprintf(buf,
402 i.r.funct == C0_TLBR ? "tlbr" :
403 i.r.funct == C0_TLBWI ? "tlbwi" :
404 i.r.funct == C0_TLBWR ? "tlbwr" :
405 i.r.funct == C0_TLBP ? "tlbp" :
406 i.r.funct == C0_ERET ? "eret" :
407 i.r.funct == C0_DERET ? "deret" :
408 i.r.funct == C0_WAIT ? "wait" :
409 "???");
410 } else {
411 /* Regular r format with i.r.rs[3] ? MT : MF */
412 sprintf(buf,
413 "%-6s$%d,$%d (sel %d, rs %d)",
414 i.r.rs & 4 ? "mtc0" : "mfc0",
415 i.r.rt, i.r.rd,
416 i.r.funct,
417 i.r.rs);
420 40826000 mtc0 v0,$12
421 40806800 mtc0 zero,$13
422 40826000 mtc0 v0,$12
423 408f4000 mtc0 t7,$8
425 break;
426 case CP1: sprintf(buf,"%-6s", "cp1"); break;
427 case CP2:
428 /* Two possible formats */
429 if (i.r.rs & 0x10) {
430 /* C1 format */
431 sprintf(buf,"%-6s%08x", "cp2", i.raw); break;
432 } else {
433 /* Regular r format with i.r.rs[3] ? MT : MF */
434 sprintf(buf,
435 "%-6s$%d,$%d (sel %d, rs %d)",
436 i.r.rs & 4 ? "mtc2" : "mfc2",
437 i.r.rt, i.r.rd,
438 i.r.funct,
439 i.r.rs);
441 break;
442 case CP1X: sprintf(buf,"%-6s", "cp1x"); break;
443 case BEQL: sprintf(buf,"%-6s","bbql"); break;
444 case RDHWR:
445 if (i.r.funct == 59) {
446 sprintf(buf,"%-6s$%d,$%d", "rdhwr", i.r.rt, i.r.rd);
447 break;
449 goto unhandled;
451 case LB: dis_load_store(buf, "lb", i); break;
452 case LH: dis_load_store(buf, "lh", i); break;
453 case LW: dis_load_store(buf, "lw", i); break;
454 case LWL: dis_load_store(buf, "lwl", i); break;
455 case LWR: dis_load_store(buf, "lwr", i); break;
456 case LBU: dis_load_store(buf, "lbu", i); break;
457 case LHU: dis_load_store(buf, "lhu", i); break;
458 case SB: dis_load_store(buf, "sb", i); break;
459 case SH: dis_load_store(buf, "sh", i); break;
460 case SW: dis_load_store(buf, "sw", i); break;
461 case SWL: dis_load_store(buf, "swl", i); break;
462 case SWR: dis_load_store(buf, "swr", i); break;
463 case LWC1: dis_load_store_cp1(buf, "lwc1", i); break;
464 case SWC1: dis_load_store_cp1(buf, "swc1", i); break;
465 case LDC1: dis_load_store_cp1(buf, "ldc1", i); break;
466 case SDC1: dis_load_store_cp1(buf, "sdc1", i); break;
468 printf("%-24s", buf);
471 unsigned load(unsigned a, // IN: address
472 int c, // IN: count of bytes to load
473 int fetch) // IN: instruction or data?
475 unsigned res;
478 * Handle special load devices.
479 * So far we only have a serial output port.
481 if (!fetch && (a >> 4) == 0xFF00000) {
482 switch ((a >> 2) & 0xF) {
483 case 0: // rs232out_busy
484 if (serial_wait) {
485 serial_wait--; // Not quite accurate, but ..
486 res = 1;
487 } else
488 res = 0;
489 break;
490 case 1: res = rs232in_data & 255;
491 if (enable_disass) {
492 fprintf(stderr, "\nSERIAL INPUT '%c' (%d)\n",
493 res, res);
495 rs232in_pending = 0;
496 break;
497 case 2:
498 if (rs232in_pending > 1) {
499 if (--rs232in_pending == 1)
500 ++rs232in_cnt;
502 res = rs232in_cnt; break;
504 case 3:
505 // TSC
506 res = TSC;
507 break;
509 default:
510 fatal("Unknown register 0x%08x\n", a);
513 service_rs232();
515 // BIG ENDIAN (XXX)
516 switch (c) {
517 case 1: return (res >> (~a & 3) * 8) & 0xFF;
518 case 2: return (res >> (~a & 1) * 16) & 0xFFFF;
519 case 4: return res;
520 default: assert(0);
524 if (!(addr_mapped(a) && addr_mapped(a + c - 1))) {
525 // fatal("Loading from outside memory 0x%08x\n", a);
526 fprintf(stderr, "Loading from outside memory 0x%08x\n", a);
527 segfault = 1;
528 return 0;
531 if (!fetch && (a & 0xFFF00000) == 0xBFC00000) {
532 fatal("\tloading from boot PROM 0x%08x\n", a);
533 return 0;
536 if (a & (c - 1))
537 fatal("Unaligned load from 0x%08x\n", a);
539 // BIG ENDIAN
541 switch (c) {
542 case 1:
543 res = *(u_int8_t *)addr2phys(a);
544 break;
545 case 2:
546 res = H(*(u_int16_t*)addr2phys(a));
547 break;
548 case 4:
549 res = W(*(u_int32_t*)addr2phys(a));
550 break;
551 default: assert(0);
554 if (0 && enable_disass && !fetch)
555 switch (c) {
556 case 1: printf("\t\t\t\t\t%02x <- [%08x]\n",
557 res, a);
558 break;
559 case 2: printf("\t\t\t\t\t%04x <- [%08x]\n",
560 res, a);
561 break;
562 case 4: printf("\t\t\t\t\t%08x <- [%08x]\n",
563 res, a);
564 break;
567 return res;
570 void store(unsigned a, unsigned v, int c)
572 // XXX debug
573 void *phys;
576 * Handle special load devices.
577 * So far we only have a serial output port.
579 if (a == 0xFF000000) {
580 unsigned char ch = v;
581 serial_wait = 0;
582 if (enable_disass) {
583 fprintf(stderr, "\nSERIAL OUTPUT '%c' (%d)\n",
584 ch, ch);
585 } else {
586 printf("%c", v);
587 fflush(stdout);
589 if (rs232out_fd >= 0) {
590 // fputc(ch, stderr);
591 // fprintf(stderr, "SERIAL OUT '%c' (%d)\n", ch, ch);
592 write(rs232out_fd, &ch, 1);
594 return;
597 if (!(addr_mapped(a) && addr_mapped(a + c - 1)))
598 fatal("\tstoring outside memory 0x%08x\n", a);
600 if ((a & 0xFFF00000) == 0xBFC00000) {
601 fatal("\tstoring to boot PROM 0x%08x\n", a);
604 if (a & (c - 1))
605 fatal("\tUnaligned store at 0x%08x\n", a);
607 if (0 && enable_disass)
608 switch (c) {
609 case 1: printf("\t\t\t\t\t%02x -> [%08x] (was %02x)\n",
610 v, a, *(u_int8_t *)addr2phys(a));
611 break;
612 case 2: printf("\t\t\t\t\t%04x -> [%08x] (was %04x)\n",
613 v, a, ntohs(*(u_int16_t*)addr2phys(a)));
614 break;
615 case 4: printf("\t\t\t\t\t%08x -> [%08x] (was %08x)\n",
616 v, a, ntohl(*(u_int32_t*)addr2phys(a)));
617 break;
620 switch (c) {
621 case 1: *(u_int8_t *)(phys = addr2phys(a)) = v; break;
622 case 2: *(u_int16_t*)(phys = addr2phys(a)) = H(v); break;
623 case 4: *(u_int32_t*)(phys = addr2phys(a)) = W(v); break;
624 default: exit(1);
628 static unsigned char
629 chksum(unsigned x)
631 return (x & 255) + ((x >> 8) & 255) + ((x >> 16) & 255) + ((x >> 24) & 255);
634 void dump(char kind)
636 unsigned p = text_start;
637 int i;
639 // assert(text_start == 0x80000000);
641 // This is used to dump to "prom" and doesn't need to be very general
642 assert(text_segments == 1);
645 if (kind == 'm') {
646 printf("-- yarisim generated Memory Initialization File (.mif)\n"
647 "\n"
648 "WIDTH=32;\n"
649 "DEPTH=%d;\n"
650 "\n"
651 "ADDRESS_RADIX=HEX;\n"
652 "DATA_RADIX=HEX;\n"
653 "\n"
654 "CONTENT BEGIN\n",
655 mif_size / 4);
658 for (i = 0; p < text_start + text_size; p += 4, ++i) {
659 unsigned data = load(p, 4, 1);
661 if (kind == 'd')
662 printf("%08X\n", data);
663 else if (kind == 'm') {
664 printf("\t%08x : %08x;\n", i, data);
665 } else {
666 unsigned char checksum;
667 checksum = 4 + chksum(i) + chksum(data);
668 printf(":04%04x00%08x%02x",
669 i, data, checksum);
673 if (kind == 'm') {
674 printf("END;\n");
680 static void tinymon_cmd(unsigned char cmd, unsigned val)
682 unsigned char chk = cmd;
683 int i;
684 int leading_zero = 1;
686 putchar(cmd);
687 for (i = 0; i < 8; ++i) {
688 unsigned char c = "0123456789abcdef"[val >> 28];
690 if ((val >> 28) != 0 || !leading_zero || i == 7) {
691 leading_zero = 0;
693 chk += c;
694 putchar(c);
696 val <<= 4;
698 putchar(' ');
699 putchar("0123456789abcdef"[chk >> 4]);
700 putchar("0123456789abcdef"[chk & 15]);
701 putchar('\r');
702 putchar('\n');
705 void dump_tinymon_old(void)
707 unsigned p, k;
709 tinymon_cmd('c', 0);
711 for (k = 0; k < nsections; ++k) {
712 tinymon_cmd('l', section_start[k]);
713 unsigned end = section_start[k] + section_size[k];
714 for (p = section_start[k]; p < end; p += 4)
715 tinymon_cmd('w', load(p, 4, 1));
718 tinymon_cmd('e', program_entry);
722 * Base85 encoding inspired by git, though much simplified by only
723 * considering word-at-a-time encoding. This makes this encoding 3%
724 * less efficient which I think we can live with. Note, bigendian
725 * encoding in to slightly simplify the decoder.
727 static void tinymon_encode_word_base85(unsigned w)
729 unsigned e = w % 85; w /= 85;
730 unsigned d = w % 85; w /= 85;
731 unsigned c = w % 85; w /= 85;
732 unsigned b = w % 85; w /= 85;
733 unsigned a = w % 85; w /= 85;
734 assert(w == 0);
735 putchar(a + '(');
736 putchar(b + '(');
737 putchar(c + '(');
738 putchar(d + '(');
739 putchar(e + '(');
743 * Dump the section in base85. Format:
745 * x <size in words> \n
746 * <5 base85 bytes encoding a word> repeat size times
747 * <5 base85 bytes encoding the checksum>
750 void dump_tinymon(void)
752 unsigned p, k;
754 tinymon_cmd('c', 0);
756 for (k = 0; k < nsections; ++k) {
757 unsigned w = 0, chk = 0;
758 unsigned end = section_start[k] + section_size[k];
759 unsigned b;
761 tinymon_cmd('l', section_start[k]);
762 tinymon_cmd('x', section_size[k] / 4);
763 for (b = 1, p = section_start[k]; p < end; p += 4, b++) {
764 w = load(p, 4, 1);
765 chk += w;
766 tinymon_encode_word_base85(w);
768 if (b > 16)
769 putchar('\n'), b = 0;
771 tinymon_encode_word_base85(-chk);
772 putchar('\n');
775 tinymon_cmd('e', program_entry);
778 // Local Variables:
779 // mode: C
780 // c-style-variables-are-local-p: t
781 // c-file-style: "linux"
782 // End: