/* tc-riscv.c -- RISC-V assembler
- Copyright (C) 2011-2020 Free Software Foundation, Inc.
+ Copyright (C) 2011-2021 Free Software Foundation, Inc.
Contributed by Andrew Waterman (andrew@sifive.com).
Based on MIPS target.
case INSN_CLASS_M: return riscv_subset_supports ("m");
case INSN_CLASS_F: return riscv_subset_supports ("f");
case INSN_CLASS_D: return riscv_subset_supports ("d");
- case INSN_CLASS_D_AND_C:
- return riscv_subset_supports ("d") && riscv_subset_supports ("c");
+ case INSN_CLASS_Q: return riscv_subset_supports ("q");
case INSN_CLASS_F_AND_C:
- return riscv_subset_supports ("f") && riscv_subset_supports ("c");
-
- case INSN_CLASS_Q: return riscv_subset_supports ("q");
+ return (riscv_subset_supports ("f")
+ && riscv_subset_supports ("c"));
+ case INSN_CLASS_D_AND_C:
+ return (riscv_subset_supports ("d")
+ && riscv_subset_supports ("c"));
+
+ case INSN_CLASS_ZICSR:
+ return riscv_subset_supports ("zicsr");
+ case INSN_CLASS_ZIFENCEI:
+ return riscv_subset_supports ("zifencei");
+
+ case INSN_CLASS_ZBA:
+ return riscv_subset_supports ("zba");
+ case INSN_CLASS_ZBB:
+ return riscv_subset_supports ("zbb");
+ case INSN_CLASS_ZBC:
+ return riscv_subset_supports ("zbc");
+ case INSN_CLASS_ZBA_OR_ZBB:
+ return (riscv_subset_supports ("zba")
+ || riscv_subset_supports ("zbb"));
default:
as_fatal ("Unreachable");
&& ext->name
&& strcmp (ext->name, name) == 0)
{
- if (ext->isa_spec_class == default_isa_spec)
+ if (ext->isa_spec_class == ISA_SPEC_CLASS_DRAFT
+ || ext->isa_spec_class == default_isa_spec)
{
*major_version = ext->major_version;
*minor_version = ext->minor_version;
/* Indicate we are already assemble any instructions or not. */
static bfd_boolean start_assemble = FALSE;
-/* Indicate ELF attributes are explictly set. */
+/* Indicate ELF attributes are explicitly set. */
static bfd_boolean explicit_attr = FALSE;
-/* Indicate CSR or priv instructions are explictly used. */
+/* Indicate CSR or priv instructions are explicitly used. */
static bfd_boolean explicit_priv_attr = FALSE;
/* Macros for encoding relaxation state for RVC branches and far jumps. */
const char *
riscv_target_format (void)
{
- return xlen == 64 ? "elf64-littleriscv" : "elf32-littleriscv";
+ if (target_big_endian)
+ return xlen == 64 ? "elf64-bigriscv" : "elf32-bigriscv";
+ else
+ return xlen == 64 ? "elf64-littleriscv" : "elf32-littleriscv";
}
/* Return the length of instruction INSN. */
install_insn (const struct riscv_cl_insn *insn)
{
char *f = insn->frag->fr_literal + insn->where;
- md_number_to_chars (f, insn->insn_opcode, insn_length (insn));
+ number_to_chars_littleendian (f, insn->insn_opcode, insn_length (insn));
}
/* Move INSN to offset WHERE in FRAG. Adjust the fixups accordingly
}
}
+/* Zero extend and sign extend byte/half-word/word. */
+
+static void
+riscv_ext (int destreg, int srcreg, unsigned shift, bfd_boolean sign)
+{
+ if (sign)
+ {
+ md_assemblef ("slli x%d, x%d, 0x%x", destreg, srcreg, shift);
+ md_assemblef ("srai x%d, x%d, 0x%x", destreg, destreg, shift);
+ }
+ else
+ {
+ md_assemblef ("slli x%d, x%d, 0x%x", destreg, srcreg, shift);
+ md_assemblef ("srli x%d, x%d, 0x%x", destreg, destreg, shift);
+ }
+}
+
/* Expand RISC-V assembly macros into one or more instructions. */
+
static void
macro (struct riscv_cl_insn *ip, expressionS *imm_expr,
bfd_reloc_code_real_type *imm_reloc)
riscv_call (rd, rs1, imm_expr, *imm_reloc);
break;
+ case M_ZEXTH:
+ riscv_ext (rd, rs1, xlen - 16, FALSE);
+ break;
+
+ case M_ZEXTW:
+ riscv_ext (rd, rs1, xlen - 32, FALSE);
+ break;
+
+ case M_SEXTB:
+ riscv_ext (rd, rs1, xlen - 8, TRUE);
+ break;
+
+ case M_SEXTH:
+ riscv_ext (rd, rs1, xlen - 16, TRUE);
+ break;
+
default:
as_bad (_("Macro %s not implemented"), ip->insn_mo->name);
break;
void
md_number_to_chars (char *buf, valueT val, int n)
{
- number_to_chars_littleendian (buf, val, n);
+ if (target_big_endian)
+ number_to_chars_bigendian (buf, val, n);
+ else
+ number_to_chars_littleendian (buf, val, n);
}
const char *md_shortopts = "O::g::G:";
OPTION_NO_CSR_CHECK,
OPTION_MISA_SPEC,
OPTION_MPRIV_SPEC,
+ OPTION_BIG_ENDIAN,
+ OPTION_LITTLE_ENDIAN,
OPTION_END_OF_ENUM
};
{"mno-csr-check", no_argument, NULL, OPTION_NO_CSR_CHECK},
{"misa-spec", required_argument, NULL, OPTION_MISA_SPEC},
{"mpriv-spec", required_argument, NULL, OPTION_MPRIV_SPEC},
+ {"mbig-endian", no_argument, NULL, OPTION_BIG_ENDIAN},
+ {"mlittle-endian", no_argument, NULL, OPTION_LITTLE_ENDIAN},
{NULL, no_argument, NULL, 0}
};
case OPTION_MPRIV_SPEC:
return riscv_set_default_priv_spec (arg);
+ case OPTION_BIG_ENDIAN:
+ target_big_endian = 1;
+ break;
+
+ case OPTION_LITTLE_ENDIAN:
+ target_big_endian = 0;
+ break;
+
default:
return 0;
}
/* Use at most one 2-byte NOP. */
if ((bytes - i) % 4 == 2)
{
- md_number_to_chars (buf + i, RVC_NOP, 2);
+ number_to_chars_littleendian (buf + i, RVC_NOP, 2);
i += 2;
}
/* Fill the remainder with 4-byte NOPs. */
for ( ; i < bytes; i += 4)
- md_number_to_chars (buf + i, RISCV_NOP, 4);
+ number_to_chars_littleendian (buf + i, RISCV_NOP, 4);
}
/* Called from md_do_align. Used to create an alignment frag in a
insn = bfd_getl32 (buf);
insn ^= MATCH_BEQ ^ MATCH_BNE;
insn |= ENCODE_SBTYPE_IMM (8);
- md_number_to_chars ((char *) buf, insn, 4);
+ 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);
- md_number_to_chars ((char *) buf, MATCH_JAL, 4);
+ bfd_putl32 (MATCH_JAL, buf);
buf += 4;
break;