RISC-V: Add .insn support.

gas/ChangeLog
	2018-03-07  Kito Cheng  <kito.cheng@gmail.com>
	* config/tc-riscv.c (opcode_name_list): New.
	(opcode_names_hash): Likewise.
	(init_opcode_names_hash): Likewise.
	(opcode_name_lookup): Likewise.
	(validate_riscv_insn): New argument length, and add new format
	which used in .insn directive.
	(md_begin): Refine hash table initialization logic into
	init_opcode_hash.
	(init_opcode_hash): New.
	(my_getOpcodeExpression): Parse opcode name for .insn.
	(riscv_ip): New argument hash, able to handle .insn directive.
	(s_riscv_insn): Handler for .insn directive.
	(riscv_pseudo_table): New entry for .insn.
	* doc/c-riscv.texi: Add documentation for .insn directive.
	* testsuite/gas/riscv/insn.d: Add testcase for .insn directive.
	* testsuite/gas/riscv/insn.s: Likewise.

	include/ChangeLog
	2018-03-07  Kito Cheng  <kito.cheng@gmail.com>
	* opcode/riscv.h (OP_MASK_FUNCT3): New.
	(OP_SH_FUNCT3): Likewise.
	(OP_MASK_FUNCT7): Likewise.
	(OP_SH_FUNCT7): Likewise.
	(OP_MASK_OP2): Likewise.
	(OP_SH_OP2): Likewise.
	(OP_MASK_CFUNCT4): Likewise.
	(OP_SH_CFUNCT4): Likewise.
	(OP_MASK_CFUNCT3): Likewise.
	(OP_SH_CFUNCT3): Likewise.
	(riscv_insn_types): Likewise.

	opcodes/ChangeLog
	2018-03-07  Kito Cheng  <kito.cheng@gmail.com>
	* riscv-opc.c (riscv_insn_types): New.
This commit is contained in:
Jim Wilson 2018-03-14 16:04:03 -07:00
parent 3ae9ce5dd7
commit 0e35537d75
7 changed files with 786 additions and 27 deletions

View File

@ -1,3 +1,22 @@
2018-03-14 Kito Cheng <kito.cheng@gmail.com>
* config/tc-riscv.c (opcode_name_list): New.
(opcode_names_hash): Likewise.
(init_opcode_names_hash): Likewise.
(opcode_name_lookup): Likewise.
(validate_riscv_insn): New argument length, and add new format
which used in .insn directive.
(md_begin): Refine hash table initialization logic into
init_opcode_hash.
(init_opcode_hash): New.
(my_getOpcodeExpression): Parse opcode name for .insn.
(riscv_ip): New argument hash, able to handle .insn directive.
(s_riscv_insn): Handler for .insn directive.
(riscv_pseudo_table): New entry for .insn.
* doc/c-riscv.texi: Add documentation for .insn directive.
* testsuite/gas/riscv/insn.d: Add testcase for .insn directive.
* testsuite/gas/riscv/insn.s: Likewise.
2018-03-13 Nick Clifton <nickc@redhat.com> 2018-03-13 Nick Clifton <nickc@redhat.com>
* po/ru.po: Updated Russian translation. * po/ru.po: Updated Russian translation.

View File

