Last active
September 9, 2021 12:13
-
-
Save linsinan1995/d4ac3f90df65501675abb29998536a0f to your computer and use it in GitHub Desktop.
decbnez
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h | |
index 7eff85b7ea..b0559f9612 100644 | |
--- a/bfd/bfd-in2.h | |
+++ b/bfd/bfd-in2.h | |
@@ -4414,6 +4414,8 @@ number for the SBIC, SBIS, SBI and CBI instructions */ | |
BFD_RELOC_RISCV_SET16, | |
BFD_RELOC_RISCV_SET32, | |
BFD_RELOC_RISCV_32_PCREL, | |
+ BFD_RELOC_RISCV_DECBNEZ, | |
+ BFD_RELOC_RISCV_C_DECBNEZ, | |
/* Renesas RL78 Relocations. */ | |
BFD_RELOC_RL78_NEG8, | |
diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c | |
index ec8a3e73c8..af3a0643ea 100644 | |
--- a/bfd/elfnn-riscv.c | |
+++ b/bfd/elfnn-riscv.c | |
@@ -772,6 +772,8 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, | |
case R_RISCV_JAL: | |
case R_RISCV_BRANCH: | |
+ case R_RISCV_DECBNEZ_BRANCH: | |
+ case R_RISCV_C_DECBNEZ_BRANCH: | |
case R_RISCV_RVC_BRANCH: | |
case R_RISCV_RVC_JUMP: | |
/* In shared libraries and pie, these relocs are known | |
@@ -1657,6 +1659,18 @@ perform_relocation (const reloc_howto_type *howto, | |
value = ENCODE_BTYPE_IMM (value); | |
break; | |
+ case R_RISCV_C_DECBNEZ_BRANCH: | |
+ if (!VALID_ZCE_C_DECBNEZ_IMM (-(long)value)) | |
+ return bfd_reloc_overflow; | |
+ value = ENCODE_ZCE_C_DECBNEZ_IMM (-(long)value); | |
+ break; | |
+ | |
+ case R_RISCV_DECBNEZ_BRANCH: | |
+ if (!VALID_ZCE_DECBNEZ_IMM (value)) | |
+ return bfd_reloc_overflow; | |
+ value = ENCODE_ZCE_DECBNEZ_IMM (value); | |
+ break; | |
+ | |
case R_RISCV_RVC_BRANCH: | |
if (!VALID_CBTYPE_IMM (value)) | |
return bfd_reloc_overflow; | |
@@ -2280,6 +2294,8 @@ riscv_elf_relocate_section (bfd *output_bfd, | |
continue; | |
case R_RISCV_HI20: | |
+ case R_RISCV_DECBNEZ_BRANCH: | |
+ case R_RISCV_C_DECBNEZ_BRANCH: | |
case R_RISCV_BRANCH: | |
case R_RISCV_RVC_BRANCH: | |
case R_RISCV_RVC_LUI: | |
diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c | |
index ed48c9918d..7bd21d3bda 100644 | |
--- a/bfd/elfxx-riscv.c | |
+++ b/bfd/elfxx-riscv.c | |
@@ -871,6 +871,36 @@ static reloc_howto_type howto_table[] = | |
0, /* src_mask */ | |
0xffffffff, /* dst_mask */ | |
FALSE), /* pcrel_offset */ | |
+ | |
+ /* 12-bit PC-relative branch offset. (DECBNEZ) */ | |
+ HOWTO (R_RISCV_DECBNEZ_BRANCH, /* type */ | |
+ 0, /* rightshift */ | |
+ 2, /* size */ | |
+ 32, /* bitsize */ | |
+ TRUE, /* pc_relative */ | |
+ 0, /* bitpos */ | |
+ complain_overflow_signed, /* complain_on_overflow */ | |
+ bfd_elf_generic_reloc, /* special_function */ | |
+ "R_RISCV_DECBNEZ_BRANCH", /* name */ | |
+ FALSE, /* partial_inplace */ | |
+ 0, /* src_mask */ | |
+ ENCODE_ZCE_DECBNEZ_IMM (-1U), /* dst_mask */ | |
+ TRUE), /* pcrel_offset */ | |
+ | |
+ /* 6-bit PC-relative branch offset. (C.DECBNEZ) */ | |
+ HOWTO (R_RISCV_C_DECBNEZ_BRANCH, /* type */ | |
+ 0, /* rightshift */ | |
+ -1, /* size */ /* but no negate support so far*/ | |
+ 16, /* bitsize */ | |
+ TRUE, /* pc_relative */ | |
+ 0, /* bitpos */ | |
+ complain_overflow_dont, /* complain_on_overflow */ | |
+ bfd_elf_generic_reloc, /* special_function */ | |
+ "R_RISCV_C_DECBNEZ_BRANCH", /* name */ | |
+ FALSE, /* partial_inplace */ | |
+ 0, /* src_mask */ | |
+ ENCODE_ZCE_C_DECBNEZ_IMM (-1U), /* dst_mask */ | |
+ TRUE) /* pcrel_offset */ | |
}; | |
/* A mapping from BFD reloc types to RISC-V ELF reloc types. */ | |
@@ -932,6 +962,8 @@ static const struct elf_reloc_map riscv_reloc_map[] = | |
{ BFD_RELOC_RISCV_SET16, R_RISCV_SET16 }, | |
{ BFD_RELOC_RISCV_SET32, R_RISCV_SET32 }, | |
{ BFD_RELOC_RISCV_32_PCREL, R_RISCV_32_PCREL }, | |
+ { BFD_RELOC_RISCV_DECBNEZ, R_RISCV_DECBNEZ_BRANCH }, | |
+ { BFD_RELOC_RISCV_C_DECBNEZ, R_RISCV_C_DECBNEZ_BRANCH }, | |
}; | |
/* Given a BFD reloc type, return a howto structure. */ | |
diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c | |
index c21ba07597..64cf6007b5 100644 | |
--- a/gas/config/tc-riscv.c | |
+++ b/gas/config/tc-riscv.c | |
@@ -1047,6 +1047,20 @@ validate_riscv_insn (const struct riscv_opcode *opc, int length) | |
case 'l': used_bits |= ENCODE_CLTYPE_LD_IMM (-1U); break; | |
case 'p': used_bits |= ENCODE_CBTYPE_IMM (-1U); break; | |
case 'a': used_bits |= ENCODE_CJTYPE_IMM (-1U); break; | |
+ case 'Z': /* ZCE */ | |
+ switch (c = *p++) | |
+ { | |
+ case 'h': used_bits |= ENCODE_ZCE_LHU_IMM (-1U); break; | |
+ case 'b': used_bits |= ENCODE_ZCE_LBU_IMM (-1U); break; | |
+ case 'd': used_bits |= ENCODE_ZCE_C_DECBNEZ_IMM (-1U); break; | |
+ case 's': used_bits |= ENCODE_ZCE_C_DECBNEZ_SCALE (-1U); break; | |
+ default: | |
+ as_bad (_("internal: bad RISC-V opcode " | |
+ "(unknown operand type `CZ%c'): %s %s"), | |
+ c, opc->name, opc->args); | |
+ return FALSE; | |
+ } | |
+ break; | |
case 'F': /* Compressed funct for .insn directive. */ | |
switch (c = *p++) | |
{ | |
@@ -1068,6 +1082,20 @@ validate_riscv_insn (const struct riscv_opcode *opc, int length) | |
return FALSE; | |
} | |
break; | |
+ case 'n': /* ZCE */ | |
+ switch (c = *p++) | |
+ { | |
+ case 'l': used_bits |= ENCODE_ZCE_LWGP_IMM (-1U); break; | |
+ case 's': used_bits |= ENCODE_ZCE_SWGP_IMM (-1U); break; | |
+ case 'S': used_bits |= ENCODE_ZCE_DECBNEZ_SCALE (-1U); break; | |
+ case 'd': used_bits |= ENCODE_ZCE_DECBNEZ_IMM (-1U); break; | |
+ default: | |
+ as_bad (_("internal: bad RISC-V opcode " | |
+ "(unknown operand type `n%c'): %s %s"), | |
+ c, opc->name, opc->args); | |
+ return FALSE; | |
+ } | |
+ break; | |
case ',': break; | |
case '(': break; | |
case ')': break; | |
@@ -1250,6 +1278,52 @@ riscv_apply_const_reloc (bfd_reloc_code_real_type reloc_type, bfd_vma value) | |
} | |
} | |
+/* Extra compress routine for Code Size Reduction Extension */ | |
+void | |
+zce_compress_pass (struct riscv_cl_insn *ip, expressionS *address_expr, | |
+ bfd_reloc_code_real_type *reloc_type) | |
+{ | |
+ int rd; | |
+ long label_loc, insn_loc, offset; | |
+ | |
+ /* only deal with decbnez to c.debnze currently */ | |
+ if (*reloc_type != BFD_RELOC_RISCV_DECBNEZ) | |
+ return; | |
+ | |
+ /* check if | |
+ addressing field | |
+ 1. addressing expr is a label | |
+ 2. the label is located above the inst (if it is defined) | |
+ 3. the length of offset to label is valid | |
+ rd field | |
+ 4. regno of rd ranges from 8 to 15 | |
+ */ | |
+ if (address_expr->X_add_symbol | |
+ && S_IS_DEFINED (address_expr->X_add_symbol)) | |
+ { | |
+ label_loc = S_GET_VALUE (address_expr->X_add_symbol); | |
+ insn_loc = frag_more (0) - frag_now->fr_literal; | |
+ offset = insn_loc - label_loc; | |
+ | |
+ /* extract rd regno */ | |
+ rd = (ip->insn_opcode >> OP_SH_RD) & OP_MASK_RD; | |
+ /* offset in c.decbnez should be positive */ | |
+ if (offset == 0) | |
+ return; | |
+ /* check if the offset length is valid */ | |
+ if (VALID_ZCE_C_DECBNEZ_IMM (offset) | |
+ && (rd >= 8 && rd <= 15)) | |
+ { | |
+ /* new encoding for c.decbnez */ | |
+ ip->insn_opcode = MATCH_C_DECBNEZ \ | |
+ | ((rd-8) << OP_SH_CRS1S) \ | |
+ | ENCODE_ZCE_C_DECBNEZ_SCALE (EXTRACT_ZCE_DECBNEZ_SCALE (ip->insn_opcode)) \ | |
+ | ENCODE_ZCE_C_DECBNEZ_IMM (offset); | |
+ *reloc_type = BFD_RELOC_RISCV_C_DECBNEZ; | |
+ } | |
+ } | |
+} | |
+ | |
/* Output an instruction. IP is the instruction information. | |
ADDRESS_EXPR is an operand of the instruction to be used with | |
RELOC_TYPE. */ | |
@@ -1260,13 +1334,16 @@ append_insn (struct riscv_cl_insn *ip, expressionS *address_expr, | |
{ | |
dwarf2_emit_insn (0); | |
+ | |
if (reloc_type != BFD_RELOC_UNUSED) | |
{ | |
reloc_howto_type *howto; | |
gas_assert (address_expr); | |
if (reloc_type == BFD_RELOC_12_PCREL | |
- || reloc_type == BFD_RELOC_RISCV_JMP) | |
+ || reloc_type == BFD_RELOC_RISCV_JMP | |
+ || reloc_type == BFD_RELOC_RISCV_DECBNEZ | |
+ || reloc_type == BFD_RELOC_RISCV_C_DECBNEZ) | |
{ | |
int j = reloc_type == BFD_RELOC_RISCV_JMP; | |
int best_case = riscv_insn_length (ip->insn_opcode); | |
@@ -1277,7 +1354,6 @@ append_insn (struct riscv_cl_insn *ip, expressionS *address_expr, | |
as_bad (_("relaxable branches not supported in absolute section")); | |
return; | |
} | |
- | |
add_relaxed_insn (ip, worst_case, best_case, | |
RELAX_BRANCH_ENCODE (j, best_case == 2, worst_case), | |
address_expr->X_add_symbol, | |
@@ -2271,7 +2347,58 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr, | |
break; | |
INSERT_OPERAND (CRS2, *ip, regno); | |
continue; | |
- case 'F': | |
+ case 'Z': | |
+ switch (*++args) | |
+ { | |
+ case 'd': | |
+ *imm_reloc = BFD_RELOC_RISCV_C_DECBNEZ; | |
+ my_getExpression (imm_expr, s); | |
+ s = expr_end; | |
+ continue; | |
+ case 's': | |
+ if (my_getSmallExpression (imm_expr, imm_reloc, s, p) | |
+ || imm_expr->X_op != O_constant | |
+ || !VALID_ZCE_C_DECBNEZ_SCALE ((valueT) imm_expr->X_add_number)) | |
+ break; | |
+ | |
+ switch (imm_expr->X_add_number) | |
+ { | |
+ case 1: imm_expr->X_add_number = 0b00; break; | |
+ case 2: imm_expr->X_add_number = 0b01; break; | |
+ case 4: imm_expr->X_add_number = 0b10; break; | |
+ case 8: imm_expr->X_add_number = 0b11; break; | |
+ default: | |
+ as_bad (_("internal: invalid scale value %ld for c.decbnez. Scale must be 1, 2, 4, 8. "), | |
+ imm_expr->X_add_number); | |
+ break; | |
+ } | |
+ ip->insn_opcode |= ENCODE_ZCE_C_DECBNEZ_SCALE (imm_expr->X_add_number); | |
+ imm_expr->X_op = O_absent; | |
+ s = expr_end; | |
+ goto rvc_imm_done; | |
+ default: | |
+ as_bad (_("internal: unknown ZCE field specifier" | |
+ "field specifier `CZ%c'"), *args); | |
+ } | |
+ break; | |
+ case 'F': | |
switch (*++args) | |
{ | |
case '6': | |
@@ -2412,6 +2539,65 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr, | |
} | |
continue; | |
+ case 'n': | |
+ switch (*++args) | |
+ { | |
+ case 'S': | |
+ my_getExpression (imm_expr, s); | |
+ if (imm_expr->X_op != O_constant) | |
+ break; | |
+ | |
+ switch (imm_expr->X_add_number) | |
+ { | |
+ case 1: imm_expr->X_add_number = 0b00; break; | |
+ case 2: imm_expr->X_add_number = 0b01; break; | |
+ case 4: imm_expr->X_add_number = 0b10; break; | |
+ case 8: imm_expr->X_add_number = 0b11; break; | |
+ default: | |
+ as_bad (_("internal: invalid scale value %ld for decbnez. Scale must be 1, 2, 4, 8. "), | |
+ imm_expr->X_add_number); | |
+ break; | |
+ }; | |
+ | |
+ ip->insn_opcode |= ENCODE_ZCE_DECBNEZ_SCALE (imm_expr->X_add_number); | |
+ s = expr_end; | |
+ imm_expr->X_op = O_absent; | |
+ continue; | |
+ case 'd': | |
+ *imm_reloc = BFD_RELOC_RISCV_DECBNEZ; | |
+ my_getExpression (imm_expr, s); | |
+ s = expr_end; | |
+ continue; | |
+ default: | |
+ as_bad (_("internal: unknown ZCE 32 bits instruction" | |
+ "field specifier `n%c'"), *args); | |
+ break; | |
+ } | |
+ | |
case 'm': /* Rounding mode. */ | |
if (arg_lookup (&s, riscv_rm, ARRAY_SIZE (riscv_rm), ®no)) | |
{ | |
@@ -2760,7 +2946,14 @@ md_assemble (char *str) | |
if (insn.insn_mo->pinfo == INSN_MACRO) | |
macro (&insn, &imm_expr, &imm_reloc); | |
else | |
+ { | |
+ if (insn.insn_mo->insn_class == INSN_CLASS_ZCEE \ | |
+ || insn.insn_mo->insn_class == INSN_CLASS_ZCEA \ | |
+ || insn.insn_mo->insn_class == INSN_CLASS_ZCEB) | |
+ zce_compress_pass (&insn, &imm_expr, &imm_reloc); | |
append_insn (&insn, &imm_expr, imm_reloc); | |
+ } | |
+ | |
} | |
const char * | |
@@ -3152,6 +3345,27 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) | |
} | |
break; | |
+ case BFD_RELOC_RISCV_DECBNEZ: | |
+ if (fixP->fx_addsy) | |
+ { | |
+ /* Fill in a tentative value to improve objdump readability. */ | |
+ bfd_vma target = S_GET_VALUE (fixP->fx_addsy) + *valP; | |
+ bfd_vma delta = target - md_pcrel_from (fixP); | |
+ /* check if it can be compressed to c.decbnez */ | |
+ bfd_putl32 (bfd_getl32 (buf) | ENCODE_ZCE_DECBNEZ_IMM (delta), buf); | |
+ } | |
+ break; | |
+ | |
+ case BFD_RELOC_RISCV_C_DECBNEZ: | |
+ if (fixP->fx_addsy) | |
+ { | |
+ /* Fill in a tentative value to improve objdump readability. */ | |
+ bfd_vma target = S_GET_VALUE (fixP->fx_addsy) + *valP; | |
+ bfd_vma delta = target - md_pcrel_from (fixP); | |
+ bfd_putl16 (bfd_getl16 (buf) | ENCODE_ZCE_C_DECBNEZ_IMM (-delta), buf); | |
+ } | |
+ break; | |
+ | |
case BFD_RELOC_RISCV_RVC_BRANCH: | |
if (fixP->fx_addsy) | |
{ | |
@@ -3527,7 +3741,6 @@ md_convert_frag_branch (fragS *fragp) | |
exp.X_add_number = fragp->fr_offset; | |
gas_assert (fragp->fr_var == RELAX_BRANCH_LENGTH (fragp->fr_subtype)); | |
- | |
if (RELAX_BRANCH_RVC (fragp->fr_subtype)) | |
{ | |
switch (RELAX_BRANCH_LENGTH (fragp->fr_subtype)) | |
@@ -3545,6 +3758,11 @@ md_convert_frag_branch (fragS *fragp) | |
insn = MATCH_BEQ | (rs1 << OP_SH_RS1); | |
else if ((insn & MASK_C_BNEZ) == MATCH_C_BNEZ) | |
insn = MATCH_BNE | (rs1 << OP_SH_RS1); | |
+ else if ((insn & MATCH_C_DECBNEZ) == MATCH_C_DECBNEZ) | |
+ { | |
+ insn = MATCH_DECBNEZ | (rs1 << OP_SH_RD); | |
+ exp.X_add_number *= -1; | |
+ } | |
else | |
abort (); | |
bfd_putl32 (insn, buf); | |
@@ -3553,18 +3771,30 @@ md_convert_frag_branch (fragS *fragp) | |
case 6: | |
/* Invert the branch condition. Branch over the jump. */ | |
insn = bfd_getl16 (buf); | |
- insn ^= MATCH_C_BEQZ ^ MATCH_C_BNEZ; | |
- insn |= ENCODE_CBTYPE_IMM (6); | |
+ if ((insn & MATCH_C_DECBNEZ) != MATCH_C_DECBNEZ) | |
+ { | |
+ insn ^= MATCH_C_BEQZ ^ MATCH_C_BNEZ; | |
+ insn |= ENCODE_CBTYPE_IMM (6); | |
+ } | |
+ else | |
+ { | |
+ insn |= ENCODE_ZCE_DECBNEZ_IMM (6); | |
+ } | |
bfd_putl16 (insn, buf); | |
buf += 2; | |
goto jump; | |
case 2: | |
+ insn = bfd_getl16 (buf); | |
/* Just keep the RVC branch. */ | |
- reloc = RELAX_BRANCH_UNCOND (fragp->fr_subtype) | |
- ? BFD_RELOC_RISCV_RVC_JUMP : BFD_RELOC_RISCV_RVC_BRANCH; | |
+ if ((insn & MATCH_C_DECBNEZ) == MATCH_C_DECBNEZ) | |
+ reloc = BFD_RELOC_RISCV_C_DECBNEZ; | |
+ else | |
+ reloc = RELAX_BRANCH_UNCOND (fragp->fr_subtype) | |
+ ? BFD_RELOC_RISCV_RVC_JUMP : BFD_RELOC_RISCV_RVC_BRANCH; | |
+ | |
fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal, | |
- 2, &exp, FALSE, reloc); | |
+ 2, &exp, FALSE, reloc); | |
buf += 2; | |
goto done; | |
@@ -3580,24 +3810,35 @@ md_convert_frag_branch (fragS *fragp) | |
/* Invert the branch condition. Branch over the jump. */ | |
insn = bfd_getl32 (buf); | |
- insn ^= MATCH_BEQ ^ MATCH_BNE; | |
- insn |= ENCODE_BTYPE_IMM (8); | |
+ if ((insn & MATCH_DECBNEZ) != MATCH_DECBNEZ) | |
+ { | |
+ insn ^= MATCH_BEQ ^ MATCH_BNE; | |
+ insn |= ENCODE_BTYPE_IMM (8); | |
+ } | |
+ else | |
+ { | |
+ insn |= ENCODE_ZCE_DECBNEZ_IMM (8); | |
+ } | |
bfd_putl32 (insn, buf); | |
buf += 4; | |
- | |
jump: | |
/* Jump to the target. */ | |
fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal, | |
- 4, &exp, FALSE, BFD_RELOC_RISCV_JMP); | |
+ 4, &exp, FALSE, BFD_RELOC_RISCV_JMP); | |
bfd_putl32 (MATCH_JAL, buf); | |
buf += 4; | |
break; | |
case 4: | |
- reloc = RELAX_BRANCH_UNCOND (fragp->fr_subtype) | |
- ? BFD_RELOC_RISCV_JMP : BFD_RELOC_12_PCREL; | |
+ insn = bfd_getl32 (buf); | |
+ if ((insn & MATCH_DECBNEZ) == MATCH_DECBNEZ) | |
+ reloc = BFD_RELOC_RISCV_DECBNEZ; | |
+ else | |
+ reloc = RELAX_BRANCH_UNCOND (fragp->fr_subtype) | |
+ ? BFD_RELOC_RISCV_JMP : BFD_RELOC_12_PCREL; | |
+ | |
fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal, | |
- 4, &exp, FALSE, reloc); | |
+ 4, &exp, FALSE, reloc); | |
buf += 4; | |
break; | |
diff --git a/include/elf/riscv.h b/include/elf/riscv.h | |
index fb376a096a..41ca1dccf2 100644 | |
--- a/include/elf/riscv.h | |
+++ b/include/elf/riscv.h | |
@@ -89,6 +89,8 @@ START_RELOC_NUMBERS (elf_riscv_reloc_type) | |
RELOC_NUMBER (R_RISCV_SET32, 56) | |
RELOC_NUMBER (R_RISCV_32_PCREL, 57) | |
RELOC_NUMBER (R_RISCV_IRELATIVE, 58) | |
+ RELOC_NUMBER (R_RISCV_DECBNEZ_BRANCH, 59) | |
+ RELOC_NUMBER (R_RISCV_C_DECBNEZ_BRANCH, 60) | |
END_RELOC_NUMBERS (R_RISCV_max) | |
/* Processor specific flags for the ELF header e_flags field. */ | |
diff --git a/include/opcode/riscv-opc.h b/include/opcode/riscv-opc.h | |
index ca2728c439..5622f9a55d 100644 | |
--- a/include/opcode/riscv-opc.h | |
+++ b/include/opcode/riscv-opc.h | |
@@ -646,8 +646,8 @@ | |
#define MASK_BEQI 0x707f | |
#define MATCH_BNEI 0x3063 | |
#define MASK_BNEI 0x707f | |
+#define MATCH_C_DECBNEZ 0xa002 | |
+#define MASK_C_DECBNEZ 0xe003 | |
+#define MATCH_DECBNEZ 0x80003007 | |
+#define MASK_DECBNEZ 0xe000707f | |
#define MATCH_LWGP 0x3007 | |
diff --git a/include/opcode/riscv.h b/include/opcode/riscv.h | |
index 8eb4c5fc41..e54bb105f6 100644 | |
--- a/include/opcode/riscv.h | |
+++ b/include/opcode/riscv.h | |
@@ -60,6 +60,7 @@ static const char * const riscv_pred_succ[16] = | |
#define RV_X(x, s, n) (((x) >> (s)) & ((1 << (n)) - 1)) | |
#define RV_IMM_SIGN(x) (-(((x) >> 31) & 1)) | |
+#define RV_DECBNEZ_IMM_SIGN(x, sh) (-(((x) >> sh) & 1)) | |
#define EXTRACT_ITYPE_IMM(x) \ | |
(RV_X(x, 20, 12) | (RV_IMM_SIGN(x) << 12)) | |
@@ -101,6 +102,22 @@ static const char * const riscv_pred_succ[16] = | |
((RV_X(x, 3, 2) << 1) | (RV_X(x, 10, 2) << 3) | (RV_X(x, 2, 1) << 5) | (RV_X(x, 5, 2) << 6) | (-RV_X(x, 12, 1) << 8)) | |
#define EXTRACT_CJTYPE_IMM(x) \ | |
((RV_X(x, 3, 3) << 1) | (RV_X(x, 11, 1) << 4) | (RV_X(x, 2, 1) << 5) | (RV_X(x, 7, 1) << 6) | (RV_X(x, 6, 1) << 7) | (RV_X(x, 9, 2) << 8) | (RV_X(x, 8, 1) << 10) | (-RV_X(x, 12, 1) << 11)) | |
+#define EXTRACT_ZCE_C_DECBNEZ_IMM(x) \ | |
+ ((RV_X(x, 4, 3) << 1) | (RV_X(x, 10, 3) << 4)) | |
+#define EXTRACT_ZCE_DECBNEZ_IMM(x) \ | |
+ ((RV_X(x, 17, 1) << 1) | (RV_X(x, 22, 7) << 2) | (RV_X(x, 20, 2) << 9) | (RV_X(x, 15, 2) << 11) | (RV_DECBNEZ_IMM_SIGN(x, 16) << 12)) | |
+#define EXTRACT_ZCE_C_DECBNEZ_SCALE(x) \ | |
+ (RV_X(x, 2, 2)) | |
+#define EXTRACT_ZCE_DECBNEZ_SCALE(x) \ | |
+ (RV_X(x, 18, 2)) | |
#define ENCODE_ITYPE_IMM(x) \ | |
(RV_X(x, 0, 12) << 20) | |
@@ -142,6 +159,22 @@ static const char * const riscv_pred_succ[16] = | |
((RV_X(x, 1, 2) << 3) | (RV_X(x, 3, 2) << 10) | (RV_X(x, 5, 1) << 2) | (RV_X(x, 6, 2) << 5) | (RV_X(x, 8, 1) << 12)) | |
#define ENCODE_CJTYPE_IMM(x) \ | |
((RV_X(x, 1, 3) << 3) | (RV_X(x, 4, 1) << 11) | (RV_X(x, 5, 1) << 2) | (RV_X(x, 6, 1) << 7) | (RV_X(x, 7, 1) << 6) | (RV_X(x, 8, 2) << 9) | (RV_X(x, 10, 1) << 8) | (RV_X(x, 11, 1) << 12)) | |
+#define ENCODE_ZCE_C_DECBNEZ_IMM(x) \ | |
+ ((RV_X(x, 1, 3) << 4) | (RV_X(x, 4, 3) << 10)) | |
+#define ENCODE_ZCE_DECBNEZ_IMM(x) \ | |
+ ((RV_X(x, 1, 1) << 17) | (RV_X(x, 2, 7) << 22) | (RV_X(x, 9, 2) << 20) | (RV_X(x, 11, 2) << 15)) | |
+#define ENCODE_ZCE_C_DECBNEZ_SCALE(x) \ | |
+ ((RV_X(x, 0, 2)) << 2) | |
+#define ENCODE_ZCE_DECBNEZ_SCALE(x) \ | |
+ ((RV_X(x, 0, 2)) << 18) | |
#define VALID_ITYPE_IMM(x) (EXTRACT_ITYPE_IMM(ENCODE_ITYPE_IMM(x)) == (x)) | |
#define VALID_STYPE_IMM(x) (EXTRACT_STYPE_IMM(ENCODE_STYPE_IMM(x)) == (x)) | |
@@ -165,6 +198,14 @@ static const char * const riscv_pred_succ[16] = | |
#define VALID_CLTYPE_LD_IMM(x) (EXTRACT_CLTYPE_LD_IMM(ENCODE_CLTYPE_LD_IMM(x)) == (x)) | |
#define VALID_CBTYPE_IMM(x) (EXTRACT_CBTYPE_IMM(ENCODE_CBTYPE_IMM(x)) == (x)) | |
#define VALID_CJTYPE_IMM(x) (EXTRACT_CJTYPE_IMM(ENCODE_CJTYPE_IMM(x)) == (x)) | |
+#define VALID_ZCE_C_DECBNEZ_IMM(x) (EXTRACT_ZCE_C_DECBNEZ_IMM(ENCODE_ZCE_C_DECBNEZ_IMM(x)) == (x)) | |
+#define VALID_ZCE_DECBNEZ_IMM(x) (EXTRACT_ZCE_DECBNEZ_IMM(ENCODE_ZCE_DECBNEZ_IMM(x)) == (x)) | |
+#define VALID_ZCE_C_DECBNEZ_SCALE(x) (EXTRACT_ZCE_C_DECBNEZ_SCALE(ENCODE_ZCE_C_DECBNEZ_SCALE(x)) == (x)) | |
+#define VALID_ZCE_DECBNEZ_SCALE(x) (EXTRACT_ZCE_DECBNEZ_SCALE(ENCODE_ZCE_DECBNEZ_SCALE(x)) == (x)) | |
#define RISCV_RTYPE(insn, rd, rs1, rs2) \ | |
((MATCH_ ## insn) | ((rd) << OP_SH_RD) | ((rs1) << OP_SH_RS1) | ((rs2) << OP_SH_RS2)) | |
diff --git a/opcodes/riscv-dis.c b/opcodes/riscv-dis.c | |
index cc80d90945..68b85ce0f2 100644 | |
--- a/opcodes/riscv-dis.c | |
+++ b/opcodes/riscv-dis.c | |
@@ -258,6 +258,30 @@ print_insn_args (const char *d, insn_t l, bfd_vma pc, disassemble_info *info) | |
print (info->stream, "%s", | |
riscv_fpr_names[EXTRACT_OPERAND (CRS2S, l) + 8]); | |
break; | |
+ case 'Z': /* ZCE 16 bits length instruction field*/ | |
+ switch (*++d) | |
+ { | |
+ case 'd': | |
+ info->target = pc - EXTRACT_ZCE_C_DECBNEZ_IMM (l); | |
+ (*info->print_address_func) (info->target, info); | |
+ break; | |
+ case 's': | |
+ switch (EXTRACT_ZCE_C_DECBNEZ_SCALE (l)) | |
+ { | |
+ case 0b00: print (info->stream, "%d", 1); break; | |
+ case 0b01: print (info->stream, "%d", 2); break; | |
+ case 0b10: print (info->stream, "%d", 4); break; | |
+ case 0b11: print (info->stream, "%d", 8); break; | |
+ } | |
+ break; | |
+ } | |
+ break; | |
} | |
break; | |
@@ -292,6 +316,30 @@ print_insn_args (const char *d, insn_t l, bfd_vma pc, disassemble_info *info) | |
(unsigned)EXTRACT_UTYPE_IMM (l) >> RISCV_IMM_BITS); | |
break; | |
+ case 'n': /* ZCE 32 bits length instruction field */ | |
+ switch (*++d) | |
+ { | |
+ case 'S': | |
+ switch ((int)EXTRACT_ZCE_DECBNEZ_SCALE (l)) | |
+ { | |
+ case 0b00: print (info->stream, "%d", 1); break; | |
+ case 0b01: print (info->stream, "%d", 2); break; | |
+ case 0b10: print (info->stream, "%d", 4); break; | |
+ case 0b11: print (info->stream, "%d", 8); break; | |
+ } | |
+ break; | |
+ case 'd': | |
+ info->target = pc + EXTRACT_ZCE_DECBNEZ_IMM (l); | |
+ (*info->print_address_func) (info->target, info); | |
+ break; | |
+ } | |
+ break; | |
case 'm': | |
arg_print (info, EXTRACT_OPERAND (RM, l), | |
riscv_rm, ARRAY_SIZE (riscv_rm)); | |
diff --git a/opcodes/riscv-opc.c b/opcodes/riscv-opc.c | |
index 411b23ed9d..40406fed7d 100644 | |
--- a/opcodes/riscv-opc.c | |
+++ b/opcodes/riscv-opc.c | |
@@ -591,6 +603,10 @@ const struct riscv_opcode riscv_opcodes[] = | |
{"fcvt.s.lu", 64, INSN_CLASS_F, "D,s", MATCH_FCVT_S_LU|MASK_RM, MASK_FCVT_S_L|MASK_RM, match_opcode, 0 }, | |
{"fcvt.s.lu", 64, INSN_CLASS_F, "D,s,m", MATCH_FCVT_S_LU, MASK_FCVT_S_LU, match_opcode, 0 }, | |
+{"c.decbnez", 0, INSN_CLASS_ZCEB, "Cs,CZs,CZd", MATCH_C_DECBNEZ, MASK_C_DECBNEZ, match_opcode, INSN_CONDBRANCH }, | |
+{"decbnez", 0, INSN_CLASS_ZCEB, "d,nS,nd", MATCH_DECBNEZ, MASK_DECBNEZ, match_opcode, INSN_CONDBRANCH }, | |
+ | |
/* Double-precision floating-point instruction subset. */ | |
{"fld", 0, INSN_CLASS_D_AND_C, "D,Cn(Cc)", MATCH_C_FLDSP, MASK_C_FLDSP, match_opcode, INSN_ALIAS|INSN_DREF|INSN_8_BYTE }, | |
{"fld", 0, INSN_CLASS_D_AND_C, "CD,Cl(Cs)", MATCH_C_FLD, MASK_C_FLD, match_opcode, INSN_ALIAS|INSN_DREF|INSN_8_BYTE }, |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment