[3/7] RISC-V: Support new GAS options and configure options to set ISA versions.

Message ID 1587208075-2462-4-git-send-email-nelson.chu@sifive.com
State New
Headers show
Series
  • RISC-V: Support version controling for ISA standard extensions and CSR
Related show

Commit Message

Nelson Chu April 18, 2020, 11:07 a.m.
For now, we can only use the GAS option -march and ELF arch attribute to set
the versions for ISA extensions.  It seems not so friendly for user.
Therefore, we support new GAS options and configure options to make it easiler
for user.

New Assembler Options,

* -misa-spec = [2p0|2p1|2p2|20190608|20191213]
You can simply choose the ISA spec by this option, and then assembler will set
the version for the standard extensions if you don’t set in the ELF arch
attributes or -march option.

* -mriscv-isa-version = <ISA-string>
The syntax of <ISA-string> is same as -march option, but without rv32 or rv64
prefix.  There are two reasons that you may need this option,

1. Some versions of extensions defined in the ISA spec are not matched to the
toolchain’s implementation.  For example, V-ext is defined to version 0.7 in
ISA spec, but we only have implementations for 0.8 and 0.9.  Therefore, you
have to use this option to choose the correct version for V-ext.

2. You want to update the version for the specific standard extensions if the
version are not set in the ELF arch attributes and -march option.

New Default Configure Options,

* --with-arch = <ISA-string>
The syntax of <ISA-string> is same as -march option.  Assembler will check this
if -march option and ELF arch attributes aren’t set.

* --with-isa-spec = [2p0|2p1|2p2|20190608|20191213]
The syntax is same as -misa-spec option.  Assembler will check this if
-misa-spec option isn’t set.

* --with-riscv-isa-version = <ISA-string>
The syntax of <ISA-string> is same as -mriscv-isa-version option.  Assembler
will check this if -mriscv-isa-version option isn’t set.

The Priority of these options,

* ELF arch attributes > Assembler options > Default configure options
* For GAS options, -march > -mriscv-isa-version > -misa-spec
* For configure options, --with-arch > --with-riscv-isa-version > --with-isa-spec

	gas/
	* config/tc-riscv.c (DEFAULT_ARCH_WITH_EXT, DEFAULT_ISA_SPEC,
	DEFAULT_RISCV_ISA_VERSION): Default configure option settings.
	You can set them by new configure options --with-arch,
	--with-isa-spec and --with-riscv-isa-version.

	(default_arch_with_ext, default_isa_spec, default_riscv_isa_version):
	const char strings which are used to set the ISA extensions. You can
	use gas options -march (or ELF build attributes), and new gas options
	-misa-spec and -mriscv-isa-version to set them, respectively.  If the
	gas options and attributes are not set, then assembler will check the
	default configure option settings.

	(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): Add new bfd_boolean parameter update_version.
	The update_version is TRUE means we just want to update the version
	according to default_riscv_isa_version, so don't call the
	riscv_release_subset_list to reset the subset list.  Pass two new
	arguments to riscv_parse_subset, one is update_version mentioned above,
	the other is the default_isa_spec.  We use the default_isa_spec to
	choose the default version for the extensions.

	(enum options, struct option md_longopts): Add new gas options,
	-misa-spec and -mriscv-isa-version.
	(md_parse_option): Handle the above new gas options.
	(riscv_after_parse_args): Call init_ext_version_hash to initialize the
	ext_version_hash, and then always call riscv_set_arch twice to set and
	update the architecture with versions according to default_arch_with_ext
	and default_riscv_isa_version.
	(s_riscv_attribute): Same as riscv_after_parse_args, we need to call
	riscv_set_arch twice.

	* testsuite/gas/riscv/attribute-01.d: Add -misa-spec=2p2.  Set 0p0
	as default version for x extensions.
	* 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.
	* testsuite/gas/riscv/attribute-08.d: Likewise.
	* testsuite/gas/riscv/attribute-09.d: New testcase.  For i-ext, we
	already set the version 1p9 in elf attribute, so -misa-spec and
	-mriscv-isa-version don't update the version to 2p0 and 2p1.
	For f-ext, we don't set the version to it, so use the default version
	2p0 according to the ISA spec 2p2.  For v-ext, the default version is
	0p7 according to ISA spec 2p2, but we use -mriscv-isa-version to update
	it to 0p9.  For a-ext, it isn't enabled by -march or elf attribute, so
	we don't update it's version even if -mriscv-isa-version is set.
	As for the zicsr extension, it is defined in the lastest ISA spec
	rather than 2p2, so set it's version to 0p0.
	* testsuite/gas/riscv/attribute-09.s: Likewise.
	* testsuite/gas/riscv/attribute-10.d: New testcase.  The version of
	zicsr is 2p0 according to ISA spec 20191213.
	* testsuite/gas/riscv/attribute-11.d: New testcase.  We can also update
	the z* extension by -mriscv-isa-version.

	* configure.ac: Add new configure options, --with-arch, --with-isa-spec
	and --with-riscv-isa-version.
	* configure: Regenerated.
	* config.in: Regenerated.

	bfd/
	* elfxx-riscv.h (struct riscv_subset_t): Add new bfd_boolean field
	use_default_version, which is used to record whether the default
	version is used for the extension.
	(struct riscv_parse_subset_t): Add new callback function
	get_default_version.  It is used to find the default version for
	the specific extension.
	(riscv_add_subset, riscv_parse_subset): Update function declaration.

	* 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_update_subset_version): Only update the version of existin
	standard extensions and their Z* sub extensions, if -mriscv-isa-version
	or --with-riscv-isa-version are set, and the default version are used.

	(riscv_add_subset): New parameter use_default_version.  Record whether
	the default version is used.  riscv_update_subset_version only update
	the version of extensions if the default versions are used.

	(riscv_parse_subset): Add two parameters isa_spec_name and
	update_version.  Pass them to riscv_parse_std_ext and
	riscv_parse_prefixed_ext.  The string set by -mriscv-isa-version or
	--with-riscv-isa-version doesn't have to start with rv32/rv64, so
	skip the checking if update_version is TRUE.
	(riscv_parse_std_ext): If update_version is TRUE, then we just call
	riscv_update_subset_version to update the default version.  Otherwise,
	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): Same as the riscv_parse_std_ext.
	(riscv_std_z_ext_strtab): Support Zicsr extensions.

	* elfnn-riscv.c (riscv_merge_std_ext, riscv_merge_multi_letter_ext):
	Updated.  Pass update_version as FALSE to riscv_add_subset, the
	update_version is only needed for assembler, not linker.
	(riscv_merge_arch_attr_info): The callback function get_default_version
	is only needed for assembler, so set it to NULL in linker.  Also, Pass
	isa_spec_name as NULL and update_version as FALSE to riscv_parse_subset.

	include/
	* opcode/riscv.h (struct riscv_ext_version): New structure holds
	version information for the specific ISA.

	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.
---
 bfd/elfnn-riscv.c                      |  24 ++-
 bfd/elfxx-riscv.c                      | 350 ++++++++++++++++++++++++---------
 bfd/elfxx-riscv.h                      |  12 +-
 gas/config.in                          |   9 +
 gas/config/tc-riscv.c                  | 128 +++++++++++-
 gas/configure                          |  53 ++++-
 gas/configure.ac                       |  35 +++-
 gas/testsuite/gas/riscv/attribute-01.d |   2 +-
 gas/testsuite/gas/riscv/attribute-02.d |   4 +-
 gas/testsuite/gas/riscv/attribute-03.d |   4 +-
 gas/testsuite/gas/riscv/attribute-04.d |   2 +-
 gas/testsuite/gas/riscv/attribute-05.d |   2 +-
 gas/testsuite/gas/riscv/attribute-06.d |   2 +-
 gas/testsuite/gas/riscv/attribute-07.d |   2 +-
 gas/testsuite/gas/riscv/attribute-08.d |   2 +-
 gas/testsuite/gas/riscv/attribute-09.d |   6 +
 gas/testsuite/gas/riscv/attribute-09.s |   1 +
 gas/testsuite/gas/riscv/attribute-10.d |   6 +
 gas/testsuite/gas/riscv/attribute-11.d |   6 +
 include/opcode/riscv.h                 |  11 ++
 opcodes/riscv-opc.c                    |  53 +++++
 21 files changed, 585 insertions(+), 129 deletions(-)
 create mode 100644 gas/testsuite/gas/riscv/attribute-09.d
 create mode 100644 gas/testsuite/gas/riscv/attribute-09.s
 create mode 100644 gas/testsuite/gas/riscv/attribute-10.d
 create mode 100644 gas/testsuite/gas/riscv/attribute-11.d

-- 
2.7.4

Comments

Palmer Dabbelt April 23, 2020, 10:58 p.m. | #1
On Sat, 18 Apr 2020 04:07:51 PDT (-0700), nelson.chu@sifive.com wrote:
> For now, we can only use the GAS option -march and ELF arch attribute to set

> the versions for ISA extensions.  It seems not so friendly for user.

> Therefore, we support new GAS options and configure options to make it easiler

> for user.

>

> New Assembler Options,

>

> * -misa-spec = [2p0|2p1|2p2|20190608|20191213]

> You can simply choose the ISA spec by this option, and then assembler will set

> the version for the standard extensions if you don’t set in the ELF arch

> attributes or -march option.


This makes sense.

> * -mriscv-isa-version = <ISA-string>

> The syntax of <ISA-string> is same as -march option, but without rv32 or rv64

> prefix.  There are two reasons that you may need this option,

>

> 1. Some versions of extensions defined in the ISA spec are not matched to the

> toolchain’s implementation.  For example, V-ext is defined to version 0.7 in

> ISA spec, but we only have implementations for 0.8 and 0.9.  Therefore, you

> have to use this option to choose the correct version for V-ext.

>

> 2. You want to update the version for the specific standard extensions if the

> version are not set in the ELF arch attributes and -march option.


I don't buy the argument for this.  The V extension stuff isn't relevant: those
are all draft versions, and this is a perfect reason why we don't want to take
drafts upstream.   When we have a defined V ISA it'll be part of a versioned
RISC-V specification and any users that want it can just use at least that ISA
spec.

For the second argument, why not just provide those via -march?  I can buy that
it's a pain to build up valid -march strings in build scripts, but this just
fixes a specific instance of that problem (and that's not going to be that
common, as most users just want a single ISA version).

I haven't really looked at the code, as dropping this will change the patches
pretty drasticly.

> New Default Configure Options,

>

> * --with-arch = <ISA-string>

> The syntax of <ISA-string> is same as -march option.  Assembler will check this

> if -march option and ELF arch attributes aren’t set.


Ya, we should have had that a while ago :)

> * --with-isa-spec = [2p0|2p1|2p2|20190608|20191213]

> The syntax is same as -misa-spec option.  Assembler will check this if

> -misa-spec option isn’t set.

>

> * --with-riscv-isa-version = <ISA-string>

> The syntax of <ISA-string> is same as -mriscv-isa-version option.  Assembler

> will check this if -mriscv-isa-version option isn’t set.

>

> The Priority of these options,

>

> * ELF arch attributes > Assembler options > Default configure options

> * For GAS options, -march > -mriscv-isa-version > -misa-spec

> * For configure options, --with-arch > --with-riscv-isa-version > --with-isa-spec

>

> 	gas/

> 	* config/tc-riscv.c (DEFAULT_ARCH_WITH_EXT, DEFAULT_ISA_SPEC,

> 	DEFAULT_RISCV_ISA_VERSION): Default configure option settings.

> 	You can set them by new configure options --with-arch,

> 	--with-isa-spec and --with-riscv-isa-version.

>

> 	(default_arch_with_ext, default_isa_spec, default_riscv_isa_version):

> 	const char strings which are used to set the ISA extensions. You can

> 	use gas options -march (or ELF build attributes), and new gas options

> 	-misa-spec and -mriscv-isa-version to set them, respectively.  If the

> 	gas options and attributes are not set, then assembler will check the

> 	default configure option settings.

>

> 	(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): Add new bfd_boolean parameter update_version.

> 	The update_version is TRUE means we just want to update the version

> 	according to default_riscv_isa_version, so don't call the

> 	riscv_release_subset_list to reset the subset list.  Pass two new

> 	arguments to riscv_parse_subset, one is update_version mentioned above,

> 	the other is the default_isa_spec.  We use the default_isa_spec to

> 	choose the default version for the extensions.

>

> 	(enum options, struct option md_longopts): Add new gas options,

> 	-misa-spec and -mriscv-isa-version.

> 	(md_parse_option): Handle the above new gas options.

> 	(riscv_after_parse_args): Call init_ext_version_hash to initialize the

> 	ext_version_hash, and then always call riscv_set_arch twice to set and

> 	update the architecture with versions according to default_arch_with_ext

> 	and default_riscv_isa_version.

> 	(s_riscv_attribute): Same as riscv_after_parse_args, we need to call

> 	riscv_set_arch twice.

>

> 	* testsuite/gas/riscv/attribute-01.d: Add -misa-spec=2p2.  Set 0p0

> 	as default version for x extensions.

> 	* 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.

> 	* testsuite/gas/riscv/attribute-08.d: Likewise.

> 	* testsuite/gas/riscv/attribute-09.d: New testcase.  For i-ext, we

> 	already set the version 1p9 in elf attribute, so -misa-spec and

> 	-mriscv-isa-version don't update the version to 2p0 and 2p1.

> 	For f-ext, we don't set the version to it, so use the default version

> 	2p0 according to the ISA spec 2p2.  For v-ext, the default version is

> 	0p7 according to ISA spec 2p2, but we use -mriscv-isa-version to update

> 	it to 0p9.  For a-ext, it isn't enabled by -march or elf attribute, so

> 	we don't update it's version even if -mriscv-isa-version is set.

> 	As for the zicsr extension, it is defined in the lastest ISA spec