@ -221,6 +221,9 @@ riscv_set_arch (const char *s)
/* Handle of the OPCODE hash table. */ /* Handle of the OPCODE hash table. */
static struct hash_control *op_hash = NULL; static struct hash_control *op_hash = NULL;
/* Handle of the type of .insn hash table. */
static struct hash_control *insn_type_hash = NULL;
/* This array holds the chars that always start a comment. If the /* This array holds the chars that always start a comment. If the
pre-processor is disabled, these aren't very useful */ pre-processor is disabled, these aren't very useful */
const char comment_chars[] = "#"; const char comment_chars[] = "#";
@ -391,6 +394,111 @@ relaxed_branch_length (fragS *fragp, asection *sec, int update)
return length; return length;
} }
/* Information about an opcode name, mnemonics and its value. */
struct opcode_name_t
{
const char *name;
unsigned int val;
};
/* List for all supported opcode name. */
static const struct opcode_name_t opcode_name_list[] =
{
{"C0", 0x0},
{"C1", 0x1},
{"C2", 0x2},
{"LOAD", 0x03},
{"LOAD_FP", 0x07},
{"CUSTOM_0", 0x0b},
{"MISC_MEM", 0x0f},
{"OP_IMM", 0x13},
{"AUIPC", 0x17},
{"OP_IMM_32", 0x1b},
/* 48b 0x1f. */
{"STORE", 0x23},
{"STORE_FP", 0x27},
{"CUSTOM_1", 0x2b},
{"AMO", 0x2f},
{"OP", 0x33},
{"LUI", 0x37},
{"OP_32", 0x3b},
/* 64b 0x3f. */
{"MADD", 0x43},
{"MSUB", 0x47},
{"NMADD", 0x4f},
{"NMSUB", 0x4b},
{"OP_FP", 0x53},
/*reserved 0x57. */
{"CUSTOM_2", 0x5b},
/* 48b 0x5f. */
{"BRANCH", 0x63},
{"JALR", 0x67},
/*reserved 0x5b. */
{"JAL", 0x6f},
{"SYSTEM", 0x73},
/*reserved 0x77. */
{"CUSTOM_3", 0x7b},
/* >80b 0x7f. */
{NULL, 0}
};
/* Hash table for lookup opcode name. */
static struct hash_control *opcode_names_hash = NULL;
/* Initialization for hash table of opcode name. */
static void
init_opcode_names_hash (void)
{
const char *retval;
const struct opcode_name_t *opcode;
for (opcode = &opcode_name_list[0]; opcode->name != NULL; ++opcode)
{
retval = hash_insert (opcode_names_hash, opcode->name, (void *)opcode);
if (retval != NULL)
as_fatal (_("internal error: can't hash `%s': %s"),
opcode->name, retval);
}
}
/* Find `s` is a valid opcode name or not,
return the opcode name info if found. */
static const struct opcode_name_t *
opcode_name_lookup (char **s)
{
char *e;
char save_c;
struct opcode_name_t *o;
/* Find end of name. */
e = *s;
if (is_name_beginner (*e))
++e;
while (is_part_of_name (*e))
++e;
/* Terminate name. */
save_c = *e;
*e = '\0';
o = (struct opcode_name_t *) hash_find (opcode_names_hash, *s);
/* Advance to next token if one was recognized. */
if (o)
*s = e;
*e = save_c;
expr_end = e;
return o;
}
struct regname struct regname
{ {
const char *name; const char *name;
@ -488,15 +596,24 @@ arg_lookup (char **s, const char *const *array, size_t size, unsigned *regnop)
/* For consistency checking, verify that all bits are specified either /* For consistency checking, verify that all bits are specified either
by the match/mask part of the instruction definition, or by the by the match/mask part of the instruction definition, or by the
operand list. */ operand list.
`length` could be 0, 4 or 8, 0 for auto detection. */
static bfd_boolean static bfd_boolean
validate_riscv_insn (const struct riscv_opcode *opc) validate_riscv_insn (const struct riscv_opcode *opc, int length)
{ {
const char *p = opc->args; const char *p = opc->args;
char c; char c;
insn_t used_bits = opc->mask; insn_t used_bits = opc->mask;
int insn_width = 8 * riscv_insn_length (opc->match); int insn_width;
insn_t required_bits = ~0ULL >> (64 - insn_width); insn_t required_bits;
if (length == 0)
insn_width = 8 * riscv_insn_length (opc->match);
else
insn_width = 8 * length;
required_bits = ~0ULL >> (64 - insn_width);
if ((used_bits & opc->match) != (opc->match & required_bits)) if ((used_bits & opc->match) != (opc->match & required_bits))
{ {
@ -536,8 +653,22 @@ validate_riscv_insn (const struct riscv_opcode *opc)
case 'V': USE_BITS (OP_MASK_CRS2, OP_SH_CRS2); break; case 'V': USE_BITS (OP_MASK_CRS2, OP_SH_CRS2); break;
case '<': used_bits |= ENCODE_RVC_IMM (-1U); break; case '<': used_bits |= ENCODE_RVC_IMM (-1U); break;
case '>': used_bits |= ENCODE_RVC_IMM (-1U); break; case '>': used_bits |= ENCODE_RVC_IMM (-1U); break;
case '8': used_bits |= ENCODE_RVC_UIMM8 (-1U); break;
case 'S': USE_BITS (OP_MASK_CRS1S, OP_SH_CRS1S); break;
case 'T': USE_BITS (OP_MASK_CRS2, OP_SH_CRS2); break; case 'T': USE_BITS (OP_MASK_CRS2, OP_SH_CRS2); break;
case 'D': USE_BITS (OP_MASK_CRS2S, OP_SH_CRS2S); break; case 'D': USE_BITS (OP_MASK_CRS2S, OP_SH_CRS2S); break;
case 'F': /* funct */
switch (c = *p++)
{
case '4': USE_BITS (OP_MASK_CFUNCT4, OP_SH_CFUNCT4); break;
case '3': USE_BITS (OP_MASK_CFUNCT3, OP_SH_CFUNCT3); break;
default:
as_bad (_("internal: bad RISC-V opcode"
" (unknown operand type `CF%c'): %s %s"),
c, opc->name, opc->args);
return FALSE;
}
break;
default: default:
as_bad (_("internal: bad RISC-V opcode (unknown operand type `C%c'): %s %s"), as_bad (_("internal: bad RISC-V opcode (unknown operand type `C%c'): %s %s"),
c, opc->name, opc->args); c, opc->name, opc->args);
@ -562,6 +693,7 @@ validate_riscv_insn (const struct riscv_opcode *opc)
case 'm': USE_BITS (OP_MASK_RM, OP_SH_RM); break; case 'm': USE_BITS (OP_MASK_RM, OP_SH_RM); break;
case 's': USE_BITS (OP_MASK_RS1, OP_SH_RS1); break; case 's': USE_BITS (OP_MASK_RS1, OP_SH_RS1); break;
case 't': USE_BITS (OP_MASK_RS2, OP_SH_RS2); break; case 't': USE_BITS (OP_MASK_RS2, OP_SH_RS2); break;
case 'r': USE_BITS (OP_MASK_RS3, OP_SH_RS3); break;
case 'P': USE_BITS (OP_MASK_PRED, OP_SH_PRED); break; case 'P': USE_BITS (OP_MASK_PRED, OP_SH_PRED); break;
case 'Q': USE_BITS (OP_MASK_SUCC, OP_SH_SUCC); break; case 'Q': USE_BITS (OP_MASK_SUCC, OP_SH_SUCC); break;
case 'o': case 'o':
@ -574,6 +706,31 @@ validate_riscv_insn (const struct riscv_opcode *opc)
case '[': break; case '[': break;
case ']': break; case ']': break;
case '0': break; case '0': break;
case 'F': /* funct */
switch (c = *p++)
{
case '7': USE_BITS (OP_MASK_FUNCT7, OP_SH_FUNCT7); break;
case '3': USE_BITS (OP_MASK_FUNCT3, OP_SH_FUNCT3); break;
case '2': USE_BITS (OP_MASK_FUNCT2, OP_SH_FUNCT2); break;
default:
as_bad (_("internal: bad RISC-V opcode"
" (unknown operand type `F%c'): %s %s"),
c, opc->name, opc->args);
return FALSE;
}
break;
case 'O': /* opcode */
switch (c = *p++)
{
case '4': USE_BITS (OP_MASK_OP, OP_SH_OP); break;
case '2': USE_BITS (OP_MASK_OP2, OP_SH_OP2); break;
default:
as_bad (_("internal: bad RISC-V opcode"
" (unknown operand type `F%c'): %s %s"),
c, opc->name, opc->args);
return FALSE;
}
break;
default: default:
as_bad (_("internal: bad RISC-V opcode " as_bad (_("internal: bad RISC-V opcode "
"(unknown operand type `%c'): %s %s"), "(unknown operand type `%c'): %s %s"),
@ -597,52 +754,73 @@ struct percent_op_match
bfd_reloc_code_real_type reloc; bfd_reloc_code_real_type reloc;
}; };
/* This function is called once, at assembler startup time. It should set up /* Common hash table initialization function for
all the tables, etc. that the MD part of the assembler will need. */ instruction and .insn directive. */
static struct hash_control *
void init_opcode_hash (const struct riscv_opcode *opcodes,
md_begin (void) bfd_boolean insn_directive_p)
{ {
int i = 0; int i = 0;
unsigned long mach = xlen == 64 ? bfd_mach_riscv64 : bfd_mach_riscv32; int length;
struct hash_control *hash = hash_new ();
if (! bfd_set_arch_mach (stdoutput, bfd_arch_riscv, mach)) while (opcodes[i].name)
as_warn (_("Could not set architecture and machine"));
op_hash = hash_new ();
while (riscv_opcodes[i].name)
{ {
const char *name = riscv_opcodes[i].name; const char *name = opcodes[i].name;
const char *hash_error = const char *hash_error =
hash_insert (op_hash, name, (void *) &riscv_opcodes[i]); hash_insert (hash, name, (void *) &opcodes[i]);
if (hash_error) if (hash_error)
{ {
fprintf (stderr, _("internal error: can't hash `%s': %s\n"), fprintf (stderr, _("internal error: can't hash `%s': %s\n"),
riscv_opcodes[i].name, hash_error); opcodes[i].name, hash_error);
/* Probably a memory allocation problem? Give up now. */ /* Probably a memory allocation problem? Give up now. */
as_fatal (_("Broken assembler. No assembly attempted.")); as_fatal (_("Broken assembler. No assembly attempted."));
} }
do do
{ {
if (riscv_opcodes[i].pinfo != INSN_MACRO) if (opcodes[i].pinfo != INSN_MACRO)
{ {
if (!validate_riscv_insn (&riscv_opcodes[i])) if (insn_directive_p)
length = ((name[0] == 'c') ? 2 : 4);
else
length = 0; /* Let assembler determine the length. */
if (!validate_riscv_insn (&opcodes[i], length))
as_fatal (_("Broken assembler. No assembly attempted.")); as_fatal (_("Broken assembler. No assembly attempted."));
} }
else
gas_assert (!insn_directive_p);
++i; ++i;
} }
while (riscv_opcodes[i].name && !strcmp (riscv_opcodes[i].name, name)); while (opcodes[i].name && !strcmp (opcodes[i].name, name));
} }
return hash;
}
/* This function is called once, at assembler startup time. It should set up
all the tables, etc. that the MD part of the assembler will need. */
void
md_begin (void)
{
unsigned long mach = xlen == 64 ? bfd_mach_riscv64 : bfd_mach_riscv32;
if (! bfd_set_arch_mach (stdoutput, bfd_arch_riscv, mach))
as_warn (_("Could not set architecture and machine"));
op_hash = init_opcode_hash (riscv_opcodes, FALSE);
insn_type_hash = init_opcode_hash (riscv_insn_types, TRUE);
reg_names_hash = hash_new (); reg_names_hash = hash_new ();
hash_reg_names (RCLASS_GPR, riscv_gpr_names_numeric, NGPR); hash_reg_names (RCLASS_GPR, riscv_gpr_names_numeric, NGPR);
hash_reg_names (RCLASS_GPR, riscv_gpr_names_abi, NGPR); hash_reg_names (RCLASS_GPR, riscv_gpr_names_abi, NGPR);
hash_reg_names (RCLASS_FPR, riscv_fpr_names_numeric, NFPR); hash_reg_names (RCLASS_FPR, riscv_fpr_names_numeric, NFPR);
hash_reg_names (RCLASS_FPR, riscv_fpr_names_abi, NFPR); hash_reg_names (RCLASS_FPR, riscv_fpr_names_abi, NFPR);
opcode_names_hash = hash_new ();
init_opcode_names_hash ();
#define DECLARE_CSR(name, num) hash_reg_name (RCLASS_CSR, #name, num); #define DECLARE_CSR(name, num) hash_reg_name (RCLASS_CSR, #name, num);
#define DECLARE_CSR_ALIAS(name, num) DECLARE_CSR(name, num); #define DECLARE_CSR_ALIAS(name, num) DECLARE_CSR(name, num);
#include "opcode/riscv-opc.h" #include "opcode/riscv-opc.h"
@ -1186,6 +1364,23 @@ my_getSmallExpression (expressionS *ep, bfd_reloc_code_real_type *reloc,
return reloc_index; return reloc_index;
} }
/* Parse opcode name, could be an mnemonics or number. */
static size_t
my_getOpcodeExpression (expressionS *ep, bfd_reloc_code_real_type *reloc,
char *str, const struct percent_op_match *percent_op)
{
const struct opcode_name_t *o = opcode_name_lookup (&str);
if (o != NULL)
{
ep->X_op = O_constant;
ep->X_add_number = o->val;
return 0;
}
return my_getSmallExpression (ep, reloc, str, percent_op);
}
/* Detect and handle implicitly zero load-store offsets. For example, /* Detect and handle implicitly zero load-store offsets. For example,
"lw t0, (t1)" is shorthand for "lw t0, 0(t1)". Return TRUE iff such "lw t0, (t1)" is shorthand for "lw t0, 0(t1)". Return TRUE iff such
an implicit offset was detected. */ an implicit offset was detected. */
@ -1211,7 +1406,7 @@ riscv_handle_implicit_zero_offset (expressionS *ep, const char *s)
static const char * static const char *
riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr, riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
bfd_reloc_code_real_type *imm_reloc) bfd_reloc_code_real_type *imm_reloc, struct hash_control *hash)
{ {
char *s; char *s;
const char *args; const char *args;
@ -1234,7 +1429,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
break; break;
} }
insn = (struct riscv_opcode *) hash_find (op_hash, str); insn = (struct riscv_opcode *) hash_find (hash, str);
argsStart = s; argsStart = s;
for ( ; insn && insn->name && strcmp (insn->name, str) == 0; insn++) for ( ; insn && insn->name && strcmp (insn->name, str) == 0; insn++)
@ -1259,7 +1454,12 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
{ {
if (!insn->match_func (insn, ip->insn_opcode)) if (!insn->match_func (insn, ip->insn_opcode))
break; break;
if (riscv_insn_length (insn->match) == 2 && !riscv_opts.rvc)
/* For .insn, insn->match and insn->mask are 0. */
if (riscv_insn_length ((insn->match == 0 && insn->mask == 0)
? ip->insn_opcode
: insn->match) == 2
&& !riscv_opts.rvc)
break; break;
} }
if (*s != '\0') if (*s != '\0')
@ -1328,6 +1528,15 @@ rvc_imm_done:
break; break;
ip->insn_opcode |= ENCODE_RVC_IMM (imm_expr->X_add_number); ip->insn_opcode |= ENCODE_RVC_IMM (imm_expr->X_add_number);
goto rvc_imm_done; goto rvc_imm_done;
case '8':
if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
|| imm_expr->X_op != O_constant
|| !VALID_RVC_UIMM8 (imm_expr->X_add_number)
|| imm_expr->X_add_number < 0
|| imm_expr->X_add_number >= 256)
break;
ip->insn_opcode |= ENCODE_RVC_UIMM8 (imm_expr->X_add_number);
goto rvc_imm_done;
case 'i': case 'i':
if (my_getSmallExpression (imm_expr, imm_reloc, s, p) if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
|| imm_expr->X_op != O_constant || imm_expr->X_op != O_constant
@ -1457,6 +1666,12 @@ rvc_lui:
goto branch; goto branch;
case 'a': case 'a':
goto jump; goto jump;
case 'S': /* Floating-point RS1 x8-x15. */
if (!reg_lookup (&s, RCLASS_FPR, &regno)
|| !(regno >= 8 && regno <= 15))
break;
INSERT_OPERAND (CRS1S, *ip, regno % 8);
continue;
case 'D': /* Floating-point RS2 x8-x15. */ case 'D': /* Floating-point RS2 x8-x15. */
if (!reg_lookup (&s, RCLASS_FPR, &regno) if (!reg_lookup (&s, RCLASS_FPR, &regno)
|| !(regno >= 8 && regno <= 15)) || !(regno >= 8 && regno <= 15))
@ -1468,6 +1683,45 @@ rvc_lui:
break; break;
INSERT_OPERAND (CRS2, *ip, regno); INSERT_OPERAND (CRS2, *ip, regno);
continue; continue;
case 'F':
switch (*++args)
{
case '4':
if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
|| imm_expr->X_op != O_constant
|| imm_expr->X_add_number < 0
|| imm_expr->X_add_number >= 16)
{
as_bad (_("bad value for funct4 field, "
"value must be 0...15"));
break;
}
INSERT_OPERAND (CFUNCT4, *ip, imm_expr->X_add_number);
imm_expr->X_op = O_absent;
s = expr_end;
continue;
case '3':
if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
|| imm_expr->X_op != O_constant
|| imm_expr->X_add_number < 0
|| imm_expr->X_add_number >= 8)
{
as_bad (_("bad value for funct3 field, "
"value must be 0...7"));
break;
}
INSERT_OPERAND (CFUNCT3, *ip, imm_expr->X_add_number);
imm_expr->X_op = O_absent;
s = expr_end;
continue;
default:
as_bad (_("bad compressed FUNCT field"
" specifier 'CF%c'\n"),
*args);
}
break;
default: default:
as_bad (_("bad RVC field specifier 'C%c'\n"), *args); as_bad (_("bad RVC field specifier 'C%c'\n"), *args);
} }
@ -1561,6 +1815,7 @@ rvc_lui:
case 'd': /* Destination register. */ case 'd': /* Destination register. */
case 's': /* Source register. */ case 's': /* Source register. */
case 't': /* Target register. */ case 't': /* Target register. */
case 'r': /* rs3. */
if (reg_lookup (&s, RCLASS_GPR, &regno)) if (reg_lookup (&s, RCLASS_GPR, &regno))
{ {
c = *args; c = *args;
@ -1580,6 +1835,9 @@ rvc_lui:
case 't': case 't':
INSERT_OPERAND (RS2, *ip, regno); INSERT_OPERAND (RS2, *ip, regno);
break; break;
case 'r':
INSERT_OPERAND (RS3, *ip, regno);
break;
} }
continue; continue;
} }
@ -1712,6 +1970,99 @@ jump:
else else
*imm_reloc = BFD_RELOC_RISCV_CALL; *imm_reloc = BFD_RELOC_RISCV_CALL;
continue; continue;
case 'O':
switch (*++args)
{
case '4':
if (my_getOpcodeExpression (imm_expr, imm_reloc, s, p)
|| imm_expr->X_op != O_constant
|| imm_expr->X_add_number < 0
|| imm_expr->X_add_number >= 128
|| (imm_expr->X_add_number & 0x3) != 3)
{
as_bad (_("bad value for opcode field, "
"value must be 0...127 and "
"lower 2 bits must be 0x3"));
break;
}
INSERT_OPERAND (OP, *ip, imm_expr->X_add_number);
imm_expr->X_op = O_absent;
s = expr_end;
continue;
case '2':
if (my_getOpcodeExpression (imm_expr, imm_reloc, s, p)
|| imm_expr->X_op != O_constant
|| imm_expr->X_add_number < 0
|| imm_expr->X_add_number >= 3)
{
as_bad (_("bad value for opcode field, "
"value must be 0...2"));
break;
}
INSERT_OPERAND (OP2, *ip, imm_expr->X_add_number);
imm_expr->X_op = O_absent;
s = expr_end;
continue;
default:
as_bad (_("bad Opcode field specifier 'O%c'\n"), *args);
}
break;
case 'F':
switch (*++args)
{
case '7':
if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
|| imm_expr->X_op != O_constant
|| imm_expr->X_add_number < 0
|| imm_expr->X_add_number >= 128)
{
as_bad (_("bad value for funct7 field, "
"value must be 0...127"));
break;
}
INSERT_OPERAND (FUNCT7, *ip, imm_expr->X_add_number);
imm_expr->X_op = O_absent;
s = expr_end;
continue;
case '3':
if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
|| imm_expr->X_op != O_constant
|| imm_expr->X_add_number < 0
|| imm_expr->X_add_number >= 8)
{
as_bad (_("bad value for funct3 field, "
"value must be 0...7"));
break;
}
INSERT_OPERAND (FUNCT3, *ip, imm_expr->X_add_number);
imm_expr->X_op = O_absent;
s = expr_end;
continue;
case '2':
if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
|| imm_expr->X_op != O_constant
|| imm_expr->X_add_number < 0
|| imm_expr->X_add_number >= 4)
{
as_bad (_("bad value for funct2 field, "
"value must be 0...3"));
break;
}
INSERT_OPERAND (FUNCT2, *ip, imm_expr->X_add_number);
imm_expr->X_op = O_absent;
s = expr_end;
continue;
default:
as_bad (_("bad FUNCT field specifier 'F%c'\n"), *args);
}
break;
case 'z': case 'z':
if (my_getSmallExpression (imm_expr, imm_reloc, s, p) if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
@ -1746,7 +2097,7 @@ md_assemble (char *str)
expressionS imm_expr; expressionS imm_expr;
bfd_reloc_code_real_type imm_reloc = BFD_RELOC_UNUSED; bfd_reloc_code_real_type imm_reloc = BFD_RELOC_UNUSED;
const char *error = riscv_ip (str, &insn, &imm_expr, &imm_reloc); const char *error = riscv_ip (str, &insn, &imm_expr, &imm_reloc, op_hash);
if (error) if (error)
{ {
@ -2614,6 +2965,40 @@ s_riscv_leb128 (int sign)
return s_leb128 (sign); return s_leb128 (sign);
} }
/* Parse the .insn directive. */
static void
s_riscv_insn (int x ATTRIBUTE_UNUSED)
{
char *str = input_line_pointer;
struct riscv_cl_insn insn;
expressionS imm_expr;
bfd_reloc_code_real_type imm_reloc = BFD_RELOC_UNUSED;
char save_c;
while (!is_end_of_line[(unsigned char) *input_line_pointer])
++input_line_pointer;
save_c = *input_line_pointer;
*input_line_pointer = '\0';
const char *error = riscv_ip (str, &insn, &imm_expr,
&imm_reloc, insn_type_hash);
if (error)
{
as_bad ("%s `%s'", error, str);
}
else
{
gas_assert (insn.insn_mo->pinfo != INSN_MACRO);
append_insn (&insn, &imm_expr, imm_reloc);
}
*input_line_pointer = save_c;
demand_empty_rest_of_line ();
}
/* Pseudo-op table. */ /* Pseudo-op table. */
static const pseudo_typeS riscv_pseudo_table[] = static const pseudo_typeS riscv_pseudo_table[] =
@ -2628,6 +3013,7 @@ static const pseudo_typeS riscv_pseudo_table[] =
{"bss", s_bss, 0}, {"bss", s_bss, 0},
{"uleb128", s_riscv_leb128, 0}, {"uleb128", s_riscv_leb128, 0},
{"sleb128", s_riscv_leb128, 1}, {"sleb128", s_riscv_leb128, 1},
{"insn", s_riscv_insn, 0},
{ NULL, NULL, 0 }, { NULL, NULL, 0 },
}; };

