File:  [Isaki's NoNo m68k/m88k emulator] / nono / hd64180 / hd64180ops.cpp
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:05:34 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v027, v026, v025, v024, v023, v022, v021, HEAD
nono 1.1.0

#include "hd64180acc.h"

#define ACC (*(hd64180acc*)&reg.f)

// LDIR, LDDR のリピート系命令の雛形。
// いずれも OP(name) を実行して BC == 0 になるまでこの PC を繰り返すもの。
// ジャンプする際には 2クロック追加で消費する。
// フラグも OP(name) が変更した以上にはここでは変更しない。
#define REPEAT_LD(name)	do {	\
	OP_FUNC(name);	\
	if (reg.f.IsV()) {	\
		reg.pc -= 2;	\
		CYCLE(2);	\
	}	\
} while (0)

// INIR, INDR, OTIR, OTDR 用。
#define REPEAT_IO(name)	do {	\
	OP_FUNC(name);	\
	if (reg.f.IsZ() == false) {	\
		reg.pc -= 2;	\
		CYCLE(2);	\
	}	\
} while (0)

// CPIR, CPDR 用。
#define REPEAT_CP(name)	do {	\
	OP_FUNC(name);	\
	if (reg.f.IsZ() == false && reg.f.IsV()) {	\
		reg.pc -= 2;	\
		CYCLE(2);	\
	}	\
} while (0)

void
MPU64180Device::Push2(uint32 data)
{
	reg.sp -= 2;
	Write2(reg.sp, data);
}

uint32
MPU64180Device::Pop2()
{
	uint16 data = Read2(reg.sp);
	reg.sp += 2;
	return data;
}

// HL (もしくは IX/IY) の値を取得する。
uint32
MPU64180Device::GetIHL() const
{
	switch (ixiy) {
	 case USE_HL:	return reg.GetHL();	break;
	 case USE_IX:	return reg.ix;		break;
	 case USE_IY:	return reg.iy;		break;
	 default:
		PANIC("invalid ixiy = %u", (uint)ixiy);
	}
}

// HL (もしくは IX/IY) に値を代入する。
void
MPU64180Device::SetIHL(uint32 data)
{
	switch (ixiy) {
	 case USE_HL:	reg.SetHL(data);	break;
	 case USE_IX:	reg.ix = data;		break;
	 case USE_IY:	reg.iy = data;		break;
	 default:
		PANIC("invalid ixiy = %u", (uint)ixiy);
	}
}

// (HL) 用に HL のアドレスを取得する。
// IX/IY の時は (IX/IY + d) のアドレスを取得する。
uint32
MPU64180Device::LeaIHL()
{
	uint32 addr = GetIHL();
	if (ixiy != USE_HL) {
		// DD と DD CB で +d をフェッチする順序が違う。
		if ((int32)ixd < 0) {
			ixd = Fetch1();
		}
		addr += (int32)(int8)ixd;
	}
	return addr;
}

// ww (BC, DE, HL, SP) の値を取得する。
// ixiy なら HL の代わりに IX/IY の値を取得する。
uint32
MPU64180Device::GetWW(uint ww) const
{
	switch (ww) {
	 case 0:	return reg.GetBC();
	 case 1:	return reg.GetDE();
	 case 2:	return GetIHL();
	 case 3:	return reg.sp;
	 default:
		PANIC("invalid ww = %u", ww);
	}
}

// ww (BC, DE, HL, SP) に値を代入する。
// ixiy なら HL の代わりに IX/IY に値を取得する。
void
MPU64180Device::SetWW(uint ww, uint32 data)
{
	switch (ww) {
	 case 0:	reg.SetBC(data);	break;
	 case 1:	reg.SetDE(data);	break;
	 case 2:	SetIHL(data);		break;
	 case 3:	reg.sp = data;		break;
	 default:
		PANIC("invalid ww = %u", ww);
	}
}


// ここから命令

// 00000000: 01R:	NOP
OP_DEF(nop)
{
	CYCLE(3);
}

//    00ww0001: 01R:	LD ww,nn
// DD:00100001: 01R:	LD IX,nn
OP_DEF(ld_ww_nn)
{
	uint32 nn = Fetch2();
	uint ww = (op >> 4) & 3;
	SetWW(ww, nn);
	CYCLE_IX(9, 12);
}

// 00ww0010: 01R:	LD (ww),A
OP_DEF(ld_wwin_a)
{
	uint ww = op >> 4;
	uint32 addr = GetWW(ww);	// ww は BC, DE のみ
	Write1(addr, reg.a);
	CYCLE_IX(7, 15);
}

//    00ww0011: 01R:	INC ww
// DD:00100011: 01R:	INC IX
OP_DEF(inc_ww)
{
	uint ww = op >> 4;
	uint32 data = GetWW(ww);
	data++;
	SetWW(ww, data);
	CYCLE_IX(4, 7);
}

// 00rrr100: 01R:	INC r
OP_DEF(inc_r)
{
	uint r = op >> 3;
	reg.r[r] = ACC.inc_8(reg.r[r]);
	CYCLE(4);
}

// 00rrr101: 01R:	DEC r
OP_DEF(dec_r)
{
	uint r = op >> 3;
	reg.r[r] = ACC.dec_8(reg.r[r]);
	CYCLE(4);
}

// 00rrr110: 01R:	LD r,n
OP_DEF(ld_r_n)
{
	uint r = op >> 3;
	reg.r[r] = Fetch1();
	CYCLE(6);
}

// 00000111: 01R:	RLCA
OP_DEF(rlca)
{
	reg.a = ACC.rlc_8(reg.a);
	CYCLE(3);
}

// 00001000: 01R:	EX AF,AF'
OP_DEF(ex_af_af)
{
	uint8 tmpa = reg.a;
	uint8 tmpf = reg.f.Get();
	reg.a = reg.ex.a;
	reg.f.Set(reg.ex.f.Get());
	reg.ex.a = tmpa;
	reg.ex.f.Set(tmpf);
	CYCLE(4);
}

