changeset 2717:04007ac9ee3b

Add upd78k2 disassembler
author Michael Pavone <pavone@retrodev.com>
date Wed, 16 Jul 2025 07:36:01 -0700
parents 033d8d4308e3
children 8ce5d1a7ef54
files Makefile disasm.c disasm.h upd78k2_dis.c upd78k2_dis.h upddis.c
diffstat 6 files changed, 1364 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Sat Jul 12 22:25:20 2025 -0700
+++ b/Makefile	Wed Jul 16 07:36:01 2025 -0700
@@ -327,6 +327,7 @@
 ZTESTOBJS:=ztestrun.o serialize.o $(Z80OBJS) $(TRANSOBJS) util.o
 CPMOBJS:=blastcpm.o util.o serialize.o $(Z80OBJS) $(TRANSOBJS)
 UPD78K2RUNOBJS:=upd78k2.o upd78k2run.o util.o backend.o tern.o
+UPDDISOBJS:=upddis.o upd78k2_dis.o disasm.o tern.o util.o backend.o
 
 LIBCFLAGS=$(CFLAGS) -fpic -DIS_LIB -DDISABLE_ZLIB
 
@@ -347,6 +348,7 @@
 -include $(LIBOBJS:%.o=$(LIBOBJDIR)/%.d)
 -include $(DISOBJS:%.o=$(OBJDIR)/%.d)
 -include $(UPD78K2RUNOBJS:%.o=$(OBJDIR)/%.d)
+-include $(UPDDISOBJS:%.o=$(OBJDIR)/%.d)
 -include $(OBJDIR)/trans.d
 -include $(OBJDIR)/ztestrun.d
 -include $(OBJDIR)/blastcpm.d
@@ -395,6 +397,9 @@
 upd78k2run : $(UPD78K2RUNOBJS:%.o=$(OBJDIR)/%.o)
 	$(CC) -o $@ $^ $(OPT)
 
+upddis$(EXE) : $(UPDDISOBJS:%.o=$(OBJDIR)/%.o)
+	$(CC) -o $@ $^ $(OPT)
+
 .PRECIOUS: %.c
 %.c %.h : %.cpu cpu_dsl.py
 	./cpu_dsl.py -d $(shell echo $@ | sed -E -e "s/^z80.*$$/$(Z80_DISPATCH)/" -e '/^goto/! s/^.*$$/call/') $< > $(shell echo $@ | sed -E 's/\.[ch]$$/./')c
--- a/disasm.c	Sat Jul 12 22:25:20 2025 -0700
+++ b/disasm.c	Wed Jul 16 07:36:01 2025 -0700
@@ -304,6 +304,81 @@
 	weak_label(context, "CDD_CTRL_BYTE", 0xFFFF8037);
 }
 
+void add_upd7823x_labels(disasm_context *context)
+{
+	weak_label(context, "P0", 0xFF00);
+	weak_label(context, "P1", 0xFF01);
+	weak_label(context, "P2", 0xFF02);
+	weak_label(context, "P3", 0xFF03);
+	weak_label(context, "P4", 0xFF04);
+	weak_label(context, "P5", 0xFF05);
+	weak_label(context, "P6", 0xFF06);
+	weak_label(context, "P7", 0xFF07);
+	weak_label(context, "P0L", 0xFF0A);
+	weak_label(context, "P0B", 0xFF0B);
+	weak_label(context, "RTPC", 0xFF0C);
+	weak_label(context, "CR00", 0xFF10);
+	weak_label(context, "CR01", 0xFF12);
+	weak_label(context, "CR10", 0xFF14);
+	weak_label(context, "CR20", 0xFF15);
+	weak_label(context, "CR21", 0xFF16);
+	weak_label(context, "CR30", 0xFF17);
+	weak_label(context, "CR02", 0xFF18);
+	weak_label(context, "CR22", 0xFF1A);
+	weak_label(context, "CR11", 0xFF1C);
+	weak_label(context, "PM0", 0xFF20);
+	weak_label(context, "PM1", 0xFF21);
+	weak_label(context, "PM3", 0xFF23);
+	weak_label(context, "PM5", 0xFF25);
+	weak_label(context, "PM6", 0xFF26);
+	weak_label(context, "CRC0", 0xFF30);
+	weak_label(context, "TOC", 0xFF31);
+	weak_label(context, "CRC1", 0xFF32);
+	weak_label(context, "CRC2", 0xFF34);
+	weak_label(context, "PUO", 0xFF40);
+	weak_label(context, "PMC3", 0xFF43);
+	weak_label(context, "TM0", 0xFF50);
+	weak_label(context, "TM1", 0xFF52);
+	weak_label(context, "TM2", 0xFF54);
+	weak_label(context, "TM3", 0xFF56);
+	weak_label(context, "PRM0", 0xFF5C);
+	weak_label(context, "TMC0", 0xFF5D);
+	weak_label(context, "PRM1", 0xFF5E);
+	weak_label(context, "TMC1", 0xFF5F);
+	weak_label(context, "DACS0", 0xFF60);
+	weak_label(context, "DACS1", 0xFF61);
+	weak_label(context, "ADM", 0xFF68);
+	weak_label(context, "ADCR", 0xFF6A);
+	weak_label(context, "PWMC", 0xFF70);
+	weak_label(context, "PWM0", 0xFF72);
+	weak_label(context, "PWM1", 0xFF74);
+	weak_label(context, "OSPC", 0xFF7D);
+	weak_label(context, "CSIM", 0xFF80);
+	weak_label(context, "SBIC", 0xFF82);
+	weak_label(context, "SIO", 0xFF86);
+	weak_label(context, "ASIM", 0xFF88);
+	weak_label(context, "ASIS", 0xFF8A);
+	weak_label(context, "RxB", 0xFF8C);
+	weak_label(context, "TxS", 0xFF8E);
+	weak_label(context, "BRGC", 0xFF90);
+	weak_label(context, "STBC", 0xFFC0);
+	weak_label(context, "MM", 0xFFC4);
+	weak_label(context, "PW", 0xFFC5);
+	weak_label(context, "RFM", 0xFFC6);
+	weak_label(context, "IMS", 0xFFCF);
+	weak_label(context, "IF0L", 0xFFE0);
+	weak_label(context, "IF0H", 0xFFE1);
+	weak_label(context, "MK0L", 0xFFE4);
+	weak_label(context, "MK0H", 0xFFE5);
+	weak_label(context, "PR0L", 0xFFE8);
+	weak_label(context, "PR0H", 0xFFE9);
+	weak_label(context, "ISM0L", 0xFFEC);
+	weak_label(context, "ISM0H", 0xFFED);
+	weak_label(context, "INTM0", 0xFFF4);
+	weak_label(context, "INTM1", 0xFFF5);
+	weak_label(context, "IST", 0xFFF8);
+}
+
 disasm_context *create_68000_disasm(void)
 {
 	disasm_context *context = calloc(1, sizeof(disasm_context));
@@ -321,3 +396,12 @@
 	context->visit_preshift = 0;
 	return context;
 }
+
+disasm_context *create_upd78k2_disasm(void)
+{
+	disasm_context *context = calloc(1, sizeof(disasm_context));
+	context->address_mask = 0xFFFF;
+	context->invalid_inst_addr_mask = 0;
+	context->visit_preshift = 0;
+	return context;
+}
--- a/disasm.h	Sat Jul 12 22:25:20 2025 -0700
+++ b/disasm.h	Wed Jul 16 07:36:01 2025 -0700
@@ -37,5 +37,7 @@
 void add_segacd_subcpu_labels(disasm_context *context);
 disasm_context *create_68000_disasm(void);
 disasm_context *create_z80_disasm(void);
+disasm_context *create_upd78k2_disasm(void);
+void add_upd7823x_labels(disasm_context *context);
 
 #endif //DISASM_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/upd78k2_dis.c	Wed Jul 16 07:36:01 2025 -0700