View File

@ -17,6 +17,7 @@
@menu @menu
* RISC-V-Options:: RISC-V Options * RISC-V-Options:: RISC-V Options
* RISC-V-Directives:: RISC-V Directives * RISC-V-Directives:: RISC-V Directives
* RISC-V-Formats:: RISC-V Instruction Formats
@end menu @end menu
@node RISC-V-Options @node RISC-V-Options
@ -148,4 +149,244 @@ opportunistically relax some code sequences, but sometimes this behavior is not
desirable. desirable.
@end table @end table
@cindex INSN directives
@item .insn @var{value}
@itemx .insn @var{value}
This directive permits the numeric representation of an instructions
and makes the assembler insert the operands according to one of the
instruction formats for @samp{.insn} (@ref{RISC-V-Formats}).
For example, the instruction @samp{add a0, a1, a2} could be written as
@samp{.insn r 0x33, 0, 0, a0, a1, a2}.
@end table @end table
@node RISC-V-Formats
@section Instruction Formats
@cindex instruction formats, risc-v
@cindex RISC-V instruction formats
The RISC-V Instruction Set Manual Volume I: User-Level ISA lists 12
instruction formats where some of the formats have multiple variants.
For the @samp{.insn} pseudo directive the assembler recognizes some
of the formats.
Typically, the most general variant of the instruction format is used
by the @samp{.insn} directive.
The following table lists the abbreviations used in the table of
instruction formats:
@display
@multitable @columnfractions .15 .40
@item opcode @tab Unsigned immediate or opcode name for 7-bits opcode.
@item opcode2 @tab Unsigned immediate or opcode name for 2-bits opcode.
@item func7 @tab Unsigned immediate for 7-bits function code.
@item func4 @tab Unsigned immediate for 4-bits function code.
@item func3 @tab Unsigned immediate for 3-bits function code.
@item func2 @tab Unsigned immediate for 2-bits function code.
@item rd @tab Destination register number for operand x, can be GPR or FPR.
@item rd' @tab Destination register number for operand x,
only accept s0-s1, a0-a5, fs0-fs1 and fa0-fa5.
@item rs1 @tab First source register number for operand x, can be GPR or FPR.
@item rs1' @tab First source register number for operand x,
only accept s0-s1, a0-a5, fs0-fs1 and fa0-fa5.
@item rs2 @tab Second source register number for operand x, can be GPR or FPR.
@item rs2' @tab Second source register number for operand x,
only accept s0-s1, a0-a5, fs0-fs1 and fa0-fa5.
@item simm12 @tab Sign-extended 12-bit immediate for operand x.
@item simm20 @tab Sign-extended 20-bit immediate for operand x.
@item simm6 @tab Sign-extended 6-bit immediate for operand x.
@item uimm8 @tab Unsigned 8-bit immediate for operand x.
@item symbol @tab Symbol or lable reference for operand x.
@end multitable
@end display
The following table lists all available opcode name:
@table @code
@item C0
@item C1
@item C2
Opcode space for compressed instructions.
@item LOAD
Opcode space for load instructions.
@item LOAD_FP
Opcode space for floating-point load instructions.
@item STORE
Opcode space for store instructions.
@item STORE_FP
Opcode space for floating-point store instructions.
@item AUIPC
Opcode space for auipc instruction.
@item LUI
Opcode space for lui instruction.
@item BRANCH
Opcode space for branch instructions.
@item JAL
Opcode space for jal instruction.
@item JALR
Opcode space for jalr instruction.
@item OP
Opcode space for ALU instructions.
@item OP_32
Opcode space for 32-bits ALU instructions.
@item OP_IMM
Opcode space for ALU with immediate instructions.
@item OP_IMM_32
Opcode space for 32-bits ALU with immediate instructions.
@item OP_FP
Opcode space for floating-point operation instructions.
@item MADD
Opcode space for madd instruction.
@item MSUB
Opcode space for msub instruction.
@item NMADD
Opcode space for nmadd instruction.
@item NMSUB
Opcode space for msub instruction.
@item AMO
Opcode space for atomic memory operation instructions.
@item MISC_IMM
Opcode space for misc instructions.
@item SYSTEM
Opcode space for system instructions.
@item CUSTOM_0
@item CUSTOM_1
@item CUSTOM_2
@item CUSTOM_3
Opcode space for customize instructions.
@end table
An instruction is two or four bytes in length and must be aligned
on a 2 byte boundary. The first two bits of the instruction specify the
length of the instruction, 00, 01 and 10 indicates a two byte instruction,
11 indicates a four byte instruction.
The following table lists the RISC-V instruction formats that are available
with the @samp{.insn} pseudo directive:
@table @code
@item R type: .insn r opcode, func3, func7, rd, rs1, rs2
@verbatim
+-------+-----+-----+-------+----+-------------+
| func7 | rs2 | rs1 | func3 | rd | opcode |
+-------+-----+-----+-------+----+-------------+
31 25 20 15 12 7 0
@end verbatim
@item R type with 4 register operands: .insn r opcode, func3, func2, rd, rs1, rs2, rs3
@verbatim
+-----+-------+-----+-----+-------+----+-------------+
| rs3 | func2 | rs2 | rs1 | func3 | rd | opcode |
+-----+-------+-----+-----+-------+----+-------------+
31 27 25 20 15 12 7 0
@end verbatim
@item I type: .insn i opcode, func3, rd, rs1, simm12
@verbatim
+-------------+-----+-------+----+-------------+
| simm12 | rs1 | func3 | rd | opcode |
+-------------+-----+-------+----+-------------+
31 20 15 12 7 0
@end verbatim
@item S type: .insn s opcode, func3, rd, rs1, simm12
@verbatim
+--------------+-----+-----+-------+-------------+-------------+
| simm12[11:5] | rs2 | rs1 | func3 | simm12[4:0] | opcode |
+--------------+-----+-----+-------+-------------+-------------+
31 25 20 15 12 7 0
@end verbatim
@item SB type: .insn sb opcode, func3, rd, rs1, symbol
@itemx SB type: .insn sb opcode, func3, rd, simm12(rs1)
@verbatim
+--------------+-----+-----+-------+-------------+-------------+
| simm21[11:5] | rs2 | rs1 | func3 | simm12[4:0] | opcode |
+--------------+-----+-----+-------+-------------+-------------+
31 25 20 15 12 7 0
@end verbatim
@item U type: .insn u opcode, rd, simm20
@verbatim
+---------------------------+----+-------------+
| simm20 | rd | opcode |
+---------------------------+----+-------------+
31 12 7 0
@end verbatim
@item UJ type: .insn uj opcode, rd, symbol
@verbatim
+------------+--------------+------------+---------------+----+-------------+
| simm20[20] | simm20[10:1] | simm20[11] | simm20[19:12] | rd | opcode |
+------------+--------------+------------+---------------+----+-------------+
31 30 21 20 12 7 0
@end verbatim
@item CR type: .insn cr opcode2, func4, rd, rs1
@verbatim
+---------+--------+-----+---------+
| func4 | rd/rs1 | rs2 | opcode2 |
+---------+--------+-----+---------+
15 12 7 2 0
@end verbatim
@item CI type: .insn ci opcode2, func3, rd, simm6
@verbatim
+---------+-----+--------+-----+---------+
| func3 | imm | rd/rs1 | imm | opcode2 |
+---------+-----+--------+-----+---------+
15 13 12 7 2 0
@end verbatim
@item CIW type: .insn ciw opcode2, func3, rd, uimm8
@verbatim
+---------+--------------+-----+---------+
| func3 | imm | rd' | opcode2 |
+---------+--------------+-----+---------+
15 13 7 2 0
@end verbatim
@item CB type: .insn cb opcode2, func3, rs1, symbol
@verbatim
+---------+--------+------+--------+---------+
| func3 | offset | rs1' | offset | opcode2 |
+---------+--------+------+--------+---------+
15 13 10 7 2 0
@end verbatim
@item CJ type: .insn cj opcode2, symbol
@verbatim
+---------+--------------------+---------+
| func3 | jump target | opcode2 |
+---------+--------------------+---------+
15 13 7 2 0
@end verbatim
@end table
For the complete list of all instruction format variants see
The RISC-V Instruction Set Manual Volume I: User-Level ISA.

