cpu_z80_jp(self, self->regs.bit.cf, cpu_z80_fetch_word(self));
break;
case 0xdb:
- cpu_z80_in(self, CPU_Z80_EA_A, cpu_z80_in_byte(self, cpu_z80_fetch_byte(self)));
+ cpu_z80_in_test(self, CPU_Z80_EA_A, cpu_z80_in_byte(self, cpu_z80_fetch_byte(self)));
break;
case 0xdc:
cpu_z80_call(self, self->regs.bit.cf, cpu_z80_fetch_word(self));
cpu_z80_call(self, true, 0x18);
break;
case 0xe0:
- cpu_z80_ret(self, self->regs.bit.pvf);
+ cpu_z80_ret(self, !self->regs.bit.pvf);
break;
case 0xe1:
cpu_z80_pop(self, CPU_Z80_EA_HL);
break;
case 0xe2:
- cpu_z80_jp(self, self->regs.bit.pvf, cpu_z80_fetch_word(self));
+ cpu_z80_jp(self, !self->regs.bit.pvf, cpu_z80_fetch_word(self));
break;
case 0xe3:
cpu_z80_ex(self, self->regs.word.sp, CPU_Z80_EA_HL);
break;
case 0xe4:
- cpu_z80_call(self, self->regs.bit.pvf, cpu_z80_fetch_word(self));
+ cpu_z80_call(self, !self->regs.bit.pvf, cpu_z80_fetch_word(self));
break;
case 0xe5:
cpu_z80_push(self, self->regs.word.hl);
cpu_z80_call(self, true, 0x20);
break;
case 0xe8:
- cpu_z80_ret(self, !self->regs.bit.pvf);
+ cpu_z80_ret(self, self->regs.bit.pvf);
break;
case 0xe9:
cpu_z80_jp(self, true, cpu_z80_read_word(self, self->regs.word.hl));
break;
case 0xea:
- cpu_z80_jp(self, !self->regs.bit.pvf, cpu_z80_fetch_word(self));
+ cpu_z80_jp(self, self->regs.bit.pvf, cpu_z80_fetch_word(self));
break;
case 0xeb:
cpu_z80_ex(self, CPU_Z80_EA_DE, CPU_Z80_EA_HL);
break;
case 0xec:
- cpu_z80_call(self, !self->regs.bit.pvf, cpu_z80_fetch_word(self));
+ cpu_z80_call(self, self->regs.bit.pvf, cpu_z80_fetch_word(self));
break;
case 0xed:
cpu_z80_execute_ed(self);
cpu_z80_jp(self, self->regs.bit.cf, cpu_z80_fetch_word(self));
break;
case 0xdb:
- cpu_z80_in(self, CPU_Z80_EA_A, cpu_z80_in_byte(self, cpu_z80_fetch_byte(self)));
+ cpu_z80_in_test(self, CPU_Z80_EA_A, cpu_z80_in_byte(self, cpu_z80_fetch_byte(self)));
break;
case 0xdc:
cpu_z80_call(self, self->regs.bit.cf, cpu_z80_fetch_word(self));
cpu_z80_call(self, true, 0x18);
break;
case 0xe0:
- cpu_z80_ret(self, self->regs.bit.pvf);
+ cpu_z80_ret(self, !self->regs.bit.pvf);
break;
case 0xe1:
cpu_z80_pop(self, CPU_Z80_EA_IX);
break;
case 0xe2:
- cpu_z80_jp(self, self->regs.bit.pvf, cpu_z80_fetch_word(self));
+ cpu_z80_jp(self, !self->regs.bit.pvf, cpu_z80_fetch_word(self));
break;
case 0xe3:
cpu_z80_ex(self, self->regs.word.sp, CPU_Z80_EA_IX);
break;
case 0xe4:
- cpu_z80_call(self, self->regs.bit.pvf, cpu_z80_fetch_word(self));
+ cpu_z80_call(self, !self->regs.bit.pvf, cpu_z80_fetch_word(self));
break;
case 0xe5:
cpu_z80_push(self, self->regs.word.ix);
cpu_z80_call(self, true, 0x20);
break;
case 0xe8:
- cpu_z80_ret(self, !self->regs.bit.pvf);
+ cpu_z80_ret(self, self->regs.bit.pvf);
break;
case 0xe9:
cpu_z80_jp(self, true, cpu_z80_read_word(self, self->regs.word.ix));
break;
case 0xea:
- cpu_z80_jp(self, !self->regs.bit.pvf, cpu_z80_fetch_word(self));
+ cpu_z80_jp(self, self->regs.bit.pvf, cpu_z80_fetch_word(self));
break;
case 0xeb:
cpu_z80_ex(self, CPU_Z80_EA_DE, CPU_Z80_EA_HL);
break;
case 0xec:
- cpu_z80_call(self, !self->regs.bit.pvf, cpu_z80_fetch_word(self));
+ cpu_z80_call(self, self->regs.bit.pvf, cpu_z80_fetch_word(self));
break;
case 0xed:
cpu_z80_ill(self);
cpu_z80_ill(self);
break;
case 0x40:
- cpu_z80_in(self, CPU_Z80_EA_B, cpu_z80_in_byte(self, self->regs.word.bc));
+ cpu_z80_in_test(self, CPU_Z80_EA_B, cpu_z80_in_byte(self, self->regs.word.bc));
break;
case 0x41:
cpu_z80_out(self, self->regs.word.bc, self->regs.byte.b);
cpu_z80_ld_byte(self, CPU_Z80_EA_I, self->regs.byte.a);
break;
case 0x48:
- cpu_z80_in(self, CPU_Z80_EA_C, cpu_z80_in_byte(self, self->regs.word.bc));
+ cpu_z80_in_test(self, CPU_Z80_EA_C, cpu_z80_in_byte(self, self->regs.word.bc));
break;
case 0x49:
cpu_z80_out(self, self->regs.word.bc, self->regs.byte.c);
cpu_z80_ld_byte(self, CPU_Z80_EA_R, self->regs.byte.a);
break;
case 0x50:
- cpu_z80_in(self, CPU_Z80_EA_D, cpu_z80_in_byte(self, self->regs.word.bc));
+ cpu_z80_in_test(self, CPU_Z80_EA_D, cpu_z80_in_byte(self, self->regs.word.bc));
break;
case 0x51:
cpu_z80_out(self, self->regs.word.bc, self->regs.byte.d);
cpu_z80_ld_byte(self, CPU_Z80_EA_A, self->regs.byte.i);
break;
case 0x58:
- cpu_z80_in(self, CPU_Z80_EA_E, cpu_z80_in_byte(self, self->regs.word.bc));
+ cpu_z80_in_test(self, CPU_Z80_EA_E, cpu_z80_in_byte(self, self->regs.word.bc));
break;
case 0x59:
cpu_z80_out(self, self->regs.word.bc, self->regs.byte.e);
cpu_z80_ld_byte(self, CPU_Z80_EA_A, self->regs.byte.r);
break;
case 0x60:
- cpu_z80_in(self, CPU_Z80_EA_H, cpu_z80_in_byte(self, self->regs.word.bc));
+ cpu_z80_in_test(self, CPU_Z80_EA_H, cpu_z80_in_byte(self, self->regs.word.bc));
break;
case 0x61:
cpu_z80_out(self, self->regs.word.bc, self->regs.byte.h);
cpu_z80_rrd(self);
break;
case 0x68:
- cpu_z80_in(self, CPU_Z80_EA_L, cpu_z80_in_byte(self, self->regs.word.bc));
+ cpu_z80_in_test(self, CPU_Z80_EA_L, cpu_z80_in_byte(self, self->regs.word.bc));
break;
case 0x69:
cpu_z80_out(self, self->regs.word.bc, self->regs.byte.l);
cpu_z80_rld(self);
break;
case 0x70:
- cpu_z80_in(self, CPU_Z80_EA_NONE, cpu_z80_in_byte(self, self->regs.word.bc));
+ cpu_z80_in_test(self, CPU_Z80_EA_NONE, cpu_z80_in_byte(self, self->regs.word.bc));
break;
case 0x71:
cpu_z80_out(self, self->regs.word.bc, 0);
cpu_z80_nop(self);
break;
case 0x78:
- cpu_z80_in(self, CPU_Z80_EA_A, cpu_z80_in_byte(self, self->regs.word.bc));
+ cpu_z80_in_test(self, CPU_Z80_EA_A, cpu_z80_in_byte(self, self->regs.word.bc));
break;
case 0x79:
cpu_z80_out(self, self->regs.word.bc, self->regs.byte.a);
cpu_z80_call(self, true, 0x18);
break;
case 0xe0:
- cpu_z80_ret(self, self->regs.bit.pvf);
+ cpu_z80_ret(self, !self->regs.bit.pvf);
break;
case 0xe1:
cpu_z80_pop(self, CPU_Z80_EA_IY);
break;
case 0xe2:
- cpu_z80_jp(self, self->regs.bit.pvf, cpu_z80_fetch_word(self));
+ cpu_z80_jp(self, !self->regs.bit.pvf, cpu_z80_fetch_word(self));
break;
case 0xe3:
cpu_z80_ex(self, self->regs.word.sp, CPU_Z80_EA_IY);
break;
case 0xe4:
- cpu_z80_call(self, self->regs.bit.pvf, cpu_z80_fetch_word(self));
+ cpu_z80_call(self, !self->regs.bit.pvf, cpu_z80_fetch_word(self));
break;
case 0xe5:
cpu_z80_push(self, self->regs.word.iy);
cpu_z80_call(self, true, 0x20);
break;
case 0xe8:
- cpu_z80_ret(self, !self->regs.bit.pvf);
+ cpu_z80_ret(self, self->regs.bit.pvf);
break;
case 0xe9:
cpu_z80_jp(self, true, cpu_z80_read_word(self, self->regs.word.iy));
break;
case 0xea:
- cpu_z80_jp(self, !self->regs.bit.pvf, cpu_z80_fetch_word(self));
+ cpu_z80_jp(self, self->regs.bit.pvf, cpu_z80_fetch_word(self));
break;
case 0xeb:
cpu_z80_ex(self, CPU_Z80_EA_DE, CPU_Z80_EA_HL);
break;
case 0xec:
- cpu_z80_call(self, !self->regs.bit.pvf, cpu_z80_fetch_word(self));
+ cpu_z80_call(self, self->regs.bit.pvf, cpu_z80_fetch_word(self));
break;
case 0xed:
cpu_z80_ill(self);
#define CPU_Z80_REG_F_BIT_S 7
// special memory locations (negative address)
-// note: CPU_Z80_EA_NONE is a byte-wide sink for the "in f,(c)" instruction,
-// so data can be stored somewhere and never read back, but is rounded up
-// to a word for alignment reasons; note it cannot be accessed via regs.xxx
+// note: CPU_Z80_EA_NONE is a byte-wide sink for implmenting "in f,(c)" and
+// DDCB/FDCB undocumented instructions, to store into and never read back
#define CPU_Z80_EA_F (-0x1c)
#define CPU_Z80_EA_A (-0x1b)
#define CPU_Z80_EA_C (-0x1a)
#define CPU_Z80_EA_DE_PRIME (-8)
#define CPU_Z80_EA_HL_PRIME (-6)
#define CPU_Z80_EA_PC (-4)
-#define CPU_Z80_EA_NONE (-2)
+#define CPU_Z80_EA_INTF (-2)
+#define CPU_Z80_EA_NONE (-1)
// registers, in same order as special memory locations, but reversed on
// big endian hardware where special memory address will be complemented
union cpu_z80_regs {
#if __BYTE_ORDER == __BIG_ENDIAN
struct {
- uint16_t _fill_none;
+ uint8_t _fill_none;
+ uint8_t _fill_intf : 4;
+ uint8_t iff2 : 1;
+ uint8_t iff1 : 1;
+ uint8_t im : 2;
uint16_t _fill_pc;
uint16_t _fill_hl_prime;
uint16_t _fill_de_prime;
uint8_t cf : 1;
} bit;
struct {
- uint16_t _fill_none;
+ uint8_t _fill_none;
+ uint8_t _fill_intf;
uint16_t _fill_pc;
uint16_t _fill_hl_prime;
uint16_t _fill_de_prime;
uint8_t f;
} byte;
struct {
- uint16_t _fill_none;
+ uint8_t _fill_none;
+ uint8_t _fill_intf;
uint16_t pc;
uint16_t hl_prime;
uint16_t de_prime;
uint16_t _fill_de_prime;
uint16_t _fill_hl_prime;
uint16_t _fill_pc;
- uint16_t _fill_none;
+ uint8_t im : 2;
+ uint8_t iff1 : 1;
+ uint8_t iff2 : 1;
+ uint8_t _fill_intf : 4;
+ uint8_t _fill_none;
} bit;
struct {
uint8_t f;
uint16_t _fill_de_prime;
uint16_t _fill_hl_prime;
uint16_t _fill_pc;
- uint16_t _fill_none;
+ uint8_t _fill_intf;
+ uint8_t _fill_none;
} byte;
struct {
uint16_t af;
uint16_t de_prime;
uint16_t hl_prime;
uint16_t pc;
- uint16_t _fill_none;
+ uint8_t _fill_intf;
+ uint8_t _fill_none;
} word;
uint8_t mem_le[0x1c];
#endif
// instruction execute
static ALWAYS_INLINE void cpu_z80_adc_byte(struct cpu_z80 *self, int lvalue, int rvalue) {
- abort();
+ int data = cpu_z80_read_byte(self, lvalue);
+ int result0 = (data & 0xf) + (rvalue & 0xf) + self->regs.bit.cf;
+ int result1 = result0 + (data & 0x70) + (rvalue & 0x70);
+ int result2 = result1 + (data & 0x80) + (rvalue & 0x80);
+ cpu_z80_write_byte(self, lvalue, result2 & 0xff);
+ self->regs.bit.cf = result2 >> 8;
+ self->regs.bit.nf = false;
+ self->regs.bit.pvf = ((result1 >> 7) ^ (result2 >> 8)) & 1;
+ self->regs.bit.hf = result0 >> 4;
+ self->regs.bit.zf = (result2 & 0xff) == 0;
+ self->regs.bit.sf = (result2 >> 7) & 1;
}
static ALWAYS_INLINE void cpu_z80_adc_word(struct cpu_z80 *self, int lvalue, int rvalue) {
- abort();
+ int data = cpu_z80_read_word(self, lvalue);
+ int result0 = (data & 0xfff) + (rvalue & 0xfff) + self->regs.bit.cf;
+ int result1 = result0 + (data & 0x7000) + (rvalue & 0x7000);
+ int result2 = result1 + (data & 0x8000) + (rvalue & 0x8000);
+ cpu_z80_write_word(self, lvalue, result2 & 0xffff);
+ self->regs.bit.cf = result2 >> 16;
+ self->regs.bit.nf = false;
+ self->regs.bit.pvf = ((result1 >> 15) ^ (result2 >> 16)) & 1;
+ self->regs.bit.hf = result0 >> 12;
+ self->regs.bit.zf = (result2 & 0xffff) == 0;
+ self->regs.bit.sf = (result2 >> 15) & 1;
}
static ALWAYS_INLINE void cpu_z80_add_byte(struct cpu_z80 *self, int lvalue, int rvalue) {
- abort();
+ int data = cpu_z80_read_byte(self, lvalue);
+ int result0 = (data & 0xf) + (rvalue & 0xf);
+ int result1 = result0 + (data & 0x70) + (rvalue & 0x70);
+ int result2 = result1 + (data & 0x80) + (rvalue & 0x80);
+ cpu_z80_write_byte(self, lvalue, result2 & 0xff);
+ self->regs.bit.cf = result2 >> 8;
+ self->regs.bit.nf = false;
+ self->regs.bit.pvf = ((result1 >> 7) ^ (result2 >> 8)) & 1;
+ self->regs.bit.hf = result0 >> 4;
+ self->regs.bit.zf = (result2 & 0xff) == 0;
+ self->regs.bit.sf = (result2 >> 7) & 1;
}
static ALWAYS_INLINE void cpu_z80_add_word(struct cpu_z80 *self, int lvalue, int rvalue) {
- abort();
+ int data = cpu_z80_read_word(self, lvalue);
+ int result0 = (data & 0xfff) + (rvalue & 0xfff);
+ int result1 = result0 + (data & 0xf000) + (rvalue & 0xf000);
+ cpu_z80_write_word(self, lvalue, result1 & 0xffff);
+ self->regs.bit.cf = result1 >> 16;
+ self->regs.bit.nf = false;
+ self->regs.bit.hf = result0 >> 12;
}
static ALWAYS_INLINE void cpu_z80_and(struct cpu_z80 *self, int rvalue) {
- abort();
+ int result = self->regs.byte.a & rvalue;
+ int parity = result;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+ self->regs.byte.a = result;
+ self->regs.bit.cf = false;
+ self->regs.bit.nf = false;
+ self->regs.bit.pvf = (parity & 1) == 0;
+ self->regs.bit.hf = true;
+ self->regs.bit.zf = result == 0;
+ self->regs.bit.sf = result >> 7;
}
static ALWAYS_INLINE void cpu_z80_bit(struct cpu_z80 *self, int n, int rvalue) {
- abort();
+ int result = rvalue & (1 << n);
+ self->regs.bit.nf = false;
+ self->regs.bit.pvf = result == 0;
+ self->regs.bit.hf = true;
+ self->regs.bit.zf = result == 0;
+ self->regs.bit.sf = result >> 7;
}
static ALWAYS_INLINE void cpu_z80_call(struct cpu_z80 *self, bool pred, int rvalue) {
- abort();
+ if (pred) {
+ cpu_z80_push_word(self, self->regs.word.pc);
+ self->regs.word.pc = rvalue;
+ }
}
static ALWAYS_INLINE void cpu_z80_ccf(struct cpu_z80 *self) {
- abort();
+ self->regs.bit.hf = self->regs.bit.cf;
+ self->regs.bit.cf = !self->regs.bit.cf;
+ self->regs.bit.nf = false;
}
static ALWAYS_INLINE void cpu_z80_cp(struct cpu_z80 *self, int rvalue) {
- abort();
+ int result0 = (self->regs.byte.a & 0xf) - (rvalue & 0xf);
+ int result1 = result0 + (self->regs.byte.a & 0x70) - (rvalue & 0x70);
+ int result2 = result1 + (self->regs.byte.a & 0x80) - (rvalue & 0x80);
+ self->regs.bit.cf = (result2 >> 8) & 1;
+ self->regs.bit.nf = true;
+ self->regs.bit.pvf = ((result1 >> 7) ^ (result2 >> 8)) & 1;
+ self->regs.bit.hf = (result0 >> 4) & 1;
+ self->regs.bit.zf = (result2 & 0xff) == 0;
+ self->regs.bit.sf = (result2 >> 7) & 1;
}
static ALWAYS_INLINE void cpu_z80_cpd(struct cpu_z80 *self) {
- abort();
+ int data = cpu_z80_read_byte(self, self->regs.word.hl--);
+ int result0 = (self->regs.byte.a & 0xf) - (data & 0xf);
+ int result1 = result0 + (self->regs.byte.a & 0xf0) - (data & 0xf0);
+ int result2 = (self->regs.word.bc - 1) & 0xffff;
+ self->regs.word.bc = result2;
+ self->regs.bit.nf = true;
+ self->regs.bit.pvf = result2 != 0;
+ self->regs.bit.hf = (result0 >> 4) & 1;
+ self->regs.bit.zf = (result1 & 0xff) == 0;
+ self->regs.bit.sf = (result1 >> 7) & 1;
}
static ALWAYS_INLINE void cpu_z80_cpdr(struct cpu_z80 *self) {
- abort();
+ int data = cpu_z80_read_byte(self, self->regs.word.hl--);
+ int result0 = (self->regs.byte.a & 0xf) - (data & 0xf);
+ int result1 = result0 + (self->regs.byte.a & 0xf0) - (data & 0xf0);
+ int result2 = (self->regs.word.bc - 1) & 0xffff;
+ self->regs.word.bc = result2;
+ self->regs.bit.nf = true;
+ self->regs.bit.pvf = result2 != 0;
+ self->regs.bit.hf = (result0 >> 4) & 1;
+ self->regs.bit.zf = (result1 & 0xff) == 0;
+ self->regs.bit.sf = (result1 >> 7) & 1;
+ if ((result1 & 0xff) && result2)
+ self->regs.word.pc -= 2;
}
static ALWAYS_INLINE void cpu_z80_cpi(struct cpu_z80 *self) {
- abort();
+ int data = cpu_z80_read_byte(self, self->regs.word.hl++);
+ int result0 = (self->regs.byte.a & 0xf) - (data & 0xf);
+ int result1 = result0 + (self->regs.byte.a & 0xf0) - (data & 0xf0);
+ int result2 = (self->regs.word.bc - 1) & 0xffff;
+ self->regs.word.bc = result2;
+ self->regs.bit.nf = true;
+ self->regs.bit.pvf = result2 != 0;
+ self->regs.bit.hf = (result0 >> 4) & 1;
+ self->regs.bit.zf = (result1 & 0xff) == 0;
+ self->regs.bit.sf = (result1 >> 7) & 1;
}
static ALWAYS_INLINE void cpu_z80_cpir(struct cpu_z80 *self) {
- abort();
+ int data = cpu_z80_read_byte(self, self->regs.word.hl++);
+ int result0 = (self->regs.byte.a & 0xf) - (data & 0xf);
+ int result1 = result0 + (self->regs.byte.a & 0xf0) - (data & 0xf0);
+ int result2 = (self->regs.word.bc - 1) & 0xffff;
+ self->regs.word.bc = result2;
+ self->regs.bit.nf = true;
+ self->regs.bit.pvf = result2 != 0;
+ self->regs.bit.hf = (result0 >> 4) & 1;
+ self->regs.bit.zf = (result1 & 0xff) == 0;
+ self->regs.bit.sf = (result1 >> 7) & 1;
+ if ((result1 & 0xff) && result2)
+ self->regs.word.pc -= 2;
}
static ALWAYS_INLINE void cpu_z80_cpl(struct cpu_z80 *self) {
- abort();
+ self->regs.byte.a = ~self->regs.byte.a;
+ self->regs.bit.nf = true;
+ self->regs.bit.hf = true;
}
static ALWAYS_INLINE void cpu_z80_daa(struct cpu_z80 *self) {
- abort();
+ int result0, result1;
+ if (self->regs.bit.nf) {
+ result0 = (self->regs.byte.a & 0xf);
+ if (self->regs.bit.hf || result0 >= 0xa)
+ result0 -= 6;
+ result1 = result0 + (self->regs.byte.a & 0xf0);
+#if 1 // insane (match z80 for a=9e cf=0 nf=1 hf=0)
+ if (self->regs.bit.cf || self->regs.byte.a >= 0x9a)
+#else // sane (but does not match z80)
+ if (self->regs.bit.cf || result1 >= 0xa0)
+#endif
+ result1 -= 0x60;
+ }
+ else {
+ result0 = (self->regs.byte.a & 0xf);
+ if (self->regs.bit.hf || result0 >= 0xa)
+ result0 += 6;
+ result1 =
+ result0 +
+ (self->regs.byte.a & 0xf0);
+ if (self->regs.bit.cf || result1 >= 0xa0)
+ result1 += 0x60;
+ }
+ int parity = result1;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+ self->regs.byte.a = result1 & 0xff;
+ self->regs.bit.cf |= (result1 >> 8) & 1;
+ self->regs.bit.pvf = (parity & 1) == 0;
+ self->regs.bit.hf = (result0 >> 4) & 1;
+ self->regs.bit.zf = (result1 & 0xff) == 0;
+ self->regs.bit.sf = (result1 >> 7) & 1;
}
static ALWAYS_INLINE void cpu_z80_dec_byte(struct cpu_z80 *self, int lvalue) {
- abort();
+ int data = cpu_z80_read_byte(self, lvalue);
+ int result0 = (data & 0xf) - 1;
+ int result1 = result0 + (data & 0x70);
+ int result2 = result1 + (data & 0x80);
+ cpu_z80_write_byte(self, lvalue, result2 & 0xff);
+ self->regs.bit.nf = true;
+ self->regs.bit.pvf = ((result1 >> 7) ^ (result2 >> 8)) & 1;
+ self->regs.bit.hf = (result0 >> 4) & 1;
+ self->regs.bit.zf = (result2 & 0xff) == 0;
+ self->regs.bit.sf = (result2 >> 7) & 1;
}
static ALWAYS_INLINE void cpu_z80_dec_word(struct cpu_z80 *self, int lvalue) {
- abort();
+ int result = (cpu_z80_read_word(self, lvalue) - 1) & 0xffff;
+ cpu_z80_write_word(self, lvalue, result);
}
static ALWAYS_INLINE void cpu_z80_di(struct cpu_z80 *self) {
- abort();
+ self->regs.bit.iff1 = false;
}
static ALWAYS_INLINE void cpu_z80_djnz(struct cpu_z80 *self, int rvalue) {
- abort();
+ if (--self->regs.byte.b)
+ self->regs.word.pc += rvalue;
}
static ALWAYS_INLINE void cpu_z80_ei(struct cpu_z80 *self) {
- abort();
+ self->regs.bit.iff1 = true;
}
static ALWAYS_INLINE void cpu_z80_ex(struct cpu_z80 *self, int lvalue0, int lvalue1) {
- abort();
+ int data0 = cpu_z80_read_word(self, lvalue0);
+ int data1 = cpu_z80_read_word(self, lvalue1);
+ cpu_z80_write_word(self, lvalue0, data1);
+ cpu_z80_write_word(self, lvalue1, data0);
}
static ALWAYS_INLINE void cpu_z80_halt(struct cpu_z80 *self) {
}
static ALWAYS_INLINE void cpu_z80_im(struct cpu_z80 *self, int n) {
- abort();
+ self->regs.bit.im = n;
}
static ALWAYS_INLINE void cpu_z80_in(struct cpu_z80 *self, int lvalue, int rvalue) {
- abort();
+ cpu_z80_write_byte(self, lvalue, rvalue);
+}
+
+static ALWAYS_INLINE void cpu_z80_in_test(struct cpu_z80 *self, int lvalue, int rvalue) {
+ int parity = rvalue;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+ cpu_z80_write_byte(self, lvalue, rvalue);
+ self->regs.bit.nf = false;
+ self->regs.bit.pvf = (parity & 1) == 0;
+ self->regs.bit.hf = false;
+ self->regs.bit.zf = rvalue == 0;
+ self->regs.bit.sf = rvalue >> 7;
}
static ALWAYS_INLINE void cpu_z80_inc_byte(struct cpu_z80 *self, int lvalue) {
- abort();
+ int data = cpu_z80_read_byte(self, lvalue);
+ int result0 = (data & 0xf) + 1;
+ int result1 = result0 + (data & 0x70);
+ int result2 = result1 + (data & 0x80);
+ cpu_z80_write_byte(self, lvalue, result2 & 0xff);
+ self->regs.bit.nf = false;
+ self->regs.bit.pvf = ((result1 >> 7) ^ (result2 >> 8)) & 1;
+ self->regs.bit.hf = result0 >> 4;
+ self->regs.bit.zf = (result2 & 0xff) == 0;
+ self->regs.bit.sf = (result2 >> 7) & 1;
}
static ALWAYS_INLINE void cpu_z80_inc_word(struct cpu_z80 *self, int lvalue) {
- abort();
+ int result = (cpu_z80_read_word(self, lvalue) + 1) & 0xffff;
+ cpu_z80_write_word(self, lvalue, result);
}
static ALWAYS_INLINE void cpu_z80_ind(struct cpu_z80 *self) {
}
static ALWAYS_INLINE void cpu_z80_jp(struct cpu_z80 *self, bool pred, int rvalue) {
- abort();
+ if (pred)
+ self->regs.word.pc = rvalue;
}
static ALWAYS_INLINE void cpu_z80_jr(struct cpu_z80 *self, bool pred, int rvalue) {
- abort();
+ if (pred)
+ self->regs.word.pc += rvalue;
}
static ALWAYS_INLINE void cpu_z80_ld_byte(struct cpu_z80 *self, int lvalue, int rvalue) {
- abort();
+ cpu_z80_write_byte(self, lvalue, rvalue);
}
static ALWAYS_INLINE void cpu_z80_ld_word(struct cpu_z80 *self, int lvalue, int rvalue) {
- abort();
+ cpu_z80_write_word(self, lvalue, rvalue);
}
static ALWAYS_INLINE void cpu_z80_ldd(struct cpu_z80 *self) {
- abort();
+ int data = cpu_z80_read_byte(self, self->regs.word.hl--);
+ cpu_z80_write_byte(self, self->regs.word.de--, data);
+ int result = (self->regs.word.bc - 1) & 0xffff;
+ self->regs.word.bc = result;
+ self->regs.bit.nf = false;
+ self->regs.bit.pvf = result != 0;
+ self->regs.bit.hf = false;
}
static ALWAYS_INLINE void cpu_z80_lddr(struct cpu_z80 *self) {
- abort();
+ int data = cpu_z80_read_byte(self, self->regs.word.hl--);
+ cpu_z80_write_byte(self, self->regs.word.de--, data);
+ int result = (self->regs.word.bc - 1) & 0xffff;
+ self->regs.word.bc = result;
+ self->regs.bit.nf = false;
+ self->regs.bit.pvf = result != 0;
+ self->regs.bit.hf = false;
+ if (result)
+ self->regs.word.pc -= 2;
}
static ALWAYS_INLINE void cpu_z80_ldi(struct cpu_z80 *self) {
- abort();
+ int data = cpu_z80_read_byte(self, self->regs.word.hl++);
+ cpu_z80_write_byte(self, self->regs.word.de++, data);
+ int result = (self->regs.word.bc - 1) & 0xffff;
+ self->regs.word.bc = result;
+ self->regs.bit.nf = false;
+ self->regs.bit.pvf = result != 0;
+ self->regs.bit.hf = false;
}
static ALWAYS_INLINE void cpu_z80_ldir(struct cpu_z80 *self) {
- abort();
+ int data = cpu_z80_read_byte(self, self->regs.word.hl++);
+ cpu_z80_write_byte(self, self->regs.word.de++, data);
+ int result = (self->regs.word.bc - 1) & 0xffff;
+ self->regs.word.bc = result;
+ self->regs.bit.nf = false;
+ self->regs.bit.pvf = result != 0;
+ self->regs.bit.hf = false;
+ if (result)
+ self->regs.word.pc -= 2;
}
static ALWAYS_INLINE void cpu_z80_neg(struct cpu_z80 *self) {
- abort();
+ int result0 = -(self->regs.byte.a & 0xf);
+ int result1 = result0 - (self->regs.byte.a & 0x70);
+ int result2 = result1 - (self->regs.byte.a & 0x80);
+ self->regs.byte.a = result2 & 0xff;
+ self->regs.bit.cf = (result2 >> 8) & 1;
+ self->regs.bit.nf = true;
+ self->regs.bit.pvf = ((result1 >> 7) ^ (result2 >> 8)) & 1;
+ self->regs.bit.hf = (result0 >> 4) & 1;
+ self->regs.bit.zf = (result2 & 0xff) == 0;
+ self->regs.bit.sf = (result2 >> 7) & 1;
}
static ALWAYS_INLINE void cpu_z80_nop(struct cpu_z80 *self) {
- abort();
}
static ALWAYS_INLINE void cpu_z80_or(struct cpu_z80 *self, int rvalue) {
- abort();
+ int result = self->regs.byte.a | rvalue;
+ int parity = result;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+ self->regs.byte.a = result;
+ self->regs.bit.cf = false;
+ self->regs.bit.nf = false;
+ self->regs.bit.pvf = (parity & 1) == 0;
+ self->regs.bit.hf = false;
+ self->regs.bit.zf = result == 0;
+ self->regs.bit.sf = result >> 7;
}
static ALWAYS_INLINE void cpu_z80_otdr(struct cpu_z80 *self) {
}
static ALWAYS_INLINE void cpu_z80_out(struct cpu_z80 *self, int lvalue, int rvalue) {
- abort();
+ cpu_z80_out_byte(self, lvalue, rvalue);
}
static ALWAYS_INLINE void cpu_z80_outd(struct cpu_z80 *self) {
}
static ALWAYS_INLINE void cpu_z80_pop(struct cpu_z80 *self, int lvalue) {
- abort();
+ cpu_z80_write_word(self, lvalue, cpu_z80_pop_word(self));
}
static ALWAYS_INLINE void cpu_z80_push(struct cpu_z80 *self, int rvalue) {
- abort();
+ cpu_z80_push_word(self, rvalue);
}
static ALWAYS_INLINE void cpu_z80_res(struct cpu_z80 *self, int n, int lvalue0, int lvalue1) {
- abort();
+ int result = cpu_z80_read_byte(self, lvalue0) & ~(1 << n);
+ cpu_z80_write_byte(self, lvalue0, result);
+ cpu_z80_write_byte(self, lvalue1, result); // undocumented DDCB/FDCB versions
}
static ALWAYS_INLINE void cpu_z80_ret(struct cpu_z80 *self, bool pred) {
- abort();
+ if (pred)
+ self->regs.word.pc = cpu_z80_pop_word(self);
}
static ALWAYS_INLINE void cpu_z80_reti(struct cpu_z80 *self) {
- abort();
+ self->regs.bit.iff1 = self->regs.bit.iff2;
+ self->regs.word.pc = cpu_z80_pop_word(self);
}
static ALWAYS_INLINE void cpu_z80_retn(struct cpu_z80 *self) {
- abort();
+ self->regs.bit.iff1 = self->regs.bit.iff2;
+ self->regs.word.pc = cpu_z80_pop_word(self);
}
static ALWAYS_INLINE void cpu_z80_rl(struct cpu_z80 *self, int lvalue0, int lvalue1) {
- abort();
+ int data = cpu_z80_read_byte(self, lvalue0);
+ int result = self->regs.bit.cf | (data << 1);
+ int parity = result;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+ data = result & 0xff;
+ cpu_z80_write_byte(self, lvalue0, data);
+ cpu_z80_write_byte(self, lvalue1, data); // undocumented DDCB/FDCB versions
+ self->regs.bit.cf = result >> 8;
+ self->regs.bit.nf = false;
+ self->regs.bit.pvf = (parity & 1) == 0;
+ self->regs.bit.hf = false;
+ self->regs.bit.zf = (result & 0xff) == 0;
+ self->regs.bit.sf = (result >> 7) & 1;
}
static ALWAYS_INLINE void cpu_z80_rla(struct cpu_z80 *self) {
- abort();
+ int result = self->regs.bit.cf | (self->regs.byte.a << 1);
+ self->regs.byte.a = result & 0xff;
+ self->regs.bit.cf = result >> 8;
+ self->regs.bit.nf = false;
+ self->regs.bit.hf = false;
}
static ALWAYS_INLINE void cpu_z80_rlc(struct cpu_z80 *self, int lvalue0, int lvalue1) {
- abort();
+ int data = cpu_z80_read_byte(self, lvalue0);
+ int result = (data >> 7) | (data << 1);
+ int parity = result;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+ data = result & 0xff;
+ cpu_z80_write_byte(self, lvalue0, data);
+ cpu_z80_write_byte(self, lvalue1, data); // undocumented DDCB/FDCB versions
+ self->regs.bit.cf = result >> 8;
+ self->regs.bit.nf = false;
+ self->regs.bit.pvf = (parity & 1) == 0;
+ self->regs.bit.hf = false;
+ self->regs.bit.zf = (result & 0xff) == 0;
+ self->regs.bit.sf = (result >> 7) & 1;
}
static ALWAYS_INLINE void cpu_z80_rlca(struct cpu_z80 *self) {
- abort();
+ int result = (self->regs.byte.a >> 7) | (self->regs.byte.a << 1);
+ self->regs.byte.a = result & 0xff;
+ self->regs.bit.cf = result >> 8;
+ self->regs.bit.nf = false;
+ self->regs.bit.hf = false;
}
static ALWAYS_INLINE void cpu_z80_rld(struct cpu_z80 *self) {
- abort();
+ int result =
+ (self->regs.byte.a & 0xf) |
+ (cpu_z80_read_byte(self, self->regs.word.hl) << 4);
+ cpu_z80_write_byte(self, self->regs.word.hl, result & 0xff);
+ result = (result >> 8) | (self->regs.byte.a & 0xf0);
+ int parity = result;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+ self->regs.byte.a = result;
+ self->regs.bit.nf = false;
+ self->regs.bit.pvf = (parity & 1) == 0;
+ self->regs.bit.hf = false;
+ self->regs.bit.zf = result == 0;
+ self->regs.bit.sf = result >> 7;
}
static ALWAYS_INLINE void cpu_z80_rr(struct cpu_z80 *self, int lvalue0, int lvalue1) {
- abort();
+ int data = cpu_z80_read_byte(self, lvalue0);
+ int result = data | (self->regs.bit.cf << 8);
+ int parity = result;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+ data = result >> 1;
+ cpu_z80_write_byte(self, lvalue0, data);
+ cpu_z80_write_byte(self, lvalue1, data); // undocumented DDCB/FDCB versions
+ self->regs.bit.cf = result & 1;
+ self->regs.bit.nf = false;
+ self->regs.bit.pvf = (parity & 2) == 0;
+ self->regs.bit.hf = false;
+ self->regs.bit.zf = (result & 0x1fe) == 0;
+ self->regs.bit.sf = result >> 8;
}
static ALWAYS_INLINE void cpu_z80_rra(struct cpu_z80 *self) {
- abort();
+ int result = self->regs.byte.a | (self->regs.bit.cf << 8);
+ self->regs.byte.a = result >> 1;
+ self->regs.bit.cf = result & 1;
+ self->regs.bit.nf = false;
+ self->regs.bit.hf = false;
}
static ALWAYS_INLINE void cpu_z80_rrc(struct cpu_z80 *self, int lvalue0, int lvalue1) {
- abort();
+ int data = cpu_z80_read_byte(self, lvalue0);
+ int result = data | ((data & 1) << 8);
+ int parity = result;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+ data = result >> 1;
+ cpu_z80_write_byte(self, lvalue0, data);
+ cpu_z80_write_byte(self, lvalue1, data); // undocumented DDCB/FDCB versions
+ self->regs.bit.cf = result & 1;
+ self->regs.bit.nf = false;
+ self->regs.bit.pvf = (parity & 2) == 0;
+ self->regs.bit.hf = false;
+ self->regs.bit.zf = (result & 0x1fe) == 0;
+ self->regs.bit.sf = result >> 8;
}
static ALWAYS_INLINE void cpu_z80_rrca(struct cpu_z80 *self) {
- abort();
+ int result = self->regs.byte.a | ((self->regs.byte.a & 1) << 8);
+ self->regs.byte.a = result >> 1;
+ self->regs.bit.cf = result & 1;
+ self->regs.bit.nf = false;
+ self->regs.bit.hf = false;
}
static ALWAYS_INLINE void cpu_z80_rrd(struct cpu_z80 *self) {
- abort();
+ int result =
+ cpu_z80_read_byte(self, self->regs.word.hl) |
+ ((self->regs.byte.a & 0xf) << 8);
+ cpu_z80_write_byte(self, self->regs.word.hl, result >> 4);
+ result = (result & 0xf) | (self->regs.byte.a & 0xf0);
+ int parity = result;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+ self->regs.byte.a = result;
+ self->regs.bit.nf = false;
+ self->regs.bit.pvf = (parity & 1) == 0;
+ self->regs.bit.hf = false;
+ self->regs.bit.zf = result == 0;
+ self->regs.bit.sf = result >> 7;
}
static ALWAYS_INLINE void cpu_z80_sbc_byte(struct cpu_z80 *self, int lvalue, int rvalue) {
- abort();
+ int data = cpu_z80_read_byte(self, lvalue);
+ int result0 = (data & 0xf) - (rvalue & 0xf) - self->regs.bit.cf;
+ int result1 = result0 + (data & 0x70) - (rvalue & 0x70);
+ int result2 = result1 + (data & 0x80) - (rvalue & 0x80);
+ cpu_z80_write_byte(self, lvalue, result2 & 0xff);
+ self->regs.bit.cf = (result2 >> 8) & 1;
+ self->regs.bit.nf = true;
+ self->regs.bit.pvf = ((result1 >> 7) ^ (result2 >> 8)) & 1;
+ self->regs.bit.hf = (result0 >> 4) & 1;
+ self->regs.bit.zf = (result2 & 0xff) == 0;
+ self->regs.bit.sf = (result2 >> 7) & 1;
}
static ALWAYS_INLINE void cpu_z80_sbc_word(struct cpu_z80 *self, int lvalue, int rvalue) {
- abort();
+ int data = cpu_z80_read_word(self, lvalue);
+ int result0 = (data & 0xfff) - (rvalue & 0xfff) - self->regs.bit.cf;
+ int result1 = result0 + (data & 0x7000) - (rvalue & 0x7000);
+ int result2 = result1 + (data & 0x8000) - (rvalue & 0x8000);
+ cpu_z80_write_word(self, lvalue, result2 & 0xffff);
+ self->regs.bit.cf = (result2 >> 16) & 1;
+ self->regs.bit.nf = true;
+ self->regs.bit.pvf = ((result1 >> 15) ^ (result2 >> 16)) & 1;
+ self->regs.bit.hf = (result0 >> 12) & 1;
+ self->regs.bit.zf = (result2 & 0xffff) == 0;
+ self->regs.bit.sf = (result2 >> 15) & 1;
}
static ALWAYS_INLINE void cpu_z80_scf(struct cpu_z80 *self) {
- abort();
+ self->regs.bit.cf = true;
+ self->regs.bit.nf = false;
+ self->regs.bit.hf = false;
}
static ALWAYS_INLINE void cpu_z80_set(struct cpu_z80 *self, int n, int lvalue0, int lvalue1) {
- abort();
+ int result = cpu_z80_read_byte(self, lvalue0) | (1 << n);
+ cpu_z80_write_byte(self, lvalue0, result);
+ cpu_z80_write_byte(self, lvalue1, result); // undocumented DDCB/FDCB versions
}
static ALWAYS_INLINE void cpu_z80_sla(struct cpu_z80 *self, int lvalue0, int lvalue1) {
- abort();
+ int data = cpu_z80_read_byte(self, lvalue0);
+ int result = data << 1;
+ int parity = result;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+ data = result & 0xff;
+ cpu_z80_write_byte(self, lvalue0, data);
+ cpu_z80_write_byte(self, lvalue1, data); // undocumented DDCB/FDCB versions
+ self->regs.bit.cf = result >> 8;
+ self->regs.bit.nf = false;
+ self->regs.bit.pvf = (parity & 1) == 0;
+ self->regs.bit.hf = false;
+ self->regs.bit.zf = (result & 0xff) == 0;
+ self->regs.bit.sf = (result >> 7) & 1;
}
static ALWAYS_INLINE void cpu_z80_sll(struct cpu_z80 *self, int lvalue0, int lvalue1) {
- abort();
+ int data = cpu_z80_read_byte(self, lvalue0);
+ int result = 1 | (data << 1);
+ int parity = result;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+ data = result & 0xff;
+ cpu_z80_write_byte(self, lvalue0, data);
+ cpu_z80_write_byte(self, lvalue1, data); // undocumented DDCB/FDCB versions
+ self->regs.bit.cf = result >> 8;
+ self->regs.bit.nf = false;
+ self->regs.bit.pvf = (parity & 1) == 0;
+ self->regs.bit.hf = false;
+ self->regs.bit.zf = (result & 0xff) == 0;
+ self->regs.bit.sf = (result >> 7) & 1;
}
static ALWAYS_INLINE void cpu_z80_sra(struct cpu_z80 *self, int lvalue0, int lvalue1) {
- abort();
+ int data = cpu_z80_read_byte(self, lvalue0);
+ int result = data | ((data << 1) & 0x100); // sign extend
+ int parity = result;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+ data = result >> 1;
+ cpu_z80_write_byte(self, lvalue0, data);
+ cpu_z80_write_byte(self, lvalue1, data); // undocumented DDCB/FDCB versions
+ self->regs.bit.cf = result & 1;
+ self->regs.bit.nf = false;
+ self->regs.bit.pvf = (parity & 2) == 0;
+ self->regs.bit.hf = false;
+ self->regs.bit.zf = (result & 0x1fe) == 0;
+ self->regs.bit.sf = result >> 8;
}
static ALWAYS_INLINE void cpu_z80_srl(struct cpu_z80 *self, int lvalue0, int lvalue1) {
- abort();
+ int data = cpu_z80_read_byte(self, lvalue0);
+ int result = data;
+ int parity = result;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+ data = result >> 1;
+ cpu_z80_write_byte(self, lvalue0, data);
+ cpu_z80_write_byte(self, lvalue1, data); // undocumented DDCB/FDCB versions
+ self->regs.bit.cf = result & 1;
+ self->regs.bit.nf = false;
+ self->regs.bit.pvf = (parity & 2) == 0;
+ self->regs.bit.hf = false;
+ self->regs.bit.zf = (result & 0x1fe) == 0;
+ self->regs.bit.sf = result >> 8;
}
static ALWAYS_INLINE void cpu_z80_sub(struct cpu_z80 *self, int rvalue) {
- abort();
+ int result0 = (self->regs.byte.a & 0xf) - (rvalue & 0xf);
+ int result1 = result0 + (self->regs.byte.a & 0x70) - (rvalue & 0x70);
+ int result2 = result1 + (self->regs.byte.a & 0x80) - (rvalue & 0x80);
+ self->regs.byte.a = result2 & 0xff;
+ self->regs.bit.cf = (result2 >> 8) & 1;
+ self->regs.bit.nf = true;
+ self->regs.bit.pvf = ((result1 >> 7) ^ (result2 >> 8)) & 1;
+ self->regs.bit.hf = (result0 >> 4) & 1;
+ self->regs.bit.zf = (result2 & 0xff) == 0;
+ self->regs.bit.sf = (result2 >> 7) & 1;
}
static ALWAYS_INLINE void cpu_z80_xor(struct cpu_z80 *self, int rvalue) {
- abort();
+ int result = self->regs.byte.a ^ rvalue;
+ int parity = result;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+ self->regs.byte.a = result;
+ self->regs.bit.cf = false;
+ self->regs.bit.nf = false;
+ self->regs.bit.pvf = (parity & 1) == 0;
+ self->regs.bit.hf = false;
+ self->regs.bit.zf = result == 0;
+ self->regs.bit.sf = result >> 7;
}
// prototypes