> 	rather than 2p2, so set it's version to 0p0.

> 	* testsuite/gas/riscv/attribute-09.s: Likewise.

> 	* testsuite/gas/riscv/attribute-10.d: New testcase.  The version of

> 	zicsr is 2p0 according to ISA spec 20191213.

> 	* testsuite/gas/riscv/attribute-11.d: New testcase.  We can also update

> 	the z* extension by -mriscv-isa-version.

>

> 	* configure.ac: Add new configure options, --with-arch, --with-isa-spec

> 	and --with-riscv-isa-version.

> 	* configure: Regenerated.

> 	* config.in: Regenerated.

>

> 	bfd/

> 	* elfxx-riscv.h (struct riscv_subset_t): Add new bfd_boolean field

> 	use_default_version, which is used to record whether the default

> 	version is used for the extension.

> 	(struct riscv_parse_subset_t): Add new callback function

> 	get_default_version.  It is used to find the default version for

> 	the specific extension.

> 	(riscv_add_subset, riscv_parse_subset): Update function declaration.

>

> 	* 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_update_subset_version): Only update the version of existin

> 	standard extensions and their Z* sub extensions, if -mriscv-isa-version

> 	or --with-riscv-isa-version are set, and the default version are used.

>

> 	(riscv_add_subset): New parameter use_default_version.  Record whether

> 	the default version is used.  riscv_update_subset_version only update

> 	the version of extensions if the default versions are used.

>

> 	(riscv_parse_subset): Add two parameters isa_spec_name and

> 	update_version.  Pass them to riscv_parse_std_ext and

> 	riscv_parse_prefixed_ext.  The string set by -mriscv-isa-version or

> 	--with-riscv-isa-version doesn't have to start with rv32/rv64, so

> 	skip the checking if update_version is TRUE.

> 	(riscv_parse_std_ext): If update_version is TRUE, then we just call

> 	riscv_update_subset_version to update the default version.  Otherwise,

> 	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): Same as the riscv_parse_std_ext.

> 	(riscv_std_z_ext_strtab): Support Zicsr extensions.

>

> 	* elfnn-riscv.c (riscv_merge_std_ext, riscv_merge_multi_letter_ext):

> 	Updated.  Pass update_version as FALSE to riscv_add_subset, the

> 	update_version is only needed for assembler, not linker.

> 	(riscv_merge_arch_attr_info): The callback function get_default_version

> 	is only needed for assembler, so set it to NULL in linker.  Also, Pass

> 	isa_spec_name as NULL and update_version as FALSE to riscv_parse_subset.

>

> 	include/

> 	* opcode/riscv.h (struct riscv_ext_version): New structure holds

> 	version information for the specific ISA.

>

> 	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.

> ---

>  bfd/elfnn-riscv.c                      |  24 ++-

>  bfd/elfxx-riscv.c                      | 350 ++++++++++++++++++++++++---------

>  bfd/elfxx-riscv.h                      |  12 +-

>  gas/config.in                          |   9 +

>  gas/config/tc-riscv.c                  | 128 +++++++++++-

>  gas/configure                          |  53 ++++-

>  gas/configure.ac                       |  35 +++-

>  gas/testsuite/gas/riscv/attribute-01.d |   2 +-

>  gas/testsuite/gas/riscv/attribute-02.d |   4 +-

>  gas/testsuite/gas/riscv/attribute-03.d |   4 +-

>  gas/testsuite/gas/riscv/attribute-04.d |   2 +-

>  gas/testsuite/gas/riscv/attribute-05.d |   2 +-

>  gas/testsuite/gas/riscv/attribute-06.d |   2 +-

>  gas/testsuite/gas/riscv/attribute-07.d |   2 +-

>  gas/testsuite/gas/riscv/attribute-08.d |   2 +-

>  gas/testsuite/gas/riscv/attribute-09.d |   6 +

>  gas/testsuite/gas/riscv/attribute-09.s |   1 +

>  gas/testsuite/gas/riscv/attribute-10.d |   6 +

>  gas/testsuite/gas/riscv/attribute-11.d |   6 +

>  include/opcode/riscv.h                 |  11 ++

>  opcodes/riscv-opc.c                    |  53 +++++

>  21 files changed, 585 insertions(+), 129 deletions(-)

>  create mode 100644 gas/testsuite/gas/riscv/attribute-09.d

>  create mode 100644 gas/testsuite/gas/riscv/attribute-09.s

>  create mode 100644 gas/testsuite/gas/riscv/attribute-10.d

>  create mode 100644 gas/testsuite/gas/riscv/attribute-11.d

>

> diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c

> index 8fcb106..4ca49e0 100644

> --- a/bfd/elfnn-riscv.c

> +++ b/bfd/elfnn-riscv.c

> @@ -2802,7 +2802,7 @@ riscv_merge_std_ext (bfd *ibfd,

>    if (!riscv_i_or_e_p (ibfd, out_arch, out))

>      return FALSE;

>

> -  if (in->name[0] != out->name[0])

> +  if (strcasecmp (in->name, out->name) != 0)

>      {

>        /* TODO: We might allow merge 'i' with 'e'.  */

>        _bfd_error_handler

> @@ -2818,8 +2818,8 @@ riscv_merge_std_ext (bfd *ibfd,

>        return FALSE;

>      }

>    else

> -    riscv_add_subset (&merged_subsets,

> -		      in->name, in->major_version, in->minor_version);

> +    riscv_add_subset (&merged_subsets, in->name, in->major_version,

> +		      in->minor_version, FALSE);

>

>    in = in->next;

>    out = out->next;

> @@ -2848,7 +2848,7 @@ riscv_merge_std_ext (bfd *ibfd,

>

>        struct riscv_subset_t *merged = find_in ? find_in : find_out;

>        riscv_add_subset (&merged_subsets, merged->name,

> -			merged->major_version, merged->minor_version);

> +			merged->major_version, merged->minor_version, FALSE);

>      }

>

>    /* Skip all standard extensions.  */

> @@ -2917,14 +2917,14 @@ riscv_merge_multi_letter_ext (bfd *ibfd,

>  	{

>  	  /* `in' comes before `out', append `in' and increment.  */

>  	  riscv_add_subset (&merged_subsets, in->name, in->major_version,

> -			    in->minor_version);

> +			    in->minor_version, FALSE);

>  	  in = in->next;

>  	}

>        else if (cmp > 0)

>  	{

>  	  /* `out' comes before `in', append `out' and increment.  */

>  	  riscv_add_subset (&merged_subsets, out->name, out->major_version,

> -			    out->minor_version);

> +			    out->minor_version, FALSE);

>  	  out = out->next;

>  	}

>        else

> @@ -2938,7 +2938,7 @@ riscv_merge_multi_letter_ext (bfd *ibfd,

>  	    }

>

>  	  riscv_add_subset (&merged_subsets, out->name, out->major_version,

> -			    out->minor_version);

> +			    out->minor_version, FALSE);

>  	  out = out->next;

>  	  in = in->next;

>  	}

> @@ -2952,7 +2952,7 @@ riscv_merge_multi_letter_ext (bfd *ibfd,

>      while (tail)

>        {

>  	riscv_add_subset (&merged_subsets, tail->name, tail->major_version,

> -			  tail->minor_version);

> +			  tail->minor_version, FALSE);

>  	tail = tail->next;

>        }

>    }

> @@ -2975,13 +2975,17 @@ riscv_merge_arch_attr_info (bfd *ibfd, char *in_arch, char *out_arch)

>    riscv_parse_subset_t rpe_in;

>    riscv_parse_subset_t rpe_out;

>

> +  /* Only assembler needs to check the default version of ISA, so just set

> +     the rpe_in.get_default_version and rpe_out.get_default_version to NULL.  */

>    rpe_in.subset_list = &in_subsets;

>    rpe_in.error_handler = _bfd_error_handler;

>    rpe_in.xlen = &xlen_in;

> +  rpe_in.get_default_version = NULL;

>

>    rpe_out.subset_list = &out_subsets;

>    rpe_out.error_handler = _bfd_error_handler;

>    rpe_out.xlen = &xlen_out;

> +  rpe_out.get_default_version = NULL;

>

>    if (in_arch == NULL && out_arch == NULL)

>      return NULL;

> @@ -2993,10 +2997,10 @@ riscv_merge_arch_attr_info (bfd *ibfd, char *in_arch, char *out_arch)

>      return in_arch;

>

>    /* Parse subset from arch string.  */

> -  if (!riscv_parse_subset (&rpe_in, in_arch))

> +  if (!riscv_parse_subset (&rpe_in, in_arch, NULL, FALSE))

>      return NULL;

>

> -  if (!riscv_parse_subset (&rpe_out, out_arch))

> +  if (!riscv_parse_subset (&rpe_out, out_arch, NULL, FALSE))

>      return NULL;

>

>    /* Checking XLEN.  */

> diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c

> index b15fdee..3a6aaf3 100644

> --- a/bfd/elfxx-riscv.c

> +++ b/bfd/elfxx-riscv.c

> @@ -1025,9 +1025,8 @@ riscv_elf_add_sub_reloc (bfd *abfd,

>       `minor_version`: Parsing result of minor version, set to 0 if version is

>       not present in arch string, but set to `default_minor_version` if

>       `major_version` using default_major_version.

> -     `default_major_version`: Default major version.

> -     `default_minor_version`: Default minor version.

> -     `std_ext_p`: True if parsing std extension.  */

> +     `std_ext_p`: True if parsing std extension.

> +     `use_default_version`: Set it to True if we need the default version.  */

>

>  static const char *

>  riscv_parsing_subset_version (riscv_parse_subset_t *rps,

> @@ -1035,17 +1034,16 @@ riscv_parsing_subset_version (riscv_parse_subset_t *rps,

>  			      const char *p,

>  			      unsigned *major_version,

>  			      unsigned *minor_version,

> -			      unsigned default_major_version,

> -			      unsigned default_minor_version,

> -			      bfd_boolean std_ext_p)

> +			      bfd_boolean std_ext_p,

> +			      bfd_boolean *use_default_version)

>  {

>    bfd_boolean major_p = TRUE;

>    unsigned version = 0;

> -  unsigned major = 0;

> -  unsigned minor = 0;

>    char np;

>

> -  for (;*p; ++p)

> +  *major_version = 0;

> +  *minor_version = 0;

> +  for (; *p; ++p)

>      {

>        if (*p == 'p')

>  	{

> @@ -1057,7 +1055,6 @@ riscv_parsing_subset_version (riscv_parse_subset_t *rps,

>  	      if (std_ext_p)

>  		{

>  		  *major_version = version;

> -		  *minor_version = 0;

>  		  return p;

>  		}

>  	      else

> @@ -1068,7 +1065,7 @@ riscv_parsing_subset_version (riscv_parse_subset_t *rps,

>  		}

>  	    }

>

> -	  major = version;

> +	  *major_version = version;

>  	  major_p = FALSE;

>  	  version = 0;

>  	}

> @@ -1079,21 +1076,15 @@ riscv_parsing_subset_version (riscv_parse_subset_t *rps,

>      }

>

>    if (major_p)

> -    major = version;

> +    *major_version = version;

>    else

> -    minor = version;

> +    *minor_version = version;

>

> -  if (major == 0 && minor == 0)

> -    {

> -      /* We don't found any version string, use default version.  */

> -      *major_version = default_major_version;

> -      *minor_version = default_minor_version;

> -    }

> -  else

> -    {

> -      *major_version = major;

> -      *minor_version = minor;

> -    }

> +  /* We can not find any version in string, need to parse default version.  */

> +  if (use_default_version != NULL

> +      && *major_version == 0

> +      && *minor_version == 0)

> +    *use_default_version = TRUE;

>    return p;

>  }

>

> @@ -1106,6 +1097,41 @@ riscv_supported_std_ext (void)

>    return "mafdqlcbjtpvn";

>  }

>

> +/* Update the version of standard extensions and their Z* sub extensions

> +   if -mriscv-isa-version is set.  */

> +

> +static bfd_boolean

> +riscv_update_subset_version (riscv_parse_subset_t *rps,

> +			     const char *ext_with_version,

> +			     char *ext,

> +                             unsigned major_version,

> +			     unsigned minor_version,

> +			     bfd_boolean use_default_version)

> +{

> +  riscv_subset_t *subset = riscv_lookup_subset (rps->subset_list, ext);;

> +

> +  /* The extension doesn't exist, so just return.  */

> +  if (subset == NULL)

> +    return TRUE;

> +

> +  /* This means we can not find the version in the string.  */

> +  if (use_default_version)

> +    {

> +      rps->error_handler ("-mriscv-isa-version=%s: unexpected version "

> +			  "setting for subset `%s'", ext_with_version, ext);

> +      return FALSE;

> +    }

> +

> +  /* We only update the extension which use the default version.  */

> +  if (subset->use_default_version)

> +    {

> +      subset->major_version = major_version;

> +      subset->minor_version = minor_version;

> +    }

> +

> +  return TRUE;

> +}

> +

>  /* Parsing function for standard extensions.

>

>     Return Value:

> @@ -1114,46 +1140,95 @@ riscv_supported_std_ext (void)

>     Arguments:

>       `rps`: Hooks and status for parsing subset.

>       `march`: Full arch string.

> -     `p`: Curent parsing position.  */

> +     `p`: Curent parsing position.

> +     `isa_spec_name`: The ISA spec name.  We set the default ISA versions

> +     according to it.

> +     `update_version`: True if the -mriscv-isa-version is set, and we need

> +     to update the version for the existing extensions.  */

>

>  static const char *

>  riscv_parse_std_ext (riscv_parse_subset_t *rps,

> -		     const char *march, const char *p)

> +		     const char *march,

> +		     const char *p,

> +		     const char *isa_spec_name,

> +		     bfd_boolean update_version)

