From 599480418116fb02b14dd3d8fa991c46de4b9f31 Mon Sep 17 00:00:00 2001 From: Daniel Beer Date: Tue, 10 Aug 2010 13:27:35 +1200 Subject: [PATCH] dis: decode extended double-operand instructions. --- cproc_util.c | 2 ++ dis.c | 90 ++++++++++++++++++++++++++++++++++++++-------------- dis.h | 23 ++++++++++++-- 3 files changed, 90 insertions(+), 25 deletions(-) diff --git a/cproc_util.c b/cproc_util.c index 4a4432a..f911549 100644 --- a/cproc_util.c +++ b/cproc_util.c @@ -136,6 +136,8 @@ static int dis_format(stab_t stab, char *buf, int max_len, suffix = ".B"; else if (insn->dsize == MSP430_DSIZE_AWORD) suffix = ".A"; + else if (insn->dsize == MSP430_DSIZE_UNKNOWN) + suffix = ".?"; len = snprintf(buf + total, max_len - total, "\x1b[36m%s%s\x1b[0m", opname, suffix); diff --git a/dis.c b/dis.c index 607ef84..a696a37 100644 --- a/dis.c +++ b/dis.c @@ -26,6 +26,7 @@ #include "util.h" #define ALL_ONES 0xfffff +#define EXTENSION_BIT 0x20000 /**********************************************************************/ /* Disassembler @@ -402,43 +403,72 @@ int dis_decode(const uint8_t *code, address_t offset, address_t len, struct msp430_instruction *insn) { uint16_t op; + uint16_t ex_word = 0; int ret; address_t ds_mask = ALL_ONES; memset(insn, 0, sizeof(*insn)); + insn->offset = offset; + /* Perform decoding */ if (len < 2) return -1; - - insn->offset = offset; op = (code[1] << 8) | code[0]; - if ((op & 0xf000) == 0x1000) - insn->itype = MSP430_ITYPE_SINGLE; - else if ((op & 0xff00) >= 0x2000 && - (op & 0xff00) < 0x4000) - insn->itype = MSP430_ITYPE_JUMP; - else if ((op & 0xf000) >= 0x4000) - insn->itype = MSP430_ITYPE_DOUBLE; - else - return -1; + if ((op & 0xf800) == 0x1800) { + ex_word = op; + code += 2; + offset += 2; + len -= 2; - switch (insn->itype) { - case MSP430_ITYPE_SINGLE: - ret = decode_single(code, offset, len, insn); - break; + if (len < 2) + return -1; + op = (code[1] << 8) | code[0]; - case MSP430_ITYPE_DOUBLE: - ret = decode_double(code, offset, len, insn); - break; + if ((op & 0xff00) >= 0x4000) { + insn->itype = MSP430_ITYPE_DOUBLE; + ret = decode_double(code, offset, len, insn); + insn->op |= EXTENSION_BIT; + } else { + return -1; + } - case MSP430_ITYPE_JUMP: - ret = decode_jump(code, offset, len, insn); - break; + if (insn->dst_mode == MSP430_AMODE_REGISTER && + (insn->itype == MSP430_ITYPE_SINGLE || + insn->src_mode == MSP430_AMODE_REGISTER)) { + insn->zero_carry = (ex_word >> 8) & 1; + insn->rep_register = (ex_word >> 7) & 1; + insn->rep_index = ex_word & 0xf; + } else { + insn->dst_addr |= (ex_word & 0xf) << 16; + insn->src_addr |= ((ex_word >> 6) & 0xf) << 16; + } - default: break; + if (ex_word & 0x40) { + if (insn->dsize == MSP430_DSIZE_BYTE) + insn->dsize = MSP430_DSIZE_AWORD; + else + insn->dsize = MSP430_DSIZE_UNKNOWN; + } + } else { + if ((op & 0xf000) == 0x1000) { + insn->itype = MSP430_ITYPE_SINGLE; + ret = decode_single(code, offset, len, insn); + } else if ((op & 0xff00) >= 0x2000 && + (op & 0xff00) < 0x4000) { + insn->itype = MSP430_ITYPE_JUMP; + ret = decode_jump(code, offset, len, insn); + } else if ((op & 0xf000) >= 0x4000) { + insn->itype = MSP430_ITYPE_DOUBLE; + ret = decode_double(code, offset, len, insn); + } else { + return -1; + } } + /* Interpret "emulated" instructions, constant generation, and + * trim data sizes. + */ find_cgens(insn); find_emulated_ops(insn); @@ -517,7 +547,21 @@ static const struct { {MSP430_OP_SETC, "SETC"}, {MSP430_OP_SETN, "SETN"}, {MSP430_OP_SETZ, "SETZ"}, - {MSP430_OP_TST, "TST"} + {MSP430_OP_TST, "TST"}, + + /* MSP430X double operand */ + {MSP430_OP_MOVX, "MOVX"}, + {MSP430_OP_ADDX, "ADDX"}, + {MSP430_OP_ADDCX, "ADDCX"}, + {MSP430_OP_SUBCX, "SUBCX"}, + {MSP430_OP_SUBX, "SUBX"}, + {MSP430_OP_CMPX, "CMPX"}, + {MSP430_OP_DADDX, "DADDX"}, + {MSP430_OP_BITX, "BITX"}, + {MSP430_OP_BICX, "BICX"}, + {MSP430_OP_BISX, "BISX"}, + {MSP430_OP_XORX, "XORX"}, + {MSP430_OP_ANDX, "ANDX"} }; /* Return the mnemonic for an operation, if possible. */ diff --git a/dis.h b/dis.h index f8aa4f3..e16d498 100644 --- a/dis.h +++ b/dis.h @@ -109,7 +109,8 @@ typedef enum { typedef enum { MSP430_DSIZE_BYTE, MSP430_DSIZE_WORD, - MSP430_DSIZE_AWORD + MSP430_DSIZE_AWORD, + MSP430_DSIZE_UNKNOWN } msp430_dsize_t; /* MSP430 operations. @@ -182,7 +183,21 @@ typedef enum { MSP430_OP_SETC = 0x10014, MSP430_OP_SETN = 0x10015, MSP430_OP_SETZ = 0x10016, - MSP430_OP_TST = 0x10017 + MSP430_OP_TST = 0x10017, + + /* MSP430X double operand */ + MSP430_OP_MOVX = 0x24000, + MSP430_OP_ADDX = 0x25000, + MSP430_OP_ADDCX = 0x26000, + MSP430_OP_SUBCX = 0x27000, + MSP430_OP_SUBX = 0x28000, + MSP430_OP_CMPX = 0x29000, + MSP430_OP_DADDX = 0x2A000, + MSP430_OP_BITX = 0x2B000, + MSP430_OP_BICX = 0x2C000, + MSP430_OP_BISX = 0x2D000, + MSP430_OP_XORX = 0x2E000, + MSP430_OP_ANDX = 0x2F000 } msp430_op_t; /* This represents a decoded instruction. All decoded addresses are @@ -205,6 +220,10 @@ struct msp430_instruction { msp430_amode_t dst_mode; address_t dst_addr; msp430_reg_t dst_reg; + + int rep_index; + int rep_register; + int zero_carry; }; /* Decode a single instruction.