//    00ww1001: 01R:	ADD HL,ww
// DD:00ww1001: 01R:	ADD IX,ww
OP_DEF(add_hl_ww)
{
	uint ww = op >> 4;
	uint32 src = GetWW(ww);
	uint32 dst = GetIHL();
	dst = ACC.add_16(dst, src);
	SetIHL(dst);
	CYCLE_IX(7, 10);
}

// 00ww1010: 01R:	LD A,(ww)
OP_DEF(ld_a_wwin)
{
	uint ww = op >> 4;
	uint32 addr = GetWW(ww);	// ww は BC, DE のみ
	reg.a = Read1(addr);
	CYCLE(6);
}

//    00ww1011: 01R:	DEC ww
// DD:00101011: 01R:	DEC IX
OP_DEF(dec_ww)
{
	uint ww = op >> 4;
	uint32 data = GetWW(ww);
	data--;
	SetWW(ww, data);
	CYCLE_IX(4, 7);
}

// 00001111: 01R:	RRCA
OP_DEF(rrca)
{
	reg.a = ACC.rrc_8(reg.a);
	CYCLE(3);
}

// 00010000: 01R:	DJNZ n
OP_DEF(djnz)
{
	int8 n = Fetch1();
	reg.b--;
	if (reg.b != 0) {
		Jump(reg.pc + n);
		CYCLE(9);
	} else {
		CYCLE(7);
	}
}

// 00010111: 01R:	RLA
OP_DEF(rla)
{
	reg.a = ACC.rl_8(reg.a);
	CYCLE(3);
}

// 00011000: 01R:	JR n
OP_DEF(jr)
{
	int8 n = Fetch1();
	Jump(reg.pc + n);
	CYCLE(8);
}

// 00011111: 01R:	RRA
OP_DEF(rra)
{
	reg.a = ACC.rr_8(reg.a);
	CYCLE(3);
}

// 00100000: 01R:	JR NZ,n
OP_DEF(jr_nz)
{
	int8 n = Fetch1();
	if (reg.f.IsZ() == false) {
		Jump(reg.pc + n);
		CYCLE(8);
	} else {
		CYCLE(6);
	}
}

//    00100010: 01R:	LD (nn),HL
// DD:00100010: 01R:	LD (nn),IX
OP_DEF(ld_nnin_hl)
{
	uint32 nn = Fetch2();
	Write2(nn, GetIHL());
	CYCLE_IX(16, 19);
}

// 00100111: 01R:	DAA
OP_DEF(daa)
{
	reg.a = ACC.daa_8(reg.a);
	CYCLE(4);
}

// 00101000: 01R:	JR Z,n
OP_DEF(jr_z)
{
	int8 n = Fetch1();
	if (reg.f.IsZ()) {
		Jump(reg.pc + n);
		CYCLE(8);
	} else {
		CYCLE(6);
	}
}

//    00101010: 01R:	LD HL,(nn)
// DD:00101010: 01R:	LD IX,(nn)
OP_DEF(ld_hl_nnin)
{
	uint32 nn = Fetch2();
	uint32 src = Read2(nn);
	SetIHL(src);
	CYCLE_IX(15, 18);
}

// 00101111: 01R:	CPL
OP_DEF(cpl)
{
	reg.a = ~reg.a;
	reg.f.SetH(true);
	reg.f.SetN(true);
	CYCLE(3);
}

// 00110000: 01R:	JR NC,n
OP_DEF(jr_nc)
{
	int8 n = Fetch1();
	if (reg.f.IsC() == false) {
		Jump(reg.pc + n);
		CYCLE(8);
	} else {
		CYCLE(6);
	}
}

// 00110010: 01R:	LD (nn),A
OP_DEF(ld_nnin_a)
{
	uint32 addr = Fetch2();
	Write1(addr, reg.a);
	CYCLE(13);
}

//    00110100: 01R:	INC (HL)
// DD:00110100: 01R:	INC (IX+d)
OP_DEF(inc_hlin)
{
	uint32 addr = LeaIHL();
	uint32 src = Read1(addr);
	uint32 dst = ACC.inc_8(src);
	Write1(addr, dst);
	CYCLE_IX(10, 18);
}

//    00110101: 01R:	DEC (HL)
// DD:00110101: 01R:	DEC (IX+d)
OP_DEF(dec_hlin)
{
	uint32 addr = LeaIHL();
	uint32 src = Read1(addr);
	uint32 dst = ACC.dec_8(src);
	Write1(addr, dst);
	CYCLE_IX(10, 18);
}

//    00110110: 01R:	LD (HL),n
// DD:00110110: 01R:	LD (IX+d),n
OP_DEF(ld_hlin_n)
{
	uint32 addr = LeaIHL();
	uint32 src = Fetch1();
	Write1(addr, src);
	CYCLE_IX(9, 15);
}

// 00110111: 01R:	SCF
OP_DEF(scf)
{
	reg.f.SetC(true);
	reg.f.SetH(false);
	reg.f.SetN(false);
	CYCLE(3);
}

// 00111000: 01R:	JR C,n
OP_DEF(jr_c)
{
	int8 n = Fetch1();
	if (reg.f.IsC()) {
		Jump(reg.pc + n);
		CYCLE(8);
	} else {
		CYCLE(6);
	}
}

// 00111010: 01R:	LD A,(nn)
OP_DEF(ld_a_nnin)
{
	uint32 nn = Fetch2();
	reg.a = Read1(nn);
	CYCLE(12);
}

// 00111111: 01R:	CCF
OP_DEF(ccf)
{
	reg.f.SetC(!reg.f.IsC());
	reg.f.SetH(false);
	reg.f.SetN(false);
	CYCLE(3);
}

// 01rrrsss: 01R:	LD r,s
OP_DEF(ld_r_s)
{
	uint d = (op >> 3) & 7;
	uint s =  op & 7;
	reg.r[d] = reg.r[s];
	CYCLE(4);
}

//    01rrr110: 01R:	LD r,(HL)
// DD:01rrr110: 01R:	LD r,(IX+d)
OP_DEF(ld_r_hlin)
{
	uint d = (op >> 3) & 7;
	uint16 addr = LeaIHL();
	reg.r[d] = Read1(addr);
	CYCLE_IX(6, 14);
}