>  {

>    const char *all_std_exts = riscv_supported_std_ext ();

>    const char *std_exts = all_std_exts;

> -

>    unsigned major_version = 0;

>    unsigned minor_version = 0;

>    char std_ext = '\0';

> +  bfd_boolean use_default_version = FALSE;

>

>    /* First letter must start with i, e or g.  */

>    switch (*p)

>      {

>        case 'i':

> -	p++;

> -	p = riscv_parsing_subset_version (

> -	      rps,

> -	      march,

> -	      p, &major_version, &minor_version,

> -	      /* default_major_version= */ 2,

> -	      /* default_minor_version= */ 0,

> -	      /* std_ext_p= */TRUE);

> -	riscv_add_subset (rps->subset_list, "i", major_version, minor_version);

> +	p = riscv_parsing_subset_version (rps,

> +					  march,

> +					  ++p,

> +					  &major_version,

> +					  &minor_version,

> +					  /* std_ext_p= */TRUE,

> +					  &use_default_version);

> +

> +	/* Update the version for exsiting extension.  */

> +	if (update_version)

> +	  {

> +	    if (!riscv_update_subset_version (rps, march, "i",

> +					      major_version,

> +					      minor_version,

> +					      use_default_version))

> +	      return NULL;

> +	    break;

> +	  }

> +

> +	/* Find the default version if needed.  */

> +	if (use_default_version)

> +	  rps->get_default_version ("i",

> +				    isa_spec_name,

> +				    &major_version,

> +				    &minor_version);

> +	riscv_add_subset (rps->subset_list, "i", major_version, minor_version,

> +			  use_default_version);

>  	break;

>

>        case 'e':

> -	p++;

> -	p = riscv_parsing_subset_version (

> -	      rps,

> -	      march,

> -	      p, &major_version, &minor_version,

> -	      /* default_major_version= */ 1,

> -	      /* default_minor_version= */ 9,

> -	      /* std_ext_p= */TRUE);

> -

> -	riscv_add_subset (rps->subset_list, "e", major_version, minor_version);

> -	riscv_add_subset (rps->subset_list, "i", 2, 0);

> +	p = riscv_parsing_subset_version (rps,

> +					  march,

> +					  ++p,

> +					  &major_version,

> +					  &minor_version,

> +					  /* std_ext_p= */TRUE,

> +					  &use_default_version);

> +

> +	/* Update the version for exsiting extension.  */

> +	if (update_version)

> +	  {

> +	    if (!riscv_update_subset_version (rps, march, "e",

> +					      major_version,

> +					      minor_version,

> +					      use_default_version))

> +	      return NULL;

> +	    break;

> +	  }

> +

> +	/* Find the default version if needed.  */

> +	if (use_default_version)

> +	  rps->get_default_version ("e",

> +				    isa_spec_name,

> +				    &major_version,

> +				    &minor_version);

> +	riscv_add_subset (rps->subset_list, "e", major_version, minor_version,

> +			  use_default_version);

> +

> +	/* i-ext must be enabled.  */

> +	rps->get_default_version ("i",

> +				  isa_spec_name,

> +				  &major_version,

> +				  &minor_version);

> +	riscv_add_subset (rps->subset_list, "i", major_version, minor_version,

> +			  TRUE);

>

>  	if (*rps->xlen > 32)

>  	  {

> @@ -1161,35 +1236,58 @@ riscv_parse_std_ext (riscv_parse_subset_t *rps,

>  				march, *rps->xlen);

>  	    return NULL;

>  	  }

> -

>  	break;

>

>        case 'g':

> -	p++;

> -	p = riscv_parsing_subset_version (

> -	      rps,

> -	      march,

> -	      p, &major_version, &minor_version,

> -	      /* default_major_version= */ 2,

> -	      /* default_minor_version= */ 0,

> -	      /* std_ext_p= */TRUE);

> -	riscv_add_subset (rps->subset_list, "i", major_version, minor_version);

> +	/* The g-ext shouldn't has the version, so we just skip the setting if

> +	   user set a version to it.  */

> +	p = riscv_parsing_subset_version (rps,

> +					  march,

> +					  ++p,

> +					  &major_version,

> +					  &minor_version,

> +					  TRUE,

> +					  &use_default_version);

> +

> +	/* Set the version of g in -mriscv-isa-version is meaningless,

> +	   so just skip it.  */

> +	if (update_version)

> +	  break;

> +

> +	/* i-ext must be enabled.  */

> +	rps->get_default_version ("i",

> +				  isa_spec_name,

> +				  &major_version,

> +				  &minor_version);

> +	riscv_add_subset (rps->subset_list, "i", major_version, minor_version,

> +			  TRUE);

>

>  	for ( ; *std_exts != 'q'; std_exts++)

>  	  {

>  	    const char subset[] = {*std_exts, '\0'};

> -	    riscv_add_subset (

> -	      rps->subset_list, subset, major_version, minor_version);

> +	    rps->get_default_version (subset,

> +				      isa_spec_name,

> +				      &major_version,

> +				      &minor_version);

> +	    riscv_add_subset (rps->subset_list, subset, major_version,

> +			      minor_version, TRUE);

>  	  }

>  	break;

>

>        default:

> -	rps->error_handler (

> -	  "-march=%s: first ISA subset must be `e', `i' or `g'", march);

> -	return NULL;

> +	/* The first ISA subset of -mriscv-isa-version will not necessarily

> +	   be e/i/g.  */

> +	if (!update_version)

> +	  {

> +	    rps->error_handler (

> +	    "-march=%s: first ISA subset must be `e', `i' or `g'", march);

> +	    return NULL;

> +	  }

>      }

>

> -  while (*p)

> +  /* The riscv_parsing_subset_version may set `p` to NULL, so I think we should

> +     skip parsing the string if `p` is NULL or value of `p` is `\0`.  */

> +  while (p != NULL && *p != '\0')

>      {

>        char subset[2] = {0, 0};

>

> @@ -1218,21 +1316,37 @@ riscv_parse_std_ext (riscv_parse_subset_t *rps,

>  	      march, *p);

>  	  return NULL;

>  	}

> -

>        std_exts++;

>

> -      p++;

> -      p = riscv_parsing_subset_version (

> -	    rps,

> -	    march,

> -	    p, &major_version, &minor_version,

> -	    /* default_major_version= */ 2,

> -	    /* default_minor_version= */ 0,

> -	    /* std_ext_p= */TRUE);

> -

> +      use_default_version = FALSE;

>        subset[0] = std_ext;

> +      p = riscv_parsing_subset_version (rps,

> +					march,

> +					++p,

> +					&major_version,

> +					&minor_version,

> +					TRUE,

> +					&use_default_version);

> +

> +      /* Update the version for exsiting extension.  */

> +      if (update_version)

> +	{

> +	  if (!riscv_update_subset_version (rps, march, subset,

> +					    major_version,

> +					    minor_version,

> +					    use_default_version))

> +	    return NULL;

> +	  continue;

> +	}

>

> -      riscv_add_subset (rps->subset_list, subset, major_version, minor_version);

> +      /* Find the default version if needed.  */

> +      if (use_default_version)

> +	rps->get_default_version (subset,

> +				  isa_spec_name,

> +				  &major_version,

> +				  &minor_version);

> +      riscv_add_subset (rps->subset_list, subset, major_version, minor_version,

> +			use_default_version);

>      }

>    return p;

>  }

> @@ -1272,21 +1386,28 @@ typedef struct riscv_parse_config

>  } riscv_parse_config_t;

>

>  /* Parse a generic prefixed extension.

> -   march: The full architecture string as passed in by "-march=...".

> -   p: Point from which to start parsing the -march string.

> -   config: What class of extensions to parse, predicate funcs,

> -   and strings to use in error reporting.  */

> +   `march`: The full architecture string as passed in by "-march=...".

> +   `p`: Point from which to start parsing the -march string.

> +   `config`: What class of extensions to parse, predicate funcs,

> +   and strings to use in error reporting.

> +   `isa_spec_name`: ISA spec name.  We set the default ISA versions

> +   according to it.

> +   `update_version`: True if the -mriscv-isa-version is set, and we need

> +   update the version for the existing extensions.  */

>

>  static const char *

>  riscv_parse_prefixed_ext (riscv_parse_subset_t *rps,

>  			  const char *march,

>  			  const char *p,

> -			  const riscv_parse_config_t *config)

> +			  const riscv_parse_config_t *config,

> +			  const char *isa_spec_name,

> +			  bfd_boolean update_version)

