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", ®_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