From 7bedc13de8dfa75b4b0f4c1b951d40163b24d45a Mon Sep 17 00:00:00 2001 From: cetus9 <23304557+cetus9@users.noreply.github.com> Date: Sun, 28 Jun 2020 00:24:16 +0100 Subject: [PATCH] Add files via upload --- Makefile | 46 ++++ README.md | 1 + anal_u8.c | 370 ++++++++++++++++++++++++++++++++ asm_u8.c | 47 ++++ u8_disas.c | 616 +++++++++++++++++++++++++++++++++++++++++++++++++++++ u8_disas.h | 242 +++++++++++++++++++++ u8_inst.c | 207 ++++++++++++++++++ 7 files changed, 1529 insertions(+) create mode 100644 Makefile create mode 100644 README.md create mode 100644 anal_u8.c create mode 100644 asm_u8.c create mode 100644 u8_disas.c create mode 100644 u8_disas.h create mode 100644 u8_inst.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..900e5c9 --- /dev/null +++ b/Makefile @@ -0,0 +1,46 @@ +# Work around 'user' r2 installation... +prefix=/home/$$USER/bin/prefix/radare2 +exec_prefix=${prefix} +libdir=/home/$$USER/bin/prefix/radare2/lib +includedir=${prefix}/include +CFLAGS=-g -fPIC -I${includedir}/libr +ASM_LDFLAGS=-shared -L${libdir} -lr_asm +ANAL_LDFLAGS=-shared -L${libdir} -lr_anal + +# ...or use pkg-config if installed normally +#CFLAGS=-g -fPIC $(shell pkg-config --cflags r_asm) +#ASM_LDFLAGS=-shared $(shell pkg-config --libs r_asm) +#ANAL_LDFLAGS=-shared $(shell pkg-config --libs r_anal) + +ASM_OBJS=asm_u8.o u8_disas.o u8_inst.o +ANAL_OBJS=anal_u8.o u8_inst.o + +R2_PLUGIN_PATH=$(shell r2 -H R2_USER_PLUGINS) +LIBEXT=$(shell r2 -H LIBEXT) +ASM_LIB=asm_u8.$(LIBEXT) +ANAL_LIB=anal_u8.$(LIBEXT) + +all: $(ASM_LIB) $(ANAL_LIB) + +clean: + rm -f $(ASM_LIB) $(ANAL_LIB) $(ASM_OBJS) $(ANAL_OBJS) + +$(ASM_LIB): $(ASM_OBJS) + $(CC) $(CFLAGS) $(ASM_LDFLAGS) $(ASM_OBJS) -o $(ASM_LIB) + +$(ANAL_LIB): $(ANAL_OBJS) + $(CC) $(CFLAGS) $(ANAL_LDFLAGS) $(ANAL_OBJS) -o $(ANAL_LIB) + +install: + cp -f asm_u8.$(LIBEXT) $(R2_PLUGIN_PATH) + cp -f anal_u8.$(LIBEXT) $(R2_PLUGIN_PATH) + +uninstall: + rm -f $(R2_PLUGIN_PATH)/asm_u8.$(LIBEXT) + rm -f $(R2_PLUGIN_PATH)/anal_u8.$(LIBEXT) + +test: + r2 -a u8 ../u8dis/rom.bin + +backup: + tar cvf ../u8_r2_plugin.tar . diff --git a/README.md b/README.md new file mode 100644 index 0000000..b37f0cb --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +Experimental radare2 disassembly and analysis plugins for nX-U8/100 architecture. diff --git a/anal_u8.c b/anal_u8.c new file mode 100644 index 0000000..26bd8eb --- /dev/null +++ b/anal_u8.c @@ -0,0 +1,370 @@ +/* radare nX-U8/100 analysis plugin - LGPL - Copyright 2020 - cetus9 */ + +#include +#include +#include +#include +#include + +#include "u8_disas.h" + +// u8inst[U8_INS_NUM] contains instruction data + +// analyse opcodes +static int u8_anop(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf, int len, RAnalOpMask mask) +{ + int ret; + struct u8_cmd cmd; + + memset (op, '\0', sizeof(RAnalOp)); + op->size = -1; + op->addr = addr; + op->type = R_ANAL_OP_TYPE_UNK; + op->family = R_ANAL_OP_FAMILY_CPU; + op->stackop = R_ANAL_STACK_NULL; + op->jump = op->fail = -1; + op->addr = addr; + op->ptr = op->val = -1; + op->refptr = 0; + + ret = op->size = u8_decode_opcode(buf, len, &cmd); + + if(ret < 0) + return ret; + + switch(cmd.type) + { + // ADD instructions + case U8_ADD_R: + case U8_ADDC_R: + case U8_ADD_O: + case U8_ADDC_O: + case U8_ADD_ER: + case U8_ADD_ER_O: + case U8_ADD_SP_O: + op->type = R_ANAL_OP_TYPE_ADD; break; + + // AND instructions + case U8_AND_R: + case U8_AND_O: + op->type = R_ANAL_OP_TYPE_AND; break; + + // CMP instructions + case U8_CMP_R: + case U8_CMPC_R: + case U8_CMP_O: + case U8_CMPC_O: + case U8_CMP_ER: + op->type = R_ANAL_OP_TYPE_CMP; break; + + // Register MOV instructions + case U8_MOV_R: + case U8_MOV_O: + case U8_MOV_ER: + case U8_MOV_ER_O: + case U8_MOV_ECSR_R: + case U8_MOV_ELR_ER: + case U8_MOV_EPSW_R: + case U8_MOV_ER_ELR: + case U8_MOV_ER_SP: + case U8_MOV_PSW_R: + case U8_MOV_PSW_O: + case U8_MOV_R_ECSR: + case U8_MOV_R_EPSW: + case U8_MOV_R_PSW: + case U8_MOV_SP_ER: + + // Coprocessor MOV instructions + case U8_MOV_CR_R: + case U8_MOV_CER_EA: + case U8_MOV_CER_EAP: + case U8_MOV_CR_EA: + case U8_MOV_CR_EAP: + case U8_MOV_CXR_EA: + case U8_MOV_CXR_EAP: + case U8_MOV_CQR_EA: + case U8_MOV_CQR_EAP: + case U8_MOV_R_CR: + case U8_MOV_EA_CER: + case U8_MOV_EAP_CER: + case U8_MOV_EA_CR: + case U8_MOV_EAP_CR: + case U8_MOV_EA_CXR: + case U8_MOV_EAP_CXR: + case U8_MOV_EA_CQR: + op->type = R_ANAL_OP_TYPE_MOV; break; + case U8_OR_R: + case U8_OR_O: + op->type = R_ANAL_OP_TYPE_OR; break; + case U8_XOR_R: + case U8_XOR_O: + op->type = R_ANAL_OP_TYPE_XOR; break; + case U8_SUB_R: + case U8_SUBC_R: + op->type = R_ANAL_OP_TYPE_SUB; break; + case U8_SLL_R: + case U8_SLLC_R: + case U8_SLL_O: + case U8_SLLC_O: + op->type = R_ANAL_OP_TYPE_SHL; break; + case U8_SRA_R: + case U8_SRA_O: + op->type = R_ANAL_OP_TYPE_SAR; break; + case U8_SRL_R: + case U8_SRLC_R: + case U8_SRL_O: + case U8_SRLC_O: + op->type = R_ANAL_OP_TYPE_SHR; break; + + // Load instructions + case U8_L_ER_EA: + case U8_L_ER_EAP: + case U8_L_ER_ER: + case U8_L_ER_D16_ER: + case U8_L_ER_D6_BP: + case U8_L_ER_D6_FP: + case U8_L_ER_DA: + case U8_L_R_EA: + case U8_L_R_EAP: + case U8_L_R_ER: + case U8_L_R_D16_ER: + case U8_L_R_D6_BP: + case U8_L_R_D6_FP: + case U8_L_R_DA: + case U8_L_XR_EA: + case U8_L_XR_EAP: + case U8_L_QR_EA: + case U8_L_QR_EAP: + op->type = R_ANAL_OP_TYPE_LOAD; break; + + // Store instructions + case U8_ST_ER_EA: + case U8_ST_ER_EAP: + case U8_ST_ER_ER: + case U8_ST_ER_D16_ER: + case U8_ST_ER_D6_BP: + case U8_ST_ER_D6_FP: + case U8_ST_ER_DA: + case U8_ST_R_EA: + case U8_ST_R_EAP: + case U8_ST_R_ER: + case U8_ST_R_D16_ER: + case U8_ST_R_D6_BP: + case U8_ST_R_D6_FP: + case U8_ST_R_DA: + case U8_ST_XR_EA: + case U8_ST_XR_EAP: + case U8_ST_QR_EA: + case U8_ST_QR_EAP: + op->type = R_ANAL_OP_TYPE_STORE; break; + + // Push/pop instructions + case U8_PUSH_ER: + case U8_PUSH_QR: + case U8_PUSH_R: + case U8_PUSH_XR: + op->stackop = R_ANAL_STACK_SET; // is this useful? + op->type = R_ANAL_OP_TYPE_PUSH; break; + case U8_POP_ER: + case U8_POP_QR: + case U8_POP_R: + case U8_POP_XR: + op->stackop = R_ANAL_STACK_GET; + op->type = R_ANAL_OP_TYPE_POP; break; + + // Register list stack instructions + // FIXME: programming model could be established here, from use of CSR, LCSR, ECSR + case U8_PUSH_RL: + op->type = R_ANAL_OP_TYPE_PUSH; break; + + case U8_POP_RL: + // certain types of 'pop' may act as subroutine or interrupt returns + // (see nX-U8/100 Core Ref. Ch.1, S.4 - Exception Levels and Backup Registers) + switch(cmd.op1) + { + // FIXME: investigate 3, 7, a, b, f (also include pc). + case 0x2: // pc (return type A-2) + case 0x6: // psw, pc (return types B-1-2, C-1) + case 0xe: // pc, psw, lr (return types B-2-2, C-2) + op->type = R_ANAL_OP_TYPE_RET; + break; + + default: + op->type = R_ANAL_OP_TYPE_POP; + break; + } + break; + + // EA register data transfer instructions + case U8_LEA_ER: + case U8_LEA_D16_ER: + case U8_LEA_DA: + op->type = R_ANAL_OP_TYPE_LEA; break; + + // ALU Instructions + case U8_DAA_R: + case U8_DAS_R: + case U8_NEG_R: + op->type = R_ANAL_OP_TYPE_NULL; break; + + // Bit access instructions + case U8_SB_R: + case U8_RB_R: + case U8_TB_R: + case U8_SB_DBIT: + case U8_RB_DBIT: + case U8_TB_DBIT: + op->type = R_ANAL_OP_TYPE_NULL; break; + + // PSW access instructions (no operands) + case U8_EI: + case U8_DI: + case U8_SC: + case U8_RC: + case U8_CPLC: + op->type = R_ANAL_OP_TYPE_NULL; break; + + // Conditional relative branch instructions + case U8_BGE_RAD: + case U8_BLT_RAD: + case U8_BGT_RAD: + case U8_BLE_RAD: + case U8_BGES_RAD: + case U8_BLTS_RAD: + case U8_BGTS_RAD: + case U8_BLES_RAD: + case U8_BNE_RAD: + case U8_BEQ_RAD: + case U8_BNV_RAD: + case U8_BOV_RAD: + case U8_BPS_RAD: + case U8_BNS_RAD: + op->type = R_ANAL_OP_TYPE_CJMP; + op->jump = addr + sizeof(cmd.opcode) + // next instruction word, plus + ((st8)cmd.op1 * sizeof(cmd.opcode)); // op1 words (+ive or -ive) + op->fail = addr + sizeof(cmd.opcode); + break; + case U8_BAL_RAD: + op->type = R_ANAL_OP_TYPE_JMP; + op->jump = addr + sizeof(cmd.opcode) + // next instruction word + ((st8)cmd.op1 * sizeof(cmd.opcode)); // op1 words (+ive or -ive) + // cannot fail + break; + // Sign extension instruction + case U8_EXTBW_ER: + op->type = R_ANAL_OP_TYPE_NULL; break; + + // Software interrupt instructions + case U8_SWI_O: + op->type = R_ANAL_OP_TYPE_SWI; break; + case U8_BRK: + op->type = R_ANAL_OP_TYPE_TRAP; break; + // Branch instructions + case U8_B_AD: + op->type = R_ANAL_OP_TYPE_CALL; break; + case U8_BL_AD: + // simulate segment register + op->jump = (cmd.op1 * 0x10000) + cmd.s_word; + op->type = R_ANAL_OP_TYPE_CALL; break; + case U8_B_ER: + case U8_BL_ER: + op->type = R_ANAL_OP_TYPE_RCALL; break; + + // Multiplication and division instructions + case U8_MUL_ER: + op->type = R_ANAL_OP_TYPE_MUL; break; + case U8_DIV_ER: + op->type = R_ANAL_OP_TYPE_DIV; break; + + // Miscellaneous (no operands) + case U8_INC_EA: + case U8_DEC_EA: + op->type = R_ANAL_OP_TYPE_NULL; break; + break; + + // Return instructions + case U8_RT: + case U8_RTI: + op->type = R_ANAL_OP_TYPE_RET; break; + case U8_NOP: + op->type = R_ANAL_OP_TYPE_NOP; break; + + case U8_ILL: + default: + op->type = R_ANAL_OP_TYPE_ILL; + + } + return op->size; +} + +// generate mask for signature matching +// FIXME: some extra thought here would improve matching accuracy +static ut8 *u8_anal_mask(RAnal *anal, int size, const ut8 *data, ut64 at) +{ + RAnalOp *op = NULL; + ut8 *ret = NULL; + int i; + struct u8_cmd cmd; + + if(!data) + { + return NULL; + } + + if(!(op = r_anal_op_new())) + { + return NULL; + } + + // mask array = length of function + if(!(ret = malloc(size))) + { + r_anal_op_free(op); + return NULL; + } + + memset(ret, 0xff, size); + + for(i=0; i+1size) + { + op->size = u8_decode_opcode(data, size, &cmd); + + if(op->size < 2) + { + break; + } + + if(op->size == 4) // second word of 2 word instruction is always data + { + ret[i + 2] = 0; + ret[i + 3] = 0; + } + + ret[i] = u8inst[cmd.type].ins_mask; + ret[i + 1] = u8inst[cmd.type].ins_mask >> 8; + } + + r_anal_op_free (op); + + return ret; +} + +struct r_anal_plugin_t r_anal_plugin_u8 = +{ + .name = "u8", + .desc = "nX-U8/100 analysis plugin", + .license = "LGPL3", + .arch = "u8", + .bits = 8 | 16, + .anal_mask = u8_anal_mask, + .op = &u8_anop, +}; + +#ifndef R2_PLUGIN_INCORE +R_API RLibStruct radare_plugin = +{ + .type = R_LIB_TYPE_ANAL, + .data = &r_anal_plugin_u8, + .version = R2_VERSION +}; +#endif diff --git a/asm_u8.c b/asm_u8.c new file mode 100644 index 0000000..674fee2 --- /dev/null +++ b/asm_u8.c @@ -0,0 +1,47 @@ +/* radare nX-U8/100 asm plugin - LGPL - Copyright 2020 - cetus9 */ + +#include +#include +#include +#include +#include + +#include "u8_disas.h" + +static int disassemble(RAsm *a, RAsmOp *op, const ut8 *buf, int len) +{ + struct u8_cmd cmd = + { + .instr = "", + .operands = "" + }; + + if (len < 2) return -1; + int ret = u8_decode_opcode(buf, len, &cmd); + + if (ret > 0) + { + r_strbuf_set(&op->buf_asm, sdb_fmt("%s %s", cmd.instr, cmd.operands)); + } + return op->size = ret; +} + +RAsmPlugin r_asm_plugin_u8 = +{ + .name = "u8", + .license = "LGPL3", + .desc = "nX-U8/100 disassembly plugin", + .arch = "u8", + .bits = 8 | 16, + .endian = R_SYS_ENDIAN_LITTLE, + .disassemble = &disassemble +}; + +#ifndef R2_PLUGIN_INCORE +R_API RLibStruct radare_plugin = +{ + .type = R_LIB_TYPE_ASM, + .data = &r_asm_plugin_u8, + .version = R2_VERSION +}; +#endif diff --git a/u8_disas.c b/u8_disas.c new file mode 100644 index 0000000..d3e166f --- /dev/null +++ b/u8_disas.c @@ -0,0 +1,616 @@ +#include +#include +#include +#include +#include +#include +#include + +// r2 specific +#include + +// The struct u8inst[U8_INS_NUM] contains instruction definitions +#include "u8_disas.h" + +// operand string format util macro +#define fmt_op_str(x, args...) snprintf(cmd->operands, sizeof(cmd->operands), x, ##args) + +// for signed 6-bit integers (Disp6) +int isneg_6bit(ut8 n) +{ + return (n>>5) & 0x01; // msb determines sign +} + +// for signed 7-bit integers (#imm7) +int isneg_7bit(ut8 n) +{ + return (n>>6) & 0x01; // msb determines sign +} + +// calculate absolute value for signed 6-bit number (Disp6) +ut8 abs_6bit(ut8 n) +{ + if(isneg_6bit(n)) // -ive number + return (~n+1 & 0x3f); // flip bits and add 1... + else // +ive number + return n & 0x3f; // ...or just mask out top 2 bits; +} + +// calculate absolute value for signed 7-bit number (#imm7) +ut8 abs_7bit(ut8 n) +{ + if(isneg_7bit(n)) // -ive number + return (~n+1 & 0x7f); // flip bits and add 1... + else // +ive number + return n & 0x7f; // ...or just mask out top bit; +} + +// get instruction type (e.g. U8_MOV_..) for given opcode +int u8_decode_inst(ut16 opcode) +{ + ut16 t; + int i; + + // iterate through master table of instructions, returning on match + // FIXME: this can be done more efficiently + for(i=0; i>n; +} + +// build opcode string +int u8_decode_opcode(const ut8 *buf, int len, struct u8_cmd *cmd) +{ + unsigned int i=0, addr; + + ut16 inst, s_word, prefix=0; + ut16 op1, op2; + + // simplify L/ST handling with separate prefix logic + ut8 pre_pseg=0, pre_dsr=0, pre_r=0; + char prefix_str[8] = ""; + + if(len < 2) // machine words are at least 2 bytes + return -1; + + inst = r_read_at_le16(buf, 0); + i++; // count number of words read + + cmd->type = u8_decode_inst(inst); + + switch(cmd->type) + { + case U8_PRE_PSEG: + pre_pseg = u8_decode_operand(inst, u8inst[cmd->type].op1_mask); + snprintf(prefix_str, sizeof(prefix_str), "%02xh:", pre_pseg); + prefix=inst; + break; + case U8_PRE_DSR: + snprintf(prefix_str, sizeof(prefix_str), "dsr:"); + pre_dsr=1; + prefix=inst; + break; + case U8_PRE_R: + pre_r = u8_decode_operand(inst, u8inst[cmd->type].op1_mask); + snprintf(prefix_str, sizeof(prefix_str), "r%d:", pre_r); + prefix=inst; + break; + } + + if(prefix) + { + // FIXME: check that instruction after prefix is L/ST + // otherwise prefix is misidentified + if(len < (i+1)*2) // buffer in bytes + return -1; + + inst = r_read_at_le16(buf, i*2); // read first real instruction word after prefix + i++; + + cmd->type = u8_decode_inst(inst); + } + + // if instruction type is 2 words long, read second word + if(u8inst[cmd->type].len == 2) + { + if(len < (i+1)*2) // buffer in bytes + return -1; + + s_word = r_read_at_le16(buf, i*2); // read second (possibly third) word from stream + i++; + } + + // set instruction mnemonic + strncpy(cmd->instr, u8inst[cmd->type].name, sizeof(cmd->instr)); + + // extract first operand from instruction word 1 + if(u8inst[cmd->type].ops == 1) // single operand + { + op1 = u8_decode_operand(inst, u8inst[cmd->type].op1_mask); + cmd->op1 = op1; + } + // ...or extract both operands from instruction word 1 + if(u8inst[cmd->type].ops == 2) // 2 operands + { + op1 = u8_decode_operand(inst, u8inst[cmd->type].op1_mask); + op2 = u8_decode_operand(inst, u8inst[cmd->type].op2_mask); + cmd->op1 = op1; + cmd->op2 = op2; + } + + // Display operands with correct formatting + switch(cmd->type) + { + // 8-bit register instructions + case U8_ADD_R: + case U8_AND_R: + case U8_ADDC_R: + case U8_CMP_R: + case U8_CMPC_R: + case U8_MOV_R: + case U8_OR_R: + case U8_XOR_R: + case U8_SUB_R: + case U8_SUBC_R: + case U8_SLL_R: + case U8_SLLC_R: + case U8_SRA_R: + case U8_SRL_R: + case U8_SRLC_R: + fmt_op_str("r%d, r%d", op1, op2); + break; + + // 8-bit register/object instructions + case U8_ADD_O: + case U8_AND_O: + case U8_ADDC_O: + case U8_CMP_O: + case U8_CMPC_O: + case U8_MOV_O: + case U8_OR_O: + case U8_XOR_O: + case U8_SLL_O: + case U8_SLLC_O: + case U8_SRA_O: + case U8_SRL_O: + case U8_SRLC_O: + fmt_op_str("r%d, #%xh", op1, op2); + break; + + // 16-bit extended register instructions + case U8_ADD_ER: + case U8_MOV_ER: + case U8_CMP_ER: + fmt_op_str("er%d, er%d", op1, op2); + break; + + // Extended register/object instructions #imm7 + case U8_ADD_ER_O: + case U8_MOV_ER_O: + if(isneg_7bit(op2)) + fmt_op_str("er%d, #-%xh", op1, abs_7bit(op2)); + else + fmt_op_str("er%d, #%xh", op1, abs_7bit(op2)); + break; + + // Extended register load/store instructions + case U8_L_ER_EA: + case U8_ST_ER_EA: + fmt_op_str("er%d, %s[ea]", op1, prefix_str); + break; + case U8_L_ER_EAP: + case U8_ST_ER_EAP: + fmt_op_str("er%d, %s[ea+]", op1, prefix_str); + break; + case U8_L_ER_ER: + case U8_ST_ER_ER: + fmt_op_str("er%d, %s[er%d]", op1, prefix_str, op2); + break; + case U8_L_ER_D16_ER: + case U8_ST_ER_D16_ER: + fmt_op_str("er%d, %04xh[er%d]", op1, s_word, op2); + break; + case U8_L_ER_D6_BP: + case U8_ST_ER_D6_BP: + if(isneg_6bit(op2)) + fmt_op_str("er%d, -%xh[bp]", op1, abs_6bit(op2)); + else + fmt_op_str("er%d, %xh[bp]", op1, abs_6bit(op2)); + break; + case U8_L_ER_D6_FP: + case U8_ST_ER_D6_FP: + if(isneg_6bit(op2)) + fmt_op_str("er%d, -%xh[fp]", op1, abs_6bit(op2)); + else + fmt_op_str("er%d, %xh[fp]", op1, abs_6bit(op2)); + break; + case U8_L_ER_DA: + case U8_ST_ER_DA: + fmt_op_str("er%d, %04xh", op1, s_word); + break; + + // Register load/store instructions + case U8_L_R_EA: + case U8_ST_R_EA: + fmt_op_str("r%d, [ea]", op1); + break; + case U8_L_R_EAP: + case U8_ST_R_EAP: + fmt_op_str("r%d, [ea+]", op1); + break; + case U8_L_R_ER: + case U8_ST_R_ER: + fmt_op_str("r%d, [er%d]", op1, op2); + break; + case U8_L_R_D16_ER: + case U8_ST_R_D16_ER: + fmt_op_str("r%d, %s%04xh[er%d]", op1, prefix_str, s_word, op2); + break; + case U8_L_R_D6_BP: + case U8_ST_R_D6_BP: + if(isneg_6bit(op2)) + fmt_op_str("r%d, %s-%xh[bp]", op1, prefix_str, abs_6bit(op2)); + else + fmt_op_str("r%d, %s%xh[bp]", op1, prefix_str, abs_6bit(op2)); + break; + case U8_L_R_D6_FP: + case U8_ST_R_D6_FP: + if(isneg_6bit(op2)) + fmt_op_str("r%d, %s-%xh[fp]", op1, prefix_str, abs_6bit(op2)); + else + fmt_op_str("r%d, %s%xh[fp]", op1, prefix_str, abs_6bit(op2)); + break; + case U8_L_R_DA: + case U8_ST_R_DA: + fmt_op_str("r%d, %s%04xh", op1, prefix_str, s_word); + break; + + // Double/quad word register load/store instructions + case U8_L_XR_EA: + case U8_ST_XR_EA: + fmt_op_str("xr%d, %s[ea]", op1, prefix_str); + break; + case U8_L_XR_EAP: + case U8_ST_XR_EAP: + fmt_op_str("xr%d, %s[ea+]", op1, prefix_str); + break; + case U8_L_QR_EA: + case U8_ST_QR_EA: + fmt_op_str("qr%d, %s[ea]", op1, prefix_str); + break; + case U8_L_QR_EAP: + case U8_ST_QR_EAP: + fmt_op_str("qr%d, %s[ea+]", op1, prefix_str); + break; + + // Control register access instructions + case U8_ADD_SP_O: + fmt_op_str("sp, #%xh", op1); + break; + case U8_MOV_ECSR_R: + fmt_op_str("ecsr, r%d", op1); + break; + case U8_MOV_ELR_ER: + fmt_op_str("elr, er%d", op1); + break; + case U8_MOV_EPSW_R: + fmt_op_str("epsw, r%d", op1); + break; + case U8_MOV_ER_ELR: + fmt_op_str("er%d, elr", op1); + break; + case U8_MOV_ER_SP: + fmt_op_str("er%d, sp", op1); + break; + case U8_MOV_PSW_R: + fmt_op_str("psw, r%d", op1); + break; + case U8_MOV_PSW_O: + fmt_op_str("psw, #%xh", op1); + break; + case U8_MOV_R_ECSR: + fmt_op_str("r%d, ecsr", op1); + break; + case U8_MOV_R_EPSW: + fmt_op_str("r%d, epsw", op1); + break; + case U8_MOV_R_PSW: + fmt_op_str("r%d, psw", op1); + break; + case U8_MOV_SP_ER: + fmt_op_str("sp, er%d", op1); + break; + + // Push/pop instructions + case U8_PUSH_ER: + case U8_POP_ER: + fmt_op_str("er%d", op1); + break; + case U8_PUSH_QR: + case U8_POP_QR: + fmt_op_str("qr%d", op1); + break; + case U8_PUSH_R: + case U8_POP_R: + fmt_op_str("r%d", op1); + break; + case U8_PUSH_XR: + case U8_POP_XR: + fmt_op_str("xr%d", op1); + break; + + // Register list stack instructions + case U8_PUSH_RL: + switch(op1) // parse 4-bit list + { + case 1: + fmt_op_str("ea"); break; + case 2: + fmt_op_str("elr"); break; + case 3: + fmt_op_str("ea, elr"); break; + case 4: + fmt_op_str("epsw"); break; + case 5: + fmt_op_str("epsw, ea"); break; + case 6: + fmt_op_str("epsw, elr"); break; + case 7: + fmt_op_str("epsw, elr, ea"); break; + case 8: + fmt_op_str("lr"); break; + case 9: + fmt_op_str("lr, ea"); break; + case 0xa: + fmt_op_str("lr, elr"); break; + case 0xb: + fmt_op_str("lr, ea, elr"); break; + case 0xc: + fmt_op_str("lr, epsw"); break; + case 0xd: + fmt_op_str("lr, epsw, ea"); break; + case 0xe: + fmt_op_str("lr, epsw, elr"); break; + case 0xf: + fmt_op_str("lr, epsw, elr, ea"); break; + default: + fmt_op_str("?"); + } + break; + + case U8_POP_RL: + switch(op1) // parse 4-bit list + { + case 1: + fmt_op_str("ea"); break; + case 2: + fmt_op_str("pc"); break; + case 3: + fmt_op_str("ea, pc"); break; + case 4: + fmt_op_str("psw"); break; + case 5: + fmt_op_str("ea, psw"); break; + case 6: + fmt_op_str("pc, psw"); break; + case 7: + fmt_op_str("ea, pc, psw"); break; + case 8: + fmt_op_str("lr"); break; + case 9: + fmt_op_str("ea, lr"); break; + case 0xa: + fmt_op_str("pc, lr"); break; + case 0xb: + fmt_op_str("ea, pc, lr"); break; + case 0xc: + fmt_op_str("lr, psw"); break; + case 0xd: + fmt_op_str("ea, psw, lr"); break; + case 0xe: + fmt_op_str("pc, psw, lr"); break; + case 0xf: + fmt_op_str("ea, pc, psw, lr"); break; + default: + fmt_op_str("?"); + } + break; + + // Coprocessor data transfer instructions + case U8_MOV_CR_R: + fmt_op_str("cr%d, r%d", op1, op2); + break; + case U8_MOV_CER_EA: + fmt_op_str("cer%d, [ea]", op1); + break; + case U8_MOV_CER_EAP: + fmt_op_str("cer%d, [ea+]", op1); + break; + case U8_MOV_CR_EA: + fmt_op_str("cr%d, [ea]", op1); + break; + case U8_MOV_CR_EAP: + fmt_op_str("cr%d, [ea+]", op1); + break; + case U8_MOV_CXR_EA: + fmt_op_str("cxr%d, [ea]", op1); + break; + case U8_MOV_CXR_EAP: + fmt_op_str("cxr%d, [ea+]", op1); + break; + case U8_MOV_CQR_EA: + fmt_op_str("cqr%d, [ea]", op1); + break; + case U8_MOV_CQR_EAP: + fmt_op_str("cqr%d, [ea+]", op1); + break; + case U8_MOV_R_CR: + fmt_op_str("r%d, cr%d", op1, op2); + break; + case U8_MOV_EA_CER: + fmt_op_str("[ea], cer%d", op1); + break; + case U8_MOV_EAP_CER: + fmt_op_str("[ea+], cer%d", op1); + break; + case U8_MOV_EA_CR: + fmt_op_str("[ea], cr%d", op1); + break; + case U8_MOV_EAP_CR: + fmt_op_str("[ea+], cr%d", op1); + break; + case U8_MOV_EA_CXR: + fmt_op_str("[ea], cxr%d", op1); + break; + case U8_MOV_EAP_CXR: + fmt_op_str("[ea+], cxr%d", op1); + break; + case U8_MOV_EA_CQR: + fmt_op_str("[ea], cqr%d", op1); + break; + case U8_MOV_EAP_CQR: + fmt_op_str("[ea+], cqr%d", op1); + break; + + // EA register data transfer instructions + case U8_LEA_ER: + fmt_op_str("[er%d]", op1); + break; + case U8_LEA_D16_ER: + fmt_op_str("%04xh[er%d]", s_word, op1); + break; + case U8_LEA_DA: + fmt_op_str("%04xh", s_word); + break; + + // ALU Instructions + case U8_DAA_R: + case U8_DAS_R: + case U8_NEG_R: + fmt_op_str("r%d", op1); + break; + + // Bit access instructions + case U8_SB_R: + case U8_RB_R: + case U8_TB_R: + fmt_op_str("r%d.%d", op1, op2); + break; + case U8_SB_DBIT: + case U8_RB_DBIT: + case U8_TB_DBIT: + fmt_op_str("%04xh.%d", s_word, op1); + break; + + // PSW access instructions (no operands) + case U8_EI: + case U8_DI: + case U8_SC: + case U8_RC: + case U8_CPLC: + break; + + // Conditional relative branch instructions + case U8_BGE_RAD: + case U8_BLT_RAD: + case U8_BGT_RAD: + case U8_BLE_RAD: + case U8_BGES_RAD: + case U8_BLTS_RAD: + case U8_BGTS_RAD: + case U8_BLES_RAD: + case U8_BNE_RAD: + case U8_BEQ_RAD: + case U8_BNV_RAD: + case U8_BOV_RAD: + case U8_BPS_RAD: + case U8_BNS_RAD: + case U8_BAL_RAD: + // handle +ive or -ive address jump cases + if((st8)op1 < 0) + fmt_op_str("-%02xh", abs(0-(st8)op1)); + else + fmt_op_str("+%02xh", (st8)op1); + break; + + // Sign extension instruction + case U8_EXTBW_ER: + fmt_op_str("er%d", op2); + break; + + // Software interrupt instructions + case U8_SWI_O: + fmt_op_str("#%xh", op1); + break; + case U8_BRK: + break; + + // Branch instructions + case U8_B_AD: + case U8_BL_AD: + fmt_op_str("%xh:%04xh", op1, s_word); + break; + case U8_B_ER: + case U8_BL_ER: + fmt_op_str("er%d", op1); + break; + + // Multiplication and division instructions + case U8_MUL_ER: + case U8_DIV_ER: + fmt_op_str("er%d, r%d", op1, op2); + break; + + // Miscellaneous (no operands) + case U8_INC_EA: + case U8_DEC_EA: + case U8_RT: + case U8_RTI: + case U8_NOP: + break; + + case U8_ILL: + default: + // will display with 'dw' mnemonic to indicate 'data' + fmt_op_str("%4xh", inst); + } + + return i*sizeof(inst); // 1 or 2 words (up to 3 with prefix) +} diff --git a/u8_disas.h b/u8_disas.h new file mode 100644 index 0000000..610a582 --- /dev/null +++ b/u8_disas.h @@ -0,0 +1,242 @@ +#ifndef U8_DISAS_H +#define U8_DISAS_H + +#include + +struct u8_cmd +{ + int type; // index in instruction table + ut16 opcode; // instruction word + ut16 op1; // first decoded operand + ut16 op2; // second decoded operand + ut16 s_word; // optional second data word + + // String of assembly operation mnemonic. + char instr[6]; + + // String of formatted operands. + char operands[20]; +}; + +int u8_decode_command(const ut8 *instr, int len, struct u8_cmd *cmd); +int u8_decode_opcode(const ut8 *buf, int len, struct u8_cmd *cmd); +int u8_decode_inst(ut16 inst); + +// define u8 instructions +#define U8_INS_NUM 159 // 155 + 3 prefix codes + 'unknown' + +// Arithmetic instructions +#define U8_ADD_R 0 +#define U8_ADD_O 1 +#define U8_ADD_ER 2 +#define U8_ADD_ER_O 3 +#define U8_ADDC_R 4 +#define U8_ADDC_O 5 +#define U8_AND_R 6 +#define U8_AND_O 7 +#define U8_CMP_R 8 +#define U8_CMP_O 9 +#define U8_CMPC_R 10 +#define U8_CMPC_O 11 +#define U8_MOV_ER 12 +#define U8_MOV_ER_O 13 +#define U8_MOV_R 14 +#define U8_MOV_O 15 +#define U8_OR_R 16 +#define U8_OR_O 17 +#define U8_XOR_R 18 +#define U8_XOR_O 19 +#define U8_CMP_ER 20 +#define U8_SUB_R 21 +#define U8_SUBC_R 22 + +// Shift instructions +#define U8_SLL_R 23 +#define U8_SLL_O 24 +#define U8_SLLC_R 25 +#define U8_SLLC_O 26 +#define U8_SRA_R 27 +#define U8_SRA_O 28 +#define U8_SRL_R 29 +#define U8_SRL_O 30 +#define U8_SRLC_R 31 +#define U8_SRLC_O 32 + +// Load/store instructions +#define U8_L_ER_EA 33 +#define U8_L_ER_EAP 34 +#define U8_L_ER_ER 35 +#define U8_L_ER_D16_ER 36 +#define U8_L_ER_D6_BP 37 +#define U8_L_ER_D6_FP 38 +#define U8_L_ER_DA 39 +#define U8_L_R_EA 40 +#define U8_L_R_EAP 41 +#define U8_L_R_ER 42 +#define U8_L_R_D16_ER 43 +#define U8_L_R_D6_BP 44 +#define U8_L_R_D6_FP 45 +#define U8_L_R_DA 46 +#define U8_L_XR_EA 47 +#define U8_L_XR_EAP 48 +#define U8_L_QR_EA 49 +#define U8_L_QR_EAP 50 +#define U8_ST_ER_EA 51 +#define U8_ST_ER_EAP 52 +#define U8_ST_ER_ER 53 +#define U8_ST_ER_D16_ER 54 +#define U8_ST_ER_D6_BP 55 +#define U8_ST_ER_D6_FP 56 +#define U8_ST_ER_DA 57 +#define U8_ST_R_EA 58 +#define U8_ST_R_EAP 59 +#define U8_ST_R_ER 60 +#define U8_ST_R_D16_ER 61 +#define U8_ST_R_D6_BP 62 +#define U8_ST_R_D6_FP 63 +#define U8_ST_R_DA 64 +#define U8_ST_XR_EA 65 +#define U8_ST_XR_EAP 66 +#define U8_ST_QR_EA 67 +#define U8_ST_QR_EAP 68 + +// Control register access instructions +#define U8_ADD_SP_O 69 +#define U8_MOV_ECSR_R 70 +#define U8_MOV_ELR_ER 71 +#define U8_MOV_EPSW_R 72 +#define U8_MOV_ER_ELR 73 +#define U8_MOV_ER_SP 74 +#define U8_MOV_PSW_R 75 +#define U8_MOV_PSW_O 76 +#define U8_MOV_R_ECSR 77 +#define U8_MOV_R_EPSW 78 +#define U8_MOV_R_PSW 79 +#define U8_MOV_SP_ER 80 + +// Push/pop instructions +#define U8_PUSH_ER 81 +#define U8_PUSH_QR 82 +#define U8_PUSH_R 83 +#define U8_PUSH_XR 84 +#define U8_PUSH_RL 85 +#define U8_POP_ER 86 +#define U8_POP_QR 87 +#define U8_POP_R 88 +#define U8_POP_XR 89 +#define U8_POP_RL 90 + +// Coprocessor data transfer instructions +#define U8_MOV_CR_R 91 +#define U8_MOV_CER_EA 92 +#define U8_MOV_CER_EAP 93 +#define U8_MOV_CR_EA 94 +#define U8_MOV_CR_EAP 95 +#define U8_MOV_CXR_EA 96 +#define U8_MOV_CXR_EAP 97 +#define U8_MOV_CQR_EA 98 +#define U8_MOV_CQR_EAP 99 +#define U8_MOV_R_CR 100 +#define U8_MOV_EA_CER 101 +#define U8_MOV_EAP_CER 102 +#define U8_MOV_EA_CR 103 +#define U8_MOV_EAP_CR 104 +#define U8_MOV_EA_CXR 105 +#define U8_MOV_EAP_CXR 106 +#define U8_MOV_EA_CQR 107 +#define U8_MOV_EAP_CQR 108 + +// EA register data transfer instructions +#define U8_LEA_ER 109 +#define U8_LEA_D16_ER 110 +#define U8_LEA_DA 111 + +// ALU Instructions +#define U8_DAA_R 112 +#define U8_DAS_R 113 +#define U8_NEG_R 114 + +// Bit access instructions +#define U8_SB_R 115 +#define U8_SB_DBIT 116 +#define U8_RB_R 117 +#define U8_RB_DBIT 118 +#define U8_TB_R 119 +#define U8_TB_DBIT 120 + +// PSW access instructions +#define U8_EI 121 +#define U8_DI 122 +#define U8_SC 123 +#define U8_RC 124 +#define U8_CPLC 125 + +// Conditional relative branch instructions +#define U8_BGE_RAD 126 +#define U8_BLT_RAD 127 +#define U8_BGT_RAD 128 +#define U8_BLE_RAD 129 +#define U8_BGES_RAD 130 +#define U8_BLTS_RAD 131 +#define U8_BGTS_RAD 132 +#define U8_BLES_RAD 133 +#define U8_BNE_RAD 134 +#define U8_BEQ_RAD 135 +#define U8_BNV_RAD 136 +#define U8_BOV_RAD 137 +#define U8_BPS_RAD 138 +#define U8_BNS_RAD 139 +#define U8_BAL_RAD 140 + +// Sign extension instruction +#define U8_EXTBW_ER 141 + +// Software interrupt instructions +#define U8_SWI_O 142 +#define U8_BRK 143 + +// Branch instructions +#define U8_B_AD 144 +#define U8_B_ER 145 +#define U8_BL_AD 146 +#define U8_BL_ER 147 + +// Multiplication and division instructions +#define U8_MUL_ER 148 +#define U8_DIV_ER 149 + +// Miscellaneous +#define U8_INC_EA 150 +#define U8_DEC_EA 151 +#define U8_RT 152 +#define U8_RTI 153 +#define U8_NOP 154 + +// DSR prefix for load/store +#define U8_PRE_PSEG 155 +#define U8_PRE_DSR 156 +#define U8_PRE_R 157 + +// Undefined +#define U8_ILL 158 + +typedef struct u8inst_t +{ + unsigned int id; // instruction ID + unsigned char name[6]; // mnemonic for instruction + unsigned int len; // 1 or 2 - instruction length in words (16 or 32 bits) + unsigned int ops; // number of operands in word 1 + + ut8 flags; // flags affected (C, Z, S, OV, MIE, HC) + ut16 ins; // word 1 instruction pattern + ut16 ins_mask; // word 1 instruction mask + ut16 op1_mask; // word 1 first operand mask + ut16 op2_mask; // word 1 second operand mask + + ut16 prefix; // DSR load/store prefix + +} u8inst_t; + +extern u8inst_t u8inst[U8_INS_NUM]; + +#endif /* U8_DISAS_H */ diff --git a/u8_inst.c b/u8_inst.c new file mode 100644 index 0000000..f60262a --- /dev/null +++ b/u8_inst.c @@ -0,0 +1,207 @@ +#include "u8_disas.h" + +// Instructions, as per "nX-U8/100 Core Instruction Manual", Ch.4 Appendix +u8inst_t u8inst[U8_INS_NUM] = +{ + + // Arithmetic instructions + {.id=U8_ADD_R, .name="add", .len=1, .ops=2, .flags=0b111101, .ins=0x8001, .ins_mask=0xf00f, .op1_mask=0x0f00, .op2_mask=0x00f0}, + {.id=U8_ADD_O, .name="add", .len=1, .ops=2, .flags=0b111101, .ins=0x1000, .ins_mask=0xf000, .op1_mask=0x0f00, .op2_mask=0x00ff}, + {.id=U8_ADD_ER, .name="add", .len=1, .ops=2, .flags=0b111101, .ins=0xf006, .ins_mask=0xf11f, .op1_mask=0x0f00, .op2_mask=0x00f0}, + {.id=U8_ADD_ER_O, .name="add", .len=1, .ops=2, .flags=0b111101, .ins=0xe080, .ins_mask=0xf180, .op1_mask=0x0f00, .op2_mask=0x007f}, + {.id=U8_ADDC_R, .name="addc", .len=1, .ops=2, .flags=0b111101, .ins=0x8006, .ins_mask=0xf00f, .op1_mask=0x0f00, .op2_mask=0x00f0}, + {.id=U8_ADDC_O, .name="addc", .len=1, .ops=2, .flags=0b111101, .ins=0x6000, .ins_mask=0xf000, .op1_mask=0x0f00, .op2_mask=0x00ff}, + {.id=U8_AND_R, .name="and", .len=1, .ops=2, .flags=0b011000, .ins=0x8002, .ins_mask=0xf00f, .op1_mask=0x0f00, .op2_mask=0x00f0}, + {.id=U8_AND_O, .name="and", .len=1, .ops=2, .flags=0b011000, .ins=0x2000, .ins_mask=0xf000, .op1_mask=0x0f00, .op2_mask=0x00ff}, + {.id=U8_CMP_R, .name="cmp", .len=1, .ops=2, .flags=0b111101, .ins=0x8007, .ins_mask=0xf00f, .op1_mask=0x0f00, .op2_mask=0x00f0}, + {.id=U8_CMP_O, .name="cmp", .len=1, .ops=2, .flags=0b111101, .ins=0x7000, .ins_mask=0xf000, .op1_mask=0x0f00, .op2_mask=0x00ff}, + {.id=U8_CMPC_R, .name="cmpc", .len=1, .ops=2, .flags=0b111101, .ins=0x8005, .ins_mask=0xf00f, .op1_mask=0x0f00, .op2_mask=0x00f0}, + {.id=U8_CMPC_O, .name="cmpc", .len=1, .ops=2, .flags=0b111101, .ins=0x5000, .ins_mask=0xf000, .op1_mask=0x0f00, .op2_mask=0x00ff}, + {.id=U8_MOV_ER, .name="mov", .len=1, .ops=2, .flags=0b011000, .ins=0xf005, .ins_mask=0xf11f, .op1_mask=0x0f00, .op2_mask=0x00f0}, + {.id=U8_MOV_ER_O, .name="mov", .len=1, .ops=2, .flags=0b011000, .ins=0xe000, .ins_mask=0xf180, .op1_mask=0x0f00, .op2_mask=0x007f}, + {.id=U8_MOV_R, .name="mov", .len=1, .ops=2, .flags=0b011000, .ins=0x8000, .ins_mask=0xf00f, .op1_mask=0x0f00, .op2_mask=0x00f0}, + {.id=U8_MOV_O, .name="mov", .len=1, .ops=2, .flags=0b011000, .ins=0x0000, .ins_mask=0xf000, .op1_mask=0x0f00, .op2_mask=0x00ff}, + {.id=U8_OR_R, .name="or", .len=1, .ops=2, .flags=0b011000, .ins=0x8003, .ins_mask=0xf00f, .op1_mask=0x0f00, .op2_mask=0x00f0}, + {.id=U8_OR_O, .name="or", .len=1, .ops=2, .flags=0b011000, .ins=0x3000, .ins_mask=0xf000, .op1_mask=0x0f00, .op2_mask=0x00ff}, + {.id=U8_XOR_R, .name="xor", .len=1, .ops=2, .flags=0b011000, .ins=0x8004, .ins_mask=0xf00f, .op1_mask=0x0f00, .op2_mask=0x00f0}, + {.id=U8_XOR_O, .name="xor", .len=1, .ops=2, .flags=0b011000, .ins=0x4000, .ins_mask=0xf000, .op1_mask=0x0f00, .op2_mask=0x00ff}, + {.id=U8_CMP_ER, .name="cmp", .len=1, .ops=2, .flags=0b111101, .ins=0xf007, .ins_mask=0xf11f, .op1_mask=0x0f00, .op2_mask=0x00f0}, + {.id=U8_SUB_R, .name="sub", .len=1, .ops=2, .flags=0b111101, .ins=0x8008, .ins_mask=0xf00f, .op1_mask=0x0f00, .op2_mask=0x00f0}, + {.id=U8_SUBC_R, .name="subc", .len=1, .ops=2, .flags=0b111101, .ins=0x8009, .ins_mask=0xf00f, .op1_mask=0x0f00, .op2_mask=0x00f0}, + + // Shift instructions + {.id=U8_SLL_R, .name="sll", .len=1, .ops=2, .flags=0b100000, .ins=0x800a, .ins_mask=0xf00f, .op1_mask=0x0f00, .op2_mask=0x00f0}, + {.id=U8_SLL_O, .name="sll", .len=1, .ops=2, .flags=0b100000, .ins=0x900a, .ins_mask=0xf08f, .op1_mask=0x0f00, .op2_mask=0x0070}, + {.id=U8_SLLC_R, .name="sllc", .len=1, .ops=2, .flags=0b100000, .ins=0x800b, .ins_mask=0xf00f, .op1_mask=0x0f00, .op2_mask=0x00f0}, + {.id=U8_SLLC_O, .name="sllc", .len=1, .ops=2, .flags=0b100000, .ins=0x900b, .ins_mask=0xf08f, .op1_mask=0x0f00, .op2_mask=0x0070}, + {.id=U8_SRA_R, .name="sra", .len=1, .ops=2, .flags=0b100000, .ins=0x800e, .ins_mask=0xf00f, .op1_mask=0x0f00, .op2_mask=0x00f0}, + {.id=U8_SRA_O, .name="sra", .len=1, .ops=2, .flags=0b100000, .ins=0x900e, .ins_mask=0xf08f, .op1_mask=0x0f00, .op2_mask=0x0070}, + {.id=U8_SRL_R, .name="srl", .len=1, .ops=2, .flags=0b100000, .ins=0x800c, .ins_mask=0xf00f, .op1_mask=0x0f00, .op2_mask=0x00f0}, + {.id=U8_SRL_O, .name="srl", .len=1, .ops=2, .flags=0b100000, .ins=0x900c, .ins_mask=0xf08f, .op1_mask=0x0f00, .op2_mask=0x0070}, + {.id=U8_SRLC_R, .name="srlc", .len=1, .ops=2, .flags=0b100000, .ins=0x800d, .ins_mask=0xf00f, .op1_mask=0x0f00, .op2_mask=0x00f0}, + {.id=U8_SRLC_O, .name="srlc", .len=1, .ops=2, .flags=0b100000, .ins=0x900d, .ins_mask=0xf08f, .op1_mask=0x0f00, .op2_mask=0x0070}, + + // Load/store instructions + {.id=U8_L_ER_EA, .name="l", .len=1, .ops=1, .flags=0b011000, .ins=0x9032, .ins_mask=0xf1ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_L_ER_EAP, .name="l", .len=1, .ops=1, .flags=0b011000, .ins=0x9052, .ins_mask=0xf1ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_L_ER_ER, .name="l", .len=1, .ops=2, .flags=0b011000, .ins=0x9002, .ins_mask=0xf11f, .op1_mask=0x0f00, .op2_mask=0x00f0}, + {.id=U8_L_ER_D16_ER, .name="l", .len=2, .ops=2, .flags=0b011000, .ins=0xa008, .ins_mask=0xf11f, .op1_mask=0x0f00, .op2_mask=0x00f0}, + {.id=U8_L_ER_D6_BP, .name="l", .len=1, .ops=2, .flags=0b011000, .ins=0xb000, .ins_mask=0xf1c0, .op1_mask=0x0f00, .op2_mask=0x003f}, + {.id=U8_L_ER_D6_FP, .name="l", .len=1, .ops=2, .flags=0b011000, .ins=0xb040, .ins_mask=0xf1c0, .op1_mask=0x0f00, .op2_mask=0x003f}, + {.id=U8_L_ER_DA, .name="l", .len=2, .ops=1, .flags=0b011000, .ins=0x9012, .ins_mask=0xf1ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_L_R_EA, .name="l", .len=1, .ops=1, .flags=0b011000, .ins=0x9030, .ins_mask=0xf0ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_L_R_EAP, .name="l", .len=1, .ops=1, .flags=0b011000, .ins=0x9050, .ins_mask=0xf0ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_L_R_ER, .name="l", .len=1, .ops=2, .flags=0b011000, .ins=0x9000, .ins_mask=0xf01f, .op1_mask=0x0f00, .op2_mask=0x00f0}, + {.id=U8_L_R_D16_ER, .name="l", .len=2, .ops=2, .flags=0b011000, .ins=0x9008, .ins_mask=0xf01f, .op1_mask=0x0f00, .op2_mask=0x00f0}, + {.id=U8_L_R_D6_BP, .name="l", .len=1, .ops=2, .flags=0b011000, .ins=0xd000, .ins_mask=0xf0c0, .op1_mask=0x0f00, .op2_mask=0x003f}, + {.id=U8_L_R_D6_FP, .name="l", .len=1, .ops=2, .flags=0b011000, .ins=0xd040, .ins_mask=0xf0c0, .op1_mask=0x0f00, .op2_mask=0x003f}, + // Per core ref.: + //{.id=U8_L_R_DA, .name="l", .len=2, .ops=1, .flags=0b011000, .ins=0x9010, .ins_mask=0xf0ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + // ....but, we match SDK disassembler behaviour, w.r.t. third nibble: + {.id=U8_L_R_DA, .name="l", .len=2, .ops=1, .flags=0b011000, .ins=0x9010, .ins_mask=0xf01f, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_L_XR_EA, .name="l", .len=1, .ops=1, .flags=0b011000, .ins=0x9034, .ins_mask=0xf3ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_L_XR_EAP, .name="l", .len=1, .ops=1, .flags=0b011000, .ins=0x9054, .ins_mask=0xf3ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_L_QR_EA, .name="l", .len=1, .ops=1, .flags=0b011000, .ins=0x9036, .ins_mask=0xf7ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_L_QR_EAP, .name="l", .len=1, .ops=1, .flags=0b011000, .ins=0x9056, .ins_mask=0xf7ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_ST_ER_EA, .name="st", .len=1, .ops=1, .flags=0b000000, .ins=0x9033, .ins_mask=0xf1ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_ST_ER_EAP, .name="st", .len=1, .ops=1, .flags=0b000000, .ins=0x9053, .ins_mask=0xf1ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_ST_ER_ER, .name="st", .len=1, .ops=2, .flags=0b000000, .ins=0x9003, .ins_mask=0xf11f, .op1_mask=0x0f00, .op2_mask=0x00f0}, + {.id=U8_ST_ER_D16_ER, .name="st", .len=2, .ops=2, .flags=0b000000, .ins=0xa009, .ins_mask=0xf11f, .op1_mask=0x0f00, .op2_mask=0x00f0}, + {.id=U8_ST_ER_D6_BP, .name="st", .len=1, .ops=2, .flags=0b000000, .ins=0xb080, .ins_mask=0xf1c0, .op1_mask=0x0f00, .op2_mask=0x003f}, + {.id=U8_ST_ER_D6_FP, .name="st", .len=1, .ops=2, .flags=0b000000, .ins=0xb0c0, .ins_mask=0xf1c0, .op1_mask=0x0f00, .op2_mask=0x003f}, + {.id=U8_ST_ER_DA, .name="st", .len=2, .ops=1, .flags=0b000000, .ins=0x9013, .ins_mask=0xf1ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_ST_R_EA, .name="st", .len=1, .ops=1, .flags=0b000000, .ins=0x9031, .ins_mask=0xf0ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_ST_R_EAP, .name="st", .len=1, .ops=1, .flags=0b000000, .ins=0x9051, .ins_mask=0xf0ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_ST_R_ER, .name="st", .len=1, .ops=2, .flags=0b000000, .ins=0x9001, .ins_mask=0xf01f, .op1_mask=0x0f00, .op2_mask=0x00f0}, + {.id=U8_ST_R_D16_ER, .name="st", .len=2, .ops=2, .flags=0b000000, .ins=0x9009, .ins_mask=0xf01f, .op1_mask=0x0f00, .op2_mask=0x00f0}, + {.id=U8_ST_R_D6_BP, .name="st", .len=1, .ops=2, .flags=0b000000, .ins=0xd080, .ins_mask=0xf0c0, .op1_mask=0x0f00, .op2_mask=0x003f}, + {.id=U8_ST_R_D6_FP, .name="st", .len=1, .ops=2, .flags=0b000000, .ins=0xd0c0, .ins_mask=0xf0c0, .op1_mask=0x0f00, .op2_mask=0x003f}, + {.id=U8_ST_R_DA, .name="st", .len=2, .ops=1, .flags=0b000000, .ins=0x9011, .ins_mask=0xf0ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_ST_XR_EA, .name="st", .len=1, .ops=1, .flags=0b000000, .ins=0x9035, .ins_mask=0xf3ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_ST_XR_EAP, .name="st", .len=1, .ops=1, .flags=0b000000, .ins=0x9055, .ins_mask=0xf3ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_ST_QR_EA, .name="st", .len=1, .ops=1, .flags=0b000000, .ins=0x9037, .ins_mask=0xf7ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_ST_QR_EAP, .name="st", .len=1, .ops=1, .flags=0b000000, .ins=0x9057, .ins_mask=0xf7ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + + // Control register access instructions + {.id=U8_ADD_SP_O, .name="add", .len=1, .ops=1, .flags=0b000000, .ins=0xe100, .ins_mask=0xff00, .op1_mask=0x00ff, .op2_mask=0x0000}, + {.id=U8_MOV_ECSR_R, .name="mov", .len=1, .ops=1, .flags=0b000000, .ins=0xa00f, .ins_mask=0xff0f, .op1_mask=0x00f0, .op2_mask=0x0000}, + {.id=U8_MOV_ELR_ER, .name="mov", .len=1, .ops=1, .flags=0b000000, .ins=0xa00d, .ins_mask=0xf1ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_MOV_EPSW_R, .name="mov", .len=1, .ops=1, .flags=0b000000, .ins=0xa00c, .ins_mask=0xff0f, .op1_mask=0x00f0, .op2_mask=0x0000}, + {.id=U8_MOV_ER_ELR, .name="mov", .len=1, .ops=1, .flags=0b000000, .ins=0xa005, .ins_mask=0xf1ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_MOV_ER_SP, .name="mov", .len=1, .ops=1, .flags=0b000000, .ins=0xa01a, .ins_mask=0xf1ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_MOV_PSW_R, .name="mov", .len=1, .ops=1, .flags=0b111111, .ins=0xa00b, .ins_mask=0xff0f, .op1_mask=0x00f0, .op2_mask=0x0000}, + {.id=U8_MOV_PSW_O, .name="mov", .len=1, .ops=1, .flags=0b111111, .ins=0xa00b, .ins_mask=0xff0f, .op1_mask=0x00f0, .op2_mask=0x0000}, + {.id=U8_MOV_R_ECSR, .name="mov", .len=1, .ops=1, .flags=0b000000, .ins=0xa007, .ins_mask=0xf0ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_MOV_R_EPSW, .name="mov", .len=1, .ops=1, .flags=0b000000, .ins=0xa004, .ins_mask=0xf0ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_MOV_R_PSW, .name="mov", .len=1, .ops=1, .flags=0b000000, .ins=0xa003, .ins_mask=0xf0ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_MOV_SP_ER, .name="mov", .len=1, .ops=1, .flags=0b000000, .ins=0xa10a, .ins_mask=0xff1f, .op1_mask=0x00f0, .op2_mask=0x0000}, + + // Push/pop instructions + {.id=U8_PUSH_ER, .name="push", .len=1, .ops=1, .flags=0b000000, .ins=0xf05e, .ins_mask=0xf1ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_PUSH_QR, .name="push", .len=1, .ops=1, .flags=0b000000, .ins=0xf07e, .ins_mask=0xf7ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_PUSH_R, .name="push", .len=1, .ops=1, .flags=0b000000, .ins=0xf04e, .ins_mask=0xf0ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_PUSH_XR, .name="push", .len=1, .ops=1, .flags=0b000000, .ins=0xf06e, .ins_mask=0xf3ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_PUSH_RL, .name="push", .len=1, .ops=1, .flags=0b000000, .ins=0xf0ce, .ins_mask=0xf0ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_POP_ER, .name="pop", .len=1, .ops=1, .flags=0b000000, .ins=0xf01e, .ins_mask=0xf1ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_POP_QR, .name="pop", .len=1, .ops=1, .flags=0b000000, .ins=0xf03e, .ins_mask=0xf7ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_POP_R, .name="pop", .len=1, .ops=1, .flags=0b000000, .ins=0xf00e, .ins_mask=0xf0ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_POP_XR, .name="pop", .len=1, .ops=1, .flags=0b000000, .ins=0xf02e, .ins_mask=0xf3ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_POP_RL, .name="pop", .len=1, .ops=1, .flags=0b111111, .ins=0xf08e, .ins_mask=0xf0ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + + // Coprocessor data transfer instructions + {.id=U8_MOV_CR_R, .name="mov", .len=1, .ops=2, .flags=0b000000, .ins=0xa00e, .ins_mask=0xf00f, .op1_mask=0x0f00, .op2_mask=0x00f0}, + {.id=U8_MOV_CER_EA, .name="mov", .len=1, .ops=1, .flags=0b000000, .ins=0xf02d, .ins_mask=0xf1ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_MOV_CER_EAP, .name="mov", .len=1, .ops=1, .flags=0b000000, .ins=0xf03d, .ins_mask=0xf1ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_MOV_CR_EA, .name="mov", .len=1, .ops=1, .flags=0b000000, .ins=0xf00d, .ins_mask=0xf0ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_MOV_CR_EAP, .name="mov", .len=1, .ops=1, .flags=0b000000, .ins=0xf01d, .ins_mask=0xf0ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_MOV_CXR_EA, .name="mov", .len=1, .ops=1, .flags=0b000000, .ins=0xf04d, .ins_mask=0xf3ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_MOV_CXR_EAP, .name="mov", .len=1, .ops=1, .flags=0b000000, .ins=0xf05d, .ins_mask=0xf3ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_MOV_CQR_EA, .name="mov", .len=1, .ops=1, .flags=0b000000, .ins=0xf06d, .ins_mask=0xf7ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_MOV_CQR_EAP, .name="mov", .len=1, .ops=1, .flags=0b000000, .ins=0xf07d, .ins_mask=0xf7ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_MOV_R_CR, .name="mov", .len=1, .ops=2, .flags=0b000000, .ins=0xa006, .ins_mask=0xf00f, .op1_mask=0x0f00, .op2_mask=0x00f0}, + {.id=U8_MOV_EA_CER, .name="mov", .len=1, .ops=1, .flags=0b000000, .ins=0xf0ad, .ins_mask=0xf1ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_MOV_EAP_CER, .name="mov", .len=1, .ops=1, .flags=0b000000, .ins=0xf0bd, .ins_mask=0xf1ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_MOV_EA_CR, .name="mov", .len=1, .ops=1, .flags=0b000000, .ins=0xf08d, .ins_mask=0xf0ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_MOV_EAP_CR, .name="mov", .len=1, .ops=1, .flags=0b000000, .ins=0xf09d, .ins_mask=0xf0ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_MOV_EA_CXR, .name="mov", .len=1, .ops=1, .flags=0b000000, .ins=0xf0cd, .ins_mask=0xf3ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_MOV_EAP_CXR, .name="mov", .len=1, .ops=1, .flags=0b000000, .ins=0xf0dd, .ins_mask=0xf3ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_MOV_EA_CQR, .name="mov", .len=1, .ops=1, .flags=0b000000, .ins=0xf0ed, .ins_mask=0xf7ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_MOV_EAP_CQR, .name="mov", .len=1, .ops=1, .flags=0b000000, .ins=0xf0fd, .ins_mask=0xf7ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + + // EA register data transfer instructions + {.id=U8_LEA_ER, .name="lea", .len=1, .ops=1, .flags=0b000000, .ins=0xf00a, .ins_mask=0xf01f, .op1_mask=0x00f0, .op2_mask=0x0000}, + {.id=U8_LEA_D16_ER, .name="lea", .len=2, .ops=1, .flags=0b000000, .ins=0xf00b, .ins_mask=0xf01f, .op1_mask=0x00f0, .op2_mask=0x0000}, + {.id=U8_LEA_DA, .name="lea", .len=2, .ops=1, .flags=0b000000, .ins=0xf00c, .ins_mask=0xffff, .op1_mask=0x0000, .op2_mask=0x0000}, + + // ALU Instructions + {.id=U8_DAA_R, .name="daa", .len=1, .ops=1, .flags=0b111001, .ins=0x801f, .ins_mask=0xf0ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_DAS_R, .name="das", .len=1, .ops=1, .flags=0b111001, .ins=0x803f, .ins_mask=0xf0ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_NEG_R, .name="neg", .len=1, .ops=1, .flags=0b111101, .ins=0x805f, .ins_mask=0xf0ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + + // Bit access instructions + {.id=U8_SB_R, .name="sb", .len=1, .ops=2, .flags=0b010000, .ins=0xa000, .ins_mask=0xf08f, .op1_mask=0x0f00, .op2_mask=0x0070}, + {.id=U8_SB_DBIT, .name="sb", .len=2, .ops=1, .flags=0b010000, .ins=0xa080, .ins_mask=0xff8f, .op1_mask=0x0070, .op2_mask=0x0000}, + {.id=U8_RB_R, .name="rb", .len=1, .ops=2, .flags=0b010000, .ins=0xa002, .ins_mask=0xf08f, .op1_mask=0x0f00, .op2_mask=0x0070}, + // Per core ref.: +// {.id=U8_RB_DBIT, .name="rb", .len=2, .ops=1, .flags=0b010000, .ins=0xa082, .ins_mask=0xff8f, .op1_mask=0x0070, .op2_mask=0x0000}, + // ....but, we match SDK disassembler behaviour, w.r.t. second nibble: + {.id=U8_RB_DBIT, .name="rb", .len=2, .ops=1, .flags=0b010000, .ins=0xa082, .ins_mask=0xf08f, .op1_mask=0x0070, .op2_mask=0x0000}, + {.id=U8_TB_R, .name="tb", .len=1, .ops=2, .flags=0b010000, .ins=0xa001, .ins_mask=0xf08f, .op1_mask=0x0f00, .op2_mask=0x0070}, +// {.id=U8_TB_DBIT, .name="tb", .len=2, .ops=1, .flags=0b010000, .ins=0xa081, .ins_mask=0xff8f, .op1_mask=0x0070, .op2_mask=0x0000}, + {.id=U8_TB_DBIT, .name="tb", .len=2, .ops=1, .flags=0b010000, .ins=0xa081, .ins_mask=0xf08f, .op1_mask=0x0070, .op2_mask=0x0000}, + + // PSW access instructions + {.id=U8_EI, .name="ei", .len=1, .ops=0, .flags=0b000010, .ins=0xed08, .ins_mask=0xffff, .op1_mask=0x0000, .op2_mask=0x0000}, + {.id=U8_DI, .name="di", .len=1, .ops=0, .flags=0b000010, .ins=0xebf7, .ins_mask=0xffff, .op1_mask=0x0000, .op2_mask=0x0000}, + {.id=U8_SC, .name="sc", .len=1, .ops=0, .flags=0b100000, .ins=0xed80, .ins_mask=0xffff, .op1_mask=0x0000, .op2_mask=0x0000}, + {.id=U8_RC, .name="rc", .len=1, .ops=0, .flags=0b100000, .ins=0xeb7f, .ins_mask=0xffff, .op1_mask=0x0000, .op2_mask=0x0000}, + {.id=U8_CPLC, .name="cplc", .len=1, .ops=0, .flags=0b100000, .ins=0xfecf, .ins_mask=0xffff, .op1_mask=0x0000, .op2_mask=0x0000}, + + // Conditional relative branch instructions + {.id=U8_BGE_RAD, .name="bge", .len=1, .ops=1, .flags=0b000000, .ins=0xc000, .ins_mask=0xff00, .op1_mask=0x00ff, .op2_mask=0x0000}, + {.id=U8_BLT_RAD, .name="blt", .len=1, .ops=1, .flags=0b000000, .ins=0xc100, .ins_mask=0xff00, .op1_mask=0x00ff, .op2_mask=0x0000}, + {.id=U8_BGT_RAD, .name="bgt", .len=1, .ops=1, .flags=0b000000, .ins=0xc200, .ins_mask=0xff00, .op1_mask=0x00ff, .op2_mask=0x0000}, + {.id=U8_BLE_RAD, .name="ble", .len=1, .ops=1, .flags=0b000000, .ins=0xc130, .ins_mask=0xff00, .op1_mask=0x00ff, .op2_mask=0x0000}, + {.id=U8_BGES_RAD, .name="bges", .len=1, .ops=1, .flags=0b000000, .ins=0xc400, .ins_mask=0xff00, .op1_mask=0x00ff, .op2_mask=0x0000}, + {.id=U8_BLTS_RAD, .name="blts", .len=1, .ops=1, .flags=0b000000, .ins=0xc500, .ins_mask=0xff00, .op1_mask=0x00ff, .op2_mask=0x0000}, + {.id=U8_BGTS_RAD, .name="bgts", .len=1, .ops=1, .flags=0b000000, .ins=0xc600, .ins_mask=0xff00, .op1_mask=0x00ff, .op2_mask=0x0000}, + {.id=U8_BLES_RAD, .name="bles", .len=1, .ops=1, .flags=0b000000, .ins=0xc700, .ins_mask=0xff00, .op1_mask=0x00ff, .op2_mask=0x0000}, + {.id=U8_BNE_RAD, .name="bne", .len=1, .ops=1, .flags=0b000000, .ins=0xc800, .ins_mask=0xff00, .op1_mask=0x00ff, .op2_mask=0x0000}, + {.id=U8_BEQ_RAD, .name="beq", .len=1, .ops=1, .flags=0b000000, .ins=0xc900, .ins_mask=0xff00, .op1_mask=0x00ff, .op2_mask=0x0000}, + {.id=U8_BNV_RAD, .name="bnv", .len=1, .ops=1, .flags=0b000000, .ins=0xca00, .ins_mask=0xff00, .op1_mask=0x00ff, .op2_mask=0x0000}, + {.id=U8_BOV_RAD, .name="bov", .len=1, .ops=1, .flags=0b000000, .ins=0xcb00, .ins_mask=0xff00, .op1_mask=0x00ff, .op2_mask=0x0000}, + {.id=U8_BPS_RAD, .name="bps", .len=1, .ops=1, .flags=0b000000, .ins=0xcc00, .ins_mask=0xff00, .op1_mask=0x00ff, .op2_mask=0x0000}, + {.id=U8_BNS_RAD, .name="bns", .len=1, .ops=1, .flags=0b000000, .ins=0xcd00, .ins_mask=0xff00, .op1_mask=0x00ff, .op2_mask=0x0000}, + {.id=U8_BAL_RAD, .name="bal", .len=1, .ops=1, .flags=0b000000, .ins=0xce00, .ins_mask=0xff00, .op1_mask=0x00ff, .op2_mask=0x0000}, + + // Sign extension instruction + {.id=U8_EXTBW_ER, .name="extbw", .len=1, .ops=2, .flags=0b011000, .ins=0x810f, .ins_mask=0xf11f, .op1_mask=0x0f00, .op2_mask=0x00f0}, + + // Software interrupt instructions + {.id=U8_SWI_O, .name="swi", .len=1, .ops=1, .flags=0b000010, .ins=0xe500, .ins_mask=0xffc0, .op1_mask=0x003f, .op2_mask=0x0000}, + {.id=U8_BRK, .name="brk", .len=1, .ops=0, .flags=0b000000, .ins=0xffff, .ins_mask=0xffff, .op1_mask=0x0000, .op2_mask=0x0000}, + + // Branch instructions + {.id=U8_B_AD, .name="b", .len=2, .ops=1, .flags=0b000000, .ins=0xf000, .ins_mask=0xf0ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_B_ER, .name="b", .len=1, .ops=1, .flags=0b000000, .ins=0xf002, .ins_mask=0xff1f, .op1_mask=0x00f0, .op2_mask=0x0000}, + {.id=U8_BL_AD, .name="bl", .len=2, .ops=1, .flags=0b000000, .ins=0xf001, .ins_mask=0xf0ff, .op1_mask=0x0f00, .op2_mask=0x0000}, + {.id=U8_BL_ER, .name="bl", .len=1, .ops=1, .flags=0b000000, .ins=0xf003, .ins_mask=0xf00f, .op1_mask=0x00f0, .op2_mask=0x0000}, + + // Multiplication and division instructions + {.id=U8_MUL_ER, .name="mul", .len=1, .ops=2, .flags=0b010000, .ins=0xf004, .ins_mask=0xf10f, .op1_mask=0x0f00, .op2_mask=0x00f0}, + {.id=U8_DIV_ER, .name="div", .len=1, .ops=2, .flags=0b110000, .ins=0xf009, .ins_mask=0xf10f, .op1_mask=0x0f00, .op2_mask=0x00f0}, + + // Miscellaneous + {.id=U8_INC_EA, .name="inc", .len=1, .ops=0, .flags=0b011101, .ins=0xfe2f, .ins_mask=0xffff, .op1_mask=0x0000, .op2_mask=0x0000}, + {.id=U8_DEC_EA, .name="dec", .len=1, .ops=0, .flags=0b011101, .ins=0xfe3f, .ins_mask=0xffff, .op1_mask=0x0000, .op2_mask=0x0000}, + {.id=U8_RT, .name="rt", .len=1, .ops=0, .flags=0b000000, .ins=0xfe1f, .ins_mask=0xffff, .op1_mask=0x0000, .op2_mask=0x0000}, + {.id=U8_RTI, .name="rti", .len=1, .ops=0, .flags=0b111111, .ins=0xfe0f, .ins_mask=0xffff, .op1_mask=0x0000, .op2_mask=0x0000}, + {.id=U8_NOP, .name="nop", .len=1, .ops=0, .flags=0b000000, .ins=0xfe8f, .ins_mask=0xffff, .op1_mask=0x0000, .op2_mask=0x0000}, + + // DSR prefix 'instructions' + {.id=U8_PRE_PSEG, .name="dsr", .len=2, .ops=1, .flags=0b011000, .ins=0xe300, .ins_mask=0xff00, .op1_mask=0x00ff, .op2_mask=0x0000}, + {.id=U8_PRE_DSR, .name="dsr", .len=2, .ops=0, .flags=0b011000, .ins=0xfe9f, .ins_mask=0xffff, .op1_mask=0x0000, .op2_mask=0x0000}, + {.id=U8_PRE_R, .name="dsr", .len=2, .ops=1, .flags=0b011000, .ins=0x900f, .ins_mask=0xff0f, .op1_mask=0x00f0, .op2_mask=0x0000}, + + {.id=U8_ILL, .name="dw", .len=1, .ops=0, .flags=0b000000, .ins=0xffff, .ins_mask=0x0000, .op1_mask=0x0000, .op2_mask=0x0000} +};