>  {

>    unsigned major_version = 0;

>    unsigned minor_version = 0;

>    const char *last_name;

>    riscv_isa_ext_class_t class;

> +  bfd_boolean use_default_version;

>

>    while (*p)

>      {

> @@ -1309,15 +1430,11 @@ riscv_parse_prefixed_ext (riscv_parse_subset_t *rps,

>        while (*++q != '\0' && *q != '_' && !ISDIGIT (*q))

>  	;

>

> +      use_default_version = FALSE;

>        end_of_version =

> -	riscv_parsing_subset_version (

> -	  rps,

> -	  march,

> -	  q, &major_version, &minor_version,

> -	  /* default_major_version= */ 2,

> -	  /* default_minor_version= */ 0,

> -	  /* std_ext_p= */FALSE);

> -

> +	riscv_parsing_subset_version (rps, march, q, &major_version,

> +				      &minor_version, FALSE,

> +				      &use_default_version);

>        *q = '\0';

>

>        /* Check that the name is valid.

> @@ -1335,10 +1452,11 @@ riscv_parse_prefixed_ext (riscv_parse_subset_t *rps,

>  	  return NULL;

>  	}

>

> -      /* Check that the last item is not the same as this.  */

> +      /* Check that the last item is not the same as this.  Just skip this

> +	 check when updating the version.  */

>        last_name = rps->subset_list->tail->name;

> -

> -      if (!strcasecmp (last_name, subset))

> +      if (!update_version

> +	  && !strcasecmp (last_name, subset))

>  	{

>  	  rps->error_handler ("-march=%s: Duplicate %s ISA extension: \'%s\'",

>  			      march, config->prefix, subset);

> @@ -1357,7 +1475,30 @@ riscv_parse_prefixed_ext (riscv_parse_subset_t *rps,

>  	  return NULL;

>  	}

>

> -      riscv_add_subset (rps->subset_list, subset, major_version, minor_version);

> +      if (update_version)

> +	{

> +	  /* Update the version for exsiting extension.  */

> +	  if (!riscv_update_subset_version (rps, march, subset,

> +					    major_version,

> +					    minor_version,

> +					    use_default_version))

> +	    {

> +	      free (subset);

> +	      return NULL;

> +	    }

> +	}

> +      else

> +	{

> +	  /* Find the default version if needed.  */

> +	  if (use_default_version)

> +	    rps->get_default_version (subset,

> +				      isa_spec_name,

> +				      &major_version,

> +				      &minor_version);

> +	  riscv_add_subset (rps->subset_list, subset, major_version,

> +			    minor_version, use_default_version);

> +	}

> +

>        free (subset);

>        p += end_of_version - subset;

>

> @@ -1384,7 +1525,7 @@ riscv_parse_prefixed_ext (riscv_parse_subset_t *rps,

>

>  static const char * const riscv_std_z_ext_strtab[] =

>    {

> -    NULL

> +    "zicsr", NULL

>    };

>

>  /* Same as `riscv_std_z_ext_strtab', but for S-class extensions.  */

> @@ -1457,11 +1598,17 @@ static const riscv_parse_config_t parse_config[] =

>

>     Arguments:

>       `rps`: Hooks and status for parsing subset.

> -     `arch`: Arch string.  */

> +     `arch`: Arch string.

> +     `isa_spec_name`: The ISA spec name.   We set the default ISA versions

> +     according to it.

> +     `update_version`: True if the -mriscv-isa-version is set, and we need

> +     update the version for the existing extensions.  */

>

>  bfd_boolean

>  riscv_parse_subset (riscv_parse_subset_t *rps,

> -		    const char *arch)

> +		    const char *arch,

> +		    const char *isa_spec_name,

> +		    bfd_boolean update_version)

>  {

>    const char *p = arch;

>    size_t i;

> @@ -1476,15 +1623,17 @@ riscv_parse_subset (riscv_parse_subset_t *rps,

>        *rps->xlen = 64;

>        p += 4;

>      }

> -  else

> +  else if (!update_version)

>      {

> +      /* The string set by -mriscv-isa-version doesn't have to start

> +	 with rv32/rv64.  */

>        rps->error_handler ("-march=%s: ISA string must begin with rv32 or rv64",

>  			  arch);

>        return FALSE;

>      }

>

>    /* Parsing standard extension.  */

> -  p = riscv_parse_std_ext (rps, arch, p);

> +  p = riscv_parse_std_ext (rps, arch, p, isa_spec_name, update_version);

>

>    if (p == NULL)

>      return FALSE;

> @@ -1492,7 +1641,8 @@ riscv_parse_subset (riscv_parse_subset_t *rps,

>    /* Parse the different classes of extensions in the specified order.  */

>

>    for (i = 0; i < ARRAY_SIZE (parse_config); ++i) {

> -    p = riscv_parse_prefixed_ext (rps, arch, p, &parse_config[i]);

> +    p = riscv_parse_prefixed_ext (rps, arch, p, &parse_config[i],

> +				  isa_spec_name, update_version);

>

>      if (p == NULL)

>        return FALSE;

> @@ -1543,7 +1693,8 @@ riscv_parse_subset (riscv_parse_subset_t *rps,

>  void

>  riscv_add_subset (riscv_subset_list_t *subset_list,

>  		  const char *subset,

> -		  int major, int minor)

> +		  int major, int minor,

> +		  bfd_boolean use_default_version)

>  {

>    riscv_subset_t *s = xmalloc (sizeof *s);

>

> @@ -1553,6 +1704,9 @@ riscv_add_subset (riscv_subset_list_t *subset_list,

>    s->name = xstrdup (subset);

>    s->major_version = major;

>    s->minor_version = minor;

> +  /* Record whether the default version is used.  The -mriscv-isa-version

> +     only update the ISA which use the default version.  */

> +  s->use_default_version = use_default_version;

>    s->next = NULL;

>

>    if (subset_list->tail != NULL)

> diff --git a/bfd/elfxx-riscv.h b/bfd/elfxx-riscv.h

> index 76ee274..e3d5177 100644

> --- a/bfd/elfxx-riscv.h

> +++ b/bfd/elfxx-riscv.h

> @@ -40,6 +40,7 @@ struct riscv_subset_t

>    const char *name;

>    int major_version;

>    int minor_version;

> +  bfd_boolean use_default_version;

>    struct riscv_subset_t *next;

>  };

>

> @@ -56,7 +57,8 @@ riscv_release_subset_list (riscv_subset_list_t *);

>  extern void

>  riscv_add_subset (riscv_subset_list_t *,

>  		  const char *,

> -		  int, int);

> +		  int, int,

> +		  bfd_boolean);

>

>  extern riscv_subset_t *

>  riscv_lookup_subset (const riscv_subset_list_t *,

> @@ -72,11 +74,17 @@ typedef struct {

>    void (*error_handler) (const char *,

>  			 ...) ATTRIBUTE_PRINTF_1;

>    unsigned *xlen;

> +  void (*get_default_version) (const char *,

> +			       const char *,

> +			       unsigned int *,

> +			       unsigned int *);

>  } riscv_parse_subset_t;

>

>  extern bfd_boolean

>  riscv_parse_subset (riscv_parse_subset_t *,

> -		    const char *);

> +		    const char *,

> +		    const char *,

> +		    bfd_boolean);

>

>  extern const char *

>  riscv_supported_std_ext (void);

> diff --git a/gas/config.in b/gas/config.in

> index 8724eb1..935bd9b 100644

> --- a/gas/config.in

> +++ b/gas/config.in

> @@ -30,6 +30,9 @@

>  /* Default architecture. */

>  #undef DEFAULT_ARCH

>

> +/* Define default value for -march */

> +#undef DEFAULT_ARCH_WITH_EXT

> +

>  /* Default CRIS architecture. */

>  #undef DEFAULT_CRIS_ARCH

>

> @@ -50,12 +53,18 @@

>  /* Define to 1 if you want to generate x86 relax relocations by default. */

>  #undef DEFAULT_GENERATE_X86_RELAX_RELOCATIONS

>

> +/* Define default value for -misa-spec */

> +#undef DEFAULT_ISA_SPEC

> +

>  /* Define to 1 if you want to fix Loongson3 LLSC Errata by default. */

>  #undef DEFAULT_MIPS_FIX_LOONGSON3_LLSC

>

>  /* Define to 1 if you want to generate RISC-V arch attribute by default. */

>  #undef DEFAULT_RISCV_ATTR

>

> +/* Define default isa version which are not covered by --with-isa-spec */

> +#undef DEFAULT_RISCV_ISA_VERSION

> +

>  /* Define to 1 if you want to generate GNU x86 used ISA and feature properties

>     by default. */

>  #undef DEFAULT_X86_USED_NOTE

> diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c

> index 168561e..bfcf2f0 100644

> --- a/gas/config/tc-riscv.c

> +++ b/gas/config/tc-riscv.c

> @@ -63,7 +63,22 @@ struct riscv_cl_insn

>  #define DEFAULT_RISCV_ATTR 0

>  #endif

>

> +#ifndef DEFAULT_ARCH_WITH_EXT

> +#define DEFAULT_ARCH_WITH_EXT NULL

> +#endif

> +

> +#ifndef DEFAULT_ISA_SPEC

> +#define DEFAULT_ISA_SPEC "2p2"

> +#endif

> +

> +#ifndef DEFAULT_RISCV_ISA_VERSION

> +#define DEFAULT_RISCV_ISA_VERSION NULL

> +#endif

> +

>  static const char default_arch[] = DEFAULT_ARCH;

> +static const char *default_arch_with_ext = DEFAULT_ARCH_WITH_EXT;

> +static const char *default_isa_spec = DEFAULT_ISA_SPEC;

> +static const char *default_riscv_isa_version = DEFAULT_RISCV_ISA_VERSION;

>

>  static unsigned xlen = 0; /* width of an x-register */

>  static unsigned abi_xlen = 0; /* width of a pointer in the ABI */

> @@ -147,18 +162,87 @@ 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,

> +			       const char *spec_name,

> +			       unsigned int *major_version,

> +			       unsigned int *minor_version)

> +{

> +  struct riscv_ext_version *ext;

> +

> +  *major_version = 0;

> +  *minor_version = 0;

> +

> +  if (name == NULL

> +      || spec_name == NULL)

> +    return;

> +

> +  ext = (struct riscv_ext_version *) hash_find (ext_version_hash, name);

> +  while (ext

> +	 && ext->name

> +	 && strcmp (ext->name, name) == 0)

> +    {

> +      if (ext->spec_name

> +	  && strcmp (ext->spec_name, spec_name) == 0)

> +	{

> +	  *major_version = ext->major_version;

> +	  *minor_version = ext->minor_version;

> +	  return;

> +	}

> +      ext++;

> +    }

> +}

> +

>  /* Set which ISA and extensions are available.  */

>

>  static void

> -riscv_set_arch (const char *s)

> +riscv_set_arch (const char *s, bfd_boolean update_version)

>  {

>    riscv_parse_subset_t rps;

>    rps.subset_list = &riscv_subsets;

>    rps.error_handler = as_fatal;

>    rps.xlen = &xlen;

> +  rps.get_default_version = riscv_get_default_ext_version;

>

> -  riscv_release_subset_list (&riscv_subsets);

> -  riscv_parse_subset (&rps, s);

> +  if (s == NULL)

> +    return;

> +

> +  if (!update_version)

> +    riscv_release_subset_list (&riscv_subsets);

> +  riscv_parse_subset (&rps, s, default_isa_spec, update_version);

>  }

>

>  /* Handle of the OPCODE hash table.  */

> @@ -2348,6 +2432,8 @@ enum options

>    OPTION_NO_ARCH_ATTR,

>    OPTION_CSR_CHECK,

>    OPTION_NO_CSR_CHECK,

> +  OPTION_MISA_SPEC,

> +  OPTION_MRISCV_ISA_VERSION,

>    OPTION_END_OF_ENUM

>  };

>

> @@ -2364,6 +2450,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},

> +  {"mriscv-isa-version", required_argument, NULL, OPTION_MRISCV_ISA_VERSION},

>

>    {NULL, no_argument, NULL, 0}

>  };

> @@ -2392,7 +2480,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 +2540,14 @@ md_parse_option (int c, const char *arg)

>        riscv_opts.csr_check = FALSE;

>        break;

>

> +    case OPTION_MISA_SPEC:

> +      default_isa_spec = arg;

> +      break;

> +

> +    case OPTION_MRISCV_ISA_VERSION:

> +      default_riscv_isa_version = arg;

> +      break;

> +

>      default:

>        return 0;

>      }

> @@ -2460,6 +2558,13 @@ md_parse_option (int c, const char *arg)

>  void

>  riscv_after_parse_args (void)

>  {

> +  /* Initialize the hash table for extensions with default version.  */

> +  ext_version_hash = init_ext_version_hash (riscv_ext_version_table);

> +

> +  /* 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 +2574,15 @@ 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";

> +

> +  /* Set the architecture according to -march or --with-arch.  */

> +  riscv_set_arch (default_arch_with_ext, FALSE);

>

> -  if (riscv_subsets.head == NULL)

> -    riscv_set_arch (xlen == 64 ? "rv64g" : "rv32g");

> +  /* Update the version info according to -mriscv-isa-spec or

> +     --with-riscv-isa-spec.  */

> +  riscv_set_arch (default_riscv_isa_version, TRUE);

>

>    /* Add the RVC extension, regardless of -march, to support .option rvc.  */

>    riscv_set_rvc (FALSE);

> @@ -3366,7 +3477,7 @@ s_riscv_attribute (int ignored ATTRIBUTE_UNUSED)

>        obj_attribute *attr;

>        attr = elf_known_obj_attributes_proc (stdoutput);

>        if (!start_assemble)

> -	riscv_set_arch (attr[Tag_RISCV_arch].s);

> +	riscv_set_arch (attr[Tag_RISCV_arch].s, FALSE);

>        else

>  	as_fatal (_(".attribute arch must set before any instructions"));

>

> @@ -3379,6 +3490,9 @@ 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"));

>  	}

> +

> +      /* We also need to update the version of ISA here.  */

> +      riscv_set_arch (default_riscv_isa_version, TRUE);

>      }

>  }

>

> diff --git a/gas/configure b/gas/configure

> index 1515787..bce847a 100755

> --- a/gas/configure

> +++ b/gas/configure

> @@ -13009,7 +13009,7 @@ $as_echo "#define NDS32_DEFAULT_ZOL_EXT 1" >>confdefs.h

>  $as_echo "$enable_zol_ext" >&6; }

>  	;;

>

> -      aarch64 | i386 | riscv | s390 | sparc)

> +      aarch64 | i386 | s390 | sparc)

>  	if test $this_target = $target ; then

>

>  cat >>confdefs.h <<_ACEOF

> @@ -13019,6 +13019,57 @@ _ACEOF

>  	fi

>  	;;

>

> +      riscv)

> +	# --target=riscv[32|64]-*-*.  */

> +	if test $this_target = $target ; then

> +

> +cat >>confdefs.h <<_ACEOF

> +#define DEFAULT_ARCH "${arch}"

> +_ACEOF

> +

> +	fi

> +

> +	# --with-arch=<value>.  The syntax of <value> is same as Gas option -march.

> +	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for default configuration of --with-arch" >&5

> +$as_echo_n "checking for default configuration of --with-arch... " >&6; }

> +	if test "x${with_arch}" != x; then

> +

> +cat >>confdefs.h <<_ACEOF

> +#define DEFAULT_ARCH_WITH_EXT "$with_arch"

> +_ACEOF

> +

> +	fi

> +	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_arch" >&5

> +$as_echo "$with_arch" >&6; }

> +

> +	# --with-isa-spec=[2p0|2p1|2p2|20190608|20191213].

> +	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for default configuration of --with-isa-spec" >&5

> +$as_echo_n "checking for default configuration of --with-isa-spec... " >&6; }

> +	if test "x${with_isa_spec}" != x; then

> +

> +cat >>confdefs.h <<_ACEOF

> +#define DEFAULT_ISA_SPEC "$with_isa_spec"

> +_ACEOF

> +

> +	fi

> +	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_isa_spec" >&5

> +$as_echo "$with_isa_spec" >&6; }

> +

> +	# --with-riscv-isa-version=<value>.  The syntax of <value> is same as Gas

> +	# -march, but without the rv[32|64] prefix.

> +	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for default configuration of --with-riscv-isa-version" >&5

> +$as_echo_n "checking for default configuration of --with-riscv-isa-version... " >&6; }

> +	if test "x${with_riscv_isa_version}" != x; then

> +

> +cat >>confdefs.h <<_ACEOF

> +#define DEFAULT_RISCV_ISA_VERSION "$with_riscv_isa_version"

> +_ACEOF

> +

> +	fi

> +	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_riscv_isa_version" >&5

> +$as_echo "$with_riscv_isa_version" >&6; }

> +	;;

> +

>        rl78)

>  	f=rl78-parse.o

>  	case " $extra_objects " in

> diff --git a/gas/configure.ac b/gas/configure.ac

> index 6f32e55..be4ba20 100644

> --- a/gas/configure.ac

> +++ b/gas/configure.ac

> @@ -569,12 +569,45 @@ changequote([,])dnl

>  	AC_MSG_RESULT($enable_zol_ext)

>  	;;

>

> -      aarch64 | i386 | riscv | s390 | sparc)

> +      aarch64 | i386 | s390 | sparc)

>  	if test $this_target = $target ; then

>  	  AC_DEFINE_UNQUOTED(DEFAULT_ARCH, "${arch}", [Default architecture.])

>  	fi

>  	;;

>

> +      riscv)

> +	# --target=riscv[32|64]-*-*.  */

> +	if test $this_target = $target ; then

> +	  AC_DEFINE_UNQUOTED(DEFAULT_ARCH, "${arch}", [Default architecture.])

> +	fi

> +

> +	# --with-arch=<value>.  The syntax of <value> is same as Gas option -march.

> +	AC_MSG_CHECKING(for default configuration of --with-arch)

> +	if test "x${with_arch}" != x; then

> +	  AC_DEFINE_UNQUOTED(DEFAULT_ARCH_WITH_EXT, "$with_arch",

> +			     [Define default value for -march])

> +	fi

> +	AC_MSG_RESULT($with_arch)

> +

> +	# --with-isa-spec=[2p0|2p1|2p2|20190608|20191213].

> +	AC_MSG_CHECKING(for default configuration of --with-isa-spec)

> +	if test "x${with_isa_spec}" != x; then

> +	  AC_DEFINE_UNQUOTED(DEFAULT_ISA_SPEC, "$with_isa_spec",

> +			     [Define default value for -misa-spec])

> +	fi

> +	AC_MSG_RESULT($with_isa_spec)

> +

> +	# --with-riscv-isa-version=<value>.  The syntax of <value> is same as Gas

> +	# -march, but without the rv[32|64] prefix.

> +	AC_MSG_CHECKING(for default configuration of --with-riscv-isa-version)

> +	if test "x${with_riscv_isa_version}" != x; then

> +	  AC_DEFINE_UNQUOTED(DEFAULT_RISCV_ISA_VERSION, "$with_riscv_isa_version",

> +			     [Define default isa version which are not

> +			      covered by --with-isa-spec])

> +	fi

> +	AC_MSG_RESULT($with_riscv_isa_version)

> +	;;