//    01110sss: 01R:	LD (HL),s
// DD:01110sss: 01R:	LD (IX+d),s
OP_DEF(ld_hlin_s)
{
	uint s = op & 7;
	uint32 addr = LeaIHL();
	Write1(addr, reg.r[s]);
	CYCLE_IX(7, 15);
}

// 01110110: 01R:	HALT
OP_DEF(halt)
{
	opmode = OpMode::Halt;
	putlog(1, "Halt");
	CYCLE(3);
}

// 10000rrr: 01R:	ADD A,r
OP_DEF(add_a_r)
{
	uint r = op & 7;
	reg.a = ACC.add_8(reg.a, reg.r[r]);
	CYCLE(4);
}

//    10000110: 01R:	ADD A,(HL)
// DD:10000110: 01R:	ADD A,(IX+d)
OP_DEF(add_a_hlin)
{
	uint32 addr = LeaIHL();
	uint32 src = Read1(addr);
	reg.a = ACC.add_8(reg.a, src);
	CYCLE_IX(6, 14);
}

// 10001rrr: 01R:	ADC A,r
OP_DEF(adc_a_r)
{
	uint r = op & 7;
	reg.a = ACC.adc_8(reg.a, reg.r[r]);
	CYCLE(4);
}

//    10001110: 01R:	ADC A,(HL)
// DD:10001110: 01R:	ADC A,(IX+d)
OP_DEF(adc_a_hlin)
{
	uint32 addr = LeaIHL();
	uint32 src = Read1(addr);
	reg.a = ACC.adc_8(reg.a, src);
	CYCLE_IX(6, 14);
}

// 10010rrr: 01R:	SUB r
OP_DEF(sub_r)
{
	uint r = op & 7;
	reg.a = ACC.sub_8(reg.a, reg.r[r]);
	CYCLE(4);
}

//    10010110: 01R:	SUB (HL)
// DD:10010110: 01R:	SUB (IX+d)
OP_DEF(sub_hlin)
{
	uint32 addr = LeaIHL();
	uint32 src = Read1(addr);
	reg.a = ACC.sub_8(reg.a, src);
	CYCLE_IX(6, 14);
}

// 10011rrr: 01R:	SBC A,r
OP_DEF(sbc_a_r)
{
	uint r = op & 7;
	reg.a = ACC.sbc_8(reg.a, reg.r[r]);
	CYCLE(4);
}

//    10011110: 01R:	SBC A,(HL)
// DD:10011110: 01R:	SBC A,(IX+d)
OP_DEF(sbc_a_hlin)
{
	uint32 addr = LeaIHL();
	uint32 src = Read1(addr);
	reg.a = ACC.sbc_8(reg.a, src);
	CYCLE_IX(6, 14);
}

// 10100rrr: 01R:	AND r
OP_DEF(and_r)
{
	uint r = op & 7;
	reg.a = ACC.and_8(reg.a, reg.r[r]);
	CYCLE(4);
}

//    10100110: 01R:	AND (HL)
// DD:10100110: 01R:	AND (IX+d)
OP_DEF(and_hlin)
{
	uint16 addr = LeaIHL();
	uint32 src = Read1(addr);
	reg.a = ACC.and_8(reg.a, src);
	CYCLE_IX(6, 14);
}

// 10101rrr: 01R:	XOR r
OP_DEF(xor_r)
{
	uint r = op & 7;
	reg.a = ACC.xor_8(reg.a, reg.r[r]);
	CYCLE(4);
}

//    10101110: 01R:	XOR (HL)
// DD:10101110: 01R:	XOR (IX+d)
OP_DEF(xor_hlin)
{
	uint16 addr = LeaIHL();
	uint32 src = Read1(addr);
	reg.a = ACC.xor_8(reg.a, src);
	CYCLE_IX(6, 14);
}

// 10110rrr: 01R:	OR r
OP_DEF(or_r)
{
	uint r = op & 7;
	reg.a = ACC.or_8(reg.a, reg.r[r]);
	CYCLE(4);
}

//    10110110: 01R:	OR (HL)
// DD:10110110: 01R:	OR (IX+d)
OP_DEF(or_hlin)
{
	uint16 addr = LeaIHL();
	uint32 src = Read1(addr);
	reg.a = ACC.or_8(reg.a, src);
	CYCLE_IX(6, 14);
}

// 10111rrr: 01R:	CP r
OP_DEF(cp_r)
{
	uint r = op & 7;
	ACC.sub_8(reg.a, reg.r[r]);
	CYCLE(4);
}

//    10111110: 01R:	CP (HL)
// DD:10111110: 01R:	CP (IX+d)
OP_DEF(cp_hlin)
{
	uint16 addr = LeaIHL();
	uint32 src = Read1(addr);
	ACC.sub_8(reg.a, src);
	CYCLE_IX(6, 14);
}

void
MPU64180Device::ops_ret()
{
	uint16 addr = Pop2();
	Jump(addr);
}

// 11fff000: 01R:	RET f
OP_DEF(ret_f)
{
	uint fff = (op >> 3) & 7;
	if (reg.f.IsCond(fff)) {
		ops_ret();
		CYCLE(10);
	} else {
		CYCLE(5);
	}
}

//    11zz0001: 01R:	POP zz
// DD:11100001: 01R:	POP IX
OP_DEF(pop_zz)
{
	// ここでは zz のうち BC, DE, HL のみなので ww が使える
	uint zz = (op >> 4) & 3;
	uint16 data = Pop2();
	SetWW(zz, data);
	CYCLE_IX(9, 12);
}

// 11fff010: 01R:	JP f,nn
OP_DEF(jp_f_nn)
{
	uint fff = (op >> 3) & 7;
	uint16 addr = Fetch2();
	if (reg.f.IsCond(fff)) {
		Jump(addr);
		CYCLE(9);
	} else {
		CYCLE(6);
	}
}

// 11000011: 01R:	JP nn
OP_DEF(jp_nn)
{
	uint32 addr = Fetch2();
	Jump(addr);
	CYCLE(9);
}

