aboutsummaryrefslogtreecommitdiff
path: root/gas/config/tc-riscv.c
diff options
context:
space:
mode:
authorNelson Chu <nelson.chu@sifive.com>2020-05-20 17:22:48 +0100
committerNick Clifton <nickc@redhat.com>2020-05-20 17:22:48 +0100
commit8f595e9b4fd0a3a74d53ddffd69f2825627ae5c6 (patch)
tree3668cb480143c82412d9050ad70d4a0e2786a7e7 /gas/config/tc-riscv.c
parent41977d16e4ee5b9ad01abf2cfce6edbfb6d79541 (diff)
downloadgdb-8f595e9b4fd0a3a74d53ddffd69f2825627ae5c6.zip
gdb-8f595e9b4fd0a3a74d53ddffd69f2825627ae5c6.tar.gz
gdb-8f595e9b4fd0a3a74d53ddffd69f2825627ae5c6.tar.bz2
[PATCH v2 0/9] RISC-V: Support version controling for ISA standard extensions and CSR
1. Remove the -mriscv-isa-version and --with-riscv-isa-version options. We can still use -march to choose the version for each extensions, so there is no need to add these. 2. Change the arguments of options from [1p9|1p9p1|...] to [1.9|1.9.1|...]. Unlike the architecture string has specified by spec, ther is no need to do the same thing for options. 3. Spilt the patches to reduce the burdens of review. [PATCH 3/7] RISC-V: Support new GAS options and configure options to set ISA versions to [PATCH v2 3/9] RISC-V: Support GAS option -misa-spec to set ISA versions [PATCH v2 4/9] RISC-V: Support configure options to set ISA versions by default. [PATCH 4/7] RISC-V: Support version checking for CSR according to privilege version. to [PATCH v2 5/9] RISC-V: Support version checking for CSR according to privilege spec version. [PATCH v2 6/9] RISC-V: Support configure option to choose the privilege spec version. 4. Use enum class rather than string to compare the choosen ISA spec in opcodes/riscv-opc.c. The behavior is same as comparing the choosen privilege spec. include * opcode/riscv.h: Include "bfd.h" to support bfd_boolean. (enum riscv_isa_spec_class): New enum class. All supported ISA spec belong to one of the class (struct riscv_ext_version): New structure holds version information for the specific ISA. * opcode/riscv-opc.h (DECLARE_CSR): There are two version information, define_version and abort_version. The define_version means which privilege spec is started to define the CSR, and the abort_version means which privilege spec is started to abort the CSR. If the CSR is valid for the newest spec, then the abort_version should be PRIV_SPEC_CLASS_DRAFT. (DECLARE_CSR_ALIAS): Same as DECLARE_CSR, but only for the obselete CSR. * opcode/riscv.h (enum riscv_priv_spec_class): New enum class. Define the current supported privilege spec versions. (struct riscv_csr_extra): Add new fields to store more information about the CSR. We use these information to find the suitable CSR address when user choosing a specific privilege spec. binutils * dwarf.c: Updated since DECLARE_CSR is changed. opcodes * riscv-opc.c (riscv_ext_version_table): The table used to store all information about the supported spec and the corresponding ISA versions. Currently, only Zicsr is supported to verify the correctness of Z sub extension settings. Others will be supported in the future patches. (struct isa_spec_t, isa_specs): List for all supported ISA spec classes and the corresponding strings. (riscv_get_isa_spec_class): New function. Get the corresponding ISA spec class by giving a ISA spec string. * riscv-opc.c (struct priv_spec_t): New structure. (struct priv_spec_t priv_specs): List for all supported privilege spec classes and the corresponding strings. (riscv_get_priv_spec_class): New function. Get the corresponding privilege spec class by giving a spec string. (riscv_get_priv_spec_name): New function. Get the corresponding privilege spec string by giving a CSR version class. * riscv-dis.c: Updated since DECLARE_CSR is changed. * riscv-dis.c: Add new disassembler option -Mpriv-spec to dump the CSR according to the chosen version. Build a hash table riscv_csr_hash to store the valid CSR for the chosen pirv verison. Dump the direct CSR address rather than it's name if it is invalid. (parse_riscv_dis_option_without_args): New function. Parse the options without arguments. (parse_riscv_dis_option): Call parse_riscv_dis_option_without_args to parse the options without arguments first, and then handle the options with arguments. Add the new option -Mpriv-spec, which has argument. * riscv-dis.c (print_riscv_disassembler_options): Add description about the new OBJDUMP option. ld * testsuite/ld-riscv-elf/attr-merge-arch-01.d: Updated priv attributes according to the -mpriv-spec option. * testsuite/ld-riscv-elf/attr-merge-arch-02.d: Likewise. * testsuite/ld-riscv-elf/attr-merge-arch-03.d: Likewise. * testsuite/ld-riscv-elf/attr-merge-priv-spec-a.s: Likewise. * testsuite/ld-riscv-elf/attr-merge-priv-spec-b.s: Likewise. * testsuite/ld-riscv-elf/attr-merge-priv-spec.d: Likewise. * testsuite/ld-riscv-elf/attr-merge-stack-align.d: Likewise. * testsuite/ld-riscv-elf/attr-merge-strict-align-01.d: Likewise. * testsuite/ld-riscv-elf/attr-merge-strict-align-02.d: Likewise. * testsuite/ld-riscv-elf/attr-merge-strict-align-03.d: Likewise. * testsuite/ld-riscv-elf/attr-merge-strict-align-04.d: Likewise. * testsuite/ld-riscv-elf/attr-merge-strict-align-05.d: Likewise. bfd * elfxx-riscv.h (riscv_parse_subset_t): Add new callback function get_default_version. It is used to find the default version for the specific extension. * elfxx-riscv.c (riscv_parsing_subset_version): Remove the parameters default_major_version and default_minor_version. Add new bfd_boolean parameter *use_default_version. Set it to TRUE if we need to call the callback rps->get_default_version to find the default version. (riscv_parse_std_ext): Call rps->get_default_version if we fail to find the default version in riscv_parsing_subset_version, and then call riscv_add_subset to add the subset into subset list. (riscv_parse_prefixed_ext): Likewise. (riscv_std_z_ext_strtab): Support Zicsr extensions. * elfnn-riscv.c (riscv_merge_std_ext): Use strcasecmp to compare the strings rather than characters. riscv_merge_arch_attr_info): The callback function get_default_version is only needed for assembler, so set it to NULL int the linker. * elfxx-riscv.c (riscv_estimate_digit): Remove the static. * elfxx-riscv.h: Updated. gas * testsuite/gas/riscv/priv-reg-fail-read-only-01.s: Updated. * config/tc-riscv.c (default_arch_with_ext, default_isa_spec): Static variables which are used to set the ISA extensions. You can use -march (or ELF build attributes) and -misa-spec to set them, respectively. (ext_version_hash): The hash table used to handle the extensions with versions. (init_ext_version_hash): Initialize the ext_version_hash according to riscv_ext_version_table. (riscv_get_default_ext_version): The callback function of riscv_parse_subset_t. According to the choosed ISA spec, get the default version for the specific extension. (riscv_set_arch): Set the callback function. (enum options, struct option md_longopts): Add new option -misa-spec. (md_parse_option): Do not call riscv_set_arch for -march. We will call it later in riscv_after_parse_args. Call riscv_get_isa_spec_class to set default_isa_spec class. (riscv_after_parse_args): Call init_ext_version_hash to initialize the ext_version_hash, and then call riscv_set_arch to set the architecture with versions according to default_arch_with_ext. * testsuite/gas/riscv/attribute-02.d: Set 0p0 as default version for x extensions. * testsuite/gas/riscv/attribute-03.d: Likewise. * testsuite/gas/riscv/attribute-09.d: New testcase. For i-ext, we already set it's version to 2p1 by march, so no need to use the default 2p2 version. For m-ext, we do not set the version by -march and ELF arch attribute, so set the default 2p0 to it. For zicsr, it is not defined in ISA spec 2p2, so set 0p0 to it. * testsuite/gas/riscv/attribute-10.d: New testcase. The version of zicsr is 2p0 according to ISA spec 20191213. * config/tc-riscv.c (DEFAULT_RISCV_ARCH_WITH_EXT) (DEFAULT_RISCV_ISA_SPEC): Default configure option settings. You can set them by configure options --with-arch and --with-isa-spec, respectively. (riscv_set_default_isa_spec): New function used to set the default ISA spec. (md_parse_option): Call riscv_set_default_isa_spec rather than call riscv_get_isa_spec_class directly. (riscv_after_parse_args): If the -isa-spec is not set, then we set the default ISA spec according to DEFAULT_RISCV_ISA_SPEC by calling riscv_set_default_isa_spec. * testsuite/gas/riscv/attribute-01.d: Add -misa-spec=2.2, since the --with-isa-spec may be set to different ISA spec. * testsuite/gas/riscv/attribute-02.d: Likewise. * testsuite/gas/riscv/attribute-03.d: Likewise. * testsuite/gas/riscv/attribute-04.d: Likewise. * testsuite/gas/riscv/attribute-05.d: Likewise. * testsuite/gas/riscv/attribute-06.d: Likewise. * testsuite/gas/riscv/attribute-07.d: Likewise. * configure.ac: Add configure options, --with-arch and --with-isa-spec. * configure: Regenerated. * config.in: Regenerated. * config/tc-riscv.c (default_priv_spec): Static variable which is used to check if the CSR is valid for the chosen privilege spec. You can use -mpriv-spec to set it. (enum reg_class): We now get the CSR address from csr_extra_hash rather than reg_names_hash. Therefore, move RCLASS_CSR behind RCLASS_MAX. (riscv_init_csr_hashes): Only need to initialize one hash table csr_extra_hash. (riscv_csr_class_check): Change the return type to void. Don't check the ISA dependency if -mcsr-check isn't set. (riscv_csr_version_check): New function. Check and find the CSR address from csr_extra_hash, according to default_priv_spec. Report warning for the invalid CSR if -mcsr-check is set. (reg_csr_lookup_internal): Updated. (reg_lookup_internal): Likewise. (md_begin): Updated since DECLARE_CSR and DECLARE_CSR_ALIAS are changed. (enum options, struct option md_longopts): Add new GAS option -mpriv-spec. (md_parse_option): Call riscv_set_default_priv_version to set default_priv_spec. (riscv_after_parse_args): If -mpriv-spec isn't set, then set the default privilege spec to the newest one. (enum riscv_csr_class, struct riscv_csr_extra): Move them to include/opcode/riscv.h. * testsuite/gas/riscv/priv-reg-fail-fext.d: This test case just want to check the ISA dependency for CSR, so fix the spec version by adding -mpriv-spec=1.11. * testsuite/gas/riscv/priv-reg-fail-fext.l: Likewise. There are some version warnings for the test case. * gas/testsuite/gas/riscv/priv-reg-fail-read-only-01.d: Likewise. * gas/testsuite/gas/riscv/priv-reg-fail-read-only-01.l: Likewise. * gas/testsuite/gas/riscv/priv-reg-fail-read-only-02.d: Likewise. * gas/testsuite/gas/riscv/priv-reg-fail-rv32-only.d: Likewise. * gas/testsuite/gas/riscv/priv-reg-fail-rv32-only.l: Likewise. * gas/testsuite/gas/riscv/priv-reg-fail-version-1p9.d: New test case. Check whether the CSR is valid when privilege version 1.9 is choosed. * gas/testsuite/gas/riscv/priv-reg-fail-version-1p9.l: Likewise. * gas/testsuite/gas/riscv/priv-reg-fail-version-1p9p1.d: New test case. Check whether the CSR is valid when privilege version 1.9.1 is choosed. * gas/testsuite/gas/riscv/priv-reg-fail-version-1p9p1.l: Likewise. * gas/testsuite/gas/riscv/priv-reg-fail-version-1p10.d: New test case. Check whether the CSR is valid when privilege version 1.10 is choosed. * gas/testsuite/gas/riscv/priv-reg-fail-version-1p10.l: Likewise. * gas/testsuite/gas/riscv/priv-reg-fail-version-1p11.d: New test case. Check whether the CSR is valid when privilege version 1.11 is choosed. * gas/testsuite/gas/riscv/priv-reg-fail-version-1p11.l: Likewise. * config/tc-riscv.c (DEFAULT_RISCV_ISA_SPEC): Default configure option setting. You can set it by configure option --with-priv-spec. (riscv_set_default_priv_spec): New function used to set the default privilege spec. (md_parse_option): Call riscv_set_default_priv_spec rather than call riscv_get_priv_spec_class directly. (riscv_after_parse_args): If -mpriv-spec isn't set, then we set the default privilege spec according to DEFAULT_RISCV_PRIV_SPEC by calling riscv_set_default_priv_spec. * testsuite/gas/riscv/csr-dw-regnums.d: Add -mpriv-spec=1.11, since the --with-priv-spec may be set to different privilege spec. * testsuite/gas/riscv/priv-reg.d: Likewise. * configure.ac: Add configure option --with-priv-spec. * configure: Regenerated. * config.in: Regenerated. * config/tc-riscv.c (explicit_attr): Rename explicit_arch_attr to explicit_attr. Set it to TRUE if any ELF attribute is found. (riscv_set_default_priv_spec): Try to set the default_priv_spec if the priv attributes are set. (md_assemble): Set the default_priv_spec according to the priv attributes when we start to assemble instruction. (riscv_write_out_attrs): Rename riscv_write_out_arch_attr to riscv_write_out_attrs. Update the arch and priv attributes. If we don't set the corresponding ELF attributes, then try to output the default ones. (riscv_set_public_attributes): If any ELF attribute or -march-attr options is set (explicit_attr is TRUE), then call riscv_write_out_attrs to update the arch and priv attributes. (s_riscv_attribute): Make sure all arch and priv attributes are set before any instruction. * testsuite/gas/riscv/attribute-01.d: Update the priv attributes if any ELF attribute or -march-attr is set. If the priv attributes are not set, then try to update them by the default setting (-mpriv-spec or --with-priv-spec). * testsuite/gas/riscv/attribute-02.d: Likewise. * testsuite/gas/riscv/attribute-03.d: Likewise. * testsuite/gas/riscv/attribute-04.d: Likewise. * testsuite/gas/riscv/attribute-06.d: Likewise. * testsuite/gas/riscv/attribute-07.d: Likewise. * testsuite/gas/riscv/attribute-08.d: Likewise. * testsuite/gas/riscv/attribute-09.d: Likewise. * testsuite/gas/riscv/attribute-10.d: Likewise. * testsuite/gas/riscv/attribute-unknown.d: Likewise. * testsuite/gas/riscv/attribute-05.d: Likewise. Also, the priv spec set by priv attributes must be supported. * testsuite/gas/riscv/attribute-05.s: Likewise. * testsuite/gas/riscv/priv-reg-fail-version-1p9.d: Likewise. Updated priv attributes according to the -mpriv-spec option. * testsuite/gas/riscv/priv-reg-fail-version-1p9p1.d: Likewise. * testsuite/gas/riscv/priv-reg-fail-version-1p10.d: Likewise. * testsuite/gas/riscv/priv-reg-fail-version-1p11.d: Likewise. * testsuite/gas/riscv/priv-reg.d: Removed. * testsuite/gas/riscv/priv-reg-version-1p9.d: New test case. Dump the CSR according to the priv spec 1.9. * testsuite/gas/riscv/priv-reg-version-1p9p1.d: New test case. Dump the CSR according to the priv spec 1.9.1. * testsuite/gas/riscv/priv-reg-version-1p10.d: New test case. Dump the CSR according to the priv spec 1.10. * testsuite/gas/riscv/priv-reg-version-1p11.d: New test case. Dump the CSR according to the priv spec 1.11. * config/tc-riscv.c (md_show_usage): Add descriptions about the new GAS options. * doc/c-riscv.texi: Likewise.
Diffstat (limited to 'gas/config/tc-riscv.c')
-rw-r--r--gas/config/tc-riscv.c514
1 files changed, 425 insertions, 89 deletions
diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index 168561e..04df088 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -63,7 +63,30 @@ struct riscv_cl_insn
#define DEFAULT_RISCV_ATTR 0
#endif
+/* Let riscv_after_parse_args set the default value according to xlen. */
+
+#ifndef DEFAULT_RISCV_ARCH_WITH_EXT
+#define DEFAULT_RISCV_ARCH_WITH_EXT NULL
+#endif
+
+/* The default ISA spec is set to 2.2 rather than the lastest version.
+ The reason is that compiler generates the ISA string with fixed 2p0
+ verisons only for the RISCV ELF architecture attributes, but not for
+ the -march option. Therefore, we should update the compiler or linker
+ to resolve this problem. */
+
+#ifndef DEFAULT_RISCV_ISA_SPEC
+#define DEFAULT_RISCV_ISA_SPEC "2.2"
+#endif
+
+#ifndef DEFAULT_RISCV_PRIV_SPEC
+#define DEFAULT_RISCV_PRIV_SPEC "1.11"
+#endif
+
static const char default_arch[] = DEFAULT_ARCH;
+static const char *default_arch_with_ext = DEFAULT_RISCV_ARCH_WITH_EXT;
+static enum riscv_isa_spec_class default_isa_spec = ISA_SPEC_CLASS_NONE;
+static enum riscv_priv_spec_class default_priv_spec = PRIV_SPEC_CLASS_NONE;
static unsigned xlen = 0; /* width of an x-register */
static unsigned abi_xlen = 0; /* width of a pointer in the ABI */
@@ -74,6 +97,95 @@ static bfd_boolean rve_abi = FALSE;
static unsigned elf_flags = 0;
+/* Set the default_isa_spec. Return 0 if the input spec string isn't
+ supported. Otherwise, return 1. */
+
+static int
+riscv_set_default_isa_spec (const char *s)
+{
+ enum riscv_isa_spec_class class;
+ if (!riscv_get_isa_spec_class (s, &class))
+ {
+ as_bad ("Unknown default ISA spec `%s' set by "
+ "-misa-spec or --with-isa-spec", s);
+ return 0;
+ }
+ else
+ default_isa_spec = class;
+ return 1;
+}
+
+/* Set the default_priv_spec, assembler will find the suitable CSR address
+ according to default_priv_spec. We will try to check priv attributes if
+ the input string is NULL. Return 0 if the input priv spec string isn't
+ supported. Otherwise, return 1. */
+
+static int
+riscv_set_default_priv_spec (const char *s)
+{
+ enum riscv_priv_spec_class class;
+ unsigned major, minor, revision;
+ obj_attribute *attr;
+ size_t buf_size;
+ char *buf;
+
+ /* Find the corresponding priv spec class. */
+ if (riscv_get_priv_spec_class (s, &class))
+ {
+ default_priv_spec = class;
+ return 1;
+ }
+
+ if (s != NULL)
+ {
+ as_bad (_("Unknown default privilege spec `%s' set by "
+ "-mpriv-spec or --with-priv-spec"), s);
+ return 0;
+ }
+
+ /* Try to set the default_priv_spec according to the priv attributes. */
+ attr = elf_known_obj_attributes_proc (stdoutput);
+ major = (unsigned) attr[Tag_RISCV_priv_spec].i;
+ minor = (unsigned) attr[Tag_RISCV_priv_spec_minor].i;
+ revision = (unsigned) attr[Tag_RISCV_priv_spec_revision].i;
+
+ /* The priv attributes setting 0.0.0 is meaningless. We should have set
+ the default_priv_spec by md_parse_option and riscv_after_parse_args,
+ so just skip the following setting. */
+ if (major == 0 && minor == 0 && revision == 0)
+ return 1;
+
+ buf_size = riscv_estimate_digit (major)
+ + 1 /* '.' */
+ + riscv_estimate_digit (minor)
+ + 1; /* string terminator */
+ if (revision != 0)
+ {
+ buf_size += 1 /* '.' */
+ + riscv_estimate_digit (revision);
+ buf = xmalloc (buf_size);
+ snprintf (buf, buf_size, "%d.%d.%d", major, minor, revision);
+ }
+ else
+ {
+ buf = xmalloc (buf_size);
+ snprintf (buf, buf_size, "%d.%d", major, minor);
+ }
+
+ if (riscv_get_priv_spec_class (buf, &class))
+ {
+ default_priv_spec = class;
+ free (buf);
+ return 1;
+ }
+
+ /* Still can not find the priv spec class. */
+ as_bad (_("Unknown default privilege spec `%d.%d.%d' set by "
+ "privilege attributes"), major, minor, revision);
+ free (buf);
+ return 0;
+}
+
/* This is the set of options which the .option pseudo-op may modify. */
struct riscv_set_options
@@ -147,6 +259,67 @@ riscv_multi_subset_supports (enum riscv_insn_class insn_class)
}
}
+/* Handle of the extension with version hash table. */
+static struct hash_control *ext_version_hash = NULL;
+
+static struct hash_control *
+init_ext_version_hash (const struct riscv_ext_version *table)
+{
+ int i = 0;
+ struct hash_control *hash = hash_new ();
+
+ while (table[i].name)
+ {
+ const char *name = table[i].name;
+ const char *hash_error =
+ hash_insert (hash, name, (void *) &table[i]);
+
+ if (hash_error != NULL)
+ {
+ fprintf (stderr, _("internal error: can't hash `%s': %s\n"),
+ table[i].name, hash_error);
+ /* Probably a memory allocation problem? Give up now. */
+ as_fatal (_("Broken assembler. No assembly attempted."));
+ return NULL;
+ }
+
+ i++;
+ while (table[i].name
+ && strcmp (table[i].name, name) == 0)
+ i++;
+ }
+
+ return hash;
+}
+
+static void
+riscv_get_default_ext_version (const char *name,
+ unsigned int *major_version,
+ unsigned int *minor_version)
+{
+ struct riscv_ext_version *ext;
+
+ *major_version = 0;
+ *minor_version = 0;
+
+ if (name == NULL || default_isa_spec == ISA_SPEC_CLASS_NONE)
+ return;
+
+ ext = (struct riscv_ext_version *) hash_find (ext_version_hash, name);
+ while (ext
+ && ext->name
+ && strcmp (ext->name, name) == 0)
+ {
+ if (ext->isa_spec_class == default_isa_spec)
+ {
+ *major_version = ext->major_version;
+ *minor_version = ext->minor_version;
+ return;
+ }
+ ext++;
+ }
+}
+
/* Set which ISA and extensions are available. */
static void
@@ -156,6 +329,10 @@ riscv_set_arch (const char *s)
rps.subset_list = &riscv_subsets;
rps.error_handler = as_fatal;
rps.xlen = &xlen;
+ rps.get_default_version = riscv_get_default_ext_version;
+
+ if (s == NULL)
+ return;
riscv_release_subset_list (&riscv_subsets);
riscv_parse_subset (&rps, s);
@@ -194,8 +371,8 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP";
/* Indicate we are already assemble any instructions or not. */
static bfd_boolean start_assemble = FALSE;
-/* Indicate arch attribute is explictly set. */
-static bfd_boolean explicit_arch_attr = FALSE;
+/* Indicate ELF attributes are explictly set. */
+static bfd_boolean explicit_attr = FALSE;
/* Macros for encoding relaxation state for RVC branches and far jumps. */
#define RELAX_BRANCH_ENCODE(uncond, rvc, length) \
@@ -452,8 +629,9 @@ enum reg_class
{
RCLASS_GPR,
RCLASS_FPR,
- RCLASS_CSR,
- RCLASS_MAX
+ RCLASS_MAX,
+
+ RCLASS_CSR
};
static struct hash_control *reg_names_hash = NULL;
@@ -483,102 +661,165 @@ hash_reg_names (enum reg_class class, const char * const names[], unsigned n)
hash_reg_name (class, names[i], i);
}
-/* All RISC-V CSRs belong to one of these classes. */
-
-enum riscv_csr_class
-{
- CSR_CLASS_NONE,
-
- CSR_CLASS_I,
- CSR_CLASS_I_32, /* rv32 only */
- CSR_CLASS_F, /* f-ext only */
-};
-
-/* This structure holds all restricted conditions for a CSR. */
+/* Init hash table csr_extra_hash to handle CSR. */
+static void
+riscv_init_csr_hash (const char *name,
+ unsigned address,
+ enum riscv_csr_class class,
+ enum riscv_priv_spec_class define_version,
+ enum riscv_priv_spec_class abort_version)
+{
+ struct riscv_csr_extra *entry, *pre_entry;
+ const char *hash_error = NULL;
+ bfd_boolean need_enrty = TRUE;
+
+ pre_entry = NULL;
+ entry = (struct riscv_csr_extra *) hash_find (csr_extra_hash, name);
+ while (need_enrty && entry != NULL)
+ {
+ if (entry->csr_class == class
+ && entry->address == address
+ && entry->define_version == define_version
+ && entry->abort_version == abort_version)
+ need_enrty = FALSE;
+ pre_entry = entry;
+ entry = entry->next;
+ }
+
+ /* Duplicate setting for the CSR, just return and do nothing. */
+ if (!need_enrty)
+ return;
-struct riscv_csr_extra
-{
- /* Class to which this CSR belongs. Used to decide whether or
- not this CSR is legal in the current -march context. */
- enum riscv_csr_class csr_class;
-};
+ entry = XNEW (struct riscv_csr_extra);
+ entry->csr_class = class;
+ entry->address = address;
+ entry->define_version = define_version;
+ entry->abort_version = abort_version;
+
+ /* If the CSR hasn't been inserted in the hash table, then insert it.
+ Otherwise, attach the extra information to the entry which is already
+ in the hash table. */
+ if (pre_entry == NULL)
+ {
+ hash_error = hash_insert (csr_extra_hash, name, (void *) entry);
+ if (hash_error != NULL)
+ {
+ fprintf (stderr, _("internal error: can't hash `%s': %s\n"),
+ name, hash_error);
+ /* Probably a memory allocation problem? Give up now. */
+ as_fatal (_("Broken assembler. No assembly attempted."));
+ }
+ }
+ else
+ pre_entry->next = entry;
+}
-/* Init two hashes, csr_extra_hash and reg_names_hash, for CSR. */
+/* Check wether the CSR is valid according to the ISA. */
static void
-riscv_init_csr_hashes (const char *name,
- unsigned address,
- enum riscv_csr_class class)
+riscv_csr_class_check (const char *s,
+ enum riscv_csr_class csr_class)
{
- struct riscv_csr_extra *entry = XNEW (struct riscv_csr_extra);
- entry->csr_class = class;
+ bfd_boolean result = TRUE;
+
+ /* Don't check the ISA dependency when -mcsr-check isn't set. */
+ if (!riscv_opts.csr_check)
+ return;
- const char *hash_error =
- hash_insert (csr_extra_hash, name, (void *) entry);
- if (hash_error != NULL)
+ switch (csr_class)
{
- fprintf (stderr, _("internal error: can't hash `%s': %s\n"),
- name, hash_error);
- /* Probably a memory allocation problem? Give up now. */
- as_fatal (_("Broken assembler. No assembly attempted."));
+ case CSR_CLASS_I:
+ result = riscv_subset_supports ("i");
+ break;
+ case CSR_CLASS_F:
+ result = riscv_subset_supports ("f");
+ break;
+ case CSR_CLASS_I_32:
+ result = (xlen == 32 && riscv_subset_supports ("i"));
+ break;
+ default:
+ as_bad (_("internal: bad RISC-V CSR class (0x%x)"), csr_class);
}
- hash_reg_name (RCLASS_CSR, name, address);
+ if (!result)
+ as_warn (_("Invalid CSR `%s' for the current ISA"), s);
}
-/* Check wether the CSR is valid according to the ISA. */
+/* Check and find the CSR address according to the privilege spec version. */
-static bfd_boolean
-riscv_csr_class_check (enum riscv_csr_class csr_class)
+static void
+riscv_csr_version_check (const char *csr_name,
+ struct riscv_csr_extra **entryP)
{
- switch (csr_class)
+ struct riscv_csr_extra *entry = *entryP;
+
+ while (entry != NULL)
{
- case CSR_CLASS_I: return riscv_subset_supports ("i");
- case CSR_CLASS_F: return riscv_subset_supports ("f");
- case CSR_CLASS_I_32:
- return (xlen == 32 && riscv_subset_supports ("i"));
+ if (default_priv_spec >= entry->define_version
+ && default_priv_spec < entry->abort_version)
+ {
+ /* Find the suitable CSR according to the specific version. */
+ *entryP = entry;
+ return;
+ }
+ entry = entry->next;
+ }
- default:
- return FALSE;
+ /* We can not find the suitable CSR address according to the privilege
+ version. Therefore, we use the last defined value. Report the warning
+ only when the -mcsr-check is set. Enable the -mcsr-check is recommended,
+ otherwise, you may get the unexpected CSR address. */
+ if (riscv_opts.csr_check)
+ {
+ const char *priv_name = riscv_get_priv_spec_name (default_priv_spec);
+
+ if (priv_name != NULL)
+ as_warn (_("Invalid CSR `%s' for the privilege spec `%s'"),
+ csr_name, priv_name);
}
}
-/* If the CSR is defined, then we call `riscv_csr_class_check` to do the
- further checking. Return FALSE if the CSR is not defined. Otherwise,
- return TRUE. */
+/* Once the CSR is defined, including the old privilege spec, then we call
+ riscv_csr_class_check and riscv_csr_version_check to do the further checking
+ and get the corresponding address. Return -1 if the CSR is never been
+ defined. Otherwise, return the address. */
-static bfd_boolean
+static unsigned int
reg_csr_lookup_internal (const char *s)
{
struct riscv_csr_extra *r =
(struct riscv_csr_extra *) hash_find (csr_extra_hash, s);
if (r == NULL)
- return FALSE;
+ return -1U;
- /* We just report the warning when the CSR is invalid. */
- if (!riscv_csr_class_check (r->csr_class))
- as_warn (_("Invalid CSR `%s' for the current ISA"), s);
+ /* We just report the warning when the CSR is invalid. "Invalid CSR" means
+ the CSR was defined, but isn't allowed for the current ISA setting or
+ the privilege spec. If the CSR is never been defined, then assembler
+ will regard it as a "Unknown CSR" and report error. If user use number
+ to set the CSR, but over the range (> 0xfff), then assembler will report
+ "Improper CSR" error for it. */
+ riscv_csr_class_check (s, r->csr_class);
+ riscv_csr_version_check (s, &r);
- return TRUE;
+ return r->address;
}
static unsigned int
reg_lookup_internal (const char *s, enum reg_class class)
{
- void *r = hash_find (reg_names_hash, s);
+ void *r;
+
+ if (class == RCLASS_CSR)
+ return reg_csr_lookup_internal (s);
+ r = hash_find (reg_names_hash, s);
if (r == NULL || DECODE_REG_CLASS (r) != class)
return -1;
if (riscv_opts.rve && class == RCLASS_GPR && DECODE_REG_NUM (r) > 15)
return -1;
- if (class == RCLASS_CSR
- && riscv_opts.csr_check
- && !reg_csr_lookup_internal (s))
- return -1;
-
return DECODE_REG_NUM (r);
}
@@ -862,8 +1103,10 @@ md_begin (void)
/* Create and insert CSR hash tables. */
csr_extra_hash = hash_new ();
-#define DECLARE_CSR(name, num, class) riscv_init_csr_hashes (#name, num, class);
-#define DECLARE_CSR_ALIAS(name, num, class) DECLARE_CSR(name, num, class);
+#define DECLARE_CSR(name, num, class, define_version, abort_version) \
+ riscv_init_csr_hash (#name, num, class, define_version, abort_version);
+#define DECLARE_CSR_ALIAS(name, num, class, define_version, abort_version) \
+ DECLARE_CSR(name, num, class, define_version, abort_version);
#include "opcode/riscv-opc.h"
#undef DECLARE_CSR
@@ -2306,9 +2549,17 @@ md_assemble (char *str)
expressionS imm_expr;
bfd_reloc_code_real_type imm_reloc = BFD_RELOC_UNUSED;
- const char *error = riscv_ip (str, &insn, &imm_expr, &imm_reloc, op_hash);
+ /* The arch and priv attributes should be set before assembling. */
+ if (!start_assemble)
+ {
+ start_assemble = TRUE;
- start_assemble = TRUE;
+ /* Set the default_priv_spec according to the priv attributes. */
+ if (!riscv_set_default_priv_spec (NULL))
+ return;
+ }
+
+ const char *error = riscv_ip (str, &insn, &imm_expr, &imm_reloc, op_hash);
if (error)
{
@@ -2348,6 +2599,8 @@ enum options
OPTION_NO_ARCH_ATTR,
OPTION_CSR_CHECK,
OPTION_NO_CSR_CHECK,
+ OPTION_MISA_SPEC,
+ OPTION_MPRIV_SPEC,
OPTION_END_OF_ENUM
};
@@ -2364,6 +2617,8 @@ struct option md_longopts[] =
{"mno-arch-attr", no_argument, NULL, OPTION_NO_ARCH_ATTR},
{"mcsr-check", no_argument, NULL, OPTION_CSR_CHECK},
{"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},
{NULL, no_argument, NULL, 0}
};
@@ -2392,7 +2647,9 @@ md_parse_option (int c, const char *arg)
switch (c)
{
case OPTION_MARCH:
- riscv_set_arch (arg);
+ /* riscv_after_parse_args will call riscv_set_arch to parse
+ the architecture. */
+ default_arch_with_ext = arg;
break;
case OPTION_NO_PIC:
@@ -2450,6 +2707,12 @@ md_parse_option (int c, const char *arg)
riscv_opts.csr_check = FALSE;
break;
+ case OPTION_MISA_SPEC:
+ return riscv_set_default_isa_spec (arg);
+
+ case OPTION_MPRIV_SPEC:
+ return riscv_set_default_priv_spec (arg);
+
default:
return 0;
}
@@ -2460,6 +2723,10 @@ md_parse_option (int c, const char *arg)
void
riscv_after_parse_args (void)
{
+ /* The --with-arch is optional for now, so we have to set the xlen
+ according to the default_arch, which is set by the --targte, first.
+ Then, we use the xlen to set the default_arch_with_ext if the
+ -march and --with-arch are not set. */
if (xlen == 0)
{
if (strcmp (default_arch, "riscv32") == 0)
@@ -2469,9 +2736,19 @@ riscv_after_parse_args (void)
else
as_bad ("unknown default architecture `%s'", default_arch);
}
+ if (default_arch_with_ext == NULL)
+ default_arch_with_ext = xlen == 64 ? "rv64g" : "rv32g";
+
+ /* Initialize the hash table for extensions with default version. */
+ ext_version_hash = init_ext_version_hash (riscv_ext_version_table);
+
+ /* If the -misa-spec isn't set, then we set the default ISA spec according
+ to DEFAULT_RISCV_ISA_SPEC. */
+ if (default_isa_spec == ISA_SPEC_CLASS_NONE)
+ riscv_set_default_isa_spec (DEFAULT_RISCV_ISA_SPEC);
- if (riscv_subsets.head == NULL)
- riscv_set_arch (xlen == 64 ? "rv64g" : "rv32g");
+ /* Set the architecture according to -march or or --with-arch. */
+ riscv_set_arch (default_arch_with_ext);
/* Add the RVC extension, regardless of -march, to support .option rvc. */
riscv_set_rvc (FALSE);
@@ -2483,6 +2760,11 @@ riscv_after_parse_args (void)
if (riscv_subset_supports ("e"))
riscv_set_rve (TRUE);
+ /* If the -mpriv-spec isn't set, then we set the default privilege spec
+ according to DEFAULT_PRIV_SPEC. */
+ if (default_priv_spec == PRIV_SPEC_CLASS_NONE)
+ riscv_set_default_priv_spec (DEFAULT_RISCV_PRIV_SPEC);
+
/* Infer ABI from ISA if not specified on command line. */
if (abi_xlen == 0)
abi_xlen = xlen;
@@ -3189,14 +3471,16 @@ md_show_usage (FILE *stream)
{
fprintf (stream, _("\
RISC-V options:\n\
- -fpic generate position-independent code\n\
- -fno-pic don't generate position-independent code (default)\n\
- -march=ISA set the RISC-V architecture\n\
- -mabi=ABI set the RISC-V ABI\n\
- -mrelax enable relax (default)\n\
- -mno-relax disable relax\n\
- -march-attr generate RISC-V arch attribute\n\
- -mno-arch-attr don't generate RISC-V arch attribute\n\
+ -fpic generate position-independent code\n\
+ -fno-pic don't generate position-independent code (default)\n\
+ -march=ISA set the RISC-V architecture\n\
+ -misa-spec=ISAspec set the RISC-V ISA spec (2.2, 20190608, 20191213)\n\
+ -mpriv-spec=PRIVspec set the RISC-V privilege spec (1.9, 1.9.1, 1.10, 1.11)\n\
+ -mabi=ABI set the RISC-V ABI\n\
+ -mrelax enable relax (default)\n\
+ -mno-relax disable relax\n\
+ -march-attr generate RISC-V arch attribute\n\
+ -mno-arch-attr don't generate RISC-V arch attribute\n\
"));
}
@@ -3284,26 +3568,66 @@ s_riscv_insn (int x ATTRIBUTE_UNUSED)
demand_empty_rest_of_line ();
}
-/* Update arch attributes. */
+/* Update arch and priv attributes. If we don't set the corresponding ELF
+ attributes, then try to output the default ones. */
static void
-riscv_write_out_arch_attr (void)
+riscv_write_out_attrs (void)
{
- const char *arch_str = riscv_arch_str (xlen, &riscv_subsets);
+ const char *arch_str, *priv_str, *p;
+ /* versions[0] is major, versions[1] is minor,
+ and versions[3] is revision. */
+ unsigned versions[3] = {0}, number = 0;
+ unsigned int i;
+ /* Re-write arch attribute to normalize the arch string. */
+ arch_str = riscv_arch_str (xlen, &riscv_subsets);
bfd_elf_add_proc_attr_string (stdoutput, Tag_RISCV_arch, arch_str);
-
xfree ((void *)arch_str);
+
+ /* For the file without any instruction, we don't set the default_priv_spec
+ according to the priv attributes since the md_assemble isn't called.
+ Call riscv_set_default_priv_spec here for the above case, although
+ it seems strange. */
+ if (!start_assemble
+ && !riscv_set_default_priv_spec (NULL))
+ return;
+
+ /* Re-write priv attributes by default_priv_spec. */
+ priv_str = riscv_get_priv_spec_name (default_priv_spec);
+ p = priv_str;
+ for (i = 0; *p; ++p)
+ {
+ if (*p == '.' && i < 3)
+ {
+ versions[i++] = number;
+ number = 0;
+ }
+ else if (ISDIGIT (*p))
+ number = (number * 10) + (*p - '0');
+ else
+ {
+ as_bad (_("internal: bad RISC-V priv spec string (%s)"), priv_str);
+ return;
+ }
+ }
+ versions[i] = number;
+
+ /* Set the priv attributes. */
+ bfd_elf_add_proc_attr_int (stdoutput, Tag_RISCV_priv_spec, versions[0]);
+ bfd_elf_add_proc_attr_int (stdoutput, Tag_RISCV_priv_spec_minor, versions[1]);
+ bfd_elf_add_proc_attr_int (stdoutput, Tag_RISCV_priv_spec_revision, versions[2]);
}
-/* Add the default contents for the .riscv.attributes section. */
+/* Add the default contents for the .riscv.attributes section. If any
+ ELF attribute or -march-attr options is set, call riscv_write_out_attrs
+ to update the arch and priv attributes. */
static void
riscv_set_public_attributes (void)
{
- if (riscv_opts.arch_attr || explicit_arch_attr)
- /* Re-write arch attribute to normalize the arch string. */
- riscv_write_out_arch_attr ();
+ if (riscv_opts.arch_attr || explicit_attr)
+ riscv_write_out_attrs ();
}
/* Called after all assembly has been done. */
@@ -3357,13 +3681,14 @@ static void
s_riscv_attribute (int ignored ATTRIBUTE_UNUSED)
{
int tag = obj_elf_vendor_attribute (OBJ_ATTR_PROC);
+ unsigned old_xlen;
+ obj_attribute *attr;
- if (tag == Tag_RISCV_arch)
+ explicit_attr = TRUE;
+ switch (tag)
{
- unsigned old_xlen = xlen;
-
- explicit_arch_attr = TRUE;
- obj_attribute *attr;
+ case Tag_RISCV_arch:
+ old_xlen = xlen;
attr = elf_known_obj_attributes_proc (stdoutput);
if (!start_assemble)
riscv_set_arch (attr[Tag_RISCV_arch].s);
@@ -3379,6 +3704,17 @@ s_riscv_attribute (int ignored ATTRIBUTE_UNUSED)
if (! bfd_set_arch_mach (stdoutput, bfd_arch_riscv, mach))
as_warn (_("Could not set architecture and machine"));
}
+ break;
+
+ case Tag_RISCV_priv_spec:
+ case Tag_RISCV_priv_spec_minor:
+ case Tag_RISCV_priv_spec_revision:
+ if (start_assemble)
+ as_fatal (_(".attribute priv spec must set before any instructions"));
+ break;
+
+ default:
+ break;
}
}