> +

>        rl78)

>  	f=rl78-parse.o

>  	case " $extra_objects " in

> diff --git a/gas/testsuite/gas/riscv/attribute-01.d b/gas/testsuite/gas/riscv/attribute-01.d

> index e22773e..3f9e841 100644

> --- a/gas/testsuite/gas/riscv/attribute-01.d

> +++ b/gas/testsuite/gas/riscv/attribute-01.d

> @@ -1,4 +1,4 @@

> -#as: -march=rv32g -march-attr

> +#as: -march=rv32g -march-attr -misa-spec=2p2

>  #readelf: -A

>  #source: empty.s

>  Attribute Section: riscv

> diff --git a/gas/testsuite/gas/riscv/attribute-02.d b/gas/testsuite/gas/riscv/attribute-02.d

> index bc3295b..a58248e 100644

> --- a/gas/testsuite/gas/riscv/attribute-02.d

> +++ b/gas/testsuite/gas/riscv/attribute-02.d

> @@ -1,6 +1,6 @@

> -#as: -march=rv32gxargle -march-attr

> +#as: -march=rv32gxargle -march-attr -misa-spec=2p2

>  #readelf: -A

>  #source: empty.s

>  Attribute Section: riscv

>  File Attributes

> -  Tag_RISCV_arch: "rv32i2p0_m2p0_a2p0_f2p0_d2p0_xargle2p0"

> +  Tag_RISCV_arch: "rv32i2p0_m2p0_a2p0_f2p0_d2p0_xargle0p0"

> diff --git a/gas/testsuite/gas/riscv/attribute-03.d b/gas/testsuite/gas/riscv/attribute-03.d

> index 78b706a..04b9ab5 100644

> --- a/gas/testsuite/gas/riscv/attribute-03.d

> +++ b/gas/testsuite/gas/riscv/attribute-03.d

> @@ -1,6 +1,6 @@

> -#as: -march=rv32gxargle_xfoo -march-attr

> +#as: -march=rv32gxargle_xfoo -march-attr -misa-spec=2p2

>  #readelf: -A

>  #source: empty.s

>  Attribute Section: riscv

>  File Attributes

> -  Tag_RISCV_arch: "rv32i2p0_m2p0_a2p0_f2p0_d2p0_xargle2p0_xfoo2p0"

> +  Tag_RISCV_arch: "rv32i2p0_m2p0_a2p0_f2p0_d2p0_xargle0p0_xfoo0p0"

> diff --git a/gas/testsuite/gas/riscv/attribute-04.d b/gas/testsuite/gas/riscv/attribute-04.d

> index c97bf03..8a3f51b 100644

> --- a/gas/testsuite/gas/riscv/attribute-04.d

> +++ b/gas/testsuite/gas/riscv/attribute-04.d

> @@ -1,4 +1,4 @@

> -#as: -march-attr

> +#as: -march-attr -misa-spec=2p2

>  #readelf: -A

>  #source: attribute-04.s

>  Attribute Section: riscv

> diff --git a/gas/testsuite/gas/riscv/attribute-05.d b/gas/testsuite/gas/riscv/attribute-05.d

> index f9b65f2..3309ff3 100644

> --- a/gas/testsuite/gas/riscv/attribute-05.d

> +++ b/gas/testsuite/gas/riscv/attribute-05.d

> @@ -1,4 +1,4 @@

> -#as: -march-attr

> +#as: -march-attr -misa-spec=2p2

>  #readelf: -A

>  #source: attribute-05.s

>  Attribute Section: riscv

> diff --git a/gas/testsuite/gas/riscv/attribute-06.d b/gas/testsuite/gas/riscv/attribute-06.d

> index 1abeb47..5c8a5c6 100644

> --- a/gas/testsuite/gas/riscv/attribute-06.d

> +++ b/gas/testsuite/gas/riscv/attribute-06.d

> @@ -1,4 +1,4 @@

> -#as: -march=rv32g2p0 -march-attr

> +#as: -march=rv32g2p1 -march-attr -misa-spec=2p2

>  #readelf: -A

>  #source: attribute-06.s

>  Attribute Section: riscv

> diff --git a/gas/testsuite/gas/riscv/attribute-07.d b/gas/testsuite/gas/riscv/attribute-07.d

> index dfd7e6b..20ac9be 100644

> --- a/gas/testsuite/gas/riscv/attribute-07.d

> +++ b/gas/testsuite/gas/riscv/attribute-07.d

> @@ -1,4 +1,4 @@

> -#as: -march=rv64g2p0 -march-attr

> +#as: -march=rv64g2p1 -march-attr -misa-spec=2p2

>  #readelf: -A

>  #source: attribute-07.s

>  Attribute Section: riscv

> diff --git a/gas/testsuite/gas/riscv/attribute-08.d b/gas/testsuite/gas/riscv/attribute-08.d

> index c10ac0c..7f580d3 100644

> --- a/gas/testsuite/gas/riscv/attribute-08.d

> +++ b/gas/testsuite/gas/riscv/attribute-08.d

> @@ -1,4 +1,4 @@

> -#as: -march-attr

> +#as: -march-attr -misa-spec=2p2

>  #readelf: -A

>  #source: attribute-08.s

>  Attribute Section: riscv

> diff --git a/gas/testsuite/gas/riscv/attribute-09.d b/gas/testsuite/gas/riscv/attribute-09.d

> new file mode 100644

> index 0000000..77c7ef3

> --- /dev/null

> +++ b/gas/testsuite/gas/riscv/attribute-09.d

> @@ -0,0 +1,6 @@

> +#as: -march-attr -misa-spec=2p2 -mriscv-isa-version=i2p1a2p1v0p9

> +#readelf: -A

> +#source: attribute-09.s

> +Attribute Section: riscv

> +File Attributes

> +  Tag_RISCV_arch: "rv32i1p9_f2p0_v0p9_zicsr0p0"

> diff --git a/gas/testsuite/gas/riscv/attribute-09.s b/gas/testsuite/gas/riscv/attribute-09.s

> new file mode 100644

> index 0000000..0b1b16c

> --- /dev/null

> +++ b/gas/testsuite/gas/riscv/attribute-09.s

> @@ -0,0 +1 @@

> +	.attribute arch, "rv32i1p9fv_zicsr"

> diff --git a/gas/testsuite/gas/riscv/attribute-10.d b/gas/testsuite/gas/riscv/attribute-10.d

> new file mode 100644

> index 0000000..9c72035

> --- /dev/null

> +++ b/gas/testsuite/gas/riscv/attribute-10.d

> @@ -0,0 +1,6 @@

> +#as: -march-attr -march=rv32i_zicsr -misa-spec=20191213

> +#readelf: -A

> +#source: empty.s

> +Attribute Section: riscv

> +File Attributes

> +  Tag_RISCV_arch: "rv32i2p1_zicsr2p0"

> diff --git a/gas/testsuite/gas/riscv/attribute-11.d b/gas/testsuite/gas/riscv/attribute-11.d

> new file mode 100644

> index 0000000..bc7f986

> --- /dev/null

> +++ b/gas/testsuite/gas/riscv/attribute-11.d

> @@ -0,0 +1,6 @@

> +#as: -march-attr -march=rv32i_zicsr -misa-spec=20191213 -mriscv-isa-version=zicsr2p1

> +#readelf: -A

> +#source: empty.s

> +Attribute Section: riscv

> +File Attributes

> +  Tag_RISCV_arch: "rv32i2p1_zicsr2p1"

> diff --git a/include/opcode/riscv.h b/include/opcode/riscv.h

> index ac6e861..f8b0de3 100644

> --- a/include/opcode/riscv.h

> +++ b/include/opcode/riscv.h

> @@ -343,6 +343,16 @@ struct riscv_opcode

>    unsigned long pinfo;

>  };

>

> +/* This structure holds version information for specific ISA.  */

> +

> +struct riscv_ext_version

> +{

> +  const char *name;

> +  const char *spec_name;

> +  unsigned int major_version;

> +  unsigned int minor_version;

> +};

> +

>  /* Instruction is a simple alias (e.g. "mv" for "addi").  */

>  #define	INSN_ALIAS		0x00000001

>

> @@ -420,5 +430,6 @@ extern const char * const riscv_fpr_names_abi[NFPR];

>

>  extern const struct riscv_opcode riscv_opcodes[];

>  extern const struct riscv_opcode riscv_insn_types[];

> +extern const struct riscv_ext_version riscv_ext_version_table[];

>

>  #endif /* _RISCV_H_ */

> diff --git a/opcodes/riscv-opc.c b/opcodes/riscv-opc.c

> index ceedcaf..7b885bf 100644

> --- a/opcodes/riscv-opc.c

> +++ b/opcodes/riscv-opc.c

> @@ -884,3 +884,56 @@ const struct riscv_opcode riscv_insn_types[] =

>  /* Terminate the list.  */

>  {0, 0, INSN_CLASS_NONE, 0, 0, 0, 0, 0}

>  };

> +

> +const struct riscv_ext_version riscv_ext_version_table[] =

> +{

> +/* name, spec name,  major,  minor.  */

> +{"e",    "20191213",      1,     9},

> +{"e",    "20190608",      1,     9},

> +{"e",    "2p2",           1,     9},

> +

> +{"i",    "20191213",      2,     1},

> +{"i",    "20190608",      2,     1},

> +{"i",    "2p2",           2,     0},

> +

> +{"m",    "20191213",      2,     0},

> +{"m",    "20190608",      2,     0},

> +{"m",    "2p2",           2,     0},

> +

> +{"a",    "20191213",      2,     1},

> +{"a",    "20190608",      2,     0},

> +{"a",    "2p2",           2,     0},

> +

> +{"f",    "20191213",      2,     2},

> +{"f",    "20190608",      2,     2},

> +{"f",    "2p2",           2,     0},

> +

> +{"d",    "20191213",      2,     2},

> +{"d",    "20190608",      2,     2},

> +{"d",    "2p2",           2,     0},

> +

> +{"q",    "20191213",      2,     2},

> +{"q",    "20190608",      2,     2},

> +{"q",    "2p2",           2,     0},

> +

> +{"c",    "20191213",      2,     0},

> +{"c",    "20190608",      2,     0},

> +{"c",    "2p2",           2,     0},

> +

> +{"p",    "20191213",      0,     2},

> +{"p",    "20190608",      0,     2},

> +{"p",    "2p2",           0,     1},

> +

> +{"v",    "20191213",      0,     7},

> +{"v",    "20190608",      0,     7},

> +{"v",    "2p2",           0,     7},

> +

> +{"n",    "20190608",      1,     1},

> +{"n",    "2p2",           1,     1},

> +

> +{"zicsr","20191213",      2,     0},

> +{"zicsr","20190608",      2,     0},

> +

> +/* Terminate the list.  */

> +{NULL, NULL, 0, 0}

> +};

Patch

diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index 8fcb106..4ca49e0 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -2802,7 +2802,7 @@  riscv_merge_std_ext (bfd *ibfd,
   if (!riscv_i_or_e_p (ibfd, out_arch, out))
     return FALSE;
 
-  if (in->name[0] != out->name[0])
+  if (strcasecmp (in->name, out->name) != 0)
     {
       /* TODO: We might allow merge 'i' with 'e'.  */
       _bfd_error_handler
@@ -2818,8 +2818,8 @@  riscv_merge_std_ext (bfd *ibfd,
       return FALSE;
     }
   else
-    riscv_add_subset (&merged_subsets,
-		      in->name, in->major_version, in->minor_version);
+    riscv_add_subset (&merged_subsets, in->name, in->major_version,
+		      in->minor_version, FALSE);
 
   in = in->next;
   out = out->next;
@@ -2848,7 +2848,7 @@  riscv_merge_std_ext (bfd *ibfd,
 
       struct riscv_subset_t *merged = find_in ? find_in : find_out;
       riscv_add_subset (&merged_subsets, merged->name,
-			merged->major_version, merged->minor_version);
+			merged->major_version, merged->minor_version, FALSE);
     }
 
   /* Skip all standard extensions.  */
@@ -2917,14 +2917,14 @@  riscv_merge_multi_letter_ext (bfd *ibfd,
 	{
 	  /* `in' comes before `out', append `in' and increment.  */
 	  riscv_add_subset (&merged_subsets, in->name, in->major_version,
-			    in->minor_version);
+			    in->minor_version, FALSE);
 	  in = in->next;
 	}
       else if (cmp > 0)
 	{
 	  /* `out' comes before `in', append `out' and increment.  */
 	  riscv_add_subset (&merged_subsets, out->name, out->major_version,
-			    out->minor_version);
+			    out->minor_version, FALSE);
 	  out = out->next;
 	}
       else
@@ -2938,7 +2938,7 @@  riscv_merge_multi_letter_ext (bfd *ibfd,
 	    }
 
 	  riscv_add_subset (&merged_subsets, out->name, out->major_version,
-			    out->minor_version);
+			    out->minor_version, FALSE);
 	  out = out->next;
 	  in = in->next;
 	}
@@ -2952,7 +2952,7 @@  riscv_merge_multi_letter_ext (bfd *ibfd,
     while (tail)
       {
 	riscv_add_subset (&merged_subsets, tail->name, tail->major_version,
-			  tail->minor_version);
+			  tail->minor_version, FALSE);
 	tail = tail->next;
       }
   }
@@ -2975,13 +2975,17 @@  riscv_merge_arch_attr_info (bfd *ibfd, char *in_arch, char *out_arch)
   riscv_parse_subset_t rpe_in;
   riscv_parse_subset_t rpe_out;
 
+  /* Only assembler needs to check the default version of ISA, so just set
+     the rpe_in.get_default_version and rpe_out.get_default_version to NULL.  */
   rpe_in.subset_list = &in_subsets;
   rpe_in.error_handler = _bfd_error_handler;
   rpe_in.xlen = &xlen_in;
