Skip to content

Instantly share code, notes, and snippets.

@linsinan1995
Last active September 9, 2021 12:13
Show Gist options
  • Save linsinan1995/d4ac3f90df65501675abb29998536a0f to your computer and use it in GitHub Desktop.
Save linsinan1995/d4ac3f90df65501675abb29998536a0f to your computer and use it in GitHub Desktop.
decbnez
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), &regno))
{
@@ -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