// 11fff100: 01R:	CALL f,nn
OP_DEF(call_f_nn)
{
	uint fff = (op >> 3) & 7;
	uint16 nn = Fetch2();
	if (reg.f.IsCond(fff)) {
		Push2(reg.pc);
		Jump(nn);
		CYCLE(16);
	} else {
		CYCLE(6);
	}
}

//    11zz0101: 01R:	PUSH zz
// DD:11100101: 01R:	PUSH IX
OP_DEF(push_zz)
{
	// ここでは zz のうち BC, DE, HL のみなので ww が使える
	uint zz = (op >> 4) & 3;
	uint16 data = GetWW(zz);
	Push2(data);
	CYCLE_IX(11, 14);
}

// 11000110: 01R:	ADD A,n
OP_DEF(add_a_n)
{
	uint32 n = Fetch1();
	reg.a = ACC.add_8(reg.a, n);
	CYCLE(6);
}

// 11vvv111: 01R:	RST v
OP_DEF(rst)
{
	Push2(reg.pc);
	uint v = op & 0x38;
	Jump(v);
	CYCLE(11);
}

// 11001001: 01R:	RET
OP_DEF(ret)
{
	ops_ret();
	CYCLE(9);
}

// 11001011: 01R:	op_CB
OP_DEF(cb)
{
	// 2バイト目をフェッチ
	op = Fetch1();
	// で分岐
	switch (op) {
#include "hd64180switch_cb.inc"
	 default:
		op_illegal(2);
		break;
	}
}

// 11001101: 01R:	CALL nn
OP_DEF(call)
{
	uint16 nn = Fetch2();
	Push2(reg.pc);
	Jump(nn);
	CYCLE(16);
}

// 11001110: 01R:	ADC A,n
OP_DEF(adc_a_n)
{
	uint32 n = Fetch1();
	reg.a = ACC.adc_8(reg.a, n);
	CYCLE(6);
}

// 11010011: 01R:	OUT (n),A
OP_DEF(out_n_a)
{
	uint32 n = Fetch1();
	// バスの上位には A が出る
	uint32 addr = (reg.a << 8) | n;
	WriteIO(addr, reg.a);
	CYCLE(10);
}

// 11010110: 01R:	SUB n
OP_DEF(sub_n)
{
	uint32 n = Fetch1();
	reg.a = ACC.sub_8(reg.a, n);
	CYCLE(6);
}

// 11011001: 01R:	EXX
OP_DEF(exx)
{
	uint8 tmpb = reg.b;
	uint8 tmpc = reg.c;
	uint8 tmpd = reg.d;
	uint8 tmpe = reg.e;
	uint8 tmph = reg.h;
	uint8 tmpl = reg.l;
	reg.b = reg.ex.b;
	reg.c = reg.ex.c;
	reg.d = reg.ex.d;
	reg.e = reg.ex.e;
	reg.h = reg.ex.h;
	reg.l = reg.ex.l;
	reg.ex.b = tmpb;
	reg.ex.c = tmpc;
	reg.ex.d = tmpd;
	reg.ex.e = tmpe;
	reg.ex.h = tmph;
	reg.ex.l = tmpl;
	CYCLE(3);
}

// 11011011: 01R:	IN A,(n)
OP_DEF(in_a_n)
{
	uint32 n = Fetch1();
	// バスの上位には A が出る
	uint32 addr = (reg.a << 8) | n;
	reg.a = ReadIO(addr);
	CYCLE(9);
}

// DD/FD の共通部
void
MPU64180Device::ops_ddfd(ixiy_t xy)
{
	ixiy = xy;

	// 2バイト目をフェッチ
	op = Fetch1();
	// で分岐
	switch (op) {
#include "hd64180switch_dd.inc"
	 default:
		op_illegal(2);
		break;
	}
}

// 11011101: 01R:	op_DD
OP_DEF(dd)
{
	ops_ddfd(USE_IX);
}

// 11011110: 01R:	SBC A,n
OP_DEF(sbc_a_n)
{
	uint32 n = Fetch1();
	reg.a = ACC.sbc_8(reg.a, n);
	CYCLE(6);
}

//    11100011: 01R:	EX (SP),HL
// DD:11100011: 01R:	EX (SP),IX
OP_DEF(ex_sp_hl)
{
	uint32 tmp = Read2(reg.sp);
	Write2(reg.sp, GetIHL());
	SetIHL(tmp);
	CYCLE_IX(16, 19);
}

// 11100110: 01R:	AND n
OP_DEF(and_n)
{
	uint32 src = Fetch1();
	reg.a = ACC.and_8(reg.a, src);
	CYCLE(6);
}

//    11101001: 01R:	JP (HL)
// DD:11101001: 01R:	JP (IX)
OP_DEF(jp_hl)
{
	Jump(GetIHL());
	CYCLE_IX(3, 6);
}

// 11101011: 01R:	EX DE,HL
OP_DEF(ex_de_hl)
{
	uint16 tmp = reg.GetDE();
	reg.SetDE(reg.GetHL());
	reg.SetHL(tmp);
	CYCLE(3);
}

// 11101101: 01R:	op_ED
OP_DEF(ed)
{
	op = Fetch1();

	switch (op) {
#include "hd64180switch_ed.inc"
	 default:
		op_illegal(2);
		break;
	}
}

// 11101110: 01R:	XOR n
OP_DEF(xor_n)
{
	uint32 src = Fetch1();
	reg.a = ACC.xor_8(reg.a, src);
	CYCLE(6);
}

// 11110001: 01R:	POP AF
OP_DEF(pop_af)
{
	uint16 data = Pop2();
	reg.a = data >> 8;
	reg.f.Set(data & 0xff);
	CYCLE(9);
}

// 11110011: 01R:	DI
OP_DEF(di)
{
	ief1 = false;
	ief2 = false;

	// DI 命令の直後は割り込みをサンプルしない。HD647180.pdf, p.205
	intcheck = false;

	CYCLE(3);
}

