[linux-unicore] [PATCH binutils] support of ldw/ldb/stw/stb

  • From: LIU Zhiyou <liuzhiyou.cs@xxxxxxxxx>
  • To: gxt@xxxxxxxxxxxxxxx
  • Date: Fri, 15 Feb 2013 14:08:49 +0800

Signed-off-by: LIU Zhiyou <liuzhiyou.cs@xxxxxxxxx>
---
 gas/config/tc-unicore32.c      |  81 +++++++++++++++++++++++++++++++++
 include/opcode/unicore32-opc.h | 101 ++++++++++++++++++++++++++++-------------
 include/opcode/unicore32.h     |   2 +-
 3 files changed, 152 insertions(+), 32 deletions(-)

diff --git a/gas/config/tc-unicore32.c b/gas/config/tc-unicore32.c
index d1bcbb7..9ccc396 100644
--- a/gas/config/tc-unicore32.c
+++ b/gas/config/tc-unicore32.c
@@ -99,6 +99,47 @@ static int assemble_inst_arith(inst *ainst,const inst_type* 
this, char **ops) {
     return 1;
 }
 
+static int assemble_inst_ldst(inst *ainst,
+                              const inst_type* this ATTRIBUTE_UNUSED,
+                              char **ops) {
+    ainst->raw = 0;
+    if (!handle_arguments(ainst, this, ops))
+        return 0;
+    ainst->raw |= this->expect;
+    unsigned long is_post = get_inst_field(ainst, InstField_P);
+    unsigned long w_map[][2] = {
+        {1, 0}, // !is_post
+        {0, 1}  // is_post
+    };
+#define HANDLE_FIELD_W(prefix)                      \
+    if (strstr(ops[0], prefix".w"))                 \
+        set_inst_field(ainst, InstField_W, w_map[is_post][1]);  \
+    else                                            \
+        set_inst_field(ainst, InstField_W, w_map[is_post][0]);  \
+
+    char *found;
+    if ((found = strstr(ops[0], "ldb"))) {
+        set_inst_field(ainst, InstField_B, 1);
+        set_inst_field(ainst, InstField_L, 1);
+        HANDLE_FIELD_W("ldb");
+    } else if ((found = strstr(ops[0], "ldw"))) {
+        set_inst_field(ainst, InstField_B, 0);
+        set_inst_field(ainst, InstField_L, 1);
+        HANDLE_FIELD_W("ldw");
+    } else if ((found = strstr(ops[0], "stb"))) {
+        set_inst_field(ainst, InstField_B, 1);
+        set_inst_field(ainst, InstField_L, 0);
+        HANDLE_FIELD_W("stb");
+    } else if ((found = strstr(ops[0], "stw"))) {
+        set_inst_field(ainst, InstField_B, 0);
+        set_inst_field(ainst, InstField_L, 0);
+        HANDLE_FIELD_W("stw");
+    } else {
+        return 0;
+    }
+    return 1;
+}
+
 static int argfrom_str_r(inst* ainst ATTRIBUTE_UNUSED,
                          argument* arg,
                          int index,
@@ -181,6 +222,46 @@ static int argfrom_str_shiftr(inst* ainst,
     }
 }
 
+static int argfrom_str_uimm(inst* ainst ATTRIBUTE_UNUSED,
+                            argument* arg,
+                            int index,
+                            char** ops) {
+    unsigned long uimm;
+    if (strlen(ops[index+1]) == 0)
+        uimm = 0;
+    else if (sscanf(ops[index+1], "#%lu", &uimm) != 1)
+        return 0;
+    arg->ucontent.uimm = uimm;
+    return 1;
+}
+
+static int argfrom_str_rbase(inst* ainst,
+                              argument* arg,
+                              int index,
+                              char** ops) {
+    unsigned long reg_idx;
+    if (sscanf(ops[index+1], "[r%lu", &reg_idx) != 1)
+        return 0;
+    if (!is_gpreg(reg_idx))
+        return 0;
+    if (endwith(ops[index+1], "+]")) {
+        set_inst_field(ainst, InstField_U, 1);
+        set_inst_field(ainst, InstField_P, 1);
+    } else if (endwith(ops[index+1], "-]")) {
+        set_inst_field(ainst, InstField_U, 0);
+        set_inst_field(ainst, InstField_P, 1);
+    } else if (endwith(ops[index+1], "]+")) {
+        set_inst_field(ainst, InstField_U, 1);
+        set_inst_field(ainst, InstField_P, 0);
+    } else if (endwith(ops[index+1], "]-")) {
+        set_inst_field(ainst, InstField_U, 0);
+        set_inst_field(ainst, InstField_P, 0);
+    } else {
+        return 0;
+    }
+    arg->ucontent.areg = reg_idx;
+    return 1;
+}
 #include "opcode/unicore32-opc.h"
 
 int
diff --git a/include/opcode/unicore32-opc.h b/include/opcode/unicore32-opc.h
index deaf460..f958b53 100644
--- a/include/opcode/unicore32-opc.h
+++ b/include/opcode/unicore32-opc.h
@@ -160,6 +160,36 @@ static void print_arg_shiftr(inst *ainst,
              "%s r%u", shift_map[shift], arg->ucontent.areg);
 }
 
