diff options
-rw-r--r-- | opcodes/ChangeLog | 12 | ||||
-rw-r--r-- | opcodes/Makefile.am | 1 | ||||
-rw-r--r-- | opcodes/Makefile.in | 2 | ||||
-rwxr-xr-x | opcodes/configure | 2 | ||||
-rw-r--r-- | opcodes/configure.ac | 2 | ||||
-rw-r--r-- | opcodes/s12z-dis.c | 2802 | ||||
-rw-r--r-- | opcodes/s12z-opc.c | 2701 | ||||
-rw-r--r-- | opcodes/s12z-opc.h | 267 |
8 files changed, 3241 insertions, 2548 deletions
diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog index 3fc4606..7f7ac9e 100644 --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -1,3 +1,15 @@ +2019-01-03 John Darrington <john@darrington.wattle.id.au> + + * s12z-opc.c: New file. + * s12z-opc.h: New file. + * s12z-dis.c: Removed all code not directly related to display + of instructions. Used the interface provided by the new files + instead. + * Makefile.am (TARGET_LIBOPCODES_CFILES) Add s12z-opc.c. + * Makefile.in: regenerate. + * configure.ac (bfd_s12z_arch): Correct the dependencies. + * configure: regenerate. + 2019-01-01 Alan Modra <amodra@gmail.com> Update year range in copyright notice of all files. diff --git a/opcodes/Makefile.am b/opcodes/Makefile.am index 06120a2..458a2b5 100644 --- a/opcodes/Makefile.am +++ b/opcodes/Makefile.am @@ -176,6 +176,7 @@ TARGET_LIBOPCODES_CFILES = \ m68k-dis.c \ m68k-opc.c \ s12z-dis.c \ + s12z-opc.c \ mcore-dis.c \ mep-asm.c \ mep-desc.c \ diff --git a/opcodes/Makefile.in b/opcodes/Makefile.in index 27b7c04..3277ba9 100644 --- a/opcodes/Makefile.in +++ b/opcodes/Makefile.in @@ -566,6 +566,7 @@ TARGET_LIBOPCODES_CFILES = \ m68k-dis.c \ m68k-opc.c \ s12z-dis.c \ + s12z-opc.c \ mcore-dis.c \ mep-asm.c \ mep-desc.c \ @@ -1022,6 +1023,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rx-decode.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rx-dis.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s12z-dis.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s12z-opc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s390-dis.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s390-opc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/score-dis.Plo@am__quote@ diff --git a/opcodes/configure b/opcodes/configure index eb74324..652b373 100755 --- a/opcodes/configure +++ b/opcodes/configure @@ -12896,7 +12896,7 @@ if test x${all_targets} = xfalse ; then bfd_m68hc12_arch) ta="$ta m68hc11-dis.lo m68hc11-opc.lo" ;; bfd_m9s12x_arch) ta="$ta m68hc11-dis.lo m68hc11-opc.lo" ;; bfd_m9s12xg_arch) ta="$ta m68hc11-dis.lo m68hc11-opc.lo" ;; - bfd_s12z_arch) ta="$ta s12z-dis.lo m68hc11-opc.lo" ;; + bfd_s12z_arch) ta="$ta s12z-dis.lo s12z-opc.lo" ;; bfd_m68k_arch) ta="$ta m68k-dis.lo m68k-opc.lo" ;; bfd_mcore_arch) ta="$ta mcore-dis.lo" ;; bfd_mep_arch) ta="$ta mep-asm.lo mep-desc.lo mep-dis.lo mep-ibld.lo mep-opc.lo" using_cgen=yes ;; diff --git a/opcodes/configure.ac b/opcodes/configure.ac index 7a1738c..4eb1900 100644 --- a/opcodes/configure.ac +++ b/opcodes/configure.ac @@ -287,7 +287,7 @@ if test x${all_targets} = xfalse ; then bfd_m68hc12_arch) ta="$ta m68hc11-dis.lo m68hc11-opc.lo" ;; bfd_m9s12x_arch) ta="$ta m68hc11-dis.lo m68hc11-opc.lo" ;; bfd_m9s12xg_arch) ta="$ta m68hc11-dis.lo m68hc11-opc.lo" ;; - bfd_s12z_arch) ta="$ta s12z-dis.lo m68hc11-opc.lo" ;; + bfd_s12z_arch) ta="$ta s12z-dis.lo s12z-opc.lo" ;; bfd_m68k_arch) ta="$ta m68k-dis.lo m68k-opc.lo" ;; bfd_mcore_arch) ta="$ta mcore-dis.lo" ;; bfd_mep_arch) ta="$ta mep-asm.lo mep-desc.lo mep-dis.lo mep-ibld.lo mep-opc.lo" using_cgen=yes ;; diff --git a/opcodes/s12z-dis.c b/opcodes/s12z-dis.c index bd64c0a..14176fb 100644 --- a/opcodes/s12z-dis.c +++ b/opcodes/s12z-dis.c @@ -29,266 +29,51 @@ #include "bfd.h" #include "dis-asm.h" - #include "disassemble.h" -static int -read_memory (bfd_vma memaddr, bfd_byte* buffer, int size, - struct disassemble_info* info) -{ - int status = (*info->read_memory_func) (memaddr, buffer, size, info); - if (status != 0) - { - (*info->memory_error_func) (status, memaddr, info); - return -1; - } - return 0; -} - -typedef int (* insn_bytes_f) (bfd_vma memaddr, - struct disassemble_info* info); - -typedef void (*operands_f) (bfd_vma memaddr, struct disassemble_info* info); - -enum OPR_MODE - { - OPR_IMMe4, - OPR_REG, - OPR_OFXYS, - OPR_XY_PRE_INC, - OPR_XY_POST_INC, - OPR_XY_PRE_DEC, - OPR_XY_POST_DEC, - OPR_S_PRE_DEC, - OPR_S_POST_INC, - OPR_REG_DIRECT, - OPR_REG_INDIRECT, - OPR_IDX_DIRECT, - OPR_IDX_INDIRECT, - OPR_EXT1, - OPR_IDX2_REG, - OPR_IDX3_DIRECT, - OPR_IDX3_INDIRECT, +#include "s12z-opc.h" - OPR_EXT18, - OPR_IDX3_DIRECT_REG, - OPR_EXT3_DIRECT, - OPR_EXT3_INDIRECT - }; - -struct opr_pb +struct mem_read_abstraction { - uint8_t mask; - uint8_t value; - int n_operands; - enum OPR_MODE mode; -}; - -static const struct opr_pb opr_pb[] = { - {0xF0, 0x70, 1, OPR_IMMe4}, - {0xF8, 0xB8, 1, OPR_REG}, - {0xC0, 0x40, 1, OPR_OFXYS}, - {0xEF, 0xE3, 1, OPR_XY_PRE_INC}, - {0xEF, 0xE7, 1, OPR_XY_POST_INC}, - {0xEF, 0xC3, 1, OPR_XY_PRE_DEC}, - {0xEF, 0xC7, 1, OPR_XY_POST_DEC}, - {0xFF, 0xFB, 1, OPR_S_PRE_DEC}, - {0xFF, 0xFF, 1, OPR_S_POST_INC}, - {0xC8, 0x88, 1, OPR_REG_DIRECT}, - {0xE8, 0xC8, 1, OPR_REG_INDIRECT}, - - {0xCE, 0xC0, 2, OPR_IDX_DIRECT}, - {0xCE, 0xC4, 2, OPR_IDX_INDIRECT}, - {0xC0, 0x00, 2, OPR_EXT1}, - - {0xC8, 0x80, 3, OPR_IDX2_REG}, - {0xFA, 0xF8, 3, OPR_EXT18}, - - {0xCF, 0xC2, 4, OPR_IDX3_DIRECT}, - {0xCF, 0xC6, 4, OPR_IDX3_INDIRECT}, - - {0xF8, 0xE8, 4, OPR_IDX3_DIRECT_REG}, - {0xFF, 0xFA, 4, OPR_EXT3_DIRECT}, - {0xFF, 0xFE, 4, OPR_EXT3_INDIRECT}, + struct mem_read_abstraction_base base; + bfd_vma memaddr; + struct disassemble_info* info; }; - -/* Return the number of bytes in a OPR operand, including the XB postbyte. - It does not include any preceeding opcodes. */ -static int -opr_n_bytes (bfd_vma memaddr, struct disassemble_info* info) -{ - bfd_byte xb; - int status = read_memory (memaddr, &xb, 1, info); - if (status < 0) - return status; - - size_t i; - for (i = 0; i < sizeof (opr_pb) / sizeof (opr_pb[0]); ++i) - { - const struct opr_pb *pb = opr_pb + i; - if ((xb & pb->mask) == pb->value) - { - return pb->n_operands; - } - } - - return 1; -} - -static int -opr_n_bytes_p1 (bfd_vma memaddr, struct disassemble_info* info) -{ - return 1 + opr_n_bytes (memaddr, info); -} - -static int -opr_n_bytes2 (bfd_vma memaddr, struct disassemble_info* info) -{ - int s = opr_n_bytes (memaddr, info); - s += opr_n_bytes (memaddr + s, info); - return s + 1; -} - -enum BB_MODE - { - BB_REG_REG_REG, - BB_REG_REG_IMM, - BB_REG_OPR_REG, - BB_OPR_REG_REG, - BB_REG_OPR_IMM, - BB_OPR_REG_IMM - }; - -struct opr_bb -{ - uint8_t mask; - uint8_t value; - int n_operands; - bool opr; - enum BB_MODE mode; -}; - -static const struct opr_bb bb_modes[] = - { - {0x60, 0x00, 2, false, BB_REG_REG_REG}, - {0x60, 0x20, 3, false, BB_REG_REG_IMM}, - {0x70, 0x40, 2, true, BB_REG_OPR_REG}, - {0x70, 0x50, 2, true, BB_OPR_REG_REG}, - {0x70, 0x60, 3, true, BB_REG_OPR_IMM}, - {0x70, 0x70, 3, true, BB_OPR_REG_IMM} - }; - -static int -bfextins_n_bytes (bfd_vma memaddr, struct disassemble_info* info) -{ - bfd_byte bb; - int status = read_memory (memaddr, &bb, 1, info); - if (status < 0) - return status; - - size_t i; - const struct opr_bb *bbs = 0; - for (i = 0; i < sizeof (bb_modes) / sizeof (bb_modes[0]); ++i) - { - bbs = bb_modes + i; - if ((bb & bbs->mask) == bbs->value) - { - break; - } - } - - int n = bbs->n_operands; - if (bbs->opr) - n += opr_n_bytes (memaddr + n - 1, info); - - return n; -} - -static int -single (bfd_vma memaddr ATTRIBUTE_UNUSED, - struct disassemble_info* info ATTRIBUTE_UNUSED) -{ - return 1; -} - -static int -two (bfd_vma memaddr ATTRIBUTE_UNUSED, - struct disassemble_info* info ATTRIBUTE_UNUSED) +static void +advance (struct mem_read_abstraction_base *b) { - return 2; + struct mem_read_abstraction *mra = (struct mem_read_abstraction *) b; + mra->memaddr ++; } -static int -three (bfd_vma memaddr ATTRIBUTE_UNUSED, - struct disassemble_info* info ATTRIBUTE_UNUSED) +static bfd_vma +posn (struct mem_read_abstraction_base *b) { - return 3; + struct mem_read_abstraction *mra = (struct mem_read_abstraction *) b; + return mra->memaddr; } static int -four (bfd_vma memaddr ATTRIBUTE_UNUSED, - struct disassemble_info* info ATTRIBUTE_UNUSED) +abstract_read_memory (struct mem_read_abstraction_base *b, + int offset, + size_t n, bfd_byte *bytes) { - return 4; -} + struct mem_read_abstraction *mra = (struct mem_read_abstraction *) b; -static int -five (bfd_vma memaddr ATTRIBUTE_UNUSED, - struct disassemble_info* info ATTRIBUTE_UNUSED) -{ - return 5; -} + int status = + (*mra->info->read_memory_func) (mra->memaddr + offset, + bytes, n, mra->info); -static int -pcrel_15bit (bfd_vma memaddr, struct disassemble_info* info) -{ - bfd_byte byte; - int status = read_memory (memaddr, &byte, 1, info); - if (status < 0) - return status; - return (byte & 0x80) ? 3 : 2; -} - - - - -static void -operand_separator (struct disassemble_info *info) -{ - if ((info->flags & 0x2)) - { - (*info->fprintf_func) (info->stream, ", "); - } - else + if (status != 0) { - (*info->fprintf_func) (info->stream, " "); + (*mra->info->memory_error_func) (status, mra->memaddr, mra->info); + return -1; } - - info->flags |= 0x2; -} - - - -static void -imm1 (bfd_vma memaddr, struct disassemble_info* info) -{ - bfd_byte byte; - int status = read_memory (memaddr, &byte, 1, info); - if (status < 0) - return; - - operand_separator (info); - (*info->fprintf_func) (info->stream, "#%d", byte); -} - -static void -trap_decode (bfd_vma memaddr, struct disassemble_info* info) -{ - imm1 (memaddr - 1, info); + return 0; } - +/* Start of disassembly file. */ const struct reg registers[S12Z_N_REGISTERS] = { {"d2", 2}, @@ -311,58 +96,128 @@ const struct reg registers[S12Z_N_REGISTERS] = {"ccw", 2} }; -static char * -xys_from_postbyte (uint8_t postbyte) -{ - char *reg = "?"; - switch ((postbyte & 0x30) >> 4) - { - case 0: - reg = "x"; - break; - case 1: - reg = "y"; - break; - case 2: - reg = "s"; - break; - default: - reg = "?"; - break; - } - return reg; -} +static const char *mnemonics[] = + { + "!!invalid!!", + "psh", + "pul", + "tbne", "tbeq", "tbpl", "tbmi", "tbgt", "tble", + "dbne", "dbeq", "dbpl", "dbmi", "dbgt", "dble", + "sex", + "exg", + "lsl", "lsr", + "asl", "asr", + "rol", "ror", + "bfins", "bfext", + + "trap", + + "ld", + "st", + "cmp", + + "stop", + "wai", + "sys", + + "minu", + "mins", + "maxu", + "maxs", + + "abs", + "adc", + "bit", + "sbc", + "rti", + "clb", + "eor", + + "sat", + + "nop", + "bgnd", + "brclr", + "brset", + "rts", + "lea", + "mov", + + "bra", + "bsr", + "bhi", + "bls", + "bcc", + "bcs", + "bne", + "beq", + "bvc", + "bvs", + "bpl", + "bmi", + "bge", + "blt", + "bgt", + "ble", + "inc", + "clr", + "dec", + + "add", + "sub", + "and", + "or", + + "tfr", + "jmp", + "jsr", + "com", + "andcc", + "neg", + "orcc", + "bclr", + "bset", + "btgl", + "swi", + + "mulu", + "divu", + "modu", + "macu", + "qmulu", + + "muls", + "divs", + "mods", + "macs", + "qmuls", + + NULL + }; -static char * -xysp_from_postbyte (uint8_t postbyte) + +static void +operand_separator (struct disassemble_info *info) { - char *reg = "?"; - switch ((postbyte & 0x30) >> 4) - { - case 0: - reg = "x"; - break; - case 1: - reg = "y"; - break; - case 2: - reg = "s"; - break; - default: - reg = "p"; - break; - } - return reg; + if ((info->flags & 0x2)) + (*info->fprintf_func) (info->stream, ","); + + (*info->fprintf_func) (info->stream, " "); + + info->flags |= 0x2; } -/* Render the symbol name whose value is ADDR or the adddress itself if there is - no symbol. */ +/* Render the symbol name whose value is ADDR + BASE or the adddress itself if + there is no symbol. If BASE is non zero, then the a PC relative adddress is + assumend (ie BASE is the value in the PC. */ static void -decode_possible_symbol (bfd_vma addr, struct disassemble_info *info) +decode_possible_symbol (bfd_vma addr, bfd_vma base, + struct disassemble_info *info, bool relative) { - if (!info->symbol_at_address_func (addr, info)) + const char *fmt = relative ? "*%+" BFD_VMA_FMT "d" : "%" BFD_VMA_FMT "d"; + if (!info->symbol_at_address_func (addr + base, info)) { - (*info->fprintf_func) (info->stream, "%" BFD_VMA_FMT "d", addr); + (*info->fprintf_func) (info->stream, fmt, addr); } else { @@ -371,7 +226,7 @@ decode_possible_symbol (bfd_vma addr, struct disassemble_info *info) for (j = 0; j < info->symtab_size; ++j) { sym = info->symtab[j]; - if (bfd_asymbol_value (sym) == addr) + if (bfd_asymbol_value (sym) == addr + base) { break; } @@ -379,2305 +234,160 @@ decode_possible_symbol (bfd_vma addr, struct disassemble_info *info) if (j < info->symtab_size) (*info->fprintf_func) (info->stream, "%s", bfd_asymbol_name (sym)); else - (*info->fprintf_func) (info->stream, "%" BFD_VMA_FMT "d", addr); - } -} - -static void ld_18bit_decode (bfd_vma memaddr, struct disassemble_info* info); - -static void -ext24_decode (bfd_vma memaddr, struct disassemble_info* info) -{ - uint8_t buffer[3]; - int status = read_memory (memaddr, buffer, 3, info); - if (status < 0) - return; - - int i; - uint32_t addr = 0; - for (i = 0; i < 3; ++i) - { - addr <<= 8; - addr |= buffer[i]; - } - - operand_separator (info); - decode_possible_symbol (addr, info); -} - - -static uint32_t -decode_signed_value (bfd_vma memaddr, struct disassemble_info* info, short size) -{ - assert (size >0); - assert (size <= 4); - bfd_byte buffer[4]; - if (0 > read_memory (memaddr, buffer, size, info)) - { - return 0; - } - - int i; - uint32_t value = 0; - for (i = 0; i < size; ++i) - { - value |= buffer[i] << (8 * (size - i - 1)); - } - - if (buffer[0] & 0x80) - { - /* Deal with negative values */ - value -= 0x1UL << (size * 8); - } - return value; -} - - -static void -opr_decode (bfd_vma memaddr, struct disassemble_info* info) -{ - bfd_byte postbyte; - int status = read_memory (memaddr, &postbyte, 1, info); - if (status < 0) - return; - - enum OPR_MODE mode = -1; - size_t i; - for (i = 0; i < sizeof (opr_pb) / sizeof (opr_pb[0]); ++i) - { - const struct opr_pb *pb = opr_pb + i; - if ((postbyte & pb->mask) == pb->value) - { - mode = pb->mode; - break; - } - } - - operand_separator (info); - switch (mode) - { - case OPR_IMMe4: - { - int n; - uint8_t x = (postbyte & 0x0F); - if (x == 0) - n = -1; - else - n = x; - - (*info->fprintf_func) (info->stream, "#%d", n); - break; - } - case OPR_REG: - { - uint8_t x = (postbyte & 0x07); - (*info->fprintf_func) (info->stream, "%s", registers[x].name); - break; - } - case OPR_OFXYS: - { - const char *reg = xys_from_postbyte (postbyte); - (*info->fprintf_func) (info->stream, "(%d,%s)", postbyte & 0x0F, reg); - break; - } - case OPR_REG_DIRECT: - { - (*info->fprintf_func) (info->stream, "(%s,%s)", registers[postbyte & 0x07].name, - xys_from_postbyte (postbyte)); - break; - } - case OPR_REG_INDIRECT: - { - (*info->fprintf_func) (info->stream, "[%s,%s]", registers[postbyte & 0x07].name, - (postbyte & 0x10) ? "y": "x"); - break; - } - - case OPR_IDX_INDIRECT: - { - uint8_t x1; - read_memory (memaddr + 1, &x1, 1, info); - int idx = x1; - - if (postbyte & 0x01) - { - /* Deal with negative values */ - idx -= 0x1UL << 8; - } - - (*info->fprintf_func) (info->stream, "[%d,%s]", idx, - xysp_from_postbyte (postbyte)); - break; - } - - case OPR_IDX3_DIRECT: - { - uint8_t x[3]; - read_memory (memaddr + 1, x, 3, info); - int idx = x[0] << 16 | x[1] << 8 | x[2]; - - if (x[0] & 0x80) - { - /* Deal with negative values */ - idx -= 0x1UL << 24; - } - - (*info->fprintf_func) (info->stream, "(%d,%s)", idx, - xysp_from_postbyte (postbyte)); - break; - } - - case OPR_IDX3_DIRECT_REG: - { - uint8_t x[3]; - read_memory (memaddr + 1, x, 3, info); - int idx = x[0] << 16 | x[1] << 8 | x[2]; - - if (x[0] & 0x80) - { - /* Deal with negative values */ - idx -= 0x1UL << 24; - } - - (*info->fprintf_func) (info->stream, "(%d,%s)", idx, - registers[postbyte & 0x07].name); - break; - } - - case OPR_IDX3_INDIRECT: - { - uint8_t x[3]; - read_memory (memaddr + 1, x, 3, info); - int idx = x[0] << 16 | x[1] << 8 | x[2]; - - if (x[0] & 0x80) - { - /* Deal with negative values */ - idx -= 0x1UL << 24; - } - - (*info->fprintf_func) (info->stream, "[%d,%s]", idx, - xysp_from_postbyte (postbyte)); - break; - } - - case OPR_IDX_DIRECT: - { - uint8_t x1; - read_memory (memaddr + 1, &x1, 1, info); - int idx = x1; - - if (postbyte & 0x01) - { - /* Deal with negative values */ - idx -= 0x1UL << 8; - } - - (*info->fprintf_func) (info->stream, "(%d,%s)", idx, - xysp_from_postbyte (postbyte)); - break; - } - - case OPR_IDX2_REG: - { - uint8_t x[2]; - read_memory (memaddr + 1, x, 2, info); - uint32_t offset = x[1] | x[0] << 8 ; - offset |= (postbyte & 0x30) << 12; - - (*info->fprintf_func) (info->stream, "(%d,%s)", offset, - registers[postbyte & 0x07].name); - break; - } - - case OPR_XY_PRE_INC: - { - (*info->fprintf_func) (info->stream, "(+%s)", - (postbyte & 0x10) ? "y": "x"); - - break; - } - case OPR_XY_POST_INC: - { - (*info->fprintf_func) (info->stream, "(%s+)", - (postbyte & 0x10) ? "y": "x"); - - break; - } - case OPR_XY_PRE_DEC: - { - (*info->fprintf_func) (info->stream, "(-%s)", - (postbyte & 0x10) ? "y": "x"); - - break; - } - case OPR_XY_POST_DEC: - { - (*info->fprintf_func) (info->stream, "(%s-)", - (postbyte & 0x10) ? "y": "x"); - - break; - } - case OPR_S_PRE_DEC: - { - (*info->fprintf_func) (info->stream, "(-s)"); - break; - } - case OPR_S_POST_INC: - { - (*info->fprintf_func) (info->stream, "(s+)"); - break; - } - - case OPR_EXT18: - { - const size_t size = 2; - bfd_byte buffer[4]; - status = read_memory (memaddr + 1, buffer, size, info); - if (status < 0) - return; - - uint32_t ext18 = 0; - for (i = 0; i < size; ++i) - { - ext18 <<= 8; - ext18 |= buffer[i]; - } - - ext18 |= (postbyte & 0x01) << 16; - ext18 |= (postbyte & 0x04) << 15; - - decode_possible_symbol (ext18, info); - break; - } - - case OPR_EXT1: - { - uint8_t x1 = 0; - read_memory (memaddr + 1, &x1, 1, info); - int16_t addr; - addr = x1; - addr |= (postbyte & 0x3f) << 8; - - decode_possible_symbol (addr, info); - break; - } - - case OPR_EXT3_DIRECT: - { - const size_t size = 3; - bfd_byte buffer[4]; - status = read_memory (memaddr + 1, buffer, size, info); - if (status < 0) - return; - - uint32_t ext24 = 0; - for (i = 0; i < size; ++i) - { - ext24 |= buffer[i] << (8 * (size - i - 1)); - } - - decode_possible_symbol (ext24, info); - break; - } - - case OPR_EXT3_INDIRECT: - { - const size_t size = 3; - bfd_byte buffer[4]; - status = read_memory (memaddr + 1, buffer, size, info); - if (status < 0) - return; - - uint32_t ext24 = 0; - for (i = 0; i < size; ++i) - { - ext24 |= buffer[i] << (8 * (size - i - 1)); - } - - (*info->fprintf_func) (info->stream, "[%d]", ext24); - - break; - } - - default: - (*info->fprintf_func) (info->stream, "Unknown OPR mode #0x%x (%d)", postbyte, mode); + (*info->fprintf_func) (info->stream, fmt, addr); } } +/* Emit the disassembled text for OPR */ static void -opr_decode2 (bfd_vma memaddr, struct disassemble_info* info) -{ - int n = opr_n_bytes (memaddr, info); - opr_decode (memaddr, info); - opr_decode (memaddr + n, info); -} - -static void -imm1234 (bfd_vma memaddr, struct disassemble_info* info, int base) -{ - bfd_byte opcode; - int status = read_memory (memaddr - 1, &opcode, 1, info); - if (status < 0) - return; - - opcode -= base; - - int size = registers[opcode & 0xF].bytes; - - uint32_t imm = decode_signed_value (memaddr, info, size); - operand_separator (info); - (*info->fprintf_func) (info->stream, "#%d", imm); -} - - -/* Special case of LD and CMP with register S and IMM operand */ -static void -reg_s_imm (bfd_vma memaddr, struct disassemble_info* info) +opr_emit_disassembly (const struct operand *opr, + struct disassemble_info *info) { operand_separator (info); - (*info->fprintf_func) (info->stream, "s"); - - uint32_t imm = decode_signed_value (memaddr, info, 3); - operand_separator (info); - (*info->fprintf_func) (info->stream, "#%d", imm); -} - -/* Special case of LD, CMP and ST with register S and OPR operand */ -static void -reg_s_opr (bfd_vma memaddr, struct disassemble_info* info) -{ - operand_separator (info); - (*info->fprintf_func) (info->stream, "s"); - - opr_decode (memaddr, info); -} - -static void -imm1234_8base (bfd_vma memaddr, struct disassemble_info* info) -{ - imm1234 (memaddr, info, 8); -} - -static void -imm1234_0base (bfd_vma memaddr, struct disassemble_info* info) -{ - imm1234 (memaddr, info, 0); -} -static void -tfr (bfd_vma memaddr, struct disassemble_info* info) -{ - bfd_byte byte; - int status = read_memory (memaddr, &byte, 1, info); - if (status < 0) - return; - - operand_separator (info); - (*info->fprintf_func) (info->stream, "%s, %s", - registers[byte >> 4].name, - registers[byte & 0xF].name); -} - - -static void -reg (bfd_vma memaddr, struct disassemble_info* info) -{ - bfd_byte byte; - int status = read_memory (memaddr - 1, &byte, 1, info); - if (status < 0) - return; - - operand_separator (info); - (*info->fprintf_func) (info->stream, "%s", registers[byte & 0x07].name); -} - -static void -reg_xy (bfd_vma memaddr, struct disassemble_info* info) -{ - bfd_byte byte; - int status = read_memory (memaddr - 1, &byte, 1, info); - if (status < 0) - return; - - operand_separator (info); - (*info->fprintf_func) (info->stream, "%s", (byte & 0x01) ? "y" : "x"); -} - -static void -lea_reg_xys_opr (bfd_vma memaddr, struct disassemble_info* info) -{ - bfd_byte byte; - int status = read_memory (memaddr - 1, &byte, 1, info); - if (status < 0) - return; - - char *reg_xys = NULL; - switch (byte & 0x03) + switch (opr->cl) { - case 0x00: - reg_xys = "x"; - break; - case 0x01: - reg_xys = "y"; - break; - case 0x02: - reg_xys = "s"; - break; - } - - operand_separator (info); - (*info->fprintf_func) (info->stream, "%s", reg_xys); - opr_decode (memaddr, info); -} - - - -static void -lea_reg_xys (bfd_vma memaddr, struct disassemble_info* info) -{ - bfd_byte byte; - int status = read_memory (memaddr - 1, &byte, 1, info); - if (status < 0) - return; - - char *reg_xys = NULL; - switch (byte & 0x03) - { - case 0x00: - reg_xys = "x"; - break; - case 0x01: - reg_xys = "y"; - break; - case 0x02: - reg_xys = "s"; - break; - } - - status = read_memory (memaddr, &byte, 1, info); - if (status < 0) - return; - - int8_t v = byte; - - operand_separator (info); - (*info->fprintf_func) (info->stream, "%s, (%d,%s)", reg_xys, v, reg_xys); -} - - -/* PC Relative offsets of size 15 or 7 bits */ -static void -rel_15_7 (bfd_vma memaddr, struct disassemble_info* info, int offset) -{ - bfd_byte upper; - int status = read_memory (memaddr, &upper, 1, info); - if (status < 0) - return; - - bool rel_size = (upper & 0x80); - - int16_t addr = upper; - if (rel_size) - { - /* 15 bits. Get the next byte */ - bfd_byte lower; - status = read_memory (memaddr + 1, &lower, 1, info); - if (status < 0) - return; - - addr <<= 8; - addr |= lower; - addr &= 0x7FFF; - - bool negative = (addr & 0x4000); - addr &= 0x3FFF; - if (negative) - addr = addr - 0x4000; - } - else - { - /* 7 bits. */ - bool negative = (addr & 0x40); - addr &= 0x3F; - if (negative) - addr = addr - 0x40; - } - - operand_separator (info); - if (!info->symbol_at_address_func (addr + memaddr - offset, info)) - { - (*info->fprintf_func) (info->stream, "*%+d", addr); - } - else - { - asymbol *sym = NULL; - int i; - for (i = 0; i < info->symtab_size; ++i) - { - sym = info->symtab[i]; - if (bfd_asymbol_value (sym) == addr + memaddr - offset) - { - break; - } - } - if (i < info->symtab_size) - (*info->fprintf_func) (info->stream, "%s", bfd_asymbol_name (sym)); - else - (*info->fprintf_func) (info->stream, "*%+d", addr); - } -} - - -/* PC Relative offsets of size 15 or 7 bits */ -static void -decode_rel_15_7 (bfd_vma memaddr, struct disassemble_info* info) -{ - rel_15_7 (memaddr, info, 1); -} - -struct opcode -{ - const char *mnemonic; - insn_bytes_f insn_bytes; - operands_f operands; - operands_f operands2; -}; - -static int shift_n_bytes (bfd_vma memaddr, struct disassemble_info* info); -static int mov_imm_opr_n_bytes (bfd_vma memaddr, struct disassemble_info* info); -static int loop_prim_n_bytes (bfd_vma memaddr, struct disassemble_info* info); -static void mov_imm_opr (bfd_vma memaddr, struct disassemble_info* info); -static void bm_rel_decode (bfd_vma memaddr, struct disassemble_info* info); -static int bm_rel_n_bytes (bfd_vma memaddr, struct disassemble_info* info); -static int mul_n_bytes (bfd_vma memaddr, struct disassemble_info* info); -static void mul_decode (bfd_vma memaddr, struct disassemble_info* info); -static int bm_n_bytes (bfd_vma memaddr, struct disassemble_info* info); -static void bm_decode (bfd_vma memaddr, struct disassemble_info* info); - -static void -cmp_xy (bfd_vma memaddr ATTRIBUTE_UNUSED, struct disassemble_info* info) -{ - operand_separator (info); - (*info->fprintf_func) (info->stream, "x, y"); -} - -static void -sub_d6_x_y (bfd_vma memaddr ATTRIBUTE_UNUSED, struct disassemble_info* info) -{ - operand_separator (info); - (*info->fprintf_func) (info->stream, "d6, x, y"); -} - -static void -sub_d6_y_x (bfd_vma memaddr ATTRIBUTE_UNUSED, struct disassemble_info* info) -{ - operand_separator (info); - (*info->fprintf_func) (info->stream, "d6, y, x"); -} - -static const char shift_size_table[] = { - 'b', 'w', 'p', 'l' -}; - -static const struct opcode page2[] = - { - [0x00] = {"ld", opr_n_bytes_p1, 0, reg_s_opr}, - [0x01] = {"st", opr_n_bytes_p1, 0, reg_s_opr}, - [0x02] = {"cmp", opr_n_bytes_p1, 0, reg_s_opr}, - [0x03] = {"ld", four, 0, reg_s_imm}, - [0x04] = {"cmp", four, 0, reg_s_imm}, - [0x05] = {"stop", single, 0, 0}, - [0x06] = {"wai", single, 0, 0}, - [0x07] = {"sys", single, 0, 0}, - [0x08] = {NULL, bfextins_n_bytes, 0, 0}, /* BFEXT / BFINS */ - [0x09] = {NULL, bfextins_n_bytes, 0, 0}, - [0x0a] = {NULL, bfextins_n_bytes, 0, 0}, - [0x0b] = {NULL, bfextins_n_bytes, 0, 0}, - [0x0c] = {NULL, bfextins_n_bytes, 0, 0}, - [0x0d] = {NULL, bfextins_n_bytes, 0, 0}, - [0x0e] = {NULL, bfextins_n_bytes, 0, 0}, - [0x0f] = {NULL, bfextins_n_bytes, 0, 0}, - [0x10] = {"minu", opr_n_bytes_p1, reg, opr_decode}, - [0x11] = {"minu", opr_n_bytes_p1, reg, opr_decode}, - [0x12] = {"minu", opr_n_bytes_p1, reg, opr_decode}, - [0x13] = {"minu", opr_n_bytes_p1, reg, opr_decode}, - [0x14] = {"minu", opr_n_bytes_p1, reg, opr_decode}, - [0x15] = {"minu", opr_n_bytes_p1, reg, opr_decode}, - [0x16] = {"minu", opr_n_bytes_p1, reg, opr_decode}, - [0x17] = {"minu", opr_n_bytes_p1, reg, opr_decode}, - [0x18] = {"maxu", opr_n_bytes_p1, reg, opr_decode}, - [0x19] = {"maxu", opr_n_bytes_p1, reg, opr_decode}, - [0x1a] = {"maxu", opr_n_bytes_p1, reg, opr_decode}, - [0x1b] = {"maxu", opr_n_bytes_p1, reg, opr_decode}, - [0x1c] = {"maxu", opr_n_bytes_p1, reg, opr_decode}, - [0x1d] = {"maxu", opr_n_bytes_p1, reg, opr_decode}, - [0x1e] = {"maxu", opr_n_bytes_p1, reg, opr_decode}, - [0x1f] = {"maxu", opr_n_bytes_p1, reg, opr_decode}, - [0x20] = {"mins", opr_n_bytes_p1, reg, opr_decode}, - [0x21] = {"mins", opr_n_bytes_p1, reg, opr_decode}, - [0x22] = {"mins", opr_n_bytes_p1, reg, opr_decode}, - [0x23] = {"mins", opr_n_bytes_p1, reg, opr_decode}, - [0x24] = {"mins", opr_n_bytes_p1, reg, opr_decode}, - [0x25] = {"mins", opr_n_bytes_p1, reg, opr_decode}, - [0x26] = {"mins", opr_n_bytes_p1, reg, opr_decode}, - [0x27] = {"mins", opr_n_bytes_p1, reg, opr_decode}, - [0x28] = {"maxs", opr_n_bytes_p1, reg, opr_decode}, - [0x29] = {"maxs", opr_n_bytes_p1, reg, opr_decode}, - [0x2a] = {"maxs", opr_n_bytes_p1, reg, opr_decode}, - [0x2b] = {"maxs", opr_n_bytes_p1, reg, opr_decode}, - [0x2c] = {"maxs", opr_n_bytes_p1, reg, opr_decode}, - [0x2d] = {"maxs", opr_n_bytes_p1, reg, opr_decode}, - [0x2e] = {"maxs", opr_n_bytes_p1, reg, opr_decode}, - [0x2f] = {"maxs", opr_n_bytes_p1, reg, opr_decode}, - [0x30] = {"div", mul_n_bytes, mul_decode, 0}, - [0x31] = {"div", mul_n_bytes, mul_decode, 0}, - [0x32] = {"div", mul_n_bytes, mul_decode, 0}, - [0x33] = {"div", mul_n_bytes, mul_decode, 0}, - [0x34] = {"div", mul_n_bytes, mul_decode, 0}, - [0x35] = {"div", mul_n_bytes, mul_decode, 0}, - [0x36] = {"div", mul_n_bytes, mul_decode, 0}, - [0x37] = {"div", mul_n_bytes, mul_decode, 0}, - [0x38] = {"mod", mul_n_bytes, mul_decode, 0}, - [0x39] = {"mod", mul_n_bytes, mul_decode, 0}, - [0x3a] = {"mod", mul_n_bytes, mul_decode, 0}, - [0x3b] = {"mod", mul_n_bytes, mul_decode, 0}, - [0x3c] = {"mod", mul_n_bytes, mul_decode, 0}, - [0x3d] = {"mod", mul_n_bytes, mul_decode, 0}, - [0x3e] = {"mod", mul_n_bytes, mul_decode, 0}, - [0x3f] = {"mod", mul_n_bytes, mul_decode, 0}, - [0x40] = {"abs", single, reg, 0}, - [0x41] = {"abs", single, reg, 0}, - [0x42] = {"abs", single, reg, 0}, - [0x43] = {"abs", single, reg, 0}, - [0x44] = {"abs", single, reg, 0}, - [0x45] = {"abs", single, reg, 0}, - [0x46] = {"abs", single, reg, 0}, - [0x47] = {"abs", single, reg, 0}, - [0x48] = {"mac", mul_n_bytes, mul_decode, 0}, - [0x49] = {"mac", mul_n_bytes, mul_decode, 0}, - [0x4a] = {"mac", mul_n_bytes, mul_decode, 0}, - [0x4b] = {"mac", mul_n_bytes, mul_decode, 0}, - [0x4c] = {"mac", mul_n_bytes, mul_decode, 0}, - [0x4d] = {"mac", mul_n_bytes, mul_decode, 0}, - [0x4e] = {"mac", mul_n_bytes, mul_decode, 0}, - [0x4f] = {"mac", mul_n_bytes, mul_decode, 0}, - [0x50] = {"adc", three, reg, imm1234_0base}, - [0x51] = {"adc", three, reg, imm1234_0base}, - [0x52] = {"adc", three, reg, imm1234_0base}, - [0x53] = {"adc", three, reg, imm1234_0base}, - [0x54] = {"adc", two, reg, imm1234_0base}, - [0x55] = {"adc", two, reg, imm1234_0base}, - [0x56] = {"adc", five, reg, imm1234_0base}, - [0x57] = {"adc", five, reg, imm1234_0base}, - [0x58] = {"bit", three, reg, imm1234_8base}, - [0x59] = {"bit", three, reg, imm1234_8base}, - [0x5a] = {"bit", three, reg, imm1234_8base}, - [0x5b] = {"bit", three, reg, imm1234_8base}, - [0x5c] = {"bit", two, reg, imm1234_8base}, - [0x5d] = {"bit", two, reg, imm1234_8base}, - [0x5e] = {"bit", five, reg, imm1234_8base}, - [0x5f] = {"bit", five, reg, imm1234_8base}, - [0x60] = {"adc", opr_n_bytes_p1, reg, opr_decode}, - [0x61] = {"adc", opr_n_bytes_p1, reg, opr_decode}, - [0x62] = {"adc", opr_n_bytes_p1, reg, opr_decode}, - [0x63] = {"adc", opr_n_bytes_p1, reg, opr_decode}, - [0x64] = {"adc", opr_n_bytes_p1, reg, opr_decode}, - [0x65] = {"adc", opr_n_bytes_p1, reg, opr_decode}, - [0x66] = {"adc", opr_n_bytes_p1, reg, opr_decode}, - [0x67] = {"adc", opr_n_bytes_p1, reg, opr_decode}, - [0x68] = {"bit", opr_n_bytes_p1, reg, opr_decode}, - [0x69] = {"bit", opr_n_bytes_p1, reg, opr_decode}, - [0x6a] = {"bit", opr_n_bytes_p1, reg, opr_decode}, - [0x6b] = {"bit", opr_n_bytes_p1, reg, opr_decode}, - [0x6c] = {"bit", opr_n_bytes_p1, reg, opr_decode}, - [0x6d] = {"bit", opr_n_bytes_p1, reg, opr_decode}, - [0x6e] = {"bit", opr_n_bytes_p1, reg, opr_decode}, - [0x6f] = {"bit", opr_n_bytes_p1, reg, opr_decode}, - [0x70] = {"sbc", three, reg, imm1234_0base}, - [0x71] = {"sbc", three, reg, imm1234_0base}, - [0x72] = {"sbc", three, reg, imm1234_0base}, - [0x73] = {"sbc", three, reg, imm1234_0base}, - [0x74] = {"sbc", two, reg, imm1234_0base}, - [0x75] = {"sbc", two, reg, imm1234_0base}, - [0x76] = {"sbc", five, reg, imm1234_0base}, - [0x77] = {"sbc", five, reg, imm1234_0base}, - [0x78] = {"eor", three, reg, imm1234_8base}, - [0x79] = {"eor", three, reg, imm1234_8base}, - [0x7a] = {"eor", three, reg, imm1234_8base}, - [0x7b] = {"eor", three, reg, imm1234_8base}, - [0x7c] = {"eor", two, reg, imm1234_8base}, - [0x7d] = {"eor", two, reg, imm1234_8base}, - [0x7e] = {"eor", five, reg, imm1234_8base}, - [0x7f] = {"eor", five, reg, imm1234_8base}, - [0x80] = {"sbc", opr_n_bytes_p1, reg, opr_decode}, - [0x81] = {"sbc", opr_n_bytes_p1, reg, opr_decode}, - [0x82] = {"sbc", opr_n_bytes_p1, reg, opr_decode}, - [0x83] = {"sbc", opr_n_bytes_p1, reg, opr_decode}, - [0x84] = {"sbc", opr_n_bytes_p1, reg, opr_decode}, - [0x85] = {"sbc", opr_n_bytes_p1, reg, opr_decode}, - [0x86] = {"sbc", opr_n_bytes_p1, reg, opr_decode}, - [0x87] = {"sbc", opr_n_bytes_p1, reg, opr_decode}, - [0x88] = {"eor", opr_n_bytes_p1, reg, opr_decode}, - [0x89] = {"eor", opr_n_bytes_p1, reg, opr_decode}, - [0x8a] = {"eor", opr_n_bytes_p1, reg, opr_decode}, - [0x8b] = {"eor", opr_n_bytes_p1, reg, opr_decode}, - [0x8c] = {"eor", opr_n_bytes_p1, reg, opr_decode}, - [0x8d] = {"eor", opr_n_bytes_p1, reg, opr_decode}, - [0x8e] = {"eor", opr_n_bytes_p1, reg, opr_decode}, - [0x8f] = {"eor", opr_n_bytes_p1, reg, opr_decode}, - [0x90] = {"rti", single, 0, 0}, - [0x91] = {"clb", two, tfr, 0}, - [0x92] = {"trap", single, trap_decode, 0}, - [0x93] = {"trap", single, trap_decode, 0}, - [0x94] = {"trap", single, trap_decode, 0}, - [0x95] = {"trap", single, trap_decode, 0}, - [0x96] = {"trap", single, trap_decode, 0}, - [0x97] = {"trap", single, trap_decode, 0}, - [0x98] = {"trap", single, trap_decode, 0}, - [0x99] = {"trap", single, trap_decode, 0}, - [0x9a] = {"trap", single, trap_decode, 0}, - [0x9b] = {"trap", single, trap_decode, 0}, - [0x9c] = {"trap", single, trap_decode, 0}, - [0x9d] = {"trap", single, trap_decode, 0}, - [0x9e] = {"trap", single, trap_decode, 0}, - [0x9f] = {"trap", single, trap_decode, 0}, - [0xa0] = {"sat", single, reg, 0}, - [0xa1] = {"sat", single, reg, 0}, - [0xa2] = {"sat", single, reg, 0}, - [0xa3] = {"sat", single, reg, 0}, - [0xa4] = {"sat", single, reg, 0}, - [0xa5] = {"sat", single, reg, 0}, - [0xa6] = {"sat", single, reg, 0}, - [0xa7] = {"sat", single, reg, 0}, - [0xa8] = {"trap", single, trap_decode, 0}, - [0xa9] = {"trap", single, trap_decode, 0}, - [0xaa] = {"trap", single, trap_decode, 0}, - [0xab] = {"trap", single, trap_decode, 0}, - [0xac] = {"trap", single, trap_decode, 0}, - [0xad] = {"trap", single, trap_decode, 0}, - [0xae] = {"trap", single, trap_decode, 0}, - [0xaf] = {"trap", single, trap_decode, 0}, - [0xb0] = {"qmul", mul_n_bytes, mul_decode, 0}, - [0xb1] = {"qmul", mul_n_bytes, mul_decode, 0}, - [0xb2] = {"qmul", mul_n_bytes, mul_decode, 0}, - [0xb3] = {"qmul", mul_n_bytes, mul_decode, 0}, - [0xb4] = {"qmul", mul_n_bytes, mul_decode, 0}, - [0xb5] = {"qmul", mul_n_bytes, mul_decode, 0}, - [0xb6] = {"qmul", mul_n_bytes, mul_decode, 0}, - [0xb7] = {"qmul", mul_n_bytes, mul_decode, 0}, - [0xb8] = {"trap", single, trap_decode, 0}, - [0xb9] = {"trap", single, trap_decode, 0}, - [0xba] = {"trap", single, trap_decode, 0}, - [0xbb] = {"trap", single, trap_decode, 0}, - [0xbc] = {"trap", single, trap_decode, 0}, - [0xbd] = {"trap", single, trap_decode, 0}, - [0xbe] = {"trap", single, trap_decode, 0}, - [0xbf] = {"trap", single, trap_decode, 0}, - [0xc0] = {"trap", single, trap_decode, 0}, - [0xc1] = {"trap", single, trap_decode, 0}, - [0xc2] = {"trap", single, trap_decode, 0}, - [0xc3] = {"trap", single, trap_decode, 0}, - [0xc4] = {"trap", single, trap_decode, 0}, - [0xc5] = {"trap", single, trap_decode, 0}, - [0xc6] = {"trap", single, trap_decode, 0}, - [0xc7] = {"trap", single, trap_decode, 0}, - [0xc8] = {"trap", single, trap_decode, 0}, - [0xc9] = {"trap", single, trap_decode, 0}, - [0xca] = {"trap", single, trap_decode, 0}, - [0xcb] = {"trap", single, trap_decode, 0}, - [0xcc] = {"trap", single, trap_decode, 0}, - [0xcd] = {"trap", single, trap_decode, 0}, - [0xce] = {"trap", single, trap_decode, 0}, - [0xcf] = {"trap", single, trap_decode, 0}, - [0xd0] = {"trap", single, trap_decode, 0}, - [0xd1] = {"trap", single, trap_decode, 0}, - [0xd2] = {"trap", single, trap_decode, 0}, - [0xd3] = {"trap", single, trap_decode, 0}, - [0xd4] = {"trap", single, trap_decode, 0}, - [0xd5] = {"trap", single, trap_decode, 0}, - [0xd6] = {"trap", single, trap_decode, 0}, - [0xd7] = {"trap", single, trap_decode, 0}, - [0xd8] = {"trap", single, trap_decode, 0}, - [0xd9] = {"trap", single, trap_decode, 0}, - [0xda] = {"trap", single, trap_decode, 0}, - [0xdb] = {"trap", single, trap_decode, 0}, - [0xdc] = {"trap", single, trap_decode, 0}, - [0xdd] = {"trap", single, trap_decode, 0}, - [0xde] = {"trap", single, trap_decode, 0}, - [0xdf] = {"trap", single, trap_decode, 0}, - [0xe0] = {"trap", single, trap_decode, 0}, - [0xe1] = {"trap", single, trap_decode, 0}, - [0xe2] = {"trap", single, trap_decode, 0}, - [0xe3] = {"trap", single, trap_decode, 0}, - [0xe4] = {"trap", single, trap_decode, 0}, - [0xe5] = {"trap", single, trap_decode, 0}, - [0xe6] = {"trap", single, trap_decode, 0}, - [0xe7] = {"trap", single, trap_decode, 0}, - [0xe8] = {"trap", single, trap_decode, 0}, - [0xe9] = {"trap", single, trap_decode, 0}, - [0xea] = {"trap", single, trap_decode, 0}, - [0xeb] = {"trap", single, trap_decode, 0}, - [0xec] = {"trap", single, trap_decode, 0}, - [0xed] = {"trap", single, trap_decode, 0}, - [0xee] = {"trap", single, trap_decode, 0}, - [0xef] = {"trap", single, trap_decode, 0}, - [0xf0] = {"trap", single, trap_decode, 0}, - [0xf1] = {"trap", single, trap_decode, 0}, - [0xf2] = {"trap", single, trap_decode, 0}, - [0xf3] = {"trap", single, trap_decode, 0}, - [0xf4] = {"trap", single, trap_decode, 0}, - [0xf5] = {"trap", single, trap_decode, 0}, - [0xf6] = {"trap", single, trap_decode, 0}, - [0xf7] = {"trap", single, trap_decode, 0}, - [0xf8] = {"trap", single, trap_decode, 0}, - [0xf9] = {"trap", single, trap_decode, 0}, - [0xfa] = {"trap", single, trap_decode, 0}, - [0xfb] = {"trap", single, trap_decode, 0}, - [0xfc] = {"trap", single, trap_decode, 0}, - [0xfd] = {"trap", single, trap_decode, 0}, - [0xfe] = {"trap", single, trap_decode, 0}, - [0xff] = {"trap", single, trap_decode, 0}, - }; - -static const struct opcode page1[] = - { - [0x00] = {"bgnd", single, 0, 0}, - [0x01] = {"nop", single, 0, 0}, - [0x02] = {"brclr", bm_rel_n_bytes, bm_rel_decode, 0}, - [0x03] = {"brset", bm_rel_n_bytes, bm_rel_decode, 0}, - [0x04] = {NULL, two, 0, 0}, /* psh/pul */ - [0x05] = {"rts", single, 0, 0}, - [0x06] = {"lea", opr_n_bytes_p1, reg, opr_decode}, - [0x07] = {"lea", opr_n_bytes_p1, reg, opr_decode}, - [0x08] = {"lea", opr_n_bytes_p1, lea_reg_xys_opr, 0}, - [0x09] = {"lea", opr_n_bytes_p1, lea_reg_xys_opr, 0}, - [0x0a] = {"lea", opr_n_bytes_p1, lea_reg_xys_opr, 0}, - [0x0b] = {NULL, loop_prim_n_bytes, 0, 0}, /* Loop primitives TBcc / DBcc */ - [0x0c] = {"mov.b", mov_imm_opr_n_bytes, mov_imm_opr, 0}, - [0x0d] = {"mov.w", mov_imm_opr_n_bytes, mov_imm_opr, 0}, - [0x0e] = {"mov.p", mov_imm_opr_n_bytes, mov_imm_opr, 0}, - [0x0f] = {"mov.l", mov_imm_opr_n_bytes, mov_imm_opr, 0}, - [0x10] = {NULL, shift_n_bytes, 0, 0}, /* lsr/lsl/asl/asr/rol/ror */ - [0x11] = {NULL, shift_n_bytes, 0, 0}, - [0x12] = {NULL, shift_n_bytes, 0, 0}, - [0x13] = {NULL, shift_n_bytes, 0, 0}, - [0x14] = {NULL, shift_n_bytes, 0, 0}, - [0x15] = {NULL, shift_n_bytes, 0, 0}, - [0x16] = {NULL, shift_n_bytes, 0, 0}, - [0x17] = {NULL, shift_n_bytes, 0, 0}, - [0x18] = {"lea", two, lea_reg_xys, NULL}, - [0x19] = {"lea", two, lea_reg_xys, NULL}, - [0x1a] = {"lea", two, lea_reg_xys, NULL}, - /* 0x1b PG2 */ - [0x1c] = {"mov.b", opr_n_bytes2, 0, opr_decode2}, - [0x1d] = {"mov.w", opr_n_bytes2, 0, opr_decode2}, - [0x1e] = {"mov.p", opr_n_bytes2, 0, opr_decode2}, - [0x1f] = {"mov.l", opr_n_bytes2, 0, opr_decode2}, - [0x20] = {"bra", pcrel_15bit, decode_rel_15_7, 0}, - [0x21] = {"bsr", pcrel_15bit, decode_rel_15_7, 0}, - [0x22] = {"bhi", pcrel_15bit, decode_rel_15_7, 0}, - [0x23] = {"bls", pcrel_15bit, decode_rel_15_7, 0}, - [0x24] = {"bcc", pcrel_15bit, decode_rel_15_7, 0}, - [0x25] = {"bcs", pcrel_15bit, decode_rel_15_7, 0}, - [0x26] = {"bne", pcrel_15bit, decode_rel_15_7, 0}, - [0x27] = {"beq", pcrel_15bit, decode_rel_15_7, 0}, - [0x28] = {"bvc", pcrel_15bit, decode_rel_15_7, 0}, - [0x29] = {"bvs", pcrel_15bit, decode_rel_15_7, 0}, - [0x2a] = {"bpl", pcrel_15bit, decode_rel_15_7, 0}, - [0x2b] = {"bmi", pcrel_15bit, decode_rel_15_7, 0}, - [0x2c] = {"bge", pcrel_15bit, decode_rel_15_7, 0}, - [0x2d] = {"blt", pcrel_15bit, decode_rel_15_7, 0}, - [0x2e] = {"bgt", pcrel_15bit, decode_rel_15_7, 0}, - [0x2f] = {"ble", pcrel_15bit, decode_rel_15_7, 0}, - [0x30] = {"inc", single, reg, 0}, - [0x31] = {"inc", single, reg, 0}, - [0x32] = {"inc", single, reg, 0}, - [0x33] = {"inc", single, reg, 0}, - [0x34] = {"inc", single, reg, 0}, - [0x35] = {"inc", single, reg, 0}, - [0x36] = {"inc", single, reg, 0}, - [0x37] = {"inc", single, reg, 0}, - [0x38] = {"clr", single, reg, 0}, - [0x39] = {"clr", single, reg, 0}, - [0x3a] = {"clr", single, reg, 0}, - [0x3b] = {"clr", single, reg, 0}, - [0x3c] = {"clr", single, reg, 0}, - [0x3d] = {"clr", single, reg, 0}, - [0x3e] = {"clr", single, reg, 0}, - [0x3f] = {"clr", single, reg, 0}, - [0x40] = {"dec", single, reg, 0}, - [0x41] = {"dec", single, reg, 0}, - [0x42] = {"dec", single, reg, 0}, - [0x43] = {"dec", single, reg, 0}, - [0x44] = {"dec", single, reg, 0}, - [0x45] = {"dec", single, reg, 0}, - [0x46] = {"dec", single, reg, 0}, - [0x47] = {"dec", single, reg, 0}, - [0x48] = {"mul", mul_n_bytes, mul_decode, 0}, - [0x49] = {"mul", mul_n_bytes, mul_decode, 0}, - [0x4a] = {"mul", mul_n_bytes, mul_decode, 0}, - [0x4b] = {"mul", mul_n_bytes, mul_decode, 0}, - [0x4c] = {"mul", mul_n_bytes, mul_decode, 0}, - [0x4d] = {"mul", mul_n_bytes, mul_decode, 0}, - [0x4e] = {"mul", mul_n_bytes, mul_decode, 0}, - [0x4f] = {"mul", mul_n_bytes, mul_decode, 0}, - [0x50] = {"add", three, reg, imm1234_0base}, - [0x51] = {"add", three, reg, imm1234_0base}, - [0x52] = {"add", three, reg, imm1234_0base}, - [0x53] = {"add", three, reg, imm1234_0base}, - [0x54] = {"add", two, reg, imm1234_0base}, - [0x55] = {"add", two, reg, imm1234_0base}, - [0x56] = {"add", five, reg, imm1234_0base}, - [0x57] = {"add", five, reg, imm1234_0base}, - [0x58] = {"and", three, reg, imm1234_8base}, - [0x59] = {"and", three, reg, imm1234_8base}, - [0x5a] = {"and", three, reg, imm1234_8base}, - [0x5b] = {"and", three, reg, imm1234_8base}, - [0x5c] = {"and", two, reg, imm1234_8base}, - [0x5d] = {"and", two, reg, imm1234_8base}, - [0x5e] = {"and", five, reg, imm1234_8base}, - [0x5f] = {"and", five, reg, imm1234_8base}, - [0x60] = {"add", opr_n_bytes_p1, reg, opr_decode}, - [0x61] = {"add", opr_n_bytes_p1, reg, opr_decode}, - [0x62] = {"add", opr_n_bytes_p1, reg, opr_decode}, - [0x63] = {"add", opr_n_bytes_p1, reg, opr_decode}, - [0x64] = {"add", opr_n_bytes_p1, reg, opr_decode}, - [0x65] = {"add", opr_n_bytes_p1, reg, opr_decode}, - [0x66] = {"add", opr_n_bytes_p1, reg, opr_decode}, - [0x67] = {"add", opr_n_bytes_p1, reg, opr_decode}, - [0x68] = {"and", opr_n_bytes_p1, reg, opr_decode}, - [0x69] = {"and", opr_n_bytes_p1, reg, opr_decode}, - [0x6a] = {"and", opr_n_bytes_p1, reg, opr_decode}, - [0x6b] = {"and", opr_n_bytes_p1, reg, opr_decode}, - [0x6c] = {"and", opr_n_bytes_p1, reg, opr_decode}, - [0x6d] = {"and", opr_n_bytes_p1, reg, opr_decode}, - [0x6e] = {"and", opr_n_bytes_p1, reg, opr_decode}, - [0x6f] = {"and", opr_n_bytes_p1, reg, opr_decode}, - [0x70] = {"sub", three, reg, imm1234_0base}, - [0x71] = {"sub", three, reg, imm1234_0base}, - [0x72] = {"sub", three, reg, imm1234_0base}, - [0x73] = {"sub", three, reg, imm1234_0base}, - [0x74] = {"sub", two, reg, imm1234_0base}, - [0x75] = {"sub", two, reg, imm1234_0base}, - [0x76] = {"sub", five, reg, imm1234_0base}, - [0x77] = {"sub", five, reg, imm1234_0base}, - [0x78] = {"or", three, reg, imm1234_8base}, - [0x79] = {"or", three, reg, imm1234_8base}, - [0x7a] = {"or", three, reg, imm1234_8base}, - [0x7b] = {"or", three, reg, imm1234_8base}, - [0x7c] = {"or", two, reg, imm1234_8base}, - [0x7d] = {"or", two, reg, imm1234_8base}, - [0x7e] = {"or", five, reg, imm1234_8base}, - [0x7f] = {"or", five, reg, imm1234_8base}, - [0x80] = {"sub", opr_n_bytes_p1, reg, opr_decode}, - [0x81] = {"sub", opr_n_bytes_p1, reg, opr_decode}, - [0x82] = {"sub", opr_n_bytes_p1, reg, opr_decode}, - [0x83] = {"sub", opr_n_bytes_p1, reg, opr_decode}, - [0x84] = {"sub", opr_n_bytes_p1, reg, opr_decode}, - [0x85] = {"sub", opr_n_bytes_p1, reg, opr_decode}, - [0x86] = {"sub", opr_n_bytes_p1, reg, opr_decode}, - [0x87] = {"sub", opr_n_bytes_p1, reg, opr_decode}, - [0x88] = {"or", opr_n_bytes_p1, reg, opr_decode}, - [0x89] = {"or", opr_n_bytes_p1, reg, opr_decode}, - [0x8a] = {"or", opr_n_bytes_p1, reg, opr_decode}, - [0x8b] = {"or", opr_n_bytes_p1, reg, opr_decode}, - [0x8c] = {"or", opr_n_bytes_p1, reg, opr_decode}, - [0x8d] = {"or", opr_n_bytes_p1, reg, opr_decode}, - [0x8e] = {"or", opr_n_bytes_p1, reg, opr_decode}, - [0x8f] = {"or", opr_n_bytes_p1, reg, opr_decode}, - [0x90] = {"ld", three, reg, imm1234_0base}, - [0x91] = {"ld", three, reg, imm1234_0base}, - [0x92] = {"ld", three, reg, imm1234_0base}, - [0x93] = {"ld", three, reg, imm1234_0base}, - [0x94] = {"ld", two, reg, imm1234_0base}, - [0x95] = {"ld", two, reg, imm1234_0base}, - [0x96] = {"ld", five, reg, imm1234_0base}, - [0x97] = {"ld", five, reg, imm1234_0base}, - [0x98] = {"ld", four, reg_xy, imm1234_0base}, - [0x99] = {"ld", four, reg_xy, imm1234_0base}, - [0x9a] = {"clr", single, reg_xy, 0}, - [0x9b] = {"clr", single, reg_xy, 0}, - [0x9c] = {"inc.b", opr_n_bytes_p1, 0, opr_decode}, - [0x9d] = {"inc.w", opr_n_bytes_p1, 0, opr_decode}, - [0x9e] = {"tfr", two, tfr, NULL}, - [0x9f] = {"inc.l", opr_n_bytes_p1, 0, opr_decode}, - [0xa0] = {"ld", opr_n_bytes_p1, reg, opr_decode}, - [0xa1] = {"ld", opr_n_bytes_p1, reg, opr_decode}, - [0xa2] = {"ld", opr_n_bytes_p1, reg, opr_decode}, - [0xa3] = {"ld", opr_n_bytes_p1, reg, opr_decode}, - [0xa4] = {"ld", opr_n_bytes_p1, reg, opr_decode}, - [0xa5] = {"ld", opr_n_bytes_p1, reg, opr_decode}, - [0xa6] = {"ld", opr_n_bytes_p1, reg, opr_decode}, - [0xa7] = {"ld", opr_n_bytes_p1, reg, opr_decode}, - [0xa8] = {"ld", opr_n_bytes_p1, reg_xy, opr_decode}, - [0xa9] = {"ld", opr_n_bytes_p1, reg_xy, opr_decode}, - [0xaa] = {"jmp", opr_n_bytes_p1, opr_decode, 0}, - [0xab] = {"jsr", opr_n_bytes_p1, opr_decode, 0}, - [0xac] = {"dec.b", opr_n_bytes_p1, 0, opr_decode}, - [0xad] = {"dec.w", opr_n_bytes_p1, 0, opr_decode}, - [0xae] = {NULL, two, 0, 0}, /* EXG / SEX */ - [0xaf] = {"dec.l", opr_n_bytes_p1, 0, opr_decode}, - [0xb0] = {"ld", four, reg, ext24_decode}, - [0xb1] = {"ld", four, reg, ext24_decode}, - [0xb2] = {"ld", four, reg, ext24_decode}, - [0xb3] = {"ld", four, reg, ext24_decode}, - [0xb4] = {"ld", four, reg, ext24_decode}, - [0xb5] = {"ld", four, reg, ext24_decode}, - [0xb6] = {"ld", four, reg, ext24_decode}, - [0xb7] = {"ld", four, reg, ext24_decode}, - [0xb8] = {"ld", four, reg_xy, ext24_decode}, - [0xb9] = {"ld", four, reg_xy, ext24_decode}, - [0xba] = {"jmp", four, ext24_decode, 0}, - [0xbb] = {"jsr", four, ext24_decode, 0}, - [0xbc] = {"clr.b", opr_n_bytes_p1, 0, opr_decode}, - [0xbd] = {"clr.w", opr_n_bytes_p1, 0, opr_decode}, - [0xbe] = {"clr.p", opr_n_bytes_p1, 0, opr_decode}, - [0xbf] = {"clr.l", opr_n_bytes_p1, 0, opr_decode}, - [0xc0] = {"st", opr_n_bytes_p1, reg, opr_decode}, - [0xc1] = {"st", opr_n_bytes_p1, reg, opr_decode}, - [0xc2] = {"st", opr_n_bytes_p1, reg, opr_decode}, - [0xc3] = {"st", opr_n_bytes_p1, reg, opr_decode}, - [0xc4] = {"st", opr_n_bytes_p1, reg, opr_decode}, - [0xc5] = {"st", opr_n_bytes_p1, reg, opr_decode}, - [0xc6] = {"st", opr_n_bytes_p1, reg, opr_decode}, - [0xc7] = {"st", opr_n_bytes_p1, reg, opr_decode}, - [0xc8] = {"st", opr_n_bytes_p1, reg_xy, opr_decode}, - [0xc9] = {"st", opr_n_bytes_p1, reg_xy, opr_decode}, - [0xca] = {"ld", three, reg_xy, ld_18bit_decode}, - [0xcb] = {"ld", three, reg_xy, ld_18bit_decode}, - [0xcc] = {"com.b", opr_n_bytes_p1, NULL, opr_decode}, - [0xcd] = {"com.w", opr_n_bytes_p1, NULL, opr_decode}, - [0xce] = {"andcc", two, imm1, 0}, - [0xcf] = {"com.l", opr_n_bytes_p1, NULL, opr_decode}, - [0xd0] = {"st", four, reg, ext24_decode}, - [0xd1] = {"st", four, reg, ext24_decode}, - [0xd2] = {"st", four, reg, ext24_decode}, - [0xd3] = {"st", four, reg, ext24_decode}, - [0xd4] = {"st", four, reg, ext24_decode}, - [0xd5] = {"st", four, reg, ext24_decode}, - [0xd6] = {"st", four, reg, ext24_decode}, - [0xd7] = {"st", four, reg, ext24_decode}, - [0xd8] = {"st", four, reg_xy, ext24_decode}, - [0xd9] = {"st", four, reg_xy, ext24_decode}, - [0xda] = {"ld", three, reg_xy, ld_18bit_decode}, - [0xdb] = {"ld", three, reg_xy, ld_18bit_decode}, - [0xdc] = {"neg.b", opr_n_bytes_p1, NULL, opr_decode}, - [0xdd] = {"neg.w", opr_n_bytes_p1, NULL, opr_decode}, - [0xde] = {"orcc", two, imm1, 0}, - [0xdf] = {"neg.l", opr_n_bytes_p1, NULL, opr_decode}, - [0xe0] = {"cmp", three, reg, imm1234_0base}, - [0xe1] = {"cmp", three, reg, imm1234_0base}, - [0xe2] = {"cmp", three, reg, imm1234_0base}, - [0xe3] = {"cmp", three, reg, imm1234_0base}, - [0xe4] = {"cmp", two, reg, imm1234_0base}, - [0xe5] = {"cmp", two, reg, imm1234_0base}, - [0xe6] = {"cmp", five, reg, imm1234_0base}, - [0xe7] = {"cmp", five, reg, imm1234_0base}, - [0xe8] = {"cmp", four, reg_xy, imm1234_0base}, - [0xe9] = {"cmp", four, reg_xy, imm1234_0base}, - [0xea] = {"ld", three, reg_xy, ld_18bit_decode}, - [0xeb] = {"ld", three, reg_xy, ld_18bit_decode}, - [0xec] = {"bclr", bm_n_bytes, bm_decode, 0}, - [0xed] = {"bset", bm_n_bytes, bm_decode, 0}, - [0xee] = {"btgl", bm_n_bytes, bm_decode, 0}, - [0xef] = {"!!invalid!!", NULL, NULL, NULL}, /* SPARE */ - [0xf0] = {"cmp", opr_n_bytes_p1, reg, opr_decode}, - [0xf1] = {"cmp", opr_n_bytes_p1, reg, opr_decode}, - [0xf2] = {"cmp", opr_n_bytes_p1, reg, opr_decode}, - [0xf3] = {"cmp", opr_n_bytes_p1, reg, opr_decode}, - [0xf4] = {"cmp", opr_n_bytes_p1, reg, opr_decode}, - [0xf5] = {"cmp", opr_n_bytes_p1, reg, opr_decode}, - [0xf6] = {"cmp", opr_n_bytes_p1, reg, opr_decode}, - [0xf7] = {"cmp", opr_n_bytes_p1, reg, opr_decode}, - [0xf8] = {"cmp", opr_n_bytes_p1, reg_xy, opr_decode}, - [0xf9] = {"cmp", opr_n_bytes_p1, reg_xy, opr_decode}, - [0xfa] = {"ld", three, reg_xy, ld_18bit_decode}, - [0xfb] = {"ld", three, reg_xy, ld_18bit_decode}, - [0xfc] = {"cmp", single, cmp_xy, 0}, - [0xfd] = {"sub", single, sub_d6_x_y, 0}, - [0xfe] = {"sub", single, sub_d6_y_x, 0}, - [0xff] = {"swi", single, 0, 0} - }; - - -static const char *oprregs1[] = - { - "d3", "d2", "d1", "d0", "ccl", "cch" - }; - -static const char *oprregs2[] = - { - "y", "x", "d7", "d6", "d5", "d4" - }; - - - - -enum MUL_MODE - { - MUL_REG_REG, - MUL_REG_OPR, - MUL_REG_IMM, - MUL_OPR_OPR - }; - -struct mb -{ - uint8_t mask; - uint8_t value; - enum MUL_MODE mode; -}; - -static const struct mb mul_table[] = { - {0x40, 0x00, MUL_REG_REG}, - - {0x47, 0x40, MUL_REG_OPR}, - {0x47, 0x41, MUL_REG_OPR}, - {0x47, 0x43, MUL_REG_OPR}, - - {0x47, 0x44, MUL_REG_IMM}, - {0x47, 0x45, MUL_REG_IMM}, - {0x47, 0x47, MUL_REG_IMM}, - - {0x43, 0x42, MUL_OPR_OPR}, -}; - -static void -mul_decode (bfd_vma memaddr, struct disassemble_info* info) -{ - uint8_t mb; - int status = read_memory (memaddr, &mb, 1, info); - if (status < 0) - return; - - - uint8_t byte; - status = read_memory (memaddr - 1, &byte, 1, info); - if (status < 0) - return; - - (*info->fprintf_func) (info->stream, "%c", (mb & 0x80) ? 's' : 'u'); - - enum MUL_MODE mode = -1; - size_t i; - for (i = 0; i < sizeof (mul_table) / sizeof (mul_table[0]); ++i) - { - const struct mb *mm = mul_table + i; - if ((mb & mm->mask) == mm->value) - { - mode = mm->mode; - break; - } - } - - switch (mode) - { - case MUL_REG_REG: - break; - case MUL_OPR_OPR: - { - int size1 = (mb & 0x30) >> 4; - int size2 = (mb & 0x0c) >> 2; - (*info->fprintf_func) (info->stream, ".%c%c", - shift_size_table [size1], - shift_size_table [size2]); - } - break; - default: - { - int size = (mb & 0x3); - (*info->fprintf_func) (info->stream, ".%c", shift_size_table [size]); - } - break; - } - - operand_separator (info); - (*info->fprintf_func) (info->stream, "%s", registers[byte & 0x7].name); - - switch (mode) - { - case MUL_REG_REG: - case MUL_REG_IMM: - case MUL_REG_OPR: - operand_separator (info); - (*info->fprintf_func) (info->stream, "%s", registers[(mb & 0x38) >> 3].name); - break; - default: - break; - } - - switch (mode) - { - case MUL_REG_IMM: - operand_separator (info); - int size = (mb & 0x3); - uint32_t imm = decode_signed_value (memaddr + 1, info, size + 1); - (*info->fprintf_func) (info->stream, "#%d", imm); - break; - case MUL_REG_REG: - operand_separator (info); - (*info->fprintf_func) (info->stream, "%s", registers[mb & 0x07].name); - break; - case MUL_REG_OPR: - opr_decode (memaddr + 1, info); - break; - case MUL_OPR_OPR: - { - int first = opr_n_bytes (memaddr + 1, info); - opr_decode (memaddr + 1, info); - opr_decode (memaddr + first + 1, info); - break; - } - } -} - - -static int -mul_n_bytes (bfd_vma memaddr, struct disassemble_info* info) -{ - int nx = 2; - uint8_t mb; - int status = read_memory (memaddr, &mb, 1, info); - if (status < 0) - return 0; - - enum MUL_MODE mode = -1; - size_t i; - for (i = 0; i < sizeof (mul_table) / sizeof (mul_table[0]); ++i) - { - const struct mb *mm = mul_table + i; - if ((mb & mm->mask) == mm->value) - { - mode = mm->mode; - break; - } - } - - int size = (mb & 0x3) + 1; - - switch (mode) - { - case MUL_REG_IMM: - nx += size; - break; - case MUL_REG_REG: - break; - case MUL_REG_OPR: - nx += opr_n_bytes (memaddr + 1, info); + case OPND_CL_IMMEDIATE: + (*info->fprintf_func) (info->stream, "#%d", + ((struct immediate_operand *) opr)->value); break; - case MUL_OPR_OPR: + case OPND_CL_REGISTER: { - int first = opr_n_bytes (memaddr + nx - 1, info); - nx += first; - int second = opr_n_bytes (memaddr + nx - 1, info); - nx += second; + int r = ((struct register_operand*) opr)->reg; + (*info->fprintf_func) (info->stream, "%s", registers[r].name); } break; - } - - return nx; -} - - - /* The NXP documentation is vague about BM_RESERVED0 and BM_RESERVED1, - and contains obvious typos. - However the Freescale tools and experiments with the chip itself - seem to indicate that they behave like BM_REG_IMM and BM_OPR_REG - respectively. */ - -enum BM_MODE { - BM_REG_IMM, - BM_RESERVED0, - BM_OPR_B, - BM_OPR_W, - BM_OPR_L, - BM_OPR_REG, - BM_RESERVED1 -}; - -struct bm -{ - uint8_t mask; - uint8_t value; - enum BM_MODE mode; -}; - -static const struct bm bm_table[] = { - { 0xC6, 0x04, BM_REG_IMM}, - { 0x84, 0x00, BM_REG_IMM}, - { 0x06, 0x06, BM_REG_IMM}, - { 0xC6, 0x44, BM_RESERVED0}, - // 00 - { 0x8F, 0x80, BM_OPR_B}, - { 0x8E, 0x82, BM_OPR_W}, - { 0x8C, 0x88, BM_OPR_L}, - - { 0x83, 0x81, BM_OPR_REG}, - { 0x87, 0x84, BM_RESERVED1}, -}; - -static void -bm_decode (bfd_vma memaddr, struct disassemble_info* info) -{ - uint8_t bm; - int status = read_memory (memaddr, &bm, 1, info); - if (status < 0) - return; - - size_t i; - enum BM_MODE mode = -1; - for (i = 0; i < sizeof (bm_table) / sizeof (bm_table[0]); ++i) - { - const struct bm *bme = bm_table + i; - if ((bm & bme->mask) == bme->value) - { - mode = bme->mode; - break; - } - } - - switch (mode) - { - case BM_REG_IMM: - case BM_RESERVED0: - operand_separator (info); - (*info->fprintf_func) (info->stream, "%s", registers[bm & 0x07].name); - break; - case BM_OPR_B: - (*info->fprintf_func) (info->stream, ".%c", 'b'); - opr_decode (memaddr + 1, info); + case OPND_CL_REGISTER_ALL16: + (*info->fprintf_func) (info->stream, "%s", "ALL16b"); break; - case BM_OPR_W: - (*info->fprintf_func) (info->stream, ".%c", 'w'); - opr_decode (memaddr + 1, info); + case OPND_CL_REGISTER_ALL: + (*info->fprintf_func) (info->stream, "%s", "ALL"); break; - case BM_OPR_L: - (*info->fprintf_func) (info->stream, ".%c", 'l'); - opr_decode (memaddr + 1, info); + case OPND_CL_BIT_FIELD: + (*info->fprintf_func) (info->stream, "#%d:%d", + ((struct bitfield_operand*)opr)->width, + ((struct bitfield_operand*)opr)->offset); break; - case BM_OPR_REG: - case BM_RESERVED1: + case OPND_CL_SIMPLE_MEMORY: { - uint8_t xb; - read_memory (memaddr + 1, &xb, 1, info); - /* Don't emit a size suffix for register operands */ - if ((xb & 0xF8) != 0xB8) - (*info->fprintf_func) (info->stream, ".%c", shift_size_table[(bm & 0x0c) >> 2]); - opr_decode (memaddr + 1, info); + struct simple_memory_operand *mo = + (struct simple_memory_operand *) opr; + decode_possible_symbol (mo->addr, mo->base, info, mo->relative); } break; - } - - uint8_t imm = 0; - operand_separator (info); - switch (mode) - { - case BM_REG_IMM: + case OPND_CL_MEMORY: { - imm = (bm & 0x38) >> 3; - (*info->fprintf_func) (info->stream, "#%d", imm); - } - break; - case BM_OPR_L: - imm |= (bm & 0x03) << 3; - /* fallthrough */ - case BM_OPR_W: - imm |= (bm & 0x01) << 3; - /* fallthrough */ - case BM_OPR_B: - imm |= (bm & 0x70) >> 4; - (*info->fprintf_func) (info->stream, "#%d", imm); - break; - case BM_OPR_REG: - case BM_RESERVED1: - (*info->fprintf_func) (info->stream, "%s", registers[(bm & 0x70) >> 4].name); - break; - case BM_RESERVED0: - assert (0); - break; - } -} - - -static void -bm_rel_decode (bfd_vma memaddr, struct disassemble_info* info) -{ - uint8_t bm; - int status = read_memory (memaddr, &bm, 1, info); - if (status < 0) - return; + int used_reg = 0; + struct memory_operand *mo = (struct memory_operand *) opr; + (*info->fprintf_func) (info->stream, "%c", mo->indirect ? '[' : '('); - size_t i; - enum BM_MODE mode = -1; - for (i = 0; i < sizeof (bm_table) / sizeof (bm_table[0]); ++i) - { - const struct bm *bme = bm_table + i; - if ((bm & bme->mask) == bme->value) - { - mode = bme->mode; - break; - } - } - - switch (mode) - { - case BM_REG_IMM: - case BM_RESERVED0: - break; - case BM_OPR_B: - (*info->fprintf_func) (info->stream, ".%c", 'b'); - break; - case BM_OPR_W: - (*info->fprintf_func) (info->stream, ".%c", 'w'); - break; - case BM_OPR_L: - (*info->fprintf_func) (info->stream, ".%c", 'l'); - break; - case BM_OPR_REG: - case BM_RESERVED1: - { - uint8_t xb; - read_memory (memaddr + 1, &xb, 1, info); - /* Don't emit a size suffix for register operands */ - if ((xb & 0xF8) != 0xB8) - (*info->fprintf_func) (info->stream, ".%c", - shift_size_table[(bm & 0x0C) >> 2]); - } - break; - } - - int n = 1; - switch (mode) - { - case BM_REG_IMM: - case BM_RESERVED0: - operand_separator (info); - (*info->fprintf_func) (info->stream, "%s", registers[bm & 0x07].name); - break; - case BM_OPR_B: - case BM_OPR_W: - case BM_OPR_L: - opr_decode (memaddr + 1, info); - n = 1 + opr_n_bytes (memaddr + 1, info); - break; - case BM_OPR_REG: - case BM_RESERVED1: - opr_decode (memaddr + 1, info); - break; - } - - - int imm = 0; - operand_separator (info); - switch (mode) - { - case BM_OPR_L: - imm |= (bm & 0x02) << 3; - /* fall through */ - case BM_OPR_W: - imm |= (bm & 0x01) << 3; - /* fall through */ - case BM_OPR_B: - imm |= (bm & 0x70) >> 4; - (*info->fprintf_func) (info->stream, "#%d", imm); - break; - case BM_RESERVED0: - imm = (bm & 0x38) >> 3; - (*info->fprintf_func) (info->stream, "#%d", imm); - break; - case BM_REG_IMM: - imm = (bm & 0xF8) >> 3; - (*info->fprintf_func) (info->stream, "#%d", imm); - break; - case BM_OPR_REG: - case BM_RESERVED1: - (*info->fprintf_func) (info->stream, "%s", registers[(bm & 0x70) >> 4].name); - n += opr_n_bytes (memaddr + 1, info); - break; - } - - rel_15_7 (memaddr + n, info, n + 1); -} - -static int -bm_n_bytes (bfd_vma memaddr, struct disassemble_info* info) -{ - uint8_t bm; - int status = read_memory (memaddr, &bm, 1, info); - if (status < 0) - return status; - - size_t i; - enum BM_MODE mode = -1; - for (i = 0; i < sizeof (bm_table) / sizeof (bm_table[0]); ++i) - { - const struct bm *bme = bm_table + i; - if ((bm & bme->mask) == bme->value) - { - mode = bme->mode; - break; - } - } - - int n = 2; - switch (mode) - { - case BM_REG_IMM: - case BM_RESERVED0: - break; - - case BM_OPR_B: - case BM_OPR_W: - case BM_OPR_L: - n += opr_n_bytes (memaddr + 1, info); - break; - case BM_OPR_REG: - case BM_RESERVED1: - n += opr_n_bytes (memaddr + 1, info); - break; - } - - return n; -} - -static int -bm_rel_n_bytes (bfd_vma memaddr, struct disassemble_info* info) -{ - int n = 1 + bm_n_bytes (memaddr, info); - - bfd_byte rb; - int status = read_memory (memaddr + n - 2, &rb, 1, info); - if (status != 0) - return status; - - if (rb & 0x80) - n++; - - return n; -} - - - - - -/* shift direction */ -enum SB_DIR - { - SB_LEFT, - SB_RIGHT - }; - -enum SB_TYPE - { - SB_ARITHMETIC, - SB_LOGICAL - }; - - -enum SB_MODE - { - SB_REG_REG_N_EFF, - SB_REG_REG_N, - SB_REG_OPR_EFF, - SB_ROT, - SB_REG_OPR_OPR, - SB_OPR_N - }; - -struct sb -{ - uint8_t mask; - uint8_t value; - enum SB_MODE mode; -}; - -static const struct sb sb_table[] = { - {0x30, 0x00, SB_REG_REG_N_EFF}, - {0x30, 0x10, SB_REG_REG_N}, - {0x34, 0x20, SB_REG_OPR_EFF}, - {0x34, 0x24, SB_ROT}, - {0x34, 0x30, SB_REG_OPR_OPR}, - {0x34, 0x34, SB_OPR_N}, -}; - -static int -shift_n_bytes (bfd_vma memaddr, struct disassemble_info* info) -{ - bfd_byte sb; - int status = read_memory (memaddr++, &sb, 1, info); - if (status != 0) - return status; - - size_t i; - enum SB_MODE mode = -1; - for (i = 0; i < sizeof (sb_table) / sizeof (sb_table[0]); ++i) - { - const struct sb *sbe = sb_table + i; - if ((sb & sbe->mask) == sbe->value) - mode = sbe->mode; - } - - switch (mode) - { - case SB_REG_REG_N_EFF: - return 2; - break; - case SB_REG_OPR_EFF: - case SB_ROT: - return 2 + opr_n_bytes (memaddr, info); - break; - case SB_REG_OPR_OPR: - { - int opr1 = opr_n_bytes (memaddr, info); - int opr2 = 0; - if ((sb & 0x30) != 0x20) - opr2 = opr_n_bytes (memaddr + opr1, info); - return 2 + opr1 + opr2; - } - break; - default: - return 3; - } - - /* not reached */ - return -1; -} - - -static int -mov_imm_opr_n_bytes (bfd_vma memaddr, struct disassemble_info* info) -{ - bfd_byte byte; - int status = read_memory (memaddr - 1, &byte, 1, info); - if (status < 0) - return status; - - int size = byte - 0x0c + 1; - - return size + opr_n_bytes (memaddr + size, info) + 1; -} - -static void -mov_imm_opr (bfd_vma memaddr, struct disassemble_info* info) -{ - bfd_byte byte; - int status = read_memory (memaddr - 1, &byte, 1, info); - if (status < 0) - return ; - - int size = byte - 0x0c + 1; - uint32_t imm = decode_signed_value (memaddr, info, size); - - operand_separator (info); - (*info->fprintf_func) (info->stream, "#%d", imm); - opr_decode (memaddr + size, info); -} - - - -static void -ld_18bit_decode (bfd_vma memaddr, struct disassemble_info* info) -{ - size_t size = 3; - bfd_byte buffer[3]; - int status = read_memory (memaddr, buffer + 1, 2, info); - if (status < 0) - return ; - - - status = read_memory (memaddr - 1, buffer, 1, info); - if (status < 0) - return ; - - buffer[0] = (buffer[0] & 0x30) >> 4; - - size_t i; - uint32_t imm = 0; - for (i = 0; i < size; ++i) - { - imm |= buffer[i] << (8 * (size - i - 1)); - } - - operand_separator (info); - (*info->fprintf_func) (info->stream, "#%d", imm); -} - - - -/* Loop Primitives */ - -enum LP_MODE { - LP_REG, - LP_XY, - LP_OPR -}; - -struct lp -{ - uint8_t mask; - uint8_t value; - enum LP_MODE mode; -}; - -static const struct lp lp_mode[] = { - {0x08, 0x00, LP_REG}, - {0x0C, 0x08, LP_XY}, - {0x0C, 0x0C, LP_OPR}, -}; - - -static const char *lb_condition[] = - { - "ne", "eq", "pl", "mi", "gt", "le", - "??", "??" - }; - -static int -loop_prim_n_bytes (bfd_vma memaddr, struct disassemble_info* info) -{ - int mx = 0; - uint8_t lb; - read_memory (memaddr + mx++, &lb, 1, info); - - enum LP_MODE mode = -1; - size_t i; - for (i = 0; i < sizeof (lp_mode) / sizeof (lp_mode[0]); ++i) - { - const struct lp *pb = lp_mode + i; - if ((lb & pb->mask) == pb->value) - { - mode = pb->mode; - break; - } - } - - if (mode == LP_OPR) - { - mx += opr_n_bytes (memaddr + mx, info) ; - } - - uint8_t rb; - read_memory (memaddr + mx++, &rb, 1, info); - if (rb & 0x80) - mx++; - - return mx + 1; -} - - - - -static int -print_insn_exg_sex (bfd_vma memaddr, struct disassemble_info* info) -{ - uint8_t eb; - int status = read_memory (memaddr, &eb, 1, info); - if (status < 0) - return -1; - - const struct reg *first = ®isters[(eb & 0xf0) >> 4]; - const struct reg *second = ®isters[(eb & 0xf)]; - - if (first->bytes < second->bytes) - (*info->fprintf_func) (info->stream, "sex"); - else - (*info->fprintf_func) (info->stream, "exg"); - - operand_separator (info); - (*info->fprintf_func) (info->stream, "%s", first->name); - operand_separator (info); - (*info->fprintf_func) (info->stream, "%s", second->name); - return 0; -} - - - -static int -print_insn_loop_primitive (bfd_vma memaddr, struct disassemble_info* info) -{ - int offs = 1; - uint8_t lb; - int status = read_memory (memaddr, &lb, 1, info); - - char mnemonic[7]; - int x = 0; - mnemonic[x++] = (lb & 0x80) ? 'd' : 't'; - mnemonic[x++] = 'b'; - stpcpy (mnemonic + x, lb_condition [(lb & 0x70) >> 4]); - x += 2; - - const char *reg_dxy = NULL; - enum LP_MODE mode = -1; - size_t i; - for (i = 0; i < sizeof (lp_mode) / sizeof (lp_mode[0]); ++i) - { - const struct lp *pb = lp_mode + i; - if ((lb & pb->mask) == pb->value) - { - mode = pb->mode; - break; - } - } - - switch (mode) - { - case LP_REG: - reg_dxy = registers [lb & 0x07].name; - break; - case LP_XY: - reg_dxy = (lb & 0x1) ? "y" : "x"; - break; - case LP_OPR: - mnemonic[x++] = '.'; - mnemonic[x++] = shift_size_table [lb & 0x03]; - offs += opr_n_bytes (memaddr + 1, info); - break; - } - - mnemonic[x++] = '\0'; - - (*info->fprintf_func) (info->stream, "%s", mnemonic); - - if (mode == LP_OPR) - opr_decode (memaddr + 1, info); - else - { - operand_separator (info); - (*info->fprintf_func) (info->stream, "%s", reg_dxy); - } - - rel_15_7 (memaddr + offs, info, offs + 1); - - return status; -} - - -static int -print_insn_shift (bfd_vma memaddr, struct disassemble_info* info, uint8_t byte) -{ - size_t i; - uint8_t sb; - int status = read_memory (memaddr, &sb, 1, info); - if (status < 0) - return status; - - enum SB_DIR dir = (sb & 0x40) ? SB_LEFT : SB_RIGHT; - enum SB_TYPE type = (sb & 0x80) ? SB_ARITHMETIC : SB_LOGICAL; - enum SB_MODE mode = -1; - for (i = 0; i < sizeof (sb_table) / sizeof (sb_table[0]); ++i) - { - const struct sb *sbe = sb_table + i; - if ((sb & sbe->mask) == sbe->value) - mode = sbe->mode; - } - - char mnemonic[6]; - int x = 0; - if (mode == SB_ROT) - { - mnemonic[x++] = 'r'; - mnemonic[x++] = 'o'; - } - else - { - mnemonic[x++] = (type == SB_LOGICAL) ? 'l' : 'a'; - mnemonic[x++] = 's'; - } - - mnemonic[x++] = (dir == SB_LEFT) ? 'l' : 'r'; - - switch (mode) - { - case SB_REG_OPR_EFF: - case SB_ROT: - case SB_REG_OPR_OPR: - mnemonic[x++] = '.'; - mnemonic[x++] = shift_size_table[sb & 0x03]; - break; - case SB_OPR_N: - { - uint8_t xb; - read_memory (memaddr + 1, &xb, 1, info); - /* The size suffix is not printed if the OPR operand refers - directly to a register, because the size is implied by the - size of that register. */ - if ((xb & 0xF8) != 0xB8) - { - mnemonic[x++] = '.'; - mnemonic[x++] = shift_size_table[sb & 0x03]; - } - } - break; - default: - break; - }; - - mnemonic[x++] = '\0'; - - (*info->fprintf_func) (info->stream, "%s", mnemonic); - - /* Destination register */ - switch (mode) - { - case SB_REG_REG_N_EFF: - case SB_REG_REG_N: - case SB_REG_OPR_EFF: - case SB_REG_OPR_OPR: - operand_separator (info); - (*info->fprintf_func) (info->stream, "%s", registers[byte & 0x7].name); - break; - - case SB_ROT: - opr_decode (memaddr + 1, info); - break; - - default: - break; - } - - /* Source register */ - switch (mode) - { - case SB_REG_REG_N_EFF: - case SB_REG_REG_N: - operand_separator (info); - (*info->fprintf_func) (info->stream, "%s", registers[sb & 0x7].name); - break; - - case SB_REG_OPR_OPR: - opr_decode (memaddr + 1, info); - break; - - default: - break; - } - - /* 3rd arg */ - switch (mode) - { - case SB_REG_OPR_EFF: - case SB_OPR_N: - opr_decode (memaddr + 1, info); - break; - - case SB_REG_REG_N: - { - uint8_t xb; - read_memory (memaddr + 1, &xb, 1, info); - /* This case is slightly unusual. - If XB matches the binary pattern 0111XXXX, then instead of - interpreting this as a general OPR postbyte in the IMMe4 mode, - the XB byte is interpreted in s special way. */ - if ((xb & 0xF0) == 0x70) + if (mo->base_offset != 0) { - operand_separator (info); - if (byte & 0x10) - { - int shift = ((sb & 0x08) >> 3) | ((xb & 0x0f) << 1); - (*info->fprintf_func) (info->stream, "#%d", shift); - } - else - { - (*info->fprintf_func) (info->stream, "%s:%d", __FILE__, __LINE__); - } + (*info->fprintf_func) (info->stream, "%d", mo->base_offset); } - else + else if (mo->n_regs > 0) { - opr_decode (memaddr + 1, info); + const char *fmt; + switch (mo->mutation) + { + case OPND_RM_PRE_DEC: + fmt = "-%s"; + break; + case OPND_RM_PRE_INC: + fmt = "+%s"; + break; + case OPND_RM_POST_DEC: + fmt = "%s-"; + break; + case OPND_RM_POST_INC: + fmt = "%s+"; + break; + case OPND_RM_NONE: + default: + fmt = "%s"; + break; + } + (*info->fprintf_func) (info->stream, fmt, + registers[mo->regs[0]].name); + used_reg = 1; } - } - break; - case SB_REG_OPR_OPR: - { - uint8_t xb; - int n = opr_n_bytes (memaddr + 1, info); - read_memory (memaddr + 1 + n, &xb, 1, info); - if ((xb & 0xF0) == 0x70) - { - int imm = xb & 0x0F; - imm <<= 1; - imm |= (sb & 0x08) >> 3; - operand_separator (info); - (*info->fprintf_func) (info->stream, "#%d", imm); - } - else - { - opr_decode (memaddr + 1 + n, info); - } - } - break; - default: - break; - } - - switch (mode) - { - case SB_REG_REG_N_EFF: - case SB_REG_OPR_EFF: - case SB_OPR_N: - operand_separator (info); - (*info->fprintf_func) (info->stream, "#%d", - (sb & 0x08) ? 2 : 1); - break; + if (mo->n_regs > used_reg) + { + (*info->fprintf_func) (info->stream, ",%s", + registers[mo->regs[used_reg]].name); + } - default: + (*info->fprintf_func) (info->stream, "%c", + mo->indirect ? ']' : ')'); + } break; - } - - return 0; + }; } +static const char shift_size_table[] = { + 'b', 'w', 'p', 'l' +}; + int print_insn_s12z (bfd_vma memaddr, struct disassemble_info* info) { - bfd_byte byte; - int status = read_memory (memaddr++, &byte, 1, info); - if (status != 0) - return status; - - const struct opcode *opc2 = NULL; - const struct opcode *opc = page1 + byte; - if (opc->mnemonic) - { - (*info->fprintf_func) (info->stream, "%s", opc->mnemonic); - } - else - { - /* The special cases ... */ - switch (byte) + int o; + enum operator operator = OP_INVALID; + int n_operands = 0; + + /* The longest instruction in S12Z can have 6 operands. + (Most have 3 or less. Only PSH and PUL have so many. */ + struct operand *operands[6]; + + struct mem_read_abstraction mra; + mra.base.read = (void *) abstract_read_memory ; + mra.base.advance = advance ; + mra.base.posn = posn; + mra.memaddr = memaddr; + mra.info = info; + + short osize = -1; + int n_bytes = + decode_s12z (&operator, &osize, &n_operands, operands, + (struct mem_read_abstraction_base *) &mra); + + (info->fprintf_func) (info->stream, "%s", mnemonics[(long)operator]); + + /* Ship out size sufficies for those instructions which + need them. */ + if (osize == -1) + { + bool suffix = false; + for (o = 0; o < n_operands; ++o) { - case PAGE2_PREBYTE: - { - bfd_byte byte2; - read_memory (memaddr++, &byte2, 1, info); - opc2 = page2 + byte2; - if (opc2->mnemonic) - { - (*info->fprintf_func) (info->stream, "%s", opc2->mnemonic); - - if (opc2->operands) - { - opc2->operands (memaddr, info); - } - - if (opc2->operands2) - { - opc2->operands2 (memaddr, info); - } - } - else if (byte2 >= 0x08 && byte2 <= 0x1F) - { - bfd_byte bb; - read_memory (memaddr, &bb, 1, info); - if (bb & 0x80) - (*info->fprintf_func) (info->stream, "bfins"); - else - (*info->fprintf_func) (info->stream, "bfext"); - - enum BB_MODE mode = -1; - size_t i; - const struct opr_bb *bbs = 0; - for (i = 0; i < sizeof (bb_modes) / sizeof (bb_modes[0]); ++i) - { - bbs = bb_modes + i; - if ((bb & bbs->mask) == bbs->value) - { - mode = bbs->mode; - break; - } - } - - switch (mode) - { - case BB_REG_OPR_REG: - case BB_REG_OPR_IMM: - case BB_OPR_REG_REG: - case BB_OPR_REG_IMM: - { - int size = (bb >> 2) & 0x03; - (*info->fprintf_func) (info->stream, ".%c", - shift_size_table [size]); - } - break; - default: - break; - } - - int reg1 = byte2 & 0x07; - /* First operand */ - switch (mode) - { - case BB_REG_REG_REG: - case BB_REG_REG_IMM: - case BB_REG_OPR_REG: - case BB_REG_OPR_IMM: - operand_separator (info); - (*info->fprintf_func) (info->stream, "%s", - registers[reg1].name); - break; - case BB_OPR_REG_REG: - opr_decode (memaddr + 1, info); - break; - case BB_OPR_REG_IMM: - opr_decode (memaddr + 2, info); - break; - } - - /* Second operand */ - switch (mode) - { - case BB_REG_REG_REG: - case BB_REG_REG_IMM: - { - int reg_src = (bb >> 2) & 0x07; - operand_separator (info); - (*info->fprintf_func) (info->stream, "%s", - registers[reg_src].name); - } - break; - case BB_OPR_REG_REG: - case BB_OPR_REG_IMM: - { - int reg_src = (byte2 & 0x07); - operand_separator (info); - (*info->fprintf_func) (info->stream, "%s", - registers[reg_src].name); - } - break; - case BB_REG_OPR_REG: - opr_decode (memaddr + 1, info); - break; - case BB_REG_OPR_IMM: - opr_decode (memaddr + 2, info); - break; - } - - /* Third operand */ - operand_separator (info); - switch (mode) - { - case BB_REG_REG_REG: - case BB_OPR_REG_REG: - case BB_REG_OPR_REG: - { - int reg_parm = bb & 0x03; - (*info->fprintf_func) (info->stream, "%s", - registers[reg_parm].name); - } - break; - case BB_REG_REG_IMM: - case BB_OPR_REG_IMM: - case BB_REG_OPR_IMM: - { - bfd_byte i1; - read_memory (memaddr + 1, &i1, 1, info); - int offset = i1 & 0x1f; - int width = bb & 0x03; - width <<= 3; - width |= i1 >> 5; - (*info->fprintf_func) (info->stream, "#%d:%d", width, offset); - } - break; - } - } - } - break; - case 0xae: /* EXG / SEX */ - status = print_insn_exg_sex (memaddr, info); - break; - case 0x0b: /* Loop Primitives TBcc and DBcc */ - status = print_insn_loop_primitive (memaddr, info); - break; - case 0x10: /* shift */ - case 0x11: /* shift */ - case 0x12: /* shift */ - case 0x13: /* shift */ - case 0x14: /* shift */ - case 0x15: /* shift */ - case 0x16: /* shift */ - case 0x17: /* shift */ - status = print_insn_shift (memaddr, info, byte); - break; - case 0x04: /* psh / pul */ - { - read_memory (memaddr, &byte, 1, info); - (*info->fprintf_func) (info->stream, (byte & 0x80) ? "pul" : "psh"); - int bit; - if (byte & 0x40) - { - if ((byte & 0x3F) == 0) - { - operand_separator (info); - (*info->fprintf_func) (info->stream, "%s", "ALL16b"); - } - else - for (bit = 5; bit >= 0; --bit) - { - if (byte & (0x1 << bit)) - { - operand_separator (info); - (*info->fprintf_func) (info->stream, "%s", oprregs2[bit]); - } - } - } - else - { - if ((byte & 0x3F) == 0) - { - operand_separator (info); - (*info->fprintf_func) (info->stream, "%s", "ALL"); - } - else - for (bit = 5; bit >= 0; --bit) - { - if (byte & (0x1 << bit)) - { - operand_separator (info); - (*info->fprintf_func) (info->stream, "%s", oprregs1[bit]); - } - } - } - } - break; - default: - operand_separator (info); - (*info->fprintf_func) (info->stream, "???"); - break; + if (operands[o]->osize != -1) + { + if (!suffix) + { + (*mra.info->fprintf_func) (mra.info->stream, "%c", '.'); + suffix = true; + } + (*mra.info->fprintf_func) (mra.info->stream, "%c", + shift_size_table[operands[o]->osize]); + } } } - - if (opc2 == NULL) + else { - if (opc->operands) - { - opc->operands (memaddr, info); - } - - if (opc->operands2) - { - opc->operands2 (memaddr, info); - } + (*mra.info->fprintf_func) (mra.info->stream, ".%c", + shift_size_table[osize]); } - int n = 0; - /* Opcodes in page2 have an additional byte */ - if (opc2) - n++; - - if (opc2 && opc2->insn_bytes == 0) - return n; - - if (!opc2 && opc->insn_bytes == 0) - return n; - - if (opc2) - n += opc2->insn_bytes (memaddr, info); - else - n += opc->insn_bytes (memaddr, info); + /* Ship out the operands. */ + for (o = 0; o < n_operands; ++o) + { + if (operands[o]) + opr_emit_disassembly (operands[o], mra.info); + free (operands[o]); + } - return n; + return n_bytes; } diff --git a/opcodes/s12z-opc.c b/opcodes/s12z-opc.c new file mode 100644 index 0000000..36509b5 --- /dev/null +++ b/opcodes/s12z-opc.c @@ -0,0 +1,2701 @@ +/* s12z-decode.c -- Freescale S12Z disassembly + Copyright (C) 2018 Free Software Foundation, Inc. + + This file is part of the GNU opcodes library. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + It is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "sysdep.h" +#include <stdio.h> +#include <stdint.h> +#include <stdbool.h> +#include <assert.h> + +#include "opcode/s12z.h" + +#include "bfd.h" + +#include "s12z-opc.h" + + +typedef int (* insn_bytes_f) (struct mem_read_abstraction_base *); + +typedef void (*operands_f) (struct mem_read_abstraction_base *, + int *n_operands, struct operand **operand); + +typedef enum operator (*discriminator_f) (struct mem_read_abstraction_base *, + enum operator hint); + +enum OPR_MODE + { + OPR_IMMe4, + OPR_REG, + OPR_OFXYS, + OPR_XY_PRE_INC, + OPR_XY_POST_INC, + OPR_XY_PRE_DEC, + OPR_XY_POST_DEC, + OPR_S_PRE_DEC, + OPR_S_POST_INC, + OPR_REG_DIRECT, + OPR_REG_INDIRECT, + OPR_IDX_DIRECT, + OPR_IDX_INDIRECT, + OPR_EXT1, + OPR_IDX2_REG, + OPR_IDX3_DIRECT, + OPR_IDX3_INDIRECT, + + OPR_EXT18, + OPR_IDX3_DIRECT_REG, + OPR_EXT3_DIRECT, + OPR_EXT3_INDIRECT + }; + +struct opr_pb +{ + uint8_t mask; + uint8_t value; + int n_operands; + enum OPR_MODE mode; +}; + +static const struct opr_pb opr_pb[] = { + {0xF0, 0x70, 1, OPR_IMMe4}, + {0xF8, 0xB8, 1, OPR_REG}, + {0xC0, 0x40, 1, OPR_OFXYS}, + {0xEF, 0xE3, 1, OPR_XY_PRE_INC}, + {0xEF, 0xE7, 1, OPR_XY_POST_INC}, + {0xEF, 0xC3, 1, OPR_XY_PRE_DEC}, + {0xEF, 0xC7, 1, OPR_XY_POST_DEC}, + {0xFF, 0xFB, 1, OPR_S_PRE_DEC}, + {0xFF, 0xFF, 1, OPR_S_POST_INC}, + {0xC8, 0x88, 1, OPR_REG_DIRECT}, + {0xE8, 0xC8, 1, OPR_REG_INDIRECT}, + + {0xCE, 0xC0, 2, OPR_IDX_DIRECT}, + {0xCE, 0xC4, 2, OPR_IDX_INDIRECT}, + {0xC0, 0x00, 2, OPR_EXT1}, + + {0xC8, 0x80, 3, OPR_IDX2_REG}, + {0xFA, 0xF8, 3, OPR_EXT18}, + + {0xCF, 0xC2, 4, OPR_IDX3_DIRECT}, + {0xCF, 0xC6, 4, OPR_IDX3_INDIRECT}, + + {0xF8, 0xE8, 4, OPR_IDX3_DIRECT_REG}, + {0xFF, 0xFA, 4, OPR_EXT3_DIRECT}, + {0xFF, 0xFE, 4, OPR_EXT3_INDIRECT}, +}; + +/* Return the number of bytes in a OPR operand, including the XB postbyte. + It does not include any preceeding opcodes. */ +static int +x_opr_n_bytes (struct mem_read_abstraction_base *mra, int offset) +{ + bfd_byte xb; + int status = mra->read (mra, offset, 1, &xb); + if (status < 0) + return status; + + size_t i; + for (i = 0; i < sizeof (opr_pb) / sizeof (opr_pb[0]); ++i) + { + const struct opr_pb *pb = opr_pb + i; + if ((xb & pb->mask) == pb->value) + { + return pb->n_operands; + } + } + + return 1; +} + +static int +opr_n_bytes_p1 (struct mem_read_abstraction_base *mra) +{ + return 1 + x_opr_n_bytes (mra, 0); +} + +static int +opr_n_bytes2 (struct mem_read_abstraction_base *mra) +{ + int s = x_opr_n_bytes (mra, 0); + s += x_opr_n_bytes (mra, s); + return s + 1; +} + +enum BB_MODE + { + BB_REG_REG_REG, + BB_REG_REG_IMM, + BB_REG_OPR_REG, + BB_OPR_REG_REG, + BB_REG_OPR_IMM, + BB_OPR_REG_IMM + }; + +struct opr_bb +{ + uint8_t mask; + uint8_t value; + int n_operands; + bool opr; + enum BB_MODE mode; +}; + +static const struct opr_bb bb_modes[] = + { + {0x60, 0x00, 2, false, BB_REG_REG_REG}, + {0x60, 0x20, 3, false, BB_REG_REG_IMM}, + {0x70, 0x40, 2, true, BB_REG_OPR_REG}, + {0x70, 0x50, 2, true, BB_OPR_REG_REG}, + {0x70, 0x60, 3, true, BB_REG_OPR_IMM}, + {0x70, 0x70, 3, true, BB_OPR_REG_IMM} + }; + +static int +bfextins_n_bytes (struct mem_read_abstraction_base *mra) +{ + bfd_byte bb; + int status = mra->read (mra, 0, 1, &bb); + if (status < 0) + return status; + + size_t i; + const struct opr_bb *bbs = 0; + for (i = 0; i < sizeof (bb_modes) / sizeof (bb_modes[0]); ++i) + { + bbs = bb_modes + i; + if ((bb & bbs->mask) == bbs->value) + { + break; + } + } + + int n = bbs->n_operands; + if (bbs->opr) + n += x_opr_n_bytes (mra, n - 1); + + return n; +} + +static int +single (struct mem_read_abstraction_base *mra ATTRIBUTE_UNUSED) +{ + return 1; +} + +static int +two (struct mem_read_abstraction_base *mra ATTRIBUTE_UNUSED) +{ + return 2; +} + +static int +three (struct mem_read_abstraction_base *mra ATTRIBUTE_UNUSED) +{ + return 3; +} + +static int +four (struct mem_read_abstraction_base *mra ATTRIBUTE_UNUSED) +{ + return 4; +} + +static int +five (struct mem_read_abstraction_base *mra ATTRIBUTE_UNUSED) +{ + return 5; +} + +static int +pcrel_15bit (struct mem_read_abstraction_base *mra) +{ + bfd_byte byte; + int status = mra->read (mra, 0, 1, &byte); + if (status < 0) + return status; + return (byte & 0x80) ? 3 : 2; +} + + + +static int +xysp_reg_from_postbyte (uint8_t postbyte) +{ + int reg = -1; + switch ((postbyte & 0x30) >> 4) + { + case 0: + reg = REG_X; + break; + case 1: + reg = REG_Y; + break; + case 2: + reg = REG_S; + break; + default: + reg = REG_P; + } + return reg; +} + +static struct operand * create_immediate_operand (int value) +{ + struct immediate_operand *op = malloc (sizeof (*op)); + + ((struct operand *)op)->cl = OPND_CL_IMMEDIATE; + op->value = value; + ((struct operand *)op)->osize = -1; + + return (struct operand *) op; +} + +static struct operand * create_bitfield_operand (int width, int offset) +{ + struct bitfield_operand *op = malloc (sizeof (*op)); + + ((struct operand *)op)->cl = OPND_CL_BIT_FIELD; + op->width = width; + op->offset = offset; + ((struct operand *)op)->osize = -1; + + return (struct operand *) op; +} + +static struct operand * +create_register_operand_with_size (int reg, short osize) +{ + struct register_operand *op = malloc (sizeof (*op)); + + ((struct operand *)op)->cl = OPND_CL_REGISTER; + op->reg = reg; + ((struct operand *)op)->osize = osize; + + return (struct operand *) op; +} + +static struct operand * +create_register_operand (int reg) +{ + return create_register_operand_with_size (reg, -1); +} + +static struct operand * create_register_all_operand (void) +{ + struct register_operand *op = malloc (sizeof (*op)); + + ((struct operand *)op)->cl = OPND_CL_REGISTER_ALL; + ((struct operand *)op)->osize = -1; + + return (struct operand *) op; +} + +static struct operand * create_register_all16_operand (void) +{ + struct register_operand *op = malloc (sizeof (*op)); + + ((struct operand *)op)->cl = OPND_CL_REGISTER_ALL16; + ((struct operand *)op)->osize = -1; + + return (struct operand *) op; +} + + +static struct operand * +create_simple_memory_operand (bfd_vma addr, bfd_vma base, bool relative) +{ + struct simple_memory_operand *op = malloc (sizeof (*op)); + + ((struct operand *)op)->cl = OPND_CL_SIMPLE_MEMORY; + op->addr = addr; + op->base = base; + op->relative = relative; + ((struct operand *)op)->osize = -1; + + assert (relative || base == 0); + + return (struct operand *) op; +} + +static struct operand * +create_memory_operand (bool indirect, int base, int n_regs, int reg0, int reg1) +{ + struct memory_operand *op = malloc (sizeof (*op)); + + ((struct operand *)op)->cl = OPND_CL_MEMORY; + op->indirect = indirect; + op->base_offset = base; + op->mutation = OPND_RM_NONE; + op->n_regs = n_regs; + op->regs[0] = reg0; + op->regs[1] = reg1; + ((struct operand *)op)->osize = -1; + + return (struct operand *) op; +} + +static struct operand * +create_memory_auto_operand (enum op_reg_mutation mutation, int reg) +{ + struct memory_operand *op = malloc (sizeof (*op)); + + ((struct operand *)op)->cl = OPND_CL_MEMORY; + op->indirect = false; + op->base_offset = 0; + op->mutation = mutation; + op->n_regs = 1; + op->regs[0] = reg; + op->regs[1] = -1; + ((struct operand *)op)->osize = -1; + + return (struct operand *) op; +} + + + +static void +z_ext24_decode (struct mem_read_abstraction_base *mra, int *n_operands, struct operand **operand) +{ + uint8_t buffer[3]; + int status = mra->read (mra, 0, 3, buffer); + if (status < 0) + return; + + int i; + uint32_t addr = 0; + for (i = 0; i < 3; ++i) + { + addr <<= 8; + addr |= buffer[i]; + } + + operand[(*n_operands)++] = create_simple_memory_operand (addr, 0, false); +} + + +static uint32_t +z_decode_signed_value (struct mem_read_abstraction_base *mra, int offset, short size) +{ + assert (size >0); + assert (size <= 4); + bfd_byte buffer[4]; + if (0 > mra->read (mra, offset, size, buffer)) + { + return 0; + } + + int i; + uint32_t value = 0; + for (i = 0; i < size; ++i) + { + value |= buffer[i] << (8 * (size - i - 1)); + } + + if (buffer[0] & 0x80) + { + /* Deal with negative values */ + value -= 0x1UL << (size * 8); + } + return value; +} + +static uint32_t +decode_signed_value (struct mem_read_abstraction_base *mra, short size) +{ + return z_decode_signed_value (mra, 0, size); +} + +static void +x_imm1 (struct mem_read_abstraction_base *mra, + int offset, + int *n_operands, struct operand **operand) +{ + bfd_byte byte; + int status = mra->read (mra, offset, 1, &byte); + if (status < 0) + return; + + operand[(*n_operands)++] = create_immediate_operand (byte); +} + +/* An eight bit immediate operand. */ +static void +imm1_decode (struct mem_read_abstraction_base *mra, + int *n_operands, struct operand **operand) +{ + x_imm1 (mra, 0, n_operands, operand); +} + +static void +trap_decode (struct mem_read_abstraction_base *mra, + int *n_operands, struct operand **operand) +{ + x_imm1 (mra, -1, n_operands, operand); +} + + +static struct operand * +x_opr_decode_with_size (struct mem_read_abstraction_base *mra, int offset, + short osize) +{ + bfd_byte postbyte; + int status = mra->read (mra, offset, 1, &postbyte); + if (status < 0) + return NULL; + offset++; + + enum OPR_MODE mode = -1; + size_t i; + for (i = 0; i < sizeof (opr_pb) / sizeof (opr_pb[0]); ++i) + { + const struct opr_pb *pb = opr_pb + i; + if ((postbyte & pb->mask) == pb->value) + { + mode = pb->mode; + break; + } + } + + struct operand *operand = NULL; + switch (mode) + { + case OPR_IMMe4: + { + int n; + uint8_t x = (postbyte & 0x0F); + if (x == 0) + n = -1; + else + n = x; + + operand = create_immediate_operand (n); + break; + } + case OPR_REG: + { + uint8_t x = (postbyte & 0x07); + operand = create_register_operand (x); + break; + } + case OPR_OFXYS: + { + operand = create_memory_operand (false, postbyte & 0x0F, 1, + xysp_reg_from_postbyte (postbyte), -1); + break; + } + case OPR_REG_DIRECT: + { + operand = create_memory_operand (false, 0, 2, postbyte & 0x07, + xysp_reg_from_postbyte (postbyte)); + break; + } + case OPR_REG_INDIRECT: + { + operand = create_memory_operand (true, 0, 2, postbyte & 0x07, + (postbyte & 0x10) ? REG_Y : REG_X); + break; + } + + case OPR_IDX_INDIRECT: + { + uint8_t x1; + mra->read (mra, offset, 1, &x1); + int idx = x1; + + if (postbyte & 0x01) + { + /* Deal with negative values */ + idx -= 0x1UL << 8; + } + + operand = create_memory_operand (true, idx, 1, + xysp_reg_from_postbyte (postbyte), -1); + break; + } + + case OPR_IDX3_DIRECT: + { + uint8_t x[3]; + mra->read (mra, offset, 3, x); + int idx = x[0] << 16 | x[1] << 8 | x[2]; + + if (x[0] & 0x80) + { + /* Deal with negative values */ + idx -= 0x1UL << 24; + } + + operand = create_memory_operand (false, idx, 1, + xysp_reg_from_postbyte (postbyte), -1); + break; + } + + case OPR_IDX3_DIRECT_REG: + { + uint8_t x[3]; + mra->read (mra, offset, 3, x); + int idx = x[0] << 16 | x[1] << 8 | x[2]; + + if (x[0] & 0x80) + { + /* Deal with negative values */ + idx -= 0x1UL << 24; + } + + operand = create_memory_operand (false, idx, 1, postbyte & 0x07, -1); + break; + } + + case OPR_IDX3_INDIRECT: + { + uint8_t x[3]; + mra->read (mra, offset, 3, x); + int idx = x[0] << 16 | x[1] << 8 | x[2]; + + if (x[0] & 0x80) + { + /* Deal with negative values */ + idx -= 0x1UL << 24; + } + + operand = create_memory_operand (true, idx, 1, + xysp_reg_from_postbyte (postbyte), -1); + break; + } + + case OPR_IDX_DIRECT: + { + uint8_t x1; + mra->read (mra, offset, 1, &x1); + int idx = x1; + + if (postbyte & 0x01) + { + /* Deal with negative values */ + idx -= 0x1UL << 8; + } + + operand = create_memory_operand (false, idx, 1, + xysp_reg_from_postbyte (postbyte), -1); + break; + } + + case OPR_IDX2_REG: + { + uint8_t x[2]; + mra->read (mra, offset, 2, x); + uint32_t idx = x[1] | x[0] << 8 ; + idx |= (postbyte & 0x30) << 12; + + operand = create_memory_operand (false, idx, 1, postbyte & 0x07, -1); + break; + } + + case OPR_XY_PRE_INC: + { + operand = create_memory_auto_operand (OPND_RM_PRE_INC, + (postbyte & 0x10) ? REG_Y: REG_X); + break; + } + case OPR_XY_POST_INC: + { + operand = create_memory_auto_operand (OPND_RM_POST_INC, + (postbyte & 0x10) ? REG_Y: REG_X); + break; + } + case OPR_XY_PRE_DEC: + { + operand = create_memory_auto_operand (OPND_RM_PRE_DEC, + (postbyte & 0x10) ? REG_Y: REG_X); + break; + } + case OPR_XY_POST_DEC: + { + operand = create_memory_auto_operand (OPND_RM_POST_DEC, + (postbyte & 0x10) ? REG_Y: REG_X); + break; + } + case OPR_S_PRE_DEC: + { + operand = create_memory_auto_operand (OPND_RM_PRE_DEC, REG_S); + break; + } + case OPR_S_POST_INC: + { + operand = create_memory_auto_operand (OPND_RM_POST_INC, REG_S); + break; + } + + case OPR_EXT18: + { + const size_t size = 2; + bfd_byte buffer[4]; + status = mra->read (mra, offset, size, buffer); + if (status < 0) + operand = NULL; + + uint32_t ext18 = 0; + for (i = 0; i < size; ++i) + { + ext18 <<= 8; + ext18 |= buffer[i]; + } + + ext18 |= (postbyte & 0x01) << 16; + ext18 |= (postbyte & 0x04) << 15; + + operand = create_simple_memory_operand (ext18, 0, false); + break; + } + + case OPR_EXT1: + { + uint8_t x1 = 0; + mra->read (mra, offset, 1, &x1); + int16_t addr; + addr = x1; + addr |= (postbyte & 0x3f) << 8; + + operand = create_simple_memory_operand (addr, 0, false); + break; + } + + case OPR_EXT3_DIRECT: + { + const size_t size = 3; + bfd_byte buffer[4]; + status = mra->read (mra, offset, size, buffer); + if (status < 0) + operand = NULL; + + uint32_t ext24 = 0; + for (i = 0; i < size; ++i) + { + ext24 |= buffer[i] << (8 * (size - i - 1)); + } + + operand = create_simple_memory_operand (ext24, 0, false); + break; + } + + case OPR_EXT3_INDIRECT: + { + const size_t size = 3; + bfd_byte buffer[4]; + status = mra->read (mra, offset, size, buffer); + if (status < 0) + operand = NULL; + + uint32_t ext24 = 0; + for (i = 0; i < size; ++i) + { + ext24 |= buffer[i] << (8 * (size - i - 1)); + } + + operand = create_memory_operand (true, ext24, 0, -1, -1); + break; + } + + default: + printf ("Unknown OPR mode #0x%x (%d)", postbyte, mode); + abort (); + } + + operand->osize = osize; + + return operand; +} + +static struct operand * +x_opr_decode (struct mem_read_abstraction_base *mra, int offset) +{ + return x_opr_decode_with_size (mra, offset, -1); +} + +static void +z_opr_decode (struct mem_read_abstraction_base *mra, + int *n_operands, struct operand **operand) +{ + operand[(*n_operands)++] = x_opr_decode (mra, 0); +} + +static void +z_opr_decode2 (struct mem_read_abstraction_base *mra, + int *n_operands, struct operand **operand) +{ + int n = x_opr_n_bytes (mra, 0); + + operand[(*n_operands)++] = x_opr_decode (mra, 0); + operand[(*n_operands)++] = x_opr_decode (mra, n); +} + +static void +imm1234 (struct mem_read_abstraction_base *mra, int base, + int *n_operands, struct operand **operand) +{ + bfd_byte opcode; + int status = mra->read (mra, -1, 1, &opcode); + if (status < 0) + return; + + opcode -= base; + + int size = registers[opcode & 0xF].bytes; + + uint32_t imm = decode_signed_value (mra, size); + + operand[(*n_operands)++] = create_immediate_operand (imm); +} + + +/* Special case of LD and CMP with register S and IMM operand */ +static void +reg_s_imm (struct mem_read_abstraction_base *mra, int *n_operands, + struct operand **operand) +{ + operand[(*n_operands)++] = create_register_operand (REG_S); + + uint32_t imm = decode_signed_value (mra, 3); + operand[(*n_operands)++] = create_immediate_operand (imm); +} + +/* Special case of LD, CMP and ST with register S and OPR operand */ +static void +reg_s_opr (struct mem_read_abstraction_base *mra, int *n_operands, + struct operand **operand) +{ + operand[(*n_operands)++] = create_register_operand (REG_S); + operand[(*n_operands)++] = x_opr_decode (mra, 0); +} + +static void +z_imm1234_8base (struct mem_read_abstraction_base *mra, int *n_operands, + struct operand **operand) +{ + imm1234 (mra, 8, n_operands, operand); +} + +static void +z_imm1234_0base (struct mem_read_abstraction_base *mra, int *n_operands, + struct operand **operand) +{ + imm1234 (mra, 0, n_operands, operand); +} + + +static void +z_tfr (struct mem_read_abstraction_base *mra, int *n_operands, + struct operand **operand) +{ + bfd_byte byte; + int status = mra->read (mra, 0, 1, &byte); + if (status < 0) + return; + + operand[(*n_operands)++] = create_register_operand (byte >> 4); + operand[(*n_operands)++] = create_register_operand (byte & 0x0F); +} + +static void +z_reg (struct mem_read_abstraction_base *mra, int *n_operands, + struct operand **operand) +{ + bfd_byte byte; + int status = mra->read (mra, -1, 1, &byte); + if (status < 0) + return; + + operand[(*n_operands)++] = create_register_operand (byte & 0x07); +} + + +static void +reg_xy (struct mem_read_abstraction_base *mra, + int *n_operands, struct operand **operand) +{ + bfd_byte byte; + int status = mra->read (mra, -1, 1, &byte); + if (status < 0) + return; + + operand[(*n_operands)++] = + create_register_operand ((byte & 0x01) ? REG_Y : REG_X); +} + +static void +lea_reg_xys_opr (struct mem_read_abstraction_base *mra, + int *n_operands, struct operand **operand) +{ + bfd_byte byte; + int status = mra->read (mra, -1, 1, &byte); + if (status < 0) + return; + + int reg_xys = -1; + switch (byte & 0x03) + { + case 0x00: + reg_xys = REG_X; + break; + case 0x01: + reg_xys = REG_Y; + break; + case 0x02: + reg_xys = REG_S; + break; + } + + operand[(*n_operands)++] = create_register_operand (reg_xys); + operand[(*n_operands)++] = x_opr_decode (mra, 0); +} + +static void +lea_reg_xys (struct mem_read_abstraction_base *mra, + int *n_operands, struct operand **operand) +{ + bfd_byte byte; + int status = mra->read (mra, -1, 1, &byte); + if (status < 0) + return; + + int reg_n = -1; + switch (byte & 0x03) + { + case 0x00: + reg_n = REG_X; + break; + case 0x01: + reg_n = REG_Y; + break; + case 0x02: + reg_n = REG_S; + break; + } + + status = mra->read (mra, 0, 1, &byte); + if (status < 0) + return; + + operand[(*n_operands)++] = create_register_operand (reg_n); + operand[(*n_operands)++] = create_memory_operand (false, (int8_t) byte, + 1, reg_n, -1); +} + + +/* PC Relative offsets of size 15 or 7 bits */ +static void +rel_15_7 (struct mem_read_abstraction_base *mra, int offset, + int *n_operands, struct operand **operands) +{ + bfd_byte upper; + int status = mra->read (mra, offset - 1, 1, &upper); + if (status < 0) + return; + + bool rel_size = (upper & 0x80); + + int16_t addr = upper; + if (rel_size) + { + /* 15 bits. Get the next byte */ + bfd_byte lower; + status = mra->read (mra, offset, 1, &lower); + if (status < 0) + return; + + addr <<= 8; + addr |= lower; + addr &= 0x7FFF; + + bool negative = (addr & 0x4000); + addr &= 0x3FFF; + if (negative) + addr = addr - 0x4000; + } + else + { + /* 7 bits. */ + bool negative = (addr & 0x40); + addr &= 0x3F; + if (negative) + addr = addr - 0x40; + } + + operands[(*n_operands)++] = + create_simple_memory_operand (addr, mra->posn (mra) - 1, true); +} + + +/* PC Relative offsets of size 15 or 7 bits */ +static void +decode_rel_15_7 (struct mem_read_abstraction_base *mra, + int *n_operands, struct operand **operand) +{ + rel_15_7 (mra, 1, n_operands, operand); +} + +static int shift_n_bytes (struct mem_read_abstraction_base *); +static int mov_imm_opr_n_bytes (struct mem_read_abstraction_base *); +static int loop_prim_n_bytes (struct mem_read_abstraction_base *); +static int bm_rel_n_bytes (struct mem_read_abstraction_base *); +static int mul_n_bytes (struct mem_read_abstraction_base *); +static int bm_n_bytes (struct mem_read_abstraction_base *); + +static void psh_pul_decode (struct mem_read_abstraction_base *mra, int *n_operands, struct operand **operand); +static void shift_decode (struct mem_read_abstraction_base *mra, int *n_operands, struct operand **operand); +static void mul_decode (struct mem_read_abstraction_base *mra, int *n_operands, struct operand **operand); +static void bm_decode (struct mem_read_abstraction_base *mra, int *n_operands, struct operand **operand); +static void bm_rel_decode (struct mem_read_abstraction_base *mra, int *n_operands, struct operand **operand); +static void mov_imm_opr (struct mem_read_abstraction_base *mra, int *n_operands, struct operand **operand); +static void loop_primitive_decode (struct mem_read_abstraction_base *mra, int *n_operands, struct operand **operands); +static void bit_field_decode (struct mem_read_abstraction_base *mra, int *n_operands, struct operand **operands); +static void exg_sex_decode (struct mem_read_abstraction_base *mra, int *n_operands, struct operand **operands); + + +static enum operator shift_discrim (struct mem_read_abstraction_base *mra, enum operator hint); +static enum operator psh_pul_discrim (struct mem_read_abstraction_base *mra, enum operator hint); +static enum operator mul_discrim (struct mem_read_abstraction_base *mra, enum operator hint); +static enum operator loop_primitive_discrim (struct mem_read_abstraction_base *mra, enum operator hint); +static enum operator bit_field_discrim (struct mem_read_abstraction_base *mra, enum operator hint); +static enum operator exg_sex_discrim (struct mem_read_abstraction_base *mra, enum operator hint); + + +static void +cmp_xy (struct mem_read_abstraction_base *mra ATTRIBUTE_UNUSED, + int *n_operands, struct operand **operand) +{ + operand[(*n_operands)++] = create_register_operand (REG_X); + operand[(*n_operands)++] = create_register_operand (REG_Y); +} + +static void +sub_d6_x_y (struct mem_read_abstraction_base *mra ATTRIBUTE_UNUSED, + int *n_operands, struct operand **operand) +{ + operand[(*n_operands)++] = create_register_operand (REG_D6); + operand[(*n_operands)++] = create_register_operand (REG_X); + operand[(*n_operands)++] = create_register_operand (REG_Y); +} + +static void +sub_d6_y_x (struct mem_read_abstraction_base *mra ATTRIBUTE_UNUSED, + int *n_operands, struct operand **operand) +{ + operand[(*n_operands)++] = create_register_operand (REG_D6); + operand[(*n_operands)++] = create_register_operand (REG_Y); + operand[(*n_operands)++] = create_register_operand (REG_X); +} + +static void ld_18bit_decode (struct mem_read_abstraction_base *mra, int *n_operands, struct operand **operand); + +static enum operator +mul_discrim (struct mem_read_abstraction_base *mra, enum operator hint) +{ + uint8_t mb; + int status = mra->read (mra, 0, 1, &mb); + if (status < 0) + return OP_INVALID; + + bool signed_op = (mb & 0x80); + + switch (hint) + { + case OPBASE_mul: + return signed_op ? OP_muls : OP_mulu; + break; + case OPBASE_div: + return signed_op ? OP_divs : OP_divu; + break; + case OPBASE_mod: + return signed_op ? OP_mods : OP_modu; + break; + case OPBASE_mac: + return signed_op ? OP_macs : OP_macu; + break; + case OPBASE_qmul: + return signed_op ? OP_qmuls : OP_qmulu; + break; + default: + abort (); + } + + return OP_INVALID; +} + +struct opcode +{ + /* The operation that this opcode performs. */ + enum operator operator; + + /* The size of this operation. May be -1 if it is implied + in the operands or if size is not applicable. */ + short osize; + + /* Some operations need this function to work out which operation + is intended. */ + discriminator_f discriminator; + + /* A function returning the number of bytes in this instruction. */ + insn_bytes_f insn_bytes; + + operands_f operands; + operands_f operands2; +}; + +static const struct opcode page2[] = + { + [0x00] = {OP_ld, -1, 0, opr_n_bytes_p1, reg_s_opr, 0}, + [0x01] = {OP_st, -1, 0, opr_n_bytes_p1, reg_s_opr, 0}, + [0x02] = {OP_cmp, -1, 0, opr_n_bytes_p1, reg_s_opr, 0}, + [0x03] = {OP_ld, -1, 0, four, reg_s_imm, 0}, + [0x04] = {OP_cmp, -1, 0, four, reg_s_imm, 0}, + [0x05] = {OP_stop, -1, 0, single, 0, 0}, + [0x06] = {OP_wai, -1, 0, single, 0, 0}, + [0x07] = {OP_sys, -1, 0, single, 0, 0}, + [0x08] = {0xFFFF, -1, bit_field_discrim, bfextins_n_bytes, bit_field_decode, 0}, /* BFEXT / BFINS */ + [0x09] = {0xFFFF, -1, bit_field_discrim, bfextins_n_bytes, bit_field_decode, 0}, + [0x0a] = {0xFFFF, -1, bit_field_discrim, bfextins_n_bytes, bit_field_decode, 0}, + [0x0b] = {0xFFFF, -1, bit_field_discrim, bfextins_n_bytes, bit_field_decode, 0}, + [0x0c] = {0xFFFF, -1, bit_field_discrim, bfextins_n_bytes, bit_field_decode, 0}, + [0x0d] = {0xFFFF, -1, bit_field_discrim, bfextins_n_bytes, bit_field_decode, 0}, + [0x0e] = {0xFFFF, -1, bit_field_discrim, bfextins_n_bytes, bit_field_decode, 0}, + [0x0f] = {0xFFFF, -1, bit_field_discrim, bfextins_n_bytes, bit_field_decode, 0}, + [0x10] = {OP_minu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x11] = {OP_minu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x12] = {OP_minu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x13] = {OP_minu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x14] = {OP_minu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x15] = {OP_minu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x16] = {OP_minu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x17] = {OP_minu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x18] = {OP_maxu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x19] = {OP_maxu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x1a] = {OP_maxu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x1b] = {OP_maxu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x1c] = {OP_maxu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x1d] = {OP_maxu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x1e] = {OP_maxu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x1f] = {OP_maxu, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x20] = {OP_mins, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x21] = {OP_mins, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x22] = {OP_mins, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x23] = {OP_mins, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x24] = {OP_mins, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x25] = {OP_mins, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x26] = {OP_mins, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x27] = {OP_mins, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x28] = {OP_maxs, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x29] = {OP_maxs, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x2a] = {OP_maxs, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x2b] = {OP_maxs, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x2c] = {OP_maxs, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x2d] = {OP_maxs, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x2e] = {OP_maxs, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x2f] = {OP_maxs, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x30] = {OPBASE_div, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x31] = {OPBASE_div, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x32] = {OPBASE_div, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x33] = {OPBASE_div, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x34] = {OPBASE_div, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x35] = {OPBASE_div, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x36] = {OPBASE_div, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x37] = {OPBASE_div, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x38] = {OPBASE_mod, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x39] = {OPBASE_mod, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x3a] = {OPBASE_mod, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x3b] = {OPBASE_mod, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x3c] = {OPBASE_mod, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x3d] = {OPBASE_mod, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x3e] = {OPBASE_mod, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x3f] = {OPBASE_mod, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x40] = {OP_abs, -1, 0, single, z_reg, 0}, + [0x41] = {OP_abs, -1, 0, single, z_reg, 0}, + [0x42] = {OP_abs, -1, 0, single, z_reg, 0}, + [0x43] = {OP_abs, -1, 0, single, z_reg, 0}, + [0x44] = {OP_abs, -1, 0, single, z_reg, 0}, + [0x45] = {OP_abs, -1, 0, single, z_reg, 0}, + [0x46] = {OP_abs, -1, 0, single, z_reg, 0}, + [0x47] = {OP_abs, -1, 0, single, z_reg, 0}, + [0x48] = {OPBASE_mac, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x49] = {OPBASE_mac, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x4a] = {OPBASE_mac, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x4b] = {OPBASE_mac, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x4c] = {OPBASE_mac, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x4d] = {OPBASE_mac, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x4e] = {OPBASE_mac, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x4f] = {OPBASE_mac, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x50] = {OP_adc, -1, 0, three, z_reg, z_imm1234_0base}, + [0x51] = {OP_adc, -1, 0, three, z_reg, z_imm1234_0base}, + [0x52] = {OP_adc, -1, 0, three, z_reg, z_imm1234_0base}, + [0x53] = {OP_adc, -1, 0, three, z_reg, z_imm1234_0base}, + [0x54] = {OP_adc, -1, 0, two, z_reg, z_imm1234_0base}, + [0x55] = {OP_adc, -1, 0, two, z_reg, z_imm1234_0base}, + [0x56] = {OP_adc, -1, 0, five, z_reg, z_imm1234_0base}, + [0x57] = {OP_adc, -1, 0, five, z_reg, z_imm1234_0base}, + [0x58] = {OP_bit, -1, 0, three, z_reg, z_imm1234_8base}, + [0x59] = {OP_bit, -1, 0, three, z_reg, z_imm1234_8base}, + [0x5a] = {OP_bit, -1, 0, three, z_reg, z_imm1234_8base}, + [0x5b] = {OP_bit, -1, 0, three, z_reg, z_imm1234_8base}, + [0x5c] = {OP_bit, -1, 0, two, z_reg, z_imm1234_8base}, + [0x5d] = {OP_bit, -1, 0, two, z_reg, z_imm1234_8base}, + [0x5e] = {OP_bit, -1, 0, five, z_reg, z_imm1234_8base}, + [0x5f] = {OP_bit, -1, 0, five, z_reg, z_imm1234_8base}, + [0x60] = {OP_adc, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x61] = {OP_adc, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x62] = {OP_adc, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x63] = {OP_adc, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x64] = {OP_adc, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x65] = {OP_adc, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x66] = {OP_adc, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x67] = {OP_adc, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x68] = {OP_bit, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x69] = {OP_bit, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x6a] = {OP_bit, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x6b] = {OP_bit, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x6c] = {OP_bit, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x6d] = {OP_bit, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x6e] = {OP_bit, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x6f] = {OP_bit, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x70] = {OP_sbc, -1, 0, three, z_reg, z_imm1234_0base}, + [0x71] = {OP_sbc, -1, 0, three, z_reg, z_imm1234_0base}, + [0x72] = {OP_sbc, -1, 0, three, z_reg, z_imm1234_0base}, + [0x73] = {OP_sbc, -1, 0, three, z_reg, z_imm1234_0base}, + [0x74] = {OP_sbc, -1, 0, two, z_reg, z_imm1234_0base}, + [0x75] = {OP_sbc, -1, 0, two, z_reg, z_imm1234_0base}, + [0x76] = {OP_sbc, -1, 0, five, z_reg, z_imm1234_0base}, + [0x77] = {OP_sbc, -1, 0, five, z_reg, z_imm1234_0base}, + [0x78] = {OP_eor, -1, 0, three, z_reg, z_imm1234_8base}, + [0x79] = {OP_eor, -1, 0, three, z_reg, z_imm1234_8base}, + [0x7a] = {OP_eor, -1, 0, three, z_reg, z_imm1234_8base}, + [0x7b] = {OP_eor, -1, 0, three, z_reg, z_imm1234_8base}, + [0x7c] = {OP_eor, -1, 0, two, z_reg, z_imm1234_8base}, + [0x7d] = {OP_eor, -1, 0, two, z_reg, z_imm1234_8base}, + [0x7e] = {OP_eor, -1, 0, five, z_reg, z_imm1234_8base}, + [0x7f] = {OP_eor, -1, 0, five, z_reg, z_imm1234_8base}, + [0x80] = {OP_sbc, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x81] = {OP_sbc, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x82] = {OP_sbc, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x83] = {OP_sbc, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x84] = {OP_sbc, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x85] = {OP_sbc, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x86] = {OP_sbc, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x87] = {OP_sbc, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x88] = {OP_eor, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x89] = {OP_eor, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x8a] = {OP_eor, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x8b] = {OP_eor, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x8c] = {OP_eor, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x8d] = {OP_eor, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x8e] = {OP_eor, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x8f] = {OP_eor, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x90] = {OP_rti, -1, 0, single, 0, 0}, + [0x91] = {OP_clb, -1, 0, two, z_tfr, 0}, + [0x92] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0x93] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0x94] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0x95] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0x96] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0x97] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0x98] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0x99] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0x9a] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0x9b] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0x9c] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0x9d] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0x9e] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0x9f] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xa0] = {OP_sat, -1, 0, single, z_reg, 0}, + [0xa1] = {OP_sat, -1, 0, single, z_reg, 0}, + [0xa2] = {OP_sat, -1, 0, single, z_reg, 0}, + [0xa3] = {OP_sat, -1, 0, single, z_reg, 0}, + [0xa4] = {OP_sat, -1, 0, single, z_reg, 0}, + [0xa5] = {OP_sat, -1, 0, single, z_reg, 0}, + [0xa6] = {OP_sat, -1, 0, single, z_reg, 0}, + [0xa7] = {OP_sat, -1, 0, single, z_reg, 0}, + [0xa8] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xa9] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xaa] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xab] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xac] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xad] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xae] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xaf] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xb0] = {OPBASE_qmul, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0xb1] = {OPBASE_qmul, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0xb2] = {OPBASE_qmul, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0xb3] = {OPBASE_qmul, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0xb4] = {OPBASE_qmul, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0xb5] = {OPBASE_qmul, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0xb6] = {OPBASE_qmul, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0xb7] = {OPBASE_qmul, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0xb8] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xb9] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xba] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xbb] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xbc] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xbd] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xbe] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xbf] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xc0] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xc1] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xc2] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xc3] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xc4] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xc5] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xc6] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xc7] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xc8] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xc9] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xca] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xcb] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xcc] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xcd] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xce] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xcf] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xd0] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xd1] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xd2] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xd3] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xd4] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xd5] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xd6] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xd7] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xd8] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xd9] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xda] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xdb] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xdc] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xdd] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xde] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xdf] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xe0] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xe1] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xe2] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xe3] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xe4] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xe5] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xe6] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xe7] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xe8] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xe9] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xea] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xeb] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xec] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xed] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xee] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xef] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xf0] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xf1] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xf2] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xf3] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xf4] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xf5] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xf6] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xf7] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xf8] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xf9] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xfa] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xfb] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xfc] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xfd] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xfe] = {OP_trap, -1, 0, single, trap_decode, 0}, + [0xff] = {OP_trap, -1, 0, single, trap_decode, 0}, + }; + +static const struct opcode page1[] = + { + [0x00] = {OP_bgnd, -1, 0, single, 0, 0}, + [0x01] = {OP_nop, -1, 0, single, 0, 0}, + [0x02] = {OP_brclr, -1, 0, bm_rel_n_bytes, bm_rel_decode, 0}, + [0x03] = {OP_brset, -1, 0, bm_rel_n_bytes, bm_rel_decode, 0}, + [0x04] = {0xFFFF, -1, psh_pul_discrim, two, psh_pul_decode, 0}, /* psh/pul */ + [0x05] = {OP_rts, -1, 0, single, 0, 0}, + [0x06] = {OP_lea, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x07] = {OP_lea, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x08] = {OP_lea, -1, 0, opr_n_bytes_p1, lea_reg_xys_opr, 0}, + [0x09] = {OP_lea, -1, 0, opr_n_bytes_p1, lea_reg_xys_opr, 0}, + [0x0a] = {OP_lea, -1, 0, opr_n_bytes_p1, lea_reg_xys_opr, 0}, + [0x0b] = {0xFFFF, -1, loop_primitive_discrim, loop_prim_n_bytes, loop_primitive_decode, 0}, /* Loop primitives TBcc / DBcc */ + [0x0c] = {OP_mov, 0, 0, mov_imm_opr_n_bytes, mov_imm_opr, 0}, + [0x0d] = {OP_mov, 1, 0, mov_imm_opr_n_bytes, mov_imm_opr, 0}, + [0x0e] = {OP_mov, 2, 0, mov_imm_opr_n_bytes, mov_imm_opr, 0}, + [0x0f] = {OP_mov, 3, 0, mov_imm_opr_n_bytes, mov_imm_opr, 0}, + [0x10] = {0xFFFF, -1, shift_discrim, shift_n_bytes, shift_decode, 0}, /* lsr/lsl/asl/asr/rol/ror */ + [0x11] = {0xFFFF, -1, shift_discrim, shift_n_bytes, shift_decode, 0}, + [0x12] = {0xFFFF, -1, shift_discrim, shift_n_bytes, shift_decode, 0}, + [0x13] = {0xFFFF, -1, shift_discrim, shift_n_bytes, shift_decode, 0}, + [0x14] = {0xFFFF, -1, shift_discrim, shift_n_bytes, shift_decode, 0}, + [0x15] = {0xFFFF, -1, shift_discrim, shift_n_bytes, shift_decode, 0}, + [0x16] = {0xFFFF, -1, shift_discrim, shift_n_bytes, shift_decode, 0}, + [0x17] = {0xFFFF, -1, shift_discrim, shift_n_bytes, shift_decode, 0}, + [0x18] = {OP_lea, -1, 0, two, lea_reg_xys, NULL}, + [0x19] = {OP_lea, -1, 0, two, lea_reg_xys, NULL}, + [0x1a] = {OP_lea, -1, 0, two, lea_reg_xys, NULL}, + /* 0x1b PG2 */ + [0x1c] = {OP_mov, 0, 0, opr_n_bytes2, z_opr_decode2, 0}, + [0x1d] = {OP_mov, 1, 0, opr_n_bytes2, z_opr_decode2, 0}, + [0x1e] = {OP_mov, 2, 0, opr_n_bytes2, z_opr_decode2, 0}, + [0x1f] = {OP_mov, 3, 0, opr_n_bytes2, z_opr_decode2, 0}, + [0x20] = {OP_bra, -1, 0, pcrel_15bit, decode_rel_15_7, 0}, + [0x21] = {OP_bsr, -1, 0, pcrel_15bit, decode_rel_15_7, 0}, + [0x22] = {OP_bhi, -1, 0, pcrel_15bit, decode_rel_15_7, 0}, + [0x23] = {OP_bls, -1, 0, pcrel_15bit, decode_rel_15_7, 0}, + [0x24] = {OP_bcc, -1, 0, pcrel_15bit, decode_rel_15_7, 0}, + [0x25] = {OP_bcs, -1, 0, pcrel_15bit, decode_rel_15_7, 0}, + [0x26] = {OP_bne, -1, 0, pcrel_15bit, decode_rel_15_7, 0}, + [0x27] = {OP_beq, -1, 0, pcrel_15bit, decode_rel_15_7, 0}, + [0x28] = {OP_bvc, -1, 0, pcrel_15bit, decode_rel_15_7, 0}, + [0x29] = {OP_bvs, -1, 0, pcrel_15bit, decode_rel_15_7, 0}, + [0x2a] = {OP_bpl, -1, 0, pcrel_15bit, decode_rel_15_7, 0}, + [0x2b] = {OP_bmi, -1, 0, pcrel_15bit, decode_rel_15_7, 0}, + [0x2c] = {OP_bge, -1, 0, pcrel_15bit, decode_rel_15_7, 0}, + [0x2d] = {OP_blt, -1, 0, pcrel_15bit, decode_rel_15_7, 0}, + [0x2e] = {OP_bgt, -1, 0, pcrel_15bit, decode_rel_15_7, 0}, + [0x2f] = {OP_ble, -1, 0, pcrel_15bit, decode_rel_15_7, 0}, + [0x30] = {OP_inc, -1, 0, single, z_reg, 0}, + [0x31] = {OP_inc, -1, 0, single, z_reg, 0}, + [0x32] = {OP_inc, -1, 0, single, z_reg, 0}, + [0x33] = {OP_inc, -1, 0, single, z_reg, 0}, + [0x34] = {OP_inc, -1, 0, single, z_reg, 0}, + [0x35] = {OP_inc, -1, 0, single, z_reg, 0}, + [0x36] = {OP_inc, -1, 0, single, z_reg, 0}, + [0x37] = {OP_inc, -1, 0, single, z_reg, 0}, + [0x38] = {OP_clr, -1, 0, single, z_reg, 0}, + [0x39] = {OP_clr, -1, 0, single, z_reg, 0}, + [0x3a] = {OP_clr, -1, 0, single, z_reg, 0}, + [0x3b] = {OP_clr, -1, 0, single, z_reg, 0}, + [0x3c] = {OP_clr, -1, 0, single, z_reg, 0}, + [0x3d] = {OP_clr, -1, 0, single, z_reg, 0}, + [0x3e] = {OP_clr, -1, 0, single, z_reg, 0}, + [0x3f] = {OP_clr, -1, 0, single, z_reg, 0}, + [0x40] = {OP_dec, -1, 0, single, z_reg, 0}, + [0x41] = {OP_dec, -1, 0, single, z_reg, 0}, + [0x42] = {OP_dec, -1, 0, single, z_reg, 0}, + [0x43] = {OP_dec, -1, 0, single, z_reg, 0}, + [0x44] = {OP_dec, -1, 0, single, z_reg, 0}, + [0x45] = {OP_dec, -1, 0, single, z_reg, 0}, + [0x46] = {OP_dec, -1, 0, single, z_reg, 0}, + [0x47] = {OP_dec, -1, 0, single, z_reg, 0}, + [0x48] = {OPBASE_mul, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x49] = {OPBASE_mul, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x4a] = {OPBASE_mul, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x4b] = {OPBASE_mul, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x4c] = {OPBASE_mul, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x4d] = {OPBASE_mul, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x4e] = {OPBASE_mul, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x4f] = {OPBASE_mul, -1, mul_discrim, mul_n_bytes, mul_decode, 0}, + [0x50] = {OP_add, -1, 0, three, z_reg, z_imm1234_0base}, + [0x51] = {OP_add, -1, 0, three, z_reg, z_imm1234_0base}, + [0x52] = {OP_add, -1, 0, three, z_reg, z_imm1234_0base}, + [0x53] = {OP_add, -1, 0, three, z_reg, z_imm1234_0base}, + [0x54] = {OP_add, -1, 0, two, z_reg, z_imm1234_0base}, + [0x55] = {OP_add, -1, 0, two, z_reg, z_imm1234_0base}, + [0x56] = {OP_add, -1, 0, five, z_reg, z_imm1234_0base}, + [0x57] = {OP_add, -1, 0, five, z_reg, z_imm1234_0base}, + [0x58] = {OP_and, -1, 0, three, z_reg, z_imm1234_8base}, + [0x59] = {OP_and, -1, 0, three, z_reg, z_imm1234_8base}, + [0x5a] = {OP_and, -1, 0, three, z_reg, z_imm1234_8base}, + [0x5b] = {OP_and, -1, 0, three, z_reg, z_imm1234_8base}, + [0x5c] = {OP_and, -1, 0, two, z_reg, z_imm1234_8base}, + [0x5d] = {OP_and, -1, 0, two, z_reg, z_imm1234_8base}, + [0x5e] = {OP_and, -1, 0, five, z_reg, z_imm1234_8base}, + [0x5f] = {OP_and, -1, 0, five, z_reg, z_imm1234_8base}, + [0x60] = {OP_add, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x61] = {OP_add, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x62] = {OP_add, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x63] = {OP_add, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x64] = {OP_add, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x65] = {OP_add, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x66] = {OP_add, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x67] = {OP_add, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x68] = {OP_and, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x69] = {OP_and, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x6a] = {OP_and, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x6b] = {OP_and, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x6c] = {OP_and, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x6d] = {OP_and, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x6e] = {OP_and, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x6f] = {OP_and, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x70] = {OP_sub, -1, 0, three, z_reg, z_imm1234_0base}, + [0x71] = {OP_sub, -1, 0, three, z_reg, z_imm1234_0base}, + [0x72] = {OP_sub, -1, 0, three, z_reg, z_imm1234_0base}, + [0x73] = {OP_sub, -1, 0, three, z_reg, z_imm1234_0base}, + [0x74] = {OP_sub, -1, 0, two, z_reg, z_imm1234_0base}, + [0x75] = {OP_sub, -1, 0, two, z_reg, z_imm1234_0base}, + [0x76] = {OP_sub, -1, 0, five, z_reg, z_imm1234_0base}, + [0x77] = {OP_sub, -1, 0, five, z_reg, z_imm1234_0base}, + [0x78] = {OP_or, -1, 0, three, z_reg, z_imm1234_8base}, + [0x79] = {OP_or, -1, 0, three, z_reg, z_imm1234_8base}, + [0x7a] = {OP_or, -1, 0, three, z_reg, z_imm1234_8base}, + [0x7b] = {OP_or, -1, 0, three, z_reg, z_imm1234_8base}, + [0x7c] = {OP_or, -1, 0, two, z_reg, z_imm1234_8base}, + [0x7d] = {OP_or, -1, 0, two, z_reg, z_imm1234_8base}, + [0x7e] = {OP_or, -1, 0, five, z_reg, z_imm1234_8base}, + [0x7f] = {OP_or, -1, 0, five, z_reg, z_imm1234_8base}, + [0x80] = {OP_sub, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x81] = {OP_sub, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x82] = {OP_sub, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x83] = {OP_sub, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x84] = {OP_sub, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x85] = {OP_sub, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x86] = {OP_sub, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x87] = {OP_sub, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x88] = {OP_or, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x89] = {OP_or, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x8a] = {OP_or, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x8b] = {OP_or, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x8c] = {OP_or, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x8d] = {OP_or, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x8e] = {OP_or, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x8f] = {OP_or, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0x90] = {OP_ld, -1, 0, three, z_reg, z_imm1234_0base}, + [0x91] = {OP_ld, -1, 0, three, z_reg, z_imm1234_0base}, + [0x92] = {OP_ld, -1, 0, three, z_reg, z_imm1234_0base}, + [0x93] = {OP_ld, -1, 0, three, z_reg, z_imm1234_0base}, + [0x94] = {OP_ld, -1, 0, two, z_reg, z_imm1234_0base}, + [0x95] = {OP_ld, -1, 0, two, z_reg, z_imm1234_0base}, + [0x96] = {OP_ld, -1, 0, five, z_reg, z_imm1234_0base}, + [0x97] = {OP_ld, -1, 0, five, z_reg, z_imm1234_0base}, + [0x98] = {OP_ld, -1, 0, four, reg_xy, z_imm1234_0base}, + [0x99] = {OP_ld, -1, 0, four, reg_xy, z_imm1234_0base}, + [0x9a] = {OP_clr, -1, 0, single, reg_xy, 0}, + [0x9b] = {OP_clr, -1, 0, single, reg_xy, 0}, + [0x9c] = {OP_inc, 0, 0, opr_n_bytes_p1, z_opr_decode, 0}, + [0x9d] = {OP_inc, 1, 0, opr_n_bytes_p1, z_opr_decode, 0}, + [0x9e] = {OP_tfr, -1, 0, two, z_tfr, NULL}, + [0x9f] = {OP_inc, 3, 0, opr_n_bytes_p1, z_opr_decode, 0}, + [0xa0] = {OP_ld, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0xa1] = {OP_ld, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0xa2] = {OP_ld, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0xa3] = {OP_ld, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0xa4] = {OP_ld, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0xa5] = {OP_ld, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0xa6] = {OP_ld, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0xa7] = {OP_ld, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0xa8] = {OP_ld, -1, 0, opr_n_bytes_p1, reg_xy, z_opr_decode}, + [0xa9] = {OP_ld, -1, 0, opr_n_bytes_p1, reg_xy, z_opr_decode}, + [0xaa] = {OP_jmp, -1, 0, opr_n_bytes_p1, z_opr_decode, 0}, + [0xab] = {OP_jsr, -1, 0, opr_n_bytes_p1, z_opr_decode, 0}, + [0xac] = {OP_dec, 0, 0, opr_n_bytes_p1, z_opr_decode, 0}, + [0xad] = {OP_dec, 1, 0, opr_n_bytes_p1, z_opr_decode, 0}, + [0xae] = {0xFFFF, -1, exg_sex_discrim, two, exg_sex_decode, 0}, /* EXG / SEX */ + [0xaf] = {OP_dec, 3, 0, opr_n_bytes_p1, 0, z_opr_decode}, + [0xb0] = {OP_ld, -1, 0, four, z_reg, z_ext24_decode}, + [0xb1] = {OP_ld, -1, 0, four, z_reg, z_ext24_decode}, + [0xb2] = {OP_ld, -1, 0, four, z_reg, z_ext24_decode}, + [0xb3] = {OP_ld, -1, 0, four, z_reg, z_ext24_decode}, + [0xb4] = {OP_ld, -1, 0, four, z_reg, z_ext24_decode}, + [0xb5] = {OP_ld, -1, 0, four, z_reg, z_ext24_decode}, + [0xb6] = {OP_ld, -1, 0, four, z_reg, z_ext24_decode}, + [0xb7] = {OP_ld, -1, 0, four, z_reg, z_ext24_decode}, + [0xb8] = {OP_ld, -1, 0, four, reg_xy, z_ext24_decode}, + [0xb9] = {OP_ld, -1, 0, four, reg_xy, z_ext24_decode}, + [0xba] = {OP_jmp, -1, 0, four, z_ext24_decode, 0}, + [0xbb] = {OP_jsr, -1, 0, four, z_ext24_decode, 0}, + [0xbc] = {OP_clr, 0, 0, opr_n_bytes_p1, z_opr_decode, 0}, + [0xbd] = {OP_clr, 1, 0, opr_n_bytes_p1, z_opr_decode, 0}, + [0xbe] = {OP_clr, 2, 0, opr_n_bytes_p1, z_opr_decode, 0}, + [0xbf] = {OP_clr, 3, 0, opr_n_bytes_p1, z_opr_decode, 0}, + [0xc0] = {OP_st, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0xc1] = {OP_st, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0xc2] = {OP_st, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0xc3] = {OP_st, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0xc4] = {OP_st, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0xc5] = {OP_st, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0xc6] = {OP_st, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0xc7] = {OP_st, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0xc8] = {OP_st, -1, 0, opr_n_bytes_p1, reg_xy, z_opr_decode}, + [0xc9] = {OP_st, -1, 0, opr_n_bytes_p1, reg_xy, z_opr_decode}, + [0xca] = {OP_ld, -1, 0, three, reg_xy, ld_18bit_decode}, + [0xcb] = {OP_ld, -1, 0, three, reg_xy, ld_18bit_decode}, + [0xcc] = {OP_com, 0, 0, opr_n_bytes_p1, NULL, z_opr_decode}, + [0xcd] = {OP_com, 1, 0, opr_n_bytes_p1, NULL, z_opr_decode}, + [0xce] = {OP_andcc, -1, 0, two, imm1_decode, 0}, + [0xcf] = {OP_com, 3, 0, opr_n_bytes_p1, NULL, z_opr_decode}, + [0xd0] = {OP_st, -1, 0, four, z_reg, z_ext24_decode}, + [0xd1] = {OP_st, -1, 0, four, z_reg, z_ext24_decode}, + [0xd2] = {OP_st, -1, 0, four, z_reg, z_ext24_decode}, + [0xd3] = {OP_st, -1, 0, four, z_reg, z_ext24_decode}, + [0xd4] = {OP_st, -1, 0, four, z_reg, z_ext24_decode}, + [0xd5] = {OP_st, -1, 0, four, z_reg, z_ext24_decode}, + [0xd6] = {OP_st, -1, 0, four, z_reg, z_ext24_decode}, + [0xd7] = {OP_st, -1, 0, four, z_reg, z_ext24_decode}, + [0xd8] = {OP_st, -1, 0, four, reg_xy, z_ext24_decode}, + [0xd9] = {OP_st, -1, 0, four, reg_xy, z_ext24_decode}, + [0xda] = {OP_ld, -1, 0, three, reg_xy, ld_18bit_decode}, + [0xdb] = {OP_ld, -1, 0, three, reg_xy, ld_18bit_decode}, + [0xdc] = {OP_neg, 0, 0, opr_n_bytes_p1, NULL, z_opr_decode}, + [0xdd] = {OP_neg, 1, 0, opr_n_bytes_p1, NULL, z_opr_decode}, + [0xde] = {OP_orcc, -1, 0, two, imm1_decode, 0}, + [0xdf] = {OP_neg, 3, 0, opr_n_bytes_p1, NULL, z_opr_decode}, + [0xe0] = {OP_cmp, -1, 0, three, z_reg, z_imm1234_0base}, + [0xe1] = {OP_cmp, -1, 0, three, z_reg, z_imm1234_0base}, + [0xe2] = {OP_cmp, -1, 0, three, z_reg, z_imm1234_0base}, + [0xe3] = {OP_cmp, -1, 0, three, z_reg, z_imm1234_0base}, + [0xe4] = {OP_cmp, -1, 0, two, z_reg, z_imm1234_0base}, + [0xe5] = {OP_cmp, -1, 0, two, z_reg, z_imm1234_0base}, + [0xe6] = {OP_cmp, -1, 0, five, z_reg, z_imm1234_0base}, + [0xe7] = {OP_cmp, -1, 0, five, z_reg, z_imm1234_0base}, + [0xe8] = {OP_cmp, -1, 0, four, reg_xy, z_imm1234_0base}, + [0xe9] = {OP_cmp, -1, 0, four, reg_xy, z_imm1234_0base}, + [0xea] = {OP_ld, -1, 0, three, reg_xy, ld_18bit_decode}, + [0xeb] = {OP_ld, -1, 0, three, reg_xy, ld_18bit_decode}, + [0xec] = {OP_bclr, -1, 0, bm_n_bytes, bm_decode, 0}, + [0xed] = {OP_bset, -1, 0, bm_n_bytes, bm_decode, 0}, + [0xee] = {OP_btgl, -1, 0, bm_n_bytes, bm_decode, 0}, + [0xef] = {OP_INVALID, -1, 0, NULL, NULL, NULL}, /* SPARE */ + [0xf0] = {OP_cmp, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0xf1] = {OP_cmp, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0xf2] = {OP_cmp, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0xf3] = {OP_cmp, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0xf4] = {OP_cmp, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0xf5] = {OP_cmp, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0xf6] = {OP_cmp, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0xf7] = {OP_cmp, -1, 0, opr_n_bytes_p1, z_reg, z_opr_decode}, + [0xf8] = {OP_cmp, -1, 0, opr_n_bytes_p1, reg_xy, z_opr_decode}, + [0xf9] = {OP_cmp, -1, 0, opr_n_bytes_p1, reg_xy, z_opr_decode}, + [0xfa] = {OP_ld, -1, 0, three, reg_xy, ld_18bit_decode}, + [0xfb] = {OP_ld, -1, 0, three, reg_xy, ld_18bit_decode}, + [0xfc] = {OP_cmp, -1, 0, single, cmp_xy, 0}, + [0xfd] = {OP_sub, -1, 0, single, sub_d6_x_y, 0}, + [0xfe] = {OP_sub, -1, 0, single, sub_d6_y_x, 0}, + [0xff] = {OP_swi, -1, 0, single, 0, 0} + }; + +static const int oprregs1[] = + { + REG_D3, REG_D2, REG_D1, REG_D0, REG_CCL, REG_CCH + }; + +static const int oprregs2[] = + { + REG_Y, REG_X, REG_D7, REG_D6, REG_D5, REG_D4 + }; + + + + +enum MUL_MODE + { + MUL_REG_REG, + MUL_REG_OPR, + MUL_REG_IMM, + MUL_OPR_OPR + }; + +struct mb +{ + uint8_t mask; + uint8_t value; + enum MUL_MODE mode; +}; + +static const struct mb mul_table[] = { + {0x40, 0x00, MUL_REG_REG}, + + {0x47, 0x40, MUL_REG_OPR}, + {0x47, 0x41, MUL_REG_OPR}, + {0x47, 0x43, MUL_REG_OPR}, + + {0x47, 0x44, MUL_REG_IMM}, + {0x47, 0x45, MUL_REG_IMM}, + {0x47, 0x47, MUL_REG_IMM}, + + {0x43, 0x42, MUL_OPR_OPR}, +}; + + +static void +mul_decode (struct mem_read_abstraction_base *mra, + int *n_operands, struct operand **operand) +{ + uint8_t mb; + int status = mra->read (mra, 0, 1, &mb); + if (status < 0) + return; + + uint8_t byte; + status = mra->read (mra, -1, 1, &byte); + if (status < 0) + return; + + enum MUL_MODE mode = -1; + size_t i; + for (i = 0; i < sizeof (mul_table) / sizeof (mul_table[0]); ++i) + { + const struct mb *mm = mul_table + i; + if ((mb & mm->mask) == mm->value) + { + mode = mm->mode; + break; + } + } + operand[(*n_operands)++] = create_register_operand (byte & 0x07); + + switch (mode) + { + case MUL_REG_IMM: + { + int size = (mb & 0x3); + operand[(*n_operands)++] = + create_register_operand_with_size ((mb & 0x38) >> 3, size); + uint32_t imm = z_decode_signed_value (mra, 1, size + 1); + operand[(*n_operands)++] = create_immediate_operand (imm); + } + break; + case MUL_REG_REG: + operand[(*n_operands)++] = create_register_operand ((mb & 0x38) >> 3); + operand[(*n_operands)++] = create_register_operand (mb & 0x07); + break; + case MUL_REG_OPR: + operand[(*n_operands)++] = create_register_operand ((mb & 0x38) >> 3); + operand[(*n_operands)++] = x_opr_decode_with_size (mra, 1, mb & 0x3); + break; + case MUL_OPR_OPR: + { + int first = x_opr_n_bytes (mra, 1); + operand[(*n_operands)++] = x_opr_decode_with_size (mra, 1, + (mb & 0x30) >> 4); + operand[(*n_operands)++] = x_opr_decode_with_size (mra, first + 1, + (mb & 0x0c) >> 2); + break; + } + } +} + + +static int +mul_n_bytes (struct mem_read_abstraction_base *mra) +{ + int nx = 2; + uint8_t mb; + int status = mra->read (mra, 0, 1, &mb); + if (status < 0) + return 0; + + enum MUL_MODE mode = -1; + size_t i; + for (i = 0; i < sizeof (mul_table) / sizeof (mul_table[0]); ++i) + { + const struct mb *mm = mul_table + i; + if ((mb & mm->mask) == mm->value) + { + mode = mm->mode; + break; + } + } + + int size = (mb & 0x3) + 1; + + switch (mode) + { + case MUL_REG_IMM: + nx += size; + break; + case MUL_REG_REG: + break; + case MUL_REG_OPR: + nx += x_opr_n_bytes (mra, 1); + break; + case MUL_OPR_OPR: + { + int first = x_opr_n_bytes (mra, nx - 1); + nx += first; + int second = x_opr_n_bytes (mra, nx - 1); + nx += second; + } + break; + } + + return nx; +} + + +/* The NXP documentation is vague about BM_RESERVED0 and BM_RESERVED1, + and contains obvious typos. + However the Freescale tools and experiments with the chip itself + seem to indicate that they behave like BM_REG_IMM and BM_OPR_REG + respectively. */ + +enum BM_MODE +{ + BM_REG_IMM, + BM_RESERVED0, + BM_OPR_B, + BM_OPR_W, + BM_OPR_L, + BM_OPR_REG, + BM_RESERVED1 +}; + +struct bm +{ + uint8_t mask; + uint8_t value; + enum BM_MODE mode; +}; + +static const struct bm bm_table[] = { + { 0xC6, 0x04, BM_REG_IMM}, + { 0x84, 0x00, BM_REG_IMM}, + { 0x06, 0x06, BM_REG_IMM}, + { 0xC6, 0x44, BM_RESERVED0}, + // 00 + { 0x8F, 0x80, BM_OPR_B}, + { 0x8E, 0x82, BM_OPR_W}, + { 0x8C, 0x88, BM_OPR_L}, + + { 0x83, 0x81, BM_OPR_REG}, + { 0x87, 0x84, BM_RESERVED1}, +}; + +static void +bm_decode (struct mem_read_abstraction_base *mra, + int *n_operands, struct operand **operand) +{ + uint8_t bm; + int status = mra->read (mra, 0, 1, &bm); + if (status < 0) + return; + + size_t i; + enum BM_MODE mode = -1; + for (i = 0; i < sizeof (bm_table) / sizeof (bm_table[0]); ++i) + { + const struct bm *bme = bm_table + i; + if ((bm & bme->mask) == bme->value) + { + mode = bme->mode; + break; + } + } + + switch (mode) + { + case BM_REG_IMM: + case BM_RESERVED0: + operand[(*n_operands)++] = create_register_operand (bm & 0x07); + break; + case BM_OPR_B: + operand[(*n_operands)++] = x_opr_decode_with_size (mra, 1, 0); + break; + case BM_OPR_W: + operand[(*n_operands)++] = x_opr_decode_with_size (mra, 1, 1); + break; + case BM_OPR_L: + operand[(*n_operands)++] = x_opr_decode_with_size (mra, 1, 3); + break; + case BM_OPR_REG: + case BM_RESERVED1: + { + uint8_t xb; + mra->read (mra, 1, 1, &xb); + /* Don't emit a size suffix for register operands */ + if ((xb & 0xF8) != 0xB8) + operand[(*n_operands)++] = + x_opr_decode_with_size (mra, 1, (bm & 0x0c) >> 2); + else + operand[(*n_operands)++] = x_opr_decode (mra, 1); + } + break; + } + + uint8_t imm = 0; + switch (mode) + { + case BM_REG_IMM: + imm = (bm & 0x38) >> 3; + operand[(*n_operands)++] = create_immediate_operand (imm); + break; + case BM_OPR_L: + imm |= (bm & 0x03) << 3; + /* fallthrough */ + case BM_OPR_W: + imm |= (bm & 0x01) << 3; + /* fallthrough */ + case BM_OPR_B: + imm |= (bm & 0x70) >> 4; + operand[(*n_operands)++] = create_immediate_operand (imm); + break; + case BM_OPR_REG: + case BM_RESERVED1: + operand[(*n_operands)++] = create_register_operand ((bm & 0x70) >> 4); + break; + case BM_RESERVED0: + assert (0); + break; + } +} + + +static void +bm_rel_decode (struct mem_read_abstraction_base *mra, + int *n_operands, struct operand **operand) +{ + uint8_t bm; + int status = mra->read (mra, 0, 1, &bm); + if (status < 0) + return; + + size_t i; + enum BM_MODE mode = -1; + for (i = 0; i < sizeof (bm_table) / sizeof (bm_table[0]); ++i) + { + const struct bm *bme = bm_table + i; + if ((bm & bme->mask) == bme->value) + { + mode = bme->mode; + break; + } + } + + int n = 1; + switch (mode) + { + case BM_REG_IMM: + case BM_RESERVED0: + operand[(*n_operands)++] = create_register_operand (bm & 0x07); + break; + case BM_OPR_B: + operand[(*n_operands)++] = x_opr_decode_with_size (mra, 1, 0); + n = 1 + x_opr_n_bytes (mra, 1); + break; + case BM_OPR_W: + operand[(*n_operands)++] = x_opr_decode_with_size (mra, 1, 1); + n = 1 + x_opr_n_bytes (mra, 1); + break; + case BM_OPR_L: + operand[(*n_operands)++] = x_opr_decode_with_size (mra, 1, 3); + n = 1 + x_opr_n_bytes (mra, 1); + break; + case BM_OPR_REG: + case BM_RESERVED1: + { + uint8_t xb; + mra->read (mra, +1, 1, &xb); + /* Don't emit a size suffix for register operands */ + if ((xb & 0xF8) != 0xB8) + { + short os = (bm & 0x0c) >> 2; + operand[(*n_operands)++] = x_opr_decode_with_size (mra, 1, os); + } + else + operand[(*n_operands)++] = x_opr_decode (mra, 1); + + } + break; + } + + int imm = 0; + switch (mode) + { + case BM_OPR_L: + imm |= (bm & 0x02) << 3; + /* fall through */ + case BM_OPR_W: + imm |= (bm & 0x01) << 3; + /* fall through */ + case BM_OPR_B: + imm |= (bm & 0x70) >> 4; + operand[(*n_operands)++] = create_immediate_operand (imm); + break; + case BM_RESERVED0: + imm = (bm & 0x38) >> 3; + operand[(*n_operands)++] = create_immediate_operand (imm); + break; + case BM_REG_IMM: + imm = (bm & 0xF8) >> 3; + operand[(*n_operands)++] = create_immediate_operand (imm); + break; + case BM_OPR_REG: + case BM_RESERVED1: + operand[(*n_operands)++] = create_register_operand ((bm & 0x70) >> 4); + n += x_opr_n_bytes (mra, 1); + break; + } + + rel_15_7 (mra, n + 1, n_operands, operand); +} + +static int +bm_n_bytes (struct mem_read_abstraction_base *mra) +{ + uint8_t bm; + int status = mra->read (mra, 0, 1, &bm); + if (status < 0) + return status; + + size_t i; + enum BM_MODE mode = -1; + for (i = 0; i < sizeof (bm_table) / sizeof (bm_table[0]); ++i) + { + const struct bm *bme = bm_table + i; + if ((bm & bme->mask) == bme->value) + { + mode = bme->mode; + break; + } + } + + int n = 2; + switch (mode) + { + case BM_REG_IMM: + case BM_RESERVED0: + break; + + case BM_OPR_B: + case BM_OPR_W: + case BM_OPR_L: + n += x_opr_n_bytes (mra, 1); + break; + case BM_OPR_REG: + case BM_RESERVED1: + n += x_opr_n_bytes (mra, 1); + break; + } + + return n; +} + +static int +bm_rel_n_bytes (struct mem_read_abstraction_base *mra) +{ + int n = 1 + bm_n_bytes (mra); + + bfd_byte rb; + int status = mra->read (mra, n - 2, 1, &rb); + if (status != 0) + return status; + + if (rb & 0x80) + n++; + + return n; +} + + + + + +/* shift direction */ +enum SB_DIR + { + SB_LEFT, + SB_RIGHT + }; + +enum SB_TYPE + { + SB_ARITHMETIC, + SB_LOGICAL + }; + + +enum SB_MODE + { + SB_REG_REG_N_EFF, + SB_REG_REG_N, + SB_REG_OPR_EFF, + SB_ROT, + SB_REG_OPR_OPR, + SB_OPR_N + }; + +struct sb +{ + uint8_t mask; + uint8_t value; + enum SB_MODE mode; +}; + +static const struct sb sb_table[] = { + {0x30, 0x00, SB_REG_REG_N_EFF}, + {0x30, 0x10, SB_REG_REG_N}, + {0x34, 0x20, SB_REG_OPR_EFF}, + {0x34, 0x24, SB_ROT}, + {0x34, 0x30, SB_REG_OPR_OPR}, + {0x34, 0x34, SB_OPR_N}, +}; + +static int +shift_n_bytes (struct mem_read_abstraction_base *mra) +{ + bfd_byte sb; + int status = mra->read (mra, 0, 1, &sb); + if (status != 0) + return status; + + size_t i; + enum SB_MODE mode = -1; + for (i = 0; i < sizeof (sb_table) / sizeof (sb_table[0]); ++i) + { + const struct sb *sbe = sb_table + i; + if ((sb & sbe->mask) == sbe->value) + mode = sbe->mode; + } + + switch (mode) + { + case SB_REG_REG_N_EFF: + return 2; + break; + case SB_REG_OPR_EFF: + case SB_ROT: + return 2 + x_opr_n_bytes (mra, 1); + break; + case SB_REG_OPR_OPR: + { + int opr1 = x_opr_n_bytes (mra, 1); + int opr2 = 0; + if ((sb & 0x30) != 0x20) + opr2 = x_opr_n_bytes (mra, opr1 + 1); + return 2 + opr1 + opr2; + } + break; + default: + return 3; + } + + /* not reached */ + return -1; +} + + +static int + +mov_imm_opr_n_bytes (struct mem_read_abstraction_base *mra) +{ + bfd_byte byte; + int status = mra->read (mra, -1, 1, &byte); + if (status < 0) + return status; + + int size = byte - 0x0c + 1; + + return size + x_opr_n_bytes (mra, size) + 1; +} + +static void +mov_imm_opr (struct mem_read_abstraction_base *mra, + int *n_operands, struct operand **operand) +{ + bfd_byte byte; + int status = mra->read (mra, -1, 1, &byte); + if (status < 0) + return ; + + int size = byte - 0x0c + 1; + uint32_t imm = decode_signed_value (mra, size); + + operand[(*n_operands)++] = create_immediate_operand (imm); + operand[(*n_operands)++] = x_opr_decode (mra, size); +} + + + +static void +ld_18bit_decode (struct mem_read_abstraction_base *mra, + int *n_operands, struct operand **operand) +{ + size_t size = 3; + bfd_byte buffer[3]; + int status = mra->read (mra, 0, 2, buffer + 1); + if (status < 0) + return ; + + status = mra->read (mra, -1, 1, buffer); + if (status < 0) + return ; + + buffer[0] = (buffer[0] & 0x30) >> 4; + + size_t i; + uint32_t imm = 0; + for (i = 0; i < size; ++i) + { + imm |= buffer[i] << (8 * (size - i - 1)); + } + + operand[(*n_operands)++] = create_immediate_operand (imm); +} + + + +/* Loop Primitives */ + +enum LP_MODE { + LP_REG, + LP_XY, + LP_OPR +}; + +struct lp +{ + uint8_t mask; + uint8_t value; + enum LP_MODE mode; +}; + +static const struct lp lp_mode[] = { + {0x08, 0x00, LP_REG}, + {0x0C, 0x08, LP_XY}, + {0x0C, 0x0C, LP_OPR}, +}; + + +static int +loop_prim_n_bytes (struct mem_read_abstraction_base *mra) +{ + int mx = 0; + uint8_t lb; + mra->read (mra, mx++, 1, &lb); + + enum LP_MODE mode = -1; + size_t i; + for (i = 0; i < sizeof (lp_mode) / sizeof (lp_mode[0]); ++i) + { + const struct lp *pb = lp_mode + i; + if ((lb & pb->mask) == pb->value) + { + mode = pb->mode; + break; + } + } + + if (mode == LP_OPR) + { + mx += x_opr_n_bytes (mra, mx) ; + } + + uint8_t rb; + mra->read (mra, mx++, 1, &rb); + if (rb & 0x80) + mx++; + + return mx + 1; +} + + + + +static enum operator +exg_sex_discrim (struct mem_read_abstraction_base *mra, enum operator hint ATTRIBUTE_UNUSED) +{ + uint8_t eb; + int status = mra->read (mra, 0, 1, &eb); + if (status < 0) + return OP_INVALID; + + struct operand *op0 = create_register_operand ((eb & 0xf0) >> 4); + struct operand *op1 = create_register_operand (eb & 0xf); + + const struct reg *r0 = registers + ((struct register_operand *) op0)->reg; + const struct reg *r1 = registers + ((struct register_operand *) op1)->reg; + + enum operator operator = (r0->bytes < r1->bytes) ? OP_sex : OP_exg; + + free (op0); + free (op1); + + return operator; +} + + +static void +exg_sex_decode (struct mem_read_abstraction_base *mra, + int *n_operands, struct operand **operands) +{ + uint8_t eb; + int status = mra->read (mra, 0, 1, &eb); + if (status < 0) + return; + + /* Ship out the operands. */ + operands[(*n_operands)++] = create_register_operand ((eb & 0xf0) >> 4); + operands[(*n_operands)++] = create_register_operand (eb & 0xf); +} + +static enum operator +loop_primitive_discrim (struct mem_read_abstraction_base *mra, + enum operator hint ATTRIBUTE_UNUSED) +{ + uint8_t lb; + int status = mra->read (mra, 0, 1, &lb); + if (status < 0) + return OP_INVALID; + + enum operator opbase = (lb & 0x80) ? OP_dbNE : OP_tbNE; + return opbase + ((lb & 0x70) >> 4); +} + +static void +loop_primitive_decode (struct mem_read_abstraction_base *mra, + int *n_operands, struct operand **operands) +{ + int offs = 1; + uint8_t lb; + int status = mra->read (mra, 0, 1, &lb); + if (status < 0) + return ; + + enum LP_MODE mode = -1; + size_t i; + for (i = 0; i < sizeof (lp_mode) / sizeof (lp_mode[0]); ++i) + { + const struct lp *pb = lp_mode + i; + if ((lb & pb->mask) == pb->value) + { + mode = pb->mode; + break; + } + } + + switch (mode) + { + case LP_REG: + operands[(*n_operands)++] = create_register_operand (lb & 0x07); + break; + case LP_XY: + operands[(*n_operands)++] = + create_register_operand ((lb & 0x01) + REG_X); + break; + case LP_OPR: + offs += x_opr_n_bytes (mra, 1); + operands[(*n_operands)++] = x_opr_decode_with_size (mra, 1, lb & 0x03); + break; + } + + rel_15_7 (mra, offs + 1, n_operands, operands); +} + + +static enum operator +shift_discrim (struct mem_read_abstraction_base *mra, enum operator hint ATTRIBUTE_UNUSED) +{ + size_t i; + uint8_t sb; + int status = mra->read (mra, 0, 1, &sb); + if (status < 0) + return status; + + enum SB_DIR dir = (sb & 0x40) ? SB_LEFT : SB_RIGHT; + enum SB_TYPE type = (sb & 0x80) ? SB_ARITHMETIC : SB_LOGICAL; + enum SB_MODE mode = -1; + for (i = 0; i < sizeof (sb_table) / sizeof (sb_table[0]); ++i) + { + const struct sb *sbe = sb_table + i; + if ((sb & sbe->mask) == sbe->value) + mode = sbe->mode; + } + + if (mode == SB_ROT) + return (dir == SB_LEFT) ? OP_rol : OP_ror; + + if (type == SB_LOGICAL) + return (dir == SB_LEFT) ? OP_lsl : OP_lsr; + + return (dir == SB_LEFT) ? OP_asl : OP_asr; +} + + +static void +shift_decode (struct mem_read_abstraction_base *mra, int *n_operands, struct operand **operands) +{ + size_t i; + + uint8_t byte; + int status = mra->read (mra, -1, 1, &byte); + if (status < 0) + return ; + + uint8_t sb; + status = mra->read (mra, 0, 1, &sb); + if (status < 0) + return ; + + enum SB_MODE mode = -1; + for (i = 0; i < sizeof (sb_table) / sizeof (sb_table[0]); ++i) + { + const struct sb *sbe = sb_table + i; + if ((sb & sbe->mask) == sbe->value) + mode = sbe->mode; + } + + short osize = -1; + switch (mode) + { + case SB_REG_OPR_EFF: + case SB_ROT: + case SB_REG_OPR_OPR: + osize = sb & 0x03; + break; + case SB_OPR_N: + { + uint8_t xb; + mra->read (mra, 1, 1, &xb); + /* The size suffix is not printed if the OPR operand refers + directly to a register, because the size is implied by the + size of that register. */ + if ((xb & 0xF8) != 0xB8) + osize = sb & 0x03; + } + break; + default: + break; + }; + + /* Destination register */ + switch (mode) + { + case SB_REG_REG_N_EFF: + case SB_REG_REG_N: + operands[(*n_operands)++] = create_register_operand (byte & 0x07); + break; + case SB_REG_OPR_EFF: + case SB_REG_OPR_OPR: + operands[(*n_operands)++] = create_register_operand (byte & 0x07); + break; + + case SB_ROT: + operands[(*n_operands)++] = x_opr_decode_with_size (mra, 1, osize); + break; + + default: + break; + } + + /* Source register */ + switch (mode) + { + case SB_REG_REG_N_EFF: + case SB_REG_REG_N: + operands[(*n_operands)++] = + create_register_operand_with_size (sb & 0x07, osize); + break; + + case SB_REG_OPR_OPR: + operands[(*n_operands)++] = x_opr_decode_with_size (mra, 1, osize); + break; + + default: + break; + } + + /* 3rd arg */ + switch (mode) + { + case SB_REG_OPR_EFF: + case SB_OPR_N: + operands[(*n_operands)++] = x_opr_decode_with_size (mra, 1, osize); + break; + + case SB_REG_REG_N: + { + uint8_t xb; + mra->read (mra, 1, 1, &xb); + + /* This case is slightly unusual. + If XB matches the binary pattern 0111XXXX, then instead of + interpreting this as a general OPR postbyte in the IMMe4 mode, + the XB byte is interpreted in s special way. */ + if ((xb & 0xF0) == 0x70) + { + if (byte & 0x10) + { + int shift = ((sb & 0x08) >> 3) | ((xb & 0x0f) << 1); + operands[(*n_operands)++] = create_immediate_operand (shift); + } + else + { + /* This should not happen. */ + abort (); + } + } + else + { + operands[(*n_operands)++] = x_opr_decode (mra, 1); + } + } + break; + case SB_REG_OPR_OPR: + { + uint8_t xb; + int n = x_opr_n_bytes (mra, 1); + mra->read (mra, 1 + n, 1, &xb); + + if ((xb & 0xF0) == 0x70) + { + int imm = xb & 0x0F; + imm <<= 1; + imm |= (sb & 0x08) >> 3; + operands[(*n_operands)++] = create_immediate_operand (imm); + } + else + { + operands[(*n_operands)++] = x_opr_decode (mra, 1 + n); + } + } + break; + default: + break; + } + + switch (mode) + { + case SB_REG_REG_N_EFF: + case SB_REG_OPR_EFF: + case SB_OPR_N: + { + int imm = (sb & 0x08) ? 2 : 1; + operands[(*n_operands)++] = create_immediate_operand (imm); + } + break; + + default: + break; + } +} + +static enum operator +psh_pul_discrim (struct mem_read_abstraction_base *mra, + enum operator hint ATTRIBUTE_UNUSED) +{ + uint8_t byte; + int status = mra->read (mra, 0, 1, &byte); + if (status != 0) + return OP_INVALID; + + return (byte & 0x80) ? OP_pull: OP_push; +} + + +static void +psh_pul_decode (struct mem_read_abstraction_base *mra, + int *n_operands, struct operand **operand) +{ + uint8_t byte; + int status = mra->read (mra, 0, 1, &byte); + if (status != 0) + return; + int bit; + if (byte & 0x40) + { + if ((byte & 0x3F) == 0) + { + operand[(*n_operands)++] = create_register_all16_operand (); + } + else + for (bit = 5; bit >= 0; --bit) + { + if (byte & (0x1 << bit)) + { + operand[(*n_operands)++] = create_register_operand (oprregs2[bit]); + } + } + } + else + { + if ((byte & 0x3F) == 0) + { + operand[(*n_operands)++] = create_register_all_operand (); + } + else + for (bit = 5; bit >= 0; --bit) + { + if (byte & (0x1 << bit)) + { + operand[(*n_operands)++] = create_register_operand (oprregs1[bit]); + } + } + } +} + +static enum operator +bit_field_discrim (struct mem_read_abstraction_base *mra, enum operator hint ATTRIBUTE_UNUSED) +{ + int status; + bfd_byte bb; + status = mra->read (mra, 0, 1, &bb); + if (status != 0) + return OP_INVALID; + + return (bb & 0x80) ? OP_bfins : OP_bfext; +} + +static void +bit_field_decode (struct mem_read_abstraction_base *mra, + int *n_operands, struct operand **operands) +{ + int status; + + bfd_byte byte2; + status = mra->read (mra, -1, 1, &byte2); + if (status != 0) + return; + + bfd_byte bb; + status = mra->read (mra, 0, 1, &bb); + if (status != 0) + return; + + enum BB_MODE mode = -1; + size_t i; + const struct opr_bb *bbs = 0; + for (i = 0; i < sizeof (bb_modes) / sizeof (bb_modes[0]); ++i) + { + bbs = bb_modes + i; + if ((bb & bbs->mask) == bbs->value) + { + mode = bbs->mode; + break; + } + } + int reg1 = byte2 & 0x07; + /* First operand */ + switch (mode) + { + case BB_REG_REG_REG: + case BB_REG_REG_IMM: + case BB_REG_OPR_REG: + case BB_REG_OPR_IMM: + operands[(*n_operands)++] = create_register_operand (reg1); + break; + case BB_OPR_REG_REG: + operands[(*n_operands)++] = x_opr_decode_with_size (mra, 1, + (bb >> 2) & 0x03); + break; + case BB_OPR_REG_IMM: + operands[(*n_operands)++] = x_opr_decode_with_size (mra, 2, + (bb >> 2) & 0x03); + break; + } + + /* Second operand */ + switch (mode) + { + case BB_REG_REG_REG: + case BB_REG_REG_IMM: + { + int reg_src = (bb >> 2) & 0x07; + operands[(*n_operands)++] = create_register_operand (reg_src); + } + break; + case BB_OPR_REG_REG: + case BB_OPR_REG_IMM: + { + int reg_src = (byte2 & 0x07); + operands[(*n_operands)++] = create_register_operand (reg_src); + } + break; + case BB_REG_OPR_REG: + operands[(*n_operands)++] = x_opr_decode_with_size (mra, 1, + (bb >> 2) & 0x03); + break; + case BB_REG_OPR_IMM: + operands[(*n_operands)++] = x_opr_decode_with_size (mra, 2, + (bb >> 2) & 0x03); + break; + } + + /* Third operand */ + switch (mode) + { + case BB_REG_REG_REG: + case BB_OPR_REG_REG: + case BB_REG_OPR_REG: + { + int reg_parm = bb & 0x03; + operands[(*n_operands)++] = create_register_operand (reg_parm); + } + break; + case BB_REG_REG_IMM: + case BB_OPR_REG_IMM: + case BB_REG_OPR_IMM: + { + bfd_byte i1; + mra->read (mra, 1, 1, &i1); + int offset = i1 & 0x1f; + int width = bb & 0x03; + width <<= 3; + width |= i1 >> 5; + operands[(*n_operands)++] = create_bitfield_operand (width, offset); + } + break; + } +} + + +/* Decode the next instruction at MRA, according to OPC. + The operation to be performed is returned. + The number of operands, will be placed in N_OPERANDS. + The operands themselved into OPERANDS. */ +static enum operator +decode_operation (const struct opcode *opc, + struct mem_read_abstraction_base *mra, + int *n_operands, struct operand **operands) +{ + enum operator op = opc->operator; + if (opc->discriminator) + op = opc->discriminator (mra, opc->operator); + + if (opc->operands) + opc->operands (mra, n_operands, operands); + + if (opc->operands2) + opc->operands2 (mra, n_operands, operands); + + return op; +} + +int +decode_s12z (enum operator *myoperator, short *osize, + int *n_operands, struct operand **operands, + struct mem_read_abstraction_base *mra) +{ + int n_bytes = 0; + bfd_byte byte; + + int status = mra->read (mra, 0, 1, &byte); + if (status != 0) + return status; + + mra->advance (mra); + + const struct opcode *opc = page1 + byte; + if (byte == PAGE2_PREBYTE) + { + /* Opcodes in page2 have an additional byte */ + n_bytes++; + + bfd_byte byte2; + mra->read (mra, 0, 1, &byte2); + mra->advance (mra); + opc = page2 + byte2; + } + *myoperator = decode_operation (opc, mra, n_operands, operands); + *osize = opc->osize; + + /* Return the number of bytes in the instruction. */ + n_bytes += (opc && opc->insn_bytes) ? opc->insn_bytes (mra) : 0; + + return n_bytes; +} + diff --git a/opcodes/s12z-opc.h b/opcodes/s12z-opc.h new file mode 100644 index 0000000..186a7f2 --- /dev/null +++ b/opcodes/s12z-opc.h @@ -0,0 +1,267 @@ +/* s12z-dis.h -- Header file for s12z-dis.c and s12z-decode.c + Copyright (C) 2019 Free Software Foundation, Inc. + + This file is part of the GNU opcodes library. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + It is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING3. If not, + see <http://www.gnu.org/licenses/>. */ + +#ifndef S12Z_OPC_H +#define S12Z_OPC_H + +#include <stdbool.h> + +/* An abstraction used to read machine code from a source. */ +struct mem_read_abstraction_base +{ + int (*read) (struct mem_read_abstraction_base *, int, size_t, bfd_byte *); + void (*advance) (struct mem_read_abstraction_base *); + bfd_vma (*posn) (struct mem_read_abstraction_base *); +}; + + +/* Machine code operators. + These *roughly* correspond to opcodes. + But describe their purpose rather than their form. */ +enum operator + { + OP_INVALID = 0, + + OP_push, + OP_pull, + /* Test and branch. */ + OP_tbNE, OP_tbEQ, OP_tbPL, OP_tbMI, OP_tbGT, OP_tbLE, + /* Decrement and branch. */ + OP_dbNE, OP_dbEQ, OP_dbPL, OP_dbMI, OP_dbGT, OP_dbLE, + + /* Note: sex and exg are the same opcode. + They are mnemonic changes according to the operands. */ + OP_sex, + OP_exg, + + /* Shifters. */ + OP_lsl, OP_lsr, + OP_asl, OP_asr, + OP_rol, OP_ror, + /* Bit field operations. */ + OP_bfins, OP_bfext, + OP_trap, + + OP_ld, + OP_st, + OP_cmp, + + OP_stop, + OP_wai, + OP_sys, + + OP_minu, + OP_mins, + OP_maxu, + OP_maxs, + + OP_abs, + OP_adc, + OP_bit, + OP_sbc, + OP_rti, + OP_clb, + OP_eor, + + OP_sat, + + OP_nop, + OP_bgnd, + OP_brclr, + OP_brset, + OP_rts, + OP_lea, + OP_mov, + + OP_bra, + OP_bsr, + OP_bhi, + OP_bls, + OP_bcc, + OP_bcs, + OP_bne, + OP_beq, + OP_bvc, + OP_bvs, + OP_bpl, + OP_bmi, + OP_bge, + OP_blt, + OP_bgt, + OP_ble, + OP_inc, + OP_clr, + OP_dec, + + OP_add, + OP_sub, + OP_and, + OP_or, + + OP_tfr, + OP_jmp, + OP_jsr, + OP_com, + OP_andcc, + OP_neg, + OP_orcc, + OP_bclr, + OP_bset, + OP_btgl, + OP_swi, + + OP_mulu, + OP_divu, + OP_modu, + OP_macu, + OP_qmulu, + + OP_muls, + OP_divs, + OP_mods, + OP_macs, + OP_qmuls, + + OPBASE_mul = 0x4000, + OPBASE_div, + OPBASE_mod, + OPBASE_mac, + OPBASE_qmul, + + n_OPS + }; + + +/* Used for operands which mutate their index/base registers. + Eg ld d0, (s+). */ +enum op_reg_mutation + { + OPND_RM_NONE, + OPND_RM_PRE_DEC, + OPND_RM_PRE_INC, + OPND_RM_POST_DEC, + OPND_RM_POST_INC + }; + +/* The class of an operand. */ +enum opnd_class + { + OPND_CL_IMMEDIATE, + OPND_CL_MEMORY, + OPND_CL_REGISTER, + OPND_CL_REGISTER_ALL, /* Used only for psh/pul. */ + OPND_CL_REGISTER_ALL16, /* Used only for psh/pul. */ + OPND_CL_SIMPLE_MEMORY, + OPND_CL_BIT_FIELD + }; + + +/* Base structure of all operands. */ +struct operand +{ + enum opnd_class cl; + + /* OSIZE determines the size of memory access for + the operation in which the operand participates. + It may be -1 which indicates either unknown + (must be determined by other operands) or if + it is not applicable for this operation. */ + int osize; +}; + +/* Immediate operands. Eg: #23 */ +struct immediate_operand +{ + struct operand parent; + int value; +}; + +/* Bitfield operands. Used only in bfext and bfins + instructions. */ +struct bitfield_operand +{ + struct operand parent; + int width; + int offset; +}; + +/* Register operands. */ +struct register_operand +{ + struct operand parent; + int reg; +}; + + +/* Simple memory operands. ie, direct memory, + no index, no pre/post inc/dec. May be either relative or absolute. + Eg st d0, 0x123456 */ +struct simple_memory_operand +{ + struct operand parent; + + bfd_vma addr; + bfd_vma base; + bool relative; +}; + + +/* Memory operands. Should be able to represent all memory + operands in the S12Z instruction set which are not simple + memory operands. */ +struct memory_operand +{ + struct operand parent; + + /* True for indirect operands: eg [0x123456] */ + bool indirect; + + /* The value of any offset. eg 45 in (45,d7) */ + int base_offset; + + /* Does this operand increment or decrement + its participating registers. Eg (-s) */ + enum op_reg_mutation mutation; + + /* The number of registers participating in this operand. + For S12Z this is always in the range [0, 6] (but for most + instructions it's <= 2). */ + int n_regs; + + /* The participating registers. */ + int regs[6]; +}; + + +/* Decode a single instruction. + OPERATOR, OSIZE, N_OPERANDS and OPERANDS are pointers to + variables which must be provided by the caller. + N_OPERANDS will be incremented by the number of operands read, so + you should assign it to something before calling this function. + OPERANDS must be large enough to contain all operands read + (which may be up to 6). + It is the responsibility of the caller to free all operands + when they are no longer needed. + Returns the number of bytes read. */ +int decode_s12z (enum operator *myoperator, short *osize, + int *n_operands, struct operand **operands, + struct mem_read_abstraction_base *); + + +#endif /* S12Z_OPC_H */ |