// 11110101: 01R:	PUSH AF
OP_DEF(push_af)
{
	uint16 data;
	data  = reg.a << 8;
	data |= reg.f.Get();
	Push2(data);
	CYCLE(11);
}

// 11110110: 01R:	OR n
OP_DEF(or_n)
{
	uint32 src = Fetch1();
	reg.a = ACC.or_8(reg.a, src);
	CYCLE(6);
}

//    11111001: 01R:	LD SP,HL
// DD:11111001: 01R:	LD SP,IX
OP_DEF(ld_sp_hl)
{
	reg.sp = GetIHL();
	CYCLE_IX(4, 7);
}

// 11111011: 01R:	EI
OP_DEF(ei)
{
	ief1 = true;
	ief2 = true;

	// EI 命令の直後は割り込みをサンプルしない。HD647180.pdf, p.205
	intcheck = false;

	CYCLE(3);
}

// 11111101: 01R:	op_FD
OP_DEF(fd)
{
	ops_ddfd(USE_IY);
}

// 11111110: 01R:	CP n
OP_DEF(cp_n)
{
	uint32 n = Fetch1();
	ACC.sub_8(reg.a, n);
	CYCLE(6);
}

// CB:00000rrr: 01R:	RLC r
OP_DEF(rlc_r)
{
	uint r = op & 7;
	reg.r[r] = ACC.in_8(ACC.rlc_8(reg.r[r]));
	CYCLE(7);
}

//    CB:00000110: 01R:	RLC (HL)
// DD_CB:00000110: 01R:	RLC (IX+d)
OP_DEF(rlc_hlin)
{
	uint32 addr = LeaIHL();
	uint32 src = Read1(addr);
	uint32 res = ACC.in_8(ACC.rlc_8(src));
	Write1(addr, res);
	CYCLE_IX(13, 19);
}

// CB:00001rrr: 01R:	RRC r
OP_DEF(rrc_r)
{
	uint r = op & 7;
	reg.r[r] = ACC.in_8(ACC.rrc_8(reg.r[r]));
	CYCLE(7);
}

//    CB:00001110: 01R:	RRC (HL)
// DD_CB:00001110: 01R:	RRC (IX+d)
OP_DEF(rrc_hlin)
{
	uint32 addr = LeaIHL();
	uint32 src = Read1(addr);
	uint32 res = ACC.in_8(ACC.rrc_8(src));
	Write1(addr, res);
	CYCLE_IX(13, 19);
}

// CB:00010rrr: 01R:	RL r
OP_DEF(rl_r)
{
	uint r = op & 7;
	reg.r[r] = ACC.in_8(ACC.rl_8(reg.r[r]));
	CYCLE(7);
}

//    CB:00010110: 01R:	RL (HL)
// DD_CB:00010110: 01R:	RL (IX+d)
OP_DEF(rl_hlin)
{
	uint32 addr = LeaIHL();
	uint32 src = Read1(addr);
	uint32 res = ACC.in_8(ACC.rl_8(src));
	Write1(addr, res);
	CYCLE_IX(13, 19);
}

// CB:00011rrr: 01R:	RR r
OP_DEF(rr_r)
{
	uint r = op & 7;
	reg.r[r] = ACC.in_8(ACC.rr_8(reg.r[r]));
	CYCLE(7);
}

//    CB:00011110: 01R:	RR (HL)
// DD_CB:00011110: 01R:	RR (IX+d)
OP_DEF(rr_hlin)
{
	uint32 addr = LeaIHL();
	uint32 src = Read1(addr);
	uint32 res = ACC.in_8(ACC.rr_8(src));
	Write1(addr, res);
	CYCLE_IX(13, 19);
}

// CB:00100rrr: 01R:	SLA r
OP_DEF(sla_r)
{
	uint r = op & 7;
	reg.r[r] = ACC.in_8(ACC.sla_8(reg.r[r]));
	CYCLE(7);
}

//    CB:00100110: 01R:	SLA (HL)
// DD_CB:00100110: 01R:	SLA (IX+d)
OP_DEF(sla_hlin)
{
	uint32 addr = LeaIHL();
	uint32 src = Read1(addr);
	uint32 res = ACC.in_8(ACC.sla_8(src));
	Write1(addr, res);
	CYCLE_IX(13, 19);
}

// CB:00101rrr: 01R:	SRA r
OP_DEF(sra_r)
{
	uint r = op & 7;
	reg.r[r] = ACC.in_8(ACC.sra_8(reg.r[r]));
	CYCLE(7);
}

//    CB:00101110: 01R:	SRA (HL)
// DD_CB:00101110: 01R:	SRA (IX+d)
OP_DEF(sra_hlin)
{
	uint32 addr = LeaIHL();
	uint32 src = Read1(addr);
	uint32 res = ACC.in_8(ACC.sra_8(src));
	Write1(addr, res);
	CYCLE_IX(13, 19);
}

// CB:00110rrr: Z--:	SLL
OP_DEF(sll_r)
{
	if (1) {
		op_illegal(2);
	} else {
		uint r = op & 7;
		reg.r[r] = ACC.in_8(ACC.sll_8(reg.r[r]));
		CYCLE(7);
	}
}

//    CB:00110110: Z--:	SLL (HL)
// DD_CB:00110110: Z--:	SLL (IX+d)
OP_DEF(sll_hlin)
{
	if (1) {
		if (ixiy == USE_HL) {
			op_illegal(2);
		} else {
			op_illegal(3);
		}
	} else {
		uint32 addr = LeaIHL();
		uint32 src = Read1(addr);
		uint32 res = ACC.in_8(ACC.sll_8(src));
		Write1(addr, res);
		CYCLE_IX(13, 19);
	}
}

// CB:00111rrr: 01R:	SRL r
OP_DEF(srl_r)
{
	uint r = op & 7;
	reg.r[r] = ACC.in_8(ACC.srl_8(reg.r[r]));
	CYCLE(7);
}

//    CB:00111110: 01R:	SRL (HL)
// DD_CB:00111110: 01R:	SRL (IX+d)
OP_DEF(srl_hlin)
{
	uint32 addr = LeaIHL();
	uint32 src = Read1(addr);
	uint32 res = ACC.in_8(ACC.srl_8(src));
	Write1(addr, res);
	CYCLE_IX(13, 19);
}

