[linux-unicore] [PATCH/binutils] Opcodes backend incomplete implement.

  • From: LIU Zhiyou <liuzhiyou.cs@xxxxxxxxx>
  • To: gxt@xxxxxxxxxxxxxxx, linux-unicore@xxxxxxxxxxxxx
  • Date: Sun, 20 Jan 2013 13:34:13 +0800

All most the same as the last RFC of opcodes. But now we
can check whether the code can pass compilation. It helps
me fix several bugs.
---
 include/opcode/unicore32.h | 156 ++++++++++++++++++++++++++++-
 opcodes/unicore32-dis.c    |  45 ++++++++-
 opcodes/unicore32-opc.c    | 238 ++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 433 insertions(+), 6 deletions(-)

diff --git a/include/opcode/unicore32.h b/include/opcode/unicore32.h
index b5fe8e0..b9477e5 100644
--- a/include/opcode/unicore32.h
+++ b/include/opcode/unicore32.h
@@ -21,6 +21,160 @@
 #ifndef _UNICORE32_H_
 #define _UNICORE32_H
 
-/* Just a stub */
+struct disassemble_info;
 
+typedef enum
+{
+    /* all general purpose registers in UniCore32 */
+    r0, r1, r2, r3,
+    r4, r5, r6, r7,
+    r8, r9, r10, r11,
+    r12, r13, r14, r15,
+    r16, r17, r18, r19,
+    r20, r21, r22, r23,
+    r24, r25, r26, r27,
+    r28, r29, r30, r31,
+    MAX_GPREG,
+    /* UniCore32 processor registers and special registers : */
+    apreg, /* just a stub */
+    MAX_PREG,
+    /* Unicore32 coprocessor registers */
+    acoreg, /* just a stub */
+    MAX_COREG,
+    /* Not a register.  */
+    nullregister,
+    MAX_REG
+} regs;
+
+/* util macros of enum reg */
+#define first_gpreg r0
+#define first_preg apreg
+#define first_coreg acoreg
+#define is_gpreg(x) ((x) >= first_gpreg && (x) < MAX_GPREG)
+#define is_preg(x) ((x) >= first_preg && (x) < MAX_PREG)
+#define is_coreg(x) ((x) >= first_coreg && (x) < MAX_COREG)
+
+
+
+/* Macro for binary literal support */
+/* Helper macros */
+#define HEX__(n) 0x##n##LU
+#define B8__(x) ((x&0x0000000FLU)?1:0) \
++((x&0x000000F0LU)?2:0) \
++((x&0x00000F00LU)?4:0) \
++((x&0x0000F000LU)?8:0) \
++((x&0x000F0000LU)?16:0) \
++((x&0x00F00000LU)?32:0) \
++((x&0x0F000000LU)?64:0) \
++((x&0xF0000000LU)?128:0)
+
+/* User macros */
+#define B8(d) ((unsigned char)B8__(HEX__(d)))
+#define B16(dmsb,dlsb) (((unsigned short)B8(dmsb)<<8) \
++ B8(dlsb))
+#define B32(dmsb,db2,db3,dlsb) (((unsigned long)B8(dmsb)<<24) \
++ ((unsigned long)B8(db2)<<16) \
++ ((unsigned long)B8(db3)<<8) \
++ B8(dlsb))
+
+#define InstField_DEF \
+    InstF(InstField_Opcodes, 4, 25)        \
+    InstF(InstField_S, 1, 24)                  \
+    InstF(InstField_Rn, 5, 19)                    \
+    InstF(InstField_Rd, 5, 14)                       \
+    InstF(InstField_ShiftImm, 5, 9)                    \
+    InstF(InstField_Shift, 2, 6)                       \
+    InstF(InstField_Rm, 5, 0)                          \
+    InstF(InstField_Rs, 5, 9)                            \
+    InstF(InstField_N, 1, 26)                            \
+    InstF(InstField_Cond, 4, 19)                  \
+    InstF(InstField_R, 1, 26)                    \
+    InstF(InstField_A, 1, 25)                       \
+    InstF(InstField_U, 1, 26)                            \
+    InstF(InstField_RdLo, 5,14)                       \
+    InstF(InstField_RdHi, 5, 9)                          \
+    InstF(InstField_Z, 1, 26)                            \
+    InstF(InstField_Rotate, 5, 9)                          \
+    InstF(InstField_Imm9, 9, 0)                          \
+    InstF(InstField_B, 1, 26)                            \
+    InstF(InstField_P, 1, 28)                            \
+    InstF(InstField_W, 1, 25)                            \
+    InstF(InstField_L, 1, 24)                            \
+    InstF(InstField_Imm14, 14, 0)                          \
+    InstF(InstField_hRlist, 10, 9)                            \
+    InstF(InstField_lRlist, 6, 0)                            \
+    InstF(InstField_H, 1, 6)                            \
+    InstF(InstField_hOff10, 5, 9)                            \
+    InstF(InstField_lOff10, 5, 0)                            \
+    InstF(InstField_hX, 20, 9)                          \
+    InstF(InstField_lX, 0, 8)                            \
+    InstF(InstField_sOff24, 24, 0)                            \
+    InstF(InstField_CRd, 5, 14)                            \
+    InstF(InstField_Cp_num, 5, 9)                            \
+    InstF(InstField_Off10, 10, 0)                            \
+    InstF(InstField_8Rlist, 8, 0)                           \
+    InstF(InstField_DPOp1, 4, 24)                            \
+    InstF(InstField_CRn, 5, 19)                            \
+    InstF(InstField_Op2, 4, 6)                             \
+    InstF(InstField_CRm, 5, 0)                           \
+    InstF(InstField_RTOp1, 3, 25)                            \
+    InstF(InstField_STnum, 24, 0)
+
+typedef enum {
+#define InstF(name, width, offset) name,
+InstField_DEF
+#undef InstF
+} inst_fields;
+
+extern short inst_width[];
+extern short inst_offset[];
+extern long inst_mask[];
+
+#define MAX_ARG 4
+
+struct _inst;
+typedef struct _inst inst;
+struct _argument;
+typedef struct _argument argument;
+struct _argument_type;
+typedef struct _argument_type argument_type;
+struct _argument{
+    union {
+        regs areg;
+        unsigned long uimm;
+        unsigned long raw;
+    } ucontent;
+    long scontent;
+    argument_type* type;
+};
+
+struct _argument_type{
+    void (*init)(inst *, argument*);
+    /* field1 and field2 are in fact init's argument, */
+    inst_fields field1, field2;
+    void (*print_arg)(inst *, argument *, struct disassemble_info *);
+};
+
+typedef struct {
+    char *prefix;
+    /***
+     * (inst.raw & mask) == expect should be true
+     * if and only if inst is belong to such inst_type;
+     ***/
+    unsigned long mask;
+    unsigned long expect;
+    void (*print)(inst *, struct disassemble_info *);
+    argument_type args[MAX_ARG];
+} inst_type;
+
+struct _inst{
+    unsigned long raw;
+    const inst_type  *type;
+    argument args[MAX_ARG];
+};
+
+
+
+extern inst_type inst_types[];
+extern const long NUMINST;
 #endif
