changeset 199:69585e7d474f

Add initial stab at Z80 decoder and disassembler
author Mike Pavone <pavone@retrodev.com>
date Sun, 20 Jan 2013 19:11:24 -0800
parents 209a37eed3e7
children d3066ceb29d1
files Makefile z80inst.c z80inst.h zdis.c
diffstat 4 files changed, 770 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Sun Jan 20 19:10:29 2013 -0800
+++ b/Makefile	Sun Jan 20 19:11:24 2013 -0800
@@ -7,6 +7,9 @@
 
 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 @@
 %.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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/z80inst.c	Sun Jan 20 19:11:24 2013 -0800
@@ -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;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/z80inst.h	Sun Jan 20 19:11:24 2013 -0800
@@ -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);
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zdis.c	Sun Jan 20 19:11:24 2013 -0800
@@ -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;
+}