ref: df6478340d048ba76ab8e96aaaf490930a778eae
author: Alex Musolino <[email protected]>
date: Sat Nov 28 22:14:37 EST 2020
initial commit
--- /dev/null
+++ b/8080.c
@@ -1,0 +1,226 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "dat.h"
+#include "fns.h"
+
+CPU ocpu, cpu;
+Insn insn;
+
+uchar mem[MEMSZ];
+uchar *rom = &mem[0];
+uchar *ram = &mem[ROMSZ];
+uchar *vid = &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] rom\n", argv0);
+ exits("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 && cpu.PC == brkpts[i].addr){
+ brkpts[i].enabled = 0;
+ trap();
+ }
+
+ insn.pc = cpu.PC;
+ insn.op = decodeop(buf[0] = ifetch(&cpu));
+ if(insn.op == -1){
+ fprint(2, "illegal opcode %#.2uhhx @ pc=%#.4uhx\n", buf[0], insn.pc);
+ 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].enabled = 1;
+
+ 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;
+}
+
+static void
+prompt(void)
+{
+ static char prev[256] = "";
+ int n;
+ char buf[256];
+
+ trapinit();
+ if(interactive)
+ print("8080> ");
+ n = read(0, buf, sizeof(buf) - 1);
+ if(n <= 0)
+ exits("eof");
+ if(buf[n-1] != '\n')
+ exits("nl");
+ buf[n-1] = 0;
+ if(strcmp(buf, "") == 0){
+ if(strcmp(prev, "") == 0)
+ return;
+ strcpy(buf, prev);
+ }
+ if(strcmp(buf, "das") == 0){
+ //das(&insn, mem);
+ }else if(strcmp(buf, "bpset") == 0){
+ }else if(strcmp(buf, "load") == 0){
+ if(loadrom("invaders.rom", 0) < 0)
+ fprint(2, "load failed: %r\n");
+ }else if(strcmp(buf, "reg") == 0){
+ dumpregs();
+ }else if(strcmp(buf, "run") == 0){
+ if(wastrap())
+ cpu = ocpu;
+ else
+ for(;;){
+ //print("%#.4uhx\t", cpu.PC);
+ //das(mem+cpu.PC,nelem(mem));
+ cpustep();
+ }
+ }else if(strcmp(buf, "step") == 0){
+ if(wastrap())
+ cpu = ocpu;
+ else{
+ print("%#.4uhx\t", cpu.PC);
+ das(mem+cpu.PC,nelem(mem));
+ cpustep();
+ }
+ }else if(strcmp(buf, "exit") == 0){
+ exits(0);
+ }else if(strcmp(buf, "reset") == 0){
+ cpureset();
+ }else{
+ fprint(2, "unknown command: %s\n", buf);
+ buf[0] = 0;
+ }
+ strcpy(prev, buf);
+}
+
+static int
+isatty(void)
+{
+ char buf[64];
+
+ if(fd2path(0, buf, sizeof(buf)) != 0)
+ return 0;
+ return strcmp(buf, "/dev/cons") == 0;
+}
+
+void
+main(int argc, char **argv)
+{
+ 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 '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();
+ interactive = isatty();
+ fmtinstall('I', insnfmt);
+ cpureset();
+ if(loadrom("invaders.rom", 0) < 0)
+ fprint(2, "load failed: %r\n");
+ for(;;)
+ prompt();
+}
--- /dev/null
+++ b/das.c
@@ -1,0 +1,1163 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "dat.h"
+#include "fns.h"
+
+static void Xshld(CPU*, Insn*);
+static void Xsbi(CPU*, Insn*);
+static void Xjm(CPU*, Insn*);
+static void Xdaa(CPU*, Insn*);
+static void Xcz(CPU*, Insn*);
+static void Xpchl(CPU*, Insn*);
+static void Xnop(CPU*, Insn*);
+static void Xjmp(CPU*, Insn*);
+static void Xlxi(CPU*, Insn*);
+static void Xmvi(CPU*, Insn*);
+static void Xpop(CPU*, Insn*);
+static void Xcall(CPU*, Insn*);
+static void Xldax(CPU*, Insn*);
+static void Xmov(CPU*, Insn*);
+static void Xinx(CPU*, Insn*);
+static void Xdcr(CPU*, Insn*);
+static void Xret(CPU*, Insn*);
+static void Xdad(CPU*, Insn*);
+static void Xsta(CPU*, Insn*);
+static void Xxra(CPU*, Insn*);
+static void Xout(CPU*, Insn*);
+static void Xora(CPU*, Insn*);
+static void Xlda(CPU*, Insn*);
+static void Xana(CPU*, Insn*);
+static void Xpush(CPU*, Insn*);
+static void Xxchg(CPU*, Insn*);
+static void Xinr(CPU*, Insn*);
+static void Xani(CPU*, Insn*);
+static void Xrar(CPU*, Insn*);
+static void Xori(CPU*, Insn*);
+static void Xcmp(CPU*, Insn*);
+static void Xrlc(CPU*, Insn*);
+static void Xrim(CPU*, Insn*);
+static void Xrrc(CPU*, Insn*);
+static void Xdcx(CPU*, Insn*);
+static void Xstax(CPU*, Insn*);
+static void Xcpi(CPU*, Insn*);
+static void Xadi(CPU*, Insn*);
+static void Xei(CPU*, Insn*);
+static void Xdi(CPU*, Insn*);
+static void Xin(CPU*, Insn*);
+static void Xjc(CPU*, Insn*);
+static void Xjz(CPU*, Insn*);
+static void Xjnc(CPU*, Insn*);
+static void Xjnz(CPU*, Insn*);
+static void Xrc(CPU*, Insn*);
+static void Xrnc(CPU*, Insn*);
+static void Xrnz(CPU*, Insn*);
+static void Xrz(CPU*, Insn*);
+static void Xsui(CPU*, Insn*);
+static void Xxthl(CPU*, Insn*);
+
+static int dec0(Insn*, uchar*, long);
+static int decaddr(Insn*, uchar*, long);
+static int decimm(Insn*, uchar*, long);
+static int decr00000xxx(Insn*, uchar*, long);
+static int decr00xxx000(Insn*, uchar*, long);
+static int decrimm(Insn*, uchar*, long);
+static int decrp(Insn*, uchar*, long);
+static int decrpimm(Insn*, uchar*, long);
+static int decrr(Insn*, uchar*, long);
+
+static int das0(Fmt*, Insn*);
+static int dasaddr(Fmt*, Insn*);
+static int dasimm(Fmt*, Insn*);
+static int dasr(Fmt*, Insn*);
+static int dasrimm(Fmt*, Insn*);
+static int dasrp(Fmt*, Insn*);
+static int dasrpimm(Fmt*, Insn*);
+static int dasrr(Fmt*, Insn*);
+
+static InsnType insntypes[] = {
+ [T0] = { 1, das0, dec0 },
+ [Taddr] = { 3, dasaddr, decaddr },
+ [Timm] = { 2, dasimm, decimm },
+ [Tr012] = { 1, dasr, decr00000xxx },
+ [Tr345] = { 1, dasr, decr00xxx000 },
+ [Trimm] = { 2, dasrimm, decrimm },
+ [Trp] = { 1, dasrp, decrp },
+ [Trpimm] = { 3, dasrpimm, decrpimm },
+ [Trr] = { 1, dasrr, decrr },
+};
+
+static ISA isa[] = {
+ [Oadc]{"ADC", Tr012},
+ [Oadd]{"ADD", Tr012},
+ [Oadi]{"ADI", Timm, Xadi},
+ [Oana]{"ANA", Tr012, Xana},
+ [Oani]{"ANI", Timm, Xani},
+ [Ocall]{"CALL", Taddr, Xcall},
+ [Ocm]{"CM", Taddr},
+ [Ocma]{"CMA", T0},
+ [Ocmc]{"CMC", T0},
+ [Ocmp]{"CMP", Tr012, Xcmp},
+ [Ocnc]{"CNC", Taddr},
+ [Ocpe]{"CPE", Taddr},
+ [Ocpi]{"CPI", Timm, Xcpi},
+ [Ocz]{"CZ", Taddr, Xcz},
+ [Odaa]{"DAA", T0, Xdaa},
+ [Odad]{"DAD", Trp, Xdad},
+ [Odcr]{"DCR", Tr345, Xdcr},
+ [Odcx]{"DCX", Trp, Xdcx},
+ [Odi]{"DI", T0, Xdi},
+ [Oei]{"EI", T0, Xei},
+ [Oin]{"IN", Timm, Xin},
+ [Oinr]{"INR", Tr345, Xinr},
+ [Oinx]{"INX", Trp, Xinx},
+ [Ojc]{"JC", Taddr, Xjc},
+ [Ojm]{"JM", Taddr, Xjm},
+ [Ojmp]{"JMP", Taddr, Xjmp},
+ [Ojnc]{"JNC", Taddr, Xjnc},
+ [Ojnz]{"JNZ", Taddr, Xjnz},
+ [Ojpo]{"JPO", Taddr},
+ [Ojz]{"JZ", Taddr, Xjz},
+ [Olda]{"LDA", Taddr, Xlda},
+ [Oldax]{"LDAX", Trp, Xldax},
+ [Olxi]{"LXI", Trpimm, Xlxi},
+ [Omov]{"MOV", Trr, Xmov},
+ [Omvi]{"MVI", Trimm, Xmvi},
+ [Onop]{"NOP", T0, Xnop},
+ [Oora]{"ORA", Tr012, Xora},
+ [Oori]{"ORI", Timm, Xori},
+ [Oout]{"OUT", Timm, Xout},
+ [Opchl]{"PCHL", T0, Xpchl},
+ [Opop]{"POP", Trp, Xpop},
+ [Opush]{"PUSH", Trp, Xpush},
+ [Orar]{"RAR", T0, Xrar},
+ [Orc]{"RC", T0, Xrc},
+ [Oret]{"RET", T0, Xret},
+ [Orim]{"RIM", T0},
+ [Orlc]{"RLC", T0, Xrlc},
+ [Orm]{"RM", T0},
+ [Ornc]{"RNC", T0, Xrnc},
+ [Ornz]{"RNZ", T0, Xrnz},
+ [Orp]{"RP", T0},
+ [Orpo]{"RPO", T0},
+ [Orrc]{"RRC", T0, Xrrc},
+ [Orst]{"RST", Timm},
+ [Orz]{"RZ", T0, Xrz},
+ [Osbb]{"SBB", Tr012},
+ [Osbi]{"SBI", Timm, Xsbi},
+ [Oshld]{"SHLD", Taddr, Xshld},
+ [Osim]{"SIM", T0},
+ [Osta]{"STA", Taddr, Xsta},
+ [Ostax]{"STAX", Trp, Xstax},
+ [Osub]{"SUB", Tr012},
+ [Osui]{"SUI", Timm, Xsui},
+ [Oxchg]{"XCHG", T0, Xxchg},
+ [Oxra]{"XRA", Tr012, Xxra},
+ [Oxri]{"XRI", Timm},
+ [Oxthl]{"XTHL", T0, Xxthl},
+};
+
+static char*
+opstr(int op)
+{
+ if(op < 0 || op >= nelem(isa))
+ return "XXX";
+ return isa[op].opstr;
+}
+
+static int
+das0(Fmt *fmt, Insn *insn)
+{
+ return fmtprint(fmt, "%s", opstr(insn->op));
+}
+
+static int
+dasr(Fmt *fmt, Insn *insn)
+{
+ return fmtprint(fmt, "%s %s", opstr(insn->op), rnam(insn->r1));
+}
+
+static int
+dasrr(Fmt *fmt, Insn *insn)
+{
+ return fmtprint(fmt, "%s %s, %s", opstr(insn->op),
+ rnam(insn->r1), rnam(insn->r2));
+}
+
+static int
+dasimm(Fmt *fmt, Insn *insn)
+{
+ char *fmtstr;
+
+ if(insn->op == Orst)
+ fmtstr = "%s %uhhd";
+ else
+ fmtstr = "%s #$%#.2uhhx";
+ return fmtprint(fmt, fmtstr, opstr(insn->op), insn->imm);
+}
+
+static int
+dasrimm(Fmt *fmt, Insn *insn)
+{
+ return fmtprint(fmt, "%s %s, #$%#.2uhhx", opstr(insn->op), rnam(insn->r1), insn->imm);
+}
+
+static int
+dasrp(Fmt *fmt, Insn *insn)
+{
+ char *rp;
+
+ rp = rpnam(insn->rp);
+ if(insn->rp == 3){
+ switch(insn->op){
+ case Opush:
+ case Opop:
+ rp = "PSW";
+ break;
+ case Odad:
+ rp = "SP";
+ break;
+ }
+ }
+ return fmtprint(fmt, "%s %s", opstr(insn->op), rp);
+}
+
+static int
+dasaddr(Fmt *fmt, Insn *insn)
+{
+ return fmtprint(fmt, "%s %#.4x", opstr(insn->op), insn->addr);
+}
+
+static int
+dasrpimm(Fmt *fmt, Insn *insn)
+{
+ return fmtprint(fmt, "%s %s, #$0x%.2uhhx%.2uhhx", opstr(insn->op),
+ insn->rp == 3 ? "SP" : rpnam(insn->rp), insn->imm1, insn->imm);
+}
+
+static int
+dec0(Insn*, uchar*, long)
+{
+ return 1;
+}
+
+static int
+decr00000xxx(Insn *insn, uchar *mem, long)
+{
+ insn->r1 = mem[0]&0x7;
+ return 1;
+}
+
+static int
+decr00xxx000(Insn *insn, uchar *mem, long)
+{
+ insn->r1 = (mem[0]>>3)&0x7;
+ return 1;
+}
+
+static int
+decrimm(Insn *insn, uchar *mem, long len)
+{
+ if(len < 2)
+ return 0;
+ insn->r1 = (mem[0]>>3)&0x7;
+ insn->imm = mem[1];
+ return 2;
+}
+
+static int
+decimm(Insn *insn, uchar *mem, long len)
+{
+ if(len < 2)
+ return 0;
+ insn->imm = mem[1];
+ return 2;
+}
+
+static int
+decaddr(Insn *insn, uchar *mem, long len)
+{
+ if(len < 3)
+ return 0;
+ insn->addr = (u8int)mem[1]|((u16int)mem[2])<<8;
+ return 3;
+}
+
+static int
+decrr(Insn *insn, uchar *mem, long)
+{
+ insn->r1 = (mem[0]>>3)&0x7;
+ insn->r2 = mem[0]&0x7;
+ if(insn->r1 == M && insn->r2 == M)
+ insn->op = Onop;
+ return 1;
+}
+
+static int
+decrp(Insn *insn, uchar *mem, long)
+{
+ insn->rp = (mem[0]>>4)&0x3;
+ return 1;
+}
+
+static int
+decrpimm(Insn *insn, uchar *mem, long len)
+{
+ if(len < 3)
+ return 0;
+ insn->rp = (mem[0]>>4)&0x3;
+ insn->imm = mem[1];
+ insn->imm1 = mem[2];
+ return 3;
+}
+
+int
+insnfmt(Fmt *fmt)
+{
+ Insn *insn;
+
+ insn = va_arg(fmt->args, Insn*);
+ if(insn->op < 0 || insn->op >= nelem(isa))
+ return fmtprint(fmt, "XXX");
+ return insntypes[isa[insn->op].type].das(fmt, insn);
+}
+
+int
+insnlen(u8int op)
+{
+ if(op >= nelem(isa))
+ return 0;
+ return insntypes[isa[op].type].len;
+}
+
+int
+decodeop(u8int b)
+{
+ if((b&0xc0) == 0x40)
+ return Omov;
+ switch(b){
+ case 0x0f: return Orrc;
+ case 0x1f: return Orar;
+ case 0x27: return Odaa;
+ case 0x2f: return Ocma;
+ case 0x3f: return Ocmc;
+ case 0xc0: return Ornz;
+ case 0xc2: return Ojnz;
+ case 0xc3: return Ojmp;
+ case 0xc4: return Ocz;
+ case 0xc6: return Oadi;
+ case 0xc8: return Orz;
+ case 0xc9: return Oret;
+ case 0xca: return Ojz;
+ case 0xcc: return Ocz;
+ case 0xcd: return Ocall;
+ case 0xd0: return Ornc;
+ case 0xd2: return Ojnc;
+ case 0xd3: return Oout;
+ case 0xd4: return Ocnc;
+ case 0xd6: return Osui;
+ case 0xd8: return Orc;
+ case 0xda: return Ojc;
+ case 0xdb: return Oin;
+ case 0xde: return Osbi;
+ case 0xe0: return Orpo;
+ case 0xe2: return Ojpo;
+ case 0xe3: return Oxthl;
+ case 0xe6: return Oani;
+ case 0xe9: return Opchl;
+ case 0xea: return Ojpe;
+ case 0xeb: return Oxchg;
+ case 0xec: return Ocpe;
+ case 0xee: return Oxri;
+ case 0xf0: return Orp;
+ case 0xf2: return Ojp;
+ case 0xf3: return Odi;
+ case 0xf6: return Oori;
+ case 0xf8: return Orm;
+ case 0xfa: return Ojm;
+ case 0xfb: return Oei;
+ case 0xfc: return Ocm;
+ case 0xfe: return Ocpi;
+ }
+ if((b&0x80) != 0){
+ switch(b&0xf8){
+ case 0x80: return Oadd;
+ case 0x88: return Oadc;
+ case 0x90: return Osub;
+ case 0x98: return Osbb;
+ case 0xa0: return Oana;
+ case 0xa8: return Oxra;
+ case 0xb0: return Oora;
+ case 0xb8: return Ocmp;
+ }
+ switch(b&0x7){
+ case 0x1: return Opop;
+ case 0x5:
+ switch(b&0xf){
+ case 0x5: return Opush;
+ }
+ break;
+ case 0x7: return Orst;
+ }
+ }else{
+ if((b&0xc0) == 0x40)
+ return Omov;
+ switch(b&0x0f){
+ case 0x00:
+ switch(b){
+ case 0x00: return Onop;
+ case 0x10: return Onop;
+ case 0x20: return Orim;
+ case 0x30: return Osim;
+ }
+ break;
+ case 0x01: return Olxi;
+ case 0x02:
+ switch((b>>5)&1){
+ case 0: return Ostax;
+ case 1:
+ switch(b){
+ case 0x22: return Oshld;
+ case 0x32: return Osta;
+ }
+ break;
+ }
+ break;
+ case 0x03: return Oinx;
+ case 0x07: return Orlc;
+ case 0x08: return Onop;
+ case 0x09: return Odad;
+ case 0x0a:
+ switch((b>>5)&1){
+ case 0: return Oldax;
+ case 1: return Olda;
+ }
+ break;
+ case 0x0b: return Odcx;
+ }
+ switch(b&0x07){
+ case 0x04: return Oinr;
+ case 0x05: return Odcr;
+ case 0x06: return Omvi;
+ }
+ }
+ return -1;
+}
+
+int
+decodeinsn(Insn *insn, uchar *mem, long len)
+{
+ if(len < 1)
+ return 0;
+ if(insn->op == -1)
+ return -1;
+ return insntypes[isa[insn->op].type].dec(insn, mem, len);
+}
+
+static int
+decode(Insn *insn, uchar *mem, long len)
+{
+ if(len < 1)
+ return 0;
+ insn->op = decodeop(mem[0]);
+ return decodeinsn(insn, mem, len);
+}
+
+int
+das(uchar *mem, long mlen)
+{
+ int n;
+ Insn insn;
+
+ if((n = decode(&insn, mem, mlen)) < 0)
+ return -1;
+ print("\t%I\n", &insn);
+ return n;
+}
+
+int
+dasfile(char *file)
+{
+ Biobuf *r;
+ Insn insn;
+ int buflen, n;
+ u16int addr;
+ uchar buf[1024];
+ uchar *bp;
+
+ r = Bopen(file, OREAD);
+ if(r == nil)
+ return -1;
+ addr = 0;
+ buflen = 0;
+ bp = buf;
+ for(;;){
+ memmove(buf, bp, buflen);
+ bp = buf;
+ n = Bread(r, buf + buflen, sizeof(buf) - buflen);
+ if(n < 0){
+ Bterm(r);
+ return -1;
+ }
+ if(n == 0){
+ Bterm(r);
+ break;
+ }
+ buflen += n;
+ while(buflen > 0){
+ n = decode(&insn, bp, buflen);
+ if(n == 0)
+ break;
+ if(n < 0){
+ print("%#.4ux\t???\t%#.2uhhx\n", addr, bp[0]);
+ addr++;
+ bp++;
+ buflen--;
+ }else{
+ print("%#.4ux\t%I\n", addr, &insn);
+ addr += n;
+ bp += n;
+ buflen -= n;
+ }
+ }
+ }
+ while(buflen > 0){
+ print("%#.4x\t???\t%#.2x\n", addr, buf[0]);
+ addr++;
+ bp++;
+ buflen--;
+ }
+ return 0;
+}
+
+void
+cpuexec(CPU *cpu, Insn *insn)
+{
+ if(isa[insn->op].exec == nil){
+ fprint(2, "%s (%#.2uhhx) not implemented!\n", opstr(insn->op), insn->op);
+ trap();
+ }
+ itrace(opstr(insn->op));
+ isa[insn->op].exec(cpu, insn);
+}
+
+static u16int
+rpair(CPU *cpu, u8int rp)
+{
+ switch(rp){
+ case BC: return cpu->r[B]<<8 | cpu->r[C];
+ case DE: return cpu->r[D]<<8 | cpu->r[E];
+ case HL: return cpu->r[H]<<8 | cpu->r[L];
+ }
+ fatal("unknown register pair %d", rp);
+ return 0;
+}
+
+static void
+wpair(CPU *cpu, u8int rp, u16int x)
+{
+ cpu->r[(rp<<1)+B] = x>>8;
+ cpu->r[(rp<<1)+B+1] = x;
+}
+
+static void
+Xnop(CPU*, Insn*)
+{
+}
+
+static void
+Xjmp(CPU *cpu, Insn *insn)
+{
+ cpu->PC = insn->addr;
+}
+
+static void
+Xlxi(CPU *cpu, Insn *insn)
+{
+ if(insn->rp == 3)
+ cpu->SP = insn->imm1<<8|insn->imm;
+ else
+ wpair(cpu, insn->rp, insn->imm1<<8|insn->imm);
+}
+
+static void
+Xmvi(CPU *cpu, Insn *insn)
+{
+ u16int addr;
+
+ if(insn->r1 == M){
+ addr = rpair(cpu, HL);
+ memwrite(addr, insn->imm);
+ }else{
+ cpu->r[insn->r1] = insn->imm;
+ }
+}
+
+static void
+Xcall(CPU *cpu, Insn *insn)
+{
+ push16(cpu, cpu->PC);
+ cpu->PC = insn->addr;
+}
+
+static void
+Xldax(CPU *cpu, Insn *insn)
+{
+ cpu->r[A] = memread(rpair(cpu, insn->rp));
+}
+
+static void
+Xmov(CPU *cpu, Insn *insn)
+{
+ if(insn->r2 == M && insn->r1 == M)
+ return;
+ if(insn->r2 == M)
+ cpu->r[insn->r1] = memread(rpair(cpu, HL));
+ else if(insn->r1 == M)
+ memwrite(rpair(cpu, HL), cpu->r[insn->r2]);
+ else
+ cpu->r[insn->r1] = cpu->r[insn->r2];
+}
+
+static void
+Xinx(CPU *cpu, Insn *insn)
+{
+ wpair(cpu, insn->rp, rpair(cpu, insn->rp) + 1);
+}
+
+static void
+Xdcr(CPU *cpu, Insn *insn)
+{
+ u16int a, x;
+
+ if(insn->r1 == M){
+ a = rpair(cpu, HL);
+ x = memread(a);
+ }else{
+ a = 0;
+ x = cpu->r[insn->r1];
+ }
+
+ if(--x == 0)
+ cpu->flg |= Fzero;
+ cpu->flg &= ~Fsign;
+ if((x&0x80) != 0)
+ cpu->flg |= Fsign;
+
+ if(insn->r1 == M)
+ memwrite(a, x);
+ else
+ cpu->r[insn->r1] = x;
+}
+
+static void
+Xret(CPU *cpu, Insn*)
+{
+ cpu->PC = pop16(cpu);
+}
+
+static void
+Xdad(CPU *cpu, Insn *insn)
+{
+ u32int x;
+
+ if(insn->rp == 3){
+ x = cpu->SP;
+ }else{
+ x = rpair(cpu, insn->rp);
+ }
+ x += rpair(cpu, HL);
+ if(x>>16 > 0)
+ cpu->flg |= Fcarry;
+ //else
+ //cpu->flg &= ~Fcarry;
+ wpair(cpu, HL, x);
+}
+
+static void
+Xsta(CPU *cpu, Insn *insn)
+{
+ memwrite(insn->addr, cpu->r[A]);
+}
+
+static void
+Xxra(CPU *cpu, Insn *insn)
+{
+ u8int x;
+
+ if(insn->r1 == M)
+ x = memread(rpair(cpu, HL));
+ else
+ x = cpu->r[insn->r1];
+
+ cpu->r[A] ^= x;
+
+ if(cpu->r[A] == 0)
+ cpu->flg |= Fzero;
+ else
+ cpu->flg &= ~Fzero;
+
+ if((cpu->r[A] & 0x80) != 0)
+ cpu->flg |= Fsign;
+ else
+ cpu->flg &= ~Fsign;
+
+ cpu->flg &= ~(Fcarry|Fhcarry);
+}
+
+void
+iow(u16int a, u8int v)
+{
+}
+
+static void
+Xout(CPU *cpu, Insn *insn)
+{
+ iow(insn->imm<<8|insn->imm, cpu->r[A]);
+}
+
+static void
+Xora(CPU *cpu, Insn *insn)
+{
+ u8int x;
+
+ if(insn->r1 == M)
+ x = memread(rpair(cpu, HL));
+ else
+ x = cpu->r[insn->r1];
+
+ cpu->r[A] |= x;
+
+ if(cpu->r[A] == 0)
+ cpu->flg |= Fzero;
+ else
+ cpu->flg &= ~Fzero;
+
+ if((cpu->r[A] & 0x80) != 0)
+ cpu->flg |= Fsign;
+ else
+ cpu->flg &= ~Fsign;
+
+ cpu->flg &= ~(Fcarry|Fhcarry);
+}
+
+static void
+Xlda(CPU *cpu, Insn *insn)
+{
+ cpu->r[A] = memread(insn->addr);
+}
+
+static void
+Xana(CPU *cpu, Insn *insn)
+{
+ u8int x;
+
+ if(insn->r1 == M)
+ x = memread(rpair(cpu, HL));
+ else
+ x = cpu->r[insn->r1];
+
+ cpu->r[A] &= x;
+
+ if(cpu->r[A] == 0)
+ cpu->flg |= Fzero;
+ else
+ cpu->flg &= ~Fzero;
+
+ if((cpu->r[A] & 0x80) != 0)
+ cpu->flg |= Fsign;
+ else
+ cpu->flg &= ~Fsign;
+
+ cpu->flg &= ~(Fcarry|Fhcarry);
+}
+
+static void
+Xpush(CPU *cpu, Insn *insn)
+{
+ if(insn->rp == 3){
+ push8(cpu, cpu->r[A]);
+ push8(cpu, cpu->flg);
+ }else
+ push16(cpu, rpair(cpu, insn->rp));
+}
+
+static void
+Xpop(CPU *cpu, Insn *insn)
+{
+ if(insn->rp == 3){
+ cpu->flg = pop8(cpu);
+ cpu->r[A] = pop8(cpu);
+ }else
+ wpair(cpu, insn->rp, pop16(cpu));
+}
+
+static void
+Xxchg(CPU *cpu, Insn*)
+{
+ u16int x;
+
+ x = rpair(cpu, HL);
+ wpair(cpu, HL, rpair(cpu, DE));
+ wpair(cpu, DE, x);
+}
+
+static void
+Xinr(CPU *cpu, Insn *insn)
+{
+ u8int x;
+ u16int a;
+
+ if(insn->r1 == M){
+ a = memread(rpair(cpu, HL));
+ x = memread(a) + 1;
+ memwrite(a, x);
+ }else{
+ x = cpu->r[insn->r1] + 1;
+ cpu->r[insn->r1] = x;
+ }
+
+ if(x == 0)
+ cpu->flg |= Fzero;
+ else
+ cpu->flg &= ~Fzero;
+
+ if((x & 0x80) != 0)
+ cpu->flg |= Fsign;
+ else
+ cpu->flg &= ~Fsign;
+
+ cpu->flg &= ~Fhcarry;
+}
+
+static void
+Xani(CPU *cpu, Insn *insn)
+{
+ cpu->r[A] &= insn->imm;
+
+ if(cpu->r[A] == 0)
+ cpu->flg |= Fzero;
+ else
+ cpu->flg &= ~Fzero;
+
+ if((cpu->r[A] & 0x80) != 0)
+ cpu->flg |= Fsign;
+ else
+ cpu->flg &= ~Fsign;
+
+ cpu->flg &= ~(Fcarry|Fhcarry);
+}
+
+static void
+Xrar(CPU *cpu, Insn*)
+{
+ u8int ocarry;
+
+ ocarry = (cpu->flg&Fcarry) != 0;
+ if((cpu->r[A]&1) != 0)
+ cpu->flg |= Fcarry;
+ else
+ cpu->flg &= ~Fcarry;
+ cpu->r[A] = ocarry<<7|((cpu->r[A]>>1)&0x7f);
+}
+
+static void
+Xori(CPU *cpu, Insn *insn)
+{
+ cpu->r[A] |= insn->imm;
+
+ if(cpu->r[A] == 0)
+ cpu->flg |= Fzero;
+ else
+ cpu->flg &= ~Fzero;
+
+ if((cpu->r[A] & 0x80) != 0)
+ cpu->flg |= Fsign;
+ else
+ cpu->flg &= ~Fsign;
+
+ cpu->flg &= ~(Fcarry|Fhcarry);
+}
+
+static void
+Xcmp(CPU *cpu, Insn *insn)
+{
+ if(cpu->r[A] == insn->r1)
+ cpu->flg |= Fzero;
+ else{
+ cpu->flg &= ~Fzero;
+ if(cpu->r[A] < insn->r1)
+ cpu->flg |= Fcarry;
+ else
+ cpu->flg &= ~Fcarry;
+ }
+}
+
+static void
+Xrlc(CPU *cpu, Insn*)
+{
+ u8int ncarry;
+
+ ncarry = (cpu->r[A]&0x80) != 0;
+ if(ncarry != 0)
+ cpu->flg |= Fcarry;
+ else
+ cpu->flg &= ~Fcarry;
+ cpu->r[A] = ((cpu->r[A]<<1)&0xfe)|ncarry;
+}
+
+static void
+Xrrc(CPU *cpu, Insn*)
+{
+ u8int ncarry;
+
+ ncarry = cpu->r[A]&1;
+ if(ncarry != 0)
+ cpu->flg |= Fcarry;
+ else
+ cpu->flg &= ~Fcarry;
+ cpu->r[A] = ncarry<<7|((cpu->r[A]>>1)&0x7f);
+}
+
+static void
+Xdcx(CPU *cpu, Insn *insn)
+{
+ if(insn->rp == 3)
+ cpu->SP--;
+ else
+ wpair(cpu, insn->rp, rpair(cpu, insn->rp) - 1);
+}
+
+static void
+Xstax(CPU *cpu, Insn *insn)
+{
+ memwrite(rpair(cpu, insn->rp), cpu->r[A]);
+}
+
+static void
+Xcpi(CPU *cpu, Insn *insn)
+{
+ if(cpu->r[A] == insn->imm)
+ cpu->flg |= Fzero;
+ else{
+ cpu->flg &= ~Fzero;
+ if(cpu->r[A] < insn->imm)
+ cpu->flg |= Fcarry;
+ else
+ cpu->flg &= ~Fcarry;
+ }
+}
+
+static void
+psz(CPU *cpu, int f)
+{
+ u8int x, p;
+
+ if(cpu->r[A] == 0){
+ if(f & Fzero) cpu->flg |= Fzero;
+ if(f & Fsign) cpu->flg &= ~Fsign;
+ }else{
+ if(f & Fzero) cpu->flg &= ~Fzero;
+ if((cpu->r[A] & 0x80) != 0)
+ if(f & Fsign) cpu->flg |= Fsign;
+ }
+
+ if(f & Fparity){
+ x = cpu->r[A];
+ p = 0;
+ p += (x&1); x >>= 1;
+ p += (x&1); x >>= 1;
+ p += (x&1); x >>= 1;
+ p += (x&1); x >>= 1;
+ p += (x&1); x >>= 1;
+ p += (x&1); x >>= 1;
+ p += (x&1); x >>= 1;
+ p += (x&1);
+ if((p & 1) != 0)
+ cpu->flg |= Fparity;
+ else
+ cpu->flg &= ~Fparity;
+ }
+}
+
+static void
+Xadi(CPU *cpu, Insn *insn)
+{
+ u16int x;
+
+ x = cpu->r[A] + insn->imm;
+ if((x>>8) > 0)
+ cpu->flg |= Fcarry;
+ else
+ cpu->flg &= ~Fcarry;
+ cpu->r[A] = x;
+ psz(cpu, Fparity|Fsign|Fzero);
+}
+
+static void
+Xei(CPU *cpu, Insn*)
+{
+ cpu->intr |= Ienabled;
+}
+
+static void
+Xdi(CPU *cpu, Insn*)
+{
+ cpu->intr &= ~Ienabled;
+}
+
+static void
+Xin(CPU *cpu, Insn*)
+{
+ cpu->r[A] = 0;
+}
+
+static void
+Xjc(CPU *cpu, Insn *insn)
+{
+ if((cpu->flg&Fcarry) != 0)
+ cpu->PC = insn->addr;
+}
+
+static void
+Xjz(CPU *cpu, Insn *insn)
+{
+ if((cpu->flg&Fzero) != 0)
+ cpu->PC = insn->addr;
+}
+
+static void
+Xjnc(CPU *cpu, Insn *insn)
+{
+ if((cpu->flg&Fcarry) == 0)
+ cpu->PC = insn->addr;
+}
+
+static void
+Xjnz(CPU *cpu, Insn *insn)
+{
+ if((cpu->flg&Fzero) == 0)
+ cpu->PC = insn->addr;
+}
+
+static void
+Xrc(CPU *cpu, Insn*)
+{
+ if((cpu->flg&Fcarry) != 0)
+ cpu->PC = pop16(cpu);
+}
+
+static void
+Xrnc(CPU *cpu, Insn*)
+{
+ if((cpu->flg&Fcarry) == 0)
+ cpu->PC = pop16(cpu);
+}
+
+static void
+Xrz(CPU *cpu, Insn*)
+{
+ if((cpu->flg&Fzero) != 0)
+ cpu->PC = pop16(cpu);
+}
+
+static void
+Xrnz(CPU *cpu, Insn*)
+{
+ if((cpu->flg&Fzero) == 0)
+ cpu->PC = pop16(cpu);
+}
+
+static void
+Xsui(CPU *cpu, Insn *insn)
+{
+ u8int a, b;
+ u16int x;
+
+ a = cpu->r[A];
+ b = -insn->imm;
+ if((((a&0xf)+(b&0xf))&0x10) != 0)
+ cpu->flg |= Fhcarry;
+ else
+ cpu->flg &= Fhcarry;
+ x = a + b;
+ if((x&0x100) != 0)
+ cpu->flg &= ~Fcarry;
+ else
+ cpu->flg |= Fcarry;
+ cpu->r[A] = x;
+ psz(cpu, Fparity|Fsign|Fzero);
+}
+
+static void
+Xxthl(CPU *cpu, Insn*)
+{
+ u8int x;
+
+ x = memread(cpu->SP+0);
+ memwrite(cpu->SP+0, cpu->r[L]);
+ cpu->r[L] = x;
+ x = memread(cpu->SP+1);
+ memwrite(cpu->SP+1, cpu->r[H]);
+ cpu->r[H] = x;
+}
+
+static void
+Xpchl(CPU *cpu, Insn*)
+{
+ cpu->PC = rpair(cpu, HL);
+}
+
+static void
+Xcz(CPU *cpu, Insn *insn)
+{
+ if((cpu->flg&Fzero) != 0){
+ push16(cpu, cpu->PC);
+ cpu->PC = insn->addr;
+ }
+}
+
+static void
+Xdaa(CPU *cpu, Insn*)
+{
+ u16int x;
+
+ if((cpu->flg&Fhcarry) != 0 || cpu->r[A] > 9){
+ x = (cpu->r[A]&0xf)+6;
+ if(x>>4 > 0)
+ cpu->flg |= Fhcarry;
+ else
+ cpu->flg &= ~Fhcarry;
+ cpu->r[A] = (cpu->r[A]&0xf0)|(x&0x0f);
+ }
+
+ if((cpu->flg&Fcarry) != 0 || (cpu->r[A]>>4) > 9){
+ x = (cpu->r[A]>>4)+6;
+ if(x>>4 > 0)
+ cpu->flg |= Fcarry;
+ else
+ cpu->flg &= ~Fcarry;
+ cpu->r[A] = (x<<4)|(cpu->r[A]&0xf);
+ }
+}
+
+static void
+Xjm(CPU *cpu, Insn *insn)
+{
+ if((cpu->flg&Fsign) != 0)
+ cpu->PC = insn->addr;
+}
+
+static void
+Xsbi(CPU *cpu, Insn *insn)
+{
+ insn->imm = -insn->imm;
+ Xadi(cpu, insn);
+}
+
+static void
+Xshld(CPU *cpu, Insn *insn)
+{
+ memwrite(insn->addr+0, cpu->r[L]);
+ memwrite(insn->addr+1, cpu->r[H]);
+}
--- /dev/null
+++ b/dat.h
@@ -1,0 +1,202 @@
+typedef struct CPU CPU;
+typedef struct Insn Insn;
+typedef struct ISA ISA;
+typedef struct InsnType InsnType;
+
+struct CPU
+{
+ u8int flg;
+ u8int r[8];
+ u16int SP;
+ u16int PC;
+ u8int intr;
+};
+
+enum{
+ B,
+ C,
+ D,
+ E,
+ H,
+ L,
+ M, /* dummy */
+ A,
+};
+
+enum{
+ BC,
+ DE,
+ HL,
+};
+
+enum{
+ Fcarry = 1<<0,
+ Fparity = 1<<2,
+ Fhcarry = 1<<4,
+ Fzero = 1<<6,
+ Fsign = 1<<7,
+};
+
+enum{
+ Imask = 7<<0,
+ Ienabled = 1<<3,
+ Ipending = 7<<4,
+};
+
+struct Insn
+{
+ u16int pc;
+ s8int op;
+ u8int r1;
+ u8int r2;
+ u8int rp;
+ u16int addr;
+ u8int imm;
+ u8int imm1;
+};
+
+enum{
+ Oadc,
+ Oadd,
+ Oadi,
+ Oana,
+ Oani,
+ Ocall,
+ Ocm,
+ Ocma,
+ Ocmc,
+ Ocmp,
+ Ocnc,
+ Ocpe,
+ Ocpi,
+ Ocz,
+ Odaa,
+ Odad,
+ Odcr,
+ Odcx,
+ Odi,
+ Oei,
+ Oin,
+ Oinr,
+ Oinx,
+ Ojc,
+ Ojm,
+ Ojmp,
+ Ojnc,
+ Ojnz,
+ Ojp,
+ Ojpe,
+ Ojpo,
+ Ojz,
+ Olda,
+ Oldax,
+ Olxi,
+ Omov,
+ Omvi,
+ Onop,
+ Oora,
+ Oori,
+ Oout,
+ Opchl,
+ Opop,
+ Opush,
+ Orar,
+ Orc,
+ Oret,
+ Orim,
+ Orlc,
+ Orm,
+ Ornc,
+ Ornz,
+ Orp,
+ Orpo,
+ Orrc,
+ Orst,
+ Orz,
+ Osbb,
+ Osbi,
+ Oshld,
+ Osim,
+ Osta,
+ Ostax,
+ Osub,
+ Osui,
+ Oxchg,
+ Oxra,
+ Oxri,
+ Oxthl,
+};
+
+enum
+{
+ T0,
+ Taddr,
+ Timm,
+ Tr012,
+ Tr345,
+ Trimm,
+ Trp,
+ Trpimm,
+ Trr,
+};
+
+struct ISA
+{
+ char *opstr;
+ int type;
+ void (*exec)(CPU*, Insn*);
+};
+
+struct InsnType
+{
+ int len;
+ int (*das)(Fmt*, Insn*);
+ int (*dec)(Insn*, uchar*, long);
+};
+
+enum{
+ ROMSZ = 8*1024,
+ RAMSZ = 1*1024,
+ VIDSZ = 7*1024,
+ MEMSZ = ROMSZ+RAMSZ+VIDSZ,
+};
+
+extern u8int mem[MEMSZ];
+extern u8int *rom;
+extern u8int *ram;
+extern u8int *vid;
+
+enum
+{
+ Tpush,
+ Tpop,
+};
+
+typedef struct TraceOp TraceOp;
+struct TraceOp
+{
+ u16int addr;
+ uchar op;
+};
+
+typedef struct BrkPt BrkPt;
+struct BrkPt
+{
+ u16int addr;
+ uchar enabled;
+};
+
+enum{
+ MAXBRKPTS = 10,
+ MAXTRACEOPS = 10,
+};
+
+extern CPU ocpu, cpu;
+extern Insn insn;
+extern int debug;
+extern int tracing;
+extern int ntraceops;
+extern TraceOp traceops[MAXTRACEOPS];
+extern int nbrkpts;
+extern BrkPt brkpts[MAXBRKPTS];
+extern jmp_buf trapjmp;
--- /dev/null
+++ b/debug.c
@@ -1,0 +1,139 @@
+#include <u.h>
+#include <libc.h>
+#include "dat.h"
+#include "fns.h"
+
+jmp_buf trapjmp;
+
+static void
+deltrap(void *u, char *msg)
+{
+ if(strcmp(msg, "interrupt") == 0){
+ notejmp(u, trapjmp, 1);
+ noted(NCONT);
+ }
+ noted(NDFLT);
+}
+
+void
+trapinit(void)
+{
+ static int init = 0;
+ if(init == 0){
+ notify(deltrap);
+ init++;
+ }
+}
+
+void
+trap(void)
+{
+ longjmp(trapjmp, 1);
+}
+
+char*
+rnam(u8int r)
+{
+ switch(r){
+ case B: return "B";
+ case C: return "C";
+ case D: return "D";
+ case E: return "E";
+ case H: return "H";
+ case L: return "L";
+ case M: return "M";
+ case A: return "A";
+ }
+ return "X";
+}
+
+char*
+rpnam(u8int r)
+{
+ switch(r){
+ case BC: return "BC";
+ case DE: return "DE";
+ case HL: return "HL";
+ }
+ return "XX";
+}
+
+void
+dumpinst(void)
+{
+ fprint(2, "op: %#.2x [%#.2x %#.2x]\n",
+ mem[insn.pc+0], mem[insn.pc+1], mem[insn.pc+2]);
+}
+
+static char
+flagchar(int f)
+{
+ switch(1<<f){
+ case Fcarry: return 'C';
+ case Fparity: return 'P';
+ case Fhcarry: return 'H';
+ case Fzero: return 'Z';
+ case Fsign: return 'S';
+ }
+ return 0;
+}
+
+void
+dumpregs(void)
+{
+ int i;
+
+ fprint(2, "A=%#.2x\n", cpu.r[A]);
+ fprint(2, "B=%#.2x\n", cpu.r[B]);
+ fprint(2, "C=%#.2x\n", cpu.r[C]);
+ fprint(2, "D=%#.2x\n", cpu.r[D]);
+ fprint(2, "E=%#.2x\n", cpu.r[E]);
+ fprint(2, "H=%#.2x\n", cpu.r[H]);
+ fprint(2, "L=%#.2x\n", cpu.r[L]);
+ fprint(2, "F=%#.2x", cpu.flg);
+ if(cpu.flg != 0){
+ fprint(2, " (");
+ for(i = 0; i < 8; i++)
+ if((cpu.flg&1<<i) != 0)
+ fprint(2, "%c", flagchar(i));
+ fprint(2, ")");
+ }
+ fprint(2, "\n");
+ fprint(2, "PC=%#.4x\n", cpu.PC);
+ fprint(2, "SP=%#.4x\n", cpu.SP);
+}
+
+void
+dumpmem(u16int s, u16int e)
+{
+ while(s < e){
+ fprint(2, "%.4x: %.2x\n", s, mem[s]);
+ s++;
+ }
+}
+
+void
+itrace0(char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ fprint(2, "%#.4x ", insn.pc);
+ vfprint(2, fmt, args);
+ fprint(2, "\n");
+ va_end(args);
+}
+
+void
+fatal(char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ vfprint(2, fmt, args);
+ fprint(2, "\n");
+ va_end(args);
+ dumpinst();
+ dumpregs();
+ exits("fatal");
+}
--- /dev/null
+++ b/fns.h
@@ -1,0 +1,36 @@
+/* debug */
+void dumpregs(void);
+void dumpmem(u16int, u16int);
+void fatal(char *fmt, ...);
+void itrace0(char *fmt, ...);
+char* rnam(u8int);
+char* rpnam(u8int);
+
+#define dprint(...) if(debug)fprint(2, __VA_ARGS__)
+#define itrace(...) if(tracing>0)itrace0(__VA_ARGS__)
+
+/* disassembler */
+#pragma varargck type "I" Insn*
+int insnfmt(Fmt*);
+int das(uchar*, long);
+int dasfile(char*);
+
+/* isa */
+int decodeop(u8int);
+int decodeinsn(Insn*, uchar*, long);
+int insnlen(u8int);
+void cpuexec(CPU*, Insn*);
+
+/* traps */
+void trapinit(void);
+void trap(void);
+#define wastrap() setjmp(trapjmp)
+
+/* memory */
+u8int memread(u16int);
+void memwrite(u16int, u8int);
+u8int ifetch(CPU*);
+u8int pop8(CPU*);
+u16int pop16(CPU*);
+void push8(CPU*, u8int);
+void push16(CPU*, u16int);
--- /dev/null
+++ b/mem.c
@@ -1,0 +1,62 @@
+#include <u.h>
+#include <libc.h>
+#include "dat.h"
+#include "fns.h"
+
+u8int
+memread(u16int a)
+{
+ if(a >= MEMSZ){
+ fprint(2, "memread failed addr=%#.4x op=%#0.2x pc=%#.4x\n", a, insn.op, ocpu.PC);
+ trap();
+ }
+ return mem[a];
+}
+
+void
+memwrite(u16int a, u8int x)
+{
+ if(a < ROMSZ || a >= MEMSZ){
+ fprint(2, "write failed addr=%#.4x op=%#0.2x pc=%#.4x\n", a, insn.op, ocpu.PC);
+ trap();
+ }
+ mem[a] = x;
+}
+
+u8int
+ifetch(CPU *cpu)
+{
+ if(cpu->PC >= ROMSZ){
+ fprint(2, "ifetch failed pc=%#.4x\n", cpu->PC);
+ trap();
+ }
+ return memread(cpu->PC++);
+}
+
+u8int
+pop8(CPU *cpu)
+{
+ return memread(cpu->SP++);
+}
+
+u16int
+pop16(CPU *cpu)
+{
+ u16int x;
+
+ x = memread(cpu->SP++);
+ return x | memread(cpu->SP++)<<8;
+}
+
+void
+push8(CPU *cpu, u8int x)
+{
+ memwrite(--cpu->SP, x);
+}
+
+void
+push16(CPU *cpu, u16int x)
+{
+ memwrite(--cpu->SP, x>>8);
+ memwrite(--cpu->SP, x&0xff);
+}
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,14 @@
+</$objtype/mkfile
+
+TARG=8080
+OFILES=\
+ 8080.$O\
+ mem.$O\
+ debug.$O\
+ das.$O\
+
+HFILES=\
+ dat.h\
+ fns.h\
+
+</sys/src/cmd/mkone
--- /dev/null
+++ b/screen.c
@@ -1,0 +1,98 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <thread.h>
+
+enum{
+ Width = 224,
+ Height = 256,
+};
+
+uchar videomem[Width*Height/8];
+
+static void
+usage(void)
+{
+ fprint(2, "usage: %s\n", argv0);
+ exits("usage");
+}
+
+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(Channel *c, uchar *vmem)
+{
+ int i;
+ uchar *p;
+ Image *line;
+ Rectangle r;
+
+ line = allocimage(display, Rect(0,0,Width,1), GREY1, 0, DNofill);
+
+ for(;;){
+ p = vmem;
+ r.min = screen->r.min;
+ r.max = Pt(screen->r.max.x, screen->r.min.y+1);
+ 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);
+ if(c != nil)
+ nbsendul(c, 0);
+ 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);
+ if(c != nil)
+ nbsendul(c, 1);
+ }
+}
+
+static void
+initvmem(void)
+{
+ uchar *p;
+ int i;
+
+ p = videomem;
+ srand(time(nil));
+ for(i = 0; i < nelem(videomem); i++)
+ *p++ = rand();
+}
+
+void
+threadmain(int argc, char **argv)
+{
+ ARGBEGIN{
+ 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");
+ draw(screen, screen->r, display->black, nil, ZP);
+ flushimage(display, 1);
+ initvmem();
+ scanout(nil, videomem);
+ for(;;)
+ sleep(1000);
+}
--- /dev/null
+++ b/test.rc
@@ -1,0 +1,2 @@
+#!/bin/rc
+mk && {echo load; echo run} | 6.out