diff --git a/opcodes/unicore32-dis.c b/opcodes/unicore32-dis.c
index 6cba4e3..924cda0 100644
--- a/opcodes/unicore32-dis.c
+++ b/opcodes/unicore32-dis.c
@@ -25,10 +25,47 @@
 
 #define ILLEGAL  "illegal"
 
-/* stub */
+/* Retrieve a single word from a given memory address.  */
+static unsigned long
+get_word_at (bfd_vma memaddr, struct disassemble_info *info)
+{
+    bfd_byte buffer[4];
+    int status;
+    unsigned long insn = 0;
+
+    status = info->read_memory_func (memaddr, buffer, 4, info);
+
+    if (status == 0)
+        insn = (unsigned long) bfd_getl32 (buffer);
+
+    return insn;
+}
+
 int
-print_insn_unicore32 (bfd_vma memaddr ATTRIBUTE_UNUSED,
-                      struct disassemble_info *info ATTRIBUTE_UNUSED)
+print_insn_unicore32 (bfd_vma memaddr, struct disassemble_info *info)
 {
-    return 0;
+    unsigned long raw = get_word_at(memaddr, info);
+  
+    int i = 0, j;
+    for (i = 0; i < NUMINST; i++) 
+        if ((inst_types[i].mask & raw) == inst_types[i].expect) {
+            /* Initialize */
+            inst ainst; 
+            ainst.raw = raw;
+            ainst.type = inst_types+i;
+            for (j = 0; j < MAX_ARG && ainst.type->args[j].init; j++)
+                ainst.type->args[j].init(&ainst, ainst.args+j);
+            
+            /* Disassembler */
+            ainst.type->print(&ainst, info);
+            for (j = 0; j < MAX_ARG && ainst.type->args[j].init; j++) {
+                info->fprintf_func(info->stream, " ");
+                ainst.type->args[j].print_arg(&ainst, &ainst.args[j], info);
+            }
+            return 0;
+        }
+
+    /* No match found.  */
+    info->fprintf_func (info->stream,"%s ",ILLEGAL);
+    return 2;
 }
diff --git a/opcodes/unicore32-opc.c b/opcodes/unicore32-opc.c
index 087949a..e417e6a 100644
--- a/opcodes/unicore32-opc.c
+++ b/opcodes/unicore32-opc.c
@@ -23,4 +23,240 @@
 #include "opcode/unicore32.h"
 #include "libiberty.h"
 