+/***
+ * register as address base
+ * in type: L/S instructions
+ ***/
+static void print_arg_rbase(inst *ainst, argument *arg,
+                            struct disassemble_info *info ATTRIBUTE_UNUSED,
+                            char *output) {
+    regs rbase = arg->ucontent.areg;
+    const char *fmt[] = {"[r%d]%c", "[r%d%c]"};
+    char op[] = {'-', '+'};
+    snprintf(output, PRINT_BUFFER_SIZE,
+             fmt[get_inst_field(ainst, InstField_P)],
+             rbase, op[get_inst_field(ainst, InstField_U)]);
+}
+
+/***
+ * unsigned imm
+ ***/
+static void print_arg_uimm(inst *ainst  ATTRIBUTE_UNUSED,
+                           argument *arg,
+                           struct disassemble_info *info ATTRIBUTE_UNUSED,
+                           char *output) {
+    unsigned long uimm = arg->ucontent.uimm;
+    if (uimm)
+        snprintf(output, PRINT_BUFFER_SIZE,
+                 "#%lu", uimm);
+    else
+        *output = '\0';
+}
+
 #if 0
 /***
  * imm in inst with field `rotate', signed
@@ -174,17 +204,7 @@ static void print_arg_rotateimm(inst *ainst 
ATTRIBUTE_UNUSED,
     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
@@ -198,19 +218,7 @@ static void print_arg_simm(inst *ainst ATTRIBUTE_UNUSED,
 }
 
 
-/***
- * 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
@@ -235,13 +243,7 @@ static void print_arg_lsmulti(inst *ainst,
 }
 #endif
 
-#if 0
-static argument_type noarg = {
-    .from_inst = NULL,
-    .print_arg = NULL,
-    .from_str = NULL,
-};
-#endif
+#define NO_ARG { NULL, NULL, 0, 0, NULL, NULL}
 
 static void print_inst_arith(inst *ainst, struct disassemble_info *info) {
     PTR stream = info->stream;
@@ -251,15 +253,41 @@ static void print_inst_arith(inst *ainst, struct 
disassemble_info *info) {
         func(stream, ".a");
 }
 
+/**
+ * Disassemble ldw/ldb/stw/stb with .u, .w or nothing
+ **/
+static void print_inst_ldst(inst *ainst, struct disassemble_info *info) {
+    PTR stream = info->stream;
+    fprintf_ftype func = info->fprintf_func;
+    unsigned long is_load = get_inst_field(ainst, InstField_L);
+    unsigned long is_write = get_inst_field(ainst, InstField_W);
+    unsigned long is_post = get_inst_field(ainst, InstField_P);
+    unsigned long is_byte = get_inst_field(ainst, InstField_B);
+    if (is_post) {
+        func(stream, "%s%c%s",
+             is_load ? "ld":"st",
+             is_byte ? 'b':'w',
+             is_write ? ".w":"");
+    } else {
+        func(stream, "%s%c%s",
+             is_load ? "ld":"st",
+             is_byte ? 'b':'w',
+             is_write ? ".u":".w");
+    }
+}
+
 /* Remember to add a similar #define here if you
  * add a new argfrom_str_xxx in tc-unicore32.c
  * and use it in inst_types[].
  * Check the head of this file to see why */
 #ifndef TC_UNICORE32_H
 #define assemble_inst_arith NULL
+#define assemble_inst_ldst NULL
 #define argfrom_str_r NULL
 #define argfrom_str_shiftuimm NULL
 #define argfrom_str_shiftr NULL
+#define argfrom_str_uimm NULL
+#define argfrom_str_rbase NULL
 #endif
 
 /* Macro for binary literal support */
@@ -352,6 +380,17 @@ static const inst_type inst_types[] = {
     ARITH_INS("mov", 11101),
     ARITH_INS("andn", 11110),
     ARITH_INS("not", 11111),
+    {"", "ldst-imm14",
+     B32(11100000, 00000000, 00000000, 00000000),
+     B32(01100000, 00000000, 00000000, 00000000),
+     print_inst_ldst,
+     assemble_inst_ldst,
+     {ARG_SingleUField(InstField_Rd, print_arg_r, argfrom_str_r),
+      ARG_SingleUField(InstField_Rn, print_arg_rbase, argfrom_str_rbase),
+      ARG_SingleUField(InstField_Imm14, print_arg_uimm, argfrom_str_uimm),
+      NO_ARG
+     }
+    },
 };
 static const long NUMINST = ARRAY_SIZE(inst_types);
 
diff --git a/include/opcode/unicore32.h b/include/opcode/unicore32.h
index 5f894e3..a108269 100644
--- a/include/opcode/unicore32.h
+++ b/include/opcode/unicore32.h
@@ -79,7 +79,7 @@ typedef enum
     InstF(InstField_Cond, 4, 19)                \
     InstF(InstField_R, 1, 26)                   \
     InstF(InstField_A, 1, 25)                   \
-    InstF(InstField_U, 1, 26)                   \
+    InstF(InstField_U, 1, 27)                   \
     InstF(InstField_RdLo, 5,14)                 \
     InstF(InstField_RdHi, 5, 9)                 \
     InstF(InstField_Z, 1, 26)                   \
-- 
1.8.1.1


Other related posts:

  • » [linux-unicore] [PATCH binutils] support of ldw/ldb/stw/stb - LIU Zhiyou