+  rpe_in.get_default_version = NULL;
 
   rpe_out.subset_list = &out_subsets;
   rpe_out.error_handler = _bfd_error_handler;
   rpe_out.xlen = &xlen_out;
+  rpe_out.get_default_version = NULL;
 
   if (in_arch == NULL && out_arch == NULL)
     return NULL;
@@ -2993,10 +2997,10 @@  riscv_merge_arch_attr_info (bfd *ibfd, char *in_arch, char *out_arch)
     return in_arch;
 
   /* Parse subset from arch string.  */
-  if (!riscv_parse_subset (&rpe_in, in_arch))
+  if (!riscv_parse_subset (&rpe_in, in_arch, NULL, FALSE))
     return NULL;
 
-  if (!riscv_parse_subset (&rpe_out, out_arch))
+  if (!riscv_parse_subset (&rpe_out, out_arch, NULL, FALSE))
     return NULL;
 
   /* Checking XLEN.  */
diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
index b15fdee..3a6aaf3 100644
--- a/bfd/elfxx-riscv.c
+++ b/bfd/elfxx-riscv.c
@@ -1025,9 +1025,8 @@  riscv_elf_add_sub_reloc (bfd *abfd,
      `minor_version`: Parsing result of minor version, set to 0 if version is
      not present in arch string, but set to `default_minor_version` if
      `major_version` using default_major_version.
-     `default_major_version`: Default major version.
-     `default_minor_version`: Default minor version.
-     `std_ext_p`: True if parsing std extension.  */
+     `std_ext_p`: True if parsing std extension.
+     `use_default_version`: Set it to True if we need the default version.  */
 
 static const char *
 riscv_parsing_subset_version (riscv_parse_subset_t *rps,
@@ -1035,17 +1034,16 @@  riscv_parsing_subset_version (riscv_parse_subset_t *rps,
 			      const char *p,
 			      unsigned *major_version,
 			      unsigned *minor_version,
-			      unsigned default_major_version,
-			      unsigned default_minor_version,
-			      bfd_boolean std_ext_p)
+			      bfd_boolean std_ext_p,
+			      bfd_boolean *use_default_version)
 {
   bfd_boolean major_p = TRUE;
   unsigned version = 0;
-  unsigned major = 0;
-  unsigned minor = 0;
   char np;
 
-  for (;*p; ++p)
+  *major_version = 0;
+  *minor_version = 0;
+  for (; *p; ++p)
     {
       if (*p == 'p')
 	{
@@ -1057,7 +1055,6 @@  riscv_parsing_subset_version (riscv_parse_subset_t *rps,
 	      if (std_ext_p)
 		{
 		  *major_version = version;
-		  *minor_version = 0;
 		  return p;
 		}
 	      else
@@ -1068,7 +1065,7 @@  riscv_parsing_subset_version (riscv_parse_subset_t *rps,
 		}
 	    }
 
-	  major = version;
+	  *major_version = version;
 	  major_p = FALSE;
 	  version = 0;
 	}
@@ -1079,21 +1076,15 @@  riscv_parsing_subset_version (riscv_parse_subset_t *rps,
     }
 
   if (major_p)
-    major = version;
+    *major_version = version;
   else
-    minor = version;
+    *minor_version = version;
 
-  if (major == 0 && minor == 0)
-    {
-      /* We don't found any version string, use default version.  */
-      *major_version = default_major_version;
-      *minor_version = default_minor_version;
-    }
-  else
-    {
-      *major_version = major;
-      *minor_version = minor;
-    }
+  /* We can not find any version in string, need to parse default version.  */
+  if (use_default_version != NULL
+      && *major_version == 0
+      && *minor_version == 0)
+    *use_default_version = TRUE;
   return p;
 }
 
@@ -1106,6 +1097,41 @@  riscv_supported_std_ext (void)
   return "mafdqlcbjtpvn";
 }
 
+/* Update the version of standard extensions and their Z* sub extensions
+   if -mriscv-isa-version is set.  */
+
+static bfd_boolean
+riscv_update_subset_version (riscv_parse_subset_t *rps,
+			     const char *ext_with_version,
+			     char *ext,
+                             unsigned major_version,
+			     unsigned minor_version,
+			     bfd_boolean use_default_version)
+{
+  riscv_subset_t *subset = riscv_lookup_subset (rps->subset_list, ext);;
+
+  /* The extension doesn't exist, so just return.  */
+  if (subset == NULL)
+    return TRUE;
+
+  /* This means we can not find the version in the string.  */
+  if (use_default_version)
+    {
+      rps->error_handler ("-mriscv-isa-version=%s: unexpected version "
+			  "setting for subset `%s'", ext_with_version, ext);
+      return FALSE;
+    }
+
+  /* We only update the extension which use the default version.  */
+  if (subset->use_default_version)
+    {
+      subset->major_version = major_version;
+      subset->minor_version = minor_version;
+    }
+
+  return TRUE;
+}
+
 /* Parsing function for standard extensions.
 
    Return Value:
@@ -1114,46 +1140,95 @@  riscv_supported_std_ext (void)
    Arguments:
      `rps`: Hooks and status for parsing subset.
      `march`: Full arch string.
-     `p`: Curent parsing position.  */
+     `p`: Curent parsing position.
+     `isa_spec_name`: The ISA spec name.  We set the default ISA versions
+     according to it.
+     `update_version`: True if the -mriscv-isa-version is set, and we need
+     to update the version for the existing extensions.  */
 
 static const char *
 riscv_parse_std_ext (riscv_parse_subset_t *rps,
-		     const char *march, const char *p)
+		     const char *march,
+		     const char *p,
+		     const char *isa_spec_name,
+		     bfd_boolean update_version)
 {
   const char *all_std_exts = riscv_supported_std_ext ();
   const char *std_exts = all_std_exts;
-
   unsigned major_version = 0;
   unsigned minor_version = 0;
   char std_ext = '\0';
+  bfd_boolean use_default_version = FALSE;
 
   /* First letter must start with i, e or g.  */
   switch (*p)
     {
       case 'i':
-	p++;
-	p = riscv_parsing_subset_version (
-	      rps,
-	      march,
-	      p, &major_version, &minor_version,
-	      /* default_major_version= */ 2,
-	      /* default_minor_version= */ 0,
-	      /* std_ext_p= */TRUE);
-	riscv_add_subset (rps->subset_list, "i", major_version, minor_version);
+	p = riscv_parsing_subset_version (rps,
+					  march,
+					  ++p,
+					  &major_version,
+					  &minor_version,
+					  /* std_ext_p= */TRUE,
+					  &use_default_version);
+
+	/* Update the version for exsiting extension.  */
+	if (update_version)
+	  {
+	    if (!riscv_update_subset_version (rps, march, "i",
+					      major_version,
+					      minor_version,
+					      use_default_version))
+	      return NULL;
+	    break;
+	  }
+
+	/* Find the default version if needed.  */
+	if (use_default_version)
+	  rps->get_default_version ("i",
+				    isa_spec_name,
+				    &major_version,
+				    &minor_version);
+	riscv_add_subset (rps->subset_list, "i", major_version, minor_version,
+			  use_default_version);
 	break;
 
       case 'e':
-	p++;
-	p = riscv_parsing_subset_version (
-	      rps,
-	      march,
-	      p, &major_version, &minor_version,
-	      /* default_major_version= */ 1,
-	      /* default_minor_version= */ 9,
-	      /* std_ext_p= */TRUE);
-
-	riscv_add_subset (rps->subset_list, "e", major_version, minor_version);
-	riscv_add_subset (rps->subset_list, "i", 2, 0);
+	p = riscv_parsing_subset_version (rps,
+					  march,
+					  ++p,
+					  &major_version,
+					  &minor_version,
+					  /* std_ext_p= */TRUE,
+					  &use_default_version);
+
+	/* Update the version for exsiting extension.  */
+	if (update_version)
+	  {
+	    if (!riscv_update_subset_version (rps, march, "e",
+					      major_version,
+					      minor_version,
+					      use_default_version))
+	      return NULL;
+	    break;
+	  }
+
+	/* Find the default version if needed.  */
+	if (use_default_version)
+	  rps->get_default_version ("e",
+				    isa_spec_name,
+				    &major_version,
+				    &minor_version);
+	riscv_add_subset (rps->subset_list, "e", major_version, minor_version,
+			  use_default_version);
+
+	/* i-ext must be enabled.  */
+	rps->get_default_version ("i",
+				  isa_spec_name,
+				  &major_version,
+				  &minor_version);
+	riscv_add_subset (rps->subset_list, "i", major_version, minor_version,
+			  TRUE);
 
 	if (*rps->xlen > 32)
 	  {
@@ -1161,35 +1236,58 @@  riscv_parse_std_ext (riscv_parse_subset_t *rps,
 				march, *rps->xlen);
 	    return NULL;
 	  }
-
 	break;
 
       case 'g':
-	p++;
-	p = riscv_parsing_subset_version (
-	      rps,
-	      march,
-	      p, &major_version, &minor_version,
-	      /* default_major_version= */ 2,
-	      /* default_minor_version= */ 0,
-	      /* std_ext_p= */TRUE);
-	riscv_add_subset (rps->subset_list, "i", major_version, minor_version);
+	/* The g-ext shouldn't has the version, so we just skip the setting if
+	   user set a version to it.  */
+	p = riscv_parsing_subset_version (rps,
+					  march,
+					  ++p,
+					  &major_version,
+					  &minor_version,
+					  TRUE,
+					  &use_default_version);
+
+	/* Set the version of g in -mriscv-isa-version is meaningless,
+	   so just skip it.  */
+	if (update_version)
+	  break;
+
+	/* i-ext must be enabled.  */
+	rps->get_default_version ("i",
+				  isa_spec_name,
+				  &major_version,
+				  &minor_version);
+	riscv_add_subset (rps->subset_list, "i", major_version, minor_version,
+			  TRUE);
 
 	for ( ; *std_exts != 'q'; std_exts++)
 	  {
 	    const char subset[] = {*std_exts, '\0'};
-	    riscv_add_subset (
-	      rps->subset_list, subset, major_version, minor_version);
+	    rps->get_default_version (subset,
+				      isa_spec_name,
+				      &major_version,
+				      &minor_version);
+	    riscv_add_subset (rps->subset_list, subset, major_version,
+			      minor_version, TRUE);
 	  }
 	break;
 
       default:
-	rps->error_handler (
-	  "-march=%s: first ISA subset must be `e', `i' or `g'", march);
-	return NULL;
+	/* The first ISA subset of -mriscv-isa-version will not necessarily
+	   be e/i/g.  */
+	if (!update_version)
+	  {
+	    rps->error_handler (
+	    "-march=%s: first ISA subset must be `e', `i' or `g'", march);
+	    return NULL;
+	  }
     }
 
-  while (*p)
+  /* The riscv_parsing_subset_version may set `p` to NULL, so I think we should
+     skip parsing the string if `p` is NULL or value of `p` is `\0`.  */
+  while (p != NULL && *p != '\0')
     {
       char subset[2] = {0, 0};
 
@@ -1218,21 +1316,37 @@  riscv_parse_std_ext (riscv_parse_subset_t *rps,
 	      march, *p);
 	  return NULL;
 	}
-
       std_exts++;
 
-      p++;
-      p = riscv_parsing_subset_version (
-	    rps,
-	    march,
-	    p, &major_version, &minor_version,
-	    /* default_major_version= */ 2,
-	    /* default_minor_version= */ 0,
-	    /* std_ext_p= */TRUE);
-
+      use_default_version = FALSE;
       subset[0] = std_ext;
+      p = riscv_parsing_subset_version (rps,
+					march,
+					++p,
+					&major_version,
+					&minor_version,
+					TRUE,
+					&use_default_version);
+
+      /* Update the version for exsiting extension.  */
+      if (update_version)
+	{
+	  if (!riscv_update_subset_version (rps, march, subset,
+					    major_version,
+					    minor_version,
+					    use_default_version))
+	    return NULL;
+	  continue;
+	}
 
-      riscv_add_subset (rps->subset_list, subset, major_version, minor_version);
+      /* Find the default version if needed.  */
+      if (use_default_version)
+	rps->get_default_version (subset,
+				  isa_spec_name,
+				  &major_version,
+				  &minor_version);
+      riscv_add_subset (rps->subset_list, subset, major_version, minor_version,
+			use_default_version);
     }
   return p;
 }