-/* Just a stub */
+short inst_width[] = {
+#define InstF(name, width, offset)    width,
+
+InstField_DEF
+
+#undef InstF
+};
+
+short inst_offset[] = {
+#define InstF(name, width, offset)    offset,
+
+InstField_DEF
+
+#undef InstF
+};
+
+long inst_mask[] =     {
+#define InstF(name, width, offset)    ((1 << width) - 1)  << offset,
+InstField_DEF
+#undef InstF    
+};
+    
+static unsigned long get_inst_field(inst const *ainst, inst_fields field) {
+    return (ainst->raw >> inst_offset[field]) &
+        ((1UL << inst_width[field]) - 1UL);
+}
+
+static long u2s(unsigned long us, short width) {
+    return us | (-1L ^ ((1L << width) -1 ));
+}
+
+static void init_singlefield(inst *ainst, argument* arg) {
+    arg->ucontent.raw = get_inst_field(ainst, arg->type->field1);
+    arg->scontent = u2s(arg->ucontent.raw, inst_width[arg->type->field1]);
+    return ;
+}
+
+static void init_combinefield(inst *ainst, argument* arg) {
+    unsigned long field_content = get_inst_field(ainst, arg->type->field1);
+    field_content <<= inst_width[arg->type->field2];
+    field_content |= get_inst_field(ainst, arg->type->field2);
+    arg->ucontent.raw = field_content;
+    arg->scontent = u2s(arg->ucontent.raw,
+                       inst_width[arg->type->field1]+
+                       inst_width[arg->type->field2]);
+    return ;
+}
+
+/***
+ * print argument as regard register
+ * TODO: Make it better
+ ***/
+static void print_arg_r(inst *ainst ATTRIBUTE_UNUSED,
+                        argument *arg,
+                        struct disassemble_info *info) {
+    PTR stream = info->stream;
+    fprintf_ftype func = info->fprintf_func;
+    func(stream, "r%d", (int)arg->ucontent.areg);
+}
+
+
+
+/***
+ * print argument as shift imm5.
+ * in type: D_Imm_Shift, M_Imm_Shift
+ ***/
+static void print_arg_shiftimm(inst *ainst ATTRIBUTE_UNUSED,
+                               argument *arg,
+                               struct disassemble_info *info) {
+    PTR stream = info->stream;
+    fprintf_ftype func = info->fprintf_func;
+    char const * shift_map[] = {"<<", ">>", "|>", "<>"};
+    unsigned long shift = get_inst_field(ainst, InstField_Shift);
+    func(stream, "%s #%lu", shift_map[shift], arg->ucontent.uimm);
+}
+
+/***
+ * shift with a register
+ * in type: D_Reg_Shift, M_Reg_Shift
+ ***/
+static void print_arg_shiftr(inst *ainst, argument *arg, struct 
disassemble_info *info) {
+    PTR stream = info->stream;
+    fprintf_ftype func = info->fprintf_func;
+    char const * shift_map[] = {"<<", ">>", "|>", "<>"};
+    unsigned long shift = get_inst_field(ainst, InstField_Shift);
+    func(stream, "%s r%d", shift_map[shift], arg->ucontent.areg);
+}
+
+/***
+ * imm in inst with field `rotate', signed
+ * in type: D_Immediate, MvToStFlag
+ ***/
+static void print_arg_rotateimm(inst *ainst ATTRIBUTE_UNUSED,
+                                argument *arg ATTRIBUTE_UNUSED,
+                                struct disassemble_info *info) {
+    PTR stream = info->stream;
+    fprintf_ftype func = info->fprintf_func;
+    /* TODO: stub */
+    func(stream, "Just a stub");
+}
+
+/***
+ * unsigned imm
+ ***/
+static void print_arg_uimm(inst *ainst  ATTRIBUTE_UNUSED,
+                           argument *arg,
+                           struct disassemble_info *info) {
+    PTR stream = info->stream;
+    fprintf_ftype func = info->fprintf_func;
+    unsigned long uimm = arg->ucontent.uimm;
+    func(stream, "#%lu", uimm);
+}
+
+/***
+ * signed imm, for example, imm14 on L/S instructions
+ ***/
+static void print_arg_simm(inst *ainst ATTRIBUTE_UNUSED,
+                           argument *arg,
+                           struct disassemble_info *info) {
+    PTR stream = info->stream;
+    fprintf_ftype func = info->fprintf_func;
+    func(stream, "#%ld", arg->scontent);
+}
+
+
+/***
+ * register as address base
+ * in type: L/S instructions
+ ***/
+static void print_arg_rbase(inst *ainst, argument *arg, struct 
disassemble_info *info) {
+    PTR stream = info->stream;
+    fprintf_ftype func = info->fprintf_func;
+    regs rbase = arg->ucontent.areg;
+    char *fmt[] = {"[r%d]%c, [r%d%c]"};
+    char op[] = {'-', '+'};
+    func(stream, fmt[get_inst_field(ainst, InstField_P)],
+         rbase, op[get_inst_field(ainst, InstField_U)]);
+}
+
+/***
+ * Register List, in L/S multipy
+ */
+static void print_arg_lsmulti(inst *ainst,
+                              argument *arg,
+                              struct disassemble_info *info) {
+    PTR stream = info->stream;
+    fprintf_ftype func = info->fprintf_func;
+    unsigned long reg_bitmap = arg->ucontent.raw;
+    int base = get_inst_field(ainst, InstField_H)? 16 : 0;
+    int first_reg = 1, i;
+    for (i = 0; i < 16; i++) {
+        if (reg_bitmap & (1 << i)) {
+            if (first_reg) 
+                first_reg = 0;
+            else
+                func(stream, " ");
+            func(stream, "r%d", base+i);
+        }
+    }
+}
+
+argument_type noarg = {
+    .init = NULL,
+    .print_arg = NULL,
+};
+
+static void print_inst_arith(inst *ainst, struct disassemble_info *info) {
+    PTR stream = info->stream;
+    fprintf_ftype func = info->fprintf_func;
+    func(stream, "%s", ainst->type->prefix);
+    if (get_inst_field(ainst, InstField_S))
+        func(stream, ".a");
+}
+
+#define SingleField(field) init_singlefield, field, 0
+#define ARG_T(INIT, PRINT) {INIT, PRINT}
+#define ARG_SingleField(field, PRINT) {SingleField(field), PRINT}
+
+inst_type inst_types[] = {
+    
+// for D_Imm_Shift and D_Reg_Shift    
+#define ARITH_INS(prefix, opcodes)                              \
+    { prefix,                                                   \
+      /**/B32(11111111, 00000000, 00000001, 00100000),          \
+      B32(000##opcodes, 00000000, 00000000, 00000000),          \
+      print_inst_arith,                                         \
+      {ARG_SingleField(InstField_Rd, print_arg_r),              \
+       ARG_SingleField(InstField_Rn, print_arg_r),              \
+       ARG_SingleField(InstField_Rm, print_arg_r),              \
+       ARG_SingleField(InstField_ShiftImm, print_arg_shiftimm)  \
+      }                                                         \
+    },                                                          \
+    { prefix,                                                   \
+      /**/B32(11111111, 00000000, 00000001, 00100000),          \
+      B32(000##opcodes, 00000000, 00000001, 00000000),          \
+      print_inst_arith,                                         \
+      {ARG_SingleField(InstField_Rd, print_arg_r),              \
+       ARG_SingleField(InstField_Rn, print_arg_r),              \
+       ARG_SingleField(InstField_Rm, print_arg_r),              \
+       ARG_SingleField(InstField_Rs, print_arg_shiftr)          \
+      }                                                         \
+    }
+    
+    ARITH_INS("and", 00000),
+    ARITH_INS("xor", 00001),
+    ARITH_INS("sub", 00010),
+    ARITH_INS("rsub", 00011),
+    ARITH_INS("add", 00100),
+    ARITH_INS("addc", 00101),
+    ARITH_INS("subc", 00110),
+    ARITH_INS("rsubc", 00111),
+    ARITH_INS("undefined", 01000),
+    ARITH_INS("undefined", 01001),
+    ARITH_INS("undefined", 01010),
+    ARITH_INS("undefined", 01011),
+    ARITH_INS("or", 01100),
+    ARITH_INS("mov", 01101),
+    ARITH_INS("andn", 01110),
+    ARITH_INS("not", 01111),
+    ARITH_INS("and", 10000),
+    ARITH_INS("xor", 10001),
+    ARITH_INS("sub", 10010),
+    ARITH_INS("rsub", 10011),
+    ARITH_INS("add", 10100),
+    ARITH_INS("addc", 10101),
+    ARITH_INS("subc", 10110),
+    ARITH_INS("rsubc", 10111),
+    ARITH_INS("undefined", 11000),
+    ARITH_INS("undefined", 11001),
+    ARITH_INS("undefined", 11010),
+    ARITH_INS("undefined", 11011),
+    ARITH_INS("or", 11100),
+    ARITH_INS("mov", 11101),
+    ARITH_INS("andn", 11110),
+    ARITH_INS("not", 11111),
+};
+const long NUMINST = ARRAY_SIZE(inst_types);
-- 
1.8.1.1


Other related posts:

  • » [linux-unicore] [PATCH/binutils] Opcodes backend incomplete implement. - LIU Zhiyou