ref: 6ca6987e90f6757a354c0be220a4bd6c9e47d64a
dir: /8080.c/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>
#include "dat.h"
#include "fns.h"
Biobuf *stdin;
Biobuf *stdout;
Biobuf *stderr;
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] [-i script] [-t addr] [-T addr]\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 && 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:
exits(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;
}
void
main(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();
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:
exits(0);
}
}
}