ref: e86160e1c5cae5d7ac79851a7167a1a0a3a6eddb
dir: /8080.c/
#include <u.h> #include <libc.h> #include <bio.h> #include <ctype.h> #include <draw.h> #include <thread.h> #include "dat.h" #include "fns.h" Biobuf *stdin; Biobuf *stdout; Biobuf *stderr; CPU ocpu, cpu; Insn insn; enum{ Width = 256, Height = 224, }; uchar mem[MEMSZ]; uchar *rom = &mem[0]; uchar *ram = &mem[ROMSZ]; uchar *vmem = &mem[ROMSZ+RAMSZ]; int interactive; int debug; int nbrkpts; int tracing; int ntraceops; TraceOp traceops[MAXTRACEOPS]; BrkPt brkpts[MAXBRKPTS]; static void usage(void) { fprint(2, "usage: %s [-b addr] [-i script] [-t addr] [-T addr]\n", argv0); threadexitsall("usage"); } int loadrom(char *file, u16int base) { uchar *mp, *romend; int c; Biobuf *r; r = Bopen(file, OREAD); if(r == nil) return -1; romend = rom + ROMSZ; for(;;){ for(mp = &rom[base]; mp < romend; mp++){ c = Bgetc(r); if(c < 0) goto Done; *mp = c; } } Done: Bterm(r); return 0; } static void cpureset(void) { memset(&ocpu, 0, sizeof(ocpu)); memset(&cpu, 0, sizeof(cpu)); } static void cpustep(void) { int i; int ilen; uchar buf[3]; static u64int counter; for(i = 0; i < ntraceops; i++) if(cpu.PC == traceops[i].addr) if(traceops[i].op == Tpush){ dprint("@@@@ Tpush @ %2x\n", traceops[i].addr); tracing++; } for(i = 0; i < nbrkpts; i++){ if(brkpts[i].enabled && brkpts[i].hit == 0 && cpu.PC == brkpts[i].addr){ Bprint(stderr, "hit breakpoint %d @ pc=%#.4uhx\n", i+1, cpu.PC); Bflush(stderr); brkpts[i].hit = 1; trap(); } } insn.pc = cpu.PC; insn.op = decodeop(buf[0] = ifetch(&cpu)); if(insn.op == -1){ Bprint(stderr, "illegal opcode %#.2uhhx @ pc=%#.4uhx\n", buf[0], cpu.PC); Bflush(stderr); trap(); } switch(ilen = insnlen(insn.op)){ case 2: buf[1] = ifetch(&cpu); break; case 3: buf[1] = ifetch(&cpu); buf[2] = ifetch(&cpu); break; } decodeinsn(&insn, buf, ilen); cpuexec(&cpu, &insn); counter++; if((cpu.intr&Ienabled) != 0){ if(counter % 512 == 0){ push16(&cpu, cpu.PC); cpu.PC = 2<<3; }else if(counter % 256 == 0){ push16(&cpu, cpu.PC); cpu.PC = 1<<3; } } for(i = 0; i < nbrkpts; i++) if(cpu.PC == brkpts[i].addr) brkpts[i].hit = 0; for(i = 0; i < ntraceops; i++) if(cpu.PC == traceops[i].addr) if(traceops[i].op == Tpop){ dprint("@@@@ Tpop @ %2x\n", traceops[i].addr); tracing--; } ocpu = cpu; } enum { Cerror = -1, Cnone, Cdas, Cbpls, Cbpset, Cbpdel, Cload, Creg, Crun, Cstep, Cexit, Creset, }; static char *cmdtab[] = { [Cnone] "", [Cdas] "das", [Cbpls] "bpls", [Cbpset] "bpset", [Cbpdel] "bpdel", [Cload] "load", [Creg] "reg", [Crun] "run", [Cstep] "step", [Cexit] "exit", [Creset] "reset", }; typedef struct Cmd Cmd; struct Cmd { char *buf; int argc; char *argv[16]; }; static int cmd(char *s) { int i; for(i = 0; i < nelem(cmdtab); i++){ if(strcmp(s, cmdtab[i]) == 0) return i; } return Cerror; } static void docmd(Cmd *c) { int i; switch(cmd(c->argv[0])){ case Cerror: Bprint(stderr, "unknown command: %s\n", c->argv[0]); Bflush(stderr); break; case Cnone: break; case Cdas: das(mem+cpu.PC,mem+nelem(mem), -1); break; case Cbpls: if(c->argc != 1){ Bprint(stderr, "usage: bpls\n"); Bflush(stderr); break; } for(i = 0; i < nbrkpts; i++){ if(brkpts[i].enabled == 0) continue; Bprint(stdout, "bp %d @ %#.4uhx\n", i+1, brkpts[i].addr); } Bflush(stdout); break; case Cbpset: if(c->argc != 2){ Bprint(stderr, "usage: bpset ADDR\n"); Bflush(stderr); break; } if(nbrkpts >= MAXBRKPTS){ Bprint(stderr, "too many breakpoints"); Bflush(stderr); break; } brkpts[nbrkpts].addr = strtoul(c->argv[1], 0, 0); brkpts[nbrkpts].enabled = 1; nbrkpts++; break; case Cbpdel: if(c->argc != 2){ Bprint(stderr, "usage: bpdel NUM\n"); Bflush(stderr); break; } i = strtoul(c->argv[1], 0, 0); if(i < 1 || i > nbrkpts){ Bprint(stderr, "bad breakpoint number\n"); Bflush(stderr); break; } if(brkpts[i-1].enabled == 0){ Bprint(stderr, "no such breakpoint\n"); Bflush(stderr); break; } brkpts[i-1].enabled = 0; break; case Cload: if(c->argc != 2){ Bprint(stderr, "usage: load ROM\n"); Bflush(stderr); break; } if(loadrom(c->argv[1], 0) < 0){ Bprint(stderr, "loading %s failed: %r\n", c->argv[1]); Bflush(stderr); } break; case Creg: dumpregs(); break; case Crun: if(c->argc != 1){ Bprint(stderr, "usage: run\n"); Bflush(stderr); break; } if(wastrap()){ Bflush(stdout); cpu = ocpu; }else{ for(;;){ //Bprint(stdout, "%#.4uhx\t", cpu.PC); //das1(mem+cpu.PC,nelem(mem)-cpu.PC); cpustep(); } } break; case Cstep: if(wastrap()){ cpu = ocpu; }else{ print("%#.4uhx\t", cpu.PC); das1(mem+cpu.PC,nelem(mem)-cpu.PC); cpustep(); } break; case Cexit: threadexitsall(0); break; case Creset: cpureset(); break; } } static Cmd prev; static int proc(Biobuf *in) { char *buf; Cmd cmd; trapinit(); buf = Brdstr(in, '\n', 0); Bflush(stderr); if(Blinelen(in) <= 0) return Blinelen(in); while(isspace(*buf)) buf++; if(*buf == '#') return Blinelen(in); cmd.argc = tokenize(buf, cmd.argv, nelem(cmd.argv)); if(cmd.argc == 0){ free(buf); if(prev.argc > 0) docmd(&prev); }else{ cmd.buf = buf; docmd(&cmd); free(prev.buf); prev = cmd; } return Blinelen(in); } static void procfile(char *file) { Biobuf *b; b = Bopen(file, OREAD); if(b == nil) sysfatal("could not open %s: %r", file); for(;;){ switch(proc(b)){ case -1: sysfatal("error processing %s", file); case 0: Bterm(b); return; } } } static int isatty(void) { char buf[64]; if(fd2path(0, buf, sizeof(buf)) != 0) return 0; return strcmp(buf, "/dev/cons") == 0; } static void resize(int w, int h) { int fd; if((fd = open("/dev/wctl", OWRITE)) < 0) return; fprint(fd, "resize -dx %d -dy %d", w, h); close(fd); } static void scanout(void*) { int i; uchar *p; Image *line; Rectangle r; line = allocimage(display, Rect(0,0,Width,1), GREY1, 0, DNofill); for(;;){ p = vmem; r.min = Pt(screen->r.min.x, screen->r.max.y-1); r.max = Pt(screen->r.max.x, screen->r.max.y); for(i = 0; i < Height/2; i++){ loadimage(line, Rect(0,0,Width,1), p, Width/8); draw(screen, r, line, nil, ZP); r = rectaddpt(r, Pt(0, -1)); p += Width/8; } flushimage(display, 1); sleep(1000/30); for(; i < Height; i++){ loadimage(line, Rect(0,0,Width,1), p, Width/8); draw(screen, r, line, nil, ZP); r = rectaddpt(r, Pt(0, -1)); p += Width/8; } flushimage(display, 1); sleep(1000/30); } } void threadmain(int argc, char **argv) { stdin = Bfdopen(0, OREAD); stdout = Bfdopen(1, OWRITE); stderr = Bfdopen(2, OWRITE); ARGBEGIN{ case 'b': if(nbrkpts >= MAXBRKPTS) sysfatal("too many breakpoints"); brkpts[nbrkpts].addr = strtoul(EARGF(usage()), 0, 0); brkpts[nbrkpts].enabled = 1; nbrkpts++; break; case 'd': debug++; break; case 'i': procfile(EARGF(usage())); break; case 't': case 'T': if(ntraceops >= MAXTRACEOPS) sysfatal("too many trace ops"); traceops[ntraceops].addr = strtoul(EARGF(usage()), 0, 0); traceops[ntraceops].op = ARGC() == 'T' ? Tpush : Tpop; ntraceops++; break; default: usage(); }ARGEND; if(argc != 0) usage(); if(newwindow(nil) < 0) sysfatal("newwindow: %r"); resize(Width, Height); if(initdraw(nil, nil, nil) < 0) sysfatal("initdraw: %r"); proccreate(scanout, nil, 1024); interactive = isatty(); fmtinstall('I', insnfmt); cpureset(); for(;;){ if(interactive){ Bprint(stdout, "8080> "); Bflush(stdout); } switch(proc(stdin)){ case -1: sysfatal("error reading stdin: %r"); case 0: threadexitsall(0); } } }