// CB:01bbbrrr: 01R:	BIT b,r
OP_DEF(bit_r)
{
	uint b = (op >> 3) & 7;
	uint r =  op & 7;
	ACC.bit_8(b, reg.r[r]);
	CYCLE(6);
}

//    CB:01bbb110: 01R:	BIT b,(HL)
// DD_CB:01bbb110: 01R:	BIT b,(IX+d)
OP_DEF(bit_hlin)
{
	uint b = (op >> 3) & 7;
	uint32 addr = LeaIHL();
	uint32 data = Read1(addr);
	ACC.bit_8(b, data);
	CYCLE_IX(9, 15);
}

// CB:10bbbrrr: 01R:	RES b,r
OP_DEF(res_r)
{
	uint b = (op >> 3) & 7;
	uint r =  op & 7;
	reg.r[r] &= ~(1U << b);
	CYCLE(7);
}

//    CB:10bbb110: 01R:	RES b,(HL)
// DD_CB:10bbb110: 01R:	RES b,(IX+d)
OP_DEF(res_hlin)
{
	uint b = (op >> 3) & 7;
	uint32 addr = LeaIHL();
	uint32 data = Read1(addr);
	data &= ~(1U << b);
	Write1(addr, data);
	CYCLE_IX(13, 19);
}

// CB:11bbbrrr: 01R:	SET b,r
OP_DEF(set_r)
{
	uint b = (op >> 3) & 7;
	uint r =  op & 7;
	reg.r[r] |= 1U << b;
	CYCLE(7);
}

//    CB:11bbb110: 01R:	SET b,(HL)
// DD_CB:11bbb110: 01R:	SET b,(IX+d)
OP_DEF(set_hlin)
{
	uint b = (op >> 3) & 7;
	uint32 addr = LeaIHL();
	uint32 data = Read1(addr);
	data |= 1U << b;
	Write1(addr, data);
	CYCLE_IX(13, 19);
}

// ED:00rrr000: -1-:	IN0 r,(n)
OP_DEF(in0_r_n)
{
	uint32 n = Fetch1();
	uint32 src = ReadIO(n);
	uint r = op >> 3;
	reg.r[r] = ACC.in_8(src);
	CYCLE(12);
}

// ED:00rrr001: -1-:	OUT0 (n),r
OP_DEF(out0_n_r)
{
	uint32 n = Fetch1();
	uint32 r = op >> 3;
	WriteIO(n, reg.r[r]);
	CYCLE(13);
}

// ED:00rrr100: -1-:	TST r
OP_DEF(tst_r)
{
	uint r = op & 7;
	ACC.tst_8(reg.a, reg.r[r]);
	CYCLE(7);
}

// ED:00110000: -1-:	IN0 F,(n)
OP_DEF(in0_f_n)
{
	uint32 n = Fetch1();
	uint32 src = ReadIO(n);
	ACC.in_8(src);
	CYCLE(12);
}

// ED:00110100: -1-:	TST (HL)
OP_DEF(tst_hlin)
{
	uint16 addr = reg.GetHL();
	uint32 src = Read1(addr);
	ACC.tst_8(reg.a, src);
	CYCLE(10);
}

// ED:01rrr000: 01R:	IN r,(C)
OP_DEF(in_r_c)
{
	uint r = (op >> 3) & 7;
	// バスの上位には B が出る
	uint32 addr = reg.GetBC();
	uint32 data = ReadIO(addr);
	reg.r[r] = ACC.in_8(data);
	CYCLE(9);
}

// ED:01rrr001: 01R:	OUT (C),r
OP_DEF(out_c_r)
{
	uint r = (op >> 3) & 7;
	// バスの上位には B が出る
	uint32 addr = reg.GetBC();
	WriteIO(addr, reg.r[r]);
	CYCLE(10);
}

// ED:01ww0010: 01R:	SBC HL,ww
OP_DEF(sbc_hl_ww)
{
	uint ww = (op >> 4) & 3;
	uint32 src = GetWW(ww);
	uint32 dst = reg.GetHL();
	dst = ACC.sbc_16(dst, src);
	reg.SetHL(dst);
	CYCLE(10);
}

// ED:01ww0011: 01R:	LD (nn),ww
OP_DEF(ld_nnin_ww)
{
	uint ww = (op >> 4) & 3;
	uint32 src = GetWW(ww);
	uint32 nn = Fetch2();
	Write2(nn, src);
	CYCLE(19);
}

// ED:01000100: 01R:	NEG
OP_DEF(neg)
{
	reg.a = ACC.sub_8(0, reg.a);
	CYCLE(6);
}

// ED:01000101: 01R:	RETN
OP_DEF(retn)
{
	ief1 = ief2;
	Jump(Pop2());
}

// ED:01000110: 01R:	IM 0
OP_DEF(im_0)
{
	int0mode = 0;
	putlog(1, "IM %u", int0mode);
	CYCLE(6);
}

// ED:01000111: 01R:	LD I,A
OP_DEF(ld_i_a)
{
	reg_i = reg.a;
	CYCLE(6);
}

// ED:01ww1010: 01R:	ADC HL,ww
OP_DEF(adc_hl_ww)
{
	uint ww = (op >> 4) & 3;
	uint32 src = GetWW(ww);
	uint32 dst = reg.GetHL();
	dst = ACC.adc_16(dst, src);
	reg.SetHL(dst);
	CYCLE(10);
}

// ED:01ww1011: 01R:	LD ww,(nn)
OP_DEF(ld_ww_nnin)
{
	uint ww = (op >> 4) & 3;
	uint32 nn = Fetch2();
	uint32 src = Read2(nn);
	SetWW(ww, src);
	CYCLE(18);
}

// ED:01ww1100: -1-:	MLT ww
OP_DEF(mlt)
{
	uint ww = (op >> 4) & 3;
	uint32 src = GetWW(ww);
	uint32 dst = (src >> 8) * (src & 0xff);
	SetWW(ww, dst);
	// フラグ変化なし
	CYCLE(17);
}