@@ -1272,21 +1386,28 @@  typedef struct riscv_parse_config
 } riscv_parse_config_t;
 
 /* Parse a generic prefixed extension.
-   march: The full architecture string as passed in by "-march=...".
-   p: Point from which to start parsing the -march string.
-   config: What class of extensions to parse, predicate funcs,
-   and strings to use in error reporting.  */
+   `march`: The full architecture string as passed in by "-march=...".
+   `p`: Point from which to start parsing the -march string.
+   `config`: What class of extensions to parse, predicate funcs,
+   and strings to use in error reporting.
+   `isa_spec_name`: ISA spec name.  We set the default ISA versions
+   according to it.
+   `update_version`: True if the -mriscv-isa-version is set, and we need
+   update the version for the existing extensions.  */
 
 static const char *
 riscv_parse_prefixed_ext (riscv_parse_subset_t *rps,
 			  const char *march,
 			  const char *p,
-			  const riscv_parse_config_t *config)
+			  const riscv_parse_config_t *config,
+			  const char *isa_spec_name,
+			  bfd_boolean update_version)
 {
   unsigned major_version = 0;
   unsigned minor_version = 0;
   const char *last_name;
   riscv_isa_ext_class_t class;
+  bfd_boolean use_default_version;
 
   while (*p)
     {
@@ -1309,15 +1430,11 @@  riscv_parse_prefixed_ext (riscv_parse_subset_t *rps,
       while (*++q != '\0' && *q != '_' && !ISDIGIT (*q))
 	;
 
+      use_default_version = FALSE;
       end_of_version =
-	riscv_parsing_subset_version (
-	  rps,
-	  march,
-	  q, &major_version, &minor_version,
-	  /* default_major_version= */ 2,
-	  /* default_minor_version= */ 0,
-	  /* std_ext_p= */FALSE);
-
+	riscv_parsing_subset_version (rps, march, q, &major_version,
+				      &minor_version, FALSE,
+				      &use_default_version);
       *q = '\0';
 
       /* Check that the name is valid.
@@ -1335,10 +1452,11 @@  riscv_parse_prefixed_ext (riscv_parse_subset_t *rps,
 	  return NULL;
 	}
 
-      /* Check that the last item is not the same as this.  */
+      /* Check that the last item is not the same as this.  Just skip this
+	 check when updating the version.  */
       last_name = rps->subset_list->tail->name;
-
-      if (!strcasecmp (last_name, subset))
+      if (!update_version
+	  && !strcasecmp (last_name, subset))
 	{
 	  rps->error_handler ("-march=%s: Duplicate %s ISA extension: \'%s\'",
 			      march, config->prefix, subset);
@@ -1357,7 +1475,30 @@  riscv_parse_prefixed_ext (riscv_parse_subset_t *rps,
 	  return NULL;
 	}
 
-      riscv_add_subset (rps->subset_list, subset, major_version, minor_version);
+      if (update_version)
+	{
+	  /* Update the version for exsiting extension.  */
+	  if (!riscv_update_subset_version (rps, march, subset,
+					    major_version,
+					    minor_version,
+					    use_default_version))
+	    {
+	      free (subset);
+	      return NULL;
+	    }
+	}
+      else
+	{
+	  /* Find the default version if needed.  */
+	  if (use_default_version)
+	    rps->get_default_version (subset,
+				      isa_spec_name,
+				      &major_version,
+				      &minor_version);
+	  riscv_add_subset (rps->subset_list, subset, major_version,
+			    minor_version, use_default_version);
+	}
+
       free (subset);
       p += end_of_version - subset;
 
@@ -1384,7 +1525,7 @@  riscv_parse_prefixed_ext (riscv_parse_subset_t *rps,
 
 static const char * const riscv_std_z_ext_strtab[] =
   {
-    NULL
+    "zicsr", NULL
   };
 
 /* Same as `riscv_std_z_ext_strtab', but for S-class extensions.  */
@@ -1457,11 +1598,17 @@  static const riscv_parse_config_t parse_config[] =
 
    Arguments:
      `rps`: Hooks and status for parsing subset.
-     `arch`: Arch string.  */
+     `arch`: Arch string.
+     `isa_spec_name`: The ISA spec name.   We set the default ISA versions
+     according to it.
+     `update_version`: True if the -mriscv-isa-version is set, and we need
+     update the version for the existing extensions.  */
 
 bfd_boolean
 riscv_parse_subset (riscv_parse_subset_t *rps,
-		    const char *arch)
+		    const char *arch,
+		    const char *isa_spec_name,
+		    bfd_boolean update_version)
 {
   const char *p = arch;
   size_t i;
@@ -1476,15 +1623,17 @@  riscv_parse_subset (riscv_parse_subset_t *rps,
       *rps->xlen = 64;
       p += 4;
     }
-  else
+  else if (!update_version)
     {
+      /* The string set by -mriscv-isa-version doesn't have to start
+	 with rv32/rv64.  */
       rps->error_handler ("-march=%s: ISA string must begin with rv32 or rv64",
 			  arch);
       return FALSE;
     }
 
   /* Parsing standard extension.  */
-  p = riscv_parse_std_ext (rps, arch, p);
+  p = riscv_parse_std_ext (rps, arch, p, isa_spec_name, update_version);
 
   if (p == NULL)
     return FALSE;
@@ -1492,7 +1641,8 @@  riscv_parse_subset (riscv_parse_subset_t *rps,
   /* Parse the different classes of extensions in the specified order.  */
 
   for (i = 0; i < ARRAY_SIZE (parse_config); ++i) {
-    p = riscv_parse_prefixed_ext (rps, arch, p, &parse_config[i]);
+    p = riscv_parse_prefixed_ext (rps, arch, p, &parse_config[i],
+				  isa_spec_name, update_version);
 
     if (p == NULL)
       return FALSE;
@@ -1543,7 +1693,8 @@  riscv_parse_subset (riscv_parse_subset_t *rps,
 void
 riscv_add_subset (riscv_subset_list_t *subset_list,
 		  const char *subset,
-		  int major, int minor)
+		  int major, int minor,
+		  bfd_boolean use_default_version)
 {
   riscv_subset_t *s = xmalloc (sizeof *s);
 
@@ -1553,6 +1704,9 @@  riscv_add_subset (riscv_subset_list_t *subset_list,
   s->name = xstrdup (subset);
   s->major_version = major;
   s->minor_version = minor;
+  /* Record whether the default version is used.  The -mriscv-isa-version
+     only update the ISA which use the default version.  */
+  s->use_default_version = use_default_version;
   s->next = NULL;
 
   if (subset_list->tail != NULL)
diff --git a/bfd/elfxx-riscv.h b/bfd/elfxx-riscv.h
index 76ee274..e3d5177 100644
--- a/bfd/elfxx-riscv.h
+++ b/bfd/elfxx-riscv.h
@@ -40,6 +40,7 @@  struct riscv_subset_t
   const char *name;
   int major_version;
   int minor_version;
+  bfd_boolean use_default_version;
   struct riscv_subset_t *next;
 };
 
@@ -56,7 +57,8 @@  riscv_release_subset_list (riscv_subset_list_t *);
 extern void
 riscv_add_subset (riscv_subset_list_t *,
 		  const char *,
-		  int, int);
+		  int, int,
+		  bfd_boolean);
 
 extern riscv_subset_t *
 riscv_lookup_subset (const riscv_subset_list_t *,
@@ -72,11 +74,17 @@  typedef struct {
   void (*error_handler) (const char *,
 			 ...) ATTRIBUTE_PRINTF_1;
   unsigned *xlen;
+  void (*get_default_version) (const char *,
+			       const char *,
+			       unsigned int *,
+			       unsigned int *);
 } riscv_parse_subset_t;
 
 extern bfd_boolean
 riscv_parse_subset (riscv_parse_subset_t *,
-		    const char *);
+		    const char *,
+		    const char *,
+		    bfd_boolean);
 
 extern const char *
 riscv_supported_std_ext (void);
diff --git a/gas/config.in b/gas/config.in
index 8724eb1..935bd9b 100644
--- a/gas/config.in
+++ b/gas/config.in
@@ -30,6 +30,9 @@ 
 /* Default architecture. */
 #undef DEFAULT_ARCH
 
+/* Define default value for -march */
+#undef DEFAULT_ARCH_WITH_EXT
+
 /* Default CRIS architecture. */
 #undef DEFAULT_CRIS_ARCH
 
@@ -50,12 +53,18 @@ 
 /* Define to 1 if you want to generate x86 relax relocations by default. */
 #undef DEFAULT_GENERATE_X86_RELAX_RELOCATIONS
 
+/* Define default value for -misa-spec */
+#undef DEFAULT_ISA_SPEC
+
 /* Define to 1 if you want to fix Loongson3 LLSC Errata by default. */
 #undef DEFAULT_MIPS_FIX_LOONGSON3_LLSC
 
 /* Define to 1 if you want to generate RISC-V arch attribute by default. */
 #undef DEFAULT_RISCV_ATTR
 
+/* Define default isa version which are not covered by --with-isa-spec */
+#undef DEFAULT_RISCV_ISA_VERSION
+
 /* Define to 1 if you want to generate GNU x86 used ISA and feature properties
    by default. */
 #undef DEFAULT_X86_USED_NOTE
diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index 168561e..bfcf2f0 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -63,7 +63,22 @@  struct riscv_cl_insn
 #define DEFAULT_RISCV_ATTR 0
 #endif
 
+#ifndef DEFAULT_ARCH_WITH_EXT
+#define DEFAULT_ARCH_WITH_EXT NULL
+#endif
+
+#ifndef DEFAULT_ISA_SPEC
+#define DEFAULT_ISA_SPEC "2p2"
+#endif
+
+#ifndef DEFAULT_RISCV_ISA_VERSION
+#define DEFAULT_RISCV_ISA_VERSION NULL
+#endif
+
 static const char default_arch[] = DEFAULT_ARCH;
+static const char *default_arch_with_ext = DEFAULT_ARCH_WITH_EXT;
+static const char *default_isa_spec = DEFAULT_ISA_SPEC;
+static const char *default_riscv_isa_version = DEFAULT_RISCV_ISA_VERSION;
 
 static unsigned xlen = 0; /* width of an x-register */
 static unsigned abi_xlen = 0; /* width of a pointer in the ABI */
@@ -147,18 +162,87 @@  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,
+			       const char *spec_name,
+			       unsigned int *major_version,
+			       unsigned int *minor_version)
+{
+  struct riscv_ext_version *ext;
+
+  *major_version = 0;
+  *minor_version = 0;
+
+  if (name == NULL
+      || spec_name == NULL)
+    return;
+
+  ext = (struct riscv_ext_version *) hash_find (ext_version_hash, name);
+  while (ext
+	 && ext->name
+	 && strcmp (ext->name, name) == 0)
+    {
+      if (ext->spec_name
+	  && strcmp (ext->spec_name, spec_name) == 0)
+	{
+	  *major_version = ext->major_version;
+	  *minor_version = ext->minor_version;
+	  return;
+	}
+      ext++;
+    }
+}
+
 /* Set which ISA and extensions are available.  */
 
 static void
-riscv_set_arch (const char *s)
+riscv_set_arch (const char *s, bfd_boolean update_version)
 {
   riscv_parse_subset_t rps;
   rps.subset_list = &riscv_subsets;
   rps.error_handler = as_fatal;
   rps.xlen = &xlen;
+  rps.get_default_version = riscv_get_default_ext_version;
 
-  riscv_release_subset_list (&riscv_subsets);
-  riscv_parse_subset (&rps, s);
+  if (s == NULL)
+    return;
+
+  if (!update_version)
+    riscv_release_subset_list (&riscv_subsets);
+  riscv_parse_subset (&rps, s, default_isa_spec, update_version);
 }
 
 /* Handle of the OPCODE hash table.  */
@@ -2348,6 +2432,8 @@  enum options
   OPTION_NO_ARCH_ATTR,
   OPTION_CSR_CHECK,
   OPTION_NO_CSR_CHECK,
+  OPTION_MISA_SPEC,
+  OPTION_MRISCV_ISA_VERSION,
   OPTION_END_OF_ENUM
 };
 
@@ -2364,6 +2450,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},
+  {"mriscv-isa-version", required_argument, NULL, OPTION_MRISCV_ISA_VERSION},
 
   {NULL, no_argument, NULL, 0}
 };
@@ -2392,7 +2480,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 +2540,14 @@  md_parse_option (int c, const char *arg)
       riscv_opts.csr_check = FALSE;
       break;
 
+    case OPTION_MISA_SPEC:
+      default_isa_spec = arg;
+      break;
+
+    case OPTION_MRISCV_ISA_VERSION:
+      default_riscv_isa_version = arg;
+      break;
+
     default:
       return 0;
     }
@@ -2460,6 +2558,13 @@  md_parse_option (int c, const char *arg)
 void
 riscv_after_parse_args (void)
 {
+  /* Initialize the hash table for extensions with default version.  */
+  ext_version_hash = init_ext_version_hash (riscv_ext_version_table);
+
+  /* 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 +2574,15 @@  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";
+
+  /* Set the architecture according to -march or --with-arch.  */
+  riscv_set_arch (default_arch_with_ext, FALSE);
 
-  if (riscv_subsets.head == NULL)
-    riscv_set_arch (xlen == 64 ? "rv64g" : "rv32g");
+  /* Update the version info according to -mriscv-isa-spec or
+     --with-riscv-isa-spec.  */
+  riscv_set_arch (default_riscv_isa_version, TRUE);
 
   /* Add the RVC extension, regardless of -march, to support .option rvc.  */
   riscv_set_rvc (FALSE);
@@ -3366,7 +3477,7 @@  s_riscv_attribute (int ignored ATTRIBUTE_UNUSED)
       obj_attribute *attr;
       attr = elf_known_obj_attributes_proc (stdoutput);
       if (!start_assemble)
-	riscv_set_arch (attr[Tag_RISCV_arch].s);
+	riscv_set_arch (attr[Tag_RISCV_arch].s, FALSE);
       else
 	as_fatal (_(".attribute arch must set before any instructions"));
 
@@ -3379,6 +3490,9 @@  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"));
 	}
+
+      /* We also need to update the version of ISA here.  */
+      riscv_set_arch (default_riscv_isa_version, TRUE);
     }
 }
 
diff --git a/gas/configure b/gas/configure
index 1515787..bce847a 100755
--- a/gas/configure
+++ b/gas/configure
@@ -13009,7 +13009,7 @@  $as_echo "#define NDS32_DEFAULT_ZOL_EXT 1" >>confdefs.h
 $as_echo "$enable_zol_ext" >&6; }
 	;;
 
-      aarch64 | i386 | riscv | s390 | sparc)
+      aarch64 | i386 | s390 | sparc)
 	if test $this_target = $target ; then
 
 cat >>confdefs.h <<_ACEOF
@@ -13019,6 +13019,57 @@  _ACEOF
 	fi
 	;;
 