@@ -0,0 +1,889 @@
+#include <string.h>
+
+#include "upd78k2_dis.h"
+
+typedef enum {
+	T_INVALID,
+	T_STRING,
+	T_PREFIX,
+	T_REG_REG,
+	T_SFR,
+	T_SFR_BYTE,
+	T_SFR_WORD,
+	T_SADDR,
+	T_SADDR_BYTE,
+	T_SADDR_WORD,
+	T_SADDR_SADDR,
+	T_BYTE,
+	T_BASE,
+	T_WORD,
+	T_INDEXED,
+	T_ADDR16,
+	T_BR_REL,
+	T_BR_ABS,
+	T_BR_SFR,
+	T_BR_SADDR,
+	T_CALLF,
+	T_CALLT,
+	T_CUSTOM
+} upd_inst_type;
+
+typedef struct upd_inst upd_inst;
+typedef uint16_t (*custom_fun)(char *dst, upd_address_ref *ref, uint16_t address, upd_fetch_fun fetch, void *data, disasm_context *context);
+
+struct upd_inst {
+	union {
+		char       *str;
+		upd_inst   *prefix;
+		custom_fun fun;
+	} v;
+	upd_inst_type type;
+};
+
+#define STRING(s) {.v = {.str = s}, .type = T_STRING}
+#define PREFIX(t) {.v = {.prefix = t}, .type = T_PREFIX}
+#define REG_REG(s) {.v = {.str = s}, .type = T_REG_REG}
+#define SFR(s) {.v = {.str = s}, .type = T_SFR}
+#define SFR_BYTE(s) {.v = {.str = s}, .type = T_SFR_BYTE}
+#define SFR_WORD(s) {.v = {.str = s}, .type = T_SFR_WORD}
+#define SADDR(s) {.v = {.str = s}, .type = T_SADDR}
+#define SADDR_BYTE(s) {.v = {.str = s}, .type = T_SADDR_BYTE}
+#define SADDR_WORD(s) {.v = {.str = s}, .type = T_SADDR_WORD}
+#define SADDR_SADDR(s) {.v = {.str = s}, .type = T_SADDR_SADDR}
+#define BYTE(s) {.v = {.str = s}, .type = T_BYTE}
+#define BASE(s) {.v = {.str = s}, .type = T_BASE}
+#define WORD(s) {.v = {.str = s}, .type = T_WORD}
+#define INDEXED(s) {.v = {.str = s}, .type = T_INDEXED}
+#define ADDR16(s) {.v = {.str = s}, .type = T_ADDR16}
+#define BRANCH_REL(s) {.v = {.str = s}, .type = T_BR_REL}
+#define BRANCH_ABS(s) {.v = {.str = s}, .type = T_BR_ABS}
+#define BRANCH_SFR(s) {.v = {.str = s}, .type = T_BR_SFR}
+#define BRANCH_SADDR(s) {.v = {.str = s}, .type = T_BR_SADDR}
+#define CALLF {.type = T_CALLF}
+#define CALLT {.type = T_CALLT}
+#define CUSTOM(f) {.v = {.fun = f}, .type = T_CUSTOM}
+#define INVALID {.type = T_INVALID}
+
+static void format_address(disasm_context *context, char *dst, uint16_t address)
+{
+	if (context) {
+		format_label(dst, address, context);
+	} else {
+		sprintf(dst, "0%XH", address);
+	}
+}
+
+static uint16_t disasm_sfr_mov16(char *dst, upd_address_ref *ref, uint16_t address, upd_fetch_fun fetch, void *data, disasm_context *context)
+{
+	char addr_buf[256];
+	uint8_t offset = fetch(address++, data);
+	uint16_t immed = fetch(address++, data);
+	immed |= fetch(address++, data) << 8;
+	uint16_t ref_addr = 0;
+	uint8_t ref_type = UPD_REF_NONE;
+	if (offset == 0xFC) {
+		sprintf(dst, "movw sp,#0%XH", immed);
+	} else {
+		ref_addr = 0xFF00 | offset;
+		ref_type = UPD_REF_OP;
+		format_address(context, addr_buf, ref_addr);
+		sprintf(dst, "movw %s,#0%XH", addr_buf, immed);
+	}
+	if (ref) {
+		ref->address = ref_addr;
+		ref->ref_type = ref_type;
+	}
+	return address;
+}
+
+static uint16_t disasm_mov_a_sfr(char *dst, upd_address_ref *ref, uint16_t address, upd_fetch_fun fetch, void *data, disasm_context *context)
+{
+	char addr_buf[256];
+	uint8_t offset = fetch(address++, data);
+	uint16_t ref_addr = 0;
+	uint8_t ref_type = UPD_REF_NONE;
+	if (offset == 0xFE) {
+		strcpy(dst, "mov a,psw");
+	} else {
+		ref_addr = 0xFF00 | offset;
+		ref_type = UPD_REF_OP;
+		format_address(context, addr_buf, ref_addr);
+		sprintf(dst, "mov a,%s", addr_buf);
+	}
+	if (ref) {
+		ref->address = ref_addr;
+		ref->ref_type = ref_type;
+	}
+	return address;
+}
+
+static uint16_t disasm_movw_ax_sfr(char *dst, upd_address_ref *ref, uint16_t address, upd_fetch_fun fetch, void *data, disasm_context *context)
+{
+	char addr_buf[256];
+	uint8_t offset = fetch(address++, data);
+	uint16_t ref_addr = 0;
+	uint8_t ref_type = UPD_REF_NONE;
+	if (offset == 0xFC) {
+		strcpy(dst, "movw ax,sp");
+	} else {
+		ref_addr = 0xFF00 | offset;
+		ref_type = UPD_REF_OP;
+		format_address(context, addr_buf, ref_addr);
+		sprintf(dst, "movw ax,%s", addr_buf);
+	}
+	if (ref) {
+		ref->address = ref_addr;
+		ref->ref_type = ref_type;
+	}
+	return address;
+}
+
+static uint16_t disasm_mov_sfr_a(char *dst, upd_address_ref *ref, uint16_t address, upd_fetch_fun fetch, void *data, disasm_context *context)
+{
+	char addr_buf[256];
+	uint8_t offset = fetch(address++, data);
+	uint16_t ref_addr = 0;
+	uint8_t ref_type = UPD_REF_NONE;
+	if (offset == 0xFE) {
+		strcpy(dst, "mov psw,a");
+	} else {
+		ref_addr = 0xFF00 | offset;
+		ref_type = UPD_REF_OP;
+		format_address(context, addr_buf, ref_addr);
+		sprintf(dst, "mov a,%s", addr_buf);
+	}
+	if (ref) {
+		ref->address = ref_addr;
+		ref->ref_type = ref_type;
+	}
+	return address;
+}
+
+static uint16_t disasm_movw_sfr_ax(char *dst, upd_address_ref *ref, uint16_t address, upd_fetch_fun fetch, void *data, disasm_context *context)
+{
+	char addr_buf[256];
+	uint8_t offset = fetch(address++, data);
+	uint16_t ref_addr = 0;
+	uint8_t ref_type = UPD_REF_NONE;
+	if (offset == 0xFC) {
+		strcpy(dst, "movw sp,ax");
+	} else {
+		ref_addr = 0xFF00 | offset;
+		ref_type = UPD_REF_OP;
+		format_address(context, addr_buf, ref_addr);
+		sprintf(dst, "movw %s,ax", addr_buf);
+	}
+	if (ref) {
+		ref->address = ref_addr;
+		ref->ref_type = ref_type;
+	}
+	return address;
+}
+
+static uint16_t disasm_mov_sfr_byte(char *dst, upd_address_ref *ref, uint16_t address, upd_fetch_fun fetch, void *data, disasm_context *context)
+{
+	char addr_buf[256];
+	uint8_t offset = fetch(address++, data);
+	uint8_t immed = fetch(address++, data);
+	uint16_t ref_addr = 0;
+	uint8_t ref_type = UPD_REF_NONE;
+	if (offset == 0xFE) {
+		sprintf(dst, "mov psw,#0%XH", immed);
+	} else {
+		ref_addr = 0xFF00 | offset;
+		ref_type = UPD_REF_OP;
+		format_address(context, addr_buf, ref_addr);
+		sprintf(dst, "mov %s,#0%XH", addr_buf, immed);
+	}
+	if (ref) {
+		ref->address = ref_addr;
+		ref->ref_type = ref_type;
+	}
+	return address;
+}
+
+static uint16_t disasm_ror4_mov_mem1(char *dst, upd_address_ref *ref, uint16_t address, upd_fetch_fun fetch, void *data, disasm_context *context)
+{
+	uint8_t byte = fetch(address++, data);
+	if ((byte & 0xED) == 0x8C) {
+		sprintf(dst, "ro%c4 &[%s]", byte & 0x10 ? 'l' : 'r', byte & 0x02 ? "hl" : "de");
+	} else if ((byte & 0xFA) == 0xE2) {
+	}
+	
+	if (ref) {
+		ref->address = 0;
+		ref->ref_type = UPD_REF_NONE;
+	}
+	return address;
+}
+
+static uint16_t disasm_mov_stbc(char *dst, upd_address_ref *ref, uint16_t address, upd_fetch_fun fetch, void *data, disasm_context *context)
+{
+	uint8_t inverse = fetch(address++, data);
+	uint8_t byte = fetch(address++, data);
+	if ((~inverse) != byte) {
+		strcpy(dst, "invalid");
+	} else {
+		sprintf(dst, "mov stbc,#0%XH", byte);
+	}
+	if (ref) {
+		ref->address = 0;
+		ref->ref_type = UPD_REF_NONE;
+	}
+	return address;
+}
+
+static uint16_t disasm_op_r_r(char *dst, char *mnemonic, upd_address_ref *ref, uint16_t address, upd_fetch_fun fetch, void *data)
+{
+	static const char regnames[] = "xacbedlh";
+	static const char *regpairs[] = {"ax", "bc", "de", "hl"};
+	uint8_t byte = fetch(address++, data);
+	uint8_t word_mask = mnemonic[0] == 'm' ? 0x99 : 0xF9;
+	if (!(byte & 0x88)) {
+		sprintf(dst, "%s %c,%c", mnemonic, regnames[byte >> 4], regnames[byte & 7]);
+	} else if ((byte & word_mask) == 0x08) {
+		sprintf(dst, "%sw %s,%s", mnemonic, regpairs[byte >> 5], regpairs[byte >> 1 & 3]);
+	} else {
+		strcpy(dst, "invalid");
+	}
+	if (ref) {
+		ref->address = 0;
+		ref->ref_type = UPD_REF_NONE;
+	}
+	return address;
+}
+
+static uint16_t disasm_mov_r_r(char *dst, upd_address_ref *ref, uint16_t address, upd_fetch_fun fetch, void *data, disasm_context *context)
+{
+	return disasm_op_r_r(dst, "mov", ref, address, fetch, data);
+}
+
+static uint16_t disasm_add_r_r(char *dst, upd_address_ref *ref, uint16_t address, upd_fetch_fun fetch, void *data, disasm_context *context)
+{
+	return disasm_op_r_r(dst, "add", ref, address, fetch, data);
+}
+
+static uint16_t disasm_sub_r_r(char *dst, upd_address_ref *ref, uint16_t address, upd_fetch_fun fetch, void *data, disasm_context *context)
+{
+	return disasm_op_r_r(dst, "sub", ref, address, fetch, data);
+}
+
+static uint16_t disasm_cmp_r_r(char *dst, upd_address_ref *ref, uint16_t address, upd_fetch_fun fetch, void *data, disasm_context *context)
+{
+	return disasm_op_r_r(dst, "cmp", ref, address, fetch, data);
+}
+
+static uint16_t disasm_shift(char *dst, char lr, upd_address_ref *ref, uint16_t address, upd_fetch_fun fetch, void *data)
+{
+	static const char regnames[] = "xacbedlh";
+	static const char *regpairs[] = {"ax", "bc", "de", "hl"};
+	static const char *names[] = {"rolc", "rol", "shl", "shlw"};
+	uint8_t byte = fetch(address++, data);
+	uint8_t shift_type = byte >> 6;
+	if (shift_type == 3) {
+		if (byte & 1) {
+			strcpy(dst, "invalid");
+		} else {
+			sprintf(dst, "%s %s,%d", names[shift_type], regpairs[byte >> 1 & 3], byte >> 3 & 7);
+			dst[2] = lr;
+		}
+	} else {
+		sprintf(dst, "%s %c,%d", names[shift_type], regnames[byte & 7], byte >> 3 & 7);
+		dst[2] = lr;
+	}
+	if (ref) {
+		ref->address = 0;
+		ref->ref_type = UPD_REF_NONE;
+	}
+	return address;
+}
+
+static uint16_t disasm_shift_left(char *dst, upd_address_ref *ref, uint16_t address, upd_fetch_fun fetch, void *data, disasm_context *context)
+{
+	return disasm_shift(dst, 'l', ref, address, fetch, data);
+}
+
+static uint16_t disasm_shift_right(char *dst, upd_address_ref *ref, uint16_t address, upd_fetch_fun fetch, void *data, disasm_context *context)
+{
+	return disasm_shift(dst, 'r', ref, address, fetch, data);
+}
+
+upd_inst alt_base[256] = {
+	/* 0000 0000 */BASE("mov a,&[de+0%XH]"), INVALID, INVALID, INVALID,
+	/* 0000 0100 */BASE("xch a,&[de+0%XH]"), INVALID, INVALID, INVALID,
+	/* 0000 1000 */BASE("add a,&[de+0%XH]"), BASE("addc a,&[de+0%XH]"), BASE("sub a,&[de+0%XH]"), BASE("subc a,&[de+0%XH]"),
+	/* 0000 1100 */BASE("and a,&[de+0%XH]"), BASE("xor a,&[de+0%XH]"), BASE("or a,&[de+0%XH]"), BASE("cmp a,&[de+0%XH]"),
+	/* 0001 0000 */BASE("mov a,&[sp+0%XH]"), INVALID, INVALID, INVALID,
+	/* 0001 0100 */BASE("xch a,&[sp+0%XH]"), INVALID, INVALID, INVALID,
+	/* 0001 1000 */BASE("add a,&[sp+0%XH]"), BASE("addc a,&[sp+0%XH]"), BASE("sub a,&[sp+0%XH]"), BASE("subc a,&[sp+0%XH]"),
+	/* 0001 1100 */BASE("and a,&[sp+0%XH]"), BASE("xor a,&[sp+0%XH]"), BASE("or a,&[sp+0%XH]"), BASE("cmp a,&[sp+0%XH]"),
+	/* 0010 0000 */BASE("mov a,&[hl+0%XH]"), INVALID, INVALID, INVALID,
+	/* 0010 0100 */BASE("xch a,&[hl+0%XH]"), INVALID, INVALID, INVALID,
+	/* 0010 1000 */BASE("add a,&[hl+0%XH]"), BASE("addc a,&[hl+0%XH]"), BASE("sub a,&[hl+0%XH]"), BASE("subc a,&[hl+0%XH]"),
+	/* 0010 1100 */BASE("and a,&[hl+0%XH]"), BASE("xor a,&[hl+0%XH]"), BASE("or a,&[hl+0%XH]"), BASE("cmp a,&[hl+0%XH]"),
+	/* 1000 0000 */[0x80] = BASE("mov &[de+0%XH],a"),
+	/* 1001 0000 */[0x90] = BASE("mov &[sp+0%XH],a"),
+	/* 1010 0000 */[0xA0] = BASE("mov &[hl+0%XH],a")
+};
+upd_inst alt_indexed[256] = {
+	/* 0000 0000 */INDEXED("mov a,&0%XH[de]"), INVALID, INVALID, INVALID,
+	/* 0000 0100 */INDEXED("xch a,&0%XH[de]"), INVALID, INVALID, INVALID,
+	/* 0000 1000 */INDEXED("add a,&0%XH[de]"), INDEXED("addc a,&0%XH[de]"), INDEXED("sub a,&0%XH[de]"), INDEXED("subc a,&0%XH[de]"),
+	/* 0000 1100 */INDEXED("and a,&0%XH[de]"), INDEXED("xor a,&0%XH[de]"), INDEXED("or a,&0%XH[de]"), INDEXED("cmp a,&0%XH[de]"),
+	/* 0001 0000 */INDEXED("mov a,&0%XH[a]"), INVALID, INVALID, INVALID,
+	/* 0001 0100 */INDEXED("xch a,&0%XH[a]"), INVALID, INVALID, INVALID,
+	/* 0001 1000 */INDEXED("add a,&0%XH[a]"), INDEXED("addc a,&0%XH[a]"), INDEXED("sub a,&0%XH[a]"), INDEXED("subc a,&0%XH[a]"),
+	/* 0001 1100 */INDEXED("and a,&0%XH[a]"), INDEXED("xor a,&0%XH[a]"), INDEXED("or a,&0%XH[a]"), INDEXED("cmp a,&0%XH[a]"),
+	/* 0010 0000 */INDEXED("mov a,&0%XH[hl]"), INVALID, INVALID, INVALID,
+	/* 0010 0100 */INDEXED("xch a,&0%XH[hl]"), INVALID, INVALID, INVALID,
+	/* 0010 1000 */INDEXED("add a,&0%XH[hl]"), INDEXED("addc a,&0%XH[hl]"), INDEXED("sub a,&0%XH[hl]"), INDEXED("subc a,&0%XH[hl]"),
+	/* 0010 1100 */INDEXED("and a,&0%XH[hl]"), INDEXED("xor a,&0%XH[hl]"), INDEXED("or a,&0%XH[hl]"), INDEXED("cmp a,&0%XH[hl]"),
+	/* 0011 0000 */INDEXED("mov a,&0%XH[b]"), INVALID, INVALID, INVALID,
+	/* 0011 0100 */INDEXED("xch a,&0%XH[b]"), INVALID, INVALID, INVALID,
+	/* 0011 1000 */INDEXED("add a,&0%XH[b]"), INDEXED("addc a,&0%XH[b]"), INDEXED("sub a,&0%XH[b]"), INDEXED("subc a,&0%XH[b]"),
+	/* 0011 1100 */INDEXED("and a,&0%XH[b]"), INDEXED("xor a,&0%XH[b]"), INDEXED("or a,&0%XH[b]"), INDEXED("cmp a,&0%XH[b]"),
+	/* 1000 0000 */[0x80] = INDEXED("mov &0%XH[de],a"),
+	/* 1001 0000 */[0x90] = INDEXED("mov &0%XH[a],a"),
+	/* 1010 0000 */[0xA0] = INDEXED("mov &0%XH[hl],a"),
+	/* 1011 0000 */[0xB0] = INDEXED("mov &0%XH[b],a")
+};
+upd_inst alt_regind[256] = {
+	/* 0000 0000 */STRING("mov a,&[de+]"), INVALID, INVALID, INVALID,
+	/* 0000 0100 */STRING("xch a,&[de+]"), INVALID, INVALID, INVALID,
+	/* 0000 1000 */STRING("add a,&[de+]"), STRING("addc a,&[de+]"), STRING("sub a,&[de+]"), STRING("subc a,&[de+]"),
+	/* 0000 1100 */STRING("and a,&[de+]"), STRING("xor a,&[de+]"), STRING("or a,&[de+]"), STRING("cmp a,&[de+]"),
+	/* 0001 0000 */STRING("mov a,&[hl+]"), INVALID, INVALID, INVALID,
+	/* 0001 0100 */STRING("xch a,&[hl+]"), INVALID, INVALID, INVALID,
+	/* 0001 1000 */STRING("add a,&[hl+]"), STRING("addc a,&[hl+]"), STRING("sub a,&[hl+]"), STRING("subc a,&[hl+]"),
+	/* 0001 1100 */STRING("and a,&[hl+]"), STRING("xor a,&[hl+]"), STRING("or a,&[hl+]"), STRING("cmp a,&[hl+]"),
+	/* 0010 0000 */STRING("mov a,&[de-]"), INVALID, INVALID, INVALID,
+	/* 0010 0100 */STRING("xch a,&[de-]"), INVALID, INVALID, INVALID,
+	/* 0010 1000 */STRING("add a,&[de-]"), STRING("addc a,&[de-]"), STRING("sub a,&[de-]"), STRING("subc a,&[de-]"),
+	/* 0010 1100 */STRING("and a,&[de-]"), STRING("xor a,&[de-]"), STRING("or a,&[de-]"), STRING("cmp a,&[de-]"),
+	/* 0011 0000 */STRING("mov a,&[hl-]"), INVALID, INVALID, INVALID,
+	/* 0011 0100 */STRING("xch a,&[hl-]"), INVALID, INVALID, INVALID,
+	/* 0011 1000 */STRING("add a,&[hl-]"), STRING("addc a,&[hl-]"), STRING("sub a,&[hl-]"), STRING("subc a,&[hl-]"),
+	/* 0011 1100 */STRING("and a,&[hl-]"), STRING("xor a,&[hl-]"), STRING("or a,&[hl-]"), STRING("cmp a,&[hl-]"),
+	/* 0100 0000 */STRING("mov a,&[de]"), INVALID, INVALID, INVALID,
+	/* 0100 0100 */STRING("xch a,&[de]"), INVALID, INVALID, INVALID,
+	/* 0100 1000 */STRING("add a,&[de]"), STRING("addc a,&[de]"), STRING("sub a,&[de]"), STRING("subc a,&[de]"),
+	/* 0100 1100 */STRING("and a,&[de]"), STRING("xor a,&[de]"), STRING("or a,&[de]"), STRING("cmp a,&[de]"),
+	/* 0101 0000 */STRING("mov a,&[hl]"), INVALID, INVALID, INVALID,
+	/* 0101 0100 */STRING("xch a,&[hl]"), INVALID, INVALID, INVALID,
+	/* 0101 1000 */STRING("add a,&[hl]"), STRING("addc a,&[hl]"), STRING("sub a,&[hl]"), STRING("subc a,&[hl]"),
+	/* 0101 1100 */STRING("and a,&[hl]"), STRING("xor a,&[hl]"), STRING("or a,&[hl]"), STRING("cmp a,&[hl]"),
+	/* 1000 0000 */[0x80] = STRING("mov &[de+],a"),
+	/* 1001 0000 */[0x90] = STRING("mov &[hl+],a"),
+	/* 1010 0000 */[0xA0] = STRING("mov &[de-],a"),
+	/* 1011 0000 */[0xB0] = STRING("mov &[hl-],a"),
+	/* 1100 0000 */[0x80] = STRING("mov &[de],a"),
+	/* 1101 0000 */[0x90] = STRING("mov &[hl],a")
+};
+
+upd_inst sfr[256] = {
+	/* 0000 0100 */[0x04] = INVALID, CUSTOM(disasm_ror4_mov_mem1), PREFIX(alt_base), INVALID,
+	/* 0000 1000 */INVALID, INVALID, PREFIX(alt_indexed), INVALID,
+	/* 0001 0100 */[0x14] = INVALID, INVALID, PREFIX(alt_regind), INVALID,
+	/* 0001 1000 */INVALID, INVALID, INVALID, INVALID,
+	/* 0001 1100 */INVALID, SFR("addw ax,%s"), SFR("subw ax,%s"), SFR("cmpw ax,%s"),
+	/* 0010 0000 */INVALID, SFR("xch a,%s"), INVALID, INVALID,
+	/* 0101 0000 */[0x50] = STRING("mov &[de+],a"), STRING("mov &[hl+],a"), STRING("mov &[de-],a"), STRING("mov &[hl-],a"),
+	/* 0101 0100 */STRING("mov &[de],a"), STRING("mov &[hl],a"), INVALID, INVALID,
+	/* 0101 1000 */STRING("mov a,&[de+]"), STRING("mov a,&[hl+]"), STRING("mov a,&[de-]"), STRING("mov a,&[hl-]"),
+	/* 0101 1100 */STRING("mov a,&[de]"), STRING("mov a,&[hl]"), INVALID, INVALID,
+	/* 0110 1000 */[0x68] = SFR_BYTE("add %s, #0%XH"), SFR_BYTE("addc %s, #0%XH"), SFR_BYTE("sub %s, #0%XH"), SFR_BYTE("subc %s, #0%XH"),
+	/* 0110 1100 */SFR_BYTE("and %s, #0%XH"), SFR_BYTE("xor %s, #0%XH"), SFR_BYTE("or %s, #0%XH"), SFR_BYTE("cmp %s, #0%XH"),
+	/* 1001 1000 */[0x98] = SFR("add a,%s"), SFR("addc a,%s"), SFR("sub a,%s"), SFR("subc a,%s"), 
+	/* 1001 1100 */SFR("and a,%s"), SFR("xor a,%s"), SFR("or a,%s"), SFR("cmp a,%s")
+};
+upd_inst bit1[256] = {
+	/* 0000 0000 */STRING("mov1 cy,psw.0"), STRING("mov1 cy,psw.1"), STRING("mov1 cy,psw.2"), STRING("mov1 cy,psw.3"),
+	/* 0000 0100 */STRING("mov1 cy,psw.4"), STRING("mov1 cy,psw.5"), STRING("mov1 cy,psw.6"), STRING("mov1 cy,psw.7"),
+	/* 0000 1000 */INVALID, INVALID, INVALID, INVALID,
+	/* 0000 1100 */INVALID, INVALID, INVALID, INVALID,
+	/* 0001 0000 */STRING("mov1 psw.0,cy"), STRING("mov1 psw.1,cy"), STRING("mov1 psw.2,cy"), STRING("mov1 psw.3,cy"),
+	/* 0001 0100 */STRING("mov1 psw.4,cy"), STRING("mov1 psw.5,cy"), STRING("mov1 psw.6,cy"), STRING("mov1 psw.7,cy"),
+	/* 0001 1000 */INVALID, INVALID, INVALID, INVALID,
+	/* 0001 1100 */INVALID, INVALID, INVALID, INVALID,
+	/* 0010 0000 */STRING("and1 cy,psw.0"), STRING("and1 cy,psw.1"), STRING("and1 cy,psw.2"), STRING("and1 cy,psw.3"),
+	/* 0010 0100 */STRING("and1 cy,psw.4"), STRING("and1 cy,psw.5"), STRING("and1 cy,psw.6"), STRING("and1 cy,psw.7"),
+	/* 0010 1000 */INVALID, INVALID, INVALID, INVALID,
+	/* 0010 1100 */INVALID, INVALID, INVALID, INVALID,
+	/* 0011 0000 */STRING("and1 /psw.0,cy"), STRING("and1 /psw.1,cy"), STRING("and1 /psw.2,cy"), STRING("and1 /psw.3,cy"),
+	/* 0011 0100 */STRING("and1 /psw.4,cy"), STRING("and1 /psw.5,cy"), STRING("and1 /psw.6,cy"), STRING("and1 /psw.7,cy"),
+	/* 0011 1000 */INVALID, INVALID, INVALID, INVALID,
+	/* 0011 1100 */INVALID, INVALID, INVALID, INVALID,
+	/* 0100 0000 */STRING("or1 cy,psw.0"), STRING("or1 cy,psw.1"), STRING("or1 cy,psw.2"), STRING("or1 cy,psw.3"),
+	/* 0100 0100 */STRING("or1 cy,psw.4"), STRING("or1 cy,psw.5"), STRING("or1 cy,psw.6"), STRING("or1 cy,psw.7"),
+	/* 0100 1000 */INVALID, INVALID, INVALID, INVALID,
+	/* 0100 1100 */INVALID, INVALID, INVALID, INVALID,
+	/* 0101 0000 */STRING("or1 /psw.0,cy"), STRING("or1 /psw.1,cy"), STRING("or1 /psw.2,cy"), STRING("or1 /psw.3,cy"),
+	/* 0101 0100 */STRING("or1 /psw.4,cy"), STRING("or1 /psw.5,cy"), STRING("or1 /psw.6,cy"), STRING("or1 /psw.7,cy"),
+	/* 0101 1000 */INVALID, INVALID, INVALID, INVALID,
+	/* 0101 1100 */INVALID, INVALID, INVALID, INVALID,
+	/* 0110 0000 */STRING("xor1 cy,psw.0"), STRING("xor1 cy,psw.1"), STRING("xor1 cy,psw.2"), STRING("xor1 cy,psw.3"),
+	/* 0110 0100 */STRING("xor1 cy,psw.4"), STRING("xor1 cy,psw.5"), STRING("xor1 cy,psw.6"), STRING("xor1 cy,psw.7"),
+	/* 0110 1000 */INVALID, INVALID, INVALID, INVALID,
+	/* 0110 1100 */INVALID, INVALID, INVALID, INVALID,
+	/* 0111 0000 */STRING("not1 psw.0"), STRING("not1 psw.1"), STRING("not1 psw.2"), STRING("not1 psw.3"),
+	/* 0111 0100 */STRING("not1 psw.4"), STRING("not1 psw.5"), STRING("not1 psw.6"), STRING("not1 psw.7"),
+	/* 0111 1000 */INVALID, INVALID, INVALID, INVALID,
+	/* 0111 1100 */INVALID, INVALID, INVALID, INVALID,
+	/* 1000 0000 */STRING("set1 psw.0"), STRING("set1 psw.1"), STRING("set1 psw.2"), STRING("set1 psw.3"),
+	/* 1000 0100 */STRING("set1 psw.4"), STRING("set1 psw.5"), STRING("set1 psw.6"), STRING("set1 psw.7"),
+	/* 1000 1000 */INVALID, INVALID, INVALID, INVALID,
+	/* 1000 1100 */INVALID, INVALID, INVALID, INVALID,
+	/* 1001 0000 */STRING("clr1 psw.0"), STRING("clr1 psw.1"), STRING("clr1 psw.2"), STRING("clr1 psw.3"),
+	/* 1001 0100 */STRING("clr1 psw.4"), STRING("clr1 psw.5"), STRING("clr1 psw.6"), STRING("clr1 psw.7"),
+	/* 1001 1000 */INVALID, INVALID, INVALID, INVALID,
+	/* 1001 1100 */INVALID, INVALID, INVALID, INVALID,
+	/* 1010 0000 */BRANCH_REL("bf psw.0,$%s"), BRANCH_REL("bf psw.1,$%s"), BRANCH_REL("bf psw.2,$%s"), BRANCH_REL("bf psw.3,$%s"),
+	/* 1010 0100 */BRANCH_REL("bf psw.4,$%s"), BRANCH_REL("bf psw.5,$%s"), BRANCH_REL("bf psw.6,$%s"), BRANCH_REL("bf psw.7,$%s"),
+	/* 1010 1000 */INVALID, INVALID, INVALID, INVALID,
+	/* 1010 1100 */INVALID, INVALID, INVALID, INVALID,
+	/* 1011 0000 */BRANCH_REL("bt psw.0,$%s"), BRANCH_REL("bt psw.1,$%s"), BRANCH_REL("bt psw.2,$%s"), BRANCH_REL("bt psw.3,$%s"),
+	/* 1011 0100 */BRANCH_REL("bt psw.4,$%s"), BRANCH_REL("bt psw.5,$%s"), BRANCH_REL("bt psw.6,$%s"), BRANCH_REL("bt psw.7,$%s"),
+	/* 1011 1000 */INVALID, INVALID, INVALID, INVALID,
+	/* 1011 1100 */INVALID, INVALID, INVALID, INVALID,
+	/* 1100 0000 */INVALID, INVALID, INVALID, INVALID,
+	/* 1100 0100 */INVALID, INVALID, INVALID, INVALID,
+	/* 1100 1000 */INVALID, INVALID, INVALID, INVALID,
+	/* 1100 1100 */INVALID, INVALID, INVALID, INVALID,
+	/* 1101 0000 */BRANCH_REL("btclr psw.0,$%s"), BRANCH_REL("btclr psw.1,$%s"), BRANCH_REL("btclr psw.2,$%s"), BRANCH_REL("btclr psw.3,$%s"),
+	/* 1101 0100 */BRANCH_REL("btclr psw.4,$%s"), BRANCH_REL("btclr psw.5,$%s"), BRANCH_REL("btclr psw.6,$%s"), BRANCH_REL("btclr psw.7,$%s")
+};
+upd_inst bit2[256] = {
+	/* 0000 0000 */STRING("mov1 cy,x.0"), STRING("mov1 cy,x.1"), STRING("mov1 cy,x.2"), STRING("mov1 cy,x.3"),
+	/* 0000 0100 */STRING("mov1 cy,x.4"), STRING("mov1 cy,x.5"), STRING("mov1 cy,x.6"), STRING("mov1 cy,x.7"),
+	/* 0000 1000 */STRING("mov1 cy,a.0"), STRING("mov1 cy,a.1"), STRING("mov1 cy,a.2"), STRING("mov1 cy,a.3"),
+	/* 0000 1100 */STRING("mov1 cy,a.4"), STRING("mov1 cy,a.5"), STRING("mov1 cy,a.6"), STRING("mov1 cy,a.7"),
+	/* 0001 0000 */STRING("mov1 x.0,cy"), STRING("mov1 x.1,cy"), STRING("mov1 x.2,cy"), STRING("mov1 x.3,cy"),
+	/* 0001 0100 */STRING("mov1 x.4,cy"), STRING("mov1 x.5,cy"), STRING("mov1 x.6,cy"), STRING("mov1 x.7,cy"),
+	/* 0001 1000 */STRING("mov1 a.0,cy"), STRING("mov1 a.1,cy"), STRING("mov1 a.2,cy"), STRING("mov1 a.3,cy"),
+	/* 0001 1100 */STRING("mov1 a.4,cy"), STRING("mov1 a.5,cy"), STRING("mov1 a.6,cy"), STRING("mov1 a.7,cy"),
+	/* 0010 0000 */STRING("and1 cy,x.0"), STRING("and1 cy,x.1"), STRING("and1 cy,x.2"), STRING("and1 cy,x.3"),
+	/* 0010 0100 */STRING("and1 cy,x.4"), STRING("and1 cy,x.5"), STRING("and1 cy,x.6"), STRING("and1 cy,x.7"),
+	/* 0010 1000 */STRING("and1 cy,a.0"), STRING("and1 cy,a.1"), STRING("and1 cy,a.2"), STRING("and1 cy,a.3"),
+	/* 0010 1100 */STRING("and1 cy,a.4"), STRING("and1 cy,a.5"), STRING("and1 cy,a.6"), STRING("and1 cy,a.7"),
+	/* 0011 0000 */STRING("and1 cy,/x.0"), STRING("and1 cy,/x.1"), STRING("and1 cy,/x.2"), STRING("and1 cy,/x.3"),
+	/* 0011 0100 */STRING("and1 cy,/x.4"), STRING("and1 cy,/x.5"), STRING("and1 cy,/x.6"), STRING("and1 cy,/x.7"),
+	/* 0011 1000 */STRING("and1 cy,/a.0"), STRING("and1 cy,/a.1"), STRING("and1 cy,/a.2"), STRING("and1 cy,/a.3"),
+	/* 0011 1100 */STRING("and1 cy,/a.4"), STRING("and1 cy,/a.5"), STRING("and1 cy,/a.6"), STRING("and1 cy,/a.7"),
+	/* 0100 0000 */STRING("or1 cy,x.0"), STRING("or1 cy,x.1"), STRING("or1 cy,x.2"), STRING("or1 cy,x.3"),
+	/* 0100 0100 */STRING("or1 cy,x.4"), STRING("or1 cy,x.5"), STRING("or1 cy,x.6"), STRING("or1 cy,x.7"),
+	/* 0100 1000 */STRING("or1 cy,a.0"), STRING("or1 cy,a.1"), STRING("or1 cy,a.2"), STRING("or1 cy,a.3"),
+	/* 0100 1100 */STRING("or1 cy,a.4"), STRING("or1 cy,a.5"), STRING("or1 cy,a.6"), STRING("or1 cy,a.7"),
+	/* 0101 0000 */STRING("or1 cy,/x.0"), STRING("or1 cy,/x.1"), STRING("or1 cy,/x.2"), STRING("or1 cy,/x.3"),
+	/* 0101 0100 */STRING("or1 cy,/x.4"), STRING("or1 cy,/x.5"), STRING("or1 cy,/x.6"), STRING("or1 cy,/x.7"),
+	/* 0101 1000 */STRING("or1 cy,/a.0"), STRING("or1 cy,/a.1"), STRING("or1 cy,/a.2"), STRING("or1 cy,/a.3"),
+	/* 0101 1100 */STRING("or1 cy,/a.4"), STRING("or1 cy,/a.5"), STRING("or1 cy,/a.6"), STRING("or1 cy,/a.7"),
+	/* 0110 0000 */STRING("xor1 cy,x.0"), STRING("xor1 cy,x.1"), STRING("xor1 cy,x.2"), STRING("xor1 cy,x.3"),
+	/* 0110 0100 */STRING("xor1 cy,x.4"), STRING("xor1 cy,x.5"), STRING("xor1 cy,x.6"), STRING("xor1 cy,x.7"),
+	/* 0110 1000 */STRING("xor1 cy,a.0"), STRING("xor1 cy,a.1"), STRING("xor1 cy,a.2"), STRING("xor1 cy,a.3"),
+	/* 0110 1100 */STRING("xor1 cy,a.4"), STRING("xor1 cy,a.5"), STRING("xor1 cy,a.6"), STRING("xor1 cy,a.7"),
+	/* 0111 0000 */STRING("not1 x.0"), STRING("not1 x.1"), STRING("not1 x.2"), STRING("not1 x.3"),
+	/* 0111 0100 */STRING("not1 x.4"), STRING("not1 x.5"), STRING("not1 x.6"), STRING("not1 x.7"),
+	/* 0111 1000 */STRING("not1 a.0"), STRING("not1 a.1"), STRING("not1 a.2"), STRING("not1 a.3"),
+	/* 0111 1100 */STRING("not1 a.4"), STRING("not1 a.5"), STRING("not1 a.6"), STRING("not1 a.7"),
+	/* 1000 0000 */STRING("set1 x.0"), STRING("set1 x.1"), STRING("set1 x.2"), STRING("set1 x.3"),
+	/* 1000 0100 */STRING("set1 x.4"), STRING("set1 x.5"), STRING("set1 x.6"), STRING("set1 x.7"),
+	/* 1000 1000 */STRING("set1 a.0"), STRING("set1 a.1"), STRING("set1 a.2"), STRING("set1 a.3"),
+	/* 1000 1100 */STRING("set1 a.4"), STRING("set1 a.5"), STRING("set1 a.6"), STRING("set1 a.7"),
+	/* 1001 0000 */STRING("clr1 x.0"), STRING("clr1 x.1"), STRING("clr1 x.2"), STRING("clr1 x.3"),
+	/* 1001 0100 */STRING("clr1 x.4"), STRING("clr1 x.5"), STRING("clr1 x.6"), STRING("clr1 x.7"),
+	/* 1001 1000 */STRING("clr1 a.0"), STRING("clr1 a.1"), STRING("clr1 a.2"), STRING("clr1 a.3"),
+	/* 1001 1100 */STRING("clr1 a.4"), STRING("clr1 a.5"), STRING("clr1 a.6"), STRING("clr1 a.7"),
+	/* 1010 0000 */BRANCH_REL("bf x.0,$%s"), BRANCH_REL("bf x.1,$%s"), BRANCH_REL("bf x.2,$%s"), BRANCH_REL("bf x.3,$%s"),
+	/* 1010 0100 */BRANCH_REL("bf x.4,$%s"), BRANCH_REL("bf x.5,$%s"), BRANCH_REL("bf x.6,$%s"), BRANCH_REL("bf x.7,$%s"),
+	/* 1010 1000 */BRANCH_REL("bf a.0,$%s"), BRANCH_REL("bf a.1,$%s"), BRANCH_REL("bf a.2,$%s"), BRANCH_REL("bf a.3,$%s"),
+	/* 1010 1100 */BRANCH_REL("bf a.4,$%s"), BRANCH_REL("bf a.5,$%s"), BRANCH_REL("bf a.6,$%s"), BRANCH_REL("bf a.7,$%s"),
+	/* 1011 0000 */BRANCH_REL("bt x.0,$%s"), BRANCH_REL("bt x.1,$%s"), BRANCH_REL("bt x.2,$%s"), BRANCH_REL("bt x.3,$%s"),
+	/* 1011 0100 */BRANCH_REL("bt x.4,$%s"), BRANCH_REL("bt x.5,$%s"), BRANCH_REL("bt x.6,$%s"), BRANCH_REL("bt x.7,$%s"),
+	/* 1011 1000 */BRANCH_REL("bt a.0,$%s"), BRANCH_REL("bt a.1,$%s"), BRANCH_REL("bt a.2,$%s"), BRANCH_REL("bt a.3,$%s"),
+	/* 1011 1100 */BRANCH_REL("bt a.4,$%s"), BRANCH_REL("bt a.5,$%s"), BRANCH_REL("bt a.6,$%s"), BRANCH_REL("bt a.7,$%s"),
+	/* 1100 0000 */INVALID, INVALID, INVALID, INVALID,
+	/* 1100 0100 */INVALID, INVALID, INVALID, INVALID,
+	/* 1100 1000 */INVALID, INVALID, INVALID, INVALID,
+	/* 1100 1100 */INVALID, INVALID, INVALID, INVALID,
+	/* 1101 0000 */BRANCH_REL("btclr x.0,$%s"), BRANCH_REL("btclr x.1,$%s"), BRANCH_REL("btclr x.2,$%s"), BRANCH_REL("btclr x.3,$%s"),
+	/* 1101 0100 */BRANCH_REL("btclr x.4,$%s"), BRANCH_REL("btclr x.5,$%s"), BRANCH_REL("btclr x.6,$%s"), BRANCH_REL("btclr x.7,$%s"),
+	/* 1101 1000 */BRANCH_REL("btclr a.0,$%s"), BRANCH_REL("btclr a.1,$%s"), BRANCH_REL("btclr a.2,$%s"), BRANCH_REL("btclr a.3,$%s"),
+	/* 1101 1100 */BRANCH_REL("btclr a.4,$%s"), BRANCH_REL("btclr a.5,$%s"), BRANCH_REL("btclr a.6,$%s"), BRANCH_REL("btclr a.7,$%s"),
+};
+upd_inst muldiv[256] = {
+	/* 0000 1000 */[0x08] = STRING("mulu x"), STRING("mulu a"), STRING("mulu c"), STRING("mulu b"),
+	/* 0000 1100 */STRING("mulu e"), STRING("mulu d"), STRING("mulu l"), STRING("mulu h"),
+	/* 0001 1000 */[0x18] = STRING("divuw x"), STRING("divuw a"), STRING("divuw c"), STRING("divuw b"),
+	/* 0001 1100 */STRING("divuw e"), STRING("divuw d"), STRING("divuw l"), STRING("divuw h"),
+	/* 0100 1000 */[0x48] = STRING("br ax"), INVALID, STRING("br bc"), INVALID,
+	/* 0100 1100 */STRING("br de"), INVALID, STRING("br hl"), INVALID,
+	/* 0101 1000 */[0x58] = STRING("call ax"), INVALID, STRING("call bc"), INVALID,
+	/* 0101 1100 */STRING("call de"), INVALID, STRING("call hl"), INVALID,
+	/* 1000 1100 */[0x8C] = STRING("ror4 [de]"), INVALID, STRING("ror4 [hl]"), INVALID,
+	/* 1001 1100 */[0x9C] = STRING("rol4 [de]"), INVALID, STRING("rol4 [hl]"), INVALID,
+	/* 1010 1000 */[0xA8] = STRING("sel rb0"), STRING("sel rb1"), STRING("sel rb2"), STRING("sel rb3"),
+	/* 1100 1000 */[0xC8] = STRING("incw sp"), STRING("decw sp"),
+	/* 1110 0010 */[0xE2] = STRING("movw ax,[de]"), STRING("movw ax,[hl]"),
+	/* 1110 0110 */[0xE6] = STRING("movw [de],ax"), STRING("movw [hl],ax")
+};
+upd_inst base[256] = {
+	/* 0000 0000 */BASE("mov a,[de+0%XH]"), INVALID, INVALID, INVALID,
+	/* 0000 0100 */BASE("xch a,[de+0%XH]"), INVALID, INVALID, INVALID,
+	/* 0000 1000 */BASE("add a,[de+0%XH]"), BASE("addc a,[de+0%XH]"), BASE("sub a,[de+0%XH]"), BASE("subc a,[de+0%XH]"),
+	/* 0000 1100 */BASE("and a,[de+0%XH]"), BASE("xor a,[de+0%XH]"), BASE("or a,[de+0%XH]"), BASE("cmp a,[de+0%XH]"),
+	/* 0001 0000 */BASE("mov a,[sp+0%XH]"), INVALID, INVALID, INVALID,
+	/* 0001 0100 */BASE("xch a,[sp+0%XH]"), INVALID, INVALID, INVALID,
+	/* 0001 1000 */BASE("add a,[sp+0%XH]"), BASE("addc a,[sp+0%XH]"), BASE("sub a,[sp+0%XH]"), BASE("subc a,[sp+0%XH]"),
+	/* 0001 1100 */BASE("and a,[sp+0%XH]"), BASE("xor a,[sp+0%XH]"), BASE("or a,[sp+0%XH]"), BASE("cmp a,[sp+0%XH]"),
+	/* 0010 0000 */BASE("mov a,[hl+0%XH]"), INVALID, INVALID, INVALID,
+	/* 0010 0100 */BASE("xch a,[hl+0%XH]"), INVALID, INVALID, INVALID,
+	/* 0010 1000 */BASE("add a,[hl+0%XH]"), BASE("addc a,[hl+0%XH]"), BASE("sub a,[hl+0%XH]"), BASE("subc a,[hl+0%XH]"),
+	/* 0010 1100 */BASE("and a,[hl+0%XH]"), BASE("xor a,[hl+0%XH]"), BASE("or a,[hl+0%XH]"), BASE("cmp a,[hl+0%XH]"),
+	/* 1000 0000 */[0x80] = BASE("mov [de+0%XH],a"),
+	/* 1001 0000 */[0x90] = BASE("mov [sp+0%XH],a"),
+	/* 1010 0000 */[0xA0] = BASE("mov [hl+0%XH],a")
+};
+upd_inst sfrbit[256] = {
+	/* 0000 0000 */SADDR("mov1 cy,%s.0"), SADDR("mov1 cy,%s.1"), SADDR("mov1 cy,%s.2"), SADDR("mov1 cy,%s.3"),
+	/* 0000 0100 */SADDR("mov1 cy,%s.4"), SADDR("mov1 cy,%s.5"), SADDR("mov1 cy,%s.6"), SADDR("mov1 cy,%s.7"),
+	/* 0000 1000 */SFR("mov1 cy,%s.0"), SFR("mov1 cy,%s.1"), SFR("mov1 cy,%s.2"), SFR("mov1 cy,%s.3"),
+	/* 0000 1100 */SFR("mov1 cy,%s.4"), SFR("mov1 cy,%s.5"), SFR("mov1 cy,%s.6"), SFR("mov1 cy,%s.7"),
+	/* 0001 0000 */SADDR("mov1 %s.0,cy"), SADDR("mov1 %s.1,cy"), SADDR("mov1 %s.2,cy"), SADDR("mov1 %s.3,cy"),
+	/* 0001 0100 */SADDR("mov1 %s.4,cy"), SADDR("mov1 %s.5,cy"), SADDR("mov1 %s.6,cy"), SADDR("mov1 %s.7,cy"),
+	/* 0001 1000 */SFR("mov1 %s.0,cy"), SFR("mov1 %s.1,cy"), SFR("mov1 %s.2,cy"), SFR("mov1 %s.3,cy"),
+	/* 0001 1100 */SFR("mov1 %s.4,cy"), SFR("mov1 %s.5,cy"), SFR("mov1 %s.6,cy"), SFR("mov1 %s.7,cy"),
+	/* 0010 0000 */SADDR("and1 cy,%s.0"), SADDR("and1 cy,%s.1"), SADDR("and1 cy,%s.2"), SADDR("and1 cy,%s.3"),
+	/* 0010 0100 */SADDR("and1 cy,%s.4"), SADDR("and1 cy,%s.5"), SADDR("and1 cy,%s.6"), SADDR("and1 cy,%s.7"),
+	/* 0010 1000 */SFR("and1 cy,%s.0"), SFR("and1 cy,%s.1"), SFR("and1 cy,%s.2"), SFR("and1 cy,%s.3"),
+	/* 0010 1100 */SFR("and1 cy,%s.4"), SFR("and1 cy,%s.5"), SFR("and1 cy,%s.6"), SFR("and1 cy,%s.7"),
+	/* 0011 0000 */SADDR("and1 cy,/%s.0"), SADDR("and1 cy,/%s.1"), SADDR("and1 cy,/%s.2"), SADDR("and1 cy,/%s.3"),
+	/* 0011 0100 */SADDR("and1 cy,/%s.4"), SADDR("and1 cy,/%s.5"), SADDR("and1 cy,/%s.6"), SADDR("and1 cy,/%s.7"),
+	/* 0011 1000 */SFR("and1 cy,/%s.0"), SFR("and1 cy,/%s.1"), SFR("and1 cy,/%s.2"), SFR("and1 cy,/%s.3"),
+	/* 0011 1100 */SFR("and1 cy,/%s.4"), SFR("and1 cy,/%s.5"), SFR("and1 cy,/%s.6"), SFR("and1 cy,/%s.7"),
+	/* 0100 0000 */SADDR("or1 cy,%s.0"), SADDR("or1 cy,%s.1"), SADDR("or1 cy,%s.2"), SADDR("or1 cy,%s.3"),
+	/* 0100 0100 */SADDR("or1 cy,%s.4"), SADDR("or1 cy,%s.5"), SADDR("or1 cy,%s.6"), SADDR("or1 cy,%s.7"),
+	/* 0100 1000 */SFR("or1 cy,%s.0"), SFR("or1 cy,%s.1"), SFR("or1 cy,%s.2"), SFR("or1 cy,%s.3"),
+	/* 0100 1100 */SFR("or1 cy,%s.4"), SFR("or1 cy,%s.5"), SFR("or1 cy,%s.6"), SFR("or1 cy,%s.7"),
+	/* 0101 0000 */SADDR("or1 cy,/%s.0"), SADDR("or1 cy,/%s.1"), SADDR("or1 cy,/%s.2"), SADDR("or1 cy,/%s.3"),
+	/* 0101 0100 */SADDR("or1 cy,/%s.4"), SADDR("or1 cy,/%s.5"), SADDR("or1 cy,/%s.6"), SADDR("or1 cy,/%s.7"),
+	/* 0101 1000 */SFR("or1 cy,/%s.0"), SFR("or1 cy,/%s.1"), SFR("or1 cy,/%s.2"), SFR("or1 cy,/%s.3"),
+	/* 0101 1100 */SFR("or1 cy,/%s.4"), SFR("or1 cy,/%s.5"), SFR("or1 cy,/%s.6"), SFR("or1 cy,/%s.7"),
+	/* 0110 0000 */SADDR("xor1 cy,%s.0"), SADDR("xor1 cy,%s.1"), SADDR("xor1 cy,%s.2"), SADDR("xor1 cy,%s.3"),
+	/* 0110 0100 */SADDR("xor1 cy,%s.4"), SADDR("xor1 cy,%s.5"), SADDR("xor1 cy,%s.6"), SADDR("xor1 cy,%s.7"),
+	/* 0110 1000 */SFR("xor1 cy,%s.0"), SFR("xor1 cy,%s.1"), SFR("xor1 cy,%s.2"), SFR("xor1 cy,%s.3"),
+	/* 0110 1100 */SFR("xor1 cy,%s.4"), SFR("xor1 cy,%s.5"), SFR("xor1 cy,%s.6"), SFR("xor1 cy,%s.7"),
+	/* 0111 0000 */SADDR("not1 %s.0"), SADDR("not1 %s.1"), SADDR("not1 %s.2"), SADDR("not1 %s.3"),
+	/* 0111 0100 */SADDR("not1 %s.4"), SADDR("not1 %s.5"), SADDR("not1 %s.6"), SADDR("not1 %s.7"),
+	/* 0111 1000 */SFR("not1 %s.0"), SFR("not1 %s.1"), SFR("not1 %s.2"), SFR("not1 %s.3"),
+	/* 0111 1100 */SFR("not1 %s.4"), SFR("not1 %s.5"), SFR("not1 %s.6"), SFR("not1 %s.7"),
+	/* 1000 0000 */SADDR("set1 %s.0"), SADDR("set1 %s.1"), SADDR("set1 %s.2"), SADDR("set1 %s.3"),
+	/* 1000 0100 */SADDR("set1 %s.4"), SADDR("set1 %s.5"), SADDR("set1 %s.6"), SADDR("set1 %s.7"),
+	/* 1000 1000 */SFR("set1 %s.0"), SFR("set1 %s.1"), SFR("set1 %s.2"), SFR("set1 %s.3"),
+	/* 1000 1100 */SFR("set1 %s.4"), SFR("set1 %s.5"), SFR("set1 %s.6"), SFR("set1 %s.7"),
+	/* 1001 0000 */SADDR("clr1 %s.0"), SADDR("clr1 %s.1"), SADDR("clr1 %s.2"), SADDR("clr1 %s.3"),
+	/* 1001 0100 */SADDR("clr1 %s.4"), SADDR("clr1 %s.5"), SADDR("clr1 %s.6"), SADDR("clr1 %s.7"),
+	/* 1001 1000 */SFR("clr1 %s.0"), SFR("clr1 %s.1"), SFR("clr1 %s.2"), SFR("clr1 %s.3"),
+	/* 1001 1100 */SFR("clr1 %s.4"), SFR("clr1 %s.5"), SFR("clr1 %s.6"), SFR("clr1 %s.7"),
+	/* 1010 0000 */BRANCH_SADDR("bf %s.0,$%s"), BRANCH_SADDR("bf %s.1,$%s"), BRANCH_SADDR("bf %s.2,$%s"), BRANCH_SADDR("bf %s.3,$%s"),
+	/* 1010 0100 */BRANCH_SADDR("bf %s.4,$%s"), BRANCH_SADDR("bf %s.5,$%s"), BRANCH_SADDR("bf %s.6,$%s"), BRANCH_SADDR("bf %s.7,$%s"),
+	/* 1010 1000 */BRANCH_SFR("bf %s.0,$%s"), BRANCH_SFR("bf %s.1,$%s"), BRANCH_SFR("bf %s.2,$%s"), BRANCH_SFR("bf %s.3,$%s"),
+	/* 1010 1100 */BRANCH_SFR("bf %s.4,$%s"), BRANCH_SFR("bf %s.5,$%s"), BRANCH_SFR("bf %s.6,$%s"), BRANCH_SFR("bf %s.7,$%s"),
+	/* 1011 1000 */[0xB8] = BRANCH_SFR("bt %s.0,$%s"), BRANCH_SFR("bt %s.1,$%s"), BRANCH_SFR("bt %s.2,$%s"), BRANCH_SFR("bt %s.3,$%s"),
+	/* 1011 1100 */BRANCH_SFR("bt %s.4,$%s"), BRANCH_SFR("bt %s.5,$%s"), BRANCH_SFR("bt %s.6,$%s"), BRANCH_SFR("bt %s.7,$%s"),
+	/* 1101 0000 */[0xD0] = BRANCH_SADDR("btclr %s.0,$%s"), BRANCH_SADDR("btclr %s.1,$%s"), BRANCH_SADDR("btclr %s.2,$%s"), BRANCH_SADDR("btclr %s.3,$%s"),
+	/* 1101 0100 */BRANCH_SADDR("btclr %s.4,$%s"), BRANCH_SADDR("btclr %s.5,$%s"), BRANCH_SADDR("btclr %s.6,$%s"), BRANCH_SADDR("btclr %s.7,$%s"),
+	/* 1101 1000 */BRANCH_SFR("btclr %s.0,$%s"), BRANCH_SFR("btclr %s.1,$%s"), BRANCH_SFR("btclr %s.2,$%s"), BRANCH_SFR("btclr %s.3,$%s"),
+	/* 1101 1100 */BRANCH_SFR("btclr %s.4,$%s"), BRANCH_SFR("btclr %s.5,$%s"), BRANCH_SFR("btclr %s.6,$%s"), BRANCH_SFR("btclr %s.7,$%s"),
+};
+upd_inst spmov[256] = {
+	[0xC0] = CUSTOM(disasm_mov_stbc),
+	[0xF0] = ADDR16("mov a,!%s"), ADDR16("mov !%s,a")
+};
+upd_inst indexed[256] = {
+	/* 0000 0000 */INDEXED("mov a,0%XH[de]"), INVALID, INVALID, INVALID,
+	/* 0000 0100 */INDEXED("xch a,0%XH[de]"), INVALID, INVALID, INVALID,
+	/* 0000 1000 */INDEXED("add a,0%XH[de]"), INDEXED("addc a,0%XH[de]"), INDEXED("sub a,0%XH[de]"), INDEXED("subc a,0%XH[de]"),
+	/* 0000 1100 */INDEXED("and a,0%XH[de]"), INDEXED("xor a,0%XH[de]"), INDEXED("or a,0%XH[de]"), INDEXED("cmp a,0%XH[de]"),
+	/* 0001 0000 */INDEXED("mov a,0%XH[a]"), INVALID, INVALID, INVALID,
+	/* 0001 0100 */INDEXED("xch a,0%XH[a]"), INVALID, INVALID, INVALID,
+	/* 0001 1000 */INDEXED("add a,0%XH[a]"), INDEXED("addc a,0%XH[a]"), INDEXED("sub a,0%XH[a]"), INDEXED("subc a,0%XH[a]"),
+	/* 0001 1100 */INDEXED("and a,0%XH[a]"), INDEXED("xor a,0%XH[a]"), INDEXED("or a,0%XH[a]"), INDEXED("cmp a,0%XH[a]"),
+	/* 0010 0000 */INDEXED("mov a,0%XH[hl]"), INVALID, INVALID, INVALID,
+	/* 0010 0100 */INDEXED("xch a,0%XH[hl]"), INVALID, INVALID, INVALID,
+	/* 0010 1000 */INDEXED("add a,0%XH[hl]"), INDEXED("addc a,0%XH[hl]"), INDEXED("sub a,0%XH[hl]"), INDEXED("subc a,0%XH[hl]"),
+	/* 0010 1100 */INDEXED("and a,0%XH[hl]"), INDEXED("xor a,0%XH[hl]"), INDEXED("or a,0%XH[hl]"), INDEXED("cmp a,0%XH[hl]"),
+	/* 0011 0000 */INDEXED("mov a,0%XH[b]"), INVALID, INVALID, INVALID,
+	/* 0011 0100 */INDEXED("xch a,0%XH[b]"), INVALID, INVALID, INVALID,
+	/* 0011 1000 */INDEXED("add a,0%XH[b]"), INDEXED("addc a,0%XH[b]"), INDEXED("sub a,0%XH[b]"), INDEXED("subc a,0%XH[b]"),
+	/* 0011 1100 */INDEXED("and a,0%XH[b]"), INDEXED("xor a,0%XH[b]"), INDEXED("or a,0%XH[b]"), INDEXED("cmp a,0%XH[b]"),
+	/* 1000 0000 */[0x80] = INDEXED("mov 0%XH[de],a"),
+	/* 1001 0000 */[0x90] = INDEXED("mov 0%XH[a],a"),
+	/* 1010 0000 */[0xA0] = INDEXED("mov 0%XH[hl],a"),
+	/* 1011 0000 */[0xB0] = INDEXED("mov 0%XH[b],a")
+};
+upd_inst regind[256] = {
+	/* 0000 0000 */STRING("mov a,[de+]"), INVALID, INVALID, INVALID,
+	/* 0000 0100 */STRING("xch a,[de+]"), INVALID, INVALID, INVALID,
+	/* 0000 1000 */STRING("add a,[de+]"), STRING("addc a,[de+]"), STRING("sub a,[de+]"), STRING("subc a,[de+]"),
+	/* 0000 1100 */STRING("and a,[de+]"), STRING("xor a,[de+]"), STRING("or a,[de+]"), STRING("cmp a,[de+]"),
+	/* 0001 0000 */STRING("mov a,[hl+]"), INVALID, INVALID, INVALID,
+	/* 0001 0100 */STRING("xch a,[hl+]"), INVALID, INVALID, INVALID,
+	/* 0001 1000 */STRING("add a,[hl+]"), STRING("addc a,[hl+]"), STRING("sub a,[hl+]"), STRING("subc a,[hl+]"),
+	/* 0001 1100 */STRING("and a,[hl+]"), STRING("xor a,[hl+]"), STRING("or a,[hl+]"), STRING("cmp a,[hl+]"),
+	/* 0010 0000 */STRING("mov a,[de-]"), INVALID, INVALID, INVALID,
+	/* 0010 0100 */STRING("xch a,[de-]"), INVALID, INVALID, INVALID,
+	/* 0010 1000 */STRING("add a,[de-]"), STRING("addc a,[de-]"), STRING("sub a,[de-]"), STRING("subc a,[de-]"),
+	/* 0010 1100 */STRING("and a,[de-]"), STRING("xor a,[de-]"), STRING("or a,[de-]"), STRING("cmp a,[de-]"),
+	/* 0011 0000 */STRING("mov a,[hl-]"), INVALID, INVALID, INVALID,
+	/* 0011 0100 */STRING("xch a,[hl-]"), INVALID, INVALID, INVALID,
+	/* 0011 1000 */STRING("add a,[hl-]"), STRING("addc a,[hl-]"), STRING("sub a,[hl-]"), STRING("subc a,[hl-]"),
+	/* 0011 1100 */STRING("and a,[hl-]"), STRING("xor a,[hl-]"), STRING("or a,[hl-]"), STRING("cmp a,[hl-]"),
+	/* 0100 0000 */STRING("mov a,[de]"), INVALID, INVALID, INVALID,
+	/* 0100 0100 */STRING("xch a,[de]"), INVALID, INVALID, INVALID,
+	/* 0100 1000 */STRING("add a,[de]"), STRING("addc a,[de]"), STRING("sub a,[de]"), STRING("subc a,[de]"),
+	/* 0100 1100 */STRING("and a,[de]"), STRING("xor a,[de]"), STRING("or a,[de]"), STRING("cmp a,[de]"),
+	/* 0101 0000 */STRING("mov a,[hl]"), INVALID, INVALID, INVALID,
+	/* 0101 0100 */STRING("xch a,[hl]"), INVALID, INVALID, INVALID,
+	/* 0101 1000 */STRING("add a,[hl]"), STRING("addc a,[hl]"), STRING("sub a,[hl]"), STRING("subc a,[hl]"),
+	/* 0101 1100 */STRING("and a,[hl]"), STRING("xor a,[hl]"), STRING("or a,[hl]"), STRING("cmp a,[hl]"),
+	/* 1000 0000 */[0x80] = STRING("mov [de+],a"),
+	/* 1001 0000 */[0x90] = STRING("mov [hl+],a"),
+	/* 1010 0000 */[0xA0] = STRING("mov [de-],a"),
+	/* 1011 0000 */[0xB0] = STRING("mov [hl-],a"),
+	/* 1100 0000 */[0x80] = STRING("mov [de],a"),
+	/* 1101 0000 */[0x90] = STRING("mov [hl],a")
+};
+
+upd_inst maint[256] = {
+	/* 0000 0000 */STRING("nop"), PREFIX(sfr), PREFIX(bit1), PREFIX(bit2),
+	/* 0000 0100 */INVALID, PREFIX(muldiv), PREFIX(base), INVALID,
+	/* 0000 1000 */PREFIX(sfrbit), PREFIX(spmov), PREFIX(indexed), CUSTOM(disasm_sfr_mov16),
+	/* 0000 1100 */SADDR_WORD("movw %s, #0%XH"), INVALID, STRING("adjba"), STRING("adjbs"),
+	/* 0001 0000 */CUSTOM(disasm_mov_a_sfr), CUSTOM(disasm_movw_ax_sfr), CUSTOM(disasm_mov_sfr_a), CUSTOM(disasm_movw_sfr_ax),
+	/* 0001 0100 */BRANCH_REL("br $%s"), INVALID, PREFIX(regind), INVALID, 
+	/* 0001 1000 */INVALID, INVALID, SADDR("movw %s,ax"), INVALID,
+	/* 0001 1100 */SADDR("movw ax,%s"), SADDR("addw ax,%s"), SADDR("subw ax,%s"), SADDR("cmpw ax,%s"),
+	/* 0010 0000 */SADDR("mov a,%s"), SADDR("xch a,%s"), SADDR("mov %s,a"), INVALID,
+	/* 0010 0100 */CUSTOM(disasm_mov_r_r), REG_REG("mov %c,%c"), SADDR("inc %s"), SADDR("dec %s"),
+	/* 0010 1000 */BRANCH_ABS("call !%s"), SFR("push %s"), SFR("pop %s"), CUSTOM(disasm_mov_sfr_byte),
+	/* 0010 1100 */BRANCH_ABS("br !%s"), WORD("addw ax,#0%XH"), WORD("subw ax,#0%XH"), WORD("cmpw ax,#0%XH"),
+	/* 0011 0000 */CUSTOM(disasm_shift_right), CUSTOM(disasm_shift_left), BRANCH_REL("dbnz c,$%s"), BRANCH_REL("dbnz b,$%s"),
+	/* 0011 0100 */STRING("pop ax"), STRING("pop bc"), STRING("pop de"), STRING("pop hl"),
+	/* 0011 1000 */SADDR_SADDR("mov %s,%s"), SADDR_SADDR("xch %s,%s"), SADDR_BYTE("mov %s, #0%XH"), BRANCH_SADDR("dbnz %s,$%s"),
+	/* 0011 1100 */STRING("push ax"), STRING("push bc"), STRING("push de"), STRING("push hl"),
+	/* 0100 0000 */STRING("clr1 cy"), STRING("set1 cy"), STRING("not1 cy"), SFR("pop %s"),
+	/* 0100 0100 */STRING("incw ax"), STRING("incw bc"), STRING("incw de"), STRING("incw hl"),
+	/* 0100 1000 */STRING("pop psw"), STRING("push psw"), STRING("di"), STRING("ei"),
+	/* 0100 1100 */STRING("decw ax"), STRING("decw bc"), STRING("decw de"), STRING("decw hl"),
+	/* 0101 0000 */STRING("mov [de+],a"), STRING("mov [hl+],a"), STRING("mov [de-],a"), STRING("mov [hl-],a"),
+	/* 0101 0100 */STRING("mov [de],a"), STRING("mov [hl],a"), STRING("ret"), STRING("reti"),
+	/* 0101 1000 */STRING("mov a,[de+]"), STRING("mov a,[hl+]"), STRING("mov a,[de-]"), STRING("mov a,[hl-]"),
+	/* 0101 1100 */STRING("mov a,[de]"), STRING("mov a,[hl]"), STRING("brk"), STRING("retb"),
+	/* 0110 0000 */WORD("movw ax,#0%XH"), INVALID, WORD("movw bc,#0%XH"), INVALID,
+	/* 0110 0100 */WORD("movw de,#0%XH"), INVALID, WORD("movw hl,#0%XH"), INVALID,
+	/* 0110 1000 */SADDR_BYTE("add %s, #0%XH"), SADDR_BYTE("addc %s, #0%XH"), SADDR_BYTE("sub %s, #0%XH"), SADDR_BYTE("subc %s, #0%XH"),
+	/* 0110 1100 */SADDR_BYTE("and %s, #0%XH"), SADDR_BYTE("xor %s, #0%XH"), SADDR_BYTE("or %s, #0%XH"), SADDR_BYTE("cmp %s, #0%XH"),
+	/* 0111 0000 */BRANCH_SADDR("bt %s.0,%s"), BRANCH_SADDR("bt %s.1,%s"), BRANCH_SADDR("bt %s.2,%s"), BRANCH_SADDR("bt %s.3,%s"),
+	/* 0111 0100 */BRANCH_SADDR("bt %s.4,%s"), BRANCH_SADDR("bt %s.5,%s"), BRANCH_SADDR("bt %s.6,%s"), BRANCH_SADDR("bt %s.7,%s"),
+	/* 0111 1000 */SADDR_SADDR("add %s,%s"), SADDR_SADDR("addc %s,%s"), SADDR_SADDR("sub %s,%s"), SADDR_SADDR("subc %s,%s"),
+	/* 0111 1100 */SADDR_SADDR("and %s,%s"), SADDR_SADDR("xor %s,%s"), SADDR_SADDR("or %s,%s"), SADDR_SADDR("cmp %s,%s"),
+	/* 1000 0000 */BRANCH_REL("bnz $%s"), BRANCH_REL("bz $%s"), BRANCH_REL("bnc $%s"), BRANCH_REL("bc $%s"),
+	/* 1000 0100 */INVALID, INVALID, INVALID, INVALID,
+	/* 1000 1000 */CUSTOM(disasm_add_r_r), REG_REG("addc %c,%c"), CUSTOM(disasm_sub_r_r), REG_REG("subc %c,%c"),
+	/* 1000 1100 */REG_REG("and %c,%c"), REG_REG("xor %c,%c"), REG_REG("or %c,%c"), CUSTOM(disasm_cmp_r_r),
+	/* 1001 0000 */CALLF, CALLF, CALLF, CALLF,
+	/* 1001 0100 */CALLF, CALLF, CALLF, CALLF,
+	/* 1001 1000 */SADDR("add a,%s"), SADDR("addc a,%s"), SADDR("sub a,%s"), SADDR("subc a,%s"), 
+	/* 1001 1100 */SADDR("and a,%s"), SADDR("xor a,%s"), SADDR("or a,%s"), SADDR("cmp a,%s"),
+	/* 1010 0000 */SADDR("clr1 %s.0"), SADDR("clr1 %s.1"), SADDR("clr1 %s.2"), SADDR("clr1 %s.3"),
+	/* 1010 0100 */SADDR("clr1 %s.4"), SADDR("clr1 %s.5"), SADDR("clr1 %s.6"), SADDR("clr1 %s.7"),
+	/* 1010 1000 */BYTE("add a,#0%XH"), BYTE("addc a,#0%XH"), BYTE("sub a,#0%XH"), BYTE("subc a,#0%XH"),
+	/* 1010 1100 */BYTE("and a,#0%XH"), BYTE("xor a,#0%XH"), BYTE("or a,#0%XH"), BYTE("cmp a,#0%XH"),
+	/* 1011 0000 */SADDR("set1 %s.0"), SADDR("set1 %s.1"), SADDR("set1 %s.2"), SADDR("set1 %s.3"),
+	/* 1011 0100 */SADDR("set1 %s.4"), SADDR("set1 %s.5"), SADDR("set1 %s.6"), SADDR("set1 %s.7"),
+	/* 1011 1000 */BYTE("mov x,#0%XH"), BYTE("mov a,#0%XH"), BYTE("mov c,#0%XH"), BYTE("mov b,#0%XH"),
+	/* 1011 1100 */BYTE("mov e,#0%XH"), BYTE("mov d,#0%XH"), BYTE("mov l,#0%XH"), BYTE("mov h,#0%XH"),
+	/* 1100 0000 */STRING("inc x"), STRING("inc a"), STRING("inc c"), STRING("inc b"),
+	/* 1100 0100 */STRING("inc e"), STRING("inc d"), STRING("inc l"), STRING("inc h"),
+	/* 1100 1000 */STRING("dec x"), STRING("dec a"), STRING("dec c"), STRING("dec b"),
+	/* 1100 1100 */STRING("dec e"), STRING("dec d"), STRING("dec l"), STRING("dec h"),
+	/* 1101 0000 */STRING("mov a,x"), STRING("mov a,a"), STRING("mov a,c"), STRING("mov a,b"),
+	/* 1101 0100 */STRING("mov a,e"), STRING("mov a,d"), STRING("mov a,l"), STRING("mov a,h"),
+	/* 1101 1000 */STRING("xch a,x"), STRING("xch a,a"), STRING("xch a,c"), STRING("xch a,b"),
+	/* 1101 1100 */STRING("xch a,e"), STRING("xch a,d"), STRING("xch a,l"), STRING("xch a,h"),
+	/* 1110 0000 */CALLT, CALLT, CALLT, CALLT,
+	/* 1110 0100 */CALLT, CALLT, CALLT, CALLT,
+	/* 1110 1000 */CALLT, CALLT, CALLT, CALLT,
+	/* 1110 1100 */CALLT, CALLT, CALLT, CALLT,
+	/* 1111 0000 */CALLT, CALLT, CALLT, CALLT,
+	/* 1111 0100 */CALLT, CALLT, CALLT, CALLT,
+	/* 1111 1000 */CALLT, CALLT, CALLT, CALLT,
+	/* 1111 1100 */CALLT, CALLT, CALLT, CALLT,
+};
+
+uint16_t upd78k2_disasm(char *dst, upd_address_ref *ref, uint16_t address, upd_fetch_fun fetch, void *data, disasm_context *context)
+{
+	static const char regnames[] = "xacbedlh";
+	char addr_buf[256], addr_buf2[256];
+	uint8_t opcode = fetch(address++, data);
+	uint8_t byte;
+	uint16_t word;
+	upd_inst *table = maint;
+	while (table[opcode].type == T_PREFIX)
+	{
+		table = table[opcode].v.prefix;
+		opcode = fetch(address++, data);
+	}
+	uint16_t ref_addr = 0, ref_addr2 = 0;
+	uint8_t ref_type = UPD_REF_NONE;
+	switch (table[opcode].type)
+	{
+	case T_INVALID:
+		strcpy(dst, "invalid");
+		break;
+	case T_STRING:
+		strcpy(dst, table[opcode].v.str);
+		break;
+	case T_REG_REG:
+		byte = fetch(address++, data);
+		sprintf(dst, table[opcode].v.str, regnames[byte >> 4 & 7], regnames[byte & 7]);
+		break;
+	case T_SFR:
+		ref_addr = 0xFF00 | fetch(address++, data);
+		ref_type = UPD_REF_OP;
+		format_address(context, addr_buf, ref_addr);
+		sprintf(dst, table[opcode].v.str, addr_buf);
+		break;
+	case T_SFR_BYTE:
+		ref_addr = 0xFF00 | fetch(address++, data);
+		ref_type = UPD_REF_OP;
+		byte = fetch(address++, data);
+		format_address(context, addr_buf, ref_addr);
+		sprintf(dst, table[opcode].v.str, addr_buf, byte);
+		break;
+	case T_SFR_WORD:
+		ref_addr = 0xFF00 | fetch(address++, data);
+		ref_type = UPD_REF_OP;
+		word = fetch(address++, data);
+		word |= fetch(address++, data) << 8;
+		format_address(context, addr_buf, ref_addr);
+		sprintf(dst, table[opcode].v.str, addr_buf, word);
+		break;
+	case T_SADDR:
+		ref_addr = fetch(address++, data);
+		ref_addr |= ref_addr < 0x20 ? 0xFF00 : 0xFE00;
+		ref_type = UPD_REF_OP;
+		format_address(context, addr_buf, ref_addr);
+		sprintf(dst, table[opcode].v.str, addr_buf);
+		break;
+	case T_SADDR_BYTE:
+		ref_addr = fetch(address++, data);
+		ref_addr |= ref_addr < 0x20 ? 0xFF00 : 0xFE00;
+		ref_type = UPD_REF_OP;
+		byte = fetch(address++, data);
+		format_address(context, addr_buf, ref_addr);
+		sprintf(dst, table[opcode].v.str, addr_buf, byte);
+		break;
+	case T_SADDR_WORD:
+		ref_addr = fetch(address++, data);
+		ref_addr |= ref_addr < 0x20 ? 0xFF00 : 0xFE00;
+		ref_type = UPD_REF_OP;
+		word = fetch(address++, data);
+		word |= fetch(address++, data) << 8;
+		format_address(context, addr_buf, ref_addr);
+		sprintf(dst, table[opcode].v.str, addr_buf, word);
+		break;
+	case T_SADDR_SADDR:
+		ref_addr = fetch(address++, data);
+		ref_addr |= ref_addr < 0x20 ? 0xFF00 : 0xFE00;
+		ref_addr2 = fetch(address++, data);
+		ref_addr2 |= ref_addr2 < 0x20 ? 0xFF00 : 0xFE00;
+		ref_type = UPD_REF_2OP;
+		format_address(context, addr_buf, ref_addr);
+		format_address(context, addr_buf2, ref_addr2);
+		sprintf(dst, table[opcode].v.str, addr_buf, addr_buf2);
+		break;
+	case T_BYTE:
+	case T_BASE:
+		byte = fetch(address++, data);
+		sprintf(dst, table[opcode].v.str, byte);
+		break;
+	case T_WORD:
+	case T_INDEXED:
+		word = fetch(address++, data);
+		word |= fetch(address++, data) << 8;
+		sprintf(dst, table[opcode].v.str, word);
+		break;
+	case T_ADDR16:
+		ref_addr = fetch(address++, data);
+		ref_addr |= fetch(address++, data) << 8;
+		ref_type = UPD_REF_OP;
+		format_address(context, addr_buf, ref_addr);
+		sprintf(dst, table[opcode].v.str, addr_buf);
+		break;
+	case T_BR_REL:
+		ref_addr = fetch(address++, data);
+		if (ref_addr & 0x80) {
+			ref_addr |= 0xFF00;
+		}
+		ref_addr += address;
+		ref_type = table[opcode].v.str[1] == 'r' ? UPD_REF_BRANCH : UPD_REF_COND_BRANCH;
+		format_address(context, addr_buf, ref_addr);
+		sprintf(dst, table[opcode].v.str, addr_buf);
+		break;
+	case T_BR_ABS:
+		ref_addr = fetch(address++, data);
+		ref_addr |= fetch(address++, data) << 8;
+		ref_type = table[opcode].v.str[0] == 'c' ? UPD_REF_CALL : UPD_REF_BRANCH;
+		format_address(context, addr_buf, ref_addr);
+		sprintf(dst, table[opcode].v.str, addr_buf);
+		break;
+	case T_BR_SFR:
+		ref_addr = 0xFF00 | fetch(address++, data);
+		ref_addr2 = fetch(address++, data);
+		if (ref_addr2 & 0x80) {
+			ref_addr2 |= 0xFF00;
+		}
+		ref_addr2 += address;
+		ref_type = UPD_REF_OP_BRANCH;
+		format_address(context, addr_buf, ref_addr);
+		format_address(context, addr_buf2, ref_addr2);
+		sprintf(dst, table[opcode].v.str, addr_buf, addr_buf2);
+		break;
+	case T_BR_SADDR:
+		ref_addr = fetch(address++, data);
+		ref_addr |= ref_addr < 0x20 ? 0xFF00 : 0xFE00;
+		ref_addr2 = fetch(address++, data);
+		if (ref_addr2 & 0x80) {
+			ref_addr2 |= 0xFF00;
+		}
+		ref_addr2 += address;
+		ref_type = UPD_REF_OP_BRANCH;
+		format_address(context, addr_buf, ref_addr);
+		format_address(context, addr_buf2, ref_addr2);
+		sprintf(dst, table[opcode].v.str, addr_buf, addr_buf2);
+		break;
+	case T_CALLF:
+		ref_addr = opcode << 8 & 0x700;
+		ref_addr |= 0x800 | fetch(address++, data);
+		ref_type = UPD_REF_CALL;
+		format_address(context, addr_buf, ref_addr);
+		sprintf(dst, "callf !%s", addr_buf);
+		break;
+	case T_CALLT:
+		ref_addr = opcode << 1& 0x3E;
+		ref_addr |= 0x40;
+		ref_type = UPD_REF_CALL_TABLE;
+		format_address(context, addr_buf, ref_addr);
+		sprintf(dst, "callt [%s]", addr_buf);
+		break;
+	case T_CUSTOM:
+		return table[opcode].v.fun(dst, ref, address, fetch, data, context);
+	}
+	if (ref) {
+		ref->address = ref_addr;
+		ref->address2 = ref_addr2;
+		ref->ref_type = ref_type;
+	}
+	return address;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/upd78k2_dis.h	Wed Jul 16 07:36:01 2025 -0700
@@ -0,0 +1,28 @@
+#ifndef UPD78K2_DIS_H_
+#define UPD78K2_DIS_H_
+#include <stdint.h>
+#include "disasm.h"
+
+enum {
+	UPD_REF_NONE,
+	UPD_REF_OP,
+	UPD_REF_2OP,
+	UPD_REF_BRANCH,
+	UPD_REF_COND_BRANCH,
+	UPD_REF_OP_BRANCH,
+	UPD_REF_CALL,
+	UPD_REF_CALL_TABLE
+};
+
+typedef struct {
+	uint16_t address;
+	uint16_t address2;
+	uint8_t  ref_type;
+} upd_address_ref;
+
+typedef uint8_t (*upd_fetch_fun)(uint16_t address, void *data);
+
+uint16_t upd78k2_disasm(char *dst, upd_address_ref *ref, uint16_t address, upd_fetch_fun fetch, void *data, disasm_context *context);
+
+
+#endif //UPD78K2_DIS_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/upddis.c	Wed Jul 16 07:36:01 2025 -0700
@@ -0,0 +1,356 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include "upd78k2_dis.h"
+#include "util.h"
+
+int headless;
+void render_errorbox(char *title, char *message) {}
+void render_warnbox(char *title, char *message) {}
+void render_infobox(char *title, char *message) {}
+
+typedef struct {
+	uint16_t address_off;
+	uint16_t address_end;
+	uint8_t *buffer;
+} rom_def;
+
+uint8_t fetch(uint16_t address, void *data)
+{
+	rom_def *rom = data;
+	if (address >= rom->address_off && address < rom->address_end) {
+		return rom->buffer[(address - rom->address_off)];
+	}
+	return 0;
+}
+
+void print_label_def(char *key, tern_val val, uint8_t valtype, void *data)
+{
+	rom_def *rom = data;
+	label_def *label = val.ptrval;
+	uint32_t address = label->full_address & 0xFFFF;
+	if (address >= rom->address_off && address < rom->address_end) {
+		return;
+	}
+	if (!label->referenced) {
+		return;
+	}
+	if (label->num_labels) {
+		for (int i = 0; i < label->num_labels; i++)
+		{
+			printf("%s equ 0%XH\n", label->labels[i], label->full_address);
+		}
+	} else {
+		printf("ADR_%X equ 0%XH\n", label->full_address, label->full_address);
+	}
+}
+
+void format_data(disasm_context *context, rom_def *rom, uint8_t labels, uint16_t start_address, uint16_t end_address)
+{
+	char label_buf[256];
+	for (uint16_t address = start_address; address < end_address;)
+	{
+		if (labels) {
+			uint16_t end = address + 8;
+			if (end > end_address) {
+				end = end_address;
+			}
+			uint16_t start = address;
+			if (!(address & 1) && address < 0x80) {
+				for (; address < end; address += 2) {
+					uint16_t value = fetch(address, rom);
+					value |= fetch(address + 1, rom) << 8;
+					format_label(label_buf, value, context);
+					if (address == start) {
+						printf("\tdw %s", label_buf);
+					} else {
+						printf(", %s", label_buf);
+					}
+				}
+			} else {
+				if (address < 0x80) {
+					end = address + 1;
+				}
+				for (; address < end; address++) {
+					uint8_t value = fetch(address, rom);
+					if (address == start) {
+						printf("\tdb 0%02XH", value);
+					} else {
+						printf(", 0%02XH", value);
+					}
+				}
+			}
+			address = end;
+			puts("");
+		} else {
+			uint8_t value = fetch(address, rom);
+			printf("%X: %X\n", address, value);
+			address++;
+		}
+	}
+}
+
+int main(int argc, char ** argv)
+{
+	long filesize;
+	uint8_t *filebuf = NULL;
+	char disbuf[1024];
+
+	uint8_t labels = 0, addr = 0, only = 0, reset = 0;
+	disasm_context *context = create_upd78k2_disasm();
+	
+	uint32_t address_off = 0, address_end;
+	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 'r':
+				reset = 1;
+				break;
+			case 's':
+				opt++;
+				if (opt >= argc) {
+					fputs("-s must be followed by an offset\n", stderr);
+					exit(1);
+				}
+				address_off = strtol(argv[opt], NULL, 0);
+				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]) {
+						char *end;
+						uint32_t address = strtol(disbuf, &end, 16);
+						if (address) {
+							defer_disasm(context, address);
+							if (*end == '=') {
+								add_label(context, strip_ws(end+1), address);
+							} else {
+								reference(context, address);
+							}
+						}
+					}
+				}
+				fclose(address_log);
+			}
+		} else {
+			char *end;
+			uint32_t address = strtol(argv[opt], &end, 16);
+			defer_disasm(context, address);
+			if (*end == '=') {
+				add_label(context, end+1, address);
+			} else {
+				reference(context, address);
+			}
+		}
+	}
+	if (labels) {
+		add_upd7823x_labels(context);
+	}
+	FILE * f = fopen(argv[1], "rb");
+	fseek(f, 0, SEEK_END);
+	filesize = ftell(f);
+	fseek(f, 0, SEEK_SET);
+
+	char int_key[MAX_INT_KEY_SIZE];
+	uint8_t has_manual_defs = !!context->deferred;
+	filebuf = malloc(filesize);
+	if (fread(filebuf, 1, filesize, f) != filesize)
+	{
+		fprintf(stderr, "Failure while reading file %s\n", argv[1]);
+	}
+	address_end = address_off + filesize;
+	if (address_end > 0xFB00) {
+		//correct for uPD78237 and some other members of the uPD78K/II family
+		//but others allow external ROM up to higher addresses
+		address_end = 0xFB00;
+	}
+	if (!address_off && filesize >= 0x40) {
+		char *vector_names[] = {
+			"reset",
+			"nmi",
+			NULL,
+			"intp0",
+			"intp1",
+			"intp2",
+			"intp3",
+			"intp4_intc30",
+			"intp5_intad",
+			"intc20_intp6",
+			"intc00",
+			"intc01",
+			"intc10",
+			"intc11",
+			"intc21",
+			NULL,
+			"intser",
+			"intsr",
+			"intst",
+			"intcsi",
+			[0x3E/2] = "brkex"
+		};
+		for (int i = 0; i < sizeof(vector_names)/sizeof(*vector_names); i++)
+		{
+			if (vector_names[i]) {
+				uint16_t address = filebuf[i * 2] | (filebuf[i * 2 + 1] << 8);
+				if (address < address_end) {
+					defer_disasm(context, address);
+					add_label(context, vector_names[i], address);
+				}
+			}
+		}
+	}
+	rom_def rom = {
+		.address_off = address_off,
+		.address_end = address_end,
+		.buffer = filebuf
+	};
+	uint16_t address, tmp_addr;
+	uint8_t valid_address;
+	while(context->deferred) {
+		do {
+			valid_address = 0;
+			address = context->deferred->address;
+			if (!is_visited(context, address)) {
+				address &= context->address_mask;
+				if (address < address_end && address >= address_off) {
+					valid_address = 1;
+					address = context->deferred->address;
+				}
+			}
+			deferred_addr *tmpd = context->deferred;
+			context->deferred = context->deferred->next;
+			free(tmpd);
+		} while(context->deferred && !valid_address);
+		if (!valid_address) {
+			break;
+		}
+		for(;;) {
+			if ((address & context->address_mask) > address_end || address < address_off) {
+				break;
+			}
+			visit(context, address);
+			upd_address_ref ref;
+			address = upd78k2_disasm(disbuf, &ref, address, fetch, &rom, NULL);
+			if (!strcmp(disbuf, "invalid") || startswith(disbuf, "ret")) {
+				break;
+			}
+			switch(ref.ref_type)
+			{
+			case UPD_REF_NONE:
+				if (startswith(disbuf, "br ")) {
+					//unconditional branch to register
+					goto loop_end;
+				}
+				break;
+			case UPD_REF_OP:
+				reference(context, ref.address);
+				break;
+			case UPD_REF_2OP:
+				reference(context, ref.address);
+				reference(context, ref.address2);
+				break;
+			case UPD_REF_BRANCH:
+				reference(context, ref.address);
+				if (ref.address <= address) {
+					defer_disasm(context, ref.address);
+					goto loop_end;
+				} else {
+					address = ref.address;
+				}
+				break;
+			case UPD_REF_COND_BRANCH:
+			case UPD_REF_CALL:
+				reference(context, ref.address);
+				defer_disasm(context, ref.address);
+				break;
+			case UPD_REF_OP_BRANCH:
+				reference(context, ref.address);
+				reference(context, ref.address2);
+				defer_disasm(context, ref.address2);
+				break;
+			case UPD_REF_CALL_TABLE:
+				reference(context, ref.address);
+				if (ref.address >= address_off && ref.address < address_end - 1) {
+					uint16_t table_address = ref.address;
+					ref.address = fetch(table_address, &rom);
+					ref.address |= fetch(table_address + 1, &rom) << 8;
+					reference(context, ref.address);
+					defer_disasm(context, ref.address);
+				}
+				break;
+			}
+		}
+loop_end:
+	}
+	if (labels) {
+		tern_foreach(context->labels, print_label_def, &rom);
+		puts("");
+	}
+	uint16_t data_start = 0xFFFF;
+	for (address = address_off; address < address_end;) {
+		if (labels) {
+			label_def *label = find_label(context, address);
+			if (label) {
+				if (data_start < address) {
+					format_data(context, &rom, labels, data_start, address);
+					data_start = 0xFFFF;
+				}
+				if (label->num_labels) {
+					for (int i = 0; i < label->num_labels; i++)
+					{
+						printf("%s:\n", label->labels[i]);
+					}
+				} else {
+					printf("ADR_%X:\n", label->full_address);
+				}
+			}
+		}
+		if (is_visited(context, address)) {
+			if (data_start < address) {
+				format_data(context, &rom, labels, data_start, address);
+				data_start = 0xFFFF;
+			}
+			uint16_t next = upd78k2_disasm(disbuf, NULL, address, fetch, &rom, labels ? context : NULL);
+			if (labels) {
+				if (addr) {
+					printf("\t%s\t;%X\n", disbuf, address);
+				} else {
+					printf("\t%s\n", disbuf);
+				}
+			} else {
+				printf("%X: %s\n", address, disbuf);
+			}
+			address = next;
+		} else {
+			if (data_start > address) {
+				data_start = address;
+			}
+			address++;
+		}
+	}
+	if (data_start < address) {
+		format_data(context, &rom, labels, data_start, address);
+	}
+	return 0;
+}
\ No newline at end of file