// ED:01001101: 01R:	RETI
OP_DEF(reti)
{
	ops_ret();
	CYCLE(12);
}

// ED:01001111: 01R:	LD R,A
OP_DEF(ld_r_a)
{
	reg_r = reg.a;
	CYCLE(6);
}

// ED:01010110: 01R:	IM 1
OP_DEF(im_1)
{
	int0mode = 1;
	putlog(1, "IM %u", int0mode);
	CYCLE(6);
}

// ED:01010111: 01R:	LD A,I
OP_DEF(ld_a_i)
{
	reg.a = ACC.ld_ir8(reg_i);

	// IEF2 を P/V にコピー。P でも V でもないので一応 V にしておく。
	reg.f.SetV(GetIEF2());

	// HD64180 ではこの命令の終わりで割り込みをサンプルしない。
	intcheck = false;

	CYCLE(6);
}

// ED:01011110: 01R:	IM 2
OP_DEF(im_2)
{
	int0mode = 2;
	putlog(1, "IM %u", int0mode);
	CYCLE(6);
}

// ED:01011111: 01R:	LD A,R
OP_DEF(ld_a_r)
{
	reg.a = ACC.ld_ir8(GetR());

	// IEF2 を P/V にコピー。P でも V でもないので一応 V にしておく。
	reg.f.SetV(GetIEF2());

	// HD64180 ではこの命令の終わりで割り込みをサンプルしない。
	intcheck = false;

	CYCLE(6);
}

// ED:01100100: -1-:	TST n
OP_DEF(tst_n)
{
	uint32 src = Fetch1();
	ACC.and_8(reg.a, src);
	CYCLE(9);
}

// ED:01100111: 01R:	RRD
OP_DEF(rrd)
{
	//            +-----------+   +---+
	//            |           v   |   v
	//   +-----+-----+       +-----+-----+
	// A | 7654 3210 |  (HL) | 7654 3210 |
	//   +-----+-----+       +-----+-----+
	//            ^                   |
	//            +-------------------+

	uint32 hl = reg.GetHL();
	uint32 m = Read1(hl);
	uint32 a = (reg.a & 0xf0) | (m & 0x0f);
	uint32 b = (reg.a << 4) | (m >> 4);
	Write1(hl, b);
	reg.a = ACC.in_8(a);
	CYCLE(16);
}

// ED:01101111: 01R:	RLD
OP_DEF(rld)
{
	//            +-------------------+
	//            |                   v
	//   +-----+-----+       +-----+-----+
	// A | 7654 3210 |  (HL) | 7654 3210 |
	//   +-----+-----+       +-----+-----+
	//            ^           |   ^   |
	//            +-----------+   +---+

	uint32 hl = reg.GetHL();
	uint32 m = Read1(hl);
	uint32 a = (reg.a & 0xf0) | (m >> 4);
	uint32 b = (m << 4) | (reg.a & 0x0f);
	Write1(hl, b);
	reg.a = ACC.in_8(a);
	CYCLE(16);
}

// ED:01110000: 01R:	IN F,(C)
OP_DEF(in_f_c)
{
	// バスの上位には B が出る
	uint32 addr = reg.GetBC();
	uint32 data = ReadIO(addr);
	ACC.in_8(data);
	CYCLE(9);
}

// ED:01110100: -1-:	TSTIO n
OP_DEF(tstio_n)
{
	// バスの上位は 0 になる
	uint32 n = Fetch1();
	uint32 dst = ReadIO(reg.c);
	ACC.tst_8(dst, n);
	CYCLE(12);
}

// ED:01110110: -1-:	SLP
OP_DEF(slp)
{
	putlog(0, "SLP (NOT IMPLEMENTED)");
	EnterSleep();
	CYCLE(8);
}

// OTIM/OTDM の共通部分
void
MPU64180Device::ops_otim(int inc)
{
	uint32 hl = reg.GetHL();
	uint32 src = Read1(hl);
	// バスの上位は 0 になる
	WriteIO(reg.c, src);
	reg.c += inc;
	hl += inc;
	reg.SetHL(hl);
	reg.b = ACC.outm_8(src, reg.b);
	CYCLE(14);
}

// ED:10000011: -1-:	OTIM
OP_DEF(otim)
{
	ops_otim(+1);
}

// ED:10001011: -1-:	OTDM
OP_DEF(otdm)
{
	ops_otim(-1);
}

// OTIMR/OTDMR の終了条件の共通部分。
// 他のリピート系命令とはフラグ変化が異なる。
void
MPU64180Device::ops_otmr_until()
{
	if (reg.b != 0) {
		reg.pc -= 2;
		CYCLE(2);
	} else {
		// 終了時はフラグ変化が違う。
		// S:0 Z:1 H:0 P/V:1 N:* C:0
		// このうち S, Z, H, N, C はセットされているままでよい。
		// パリティだけセット。
		reg.f.SetP(true);
	}
}

// ED:10010011: -1-:	OTIMR
OP_DEF(otimr)
{
	OP_FUNC(otim);
	ops_otmr_until();
}

// ED:10011011: -1-:	OTDMR
OP_DEF(otdmr)
{
	OP_FUNC(otdm);
	ops_otmr_until();
}

// LDI/LDD の共通部分
void
MPU64180Device::ops_ldi(int inc)
{
	uint32 hl = reg.GetHL();
	uint32 de = reg.GetDE();
	uint32 bc = reg.GetBC();

	uint32 data = Read1(hl);
	Write1(de, data);
	hl += inc;
	de += inc;
	bc--;
	reg.SetHL(hl);
	reg.SetDE(de);
	reg.SetBC(bc);

	reg.f.SetV((bc != 0));
	reg.f.SetN(false);
	reg.f.SetH(false);

	CYCLE(12);
}

// ED:10100000: 01R:	LDI
OP_DEF(ldi)
{
	ops_ldi(+1);
}

