-
Notifications
You must be signed in to change notification settings - Fork 234
Add p-ext support with spec v0.94 #257
base: riscv-binutils-experiment
Are you sure you want to change the base?
Changes from all commits
92f414d
45fd911
99cb49a
a638e73
e9818b4
04ede4d
09ef7ea
79182e2
9377740
1b71bd8
e78ce2b
ebd2150
dcfc944
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -64,6 +64,7 @@ enum riscv_csr_class | |
CSR_CLASS_I, | ||
CSR_CLASS_I_32, /* rv32 only */ | ||
CSR_CLASS_F, /* f-ext only */ | ||
CSR_CLASS_P, /* rvp only */ | ||
CSR_CLASS_DEBUG /* debug CSR */ | ||
}; | ||
|
||
|
@@ -131,6 +132,8 @@ static const struct riscv_ext_version ext_version_table[] = | |
{"c", ISA_SPEC_CLASS_20190608, 2, 0}, | ||
{"c", ISA_SPEC_CLASS_2P2, 2, 0}, | ||
|
||
{"p", ISA_SPEC_CLASS_DRAFT, 2, 0}, | ||
|
||
{"zicsr", ISA_SPEC_CLASS_20191213, 2, 0}, | ||
{"zicsr", ISA_SPEC_CLASS_20190608, 2, 0}, | ||
|
||
|
@@ -142,7 +145,10 @@ static const struct riscv_ext_version ext_version_table[] = | |
{"zbb", ISA_SPEC_CLASS_DRAFT, 0, 93}, | ||
{"zba", ISA_SPEC_CLASS_DRAFT, 0, 93}, | ||
{"zbc", ISA_SPEC_CLASS_DRAFT, 0, 93}, | ||
|
||
|
||
{"zpn", ISA_SPEC_CLASS_DRAFT, 2, 0}, | ||
{"zpsf", ISA_SPEC_CLASS_DRAFT, 2, 0}, | ||
{"zbpbo", ISA_SPEC_CLASS_DRAFT, 2, 0}, | ||
/* Terminate the list. */ | ||
{NULL, 0, 0, 0} | ||
}; | ||
|
@@ -340,6 +346,13 @@ riscv_multi_subset_supports (enum riscv_insn_class insn_class) | |
return riscv_subset_supports ("zba"); | ||
case INSN_CLASS_ZBC: | ||
return riscv_subset_supports ("zbc"); | ||
|
||
case INSN_CLASS_ZPN: | ||
return riscv_subset_supports ("zpn"); | ||
case INSN_CLASS_ZPSF: | ||
return riscv_subset_supports ("zpsf"); | ||
case INSN_CLASS_ZBPBO: | ||
return riscv_subset_supports ("zbpbo"); | ||
|
||
default: | ||
as_fatal ("internal: unreachable"); | ||
|
@@ -856,6 +869,10 @@ riscv_csr_address (const char *csr_name, | |
result = riscv_subset_supports ("f"); | ||
need_check_version = FALSE; | ||
break; | ||
case CSR_CLASS_P: | ||
result = riscv_subset_supports ("zpn"); | ||
need_check_version = FALSE; | ||
break; | ||
case CSR_CLASS_DEBUG: | ||
need_check_version = FALSE; | ||
break; | ||
|
@@ -973,6 +990,29 @@ arg_lookup (char **s, const char *const *array, size_t size, unsigned *regnop) | |
return FALSE; | ||
} | ||
|
||
#define RVP_MAX_KEYWORD_LEN 32 | ||
|
||
static bfd_boolean | ||
parse_rvp_field (const char **str, char name[RVP_MAX_KEYWORD_LEN]) | ||
{ | ||
char *p = name; | ||
const char *str_t; | ||
|
||
str_t = *str; | ||
str_t--; | ||
while (ISALNUM (*str_t) || *str_t == '.' || *str_t == '_') | ||
*p++ = *str_t++; | ||
*p = '\0'; | ||
|
||
if (strncmp (name, "nds_", 4) == 0) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is minor, so it is OK here. But once it becomes to one of the stable standard extensions, then I think we should give them new operand names. |
||
{ | ||
*str = str_t; | ||
return TRUE; | ||
} | ||
else | ||
return FALSE; | ||
} | ||
|
||
/* For consistency checking, verify that all bits are specified either | ||
by the match/mask part of the instruction definition, or by the | ||
operand list. The `length` could be 0, 4 or 8, 0 for auto detection. */ | ||
|
@@ -1071,6 +1111,7 @@ validate_riscv_insn (const struct riscv_opcode *opc, int length) | |
case 'Z': /* RS1, CSR number. */ | ||
case 'S': /* RS1, floating point. */ | ||
case 's': USE_BITS (OP_MASK_RS1, OP_SH_RS1); break; | ||
case 'g': /* RS1 and RS2 are the same. */ | ||
case 'U': /* RS1 and RS2 are the same, floating point. */ | ||
USE_BITS (OP_MASK_RS1, OP_SH_RS1); | ||
/* Fall through. */ | ||
|
@@ -1083,6 +1124,7 @@ validate_riscv_insn (const struct riscv_opcode *opc, int length) | |
case 'P': USE_BITS (OP_MASK_PRED, OP_SH_PRED); break; | ||
case 'Q': USE_BITS (OP_MASK_SUCC, OP_SH_SUCC); break; | ||
case 'o': /* ITYPE immediate, load displacement. */ | ||
case 'l': /* IMM6L */ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This looks strange. We encode it as ENCODE_ITYPE_IMM here (validate_riscv_insn), but will use ENCODE_SBTYPE_IMM6L to encode it later in the riscv_ip. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for pointing it out. Fixed it the latest commit. |
||
case 'j': used_bits |= ENCODE_ITYPE_IMM (-1U); break; | ||
case 'a': used_bits |= ENCODE_JTYPE_IMM (-1U); break; | ||
case 'p': used_bits |= ENCODE_BTYPE_IMM (-1U); break; | ||
|
@@ -1118,6 +1160,36 @@ validate_riscv_insn (const struct riscv_opcode *opc, int length) | |
return FALSE; | ||
} | ||
break; | ||
case 'n': | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should renamed the operands eventually. Rename to `p' prefix is more reasonable and easy to understand, just like what vector instructions did, but we already have p operand for another usage. Maybe we can file an issue to discuss the problem. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I checked 'p', 'P', 'r'(for rvp), but they are taken by others. so I used the old prefix 'nds'. It would be great to have a discussion on that. Thanks! |
||
{ | ||
char field_name[RVP_MAX_KEYWORD_LEN]; | ||
if (parse_rvp_field (&p, field_name)) | ||
{ | ||
if (strcmp (field_name, "nds_rdp") == 0) | ||
USE_BITS (OP_MASK_RD, OP_SH_RD); | ||
else if (strcmp (field_name, "nds_rsp") == 0) | ||
USE_BITS (OP_MASK_RD, OP_SH_RS1); | ||
else if (strcmp (field_name, "nds_rtp") == 0) | ||
USE_BITS (OP_MASK_RD, OP_SH_RS2); | ||
else if (strcmp (field_name, "nds_i3u") == 0) | ||
used_bits |= ENCODE_PTYPE_IMM3U (-1U); | ||
else if (strcmp (field_name, "nds_i4u") == 0) | ||
used_bits |= ENCODE_PTYPE_IMM4U (-1U); | ||
else if (strcmp (field_name, "nds_i5u") == 0) | ||
used_bits |= ENCODE_PTYPE_IMM5U (-1U); | ||
else if (strcmp (field_name, "nds_i6u") == 0) | ||
used_bits |= ENCODE_PTYPE_IMM6U (-1U); | ||
else | ||
as_bad (_("internal: bad RISC-V opcode " | ||
"(unknown operand type `%s'): %s %s"), | ||
field_name, opc->name, opc->args); | ||
} | ||
else | ||
as_bad (_("internal: bad RISC-V opcode " | ||
"(unknown operand type `%c'): %s %s"), | ||
c, opc->name, opc->args); | ||
} | ||
break; | ||
default: | ||
as_bad (_("internal: bad RISC-V opcode " | ||
"(unknown operand type `%c'): %s %s"), | ||
|
@@ -2402,6 +2474,17 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr, | |
} | ||
continue; | ||
|
||
case 'l': | ||
my_getExpression (imm_expr, s); | ||
if (imm_expr->X_op != O_constant | ||
|| imm_expr->X_add_number >= xlen | ||
|| imm_expr->X_add_number < 0) | ||
break; | ||
ip->insn_opcode |= ENCODE_ITYPE_IMM6L (imm_expr->X_add_number); | ||
s = expr_end; | ||
imm_expr->X_op = O_absent; | ||
continue; | ||
|
||
case 'm': /* Rounding mode. */ | ||
if (arg_lookup (&s, riscv_rm, ARRAY_SIZE (riscv_rm), ®no)) | ||
{ | ||
|
@@ -2410,6 +2493,81 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr, | |
} | ||
break; | ||
|
||
case 'n': | ||
{ | ||
char field_name[RVP_MAX_KEYWORD_LEN]; | ||
args++; | ||
if (parse_rvp_field (&args, field_name)) | ||
{ | ||
if (strcmp (field_name, "nds_rdp") == 0 | ||
&& reg_lookup (&s, RCLASS_GPR, ®no)) | ||
{ | ||
if (xlen == 32 && (regno % 2) != 0) | ||
{ | ||
as_bad (_("the number of Rd must be even " | ||
"(limitation of register pair)")); | ||
break; | ||
} | ||
INSERT_OPERAND (RD, *ip, regno); | ||
args--; | ||
continue; | ||
} | ||
else if (strcmp (field_name, "nds_rsp") == 0 | ||
&& reg_lookup (&s, RCLASS_GPR, ®no)) | ||
{ | ||
if (xlen == 32 && (regno % 2) != 0) | ||
{ | ||
as_bad (_("the number of Rs1 must be even " | ||
"(limitation of register pair)")); | ||
break; | ||
} | ||
INSERT_OPERAND (RS1, *ip, regno); | ||
args--; | ||
continue; | ||
} | ||
else if (strcmp (field_name, "nds_rtp") == 0 | ||
&& reg_lookup (&s, RCLASS_GPR, ®no)) | ||
{ | ||
if (xlen == 32 && (regno % 2) != 0) | ||
{ | ||
as_bad (_("the number of Rs2 must be even " | ||
"(limitation of register pair)")); | ||
break; | ||
} | ||
INSERT_OPERAND (RS2, *ip, regno); | ||
args--; | ||
continue; | ||
} | ||
|
||
my_getExpression (imm_expr, s); | ||
if (imm_expr->X_op != O_constant | ||
|| imm_expr->X_add_number >= xlen | ||
|| imm_expr->X_add_number < 0) | ||
break; | ||
|
||
if (strcmp (field_name, "nds_i3u") == 0 | ||
&& VALID_PTYPE_IMM3U (imm_expr->X_add_number)) | ||
ip->insn_opcode |= ENCODE_PTYPE_IMM3U (imm_expr->X_add_number); | ||
else if (strcmp (field_name, "nds_i4u") == 0 | ||
&& VALID_PTYPE_IMM4U (imm_expr->X_add_number)) | ||
ip->insn_opcode |= ENCODE_PTYPE_IMM4U (imm_expr->X_add_number); | ||
else if (strcmp (field_name, "nds_i5u") == 0 | ||
&& VALID_PTYPE_IMM5U (imm_expr->X_add_number)) | ||
ip->insn_opcode |= ENCODE_PTYPE_IMM5U (imm_expr->X_add_number); | ||
else if (strcmp (field_name, "nds_i6u") == 0 | ||
&& VALID_PTYPE_IMM6U (imm_expr->X_add_number)) | ||
ip->insn_opcode |= ENCODE_PTYPE_IMM6U (imm_expr->X_add_number); | ||
else | ||
break; | ||
|
||
s = expr_end; | ||
imm_expr->X_op = O_absent; | ||
args--; | ||
continue; | ||
} | ||
break; | ||
} | ||
|
||
case 'P': | ||
case 'Q': /* Fence predecessor/successor. */ | ||
if (arg_lookup (&s, riscv_pred_succ, ARRAY_SIZE (riscv_pred_succ), | ||
|
@@ -2425,6 +2583,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr, | |
|
||
case 'd': /* Destination register. */ | ||
case 's': /* Source register. */ | ||
case 'g': /* RS1 and RS2. */ | ||
case 't': /* Target register. */ | ||
case 'r': /* RS3 */ | ||
if (reg_lookup (&s, RCLASS_GPR, ®no)) | ||
|
@@ -2443,6 +2602,9 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr, | |
case 'd': | ||
INSERT_OPERAND (RD, *ip, regno); | ||
break; | ||
case 'g': | ||
INSERT_OPERAND (RS1, *ip, regno); | ||
/* Fall through. */ | ||
case 't': | ||
INSERT_OPERAND (RS2, *ip, regno); | ||
break; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
#as: -march=rv32gc_zbpbo_zpn_zpsf | ||
#source: insn-dsp-zbpbo.s | ||
#objdump: -d | ||
|
||
.*:[ ]+file format .* | ||
|
||
|
||
Disassembly of section .text: | ||
|
||
0+000 <dsp>: | ||
[ ]+.*:[ ]+.*[ ]+clz[ ]+a1,a2 | ||
[ ]+.*:[ ]+.*[ ]+clz[ ]+a1,a2 | ||
[ ]+.*:[ ]+.*[ ]+cmix[ ]+a1,a2,a3,a4 | ||
[ ]+.*:[ ]+.*[ ]+fsr[ ]+a1,a2,a3,a4 | ||
[ ]+.*:[ ]+.*[ ]+fsri[ ]+a1,a2,a3,0x5 | ||
[ ]+.*:[ ]+.*[ ]+max[ ]+a1,a2,a3 | ||
[ ]+.*:[ ]+.*[ ]+min[ ]+a1,a2,a3 | ||
[ ]+.*:[ ]+.*[ ]+pack[ ]+a1,a2,a3 | ||
[ ]+.*:[ ]+.*[ ]+packu[ ]+a1,a2,a3 | ||
[ ]+.*:[ ]+.*[ ]+pack[ ]+a1,a2,a3 | ||
[ ]+.*:[ ]+.*[ ]+packu[ ]+a1,a2,a3 | ||
[ ]+.*:[ ]+.*[ ]+rev[ ]+a1,a2 | ||
[ ]+.*:[ ]+.*[ ]+rev8.h[ ]+a1,a2 | ||
[ ]+.*:[ ]+.*[ ]+rev8.h[ ]+a1,a2 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
dsp: | ||
clz a1,a2 | ||
clz32 a1,a2 | ||
cmix a1,a2,a3,a4 | ||
fsr a1,a2,a3,a4 | ||
fsri a1,a2,a3,5 | ||
max a1,a2,a3 | ||
min a1,a2,a3 | ||
pack a1,a2,a3 | ||
packu a1,a2,a3 | ||
pktt16 a1,a2,a3 | ||
pkbb16 a1,a2,a3 | ||
rev a1,a2 | ||
rev8.h a1,a2 | ||
swap8 a1,a2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as the g and k expansions, but we don't need to care about this here.