+      riscv)
+	# --target=riscv[32|64]-*-*.  */
+	if test $this_target = $target ; then
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_ARCH "${arch}"
+_ACEOF
+
+	fi
+
+	# --with-arch=<value>.  The syntax of <value> is same as Gas option -march.
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for default configuration of --with-arch" >&5
+$as_echo_n "checking for default configuration of --with-arch... " >&6; }
+	if test "x${with_arch}" != x; then
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_ARCH_WITH_EXT "$with_arch"
+_ACEOF
+
+	fi
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_arch" >&5
+$as_echo "$with_arch" >&6; }
+
+	# --with-isa-spec=[2p0|2p1|2p2|20190608|20191213].
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for default configuration of --with-isa-spec" >&5
+$as_echo_n "checking for default configuration of --with-isa-spec... " >&6; }
+	if test "x${with_isa_spec}" != x; then
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_ISA_SPEC "$with_isa_spec"
+_ACEOF
+
+	fi
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_isa_spec" >&5
+$as_echo "$with_isa_spec" >&6; }
+
+	# --with-riscv-isa-version=<value>.  The syntax of <value> is same as Gas
+	# -march, but without the rv[32|64] prefix.
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for default configuration of --with-riscv-isa-version" >&5
+$as_echo_n "checking for default configuration of --with-riscv-isa-version... " >&6; }
+	if test "x${with_riscv_isa_version}" != x; then
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_RISCV_ISA_VERSION "$with_riscv_isa_version"
+_ACEOF
+
+	fi
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_riscv_isa_version" >&5
+$as_echo "$with_riscv_isa_version" >&6; }
+	;;
+
       rl78)
 	f=rl78-parse.o
 	case " $extra_objects " in
diff --git a/gas/configure.ac b/gas/configure.ac
index 6f32e55..be4ba20 100644
--- a/gas/configure.ac
+++ b/gas/configure.ac
@@ -569,12 +569,45 @@  changequote([,])dnl
 	AC_MSG_RESULT($enable_zol_ext)
 	;;
 
-      aarch64 | i386 | riscv | s390 | sparc)
+      aarch64 | i386 | s390 | sparc)
 	if test $this_target = $target ; then
 	  AC_DEFINE_UNQUOTED(DEFAULT_ARCH, "${arch}", [Default architecture.])
 	fi
 	;;
 
+      riscv)
+	# --target=riscv[32|64]-*-*.  */
+	if test $this_target = $target ; then
+	  AC_DEFINE_UNQUOTED(DEFAULT_ARCH, "${arch}", [Default architecture.])
+	fi
+
+	# --with-arch=<value>.  The syntax of <value> is same as Gas option -march.
+	AC_MSG_CHECKING(for default configuration of --with-arch)
+	if test "x${with_arch}" != x; then
+	  AC_DEFINE_UNQUOTED(DEFAULT_ARCH_WITH_EXT, "$with_arch",
+			     [Define default value for -march])
+	fi
+	AC_MSG_RESULT($with_arch)
+
+	# --with-isa-spec=[2p0|2p1|2p2|20190608|20191213].
+	AC_MSG_CHECKING(for default configuration of --with-isa-spec)
+	if test "x${with_isa_spec}" != x; then
+	  AC_DEFINE_UNQUOTED(DEFAULT_ISA_SPEC, "$with_isa_spec",
+			     [Define default value for -misa-spec])
+	fi
+	AC_MSG_RESULT($with_isa_spec)
+
+	# --with-riscv-isa-version=<value>.  The syntax of <value> is same as Gas
+	# -march, but without the rv[32|64] prefix.
+	AC_MSG_CHECKING(for default configuration of --with-riscv-isa-version)
+	if test "x${with_riscv_isa_version}" != x; then
+	  AC_DEFINE_UNQUOTED(DEFAULT_RISCV_ISA_VERSION, "$with_riscv_isa_version",
+			     [Define default isa version which are not
+			      covered by --with-isa-spec])
+	fi
+	AC_MSG_RESULT($with_riscv_isa_version)
+	;;
+
       rl78)
 	f=rl78-parse.o
 	case " $extra_objects " in
diff --git a/gas/testsuite/gas/riscv/attribute-01.d b/gas/testsuite/gas/riscv/attribute-01.d
index e22773e..3f9e841 100644
--- a/gas/testsuite/gas/riscv/attribute-01.d
+++ b/gas/testsuite/gas/riscv/attribute-01.d
@@ -1,4 +1,4 @@ 
-#as: -march=rv32g -march-attr
+#as: -march=rv32g -march-attr -misa-spec=2p2
 #readelf: -A
 #source: empty.s
 Attribute Section: riscv
diff --git a/gas/testsuite/gas/riscv/attribute-02.d b/gas/testsuite/gas/riscv/attribute-02.d
index bc3295b..a58248e 100644
--- a/gas/testsuite/gas/riscv/attribute-02.d
+++ b/gas/testsuite/gas/riscv/attribute-02.d
@@ -1,6 +1,6 @@ 
-#as: -march=rv32gxargle -march-attr
+#as: -march=rv32gxargle -march-attr -misa-spec=2p2
 #readelf: -A
 #source: empty.s
 Attribute Section: riscv
 File Attributes
-  Tag_RISCV_arch: "rv32i2p0_m2p0_a2p0_f2p0_d2p0_xargle2p0"
+  Tag_RISCV_arch: "rv32i2p0_m2p0_a2p0_f2p0_d2p0_xargle0p0"
diff --git a/gas/testsuite/gas/riscv/attribute-03.d b/gas/testsuite/gas/riscv/attribute-03.d
index 78b706a..04b9ab5 100644
--- a/gas/testsuite/gas/riscv/attribute-03.d
+++ b/gas/testsuite/gas/riscv/attribute-03.d
@@ -1,6 +1,6 @@ 
-#as: -march=rv32gxargle_xfoo -march-attr
+#as: -march=rv32gxargle_xfoo -march-attr -misa-spec=2p2
 #readelf: -A
 #source: empty.s
 Attribute Section: riscv
 File Attributes
-  Tag_RISCV_arch: "rv32i2p0_m2p0_a2p0_f2p0_d2p0_xargle2p0_xfoo2p0"
+  Tag_RISCV_arch: "rv32i2p0_m2p0_a2p0_f2p0_d2p0_xargle0p0_xfoo0p0"
diff --git a/gas/testsuite/gas/riscv/attribute-04.d b/gas/testsuite/gas/riscv/attribute-04.d
index c97bf03..8a3f51b 100644
--- a/gas/testsuite/gas/riscv/attribute-04.d
+++ b/gas/testsuite/gas/riscv/attribute-04.d
@@ -1,4 +1,4 @@ 
-#as: -march-attr
+#as: -march-attr -misa-spec=2p2
 #readelf: -A
 #source: attribute-04.s
 Attribute Section: riscv
diff --git a/gas/testsuite/gas/riscv/attribute-05.d b/gas/testsuite/gas/riscv/attribute-05.d
index f9b65f2..3309ff3 100644
--- a/gas/testsuite/gas/riscv/attribute-05.d
+++ b/gas/testsuite/gas/riscv/attribute-05.d
@@ -1,4 +1,4 @@ 
-#as: -march-attr
+#as: -march-attr -misa-spec=2p2
 #readelf: -A
 #source: attribute-05.s
 Attribute Section: riscv
diff --git a/gas/testsuite/gas/riscv/attribute-06.d b/gas/testsuite/gas/riscv/attribute-06.d
index 1abeb47..5c8a5c6 100644
--- a/gas/testsuite/gas/riscv/attribute-06.d
+++ b/gas/testsuite/gas/riscv/attribute-06.d
@@ -1,4 +1,4 @@ 
-#as: -march=rv32g2p0 -march-attr
+#as: -march=rv32g2p1 -march-attr -misa-spec=2p2
 #readelf: -A
 #source: attribute-06.s
 Attribute Section: riscv
diff --git a/gas/testsuite/gas/riscv/attribute-07.d b/gas/testsuite/gas/riscv/attribute-07.d
index dfd7e6b..20ac9be 100644
--- a/gas/testsuite/gas/riscv/attribute-07.d
+++ b/gas/testsuite/gas/riscv/attribute-07.d
@@ -1,4 +1,4 @@ 
-#as: -march=rv64g2p0 -march-attr
+#as: -march=rv64g2p1 -march-attr -misa-spec=2p2
 #readelf: -A
 #source: attribute-07.s
 Attribute Section: riscv
diff --git a/gas/testsuite/gas/riscv/attribute-08.d b/gas/testsuite/gas/riscv/attribute-08.d
index c10ac0c..7f580d3 100644
--- a/gas/testsuite/gas/riscv/attribute-08.d
+++ b/gas/testsuite/gas/riscv/attribute-08.d
@@ -1,4 +1,4 @@ 
-#as: -march-attr
+#as: -march-attr -misa-spec=2p2
 #readelf: -A
 #source: attribute-08.s
 Attribute Section: riscv
diff --git a/gas/testsuite/gas/riscv/attribute-09.d b/gas/testsuite/gas/riscv/attribute-09.d
new file mode 100644
index 0000000..77c7ef3
--- /dev/null
+++ b/gas/testsuite/gas/riscv/attribute-09.d
@@ -0,0 +1,6 @@ 
+#as: -march-attr -misa-spec=2p2 -mriscv-isa-version=i2p1a2p1v0p9
+#readelf: -A
+#source: attribute-09.s
+Attribute Section: riscv
+File Attributes
+  Tag_RISCV_arch: "rv32i1p9_f2p0_v0p9_zicsr0p0"
diff --git a/gas/testsuite/gas/riscv/attribute-09.s b/gas/testsuite/gas/riscv/attribute-09.s
new file mode 100644
index 0000000..0b1b16c
--- /dev/null
+++ b/gas/testsuite/gas/riscv/attribute-09.s
@@ -0,0 +1 @@ 
+	.attribute arch, "rv32i1p9fv_zicsr"
diff --git a/gas/testsuite/gas/riscv/attribute-10.d b/gas/testsuite/gas/riscv/attribute-10.d
new file mode 100644
index 0000000..9c72035
--- /dev/null
+++ b/gas/testsuite/gas/riscv/attribute-10.d
@@ -0,0 +1,6 @@ 
+#as: -march-attr -march=rv32i_zicsr -misa-spec=20191213
+#readelf: -A
+#source: empty.s
+Attribute Section: riscv
+File Attributes
+  Tag_RISCV_arch: "rv32i2p1_zicsr2p0"
diff --git a/gas/testsuite/gas/riscv/attribute-11.d b/gas/testsuite/gas/riscv/attribute-11.d
new file mode 100644
index 0000000..bc7f986
--- /dev/null
+++ b/gas/testsuite/gas/riscv/attribute-11.d
@@ -0,0 +1,6 @@ 
+#as: -march-attr -march=rv32i_zicsr -misa-spec=20191213 -mriscv-isa-version=zicsr2p1
+#readelf: -A
+#source: empty.s
+Attribute Section: riscv
+File Attributes
+  Tag_RISCV_arch: "rv32i2p1_zicsr2p1"
diff --git a/include/opcode/riscv.h b/include/opcode/riscv.h
index ac6e861..f8b0de3 100644
--- a/include/opcode/riscv.h
+++ b/include/opcode/riscv.h
@@ -343,6 +343,16 @@  struct riscv_opcode
   unsigned long pinfo;
 };
 
+/* This structure holds version information for specific ISA.  */
+
+struct riscv_ext_version
+{
+  const char *name;
+  const char *spec_name;
+  unsigned int major_version;
+  unsigned int minor_version;
+};
+
 /* Instruction is a simple alias (e.g. "mv" for "addi").  */
 #define	INSN_ALIAS		0x00000001
 
@@ -420,5 +430,6 @@  extern const char * const riscv_fpr_names_abi[NFPR];
 
 extern const struct riscv_opcode riscv_opcodes[];
 extern const struct riscv_opcode riscv_insn_types[];
+extern const struct riscv_ext_version riscv_ext_version_table[];
 
 #endif /* _RISCV_H_ */
diff --git a/opcodes/riscv-opc.c b/opcodes/riscv-opc.c
index ceedcaf..7b885bf 100644
--- a/opcodes/riscv-opc.c
+++ b/opcodes/riscv-opc.c
@@ -884,3 +884,56 @@  const struct riscv_opcode riscv_insn_types[] =
 /* Terminate the list.  */
 {0, 0, INSN_CLASS_NONE, 0, 0, 0, 0, 0}
 };
+
+const struct riscv_ext_version riscv_ext_version_table[] =
+{
+/* name, spec name,  major,  minor.  */
+{"e",    "20191213",      1,     9},
+{"e",    "20190608",      1,     9},
+{"e",    "2p2",           1,     9},
+
+{"i",    "20191213",      2,     1},
+{"i",    "20190608",      2,     1},
+{"i",    "2p2",           2,     0},
+
+{"m",    "20191213",      2,     0},
+{"m",    "20190608",      2,     0},
+{"m",    "2p2",           2,     0},
+
+{"a",    "20191213",      2,     1},
+{"a",    "20190608",      2,     0},
+{"a",    "2p2",           2,     0},
+
+{"f",    "20191213",      2,     2},
+{"f",    "20190608",      2,     2},
+{"f",    "2p2",           2,     0},
+
+{"d",    "20191213",      2,     2},
+{"d",    "20190608",      2,     2},
+{"d",    "2p2",           2,     0},
+
+{"q",    "20191213",      2,     2},
+{"q",    "20190608",      2,     2},
+{"q",    "2p2",           2,     0},
+
+{"c",    "20191213",      2,     0},
+{"c",    "20190608",      2,     0},
+{"c",    "2p2",           2,     0},
+
+{"p",    "20191213",      0,     2},
+{"p",    "20190608",      0,     2},
+{"p",    "2p2",           0,     1},
+
+{"v",    "20191213",      0,     7},
+{"v",    "20190608",      0,     7},
+{"v",    "2p2",           0,     7},
+
+{"n",    "20190608",      1,     1},
+{"n",    "2p2",           1,     1},
+
+{"zicsr","20191213",      2,     0},
+{"zicsr","20190608",      2,     0},
+
+/* Terminate the list.  */
+{NULL, NULL, 0, 0}
+};