// CPI/CPD の共通部分
void
MPU64180Device::ops_cpi(int inc)
{
	uint32 hl = reg.GetHL();
	uint32 bc = reg.GetBC();

	uint32 src = Read1(hl);
	ACC.sub_8(reg.a, src, true);
	hl += inc;
	bc--;
	reg.SetHL(hl);
	reg.SetBC(bc);

	reg.f.SetV(bc != 0);

	CYCLE(12);
}

// ED:10100001: 01R:	CPI
OP_DEF(cpi)
{
	ops_cpi(+1);
}

// INI/IND の共通部分
void
MPU64180Device::ops_ini(int inc)
{
	uint32 hl = reg.GetHL();
	// バスの上位には B が出る
	uint32 addr = reg.GetBC();
	uint32 data = ReadIO(addr);
	Write1(hl, data);
	hl += inc;
	reg.b--;
	reg.SetHL(hl);
	// XXX S,H,P/V,C は本当は不定
	reg.f.SetZ(reg.b == 0);
	reg.f.SetN((int8)data < 0);
	CYCLE(12);
}

// ED:10100010: 01R:	INI
OP_DEF(ini)
{
	ops_ini(+1);
}

// OUTI/OUTD の共通部分
void
MPU64180Device::ops_outi(int inc)
{
	uint32 hl = reg.GetHL();
	// バスの上位には B が出る
	uint32 addr = reg.GetBC();
	uint32 data = Read1(hl);
	WriteIO(addr, data);
	hl += inc;
	reg.b--;
	reg.SetHL(hl);
	// XXX S,H,P/V,C は本当は不定
	reg.f.SetZ(reg.b == 0);
	reg.f.SetN((int8)data < 0);
	CYCLE(12);
}

// ED:10100011: 01R:	OUTI
OP_DEF(outi)
{
	ops_outi(+1);
}

// ED:10101000: 01R:	LDD
OP_DEF(ldd)
{
	ops_ldi(-1);
}

// ED:10101001: 01R:	CPD
OP_DEF(cpd)
{
	ops_cpi(-1);
}

// ED:10101010: 01R:	IND
OP_DEF(ind)
{
	ops_ini(-1);
}

// ED:10101011: 01R:	OUTD
OP_DEF(outd)
{
	ops_outi(-1);
}

// ED:10110000: 01R:	LDIR
OP_DEF(ldir)
{
	REPEAT_LD(ldi);
}

// ED:10110001: 01R:	CPIR
OP_DEF(cpir)
{
	REPEAT_CP(cpi);
}

// ED:10110010: 01R:	INIR
OP_DEF(inir)
{
	REPEAT_IO(ini);
}

// ED:10110011: 01R:	OTIR
OP_DEF(otir)
{
	REPEAT_IO(outi);
}

// ED:10111000: 01R:	LDDR
OP_DEF(lddr)
{
	REPEAT_LD(ldd);
}

// ED:10111001: 01R:	CPDR
OP_DEF(cpdr)
{
	REPEAT_CP(cpd);
}

// ED:10111010: 01R:	INDR
OP_DEF(indr)
{
	REPEAT_IO(ind);
}

// ED:10111011: 01R:	OTDR
OP_DEF(otdr)
{
	REPEAT_IO(outd);
}

// ED:11rrr001: --R:	MULUB A,r
OP_DEF(mulub_a_r)
{
	op_illegal(2);
}

// ED:11000011: --R:	MULUB HL,BC
OP_DEF(mulub_hl_bc)
{
	op_illegal(2);
}

// ED:11110011: --R:	MULUB HL,SP
OP_DEF(mulub_hl_sp)
{
	op_illegal(2);
}

// ED:11111111: -N-:	SYSCALL
OP_DEF(syscall)
{
	// MSX-DOS エミュレーションのような何か。
	// 通常の DOSCALL と同様、コール番号は C レジスタに入っている。

	if (gMainApp.msxdos_mode) {
		// MSX-DOS エミュレーションなら DOS コールを処理する
		assert(syscall_callback != NULL);
		syscall_callback(syscall_arg);
		CYCLE(3);
	} else {
		// 通常時は他の ED 系列と同じく不当命令例外。
		op_illegal(2);
	}
}

// DD:00rrr100: Z-Z:	INC ixr
OP_DEF(inc_ixr)
{
	op_illegal(2);
}

// DD:00rrr101: Z-Z:	DEC ixr
OP_DEF(dec_ixr)
{
	op_illegal(2);
}

// DD:00rrr110: Z-Z:	LD ixr,n
OP_DEF(ld_ixr_n)
{
	op_illegal(2);
}

// DD:01rrrsss: Z-Z:	LD r,ixs
OP_DEF(ld_r_ixs)
{
	op_illegal(2);
}

// DD:10000rrr: Z-Z:	ADD A,ixr
OP_DEF(add_a_ixr)
{
	op_illegal(2);
}

// DD:10001rrr: Z-Z:	ADC A,ixr
OP_DEF(adc_a_ixr)
{
	op_illegal(2);
}

// DD:10010rrr: Z-Z:	SUB ixr
OP_DEF(sub_ixr)
{
	op_illegal(2);
}

// DD:10011rrr: Z-Z:	SBC A,ixr
OP_DEF(sbc_a_ixr)
{
	op_illegal(2);
}

// DD:10100rrr: Z-Z:	AND ixr
OP_DEF(and_ixr)
{
	op_illegal(2);
}

// DD:10101rrr: Z-Z:	XOR ixr
OP_DEF(xor_ixr)
{
	op_illegal(2);
}

// DD:10110rrr: Z-Z:	OR ixr
OP_DEF(or_ixr)
{
	op_illegal(2);
}

// DD:10111rrr: Z-Z:	CP ixr
OP_DEF(cp_ixr)
{
	op_illegal(2);
}

// DD:11001011: 01R:	op_DD_CB
OP_DEF(dd_cb)
{
	// DD CB の場合は 3バイト目が d で、4バイト目が命令語。
	ixd = Fetch1();

	// 4バイト目をフェッチ
	op = Fetch1();

	// で分岐
	switch (op) {
#include "hd64180switch_dd_cb.inc"
	 default:
		op_illegal(3);
		break;
	}
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.