diff options
author | Nelson Chu <nelson.chu@sifive.com> | 2021-07-15 22:32:18 -0700 |
---|---|---|
committer | Nelson Chu <nelson.chu@sifive.com> | 2021-08-31 12:50:27 +0800 |
commit | a262b82fdbf4cda3b0648b1adc32245ca3f78b7a (patch) | |
tree | 97b55d8f82454d447e1929683c72e127f520b5cf /gas/config | |
parent | ad15549d514afa0602a0c0fca4b3bbf545a3c994 (diff) | |
download | gdb-a262b82fdbf4cda3b0648b1adc32245ca3f78b7a.zip gdb-a262b82fdbf4cda3b0648b1adc32245ca3f78b7a.tar.gz gdb-a262b82fdbf4cda3b0648b1adc32245ca3f78b7a.tar.bz2 |
RISC-V: Extend .insn directive to support hardcode encoding.
The .insn directive can let users use their own instructions, or
some new instruction, which haven't supported in the old binutils.
For example, if users want to use sifive cache instruction, they
cannot just write "cflush.d1.l1" in the assembly code, they should
use ".insn i SYSTEM, 0, x0, x10, -0x40". But the .insn directive
may not easy to use for some cases, and not so friendly to users.
Therefore, I believe most of the users will use ".word 0xfc050073",
to encode the instructions directly, rather than use .insn. But
once we have supported the mapping symbols, the .word directives
are marked as data, so disassembler won't dump them as instructions
as usual. I have discussed this with Kito many times, we all think
extend the .insn direcitve to support the hardcode encoding, is the
easiest way to resolve the problem. Therefore, there are two more
.insn formats are proposed as follows,
(original) .insn <type>, <operand1>, <operand2>, ...
.insn <insn-length>, <value>
.insn <value>
The <type> is string, and the <insn-length> and <value> are constants.
gas/
* config/tc-riscv.c (riscv_ip_hardcode): Similar to riscv_ip,
but assembles an instruction according to the hardcode values
of .insn directive.
* doc/c-riscv.texi: Document two new .insn formats.
* testsuite/gas/riscv/insn-fail.d: New testcases.
* testsuite/gas/riscv/insn-fail.l: Likewise.
* testsuite/gas/riscv/insn-fail.s: Likewise.
* testsuite/gas/riscv/insn.d: Updated.
* testsuite/gas/riscv/insn.s: Likewise.
Diffstat (limited to 'gas/config')
-rw-r--r-- | gas/config/tc-riscv.c | 58 |
1 files changed, 55 insertions, 3 deletions
diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c index bb6b063..1dbc4d8 100644 --- a/gas/config/tc-riscv.c +++ b/gas/config/tc-riscv.c @@ -2900,6 +2900,51 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr, return error; } +/* Similar to riscv_ip, but assembles an instruction according to the + hardcode values of .insn directive. */ + +static const char * +riscv_ip_hardcode (char *str, + struct riscv_cl_insn *ip, + expressionS *imm_expr, + const char *error) +{ + struct riscv_opcode *insn; + insn_t values[2] = {0, 0}; + unsigned int num = 0; + + input_line_pointer = str; + do + { + expression (imm_expr); + if (imm_expr->X_op != O_constant) + { + /* The first value isn't constant, so it should be + .insn <type> <operands>. We have been parsed it + in the riscv_ip. */ + if (num == 0) + return error; + return _("values must be constant"); + } + values[num++] = (insn_t) imm_expr->X_add_number; + } + while (*input_line_pointer++ == ',' && num < 2); + + input_line_pointer--; + if (*input_line_pointer != '\0') + return _("unrecognized values"); + + insn = XNEW (struct riscv_opcode); + insn->match = values[num - 1]; + create_insn (ip, insn); + unsigned int bytes = riscv_insn_length (insn->match); + if (values[num - 1] >> (8 * bytes) != 0 + || (num == 2 && values[0] != bytes)) + return _("value conflicts with instruction length"); + + return NULL; +} + void md_assemble (char *str) { @@ -3891,7 +3936,10 @@ s_riscv_leb128 (int sign) return s_leb128 (sign); } -/* Parse the .insn directive. */ +/* Parse the .insn directive. There are three formats, + Format 1: .insn <type> <operand1>, <operand2>, ... + Format 2: .insn <length>, <value> + Format 3: .insn <value>. */ static void s_riscv_insn (int x ATTRIBUTE_UNUSED) @@ -3912,11 +3960,15 @@ s_riscv_insn (int x ATTRIBUTE_UNUSED) const char *error = riscv_ip (str, &insn, &imm_expr, &imm_reloc, insn_type_hash); - if (error) { - as_bad ("%s `%s'", error, str); + char *save_in = input_line_pointer; + error = riscv_ip_hardcode (str, &insn, &imm_expr, error); + input_line_pointer = save_in; } + + if (error) + as_bad ("%s `%s'", error, str); else { gas_assert (insn.insn_mo->pinfo != INSN_MACRO); |