shithub: 8080

ref: df6478340d048ba76ab8e96aaaf490930a778eae
dir: /das.c/

View raw version
#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]);
}