View File

@ -1,3 +1,17 @@
2018-03-14 Kito Cheng <kito.cheng@gmail.com>
* opcode/riscv.h (OP_MASK_FUNCT3): New.
(OP_SH_FUNCT3): Likewise.
(OP_MASK_FUNCT7): Likewise.
(OP_SH_FUNCT7): Likewise.
(OP_MASK_OP2): Likewise.
(OP_SH_OP2): Likewise.
(OP_MASK_CFUNCT4): Likewise.
(OP_SH_CFUNCT4): Likewise.
(OP_MASK_CFUNCT3): Likewise.
(OP_SH_CFUNCT3): Likewise.
(riscv_insn_types): Likewise.
2018-03-13 Nick Clifton <nickc@redhat.com> 2018-03-13 Nick Clifton <nickc@redhat.com>
PR 22113 PR 22113

View File

@ -77,6 +77,8 @@ static const char * const riscv_pred_succ[16] =
(EXTRACT_RVC_IMM (x) << RISCV_IMM_BITS) (EXTRACT_RVC_IMM (x) << RISCV_IMM_BITS)
#define EXTRACT_RVC_SIMM3(x) \ #define EXTRACT_RVC_SIMM3(x) \
(RV_X(x, 10, 2) | (-RV_X(x, 12, 1) << 2)) (RV_X(x, 10, 2) | (-RV_X(x, 12, 1) << 2))
#define EXTRACT_RVC_UIMM8(x) \
(RV_X(x, 5, 8))
#define EXTRACT_RVC_ADDI4SPN_IMM(x) \ #define EXTRACT_RVC_ADDI4SPN_IMM(x) \
((RV_X(x, 6, 1) << 2) | (RV_X(x, 5, 1) << 3) | (RV_X(x, 11, 2) << 4) | (RV_X(x, 7, 4) << 6)) ((RV_X(x, 6, 1) << 2) | (RV_X(x, 5, 1) << 3) | (RV_X(x, 11, 2) << 4) | (RV_X(x, 7, 4) << 6))
#define EXTRACT_RVC_ADDI16SP_IMM(x) \ #define EXTRACT_RVC_ADDI16SP_IMM(x) \
@ -114,6 +116,8 @@ static const char * const riscv_pred_succ[16] =
ENCODE_RVC_IMM ((x) >> RISCV_IMM_BITS) ENCODE_RVC_IMM ((x) >> RISCV_IMM_BITS)
#define ENCODE_RVC_SIMM3(x) \ #define ENCODE_RVC_SIMM3(x) \
(RV_X(x, 0, 3) << 10) (RV_X(x, 0, 3) << 10)
#define ENCODE_RVC_UIMM8(x) \
(RV_X(x, 0, 8) << 5)
#define ENCODE_RVC_ADDI4SPN_IMM(x) \ #define ENCODE_RVC_ADDI4SPN_IMM(x) \
((RV_X(x, 2, 1) << 6) | (RV_X(x, 3, 1) << 5) | (RV_X(x, 4, 2) << 11) | (RV_X(x, 6, 4) << 7)) ((RV_X(x, 2, 1) << 6) | (RV_X(x, 3, 1) << 5) | (RV_X(x, 4, 2) << 11) | (RV_X(x, 6, 4) << 7))
#define ENCODE_RVC_ADDI16SP_IMM(x) \ #define ENCODE_RVC_ADDI16SP_IMM(x) \
@ -143,6 +147,7 @@ static const char * const riscv_pred_succ[16] =
#define VALID_RVC_IMM(x) (EXTRACT_RVC_IMM(ENCODE_RVC_IMM(x)) == (x)) #define VALID_RVC_IMM(x) (EXTRACT_RVC_IMM(ENCODE_RVC_IMM(x)) == (x))
#define VALID_RVC_LUI_IMM(x) (ENCODE_RVC_LUI_IMM(x) != 0 && EXTRACT_RVC_LUI_IMM(ENCODE_RVC_LUI_IMM(x)) == (x)) #define VALID_RVC_LUI_IMM(x) (ENCODE_RVC_LUI_IMM(x) != 0 && EXTRACT_RVC_LUI_IMM(ENCODE_RVC_LUI_IMM(x)) == (x))
#define VALID_RVC_SIMM3(x) (EXTRACT_RVC_SIMM3(ENCODE_RVC_SIMM3(x)) == (x)) #define VALID_RVC_SIMM3(x) (EXTRACT_RVC_SIMM3(ENCODE_RVC_SIMM3(x)) == (x))
#define VALID_RVC_UIMM8(x) (EXTRACT_RVC_UIMM8(ENCODE_RVC_UIMM8(x)) == (x))
#define VALID_RVC_ADDI4SPN_IMM(x) (EXTRACT_RVC_ADDI4SPN_IMM(ENCODE_RVC_ADDI4SPN_IMM(x)) == (x)) #define VALID_RVC_ADDI4SPN_IMM(x) (EXTRACT_RVC_ADDI4SPN_IMM(ENCODE_RVC_ADDI4SPN_IMM(x)) == (x))
#define VALID_RVC_ADDI16SP_IMM(x) (EXTRACT_RVC_ADDI16SP_IMM(ENCODE_RVC_ADDI16SP_IMM(x)) == (x)) #define VALID_RVC_ADDI16SP_IMM(x) (EXTRACT_RVC_ADDI16SP_IMM(ENCODE_RVC_ADDI16SP_IMM(x)) == (x))
#define VALID_RVC_LW_IMM(x) (EXTRACT_RVC_LW_IMM(ENCODE_RVC_LW_IMM(x)) == (x)) #define VALID_RVC_LW_IMM(x) (EXTRACT_RVC_LW_IMM(ENCODE_RVC_LW_IMM(x)) == (x))
@ -223,8 +228,18 @@ static const char * const riscv_pred_succ[16] =
#define OP_MASK_CSR 0xfff #define OP_MASK_CSR 0xfff
#define OP_SH_CSR 20 #define OP_SH_CSR 20
#define OP_MASK_FUNCT3 0x7
#define OP_SH_FUNCT3 12
#define OP_MASK_FUNCT7 0x7f
#define OP_SH_FUNCT7 25
#define OP_MASK_FUNCT2 0x3
#define OP_SH_FUNCT2 25
/* RVC fields. */ /* RVC fields. */
#define OP_MASK_OP2 0x3
#define OP_SH_OP2 0
#define OP_MASK_CRS2 0x1f #define OP_MASK_CRS2 0x1f
#define OP_SH_CRS2 2 #define OP_SH_CRS2 2
#define OP_MASK_CRS1S 0x7 #define OP_MASK_CRS1S 0x7
@ -232,6 +247,11 @@ static const char * const riscv_pred_succ[16] =
#define OP_MASK_CRS2S 0x7 #define OP_MASK_CRS2S 0x7
#define OP_SH_CRS2S 2 #define OP_SH_CRS2S 2
#define OP_MASK_CFUNCT4 0xf
#define OP_SH_CFUNCT4 12
#define OP_MASK_CFUNCT3 0x7
#define OP_SH_CFUNCT3 13
/* ABI names for selected x-registers. */ /* ABI names for selected x-registers. */
#define X_RA 1 #define X_RA 1
@ -340,5 +360,6 @@ extern const char * const riscv_fpr_names_numeric[NFPR];
extern const char * const riscv_fpr_names_abi[NFPR]; extern const char * const riscv_fpr_names_abi[NFPR];
extern const struct riscv_opcode riscv_opcodes[]; extern const struct riscv_opcode riscv_opcodes[];
extern const struct riscv_opcode riscv_insn_types[];
#endif /* _RISCV_H_ */ #endif /* _RISCV_H_ */

