[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH 4/5] target-lm32: add simple disassembler
From: |
Blue Swirl |
Subject: |
Re: [Qemu-devel] [PATCH 4/5] target-lm32: add simple disassembler |
Date: |
Sun, 1 Apr 2012 17:17:45 +0000 |
On Sat, Mar 31, 2012 at 18:40, Michael Walle <address@hidden> wrote:
> Because binutils disassembler is based on libopcode, this is a rewrite from
> scratch.
>
> Signed-off-by: Michael Walle <address@hidden>
> ---
> Makefile.objs | 1 +
> configure | 4 +
> dis-asm.h | 3 +
> disas.c | 6 +
> lm32-dis.c | 351
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 5 files changed, 365 insertions(+), 0 deletions(-)
> create mode 100644 lm32-dis.c
>
> diff --git a/Makefile.objs b/Makefile.objs
> index e9842b0..f308b57 100644
> --- a/Makefile.objs
> +++ b/Makefile.objs
> @@ -365,6 +365,7 @@ libdis-$(CONFIG_PPC_DIS) += ppc-dis.o
> libdis-$(CONFIG_S390_DIS) += s390-dis.o
> libdis-$(CONFIG_SH4_DIS) += sh4-dis.o
> libdis-$(CONFIG_SPARC_DIS) += sparc-dis.o
> +libdis-$(CONFIG_LM32_DIS) += lm32-dis.o
>
> ######################################################################
> # trace
> diff --git a/configure b/configure
> index 4ef5ec6..4b3adc9 100755
> --- a/configure
> +++ b/configure
> @@ -3770,6 +3770,10 @@ for i in $ARCH $TARGET_BASE_ARCH ; do
> echo "CONFIG_IA64_DIS=y" >> $config_target_mak
> echo "CONFIG_IA64_DIS=y" >> $libdis_config_mak
> ;;
> + lm32)
> + echo "CONFIG_LM32_DIS=y" >> $config_target_mak
> + echo "CONFIG_LM32_DIS=y" >> $libdis_config_mak
> + ;;
> m68k)
> echo "CONFIG_M68K_DIS=y" >> $config_target_mak
> echo "CONFIG_M68K_DIS=y" >> $libdis_config_mak
> diff --git a/dis-asm.h b/dis-asm.h
> index 4f15fad..3944b3c 100644
> --- a/dis-asm.h
> +++ b/dis-asm.h
> @@ -221,6 +221,8 @@ enum bfd_architecture
> bfd_arch_ia64, /* HP/Intel ia64 */
> #define bfd_mach_ia64_elf64 64
> #define bfd_mach_ia64_elf32 32
> + bfd_arch_lm32, /* Lattice Mico32 */
> +#define bfd_mach_lm32 1
> bfd_arch_last
> };
> #define bfd_mach_s390_31 31
> @@ -404,6 +406,7 @@ int print_insn_crisv32 (bfd_vma,
> disassemble_info*);
> int print_insn_crisv10 (bfd_vma, disassemble_info*);
> int print_insn_microblaze (bfd_vma, disassemble_info*);
> int print_insn_ia64 (bfd_vma, disassemble_info*);
> +int print_insn_lm32 (bfd_vma, disassemble_info*);
>
> #if 0
> /* Fetch the disassembler for a given BFD, if that support is available. */
> diff --git a/disas.c b/disas.c
> index 4945c44..9485824 100644
> --- a/disas.c
> +++ b/disas.c
> @@ -220,6 +220,9 @@ void target_disas(FILE *out, target_ulong code,
> target_ulong size, int flags)
> #elif defined(TARGET_MICROBLAZE)
> disasm_info.mach = bfd_arch_microblaze;
> print_insn = print_insn_microblaze;
> +#elif defined(TARGET_LM32)
> + disasm_info.mach = bfd_mach_lm32;
> + print_insn = print_insn_lm32;
> #else
> fprintf(out, "0x" TARGET_FMT_lx
> ": Asm output not supported on this arch\n", code);
> @@ -421,6 +424,9 @@ void monitor_disas(Monitor *mon, CPUArchState *env,
> #elif defined(TARGET_S390X)
> disasm_info.mach = bfd_mach_s390_64;
> print_insn = print_insn_s390;
> +#elif defined(TARGET_LM32)
> + disasm_info.mach = bfd_mach_lm32;
> + print_insn = print_insn_lm32;
> #else
> monitor_printf(mon, "0x" TARGET_FMT_lx
> ": Asm output not supported on this arch\n", pc);
> diff --git a/lm32-dis.c b/lm32-dis.c
> new file mode 100644
> index 0000000..84a264a
> --- /dev/null
> +++ b/lm32-dis.c
> @@ -0,0 +1,351 @@
> +/*
> + * Simple LatticeMico32 disassembler.
> + *
> + * Copyright (c) 2012 Michael Walle <address@hidden>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library 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
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see
> <http://www.gnu.org/licenses/>.
> + *
> + */
> +
> +#include <stdio.h>
> +#include "dis-asm.h"
> +
> +typedef enum {
> + OP_SRUI = 0, OP_NORI, OP_MULI, OP_SH, OP_LB, OP_SRI, OP_XORI, OP_LH,
> + OP_ANDI, OP_XNORI, OP_LW, OP_LHU, OP_SB, OP_ADDI, OP_ORI, OP_SLI, OP_LBU,
> + OP_BE, OP_BG, OP_BGE, OP_BGEU, OP_BGU, OP_SW, OP_BNE, OP_ANDHI, OP_CMPEI,
> + OP_CMPGI, OP_CMPGEI, OP_CMPGEUI, OP_CMPGUI, OP_ORHI, OP_CMPNEI, OP_SRU,
> + OP_NOR, OP_MUL, OP_DIVU, OP_RCSR, OP_SR, OP_XOR, OP_ILL0, OP_AND,
> OP_XNOR,
> + OP_ILL1, OP_SCALL, OP_SEXTB, OP_ADD, OP_OR, OP_SL, OP_B, OP_MODU, OP_SUB,
> + OP_ILL2, OP_WCSR, OP_ILL3, OP_CALL, OP_SEXTH, OP_BI, OP_CMPE, OP_CMPG,
> + OP_CMPGE, OP_CMPGEU, OP_CMPGU, OP_CALLI, OP_CMPNE,
> +} Lm32Opcode;
> +
> +typedef enum {
> + FMT_INVALID = 0, FMT_RRI5, FMT_RRI16, FMT_IMM26, FMT_LOAD, FMT_STORE,
> + FMT_RRR, FMT_R, FMT_RNR, FMT_CRN, FMT_CNR, FMT_BREAK,
> +} Lm32OpcodeFmt;
> +
> +typedef enum {
> + CSR_IE = 0, CSR_IM, CSR_IP, CSR_ICC, CSR_DCC, CSR_CC, CSR_CFG, CSR_EBA,
> + CSR_DC, CSR_DEBA, CSR_CFG2, CSR_JTX = 0xe, CSR_JRX, CSR_BP0, CSR_BP1,
> + CSR_BP2, CSR_BP3, CSR_WP0 = 0x18, CSR_WP1, CSR_WP2, CSR_WP3,
> +} Lm32CsrNum;
> +
> +typedef struct {
> + int csr;
> + const char *name;
> +} Lm32CsrInfo;
> +
> +static const Lm32CsrInfo lm32_csr_info[] = {
> + {CSR_IE, "ie", },
> + {CSR_IM, "im", },
> + {CSR_IP, "ip", },
> + {CSR_ICC, "icc", },
> + {CSR_DCC, "dcc", },
> + {CSR_CC, "cc", },
> + {CSR_CFG, "cfg", },
> + {CSR_EBA, "eba", },
> + {CSR_DC, "dc", },
> + {CSR_DEBA, "deba", },
> + {CSR_CFG2, "cfg2", },
> + {CSR_JTX, "jtx", },
> + {CSR_JRX, "jrx", },
> + {CSR_BP0, "bp0", },
> + {CSR_BP1, "bp1", },
> + {CSR_BP2, "bp2", },
> + {CSR_BP3, "bp3", },
> + {CSR_WP0, "wp0", },
> + {CSR_WP1, "wp1", },
> + {CSR_WP2, "wp2", },
> + {CSR_WP3, "wp3", },
> +};
> +
> +static const Lm32CsrInfo *find_csr_info(int csr)
> +{
> + const Lm32CsrInfo *info;
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(lm32_csr_info); i++) {
> + info = &lm32_csr_info[i];
> + if (csr == info->csr) {
> + return info;
> + }
> + }
> +
> + return NULL;
> +}
> +
> +typedef struct {
> + int reg;
> + const char *name;
> +} Lm32RegInfo;
> +
> +typedef enum {
> + REG_R0 = 0, REG_R1, REG_R2, REG_R3, REG_R4, REG_R5, REG_R6, REG_R7,
> REG_R8,
> + REG_R9, REG_R10, REG_R11, REG_R12, REG_R13, REG_R14, REG_R15, REG_R16,
> + REG_R17, REG_R18, REG_R19, REG_R20, REG_R21, REG_R22, REG_R23, REG_R24,
> + REG_R25, REG_GP, REG_FP, REG_SP, REG_RA, REG_EA, REG_BA,
> +} Lm32RegNum;
> +
> +static const Lm32RegInfo lm32_reg_info[] = {
> + {REG_R0, "r0", },
> + {REG_R1, "r1", },
> + {REG_R2, "r2", },
> + {REG_R3, "r3", },
> + {REG_R4, "r4", },
> + {REG_R5, "r5", },
> + {REG_R6, "r6", },
> + {REG_R7, "r7", },
> + {REG_R8, "r8", },
> + {REG_R9, "r9", },
> + {REG_R10, "r10", },
> + {REG_R11, "r11", },
> + {REG_R12, "r12", },
> + {REG_R13, "r13", },
> + {REG_R14, "r14", },
> + {REG_R15, "r15", },
Unfortunately these conflict with x86_64 system headers:
CC libdis/lm32-dis.o
/src/qemu/lm32-dis.c:96: error: redeclaration of enumerator 'REG_R8'
/usr/include/sys/ucontext.h:45: note: previous definition of 'REG_R8' was here
/src/qemu/lm32-dis.c:97: error: redeclaration of enumerator 'REG_R9'
/usr/include/sys/ucontext.h:47: note: previous definition of 'REG_R9' was here
etc.
> + {REG_R16, "r16", },
> + {REG_R17, "r17", },
> + {REG_R18, "r18", },
> + {REG_R19, "r19", },
> + {REG_R20, "r20", },
> + {REG_R21, "r21", },
> + {REG_R22, "r22", },
> + {REG_R23, "r23", },
> + {REG_R24, "r24", },
> + {REG_R25, "r25", },
> + {REG_GP, "gp", },
> + {REG_FP, "fp", },
> + {REG_SP, "sp", },
> + {REG_RA, "ra", },
> + {REG_EA, "ea", },
> + {REG_BA, "ba", },
> +};
> +
> +static const Lm32RegInfo *find_reg_info(int reg)
> +{
> + assert(ARRAY_SIZE(lm32_reg_info) == 32);
> + return &lm32_reg_info[reg & 0x1f];
> +}
> +
> +typedef struct {
> + struct {
> + uint32_t code;
> + uint32_t mask;
> + } op;
> + const char *name;
> + const char *args_fmt;
> +} Lm32OpcodeInfo;
> +
> +static const Lm32OpcodeInfo lm32_opcode_info[] = {
> + /* pseudo instructions */
> + {{0x34000000, 0xffffffff}, "nop", NULL},
> + {{0xac000002, 0xffffffff}, "break", NULL},
> + {{0xac000003, 0xffffffff}, "scall", NULL},
> + {{0xc3e00000, 0xffffffff}, "bret", NULL},
> + {{0xc3c00000, 0xffffffff}, "eret", NULL},
> + {{0xc3a00000, 0xffffffff}, "ret", NULL},
> + {{0xa4000000, 0xfc1f07ff}, "not", "%2, %0"},
> + {{0xb8000000, 0xfc1f07ff}, "mv", "%2, %0"},
> + {{0x71e00000, 0xffe00000}, "mvhi", "%1, %u"},
> + {{0x34000000, 0xffe00000}, "mvi", "%1, %s"},
> +
> +#define _O(op) {op << 26, 0x3f << 26}
> + /* regular opcodes */
> + {_O(OP_ADD), "add", "%2, %0, %1" },
> + {_O(OP_ADDI), "addi", "%1, %0, %s" },
> + {_O(OP_AND), "and", "%2, %0, %1" },
> + {_O(OP_ANDHI), "andhi", "%1, %0, %u" },
> + {_O(OP_ANDI), "andi", "%1, %0, %u" },
> + {_O(OP_B), "b", "%0", },
> + {_O(OP_BE), "be", "%1, %0, %r" },
> + {_O(OP_BG), "bg", "%1, %0, %r" },
> + {_O(OP_BGE), "bge", "%1, %0, %r" },
> + {_O(OP_BGEU), "bgeu", "%1, %0, %r" },
> + {_O(OP_BGU), "bgu", "%1, %0, %r" },
> + {_O(OP_BI), "bi", "%R", },
> + {_O(OP_BNE), "bne", "%1, %0, %r" },
> + {_O(OP_CALL), "call", "%0", },
> + {_O(OP_CALLI), "calli", "%R", },
> + {_O(OP_CMPE), "cmpe", "%2, %0, %1" },
> + {_O(OP_CMPEI), "cmpei", "%1, %0, %s" },
> + {_O(OP_CMPG), "cmpg", "%2, %0, %1" },
> + {_O(OP_CMPGE), "cmpge", "%2, %0, %1" },
> + {_O(OP_CMPGEI), "cmpgei", "%1, %0, %s" },
> + {_O(OP_CMPGEU), "cmpgeu", "%2, %0, %1" },
> + {_O(OP_CMPGEUI), "cmpgeui", "%1, %0, %s" },
> + {_O(OP_CMPGI), "cmpgi", "%1, %0, %s" },
> + {_O(OP_CMPGU), "cmpgu", "%2, %0, %1" },
> + {_O(OP_CMPGUI), "cmpgui", "%1, %0, %s" },
> + {_O(OP_CMPNE), "cmpne", "%2, %0, %1" },
> + {_O(OP_CMPNEI), "cmpnei", "%1, %0, %s" },
> + {_O(OP_DIVU), "divu", "%2, %0, %1" },
> + {_O(OP_LB), "lb", "%1, (%0+%s)" },
> + {_O(OP_LBU), "lbu", "%1, (%0+%s)" },
> + {_O(OP_LH), "lh", "%1, (%0+%s)" },
> + {_O(OP_LHU), "lhu", "%1, (%0+%s)" },
> + {_O(OP_LW), "lw", "%1, (%0+%s)" },
> + {_O(OP_MODU), "modu", "%2, %0, %1" },
> + {_O(OP_MULI), "muli", "%1, %0, %s" },
> + {_O(OP_MUL), "mul", "%2, %0, %1" },
> + {_O(OP_NORI), "nori", "%1, %0, %u" },
> + {_O(OP_NOR), "nor", "%2, %0, %1" },
> + {_O(OP_ORHI), "orhi", "%1, %0, %u" },
> + {_O(OP_ORI), "ori", "%1, %0, %u" },
> + {_O(OP_OR), "or", "%2, %0, %1" },
> + {_O(OP_RCSR), "rcsr", "%2, %c", },
> + {_O(OP_SB), "sb", "(%0+%s), %1" },
> + {_O(OP_SEXTB), "sextb", "%2, %0", },
> + {_O(OP_SEXTH), "sexth", "%2, %0", },
> + {_O(OP_SH), "sh", "(%0+%s), %1" },
> + {_O(OP_SLI), "sli", "%1, %0, %h" },
> + {_O(OP_SL), "sl", "%2, %0, %1" },
> + {_O(OP_SRI), "sri", "%1, %0, %h" },
> + {_O(OP_SR), "sr", "%2, %0, %1" },
> + {_O(OP_SRUI), "srui", "%1, %0, %d" },
> + {_O(OP_SRU), "sru", "%2, %0, %s" },
> + {_O(OP_SUB), "sub", "%2, %0, %s" },
> + {_O(OP_SW), "sw", "(%0+%s), %1" },
> + {_O(OP_WCSR), "wcsr", "%c, %1", },
> + {_O(OP_XNORI), "xnori", "%1, %0, %u" },
> + {_O(OP_XNOR), "xnor", "%2, %0, %1" },
> + {_O(OP_XORI), "xori", "%1, %0, %u" },
> + {_O(OP_XOR), "xor", "%2, %0, %1" },
> +#undef _O
> +};
> +
> +static const Lm32OpcodeInfo *find_opcode_info(uint32_t opcode)
> +{
> + const Lm32OpcodeInfo *info;
> + int i;
> + for (i = 0; i < ARRAY_SIZE(lm32_opcode_info); i++) {
> + info = &lm32_opcode_info[i];
> + if ((opcode & info->op.mask) == info->op.code) {
> + return info;
> + }
> + }
> +
> + return NULL;
> +}
> +
> +int print_insn_lm32(bfd_vma memaddr, struct disassemble_info *info)
> +{
> + fprintf_function fprintf_fn = info->fprintf_func;
> + void *stream = info->stream;
> + int rc;
> + uint8_t insn[4];
> + const Lm32OpcodeInfo *opc_info;
> + uint32_t op;
> + const char *args_fmt;
> +
> + rc = info->read_memory_func(memaddr, insn, 4, info);
> + if (rc != 0) {
> + info->memory_error_func(rc, memaddr, info);
> + return -1;
> + }
> +
> + fprintf_fn(stream, "%02x %02x %02x %02x ",
> + insn[0], insn[1], insn[2], insn[3]);
> +
> + op = bfd_getb32(insn);
> + opc_info = find_opcode_info(op);
> + if (opc_info) {
> + fprintf_fn(stream, "%-8s ", opc_info->name);
> + args_fmt = opc_info->args_fmt;
> + while (args_fmt && *args_fmt) {
> + if (*args_fmt == '%') {
> + switch (*(++args_fmt)) {
> + case '0': {
> + uint8_t r0;
> + const char *r0_name;
> + r0 = (op >> 21) & 0x1f;
> + r0_name = find_reg_info(r0)->name;
> + fprintf_fn(stream, "%s", r0_name);
> + break;
> + }
> + case '1': {
> + uint8_t r1;
> + const char *r1_name;
> + r1 = (op >> 16) & 0x1f;
> + r1_name = find_reg_info(r1)->name;
> + fprintf_fn(stream, "%s", r1_name);
> + break;
> + }
> + case '2': {
> + uint8_t r2;
> + const char *r2_name;
> + r2 = (op >> 11) & 0x1f;
> + r2_name = find_reg_info(r2)->name;
> + fprintf_fn(stream, "%s", r2_name);
> + break;
> + }
> + case 'c': {
> + uint8_t csr;
> + const char *csr_name;
> + csr = (op >> 21) & 0x1f;
> + csr_name = find_csr_info(csr)->name;
> + if (csr_name) {
> + fprintf_fn(stream, "%s", csr_name);
> + } else {
> + fprintf_fn(stream, "0x%x", csr);
> + }
> + break;
> + }
> + case 'u': {
> + uint16_t u16;
> + u16 = op & 0xffff;
> + fprintf_fn(stream, "0x%x", u16);
> + break;
> + }
> + case 's': {
> + int16_t s16;
> + s16 = (int16_t)(op & 0xffff);
> + fprintf_fn(stream, "%d", s16);
> + break;
> + }
> + case 'r': {
> + uint32_t rela;
> + rela = memaddr + (((int16_t)(op & 0xffff)) << 2);
> + fprintf_fn(stream, "%x", rela);
> + break;
> + }
> + case 'R': {
> + uint32_t rela;
> + int32_t imm26;
> + imm26 = (int32_t)((op & 0x3ffffff) << 6) >> 4;
> + rela = memaddr + imm26;
> + fprintf_fn(stream, "%x", rela);
> + break;
> + }
> + case 'h': {
> + uint8_t u5;
> + u5 = (op & 0x1f);
> + fprintf_fn(stream, "%d", u5);
> + break;
> + }
> + default:
> + break;
> + }
> + } else {
> + fprintf_fn(stream, "%c", *args_fmt);
> + }
> + args_fmt++;
> + }
> + } else {
> + fprintf_fn(stream, ".word 0x%x", op);
> + }
> +
> + return 4;
> +}
> --
> 1.7.2.5
>
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- Re: [Qemu-devel] [PATCH 4/5] target-lm32: add simple disassembler,
Blue Swirl <=