Implement Z80 instructions except block I/O group, can pass ZEXALL except daa
authorNick Downing <nick@ndcode.org>
Thu, 21 Jul 2022 19:27:25 +0000 (05:27 +1000)
committerNick Downing <nick@ndcode.org>
Thu, 21 Jul 2022 19:27:38 +0000 (05:27 +1000)
.gitmodules
ZEXALL
cpu_65c02.h
cpu_z80.c
cpu_z80.h
decode_z80.py
decode_z80.sed
emu_65c02.c
emu_z80.c
z80

index 686a3ca..06f6c19 100644 (file)
@@ -9,4 +9,4 @@
        url = https://github.com/nickd4/z80.git
 [submodule "ZEXALL"]
        path = ZEXALL
-       url = https://github.com/agn453/ZEXALL.git
+       url = https://github.com/nickd4/ZEXALL.git
diff --git a/ZEXALL b/ZEXALL
index aca2aa6..cfa3970 160000 (submodule)
--- a/ZEXALL
+++ b/ZEXALL
@@ -1 +1 @@
-Subproject commit aca2aa66cb19a4e675a5039c1a1c5aed1f52353e
+Subproject commit cfa397063c6be8558b17f281a84b31db6f562487
index a6b964c..4c63053 100644 (file)
@@ -230,18 +230,18 @@ static ALWAYS_INLINE int cpu_65c02_ea_zero_page_indirect_indexed(struct cpu_65c0
 static ALWAYS_INLINE void cpu_65c02_adc(struct cpu_65c02 *self, int rvalue) {
   int result0, result1, result2;
   if (self->regs.bit.df) {
-    result0 = (self->regs.byte.a & 0xf) + (rvalue & 0xf) + self->regs.bit.cf;
+    result0 = self->regs.bit.cf + (self->regs.byte.a & 0xf) + (rvalue & 0xf);
     if (result0 >= 0xa)
       result0 = (result0 + 6) & 0x1f;
     result0 += (self->regs.byte.a & 0x70) + (rvalue & 0x70);
-    result1 = (self->regs.byte.a & 0x80) + (rvalue & 0x80) + result0;
+    result1 = result0 + (self->regs.byte.a & 0x80) + (rvalue & 0x80);
     result2 = result1;
     if (result2 >= 0xa0)
       result2 = (result2 + 0x60) & 0x1ff;
   }
   else {
-    result0 = (self->regs.byte.a & 0x7f) + (rvalue & 0x7f) + self->regs.bit.cf;
-    result1 = (self->regs.byte.a & 0x80) + (rvalue & 0x80) + result0;
+    result0 = self->regs.bit.cf + (self->regs.byte.a & 0x7f) + (rvalue & 0x7f);
+    result1 = result0 + (self->regs.byte.a & 0x80) + (rvalue & 0x80);
     result2 = result1;
   }
   self->regs.byte.a = result2 & 0xff;
@@ -255,7 +255,7 @@ static ALWAYS_INLINE void cpu_65c02_and(struct cpu_65c02 *self, int rvalue) {
   int result = self->regs.byte.a & rvalue;
   self->regs.byte.a = result;
   self->regs.bit.zf = result == 0;
-  self->regs.bit.nf = (result >> 7) & 1;
+  self->regs.bit.nf = result >> 7;
 }
 
 static ALWAYS_INLINE void cpu_65c02_asl(struct cpu_65c02 *self, int lvalue) {
@@ -282,7 +282,7 @@ static ALWAYS_INLINE void cpu_65c02_bit_imm(struct cpu_65c02 *self, int rvalue)
 static ALWAYS_INLINE void cpu_65c02_bra(struct cpu_65c02 *self, bool pred, int lvalue) {
   if (pred) {
     self->cycles += ((self->regs.word.pc & 0xff) + (lvalue & 0xff)) >> 8;
-    self->regs.word.pc = (self->regs.word.pc + lvalue) & 0xffff;
+    self->regs.word.pc += lvalue;
   }
 }
 
@@ -301,7 +301,7 @@ static ALWAYS_INLINE void cpu_65c02_cl(struct cpu_65c02 *self, int n) {
 
 static ALWAYS_INLINE void cpu_65c02_cmp(struct cpu_65c02 *self, int rvalue0, int rvalue1) {
   rvalue1 ^= 0xff;
-  int result = rvalue0 + rvalue1 + 1;
+  int result = 1 + rvalue0 + rvalue1;
   self->regs.bit.cf = result >> 8;
   self->regs.bit.zf = (result & 0xff) == 0;
   self->regs.bit.nf = (result >> 7) & 1;
@@ -312,14 +312,14 @@ static ALWAYS_INLINE void cpu_65c02_dec(struct cpu_65c02 *self, int lvalue) {
   ++self->cycles;
   cpu_65c02_write_byte(self, lvalue, result);
   self->regs.bit.zf = result == 0;
-  self->regs.bit.nf = (result >> 7) & 1;
+  self->regs.bit.nf = result >> 7;
 }
 
 static ALWAYS_INLINE void cpu_65c02_eor(struct cpu_65c02 *self, int rvalue) {
   int result = self->regs.byte.a ^ rvalue;
   self->regs.byte.a = result;
   self->regs.bit.zf = result == 0;
-  self->regs.bit.nf = (result >> 7) & 1;
+  self->regs.bit.nf = result >> 7;
 }
 
 static ALWAYS_INLINE void cpu_65c02_ill11(struct cpu_65c02 *self) {
@@ -327,27 +327,27 @@ static ALWAYS_INLINE void cpu_65c02_ill11(struct cpu_65c02 *self) {
 
 static ALWAYS_INLINE void cpu_65c02_ill22(struct cpu_65c02 *self) {
   ++self->cycles;
-  self->regs.word.pc = (self->regs.word.pc + 1) & 0xffff;
+  self->regs.word.pc += 1;
 }
 
 static ALWAYS_INLINE void cpu_65c02_ill23(struct cpu_65c02 *self) {
   self->cycles += 2;
-  self->regs.word.pc = (self->regs.word.pc + 1) & 0xffff;
+  self->regs.word.pc += 1;
 }
 
 static ALWAYS_INLINE void cpu_65c02_ill24(struct cpu_65c02 *self) {
   self->cycles += 3;
-  self->regs.word.pc = (self->regs.word.pc + 1) & 0xffff;
+  self->regs.word.pc += 1;
 }
 
 static ALWAYS_INLINE void cpu_65c02_ill34(struct cpu_65c02 *self) {
   self->cycles += 3;
-  self->regs.word.pc = (self->regs.word.pc + 2) & 0xffff;
+  self->regs.word.pc += 2;
 }
 
 static ALWAYS_INLINE void cpu_65c02_ill38(struct cpu_65c02 *self) {
   self->cycles += 7;
-  self->regs.word.pc = (self->regs.word.pc + 2) & 0xffff;
+  self->regs.word.pc += 2;
 }
 
 static ALWAYS_INLINE void cpu_65c02_inc(struct cpu_65c02 *self, int lvalue) {
@@ -355,7 +355,7 @@ static ALWAYS_INLINE void cpu_65c02_inc(struct cpu_65c02 *self, int lvalue) {
   ++self->cycles;
   cpu_65c02_write_byte(self, lvalue, result);
   self->regs.bit.zf = result == 0;
-  self->regs.bit.nf = (result >> 7) & 1;
+  self->regs.bit.nf = result >> 7;
 }
 
 static ALWAYS_INLINE void cpu_65c02_jmp(struct cpu_65c02 *self, int lvalue) {
@@ -389,7 +389,7 @@ static ALWAYS_INLINE void cpu_65c02_ora(struct cpu_65c02 *self, int rvalue) {
   int result = self->regs.byte.a | rvalue;
   self->regs.byte.a = result;
   self->regs.bit.zf = result == 0;
-  self->regs.bit.nf = (result >> 7) & 1;
+  self->regs.bit.nf = result >> 7;
 }
 
 static ALWAYS_INLINE void cpu_65c02_ph(struct cpu_65c02 *self, int rvalue) {
@@ -400,7 +400,7 @@ static ALWAYS_INLINE void cpu_65c02_pl(struct cpu_65c02 *self, int lvalue) {
   int result = cpu_65c02_pop_byte(self);
   cpu_65c02_write_byte(self, lvalue, result);
   self->regs.bit.zf = result == 0;
-  self->regs.bit.nf = (result >> 7) & 1;
+  self->regs.bit.nf = result >> 7;
 }
 
 static ALWAYS_INLINE void cpu_65c02_plp(struct cpu_65c02 *self) {
@@ -414,7 +414,7 @@ static ALWAYS_INLINE void cpu_65c02_rmb(struct cpu_65c02 *self, int n, int lvalu
 }
 
 static ALWAYS_INLINE void cpu_65c02_rol(struct cpu_65c02 *self, int lvalue) {
-  int result = (cpu_65c02_read_byte(self, lvalue) << 1) | self->regs.bit.cf;
+  int result = self->regs.bit.cf | (cpu_65c02_read_byte(self, lvalue) << 1);
   ++self->cycles;
   cpu_65c02_write_byte(self, lvalue, result & 0xff);
   self->regs.bit.cf = result >> 8;
@@ -444,18 +444,18 @@ static ALWAYS_INLINE void cpu_65c02_sbc(struct cpu_65c02 *self, int rvalue) {
   rvalue ^= 0xff;
   int result0, result1, result2;
   if (self->regs.bit.df) {
-    result0 = (self->regs.byte.a & 0xf) + (rvalue & 0xf) + self->regs.bit.cf;
+    result0 = self->regs.bit.cf + (self->regs.byte.a & 0xf) + (rvalue & 0xf);
     if (result0 < 0x10)
       result0 = (result0 - 6) & 0x1f;
     result0 += (self->regs.byte.a & 0x70) + (rvalue & 0x70);
-    result1 = (self->regs.byte.a & 0x80) + (rvalue & 0x80) + result0;
+    result1 = result0 + (self->regs.byte.a & 0x80) + (rvalue & 0x80);
     result2 = result1;
     if (result2 < 0x100)
       result2 = (result2 - 0x60) & 0x1ff;
   }
   else {
-    result0 = (self->regs.byte.a & 0x7f) + (rvalue & 0x7f) + self->regs.bit.cf;
-    result1 = (self->regs.byte.a & 0x80) + (rvalue & 0x80) + result0;
+    result0 = self->regs.bit.cf + (self->regs.byte.a & 0x7f) + (rvalue & 0x7f);
+    result1 = result0 + (self->regs.byte.a & 0x80) + (rvalue & 0x80);
     result2 = result1;
   }
   self->regs.byte.a = result2 & 0xff;
index 6a866bf..818d8d0 100644 (file)
--- a/cpu_z80.c
+++ b/cpu_z80.c
@@ -681,7 +681,7 @@ void cpu_z80_execute(struct cpu_z80 *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));
@@ -696,19 +696,19 @@ void cpu_z80_execute(struct cpu_z80 *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);
@@ -720,19 +720,19 @@ void cpu_z80_execute(struct cpu_z80 *self) {
     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);
@@ -2232,7 +2232,7 @@ void cpu_z80_execute_dd(struct cpu_z80 *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));
@@ -2247,19 +2247,19 @@ void cpu_z80_execute_dd(struct cpu_z80 *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);
@@ -2271,19 +2271,19 @@ void cpu_z80_execute_dd(struct cpu_z80 *self) {
     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);
@@ -3314,7 +3314,7 @@ void cpu_z80_execute_ed(struct cpu_z80 *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);
@@ -3338,7 +3338,7 @@ void cpu_z80_execute_ed(struct cpu_z80 *self) {
     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);
@@ -3362,7 +3362,7 @@ void cpu_z80_execute_ed(struct cpu_z80 *self) {
     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);
@@ -3386,7 +3386,7 @@ void cpu_z80_execute_ed(struct cpu_z80 *self) {
     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);
@@ -3410,7 +3410,7 @@ void cpu_z80_execute_ed(struct cpu_z80 *self) {
     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);
@@ -3434,7 +3434,7 @@ void cpu_z80_execute_ed(struct cpu_z80 *self) {
     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);
@@ -3458,7 +3458,7 @@ void cpu_z80_execute_ed(struct cpu_z80 *self) {
     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);
@@ -3482,7 +3482,7 @@ void cpu_z80_execute_ed(struct cpu_z80 *self) {
     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);
@@ -4572,19 +4572,19 @@ void cpu_z80_execute_fd(struct cpu_z80 *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_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);
@@ -4596,19 +4596,19 @@ void cpu_z80_execute_fd(struct cpu_z80 *self) {
     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);
index c465c5e..2293f08 100644 (file)
--- a/cpu_z80.h
+++ b/cpu_z80.h
@@ -19,9 +19,8 @@
 #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)
@@ -49,7 +48,8 @@
 #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;
@@ -82,7 +86,8 @@ union cpu_z80_regs {
     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;
@@ -105,7 +110,8 @@ union cpu_z80_regs {
     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;
@@ -146,7 +152,11 @@ union cpu_z80_regs {
     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;
@@ -169,7 +179,8 @@ union cpu_z80_regs {
     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;
@@ -186,7 +197,8 @@ union cpu_z80_regs {
     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
@@ -278,87 +290,240 @@ static ALWAYS_INLINE int cpu_z80_displacement(struct cpu_z80 *self, int base) {
 
 // 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) {
@@ -370,19 +535,42 @@ static ALWAYS_INLINE void cpu_z80_ill(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) {
@@ -402,47 +590,96 @@ static ALWAYS_INLINE void cpu_z80_inir(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) {
@@ -454,7 +691,7 @@ static ALWAYS_INLINE void cpu_z80_otir(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) {
@@ -466,107 +703,312 @@ static ALWAYS_INLINE void cpu_z80_outi(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
index d5292c4..9fcd053 100755 (executable)
@@ -188,8 +188,8 @@ word_lvalue_modes = {
   'nc': '!self->regs.bit.cf',
   'm': 'self->regs.bit.sf',
   'p': '!self->regs.bit.sf',
-  'po': 'self->regs.bit.pvf',
-  'pe': '!self->regs.bit.pvf',
+  'pe': 'self->regs.bit.pvf',
+  'po': '!self->regs.bit.pvf',
 }
 
 # opcodes allowing predication need a "true" parameter when not predicated
index 295e01c..b438d56 100644 (file)
@@ -1,6 +1,8 @@
 s/cpu_z80_rst(self/cpu_z80_call(self, true/
 s/(self, true, \(!\?self->regs\.bit\.\)/(self, \1/
-s/cpu_z80_in(self, CPU_Z80_EA_F/cpu_z80_in(self, CPU_Z80_EA_NONE/
+s/cpu_z80_in(self/cpu_z80_in_test(self/
+s/cpu_z80_in_test(self\(, CPU_Z80_EA_A, cpu_z80_in_byte(self, cpu_z80_fetch_byte(self))\))/cpu_z80_in(self\1)/
+s/cpu_z80_in_test(self, CPU_Z80_EA_F/cpu_z80_in_test(self, CPU_Z80_EA_NONE/
 s/^    \(cpu_z80_ld_byte(self, \)\(cpu_z80_displacement(self, self->regs\.word\.i[xy])\)\(, cpu_z80_fetch_byte(self));\)$/    {\n      int ea = \2;\n      \1ea\3\n    }/
 s/^    cpu_z80_exx(self);$/    cpu_z80_ex(self, CPU_Z80_EA_BC, CPU_Z80_EA_BC_PRIME);\n    cpu_z80_ex(self, CPU_Z80_EA_DE, CPU_Z80_EA_DE_PRIME);\n    cpu_z80_ex(self, CPU_Z80_EA_HL, CPU_Z80_EA_HL_PRIME);/
 /^void cpu_z80_execute_dd_cb(struct cpu_z80 \*self) {$/,/^}$/s/cpu_z80_displacement(self, self->regs\.word\.ix)/ea/
index 32defe1..876a3a3 100644 (file)
@@ -134,7 +134,7 @@ int load_ihx(char *name) {
 int read_byte(int addr) {
 #if MEM_TRACE
   int data = mem[addr];
-  printf("addr=%04x rd=%02x\n", addr, data);
+  fprintf(stderr, "addr=%04x rd=%02x\n", addr, data);
   return data;
 #else
   return mem[addr];
@@ -143,7 +143,7 @@ int read_byte(int addr) {
 
 void write_byte(int addr, int data) {
 #if MEM_TRACE
-  printf("addr=%04x wr=%02x\n", addr, data);
+  fprintf(stderr, "addr=%04x wr=%02x\n", addr, data);
 #endif
   mem[addr] = data;
 }
@@ -155,12 +155,12 @@ uint8_t mem_read(uint16_t addr, bool isDbg) {
 
 void mem_write(uint16_t addr, uint8_t val) {
   write_byte(addr, val);
-} 
+}
 #endif
 
 int main(int argc, char **argv) {
   if (argc < 2) {
-    fprintf(stderr, "usage: %s image.ihx\n", argv[0]);
+    printf("usage: %s image.ihx\n", argv[0]);
     exit(EXIT_FAILURE);
   }
   int entry_point = load_ihx(argv[1]);
@@ -177,7 +177,8 @@ int main(int argc, char **argv) {
 
   while (true) {
 #if REG_TRACE
-    printf(
+    fprintf(
+      stderr,
       "pc=%04x a=%02x x=%02x y=%02x p=%02x s=%02x cf=%d zf=%d if=%d df=%d vf=%d nf=%d\n",
       vrEmu6502GetPC(cpu),
       vrEmu6502GetAcc(cpu),
@@ -209,7 +210,8 @@ int main(int argc, char **argv) {
 
   while (true) {
 #if REG_TRACE
-    printf(
+    fprintf(
+      stderr,
       "pc=%04x a=%02x x=%02x y=%02x p=%02x s=%02x cf=%d zf=%d if=%d df=%d vf=%d nf=%d\n",
       cpu.regs.word.pc,
       cpu.regs.byte.a,
index f408691..40409d7 100644 (file)
--- a/emu_z80.c
+++ b/emu_z80.c
@@ -161,7 +161,7 @@ int bdos(int c, int de) {
 int read_byte(int addr) {
 #if MEM_TRACE
   int data = mem[addr];
-  printf("addr=%04x rd=%02x\n", addr, data);
+  fprintf(stderr, "addr=%04x rd=%02x\n", addr, data);
   return data;
 #else
   return mem[addr];
@@ -170,7 +170,7 @@ int read_byte(int addr) {
 
 void write_byte(int addr, int data) {
 #if MEM_TRACE
-  printf("addr=%04x wr=%02x\n", addr, data);
+  fprintf(stderr, "addr=%04x wr=%02x\n", addr, data);
 #endif
   mem[addr] = data;
 }
@@ -214,7 +214,7 @@ void out(z80 *const z, uint8_t port, uint8_t val) {
 
 int main(int argc, char **argv) {
   if (argc < 2) {
-    fprintf(stderr, "usage: %s image.ihx\n", argv[0]);
+    printf("usage: %s image.ihx\n", argv[0]);
     exit(EXIT_FAILURE);
   }
   int entry_point = load_ihx(argv[1]);
@@ -234,16 +234,19 @@ int main(int argc, char **argv) {
 
   while (true) {
 #if REG_TRACE
-    printf(
-      "pc=%04x af=%04x bc=%04x de=%04x hl=%04x sp=%04x ix=%04x iy=%04x cf=%d nf=%d pv=%d hf=%d zf=%d sf=%d\n",
+    fprintf(
+      stderr,
+      "pc=%04x af=%04x bc=%04x de=%04x hl=%04x sp=%04x ix=%04x iy=%04x cf=%d nf=%d pvf=%d hf=%d zf=%d sf=%d\n",
       cpu.pc,
       cpu.cf |
       (cpu.nf << 1) |
       (cpu.pf << 2) |
+      (cpu.xf << 3) |
       (cpu.hf << 4) |
+      (cpu.yf << 5) |
       (cpu.zf << 6) |
       (cpu.sf << 7) |
-      (cpu.a << 8), 
+      (cpu.a << 8),
       cpu.c | (cpu.b << 8),
       cpu.e | (cpu.d << 8),
       cpu.l | (cpu.h << 8),
@@ -274,26 +277,29 @@ int main(int argc, char **argv) {
 #else
   struct cpu_z80 cpu;
   cpu_z80_init(&cpu, read_byte, write_byte, in_byte, out_byte);
+  cpu.regs.word.af = 0xffff;
+  cpu.regs.word.sp = 0xffff;
   cpu.regs.word.pc = entry_point;
 
   while (true) {
 #if REG_TRACE
-    printf(
-      "pc=%04x af=%04x bc=%04x de=%04x hl=%04x sp=%04x ix=%04x iy=%04x cf=%d nf=%d pv=%d hf=%d zf=%d sf=%d\n",
-      cpu.pc,
-      cpu.regs[CPU_Z80_REG_AF] | (cpu.regs[CPU_REG_AF + 1] << 8),
-      cpu.regs[CPU_Z80_REG_BC] | (cpu.regs[CPU_REG_BC + 1] << 8),
-      cpu.regs[CPU_Z80_REG_DE] | (cpu.regs[CPU_REG_DE + 1] << 8),
-      cpu.regs[CPU_Z80_REG_HL] | (cpu.regs[CPU_REG_HL + 1] << 8),
-      cpu.regs[CPU_Z80_REG_SP] | (cpu.regs[CPU_REG_SP + 1] << 8),
-      cpu.regs[CPU_Z80_REG_IX] | (cpu.regs[CPU_REG_IX + 1] << 8),
-      cpu.regs[CPU_Z80_REG_IY] | (cpu.regs[CPU_REG_IY + 1] << 8),
-      (cpu.regs[CPU_Z80_REG_F] >> CPU_Z80_BIT_CF) & 1,
-      (cpu.regs[CPU_Z80_REG_F] >> CPU_Z80_BIT_NF) & 1,
-      (cpu.regs[CPU_Z80_REG_F] >> CPU_Z80_BIT_PV) & 1,
-      (cpu.regs[CPU_Z80_REG_F] >> CPU_Z80_BIT_HF) & 1,
-      (cpu.regs[CPU_Z80_REG_F] >> CPU_Z80_BIT_ZF) & 1,
-      (cpu.regs[CPU_Z80_REG_F] >> CPU_Z80_BIT_SF) & 1
+    fprintf(
+      stderr,
+      "pc=%04x af=%04x bc=%04x de=%04x hl=%04x sp=%04x ix=%04x iy=%04x cf=%d nf=%d pvf=%d hf=%d zf=%d sf=%d\n",
+      cpu.regs.word.pc,
+      cpu.regs.word.af,
+      cpu.regs.word.bc,
+      cpu.regs.word.de,
+      cpu.regs.word.hl,
+      cpu.regs.word.sp,
+      cpu.regs.word.ix,
+      cpu.regs.word.iy,
+      cpu.regs.bit.cf,
+      cpu.regs.bit.nf,
+      cpu.regs.bit.pvf,
+      cpu.regs.bit.hf,
+      cpu.regs.bit.zf,
+      cpu.regs.bit.sf
     );
 #endif
 
diff --git a/z80 b/z80
index ae62511..c71125c 160000 (submodule)
--- a/z80
+++ b/z80
@@ -1 +1 @@
-Subproject commit ae625116f1f9b013fd1a69d0173f8207f8703e21
+Subproject commit c71125cbae01edb1b7d1bd9ef27d9797023f9106