diff options
author | Nelson Chu <nelson.chu@sifive.com> | 2020-05-20 17:22:48 +0100 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2020-05-20 17:22:48 +0100 |
commit | 8f595e9b4fd0a3a74d53ddffd69f2825627ae5c6 (patch) | |
tree | 3668cb480143c82412d9050ad70d4a0e2786a7e7 /gas/config/tc-riscv.c | |
parent | 41977d16e4ee5b9ad01abf2cfce6edbfb6d79541 (diff) | |
download | gdb-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.c | 514 |
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; } } |