summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile6
-rw-r--r--z80inst.c453
-rw-r--r--z80inst.h118
-rw-r--r--zdis.c193
4 files changed, 770 insertions, 0 deletions
diff --git a/Makefile b/Makefile
index a7f7cb3..9000363 100644
--- a/Makefile
+++ b/Makefile
@@ -7,6 +7,9 @@ blastem : blastem.o 68kinst.o gen_x86.o m68k_to_x86.o runtime.o mem.o vdp.o rend
dis : dis.o 68kinst.o
$(CC) -o dis dis.o 68kinst.o
+
+zdis : zdis.o z80inst.o
+ $(CC) -o zdis zdis.o z80inst.o
trans : trans.o 68kinst.o gen_x86.o m68k_to_x86.o runtime.o mem.o
$(CC) -o trans trans.o 68kinst.o gen_x86.o m68k_to_x86.o runtime.o mem.o
@@ -29,5 +32,8 @@ gen_fib : gen_fib.o gen_x86.o mem.o
%.bin : %.s68
vasmm68k_mot -Fbin -m68000 -no-opt -spaces -o $@ $<
+%.bin : %.sz8
+ vasmz80_mot -Fbin -spaces -o $@ $<
+
clean :
rm -rf dis trans stateview test_x86 gen_fib *.o
diff --git a/z80inst.c b/z80inst.c
new file mode 100644
index 0000000..370f574
--- /dev/null
+++ b/z80inst.c
@@ -0,0 +1,453 @@
+#include "z80inst.h"
+#include <string.h>
+#include <stdio.h>
+
+z80inst z80_tbl_a[256] = {
+ //0
+ {Z80_NOP, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_LD, Z80_BC, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_LD, Z80_A, Z80_REG_INDIRECT | Z80_DIR, Z80_BC, 0},
+ {Z80_INC, Z80_BC, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_INC, Z80_B, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_DEC, Z80_B, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_LD, Z80_B, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_RLC, Z80_A, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_EX, Z80_AF, Z80_REG, Z80_AF, 0},
+ {Z80_ADD, Z80_HL, Z80_REG, Z80_BC, 0},
+ {Z80_LD, Z80_A, Z80_REG_INDIRECT, Z80_BC, 0},
+ {Z80_DEC, Z80_BC, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_INC, Z80_C, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_DEC, Z80_C, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_LD, Z80_C, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_RRC, Z80_A, Z80_UNUSED, Z80_UNUSED, 0},
+ //1
+ {Z80_DJNZ, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_LD, Z80_DE, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_LD, Z80_A, Z80_REG_INDIRECT | Z80_DIR, Z80_DE, 0},
+ {Z80_INC, Z80_DE, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_INC, Z80_D, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_DEC, Z80_D, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_LD, Z80_D, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_RL, Z80_A, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_JR, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_ADD, Z80_HL, Z80_REG, Z80_DE, 0},
+ {Z80_LD, Z80_A, Z80_REG_INDIRECT, Z80_DE, 0},
+ {Z80_DEC, Z80_DE, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_INC, Z80_E, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_DEC, Z80_E, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_LD, Z80_E, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_RR, Z80_A, Z80_UNUSED, Z80_UNUSED, 0},
+ //2
+ {Z80_JRCC, Z80_CC_NZ, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_LD, Z80_HL, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_LD, Z80_HL, Z80_IMMED_INDIRECT | Z80_DIR, Z80_UNUSED, 0},
+ {Z80_INC, Z80_HL, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_INC, Z80_H, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_DEC, Z80_H, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_LD, Z80_H, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_DAA, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_JRCC, Z80_CC_Z, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_ADD, Z80_HL, Z80_REG, Z80_HL, 0},
+ {Z80_LD, Z80_HL, Z80_IMMED_INDIRECT, Z80_IMMED, 0},
+ {Z80_DEC, Z80_HL, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_INC, Z80_L, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_DEC, Z80_L, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_LD, Z80_L, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_CPL, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
+ //3
+ {Z80_JRCC, Z80_CC_NC, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_LD, Z80_SP, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_LD, Z80_A, Z80_IMMED_INDIRECT | Z80_DIR, Z80_UNUSED, 0},
+ {Z80_INC, Z80_SP, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_INC, Z80_UNUSED, Z80_REG_INDIRECT, Z80_HL, 0},
+ {Z80_DEC, Z80_UNUSED, Z80_REG_INDIRECT, Z80_HL, 0},
+ {Z80_LD, Z80_USE_IMMED, Z80_REG_INDIRECT | Z80_DIR, Z80_HL, 0},
+ {Z80_SCF, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_JRCC, Z80_CC_C, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_ADD, Z80_HL, Z80_REG, Z80_SP, 0},
+ {Z80_LD, Z80_A, Z80_IMMED_INDIRECT, Z80_IMMED, 0},
+ {Z80_DEC, Z80_SP, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_INC, Z80_A, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_DEC, Z80_A, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_LD, Z80_A, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_CCF, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
+ //4
+ {Z80_LD, Z80_B, Z80_REG, Z80_B, 0},
+ {Z80_LD, Z80_B, Z80_REG, Z80_C, 0},
+ {Z80_LD, Z80_B, Z80_REG, Z80_D, 0},
+ {Z80_LD, Z80_B, Z80_REG, Z80_E, 0},
+ {Z80_LD, Z80_B, Z80_REG, Z80_H, 0},
+ {Z80_LD, Z80_B, Z80_REG, Z80_L, 0},
+ {Z80_LD, Z80_B, Z80_REG_INDIRECT, Z80_HL, 0},
+ {Z80_LD, Z80_B, Z80_REG, Z80_A, 0},
+ {Z80_LD, Z80_C, Z80_REG, Z80_B, 0},
+ {Z80_LD, Z80_C, Z80_REG, Z80_C, 0},
+ {Z80_LD, Z80_C, Z80_REG, Z80_D, 0},
+ {Z80_LD, Z80_C, Z80_REG, Z80_E, 0},
+ {Z80_LD, Z80_C, Z80_REG, Z80_H, 0},
+ {Z80_LD, Z80_C, Z80_REG, Z80_L, 0},
+ {Z80_LD, Z80_C, Z80_REG_INDIRECT, Z80_HL, 0},
+ {Z80_LD, Z80_C, Z80_REG, Z80_A, 0},
+ //5
+ {Z80_LD, Z80_D, Z80_REG, Z80_B, 0},
+ {Z80_LD, Z80_D, Z80_REG, Z80_C, 0},
+ {Z80_LD, Z80_D, Z80_REG, Z80_D, 0},
+ {Z80_LD, Z80_D, Z80_REG, Z80_E, 0},
+ {Z80_LD, Z80_D, Z80_REG, Z80_H, 0},
+ {Z80_LD, Z80_D, Z80_REG, Z80_L, 0},
+ {Z80_LD, Z80_D, Z80_REG_INDIRECT, Z80_HL, 0},
+ {Z80_LD, Z80_D, Z80_REG, Z80_A, 0},
+ {Z80_LD, Z80_E, Z80_REG, Z80_B, 0},
+ {Z80_LD, Z80_E, Z80_REG, Z80_C, 0},
+ {Z80_LD, Z80_E, Z80_REG, Z80_D, 0},
+ {Z80_LD, Z80_E, Z80_REG, Z80_E, 0},
+ {Z80_LD, Z80_E, Z80_REG, Z80_H, 0},
+ {Z80_LD, Z80_E, Z80_REG, Z80_L, 0},
+ {Z80_LD, Z80_E, Z80_REG_INDIRECT, Z80_HL, 0},
+ {Z80_LD, Z80_E, Z80_REG, Z80_A, 0},
+ //6
+ {Z80_LD, Z80_H, Z80_REG, Z80_B, 0},
+ {Z80_LD, Z80_H, Z80_REG, Z80_C, 0},
+ {Z80_LD, Z80_H, Z80_REG, Z80_D, 0},
+ {Z80_LD, Z80_H, Z80_REG, Z80_E, 0},
+ {Z80_LD, Z80_H, Z80_REG, Z80_H, 0},
+ {Z80_LD, Z80_H, Z80_REG, Z80_L, 0},
+ {Z80_LD, Z80_H, Z80_REG_INDIRECT, Z80_HL, 0},
+ {Z80_LD, Z80_H, Z80_REG, Z80_A, 0},
+ {Z80_LD, Z80_L, Z80_REG, Z80_B, 0},
+ {Z80_LD, Z80_L, Z80_REG, Z80_C, 0},
+ {Z80_LD, Z80_L, Z80_REG, Z80_D, 0},
+ {Z80_LD, Z80_L, Z80_REG, Z80_E, 0},
+ {Z80_LD, Z80_L, Z80_REG, Z80_H, 0},
+ {Z80_LD, Z80_L, Z80_REG, Z80_L, 0},
+ {Z80_LD, Z80_L, Z80_REG_INDIRECT, Z80_HL, 0},
+ {Z80_LD, Z80_L, Z80_REG, Z80_A, 0},
+ //7
+ {Z80_LD, Z80_B, Z80_REG_INDIRECT | Z80_DIR, Z80_HL, 0},
+ {Z80_LD, Z80_C, Z80_REG_INDIRECT | Z80_DIR, Z80_HL, 0},
+ {Z80_LD, Z80_D, Z80_REG_INDIRECT | Z80_DIR, Z80_HL, 0},
+ {Z80_LD, Z80_E, Z80_REG_INDIRECT | Z80_DIR, Z80_HL, 0},
+ {Z80_LD, Z80_H, Z80_REG_INDIRECT | Z80_DIR, Z80_HL, 0},
+ {Z80_LD, Z80_L, Z80_REG_INDIRECT | Z80_DIR, Z80_HL, 0},
+ {Z80_HALT, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_LD, Z80_A, Z80_REG_INDIRECT | Z80_DIR, Z80_HL, 0},
+ {Z80_LD, Z80_A, Z80_REG, Z80_B, 0},
+ {Z80_LD, Z80_A, Z80_REG, Z80_C, 0},
+ {Z80_LD, Z80_A, Z80_REG, Z80_D, 0},
+ {Z80_LD, Z80_A, Z80_REG, Z80_E, 0},
+ {Z80_LD, Z80_A, Z80_REG, Z80_H, 0},
+ {Z80_LD, Z80_A, Z80_REG, Z80_L, 0},
+ {Z80_LD, Z80_A, Z80_REG_INDIRECT, Z80_HL, 0},
+ {Z80_LD, Z80_A, Z80_REG, Z80_A, 0},
+ //8
+ {Z80_ADD, Z80_A, Z80_REG, Z80_B, 0},
+ {Z80_ADD, Z80_A, Z80_REG, Z80_C, 0},
+ {Z80_ADD, Z80_A, Z80_REG, Z80_D, 0},
+ {Z80_ADD, Z80_A, Z80_REG, Z80_E, 0},
+ {Z80_ADD, Z80_A, Z80_REG, Z80_H, 0},
+ {Z80_ADD, Z80_A, Z80_REG, Z80_L, 0},
+ {Z80_ADD, Z80_A, Z80_REG_INDIRECT, Z80_HL, 0},
+ {Z80_ADD, Z80_A, Z80_REG, Z80_A, 0},
+ {Z80_ADC, Z80_A, Z80_REG, Z80_B, 0},
+ {Z80_ADC, Z80_A, Z80_REG, Z80_C, 0},
+ {Z80_ADC, Z80_A, Z80_REG, Z80_D, 0},
+ {Z80_ADC, Z80_A, Z80_REG, Z80_E, 0},
+ {Z80_ADC, Z80_A, Z80_REG, Z80_H, 0},
+ {Z80_ADC, Z80_A, Z80_REG, Z80_L, 0},
+ {Z80_ADC, Z80_A, Z80_REG_INDIRECT, Z80_HL, 0},
+ {Z80_ADC, Z80_A, Z80_REG, Z80_A, 0},
+ //9
+ {Z80_SUB, Z80_A, Z80_REG, Z80_B, 0},
+ {Z80_SUB, Z80_A, Z80_REG, Z80_C, 0},
+ {Z80_SUB, Z80_A, Z80_REG, Z80_D, 0},
+ {Z80_SUB, Z80_A, Z80_REG, Z80_E, 0},
+ {Z80_SUB, Z80_A, Z80_REG, Z80_H, 0},
+ {Z80_SUB, Z80_A, Z80_REG, Z80_L, 0},
+ {Z80_SUB, Z80_A, Z80_REG_INDIRECT, Z80_HL, 0},
+ {Z80_SUB, Z80_A, Z80_REG, Z80_A, 0},
+ {Z80_SBC, Z80_A, Z80_REG, Z80_B, 0},
+ {Z80_SBC, Z80_A, Z80_REG, Z80_C, 0},
+ {Z80_SBC, Z80_A, Z80_REG, Z80_D, 0},
+ {Z80_SBC, Z80_A, Z80_REG, Z80_E, 0},
+ {Z80_SBC, Z80_A, Z80_REG, Z80_H, 0},
+ {Z80_SBC, Z80_A, Z80_REG, Z80_L, 0},
+ {Z80_SBC, Z80_A, Z80_REG_INDIRECT, Z80_HL, 0},
+ {Z80_SBC, Z80_A, Z80_REG, Z80_A, 0},
+ //A
+ {Z80_AND, Z80_A, Z80_REG, Z80_B, 0},
+ {Z80_AND, Z80_A, Z80_REG, Z80_C, 0},
+ {Z80_AND, Z80_A, Z80_REG, Z80_D, 0},
+ {Z80_AND, Z80_A, Z80_REG, Z80_E, 0},
+ {Z80_AND, Z80_A, Z80_REG, Z80_H, 0},
+ {Z80_AND, Z80_A, Z80_REG, Z80_L, 0},
+ {Z80_AND, Z80_A, Z80_REG_INDIRECT, Z80_HL, 0},
+ {Z80_AND, Z80_A, Z80_REG, Z80_A, 0},
+ {Z80_XOR, Z80_A, Z80_REG, Z80_B, 0},
+ {Z80_XOR, Z80_A, Z80_REG, Z80_C, 0},
+ {Z80_XOR, Z80_A, Z80_REG, Z80_D, 0},
+ {Z80_XOR, Z80_A, Z80_REG, Z80_E, 0},
+ {Z80_XOR, Z80_A, Z80_REG, Z80_H, 0},
+ {Z80_XOR, Z80_A, Z80_REG, Z80_L, 0},
+ {Z80_XOR, Z80_A, Z80_REG_INDIRECT, Z80_HL, 0},
+ {Z80_XOR, Z80_A, Z80_REG, Z80_A, 0},
+ //B
+ {Z80_OR, Z80_A, Z80_REG, Z80_B, 0},
+ {Z80_OR, Z80_A, Z80_REG, Z80_C, 0},
+ {Z80_OR, Z80_A, Z80_REG, Z80_D, 0},
+ {Z80_OR, Z80_A, Z80_REG, Z80_E, 0},
+ {Z80_OR, Z80_A, Z80_REG, Z80_H, 0},
+ {Z80_OR, Z80_A, Z80_REG, Z80_L, 0},
+ {Z80_OR, Z80_A, Z80_REG_INDIRECT, Z80_HL, 0},
+ {Z80_OR, Z80_A, Z80_REG, Z80_A, 0},
+ {Z80_OR, Z80_CP, Z80_REG, Z80_B, 0},
+ {Z80_OR, Z80_CP, Z80_REG, Z80_C, 0},
+ {Z80_OR, Z80_CP, Z80_REG, Z80_D, 0},
+ {Z80_OR, Z80_CP, Z80_REG, Z80_E, 0},
+ {Z80_OR, Z80_CP, Z80_REG, Z80_H, 0},
+ {Z80_OR, Z80_CP, Z80_REG, Z80_L, 0},
+ {Z80_OR, Z80_CP, Z80_REG_INDIRECT, Z80_HL, 0},
+ {Z80_OR, Z80_CP, Z80_REG, Z80_A, 0},
+ //C
+ {Z80_RETCC, Z80_CC_NZ, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_POP, Z80_BC, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_JPCC, Z80_CC_NZ, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_JP, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_CALLCC, Z80_CC_NZ, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_PUSH, Z80_BC, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_ADD, Z80_A, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_RST, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 0x0},
+ {Z80_RETCC, Z80_CC_Z, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_RET, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_JPCC, Z80_CC_Z, Z80_IMMED, Z80_UNUSED, 0},
+ {0, 0, 0, 0, 0},//BITS Prefix
+ {Z80_CALLCC, Z80_CC_Z, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_CALL, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_ADC, Z80_A, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_RST, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 0x8},
+ //D
+ {Z80_RETCC, Z80_CC_NC, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_POP, Z80_DE, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_JPCC, Z80_CC_NC, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_OUT, Z80_A, Z80_IMMED_INDIRECT, Z80_UNUSED, 0},
+ {Z80_CALLCC, Z80_CC_NC, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_PUSH, Z80_DE, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_SUB, Z80_A, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_RST, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 0x10},
+ {Z80_RETCC, Z80_CC_C, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_EXX, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_JPCC, Z80_CC_C, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_IN, Z80_A, Z80_IMMED_INDIRECT, Z80_UNUSED, 0},
+ {Z80_CALLCC, Z80_CC_C, Z80_IMMED, Z80_UNUSED, 0},
+ {0, 0, 0, 0, 0},//IX Prefix
+ {Z80_SBC, Z80_A, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_RST, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 0x18},
+ //E
+ {Z80_RETCC, Z80_CC_PO, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_POP, Z80_HL, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_JPCC, Z80_CC_PO, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_EX, Z80_HL, Z80_REG_INDIRECT | Z80_DIR, Z80_SP, 0},
+ {Z80_CALLCC, Z80_CC_PO, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_PUSH, Z80_HL, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_AND, Z80_A, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_RST, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 0x20},
+ {Z80_RETCC, Z80_CC_PE, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_JP, Z80_UNUSED, Z80_REG_INDIRECT, Z80_HL, 0},
+ {Z80_JPCC, Z80_CC_PE, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_EX, Z80_DE, Z80_REG, Z80_HL, 0},
+ {Z80_CALLCC, Z80_CC_PE, Z80_IMMED, Z80_UNUSED, 0},
+ {0, 0, 0, 0, 0},//EXTD Prefix
+ {Z80_XOR, Z80_A, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_RST, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 0x28},
+ //F
+ {Z80_RETCC, Z80_CC_P, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_POP, Z80_AF, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_JPCC, Z80_CC_P, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_DI, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_CALLCC, Z80_CC_P, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_PUSH, Z80_AF, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_OR, Z80_A, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_RST, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 0x30},
+ {Z80_RETCC, Z80_CC_M, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_LD, Z80_SP, Z80_REG, Z80_HL, 0},
+ {Z80_JPCC, Z80_CC_M, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_EI, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
+ {Z80_CALLCC, Z80_CC_M, Z80_IMMED, Z80_UNUSED, 0},
+ {0, 0, 0, 0, 0},//IY Prefix
+ {Z80_CP, Z80_A, Z80_IMMED, Z80_UNUSED, 0},
+ {Z80_RST, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 0x38}
+};
+
+uint8_t * z80_decode(uint8_t * istream, z80inst * decoded)
+{
+ if (*istream == 0xCB) {
+ } else if (*istream == 0xDD) {
+ } else if (*istream == 0xED) {
+ } else if (*istream == 0xFD) {
+ } else {
+ memcpy(decoded, z80_tbl_a + *istream, sizeof(z80inst));
+ if (decoded->addr_mode == Z80_IMMED && decoded->op != Z80_RST) {
+ decoded->immed = *(++istream);
+ if (decoded->reg >= Z80_BC) {
+ decoded->immed |= *(++istream) << 8;
+ } else if (decoded->immed & 0x80) {
+ decoded->immed |= 0xFF00;
+ }
+ } else if (decoded->addr_mode == Z80_IMMED_INDIRECT) {
+ decoded->immed = *(++istream);
+ if (decoded->op != Z80_OUT && decoded->op != Z80_IN) {
+ decoded->immed |= *(++istream) << 8;
+ }
+ } else if (decoded->reg == Z80_USE_IMMED) {
+ decoded->immed = *(++istream);
+ }
+ }
+ return istream+1;
+}
+
+char *z80_mnemonics[Z80_OTDR+1] = {
+ "ld",
+ "push",
+ "pop",
+ "ex",
+ "exx",
+ "ldi",
+ "ldir",
+ "ldd",
+ "lddr",
+ "cpi",
+ "cpir",
+ "cpd",
+ "cpdr",
+ "add",
+ "adc",
+ "sub",
+ "sbc",
+ "and",
+ "or",
+ "xor",
+ "cp",
+ "inc",
+ "dec",
+ "daa",
+ "cpl",
+ "neg",
+ "ccf",
+ "scf",
+ "nop",
+ "halt",
+ "di",
+ "ei",
+ "im",
+ "rlc",
+ "rl",
+ "rrc",
+ "rr",
+ "sl",
+ "rld",
+ "rrd",
+ "bit",
+ "set",
+ "res",
+ "jp",
+ "jp",
+ "jr",
+ "jr",
+ "djnz",
+ "call",
+ "call",
+ "ret",
+ "ret",
+ "reti",
+ "retn",
+ "rst",
+ "in",
+ "ini",
+ "inir",
+ "indr",
+ "out",
+ "outi",
+ "otir",
+ "outd",
+ "otdr"
+};
+
+char * z80_regs[Z80_USE_IMMED] = {
+ "b",
+ "c",
+ "d",
+ "e",
+ "h",
+ "l",
+ "",
+ "a",
+ "bc",
+ "de",
+ "hl",
+ "sp",
+ "af",
+};
+
+char * z80_conditions[Z80_CC_M+1] = {
+ "nz",
+ "z",
+ "nc",
+ "c",
+ "po",
+ "pe",
+ "p",
+ "m"
+};
+
+int z80_disasm(z80inst * decoded, char * dst)
+{
+ int len = sprintf(dst, "%s", z80_mnemonics[decoded->op]);
+ if (decoded->addr_mode & Z80_DIR) {
+ switch (decoded->addr_mode)
+ {
+ case Z80_REG:
+ len += sprintf(dst+len, " %s", z80_regs[decoded->ea_reg]);
+ break;
+ case Z80_REG_INDIRECT:
+ len += sprintf(dst+len, " (%s)", z80_regs[decoded->ea_reg]);
+ break;
+ case Z80_IMMED:
+ len += sprintf(dst+len, " %d", decoded->immed);
+ break;
+ case Z80_IMMED_INDIRECT:
+ len += sprintf(dst+len, " (%d)", decoded->immed);
+ break;
+ }
+ if (decoded->reg != Z80_UNUSED) {
+ if (decoded->op == Z80_JRCC || decoded->op == Z80_JPCC || decoded->op == Z80_CALLCC || decoded->op == Z80_RETCC) {
+ len += sprintf(dst+len, "%s %s", decoded->reg == Z80_UNUSED ? "" : "," , z80_conditions[decoded->reg]);
+ } else {
+ len += sprintf(dst+len, "%s %s", decoded->reg == Z80_UNUSED ? "" : "," , z80_regs[decoded->reg]);
+ }
+ }
+ } else {
+ if (decoded->reg != Z80_UNUSED) {
+ if (decoded->op == Z80_JRCC || decoded->op == Z80_JPCC || decoded->op == Z80_CALLCC || decoded->op == Z80_RETCC) {
+ len += sprintf(dst+len, " %s", z80_conditions[decoded->reg]);
+ } else {
+ len += sprintf(dst+len, " %s", z80_regs[decoded->reg]);
+ }
+ }
+ switch (decoded->addr_mode)
+ {
+ case Z80_REG:
+ len += sprintf(dst+len, "%s %s", decoded->reg == Z80_UNUSED ? "" : "," , z80_regs[decoded->ea_reg]);
+ break;
+ case Z80_REG_INDIRECT:
+ len += sprintf(dst+len, "%s (%s)", decoded->reg == Z80_UNUSED ? "" : "," , z80_regs[decoded->ea_reg]);
+ break;
+ case Z80_IMMED:
+ len += sprintf(dst+len, "%s %d", decoded->reg == Z80_UNUSED ? "" : "," , decoded->immed);
+ break;
+ case Z80_IMMED_INDIRECT:
+ len += sprintf(dst+len, "%s (%d)", decoded->reg == Z80_UNUSED ? "" : "," , decoded->immed);
+ break;
+ }
+ }
+ return len;
+}
+
diff --git a/z80inst.h b/z80inst.h
new file mode 100644
index 0000000..26ccfbc
--- /dev/null
+++ b/z80inst.h
@@ -0,0 +1,118 @@
+#include <stdint.h>
+
+enum {
+ Z80_LD,
+ Z80_PUSH,
+ Z80_POP,
+ Z80_EX,
+ Z80_EXX,
+ Z80_LDI,
+ Z80_LDIR,
+ Z80_LDD,
+ Z80_LDDR,
+ Z80_CPI,
+ Z80_CPIR,
+ Z80_CPD,
+ Z80_CPDR,
+ Z80_ADD,
+ Z80_ADC,
+ Z80_SUB,
+ Z80_SBC,
+ Z80_AND,
+ Z80_OR,
+ Z80_XOR,
+ Z80_CP,
+ Z80_INC,
+ Z80_DEC,
+ Z80_DAA,
+ Z80_CPL,
+ Z80_NEG,
+ Z80_CCF,
+ Z80_SCF,
+ Z80_NOP,
+ Z80_HALT,
+ Z80_DI,
+ Z80_EI,
+ Z80_IM,
+ Z80_RLC,
+ Z80_RL,
+ Z80_RRC,
+ Z80_RR,
+ Z80_SL,
+ Z80_RLD,
+ Z80_RRD,
+ Z80_BIT,
+ Z80_SET,
+ Z80_RES,
+ Z80_JP,
+ Z80_JPCC,
+ Z80_JR,
+ Z80_JRCC,
+ Z80_DJNZ,
+ Z80_CALL,
+ Z80_CALLCC,
+ Z80_RET,
+ Z80_RETCC,
+ Z80_RETI,
+ Z80_RETN,
+ Z80_RST,
+ Z80_IN,
+ Z80_INI,
+ Z80_INIR,
+ Z80_INDR,
+ Z80_OUT,
+ Z80_OUTI,
+ Z80_OTIR,
+ Z80_OUTD,
+ Z80_OTDR
+};
+
+enum {
+ Z80_B=0,
+ Z80_C,
+ Z80_D,
+ Z80_E,
+ Z80_H,
+ Z80_L,
+ Z80_A=7,
+ Z80_BC,
+ Z80_DE,
+ Z80_HL,
+ Z80_SP,
+ Z80_AF,
+ Z80_USE_IMMED,
+ Z80_UNUSED
+};
+
+enum {
+ Z80_CC_NZ,
+ Z80_CC_Z,
+ Z80_CC_NC,
+ Z80_CC_C,
+ Z80_CC_PO,
+ Z80_CC_PE,
+ Z80_CC_P,
+ Z80_CC_M
+};
+
+enum {
+ Z80_REG,
+ Z80_REG_INDIRECT,
+ Z80_IMMED,
+ Z80_IMMED_INDIRECT,
+ Z80_REG_DISPLACE
+};
+#define Z80_DIR 0x80
+
+typedef struct {
+ uint8_t op;
+ uint8_t reg;
+ uint8_t addr_mode;
+ uint8_t ea_reg;
+ uint16_t immed;
+} z80inst;
+
+uint8_t * z80_decode(uint8_t * istream, z80inst * decoded);
+int z80_disasm(z80inst * decoded, char * dst);
+
+
diff --git a/zdis.c b/zdis.c
new file mode 100644
index 0000000..be0ffe4
--- /dev/null
+++ b/zdis.c
@@ -0,0 +1,193 @@
+#include "z80inst.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+uint8_t visited[(64*1024)/8];
+uint8_t label[(64*1024)/8];
+
+void visit(uint16_t address)
+{
+ visited[address/8] |= 1 << (address % 8);
+}
+
+void reference(uint16_t address)
+{
+ //printf("referenced: %X\n", address);
+ label[address/8] |= 1 << (address % 8);
+}
+
+uint8_t is_visited(uint16_t address)
+{
+ return visited[address/8] & (1 << (address % 8));
+}
+
+uint8_t is_label(uint16_t address)
+{
+ return label[address/8] & (1 << (address % 8));
+}
+
+typedef struct deferred {
+ uint16_t address;
+ struct deferred *next;
+} deferred;
+
+deferred * defer(uint16_t address, deferred * next)
+{
+ if (is_visited(address)) {
+ return next;
+ }
+ //printf("deferring %X\n", address);
+ deferred * d = malloc(sizeof(deferred));
+ d->address = address;
+ d->next = next;
+ return d;
+}
+
+uint8_t labels = 0;
+uint8_t addr = 0;
+uint8_t only = 0;
+
+int main(int argc, char ** argv)
+{
+ long filesize;
+ uint8_t *filebuf;
+ char disbuf[1024];
+ z80inst instbuf;
+ uint8_t * cur;
+ FILE * f = fopen(argv[1], "rb");
+ fseek(f, 0, SEEK_END);
+ filesize = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ filebuf = malloc(filesize);
+ fread(filebuf, 1, filesize, f);
+ fclose(f);
+ deferred *def = NULL, *tmpd;
+ for(uint8_t opt = 2; opt < argc; ++opt) {
+ if (argv[opt][0] == '-') {
+ FILE * address_log;
+ switch (argv[opt][1])
+ {
+ case 'l':
+ labels = 1;
+ break;
+ case 'a':
+ addr = 1;
+ break;
+ case 'o':
+ only = 1;
+ break;
+ case 'f':
+ opt++;
+ if (opt >= argc) {
+ fputs("-f must be followed by a filename\n", stderr);
+ exit(1);
+ }
+ address_log = fopen(argv[opt], "r");
+ if (!address_log) {
+ fprintf(stderr, "Failed to open %s for reading\n", argv[opt]);
+ exit(1);
+ }
+ while (fgets(disbuf, sizeof(disbuf), address_log)) {
+ if (disbuf[0]) {
+ uint16_t address = strtol(disbuf, NULL, 16);
+ if (address) {
+ def = defer(address, def);
+ reference(address);
+ }
+ }
+ }
+ }
+ } else {
+ uint16_t address = strtol(argv[opt], NULL, 16);
+ def = defer(address, def);
+ reference(address);
+ }
+ }
+ uint16_t start = 0;
+ uint8_t *encoded, *next;
+ uint32_t size;
+ if (!def || !only) {
+ def = defer(start, def);
+ }
+ uint16_t address;
+ while(def) {
+ do {
+ encoded = NULL;
+ address = def->address;
+ if (!is_visited(address)) {
+ encoded = filebuf + address;
+ }
+ tmpd = def;
+ def = def->next;
+ free(tmpd);
+ } while(def && encoded == NULL);
+ if (!encoded) {
+ break;
+ }
+ for(;;) {
+ if (address > filesize) {
+ break;
+ }
+ visit(address);
+ next = z80_decode(encoded, &instbuf);
+ address += (next-encoded);
+ encoded = next;
+
+ //m68k_disasm(&instbuf, disbuf);
+ //printf("%X: %s\n", instbuf.address, disbuf);
+ if (instbuf.op == Z80_HALT || instbuf.op == Z80_RET || instbuf.op == Z80_RETI || instbuf.op == Z80_RETN || instbuf.op == Z80_RST) {
+ break;
+ }
+ switch (instbuf.op)
+ {
+ case Z80_JR:
+ address += instbuf.immed;
+ encoded = filebuf + address;
+ break;
+ case Z80_JRCC:
+ reference(address + instbuf.immed);
+ def = defer(address + instbuf.immed, def);
+ break;
+ case Z80_JP:
+ address = instbuf.immed;
+ encoded = filebuf + address;
+ break;
+ case Z80_JPCC:
+ case Z80_CALL:
+ case Z80_CALLCC:
+ reference(instbuf.immed);
+ def = defer(instbuf.immed, def);
+ break;
+ }
+ }
+ }
+ if (labels) {
+ for (address = filesize; address < (64*1024); address++) {
+ if (is_label(address)) {
+ printf("ADR_%X equ $%X\n", address, address);
+ }
+ }
+ puts("");
+ }
+ for (address = 0; address < filesize; address++) {
+ if (is_visited(address)) {
+ encoded = filebuf + address;
+ z80_decode(encoded, &instbuf);
+ if (labels) {
+ /*m68k_disasm_labels(&instbuf, disbuf);
+ if (is_label(instbuf.address)) {
+ printf("ADR_%X:\n", instbuf.address);
+ }
+ if (addr) {
+ printf("\t%s\t;%X\n", disbuf, instbuf.address);
+ } else {
+ printf("\t%s\n", disbuf);
+ }*/
+ } else {
+ z80_disasm(&instbuf, disbuf);
+ printf("%X: %s\n", address, disbuf);
+ }
+ }
+ }
+ return 0;
+}