View File

@ -1,3 +1,7 @@
2018-03-14 Kito Cheng <kito.cheng@gmail.com>
* riscv-opc.c (riscv_insn_types): New.
2018-03-13 Nick Clifton <nickc@redhat.com> 2018-03-13 Nick Clifton <nickc@redhat.com>
* po/pt_BR.po: Updated Brazilian Portuguese translation. * po/pt_BR.po: Updated Brazilian Portuguese translation.

View File

@ -741,3 +741,77 @@ const struct riscv_opcode riscv_opcodes[] =
/* Terminate the list. */ /* Terminate the list. */
{0, 0, 0, 0, 0, 0, 0} {0, 0, 0, 0, 0, 0, 0}
}; };
/* Instruction format for .insn directive. */
const struct riscv_opcode riscv_insn_types[] =
{
/* name, isa, operands, match, mask, match_func, pinfo. */
{"r", "I", "O4,F3,F7,d,s,t", 0, 0, match_opcode, 0 },
{"r", "I", "O4,F3,F7,D,s,t", 0, 0, match_opcode, 0 },
{"r", "I", "O4,F3,F7,d,S,t", 0, 0, match_opcode, 0 },
{"r", "I", "O4,F3,F7,D,S,t", 0, 0, match_opcode, 0 },
{"r", "I", "O4,F3,F7,d,s,T", 0, 0, match_opcode, 0 },
{"r", "I", "O4,F3,F7,D,s,T", 0, 0, match_opcode, 0 },
{"r", "I", "O4,F3,F7,d,S,T", 0, 0, match_opcode, 0 },
{"r", "I", "O4,F3,F7,D,S,T", 0, 0, match_opcode, 0 },
{"r", "I", "O4,F3,F2,d,s,t,r", 0, 0, match_opcode, 0 },
{"r", "I", "O4,F3,F2,D,s,t,r", 0, 0, match_opcode, 0 },
{"r", "I", "O4,F3,F2,d,S,t,r", 0, 0, match_opcode, 0 },
{"r", "I", "O4,F3,F2,D,S,t,r", 0, 0, match_opcode, 0 },
{"r", "I", "O4,F3,F2,d,s,T,r", 0, 0, match_opcode, 0 },
{"r", "I", "O4,F3,F2,D,s,T,r", 0, 0, match_opcode, 0 },
{"r", "I", "O4,F3,F2,d,S,T,r", 0, 0, match_opcode, 0 },
{"r", "I", "O4,F3,F2,D,S,T,r", 0, 0, match_opcode, 0 },
{"r", "I", "O4,F3,F2,d,s,t,R", 0, 0, match_opcode, 0 },
{"r", "I", "O4,F3,F2,D,s,t,R", 0, 0, match_opcode, 0 },
{"r", "I", "O4,F3,F2,d,S,t,R", 0, 0, match_opcode, 0 },
{"r", "I", "O4,F3,F2,D,S,t,R", 0, 0, match_opcode, 0 },
{"r", "I", "O4,F3,F2,d,s,T,R", 0, 0, match_opcode, 0 },
{"r", "I", "O4,F3,F2,D,s,T,R", 0, 0, match_opcode, 0 },
{"r", "I", "O4,F3,F2,d,S,T,R", 0, 0, match_opcode, 0 },
{"r", "I", "O4,F3,F2,D,S,T,R", 0, 0, match_opcode, 0 },
{"i", "I", "O4,F3,d,s,j", 0, 0, match_opcode, 0 },
{"i", "I", "O4,F3,D,s,j", 0, 0, match_opcode, 0 },
{"i", "I", "O4,F3,d,S,j", 0, 0, match_opcode, 0 },
{"i", "I", "O4,F3,D,S,j", 0, 0, match_opcode, 0 },
{"i", "I", "O4,F3,d,o(s)", 0, 0, match_opcode, 0 },
{"i", "I", "O4,F3,D,o(s)", 0, 0, match_opcode, 0 },
{"s", "I", "O4,F3,d,o(s)", 0, 0, match_opcode, 0 },
{"s", "I", "O4,F3,D,o(s)", 0, 0, match_opcode, 0 },
{"sb", "I", "O4,F3,s,t,p", 0, 0, match_opcode, 0 },
{"sb", "I", "O4,F3,S,t,p", 0, 0, match_opcode, 0 },
{"sb", "I", "O4,F3,s,T,p", 0, 0, match_opcode, 0 },
{"sb", "I", "O4,F3,S,T,p", 0, 0, match_opcode, 0 },
{"sb", "I", "O4,F3,t,q(s)", 0, 0, match_opcode, 0 },
{"sb", "I", "O4,F3,T,q(s)", 0, 0, match_opcode, 0 },
{"u", "I", "O4,d,u", 0, 0, match_opcode, 0 },
{"u", "I", "O4,D,u", 0, 0, match_opcode, 0 },
{"uj", "I", "O4,d,a", 0, 0, match_opcode, 0 },
{"uj", "I", "O4,D,a", 0, 0, match_opcode, 0 },
{"cr", "C", "O2,CF4,d,CV", 0, 0, match_opcode, 0 },
{"cr", "C", "O2,CF4,D,CV", 0, 0, match_opcode, 0 },
{"cr", "C", "O2,CF4,d,CT", 0, 0, match_opcode, 0 },
{"cr", "C", "O2,CF4,D,CT", 0, 0, match_opcode, 0 },
{"ci", "C", "O2,CF3,d,Co", 0, 0, match_opcode, 0 },
{"ci", "C", "O2,CF3,D,Co", 0, 0, match_opcode, 0 },
{"ciw", "C", "O2,CF3,Ct,C8", 0, 0, match_opcode, 0 },
{"ciw", "C", "O2,CF3,CD,C8", 0, 0, match_opcode, 0 },
{"cb", "C", "O2,CF3,Cs,Cp", 0, 0, match_opcode, 0 },
{"cb", "C", "O2,CF3,CS,Cp", 0, 0, match_opcode, 0 },
{"cj", "C", "O2,CF3,Ca", 0, 0, match_opcode, 0 },
/* Terminate the list. */
{0, 0, 0, 0, 0, 0, 0}
};