From nobody Mon Feb 9 17:07:27 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=reject dis=none) header.from=sifive.com ARC-Seal: i=1; a=rsa-sha256; t=1767610886; cv=none; d=zohomail.com; s=zohoarc; b=T1j88Y0dqIvViMaxQFSkNC2QFcY4csHDtdtE25g663p07zQr/H7eR3vWPG867rVLINz/TEhbwqShsOdJhZzbQUcniH5x9LsKAYJVnQhMjScf4vqlPa8fJyrme91VCwv38cckOJ7R8R1NlZap7+ZUetDXYkaJcxx3nNHXSoZqDvY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1767610886; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=BiKcOcTTz94ABpJ/GtmfSGPNcCi/kbiWMe2ly8GnX9Q=; b=iRSv4FoH1mDW62H9gocU4GEfk/ikvKjogeoPbfx70+jQZCVpatNA+0/FvH7xW5Lw+dwNOWlXaI3q9GHem37ayWuLv6hTskvgcU1MhIGVgPXHAABd5DN25CaQQoJl6JdF5+uM6AHFzIW492+75MqvGdxRMALMp9qpJCWdyM0NpiU= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 176761088563010.228552438647057; Mon, 5 Jan 2026 03:01:25 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vciJg-0000yk-C5; Mon, 05 Jan 2026 06:00:06 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vciJZ-0000tZ-3e for qemu-devel@nongnu.org; Mon, 05 Jan 2026 05:59:58 -0500 Received: from mail-pl1-x632.google.com ([2607:f8b0:4864:20::632]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1vciJV-0001nB-FQ for qemu-devel@nongnu.org; Mon, 05 Jan 2026 05:59:56 -0500 Received: by mail-pl1-x632.google.com with SMTP id d9443c01a7336-2a0d6f647e2so226188745ad.1 for ; Mon, 05 Jan 2026 02:59:53 -0800 (PST) Received: from hsinchu18.internal.sifive.com ([210.176.154.34]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2a2f3c6661esm440193975ad.2.2026.01.05.02.59.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 05 Jan 2026 02:59:51 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sifive.com; s=google; t=1767610792; x=1768215592; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=BiKcOcTTz94ABpJ/GtmfSGPNcCi/kbiWMe2ly8GnX9Q=; b=lts3tBiUF1T2bqKHb4qZOPzZ45xrpEqJ4jVj9cWLmOOEXNGF3lfNSkJEM3Rn5Cstok lVdt935zxodHLh8hjsHjn1YBNloLxLTbM8F+cUPAQTlZ+aahoGiDqyoPgq9B9ovq2cok 5UFv6MGBwZ6czgLqbIwEcnN2d/EVVXaJ9XmMnZXrn9ZryNhjNCJc7mRrx+Nuxm2NjAqD XvuEHd23sj8Ckh/NnjMqQHVIj5Mmdn13Wrn6ZWh9oCBuk7JJRO3ssxbumeiiPbEbsWTi 0teIUpxyitE0CexXi7DLBdQuwPdHNIvaJFm17uJs+5Q9WlSyhRALnKa2ZX9yYgYXuNoI YGJg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767610792; x=1768215592; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=BiKcOcTTz94ABpJ/GtmfSGPNcCi/kbiWMe2ly8GnX9Q=; b=uDau51IkVa6dWs0V8MvHhR36JLo02JYl9I7wj+86P1q6Es+zUB6nd/4D1LxA3oJIQa UfO/AKrLCjysYIh6ScCj9v1ql31wd8cUTwI9dtvC3+gaMA3mZShCw6+f2sNlBgbdGKO7 sMmWH/CweUgt00SiLf9A2MehQfkoFH9ldTza32XI80TP+8mv4fc3kRhyASBjlzF8rPP8 zsP0moiWtZketUJk6jcAT2kqCNk1Y3bkknVueBfIkavVQ1kjc+vtLeZEMN7dG43ZxF48 KfUUDjY5nD/hwK6YlcjnoCnnaK3IYAjXeFIVesiwYnqAMExIwz+8jmHC1eHdEyhVcGpg I2Sg== X-Forwarded-Encrypted: i=1; AJvYcCUkw9lspZYA86kaD/toJeIILtLQPr8byg7TSlaH1ujbfecNWJlfyr+VWFUPsqgp7kZ5Yazn1wQCNgLl@nongnu.org X-Gm-Message-State: AOJu0Yw2vdAuNRJp5Pq3tdzQzwv4cOOdhdATb9eahunkUQ1uhknWovPS qPqRF3YSAbk5bnonuL0O2+tyJGiN0rISvLSahP+IXnMO0nE/i+8a0yYxSxAS03bV5Fg= X-Gm-Gg: AY/fxX5K69oI9YVeNPe6hplYhr2PUd6U7AjZBnFZgi9hvBrhPK9iuCINLX+EG5YxTaH R8ptBf+dUM1oOHY+vNWQPubAl7HOJnNI33/rOVwj5fhEpztEWwTrE0cwLoUQRmHUcIYn13Gi4AQ Mr1rhTaWQVS82rWDveMUl5iFkSvDxvMCIwyoPP9OoPLg1+AE0KIptgPkOJZ4uVwlKRuZRNIRDc9 2ZUq3OvljQWvavVzw2j4WGdkBPfspRjSi5ympLnT05G+IF7zhSylvOIZ3kfkKCE7sFiQGQltE2o iWRCm9ujP05Wyjs0b5EWmesMh7CwkJU5vUQbPG8siKj55xTipPmgloSxwb6CZXj7IeydOMh0AnP y3L5xZGgtjSXkB5pFOAQ9ADPQ66cGLBsRHBpCvvk4omr/XTq7Z5kriBT2f0PeJdoDuNj2x2sn/8 hDqckwZALV7NNjgmJAbaxH6FCk74yJH0jADF3TsEv6gPwBIMI= X-Google-Smtp-Source: AGHT+IHlfQV5bh9Oba/TzK2O6mXkvoZukjO4FsxjfHmysCQLPhMoZzmri8ID+ux2xpIvdYvIw6OfCg== X-Received: by 2002:a17:902:f552:b0:2a0:c933:beed with SMTP id d9443c01a7336-2a2f2209461mr486488005ad.4.1767610792036; Mon, 05 Jan 2026 02:59:52 -0800 (PST) From: Kito Cheng To: qemu-riscv@nongnu.org, qemu-devel@nongnu.org Cc: palmer@dabbelt.com, alistair.francis@wdc.com, liwei1518@gmail.com, dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com, kito.cheng@gmail.com, Kito Cheng Subject: [PATCH 1/5] target/riscv: Add arch=dump CPU property for ISA introspection Date: Mon, 5 Jan 2026 18:59:36 +0800 Message-ID: <20260105105940.3567112-2-kito.cheng@sifive.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260105105940.3567112-1-kito.cheng@sifive.com> References: <20260105105940.3567112-1-kito.cheng@sifive.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::632; envelope-from=kito.cheng@sifive.com; helo=mail-pl1-x632.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @sifive.com) X-ZM-MESSAGEID: 1767610890473154100 Content-Type: text/plain; charset="utf-8" --- docs/system/target-riscv.rst | 60 ++++++++++ target/riscv/cpu.c | 128 ++++++++++++++++++++++ target/riscv/cpu_cfg_fields.h.inc | 3 + target/riscv/tcg/tcg-cpu.c | 33 ++++++ tests/functional/riscv32/meson.build | 4 + tests/functional/riscv32/test_cpu_arch.py | 61 +++++++++++ tests/functional/riscv64/meson.build | 4 + tests/functional/riscv64/test_cpu_arch.py | 80 ++++++++++++++ 8 files changed, 373 insertions(+) create mode 100644 tests/functional/riscv32/test_cpu_arch.py create mode 100644 tests/functional/riscv64/test_cpu_arch.py diff --git a/docs/system/target-riscv.rst b/docs/system/target-riscv.rst index 89b2cb732c2..3ec53dbf9e5 100644 --- a/docs/system/target-riscv.rst +++ b/docs/system/target-riscv.rst @@ -73,6 +73,66 @@ undocumented; you can get a complete list by running riscv/virt riscv/xiangshan-kunminghu =20 +RISC-V CPU options +------------------ + +RISC-V CPUs support various options to configure ISA extensions and other +features. These options can be specified using the ``-cpu`` command line +option. + +ISA extension configuration +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Individual ISA extensions can be enabled or disabled using boolean propert= ies:: + + $ qemu-system-riscv64 -M virt -cpu rv64,v=3Dtrue,zba=3Dfalse + +The ``arch`` property +^^^^^^^^^^^^^^^^^^^^^ + +The ``arch`` property provides a convenient way to inspect the current ISA +configuration: + +* ``arch=3Ddump`` + + Print the current ISA configuration and exit. This shows the full ISA st= ring + and the status of all supported extensions:: + + $ qemu-system-riscv64 -M virt -cpu rv64,arch=3Ddump + $ qemu-riscv64 -cpu rv64,v=3Dtrue,arch=3Ddump /bin/true + + The dump shows the final configuration after all CPU properties are appl= ied, + regardless of where ``arch=3Ddump`` appears in the option list. For exam= ple, + both of the following commands show the same result with vector extension + enabled:: + + $ qemu-riscv64 -cpu rv64,v=3Dtrue,arch=3Ddump /bin/true + $ qemu-riscv64 -cpu rv64,arch=3Ddump,v=3Dtrue /bin/true + +Privilege-implied extensions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Some RISC-V extensions cannot be individually enabled or disabled. These +extensions are automatically enabled based on the privilege specification +version configured for the CPU. Examples include: + +- ``shcounterenw``, ``shgatpa``, ``shtvala``, ``shvsatpa``, ``shvstvala``, + ``shvstvecd`` - Enabled when privilege spec 1.12 or later is supported +- ``ssccptr``, ``sscounterenw``, ``ssstrict``, ``sstvala``, ``sstvecd``, + ``ssu64xl`` - Enabled when privilege spec 1.12 or later is supported +- ``ziccamoa``, ``ziccif``, ``zicclsm``, ``za64rs`` - Enabled when + privilege spec 1.12 or later is supported + +These extensions appear in the ``arch=3Ddump`` output under "Privilege Imp= lied +Extensions" section. To control these extensions, use the ``priv_spec`` +property to set the privilege specification version:: + + $ qemu-riscv64 -cpu rv64,h=3Dfalse,priv_spec=3Dv1.11.0,arch=3Ddump /bin/= true + +Note: Some extensions like H (Hypervisor) require a minimum privilege spec +version. When lowering the privilege spec, you may need to disable such +extensions first. + RISC-V CPU firmware ------------------- =20 diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 8f26d8b8b07..2886b7ebcdd 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -896,6 +896,129 @@ static void riscv_cpu_satp_mode_finalize(RISCVCPU *cp= u, Error **errp) } #endif =20 +static inline const char *riscv_ext_status_str(bool enabled) +{ + return enabled ? "enabled" : "disabled"; +} + +/* + * Helper function to print multi-letter extension entries for arch=3Ddump. + * Does not print section header. + */ +static void riscv_cpu_dump_multiext_entries(RISCVCPU *cpu, + const RISCVCPUMultiExtConfig *= exts) +{ + for (const RISCVCPUMultiExtConfig *prop =3D exts; + prop && prop->name; prop++) { + bool enabled =3D isa_ext_is_enabled(cpu, prop->offset); + qemu_printf(" %-20s %-8s\n", + prop->name, + riscv_ext_status_str(enabled)); + } +} + +/* + * Helper function to print multi-letter extensions for arch=3Ddump. + */ +static void riscv_cpu_dump_multiext(RISCVCPU *cpu, const char *title, + const RISCVCPUMultiExtConfig *exts) +{ + qemu_printf("%s:\n", title); + qemu_printf(" %-20s %-8s\n", "Name", "Status"); + qemu_printf(" %-20s %-8s\n", "----", "------"); + + riscv_cpu_dump_multiext_entries(cpu, exts); + qemu_printf("\n"); +} + +/* + * Check if an extension offset corresponds to a privilege-implied extensi= on. + * These are extensions that map to has_priv_1_11, has_priv_1_12, or + * has_priv_1_13 instead of individual ext_* fields. + */ +static bool riscv_ext_is_priv_implied(uint32_t offset) +{ + return offset =3D=3D CPU_CFG_OFFSET(has_priv_1_11) || + offset =3D=3D CPU_CFG_OFFSET(has_priv_1_12) || + offset =3D=3D CPU_CFG_OFFSET(has_priv_1_13); +} + +/* + * Helper function to print privilege-implied extensions for arch=3Ddump. + * These are extensions that are automatically enabled based on the + * privilege specification version. + */ +static void riscv_cpu_dump_priv_implied_exts(RISCVCPU *cpu) +{ + qemu_printf("Privilege Implied Extensions:\n"); + qemu_printf(" %-20s %-8s\n", "Name", "Status"); + qemu_printf(" %-20s %-8s\n", "----", "------"); + + for (const RISCVIsaExtData *edata =3D isa_edata_arr; edata->name; edat= a++) { + if (riscv_ext_is_priv_implied(edata->ext_enable_offset)) { + bool enabled =3D isa_ext_is_enabled(cpu, edata->ext_enable_off= set); + qemu_printf(" %-20s %-8s\n", + edata->name, + riscv_ext_status_str(enabled)); + } + } + qemu_printf("\n"); +} + +/* + * Print detailed ISA configuration and exit. + * Called when arch=3Ddump is specified. + */ +static G_NORETURN void riscv_cpu_dump_isa_config(RISCVCPU *cpu) +{ + RISCVCPUClass *mcc =3D RISCV_CPU_GET_CLASS(cpu); + CPURISCVState *env =3D &cpu->env; + g_autofree char *isa_str =3D riscv_isa_string(cpu); + int xlen =3D riscv_cpu_max_xlen(mcc); + + qemu_printf("\n"); + qemu_printf("RISC-V ISA Configuration (arch=3Ddump)\n"); + qemu_printf("=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D\n\n"); + + /* Print full ISA string */ + qemu_printf("Full ISA string: %s\n\n", isa_str); + + /* Print base information */ + qemu_printf("Base: RV%d\n", xlen); + qemu_printf("Privilege spec: %s\n\n", priv_spec_to_str(env->priv_ver)); + + /* Print single-letter extensions */ + qemu_printf("Standard Extensions (single-letter):\n"); + qemu_printf(" %-20s %-8s\n", "Name", "Status"); + qemu_printf(" %-20s %-8s\n", "----", "------"); + + for (int i =3D 0; misa_bits[i] !=3D 0; i++) { + uint32_t bit =3D misa_bits[i]; + const char *name =3D riscv_get_misa_ext_name(bit); + bool enabled =3D env->misa_ext & bit; + + qemu_printf(" %-20s %-8s\n", + name, + riscv_ext_status_str(enabled)); + } + qemu_printf("\n"); + + /* Print multi-letter standard extensions (including named features) */ + qemu_printf("Standard Extensions (multi-letter):\n"); + qemu_printf(" %-20s %-8s\n", "Name", "Status"); + qemu_printf(" %-20s %-8s\n", "----", "------"); + riscv_cpu_dump_multiext_entries(cpu, riscv_cpu_extensions); + riscv_cpu_dump_multiext_entries(cpu, riscv_cpu_named_features); + qemu_printf("\n"); + + riscv_cpu_dump_multiext(cpu, "Vendor Extensions", riscv_cpu_vendor_ext= s); + riscv_cpu_dump_multiext(cpu, "Experimental Extensions", + riscv_cpu_experimental_exts); + riscv_cpu_dump_priv_implied_exts(cpu); + + exit(0); +} + void riscv_cpu_finalize_features(RISCVCPU *cpu, Error **errp) { Error *local_err =3D NULL; @@ -943,6 +1066,11 @@ static void riscv_cpu_realize(DeviceState *dev, Error= **errp) return; } =20 + /* Check for arch=3Ddump request after all features are finalized */ + if (cpu->cfg.arch_dump_requested) { + riscv_cpu_dump_isa_config(cpu); + } + riscv_cpu_register_gdb_regs_for_features(cs); =20 #ifndef CONFIG_USER_ONLY diff --git a/target/riscv/cpu_cfg_fields.h.inc b/target/riscv/cpu_cfg_field= s.h.inc index a154ecdc792..87ef228a17d 100644 --- a/target/riscv/cpu_cfg_fields.h.inc +++ b/target/riscv/cpu_cfg_fields.h.inc @@ -155,6 +155,9 @@ BOOL_FIELD(misa_w) =20 BOOL_FIELD(short_isa_string) =20 +/* arch=3D property flags */ +BOOL_FIELD(arch_dump_requested) + TYPED_FIELD(uint32_t, mvendorid, 0) TYPED_FIELD(uint64_t, marchid, 0) TYPED_FIELD(uint64_t, mimpid, 0) diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index bb03f8dc0ca..f7187472cd2 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -1551,6 +1551,37 @@ static void riscv_cpu_add_multiext_prop_array(Object= *obj, } } =20 +/* + * arch=3D property handler for ISA string configuration. + * This is a write-only property used to trigger actions like arch=3Ddump. + */ +static void cpu_set_arch(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + RISCVCPU *cpu =3D RISCV_CPU(obj); + g_autofree char *value =3D NULL; + + if (!visit_type_str(v, name, &value, errp)) { + return; + } + + if (g_strcmp0(value, "dump") =3D=3D 0) { + cpu->cfg.arch_dump_requested =3D true; + } else { + error_setg(errp, "unknown arch option '%s'. " + "Supported options: dump", value); + } +} + +static void riscv_cpu_add_arch_property(Object *obj) +{ + object_property_add(obj, "arch", "str", + NULL, cpu_set_arch, + NULL, NULL); + object_property_set_description(obj, "arch", + "ISA configuration string (write-only). Use 'dump' to print ISA co= nfig."); +} + /* * Add CPU properties with user-facing flags. * @@ -1570,6 +1601,8 @@ static void riscv_cpu_add_user_properties(Object *obj) riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_experimental_exts); =20 riscv_cpu_add_profiles(obj); + + riscv_cpu_add_arch_property(obj); } =20 /* diff --git a/tests/functional/riscv32/meson.build b/tests/functional/riscv3= 2/meson.build index f3ebbb8db5d..a3f7a3dffce 100644 --- a/tests/functional/riscv32/meson.build +++ b/tests/functional/riscv32/meson.build @@ -8,3 +8,7 @@ tests_riscv32_system_quick =3D [ tests_riscv32_system_thorough =3D [ 'tuxrun', ] + +tests_riscv32_linuxuser_quick =3D [ + 'cpu_arch', +] diff --git a/tests/functional/riscv32/test_cpu_arch.py b/tests/functional/r= iscv32/test_cpu_arch.py new file mode 100644 index 00000000000..7b2f87cad88 --- /dev/null +++ b/tests/functional/riscv32/test_cpu_arch.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 +# +# Test RISC-V CPU arch=3D property +# +# Copyright (c) 2026 SiFive, Inc. +# +# SPDX-License-Identifier: GPL-2.0-or-later + +from subprocess import run + +from qemu_test import QemuUserTest + + +class RiscvCpuArch(QemuUserTest): + """Test RISC-V CPU arch=3D property""" + + def run_qemu(self, cpu_opt, bin_path=3D'/bin/true'): + """Run qemu-riscv32 with specified CPU option""" + cmd =3D [self.qemu_bin, '-cpu', cpu_opt, bin_path] + return run(cmd, text=3DTrue, capture_output=3DTrue) + + def test_arch_dump(self): + """Test arch=3Ddump prints ISA configuration and exits""" + res =3D self.run_qemu('rv32,arch=3Ddump') + + self.assertEqual(res.returncode, 0, + f"arch=3Ddump should exit with 0, got {res.return= code}") + + # Check for expected output sections + self.assertIn('RISC-V ISA Configuration', res.stdout) + self.assertIn('Full ISA string:', res.stdout) + self.assertIn('Standard Extensions (single-letter):', res.stdout) + self.assertIn('Standard Extensions (multi-letter):', res.stdout) + self.assertIn('Vendor Extensions:', res.stdout) + # Check it's RV32 + self.assertIn('Base: RV32', res.stdout) + + def test_arch_dump_shows_enabled_extensions(self): + """Test arch=3Ddump correctly shows enabled extensions""" + res =3D self.run_qemu('rv32,arch=3Ddump') + + # Default rv32 should have these enabled + self.assertRegex(res.stdout, r'i\s+enabled') + self.assertRegex(res.stdout, r'm\s+enabled') + self.assertRegex(res.stdout, r'a\s+enabled') + self.assertRegex(res.stdout, r'f\s+enabled') + self.assertRegex(res.stdout, r'd\s+enabled') + self.assertRegex(res.stdout, r'c\s+enabled') + + def test_arch_invalid_option(self): + """Test invalid arch=3D option shows error with supported options"= "" + res =3D self.run_qemu('rv32,arch=3Dinvalid') + + self.assertNotEqual(res.returncode, 0, + "Invalid arch option should fail") + self.assertIn("unknown arch option 'invalid'", res.stderr) + self.assertIn("Supported options:", res.stderr) + + +if __name__ =3D=3D '__main__': + QemuUserTest.main() diff --git a/tests/functional/riscv64/meson.build b/tests/functional/riscv6= 4/meson.build index c1704d92751..82a29dcc974 100644 --- a/tests/functional/riscv64/meson.build +++ b/tests/functional/riscv64/meson.build @@ -13,3 +13,7 @@ tests_riscv64_system_thorough =3D [ 'sifive_u', 'tuxrun', ] + +tests_riscv64_linuxuser_quick =3D [ + 'cpu_arch', +] diff --git a/tests/functional/riscv64/test_cpu_arch.py b/tests/functional/r= iscv64/test_cpu_arch.py new file mode 100644 index 00000000000..b0af8991397 --- /dev/null +++ b/tests/functional/riscv64/test_cpu_arch.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 +# +# Test RISC-V CPU arch=3D property +# +# Copyright (c) 2026 SiFive, Inc. +# +# SPDX-License-Identifier: GPL-2.0-or-later + +from subprocess import run + +from qemu_test import QemuUserTest + + +class RiscvCpuArch(QemuUserTest): + """Test RISC-V CPU arch=3D property""" + + def run_qemu(self, cpu_opt, bin_path=3D'/bin/true'): + """Run qemu-riscv64 with specified CPU option""" + cmd =3D [self.qemu_bin, '-cpu', cpu_opt, bin_path] + return run(cmd, text=3DTrue, capture_output=3DTrue) + + def test_arch_dump(self): + """Test arch=3Ddump prints ISA configuration and exits""" + res =3D self.run_qemu('rv64,arch=3Ddump') + + self.assertEqual(res.returncode, 0, + f"arch=3Ddump should exit with 0, got {res.return= code}") + + # Check for expected output sections + self.assertIn('RISC-V ISA Configuration', res.stdout) + self.assertIn('Full ISA string:', res.stdout) + self.assertIn('Standard Extensions (single-letter):', res.stdout) + self.assertIn('Standard Extensions (multi-letter):', res.stdout) + self.assertIn('Vendor Extensions:', res.stdout) + + def test_arch_dump_shows_enabled_extensions(self): + """Test arch=3Ddump correctly shows enabled extensions""" + res =3D self.run_qemu('rv64,arch=3Ddump') + + # Default rv64 should have these enabled + self.assertRegex(res.stdout, r'i\s+enabled') + self.assertRegex(res.stdout, r'm\s+enabled') + self.assertRegex(res.stdout, r'a\s+enabled') + self.assertRegex(res.stdout, r'f\s+enabled') + self.assertRegex(res.stdout, r'd\s+enabled') + self.assertRegex(res.stdout, r'c\s+enabled') + + def test_arch_dump_with_vector(self): + """Test arch=3Ddump shows vector extension when enabled""" + res =3D self.run_qemu('rv64,v=3Dtrue,arch=3Ddump') + + self.assertEqual(res.returncode, 0) + self.assertRegex(res.stdout, r'v\s+enabled') + + def test_arch_dump_position_independence(self): + """Test arch=3Ddump shows final config regardless of position""" + # arch=3Ddump before v=3Dtrue + res1 =3D self.run_qemu('rv64,arch=3Ddump,v=3Dtrue') + # arch=3Ddump after v=3Dtrue + res2 =3D self.run_qemu('rv64,v=3Dtrue,arch=3Ddump') + + self.assertEqual(res1.returncode, 0) + self.assertEqual(res2.returncode, 0) + + # Both should show v enabled + self.assertRegex(res1.stdout, r'v\s+enabled') + self.assertRegex(res2.stdout, r'v\s+enabled') + + def test_arch_invalid_option(self): + """Test invalid arch=3D option shows error with supported options"= "" + res =3D self.run_qemu('rv64,arch=3Dinvalid') + + self.assertNotEqual(res.returncode, 0, + "Invalid arch option should fail") + self.assertIn("unknown arch option 'invalid'", res.stderr) + self.assertIn("Supported options:", res.stderr) + + +if __name__ =3D=3D '__main__': + QemuUserTest.main() --=20 2.52.0 From nobody Mon Feb 9 17:07:27 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=reject dis=none) header.from=sifive.com ARC-Seal: i=1; a=rsa-sha256; t=1767610815; cv=none; d=zohomail.com; s=zohoarc; b=mJuOiwk9Xegmzh2nfLKuwmaRJb9/jDBOYRdCkeWraYlV/zRHrvcmnwZMo7ppfrv9FxP57q/tAO9Dzm8o589UaI5KDX1/ySd/CqhFvJqGhr1SVbM0jiRdokuvrS0QIj165IcJWoy6r+NIRzLQN92GcX59vdB0oDKsj3Y4vtGV0jg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1767610815; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=0mvyYXT1r2G4eaZnd++PzL/PkomyAfdOWZbiHRB33pY=; b=Ub8moQ2fzFyeBNcpZgmD8I8Q20eOFyGyxAd6vHxhUZnjwlKsycG1nAnDVP2jJe1ZZUf7pt+OhS7kM+WTuCYPIlUgpGGYS/9w4BtLF7W92E/baxMmw/FcGzmj8z3Na/GYa4nSR3B88nss2y9lpLSS0+16VrZHLqIjKffDMyFCtPE= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1767610815760971.7497301539934; Mon, 5 Jan 2026 03:00:15 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vciJe-0000y4-4p; Mon, 05 Jan 2026 06:00:02 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vciJZ-0000tc-Jr for qemu-devel@nongnu.org; Mon, 05 Jan 2026 05:59:58 -0500 Received: from mail-pl1-x62a.google.com ([2607:f8b0:4864:20::62a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1vciJX-0001nU-Mc for qemu-devel@nongnu.org; Mon, 05 Jan 2026 05:59:57 -0500 Received: by mail-pl1-x62a.google.com with SMTP id d9443c01a7336-2a07fac8aa1so151052875ad.1 for ; Mon, 05 Jan 2026 02:59:55 -0800 (PST) Received: from hsinchu18.internal.sifive.com ([210.176.154.34]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2a2f3c6661esm440193975ad.2.2026.01.05.02.59.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 05 Jan 2026 02:59:53 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sifive.com; s=google; t=1767610794; x=1768215594; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=0mvyYXT1r2G4eaZnd++PzL/PkomyAfdOWZbiHRB33pY=; b=U+rNTyRtWyPxaGl8hr10+7Ranet/TdxYsGg/7fdUDwFXWkw9aCu/AOYpjAykot8+X1 4iK02EacXBu4sz0Nsv48bY4yzX0csg58Wd19DwerpYN/QCGoTEJFYw5+f4Z7JgsVsgfM Bq/k051JtXVR2WYdg+MOJOVBZOyUz//9wR1rn95FqP6dGuysLxKvLXdROFG7uQLikH5f 7tf3FPjEy1jW5R8wWn9QuXCWLCsz6i6SHIFtFUnwytHL4XRgGlTNPHLCdZSK+tR2xRSU qJ7gGMY0eHYlf/teYHsj06uLA9h39g7vu18OcBAD1OTYjv6hu9R9k68vKfx7wGxQ6PRY Ts1g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767610794; x=1768215594; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=0mvyYXT1r2G4eaZnd++PzL/PkomyAfdOWZbiHRB33pY=; b=SZKh117Uzk6j34tOphRm6SPyKETAJNjkeM0RiLQpT86DnrBrruo7mA8gwM7eKo0AL+ 4U5L0eDaK0Fq/XC+9m/8l0tu7NTM5dL/+mjckEy5uF5eHXxFWTlUPXAfveR6mjeZ7Lwh qjX0lp2KsDwR/x1vVBsZjvNtYkpJvJMuVKqONCUqmtoMLmz/b/lW0r5ERlDVVUBPADP5 cSKI1luytkul1PlZN9lI9n3OEF9/euGehZ654yLx5MKG14AOCwEJ+8mNH6HIRJxyhStU zGbApmGDg0VmRYZ8e9/WAYpEKfhPgTdbEApD62Vorj7KWNMFc/a4a0jB2yZVZLDk+lRR q68g== X-Forwarded-Encrypted: i=1; AJvYcCXuKIeOsQdb3xFpwh65y3BeQVWaiE4KtJ/lg7YJq3h8w4/pFkGIesjZmid/SFyhnQ8tZSsQu33jJ2/N@nongnu.org X-Gm-Message-State: AOJu0YzSCMRxpRvyiwm+hs+ZL0veNQYMN0AdXAVJUT2cnswnSqrCknlZ 7E1NXr75VhlbSly62t15OOfOEn+q0MgznUnFfbY3oImgMzatIWHRQCVVfZtfqeLhO40oJurYWso Ic5TZ X-Gm-Gg: AY/fxX5mDH1Cm2Kd/ItLJOXrNDcBr5zmByf+z8NQYjV+4PtA6vZ/kMqopuxcEz41GZx ly2b1M6MOCFumqxw5a/VVZGozzgw7B96U2HSlnl1+W6ZuqihinZ4B0W85mW28RQSsi0zlvdw5BY xbOga9FTVBsQOQdAtLiqEPAe37L1ivH620HhsddYMzLu3IVf52O9fOesVsDmKuUcxDzcvTLd4K6 byFmWGUA5h1v1ApwmhgRJyGN0ZKKIflOKk/VknEAntTWSE6wNe0ESZ89k8YR5hP8yb+2r9qqpKi 2WGpH7oEej4AIFM8gGSt9Sz165On5ZEZgzblgQnPsaY5coxifUgFb4ETPuufwAly0dcU4MEMJJz i5jjl3lAtGNRXRcMoFwNqdKFBBaUMLLjYHqDedaSkRzVO8fUawF10Flb0lO12c0OvxJTKtx/qiA GG3kXyAuo7KhvPoEj2tnLdpj1hABTYJOXgtp6E X-Google-Smtp-Source: AGHT+IGirs0DCw14XjY7Q3i42GRevN1P9Txhl4P9zJ0/BtvbUydWMP2/nw2c09lgCayXYufeSGrasw== X-Received: by 2002:a17:902:e541:b0:29f:1bf:6424 with SMTP id d9443c01a7336-2a2f221ff92mr504692105ad.18.1767610794156; Mon, 05 Jan 2026 02:59:54 -0800 (PST) From: Kito Cheng To: qemu-riscv@nongnu.org, qemu-devel@nongnu.org Cc: palmer@dabbelt.com, alistair.francis@wdc.com, liwei1518@gmail.com, dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com, kito.cheng@gmail.com, Kito Cheng Subject: [PATCH 2/5] target/riscv: Add arch=help to list supported ISA extensions Date: Mon, 5 Jan 2026 18:59:37 +0800 Message-ID: <20260105105940.3567112-3-kito.cheng@sifive.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260105105940.3567112-1-kito.cheng@sifive.com> References: <20260105105940.3567112-1-kito.cheng@sifive.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::62a; envelope-from=kito.cheng@sifive.com; helo=mail-pl1-x62a.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @sifive.com) X-ZM-MESSAGEID: 1767610817440154100 Content-Type: text/plain; charset="utf-8" --- docs/system/target-riscv.rst | 14 ++++- target/riscv/cpu.c | 69 +++++++++++++++++++++++ target/riscv/cpu.h | 1 + target/riscv/tcg/tcg-cpu.c | 7 ++- tests/functional/riscv32/test_cpu_arch.py | 12 ++++ tests/functional/riscv64/test_cpu_arch.py | 25 ++++++++ 6 files changed, 124 insertions(+), 4 deletions(-) diff --git a/docs/system/target-riscv.rst b/docs/system/target-riscv.rst index 3ec53dbf9e5..9acc51fbc2b 100644 --- a/docs/system/target-riscv.rst +++ b/docs/system/target-riscv.rst @@ -90,8 +90,18 @@ Individual ISA extensions can be enabled or disabled usi= ng boolean properties:: The ``arch`` property ^^^^^^^^^^^^^^^^^^^^^ =20 -The ``arch`` property provides a convenient way to inspect the current ISA -configuration: +The ``arch`` property provides convenient ways to discover and inspect ISA +extensions: + +* ``arch=3Dhelp`` + + Print a list of all supported ISA extensions and exit:: + + $ qemu-system-riscv64 -M virt -cpu rv64,arch=3Dhelp + $ qemu-riscv64 -cpu rv64,arch=3Dhelp /bin/true + + This lists standard single-letter extensions (with descriptions), multi-= letter + extensions, vendor extensions, and experimental extensions. =20 * ``arch=3Ddump`` =20 diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 2886b7ebcdd..b1d8438cd14 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -896,6 +896,23 @@ static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu= , Error **errp) } #endif =20 +/* + * Helper function to print single-letter extensions for arch=3Dhelp. + */ +static void riscv_cpu_help_misa_exts(void) +{ + qemu_printf("Standard Extensions (single-letter):\n"); + + for (int i =3D 0; misa_bits[i] !=3D 0; i++) { + uint32_t bit =3D misa_bits[i]; + const char *name =3D riscv_get_misa_ext_name(bit); + const char *desc =3D riscv_get_misa_ext_description(bit); + + qemu_printf(" %-4s %s\n", name, desc); + } + qemu_printf("\n"); +} + static inline const char *riscv_ext_status_str(bool enabled) { return enabled ? "enabled" : "disabled"; @@ -965,6 +982,58 @@ static void riscv_cpu_dump_priv_implied_exts(RISCVCPU = *cpu) qemu_printf("\n"); } =20 +/* + * Helper function to print multi-letter extension names for arch=3Dhelp. + * Does not print section header. + */ +static void riscv_cpu_help_multiext_entries(const RISCVCPUMultiExtConfig *= exts) +{ + for (const RISCVCPUMultiExtConfig *prop =3D exts; + prop && prop->name; prop++) { + qemu_printf(" %s\n", prop->name); + } +} + +/* + * Helper function to print multi-letter extensions for arch=3Dhelp. + */ +static void riscv_cpu_help_multiext(const char *title, + const RISCVCPUMultiExtConfig *exts) +{ + qemu_printf("%s:\n", title); + + riscv_cpu_help_multiext_entries(exts); + qemu_printf("\n"); +} + +/* + * Print list of supported ISA extensions and exit. + * Called when arch=3Dhelp is specified. + */ +G_NORETURN void riscv_cpu_list_supported_extensions(void) +{ + qemu_printf("\n"); + qemu_printf("Supported RISC-V ISA Extensions\n"); + qemu_printf("=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D\n\n"); + + riscv_cpu_help_misa_exts(); + + /* Print multi-letter standard extensions (including named features) */ + qemu_printf("Standard Extensions (multi-letter):\n"); + riscv_cpu_help_multiext_entries(riscv_cpu_extensions); + riscv_cpu_help_multiext_entries(riscv_cpu_named_features); + qemu_printf("\n"); + + riscv_cpu_help_multiext("Vendor Extensions", riscv_cpu_vendor_exts); + riscv_cpu_help_multiext("Experimental Extensions", + riscv_cpu_experimental_exts); + + qemu_printf("Use '-cpu ,=3Dtrue' to enable an extension.\n"); + qemu_printf("Use '-cpu ,arch=3Ddump' to show current configuratio= n.\n"); + + exit(0); +} + /* * Print detailed ISA configuration and exit. * Called when arch=3Ddump is specified. diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 90b3e951053..5c08c2ca4d6 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -986,4 +986,5 @@ const char *satp_mode_str(uint8_t satp_mode, bool is_32= _bit); extern const RISCVCSR th_csr_list[]; =20 const char *priv_spec_to_str(int priv_version); +G_NORETURN void riscv_cpu_list_supported_extensions(void); #endif /* RISCV_CPU_H */ diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index f7187472cd2..c9600a52e1c 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -1567,9 +1567,11 @@ static void cpu_set_arch(Object *obj, Visitor *v, co= nst char *name, =20 if (g_strcmp0(value, "dump") =3D=3D 0) { cpu->cfg.arch_dump_requested =3D true; + } else if (g_strcmp0(value, "help") =3D=3D 0) { + riscv_cpu_list_supported_extensions(); } else { error_setg(errp, "unknown arch option '%s'. " - "Supported options: dump", value); + "Supported options: dump, help", value); } } =20 @@ -1579,7 +1581,8 @@ static void riscv_cpu_add_arch_property(Object *obj) NULL, cpu_set_arch, NULL, NULL); object_property_set_description(obj, "arch", - "ISA configuration string (write-only). Use 'dump' to print ISA co= nfig."); + "ISA configuration (write-only). " + "Use 'help' to list extensions, 'dump' to show current config."); } =20 /* diff --git a/tests/functional/riscv32/test_cpu_arch.py b/tests/functional/r= iscv32/test_cpu_arch.py index 7b2f87cad88..b2042f1e5d8 100644 --- a/tests/functional/riscv32/test_cpu_arch.py +++ b/tests/functional/riscv32/test_cpu_arch.py @@ -47,6 +47,18 @@ def test_arch_dump_shows_enabled_extensions(self): self.assertRegex(res.stdout, r'd\s+enabled') self.assertRegex(res.stdout, r'c\s+enabled') =20 + def test_arch_help(self): + """Test arch=3Dhelp prints list of supported extensions and exits"= "" + res =3D self.run_qemu('rv32,arch=3Dhelp') + + self.assertEqual(res.returncode, 0, + f"arch=3Dhelp should exit with 0, got {res.return= code}") + + # Check for expected output sections + self.assertIn('Supported RISC-V ISA Extensions', res.stdout) + self.assertIn('Standard Extensions (single-letter):', res.stdout) + self.assertIn('Standard Extensions (multi-letter):', res.stdout) + def test_arch_invalid_option(self): """Test invalid arch=3D option shows error with supported options"= "" res =3D self.run_qemu('rv32,arch=3Dinvalid') diff --git a/tests/functional/riscv64/test_cpu_arch.py b/tests/functional/r= iscv64/test_cpu_arch.py index b0af8991397..4ec807b7276 100644 --- a/tests/functional/riscv64/test_cpu_arch.py +++ b/tests/functional/riscv64/test_cpu_arch.py @@ -66,6 +66,31 @@ def test_arch_dump_position_independence(self): self.assertRegex(res1.stdout, r'v\s+enabled') self.assertRegex(res2.stdout, r'v\s+enabled') =20 + def test_arch_help(self): + """Test arch=3Dhelp prints list of supported extensions and exits"= "" + res =3D self.run_qemu('rv64,arch=3Dhelp') + + self.assertEqual(res.returncode, 0, + f"arch=3Dhelp should exit with 0, got {res.return= code}") + + # Check for expected output sections + self.assertIn('Supported RISC-V ISA Extensions', res.stdout) + self.assertIn('Standard Extensions (single-letter):', res.stdout) + self.assertIn('Standard Extensions (multi-letter):', res.stdout) + self.assertIn('Vendor Extensions:', res.stdout) + + def test_arch_help_shows_extensions(self): + """Test arch=3Dhelp lists common extensions""" + res =3D self.run_qemu('rv64,arch=3Dhelp') + + # Check single-letter extensions with descriptions + self.assertIn('Base integer instruction set', res.stdout) + self.assertIn('Vector operations', res.stdout) + + # Check multi-letter extensions are listed + self.assertIn('zba', res.stdout) + self.assertIn('zbb', res.stdout) + def test_arch_invalid_option(self): """Test invalid arch=3D option shows error with supported options"= "" res =3D self.run_qemu('rv64,arch=3Dinvalid') --=20 2.52.0 From nobody Mon Feb 9 17:07:27 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=reject dis=none) header.from=sifive.com ARC-Seal: i=1; a=rsa-sha256; t=1767610823; cv=none; d=zohomail.com; s=zohoarc; b=ZD/VvojLEGqavLIm2smPcrEwXgmnSz+HHcHbiYbNc6WMGE5tD+va4/8GQmZLTSRfscmwN8HXRxKkIhJ6kr78mcJ50K6p/eJDN3310y6b3hVLPh98R+aA2jTBHOBwOxLREMxpYdpQ7J0n2S8CffICKK4nL1WbIhHCa5wYbOQOhTw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1767610823; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=iVt84wL5z8nWmHQsPvVEJWwZQBhNHUCqqOx+s1/1LQ8=; b=CwEgEpjRcg5e2X4yQOw35jS3VUeif1sb2HRQ04Snx9Y1bAqiGTqj/YM1o2ecZKjqorn3Xbg+C06d/Rgbk4qCTlXGY9jzJ2w+MaW5X9uadZI4/N5uq5e0ZQPGRrx9XLVZ/nWsO9fwC2dxzDGgdh1r0oXgJtLeo202aGB9rl6XI5w= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1767610823299369.1349368268336; Mon, 5 Jan 2026 03:00:23 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vciJk-000114-3x; Mon, 05 Jan 2026 06:00:08 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vciJc-0000wc-SC for qemu-devel@nongnu.org; Mon, 05 Jan 2026 06:00:01 -0500 Received: from mail-pl1-x631.google.com ([2607:f8b0:4864:20::631]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1vciJa-0001o8-8c for qemu-devel@nongnu.org; Mon, 05 Jan 2026 06:00:00 -0500 Received: by mail-pl1-x631.google.com with SMTP id d9443c01a7336-2a09a3bd9c5so123643495ad.3 for ; Mon, 05 Jan 2026 02:59:57 -0800 (PST) Received: from hsinchu18.internal.sifive.com ([210.176.154.34]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2a2f3c6661esm440193975ad.2.2026.01.05.02.59.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 05 Jan 2026 02:59:55 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sifive.com; s=google; t=1767610796; x=1768215596; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=iVt84wL5z8nWmHQsPvVEJWwZQBhNHUCqqOx+s1/1LQ8=; b=Yf7CP83Ldv8guY63khSCxDIqF0mr9q86bspLgShgaSzVpvDdFduZEPfhwW74uZcgzB 5N6S9RwIRJeK4YRm7pobUyZY7U3BtH9G8eN1No9Fys2YCh67HCtF+O9QZ+doJfrtuiUu +Akgoml4tfKHCwL0E+rfhiQ5RM+RnbltnILKzOEkOnrVuv+zpy77tAzko8WGjCy8d9G7 NXJ3pfntt1EVdxbeIstk5hZbYlZgO3rn5cwQipTk2f5LM2/soBVZ3BkwqCKwzjyUIzrQ qGEE+MQ43Zx+lhhPURaOQ8aG+6LD7KgagXvvxYqUP1YRtFE3CF1gywVf9FFwXKSsXzzt KlRg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767610796; x=1768215596; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=iVt84wL5z8nWmHQsPvVEJWwZQBhNHUCqqOx+s1/1LQ8=; b=KgCSB71Eds7tSCPb57V5K3YNrwklh62hpkLOLYMOCfdtU2wf3tOTFhqUJUWcr1uMo7 JV9cgVFj26Mf3sSjlwSR0JbVWsqSm4amDjizZw7Vjqo1zW+2ir7HNgcbbclmb1LXXjS7 VtkrCBkSl4fSST6SgpLdfsFRdANy7mTSe//D+r449VXkNT1Q5rAsuV4n9y+pmV2VEkiB EzhGcFAeVEeggqp9cAR1IYFOUnH5BcgitpktpGfBV3jFyqOp+M3Na8w2el2N1phIT3qJ tRPU0tM7DXTszWASTWCgORSWN9hnhvq/b70x+UeQJ7hhcfV4KiAmGZr6L4ZM6jPPTnK+ ZEEQ== X-Forwarded-Encrypted: i=1; AJvYcCXAyb37UL0rM1vczi6c/PP4M7w3kVVL8JLvZUl6uhBN5SBq+bAicVO9AKtkU01Vk6BHcGodE2v21zYX@nongnu.org X-Gm-Message-State: AOJu0Yx+DoiKBmvt96hk/6ymytIZUPi4PZ2kmSH1mNvl+kSp4bSAeWb+ mpZWzxdL07WXNM0ck17xZ8GYWkTm3mGv3mITR8bz2/dQULEEY5xgcxkPP8tzYSP8PNo= X-Gm-Gg: AY/fxX5kUI+y1VbHS7646yNN1ETBf5gJ8DSRTZtpjfrDGKmFVahKyG3xNx2gsn6KyMF KqJkmbFooqkYwovV/PqWTA63/ZfAmktGIE5IGE4IDzqh8zj61GsbLZsz1tJ9F2aWjlXsbHZArC0 0ix6wJ4g+xD+Y2hgkPXwc+BohiHHZsmazs+R3zBo7YI2BAdvK3wp4s/y7w1q7NYY+8DoQdHolrJ qPXFbsnsNL42ohlQbOkZd3xCSSawuBv7eT31znKMfMXoI7Z2v87SpqNut4hhTcvkGUuQlN0tTV8 w/rEvdU2MNW0jzVf0GUqE12ZVFbNezfgq6lqMiihk3HDcVGFRB4XC4KZqMRsL8vWPSdDYXESMtI mBIE7eBJB/4M66wAQLv9V9BscXyza1O8ujGJCCZNY7hHJLMjrsk4cjkEWX4sVOvEAqYCGL+1zgt rWQUkFGKYbKeHCzR/zPndAZF0+lVOGVpjlVwZG X-Google-Smtp-Source: AGHT+IHP/CHaRo7H+0csiHOeg8Q6+thQPPb3KS9NvrIyn+Ljb/gif9eBSdfHsMGbjBJo8TJnYf1ScQ== X-Received: by 2002:a17:903:2342:b0:2a0:e5cd:80a1 with SMTP id d9443c01a7336-2a2f2a34fa1mr477949365ad.41.1767610796360; Mon, 05 Jan 2026 02:59:56 -0800 (PST) From: Kito Cheng To: qemu-riscv@nongnu.org, qemu-devel@nongnu.org Cc: palmer@dabbelt.com, alistair.francis@wdc.com, liwei1518@gmail.com, dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com, kito.cheng@gmail.com, Kito Cheng Subject: [PATCH 3/5] target/riscv: Add arch=ISA-STRING to configure extensions via ISA string Date: Mon, 5 Jan 2026 18:59:38 +0800 Message-ID: <20260105105940.3567112-4-kito.cheng@sifive.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260105105940.3567112-1-kito.cheng@sifive.com> References: <20260105105940.3567112-1-kito.cheng@sifive.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::631; envelope-from=kito.cheng@sifive.com; helo=mail-pl1-x631.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @sifive.com) X-ZM-MESSAGEID: 1767610829461154100 Content-Type: text/plain; charset="utf-8" Add support for configuring RISC-V ISA extensions using standard ISA strings with the arch=3D property. The format is: rv{32|64}[single-letter-exts][_multi-letter-ext]* Examples: -cpu rv64,arch=3Drv64gc_zba_zbb -cpu rv64,arch=3Drv64imafdc_zba_zbb_zbc -cpu rv32,arch=3Drv32gc Key features: - First extension after rv{32|64} must be 'i', 'e', or 'g' (base ISA) - Single-letter extensions can be concatenated (rv64imafdc) - Single-letter extensions can also use underscore separators (rv64i_m_a_f_d_c) - Multi-letter extensions are separated by underscores (_zba_zbb) - Single-letter extensions can transition directly to multi-letter (rv64imazba is equivalent to rv64ima_zba) - Extensions i, e, g can only appear as the first extension - When arch=3D is specified, all extensions are first reset to disabled, then only the specified extensions are enabled - G expands to imafd_zicsr_zifencei - B expands to zba_zbb_zbs - ISA string XLEN must match CPU type (rv32 for 32-bit, rv64 for 64-bit) Individual extension properties (e.g., zba=3Dtrue) can be combined with arch=3D and will override the ISA string settings when specified after arch=3D. Signed-off-by: Kito Cheng --- docs/system/target-riscv.rst | 48 ++++++ target/riscv/tcg/tcg-cpu.c | 187 +++++++++++++++++++++- tests/functional/riscv32/test_cpu_arch.py | 21 +++ tests/functional/riscv64/test_cpu_arch.py | 166 +++++++++++++++++++ 4 files changed, 418 insertions(+), 4 deletions(-) diff --git a/docs/system/target-riscv.rst b/docs/system/target-riscv.rst index 9acc51fbc2b..a16c17a22c2 100644 --- a/docs/system/target-riscv.rst +++ b/docs/system/target-riscv.rst @@ -119,6 +119,54 @@ extensions: $ qemu-riscv64 -cpu rv64,v=3Dtrue,arch=3Ddump /bin/true $ qemu-riscv64 -cpu rv64,arch=3Ddump,v=3Dtrue /bin/true =20 +* ``arch=3D`` + + Configure extensions using a standard RISC-V ISA string. The format is + ``rv{32|64}[single-letter-exts][_multi-letter-ext]*``. Examples:: + + $ qemu-riscv64 -cpu rv64,arch=3Drv64gc_zba_zbb /bin/true + $ qemu-riscv64 -cpu rv64,arch=3Drv64imafdc_zba_zbb_zbc /bin/true + + Single-letter extensions are specified immediately after the base ISA + (e.g., ``rv64gc`` enables G and C extensions). Multi-letter extensions + are separated by underscores. + + Special extensions: + + - ``g`` expands to ``imafd_zicsr_zifencei`` (General purpose) + + The ISA string must match the CPU's XLEN. For example, ``arch=3Drv32i`` = will + fail on a 64-bit CPU. + + **Important behavioral notes:** + + - When ``arch=3D`` is specified, all extensions are first re= set + to disabled, then only the extensions in the ISA string are enabled. + For example, ``-cpu rv64,zba=3Dtrue,arch=3Drv64gc`` will have ``zba`` = disabled + because ``arch=3D`` resets extensions before applying the ISA string. + + - Extensions can be specified in any order and can be repeated. For exam= ple, + ``rv64gc_zba_zbb`` and ``rv64gc_zbb_zba`` produce the same result. + + - Single-letter extensions can appear anywhere in the string separated by + underscores. For example, ``rv64im_zba_afc`` is equivalent to + ``rv64imafc_zba``. + + - The individual extension properties (e.g., ``zba=3Dtrue``) still work = and + can be combined with ``arch=3D``. Properties specified after ``arch=3D= `` will + override the ISA string settings:: + + $ qemu-riscv64 -cpu rv64,arch=3Drv64gc,zba=3Dtrue /bin/true + + - Some extensions are controlled by the privilege specification version + and cannot be enabled or disabled via ``arch=3D``. See the + "Privilege-implied extensions" section below for details. + + You can combine ``arch=3D`` with ``arch=3Ddump`` to verify t= he + configuration:: + + $ qemu-riscv64 -cpu rv64,arch=3Drv64gc_zba_zbb,arch=3Ddump /bin/true + Privilege-implied extensions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ =20 diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index c9600a52e1c..87f1a5c9c73 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -1552,8 +1552,182 @@ static void riscv_cpu_add_multiext_prop_array(Objec= t *obj, } =20 /* - * arch=3D property handler for ISA string configuration. - * This is a write-only property used to trigger actions like arch=3Ddump. + * Get MISA bit from single-letter extension name. + * Returns 0 if not found. + */ +static uint32_t riscv_get_misa_bit_from_name(char ext_char) +{ + for (int i =3D 0; misa_bits[i] !=3D 0; i++) { + uint32_t bit =3D misa_bits[i]; + const char *name =3D riscv_get_misa_ext_name(bit); + + if (name && name[0] =3D=3D ext_char && name[1] =3D=3D '\0') { + return bit; + } + } + return 0; +} + +/* + * Find multi-letter extension data by name. + * Returns NULL if not found. + */ +static const RISCVIsaExtData *riscv_find_ext_data(const char *name) +{ + for (const RISCVIsaExtData *edata =3D isa_edata_arr; edata->name; edat= a++) { + if (g_ascii_strcasecmp(edata->name, name) =3D=3D 0) { + return edata; + } + } + return NULL; +} + +/* + * Disable all ISA extensions to prepare for ISA string configuration. + */ +static void riscv_cpu_disable_all_extensions(RISCVCPU *cpu) +{ + /* Disable all MISA extensions */ + for (int i =3D 0; misa_bits[i] !=3D 0; i++) { + riscv_cpu_write_misa_bit(cpu, misa_bits[i], false); + } + + /* Disable all multi-letter extensions */ + for (const RISCVIsaExtData *edata =3D isa_edata_arr; edata->name; edat= a++) { + isa_ext_update_enabled(cpu, edata->ext_enable_offset, false); + } +} + +/* + * Parse ISA string and configure CPU extensions. + * Format: rv{32|64}[single-letter-exts][_multi-letter-ext]* + * Examples: rv64gc, rv64imafdc_zba_zbb, rv32i + * + * This first disables all extensions, then enables only those specified + * in the ISA string. + */ +static bool riscv_cpu_parse_isa_string(RISCVCPU *cpu, const char *isa_str, + Error **errp) +{ + RISCVCPUClass *mcc =3D RISCV_CPU_GET_CLASS(cpu); + int xlen =3D riscv_cpu_max_xlen(mcc); + const char *p =3D isa_str; + int expected_xlen; + + /* Parse rv32/rv64 prefix */ + if (g_ascii_strncasecmp(p, "rv32", 4) =3D=3D 0) { + expected_xlen =3D 32; + p +=3D 4; + } else if (g_ascii_strncasecmp(p, "rv64", 4) =3D=3D 0) { + expected_xlen =3D 64; + p +=3D 4; + } else { + error_setg(errp, "ISA string must start with rv32 or rv64"); + return false; + } + + /* Verify XLEN matches the CPU type */ + if (expected_xlen !=3D xlen) { + error_setg(errp, "ISA string specifies RV%d but CPU is RV%d", + expected_xlen, xlen); + return false; + } + + /* First extension must be i, e, or g */ + char first_ext =3D g_ascii_tolower(*p); + if (first_ext !=3D 'i' && first_ext !=3D 'e' && first_ext !=3D 'g') { + error_setg(errp, "first extension after rv%d must be 'i', 'e', or = 'g'", + expected_xlen); + return false; + } + + /* Disable all extensions first, then enable only those in ISA string = */ + riscv_cpu_disable_all_extensions(cpu); + + /* + * Parse extensions. Both single-letter and multi-letter extensions + * can be separated by underscores (e.g., rv64i_m_a_f_d_c_zba_zbb). + * Single-letter extensions can also be concatenated (e.g., rv64imafdc= ). + */ + bool is_first_ext =3D true; + while (*p) { + if (*p =3D=3D '_') { + p++; /* Skip underscore */ + if (*p =3D=3D '\0') { + break; /* Trailing underscore is ok */ + } + } + + /* Find the end of this extension name */ + const char *ext_start =3D p; + while (*p && *p !=3D '_') { + p++; + } + + /* Extract extension name */ + size_t ext_len =3D p - ext_start; + g_autofree char *ext_name =3D g_strndup(ext_start, ext_len); + + /* + * Parse single-letter extensions at the beginning of the group. + * Single-letter extensions can be followed directly by a multi-le= tter + * extension without underscore (e.g., "imazba" =3D "ima" + "zba"). + */ + size_t single_count =3D 0; + for (size_t i =3D 0; i < ext_len; i++) { + char c =3D g_ascii_tolower(ext_name[i]); + if (riscv_get_misa_bit_from_name(c) =3D=3D 0) { + break; + } + single_count++; + } + + /* Process single-letter extensions */ + for (size_t i =3D 0; i < single_count; i++) { + char ext_char =3D g_ascii_tolower(ext_name[i]); + + /* + * 'i', 'e', 'g' can only appear as the first extension. + * They define the base ISA and cannot be specified elsewhere. + */ + if (ext_char =3D=3D 'i' || ext_char =3D=3D 'e' || ext_char =3D= =3D 'g') { + if (!is_first_ext) { + error_setg(errp, "'%c' must be the first extension in = ISA " + "string", ext_char); + return false; + } + } + + uint32_t bit =3D riscv_get_misa_bit_from_name(ext_char); + riscv_cpu_write_misa_bit(cpu, bit, true); + is_first_ext =3D false; + } + + /* If entire group was single-letter extensions, we're done */ + if (single_count =3D=3D ext_len) { + continue; + } + + /* Process the remaining multi-letter extension */ + const char *multi_ext =3D ext_name + single_count; + + /* Look up the extension */ + const RISCVIsaExtData *edata =3D riscv_find_ext_data(multi_ext); + if (edata =3D=3D NULL) { + error_setg(errp, "unknown extension '%s' in ISA string", multi= _ext); + return false; + } + + /* Enable the extension */ + isa_ext_update_enabled(cpu, edata->ext_enable_offset, true); + } + + return true; +} + +/* + * arch=3D property handler for ISA configuration. + * Supports: dump, help, or an ISA string like rv64gc_zba_zbb. */ static void cpu_set_arch(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) @@ -1569,9 +1743,13 @@ static void cpu_set_arch(Object *obj, Visitor *v, co= nst char *name, cpu->cfg.arch_dump_requested =3D true; } else if (g_strcmp0(value, "help") =3D=3D 0) { riscv_cpu_list_supported_extensions(); + } else if (g_ascii_strncasecmp(value, "rv", 2) =3D=3D 0) { + /* Parse as ISA string */ + riscv_cpu_parse_isa_string(cpu, value, errp); } else { error_setg(errp, "unknown arch option '%s'. " - "Supported options: dump, help", value); + "Supported options: dump, help, or ISA string (e.g., " + "rv64gc_zba_zbb)", value); } } =20 @@ -1582,7 +1760,8 @@ static void riscv_cpu_add_arch_property(Object *obj) NULL, NULL); object_property_set_description(obj, "arch", "ISA configuration (write-only). " - "Use 'help' to list extensions, 'dump' to show current config."); + "Use 'help' to list extensions, 'dump' to show current config, " + "or provide an ISA string (e.g., rv64gc_zba_zbb)."); } =20 /* diff --git a/tests/functional/riscv32/test_cpu_arch.py b/tests/functional/r= iscv32/test_cpu_arch.py index b2042f1e5d8..f5526cd1e1b 100644 --- a/tests/functional/riscv32/test_cpu_arch.py +++ b/tests/functional/riscv32/test_cpu_arch.py @@ -68,6 +68,27 @@ def test_arch_invalid_option(self): self.assertIn("unknown arch option 'invalid'", res.stderr) self.assertIn("Supported options:", res.stderr) =20 + def test_arch_isa_string_basic(self): + """Test arch=3DISA-STRING enables specified extensions""" + res =3D self.run_qemu('rv32,arch=3Drv32gc_zba_zbb,arch=3Ddump') + + self.assertEqual(res.returncode, 0) + + # Check single-letter extensions from 'gc' + self.assertRegex(res.stdout, r'g\s+enabled') + self.assertRegex(res.stdout, r'c\s+enabled') + + # Check multi-letter extensions + self.assertRegex(res.stdout, r'zba\s+enabled') + self.assertRegex(res.stdout, r'zbb\s+enabled') + + def test_arch_isa_string_xlen_mismatch(self): + """Test arch=3DISA-STRING rejects XLEN mismatch""" + res =3D self.run_qemu('rv32,arch=3Drv64i') + + self.assertNotEqual(res.returncode, 0) + self.assertIn("RV64 but CPU is RV32", res.stderr) + =20 if __name__ =3D=3D '__main__': QemuUserTest.main() diff --git a/tests/functional/riscv64/test_cpu_arch.py b/tests/functional/r= iscv64/test_cpu_arch.py index 4ec807b7276..204247cdb73 100644 --- a/tests/functional/riscv64/test_cpu_arch.py +++ b/tests/functional/riscv64/test_cpu_arch.py @@ -100,6 +100,172 @@ def test_arch_invalid_option(self): self.assertIn("unknown arch option 'invalid'", res.stderr) self.assertIn("Supported options:", res.stderr) =20 + def test_arch_isa_string_basic(self): + """Test arch=3DISA-STRING enables specified extensions""" + res =3D self.run_qemu('rv64,arch=3Drv64gc_zba_zbb,arch=3Ddump') + + self.assertEqual(res.returncode, 0) + + # Check single-letter extensions from 'gc' (g =3D imafd_zicsr_zife= ncei) + self.assertRegex(res.stdout, r'g\s+enabled') + self.assertRegex(res.stdout, r'c\s+enabled') + + # Check multi-letter extensions + self.assertRegex(res.stdout, r'zba\s+enabled') + self.assertRegex(res.stdout, r'zbb\s+enabled') + + def test_arch_isa_string_g_expands(self): + """Test arch=3Drv64g enables IMAFD + Zicsr + Zifencei""" + res =3D self.run_qemu('rv64,arch=3Drv64g,arch=3Ddump') + + self.assertEqual(res.returncode, 0) + + # G expands to IMAFD_Zicsr_Zifencei + self.assertRegex(res.stdout, r'i\s+enabled') + self.assertRegex(res.stdout, r'm\s+enabled') + self.assertRegex(res.stdout, r'a\s+enabled') + self.assertRegex(res.stdout, r'f\s+enabled') + self.assertRegex(res.stdout, r'd\s+enabled') + self.assertRegex(res.stdout, r'zicsr\s+enabled') + self.assertRegex(res.stdout, r'zifencei\s+enabled') + + def test_arch_isa_string_b_expands(self): + """Test arch=3Drv64ib enables Zba + Zbb + Zbs""" + res =3D self.run_qemu('rv64,arch=3Drv64ib,arch=3Ddump') + + self.assertEqual(res.returncode, 0) + + # B expands to Zba_Zbb_Zbs + self.assertRegex(res.stdout, r'b\s+enabled') + + def test_arch_isa_string_flexible_order(self): + """Test extensions can be in any order""" + # Both should produce equivalent results + res1 =3D self.run_qemu('rv64,arch=3Drv64gc_zba_zbb,arch=3Ddump') + res2 =3D self.run_qemu('rv64,arch=3Drv64gc_zbb_zba,arch=3Ddump') + + self.assertEqual(res1.returncode, 0) + self.assertEqual(res2.returncode, 0) + self.assertRegex(res1.stdout, r'zba\s+enabled') + self.assertRegex(res1.stdout, r'zbb\s+enabled') + self.assertRegex(res2.stdout, r'zba\s+enabled') + self.assertRegex(res2.stdout, r'zbb\s+enabled') + + def test_arch_isa_string_mixed_single_multi(self): + """Test single-letter extensions can appear after underscores""" + # rv64im_zba_afc should be equivalent to rv64imafc_zba + res =3D self.run_qemu('rv64,arch=3Drv64im_zba_afc,arch=3Ddump') + + self.assertEqual(res.returncode, 0) + self.assertRegex(res.stdout, r'\bi\s+enabled') + self.assertRegex(res.stdout, r'm\s+enabled') + self.assertRegex(res.stdout, r'a\s+enabled') + self.assertRegex(res.stdout, r'f\s+enabled') + self.assertRegex(res.stdout, r'c\s+enabled') + self.assertRegex(res.stdout, r'zba\s+enabled') + + def test_arch_isa_string_no_underscore_before_multi(self): + """Test multi-letter extension can follow single-letter directly""" + # rv64imazba should be equivalent to rv64ima_zba + res1 =3D self.run_qemu('rv64,arch=3Drv64imazba,arch=3Ddump') + res2 =3D self.run_qemu('rv64,arch=3Drv64ima_zba,arch=3Ddump') + + self.assertEqual(res1.returncode, 0) + self.assertEqual(res2.returncode, 0) + + # Both should have ima and zba enabled + for res in [res1, res2]: + self.assertRegex(res.stdout, r'\bi\s+enabled') + self.assertRegex(res.stdout, r'm\s+enabled') + self.assertRegex(res.stdout, r'a\s+enabled') + self.assertRegex(res.stdout, r'zba\s+enabled') + + def test_arch_isa_string_repeated_extension(self): + """Test extensions can be repeated""" + res =3D self.run_qemu('rv64,arch=3Drv64gc_zba_zba,arch=3Ddump') + + self.assertEqual(res.returncode, 0) + self.assertRegex(res.stdout, r'zba\s+enabled') + + def test_arch_isa_string_resets_extensions(self): + """Test arch=3D resets all extensions first""" + # zba=3Dtrue before arch=3D should be reset + res =3D self.run_qemu('rv64,zba=3Dtrue,arch=3Drv64gc,arch=3Ddump') + + self.assertEqual(res.returncode, 0) + self.assertRegex(res.stdout, r'zba\s+disabled') + + def test_arch_combined_with_property(self): + """Test arch=3D can be combined with individual properties""" + # arch=3Drv64gc,zba=3Dtrue should enable zba + res =3D self.run_qemu('rv64,arch=3Drv64gc,zba=3Dtrue,arch=3Ddump') + + self.assertEqual(res.returncode, 0) + self.assertRegex(res.stdout, r'zba\s+enabled') + + def test_arch_isa_string_xlen_mismatch(self): + """Test arch=3DISA-STRING rejects XLEN mismatch""" + res =3D self.run_qemu('rv64,arch=3Drv32i') + + self.assertNotEqual(res.returncode, 0) + self.assertIn("RV32 but CPU is RV64", res.stderr) + + def test_arch_isa_string_unknown_extension(self): + """Test arch=3DISA-STRING rejects unknown extension""" + # Unknown extension after valid single-letters (ix -> i + x) + res =3D self.run_qemu('rv64,arch=3Drv64ix') + + self.assertNotEqual(res.returncode, 0) + self.assertIn("unknown extension 'x'", res.stderr) + + # Unknown multi-letter extension after underscore + res =3D self.run_qemu('rv64,arch=3Drv64i_xyzfoo') + + self.assertNotEqual(res.returncode, 0) + self.assertIn("unknown extension 'xyzfoo'", res.stderr) + + def test_arch_isa_string_first_ext_validation(self): + """Test arch=3DISA-STRING requires first extension to be i, e, or = g""" + # First extension must be i, e, or g + res =3D self.run_qemu('rv64,arch=3Drv64m') + + self.assertNotEqual(res.returncode, 0) + self.assertIn("first extension after rv64 must be 'i', 'e', or 'g'= ", + res.stderr) + + def test_arch_isa_string_base_ext_only_first(self): + """Test i, e, g can only appear as the first extension""" + # 'e' cannot appear after other extensions + res =3D self.run_qemu('rv64,arch=3Drv64imae') + + self.assertNotEqual(res.returncode, 0) + self.assertIn("'e' must be the first extension", res.stderr) + + # 'g' cannot appear after 'i' + res =3D self.run_qemu('rv64,arch=3Drv64ig') + + self.assertNotEqual(res.returncode, 0) + self.assertIn("'g' must be the first extension", res.stderr) + + # 'i' cannot appear after underscore + res =3D self.run_qemu('rv64,arch=3Drv64g_i') + + self.assertNotEqual(res.returncode, 0) + self.assertIn("'i' must be the first extension", res.stderr) + + def test_arch_isa_string_underscore_separated_single(self): + """Test single-letter extensions can be separated by underscores""" + # rv64i_m_a_f_d_c should be equivalent to rv64imafdc + res =3D self.run_qemu('rv64,arch=3Drv64i_m_a_f_d_c,arch=3Ddump') + + self.assertEqual(res.returncode, 0) + self.assertRegex(res.stdout, r'\bi\s+enabled') + self.assertRegex(res.stdout, r'm\s+enabled') + self.assertRegex(res.stdout, r'a\s+enabled') + self.assertRegex(res.stdout, r'f\s+enabled') + self.assertRegex(res.stdout, r'd\s+enabled') + self.assertRegex(res.stdout, r'c\s+enabled') + =20 if __name__ =3D=3D '__main__': QemuUserTest.main() --=20 2.52.0 From nobody Mon Feb 9 17:07:27 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=reject dis=none) header.from=sifive.com ARC-Seal: i=1; a=rsa-sha256; t=1767610857; cv=none; d=zohomail.com; s=zohoarc; b=Vog9loZ0qXmJti4/5JLWLFXMzolTPZEHPqp8Tf6fflneB1en9c3/6iFkt/HAgLWbv3tQpXgZcu+JLiUEWj6z1+BYFqn5XpYklKOPU0dMquuB3NvKF/6Ng6FkEChnnmrqfy6eRBa6INYtFQRPY6UR7luH0fu8o2zejC9tYg7O/00= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1767610857; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=ItC8uyuV9MEuPPK+zE/fnv1fLQkursu/U/pJyg29yX0=; b=DunENotutK3gKIAsK+6cULjr5nU8vJONNxKSbIrbDa0RagT9hnm+JlWLRXjZs+UjetbcNitM04sJsj2awUCgZpHK2HFDJ//A1dQedjge7pkxJ7z4fPgsqbkVYoSAn99VRjLXd//qnoPS6wI7PTii99N+XI/e2rngaAEANf6bDKA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1767610854500470.5325295782884; Mon, 5 Jan 2026 03:00:54 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vciJn-00012H-2h; Mon, 05 Jan 2026 06:00:11 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vciJe-0000yA-8M for qemu-devel@nongnu.org; Mon, 05 Jan 2026 06:00:02 -0500 Received: from mail-pl1-x62f.google.com ([2607:f8b0:4864:20::62f]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1vciJb-0001og-Mc for qemu-devel@nongnu.org; Mon, 05 Jan 2026 06:00:01 -0500 Received: by mail-pl1-x62f.google.com with SMTP id d9443c01a7336-2a0833b5aeeso187801545ad.1 for ; Mon, 05 Jan 2026 02:59:59 -0800 (PST) Received: from hsinchu18.internal.sifive.com ([210.176.154.34]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2a2f3c6661esm440193975ad.2.2026.01.05.02.59.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 05 Jan 2026 02:59:58 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sifive.com; s=google; t=1767610798; x=1768215598; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=ItC8uyuV9MEuPPK+zE/fnv1fLQkursu/U/pJyg29yX0=; b=f/1mQs60mavIxsOsOeap9l7PetIlTSCW2EQ1UobsIsZ8WvaX/WZqqshyGzpMCq7i/d BEGvISzmjWIvHGHzKUInipnbVCgBi5zFz+9XqV3hOgbZ8puIywL+XvXq94T7y7EQ3yIJ aQwX6LZuE6DLHY6btcwtruSXUc1t+FlMZN0/a4hyL/o2Ljvppv2tSKwXEa188q62gQXS /Agt7FqXXI0Ib6qUv+4fa8qApqiRCrP8vPI/EBsHcPHR5iMhlGjKwsWyegZhUTKV3Q0E S6RyFu2nVrTHauHSXR7uqQk3Vr1n6B3YcsYjmq+Sa7vh0HLYvb0BwH1Mh2AK0Ijz17p7 x+mg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767610798; x=1768215598; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=ItC8uyuV9MEuPPK+zE/fnv1fLQkursu/U/pJyg29yX0=; b=kL+hY8owmzDai07uyeFcRNH19YH+BCFHOz3iSNIs6z4cJ3hkCokjdtua3Rz87+4Q7u rzTRX6fXyhe39rZMtFt9kP2ZM7C+cRXrhPIRRD+1YKq9+FqBhwAF79BfkEQ143yaTMc9 VgoB1hSUFrKG6ZbLg2/IQBzsxV6eIwreu6AifpPhdiK20hEuPIBwxnLvs33ouO/ut9/b /JkDCqRsZPE5WPmoh7QPA3YI47GHkLdGq0/eAqjQGw3t4AxZVusqwjV/gGd9T5sxrORH l+GQQK95AekayYT1uTzDAySxaklsdy/SyZc+coCY/ESn0wFJ4E2LGRYGSrImX4WpRtTY 0g4w== X-Forwarded-Encrypted: i=1; AJvYcCUqHKydlJybUI4q39Jtcudy7vFrbbhkxsusyTwXt6yvE2u3jOzrcrGGMFdSP6VqXEA19RJmmXxnsolh@nongnu.org X-Gm-Message-State: AOJu0YyxH3keqGfBgKkZWQESrha5EYp1rydsSSrrNeZcyiQCaIkDwR42 vZjuvQ1mc4+wn4q73Kskl1vtCjWRZw92GDg6CA8usZ8xm5mLTJTWuEljbFHqk3BY4EA= X-Gm-Gg: AY/fxX6c1ag/9NneK/fvRr7JyOniiXEsKno+GTZcFWv1gOBhTngcFXB3OGT+jhONFG5 hQKGWAdEJHg8QiEV6MsUkd9M30b6vXHBYll5W0/p2cvsErvvecM+4QYtzuXDTMTuOahtFQZDOhH t2/eZE4hFUKJqHuuARN7l9iExpE9JXbV228ks3aRFvMdQup7wSxG+HKNygB3XDttdQEMoFIedfB aAb72RFX+PfBa6xcOOTmV6HWb44mNcJ39e22RErDOQZ9TTTsQRt9QwAml58epJGp6KYWzF7Gnfh LA6PlMj2o2+6xOBUXrGMB0HXtFQ9gf2J5zMzZ155wjio+hVvHpTpUopPThn6HoDQ01XFA+tp/rK wSnk9RRegt//ZWr+DsgEczvMjQioWHJvnr6vVt9gEDyDgwc11CRayhQSAFsTWrJ1beJvtcBOlT5 rSVNb989I/IMJd8gMwK0zu+vvSk1agYYW6WzmM1t3ybOQ87BQ= X-Google-Smtp-Source: AGHT+IH2dAOgb7q5OjCkQW0AFKUJuQJSmLdQx7ODCszegrKc/2QxebCubAWcPbTE9NXD5UL9YKwchA== X-Received: by 2002:a17:903:b90:b0:29f:301a:f6da with SMTP id d9443c01a7336-2a2f2a34f54mr488443665ad.43.1767610798421; Mon, 05 Jan 2026 02:59:58 -0800 (PST) From: Kito Cheng To: qemu-riscv@nongnu.org, qemu-devel@nongnu.org Cc: palmer@dabbelt.com, alistair.francis@wdc.com, liwei1518@gmail.com, dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com, kito.cheng@gmail.com, Kito Cheng Subject: [PATCH 4/5] target/riscv: Add arch=PROFILE to configure CPU using RISC-V profiles Date: Mon, 5 Jan 2026 18:59:39 +0800 Message-ID: <20260105105940.3567112-5-kito.cheng@sifive.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260105105940.3567112-1-kito.cheng@sifive.com> References: <20260105105940.3567112-1-kito.cheng@sifive.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::62f; envelope-from=kito.cheng@sifive.com; helo=mail-pl1-x62f.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @sifive.com) X-ZM-MESSAGEID: 1767610864118154100 Content-Type: text/plain; charset="utf-8" Add support for configuring RISC-V CPUs using standard RISC-V profiles with the arch=3D property. The format is: arch=3D[_extension]* Examples: -cpu rv64,arch=3Drva23u64 -cpu rv64,arch=3Drva22s64 -cpu rv64,arch=3Drva23u64_zbkb_zkne Key features: - Profiles are detected by prefix matching (case-insensitive) - Additional extensions can be appended after the profile name - Profiles are only available for 64-bit CPUs Available profiles: - rva22u64 - RVA22 User-mode profile - rva22s64 - RVA22 Supervisor-mode profile - rva23u64 - RVA23 User-mode profile (includes mandatory vector) - rva23s64 - RVA23 Supervisor-mode profile Profiles automatically enable all mandatory extensions defined by the RISC-V profile specification. Additional extensions can be appended after the profile name using underscores (following the RISC-V toolchain convention). The arch=3Dhelp command now lists available profiles in addition to extensions. Signed-off-by: Kito Cheng --- docs/system/target-riscv.rst | 24 +++++ target/riscv/cpu.c | 8 ++ target/riscv/tcg/tcg-cpu.c | 103 +++++++++++++++++++++- tests/functional/riscv64/test_cpu_arch.py | 72 +++++++++++++++ 4 files changed, 203 insertions(+), 4 deletions(-) diff --git a/docs/system/target-riscv.rst b/docs/system/target-riscv.rst index a16c17a22c2..12807974a8a 100644 --- a/docs/system/target-riscv.rst +++ b/docs/system/target-riscv.rst @@ -167,6 +167,30 @@ extensions: =20 $ qemu-riscv64 -cpu rv64,arch=3Drv64gc_zba_zbb,arch=3Ddump /bin/true =20 +* ``arch=3D[_extension]*`` + + Configure the CPU using a standard RISC-V profile, optionally with addit= ional + extensions. Profiles define sets of mandatory extensions for specific use + cases. Available profiles (64-bit only): + + - ``rva22u64`` - RVA22 User-mode profile + - ``rva22s64`` - RVA22 Supervisor-mode profile + - ``rva23u64`` - RVA23 User-mode profile (includes mandatory vector) + - ``rva23s64`` - RVA23 Supervisor-mode profile + + Examples:: + + $ qemu-riscv64 -cpu rv64,arch=3Drva23u64 /bin/true + $ qemu-riscv64 -cpu rv64,arch=3Drva22s64,arch=3Ddump /bin/true + $ qemu-riscv64 -cpu rv64,arch=3Drva23u64_zbkb_zkne /bin/true + + Profiles automatically enable all mandatory extensions defined by the RI= SC-V + profile specification. For example, RVA23 profiles enable the vector ext= ension + (V) which was optional in RVA22. Additional extensions can be appended a= fter + the profile name using underscores (following the RISC-V toolchain conve= ntion). + + Use ``arch=3Dhelp`` to see all available profiles. + Privilege-implied extensions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ =20 diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index b1d8438cd14..092635b1050 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1028,7 +1028,15 @@ G_NORETURN void riscv_cpu_list_supported_extensions(= void) riscv_cpu_help_multiext("Experimental Extensions", riscv_cpu_experimental_exts); =20 + /* Print available profiles */ + qemu_printf("Profiles (64-bit only):\n"); + for (int i =3D 0; riscv_profiles[i] !=3D NULL; i++) { + qemu_printf(" %s\n", riscv_profiles[i]->name); + } + qemu_printf("\n"); + qemu_printf("Use '-cpu ,=3Dtrue' to enable an extension.\n"); + qemu_printf("Use '-cpu ,arch=3D' to enable a profile.\n"= ); qemu_printf("Use '-cpu ,arch=3Ddump' to show current configuratio= n.\n"); =20 exit(0); diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 87f1a5c9c73..aa947337cf1 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -1725,9 +1725,99 @@ static bool riscv_cpu_parse_isa_string(RISCVCPU *cpu= , const char *isa_str, return true; } =20 +/* + * Find a profile by prefix (case-insensitive). + * The profile name must be followed by end of string or underscore. + * Returns the profile and sets *end_ptr to point after the profile name. + */ +static RISCVCPUProfile *riscv_find_profile_by_prefix(const char *str, + const char **end_ptr) +{ + for (int i =3D 0; riscv_profiles[i] !=3D NULL; i++) { + size_t len =3D strlen(riscv_profiles[i]->name); + if (g_ascii_strncasecmp(str, riscv_profiles[i]->name, len) =3D=3D = 0) { + char next_char =3D str[len]; + if (next_char =3D=3D '\0' || next_char =3D=3D '_') { + if (end_ptr) { + *end_ptr =3D str + len; + } + return riscv_profiles[i]; + } + } + } + return NULL; +} + +/* + * Parse profile string with optional extensions. + * Format: [_]* + * Examples: rva23u64, rva23u64_zbkb_zkne + */ +static bool riscv_cpu_parse_profile_string(RISCVCPU *cpu, const char *str, + Error **errp) +{ + const char *p; + RISCVCPUProfile *profile; + + profile =3D riscv_find_profile_by_prefix(str, &p); + if (profile =3D=3D NULL) { + error_setg(errp, "unknown profile in '%s'", str); + return false; + } + + /* Check CPU compatibility */ + if (riscv_cpu_is_vendor(OBJECT(cpu))) { + error_setg(errp, "Profile %s is not available for vendor CPUs", + profile->name); + return false; + } + if (riscv_cpu_is_32bit(cpu)) { + error_setg(errp, "Profile %s is only available for 64-bit CPUs", + profile->name); + return false; + } + + /* Enable the profile */ + profile->user_set =3D true; + riscv_cpu_set_profile(cpu, profile, true); + + /* Parse additional extensions after the profile name */ + while (*p =3D=3D '_') { + p++; /* Skip underscore */ + + if (*p =3D=3D '\0') { + break; /* Trailing underscore is ok */ + } + + /* Find the end of this extension name */ + const char *ext_start =3D p; + while (*p && *p !=3D '_') { + p++; + } + + /* Extract extension name */ + size_t ext_len =3D p - ext_start; + g_autofree char *ext_name =3D g_strndup(ext_start, ext_len); + + /* Look up the extension */ + const RISCVIsaExtData *edata =3D riscv_find_ext_data(ext_name); + if (edata =3D=3D NULL) { + error_setg(errp, "unknown extension '%s' in profile string", + ext_name); + return false; + } + + /* Enable the extension */ + isa_ext_update_enabled(cpu, edata->ext_enable_offset, true); + } + + return true; +} + /* * arch=3D property handler for ISA configuration. - * Supports: dump, help, or an ISA string like rv64gc_zba_zbb. + * Supports: dump, help, ISA string (rv64gc_zba_zbb), + * or profile with optional extensions (rva23u64, rva23u64_zbkb_zkne). */ static void cpu_set_arch(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) @@ -1743,13 +1833,17 @@ static void cpu_set_arch(Object *obj, Visitor *v, c= onst char *name, cpu->cfg.arch_dump_requested =3D true; } else if (g_strcmp0(value, "help") =3D=3D 0) { riscv_cpu_list_supported_extensions(); + } else if (riscv_find_profile_by_prefix(value, NULL) !=3D NULL) { + /* Parse as profile with optional extensions */ + riscv_cpu_parse_profile_string(cpu, value, errp); } else if (g_ascii_strncasecmp(value, "rv", 2) =3D=3D 0) { /* Parse as ISA string */ riscv_cpu_parse_isa_string(cpu, value, errp); } else { error_setg(errp, "unknown arch option '%s'. " - "Supported options: dump, help, or ISA string (e.g., " - "rv64gc_zba_zbb)", value); + "Supported options: dump, help, ISA string (e.g., " + "rv64gc_zba_zbb), or profile (e.g., rva23u64, " + "rva23u64_zbkb)", value); } } =20 @@ -1761,7 +1855,8 @@ static void riscv_cpu_add_arch_property(Object *obj) object_property_set_description(obj, "arch", "ISA configuration (write-only). " "Use 'help' to list extensions, 'dump' to show current config, " - "or provide an ISA string (e.g., rv64gc_zba_zbb)."); + "provide an ISA string (e.g., rv64gc_zba_zbb), " + "or use a profile (e.g., rva23u64)."); } =20 /* diff --git a/tests/functional/riscv64/test_cpu_arch.py b/tests/functional/r= iscv64/test_cpu_arch.py index 204247cdb73..c12e1c7fce4 100644 --- a/tests/functional/riscv64/test_cpu_arch.py +++ b/tests/functional/riscv64/test_cpu_arch.py @@ -266,6 +266,78 @@ def test_arch_isa_string_underscore_separated_single(s= elf): self.assertRegex(res.stdout, r'd\s+enabled') self.assertRegex(res.stdout, r'c\s+enabled') =20 + def test_arch_profile_rva23u64(self): + """Test arch=3Drva23u64 enables RVA23 profile extensions""" + res =3D self.run_qemu('rv64,arch=3Drva23u64,arch=3Ddump') + + self.assertEqual(res.returncode, 0) + + # RVA23U64 mandates vector extension + self.assertRegex(res.stdout, r'\bv\s+enabled') + + # RVA23U64 mandates these extensions + self.assertRegex(res.stdout, r'zicond\s+enabled') + self.assertRegex(res.stdout, r'zimop\s+enabled') + self.assertRegex(res.stdout, r'zcmop\s+enabled') + self.assertRegex(res.stdout, r'zcb\s+enabled') + self.assertRegex(res.stdout, r'zfa\s+enabled') + self.assertRegex(res.stdout, r'zvbb\s+enabled') + + def test_arch_profile_rva22u64(self): + """Test arch=3Drva22u64 enables RVA22 profile extensions""" + res =3D self.run_qemu('rv64,arch=3Drva22u64,arch=3Ddump') + + self.assertEqual(res.returncode, 0) + + # RVA22U64 mandates these MISA extensions + self.assertRegex(res.stdout, r'\bi\s+enabled') + self.assertRegex(res.stdout, r'm\s+enabled') + self.assertRegex(res.stdout, r'a\s+enabled') + self.assertRegex(res.stdout, r'f\s+enabled') + self.assertRegex(res.stdout, r'd\s+enabled') + self.assertRegex(res.stdout, r'c\s+enabled') + + # RVA22U64 mandates zicsr and zifencei + self.assertRegex(res.stdout, r'zicsr\s+enabled') + self.assertRegex(res.stdout, r'zifencei\s+enabled') + + def test_arch_profile_case_insensitive(self): + """Test arch=3DPROFILE is case-insensitive""" + res =3D self.run_qemu('rv64,arch=3DRVA23U64,arch=3Ddump') + + self.assertEqual(res.returncode, 0) + # Should enable vector like lowercase version + self.assertRegex(res.stdout, r'\bv\s+enabled') + + def test_arch_help_shows_profiles(self): + """Test arch=3Dhelp lists available profiles""" + res =3D self.run_qemu('rv64,arch=3Dhelp') + + self.assertEqual(res.returncode, 0) + self.assertIn('Profiles', res.stdout) + self.assertIn('rva22u64', res.stdout) + self.assertIn('rva22s64', res.stdout) + self.assertIn('rva23u64', res.stdout) + self.assertIn('rva23s64', res.stdout) + + def test_arch_profile_with_extensions(self): + """Test arch=3DPROFILE_EXT enables profile plus additional extensi= ons""" + res =3D self.run_qemu('rv64,arch=3Drva23u64_zbkb_zkne,arch=3Ddump') + + self.assertEqual(res.returncode, 0) + # Profile extensions should be enabled + self.assertRegex(res.stdout, r'\bv\s+enabled') + # Additional extensions should also be enabled + self.assertRegex(res.stdout, r'zbkb\s+enabled') + self.assertRegex(res.stdout, r'zkne\s+enabled') + + def test_arch_profile_with_unknown_extension(self): + """Test arch=3DPROFILE_EXT rejects unknown extensions""" + res =3D self.run_qemu('rv64,arch=3Drva23u64_unknown') + + self.assertNotEqual(res.returncode, 0) + self.assertIn("unknown extension 'unknown'", res.stderr) + =20 if __name__ =3D=3D '__main__': QemuUserTest.main() --=20 2.52.0 From nobody Mon Feb 9 17:07:27 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=reject dis=none) header.from=sifive.com ARC-Seal: i=1; a=rsa-sha256; t=1767610932; cv=none; d=zohomail.com; s=zohoarc; b=JzdhtiYikFT3ePw2eXaKdQPGaHo/NPPzACOkIVyCyUihVHO+IpN1QckUd5FZyCzs5Fcwz+CRxCqeVQ72E7GhK7ye76uh7X/jCDb6hPA56rg4irXG5Fi68qvksw/4guk1Rbtmcflj179YkCGRe8uZl/ox8xgRAB9Zrl6lNbjPo/Q= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1767610932; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=sgFnjjxok3hH0hllst2R9+ZDtEpVszUSR75AJx8qMMQ=; b=kbaXSn0UiXQEjisEhwHWsOq50Ng0FYqafn9i2FF7bq7Ef09xg9LxZAdCUzOzTMRj5VSWlK99ZZv3bhsCT5bSDAwbEFOY9ZuEZ9FS1RH47NYRv0xPkK1aJ7QXXoTjum2Ts8ipR93jc8YPsR0fG+8C3f4197eI5k5vt/0e6nWWJtI= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1767610932547541.0289174760795; Mon, 5 Jan 2026 03:02:12 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vciJm-000126-EA; Mon, 05 Jan 2026 06:00:10 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vciJg-0000zy-PX for qemu-devel@nongnu.org; Mon, 05 Jan 2026 06:00:06 -0500 Received: from mail-pl1-x62e.google.com ([2607:f8b0:4864:20::62e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1vciJe-0001pJ-4d for qemu-devel@nongnu.org; Mon, 05 Jan 2026 06:00:04 -0500 Received: by mail-pl1-x62e.google.com with SMTP id d9443c01a7336-2a110548cdeso186111205ad.0 for ; Mon, 05 Jan 2026 03:00:01 -0800 (PST) Received: from hsinchu18.internal.sifive.com ([210.176.154.34]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2a2f3c6661esm440193975ad.2.2026.01.05.02.59.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 05 Jan 2026 03:00:00 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sifive.com; s=google; t=1767610800; x=1768215600; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=sgFnjjxok3hH0hllst2R9+ZDtEpVszUSR75AJx8qMMQ=; b=lVE8XA8HqH1nPkWGXirPzoEdNA3xWKa/umiBR+n7VL0x+iEQu4a8fNiaAcIpxdHOxp y1frWu/9XpaP8UXIbt3V1//ldXQHt9VkOAtltYMJ9GKuD+bkNFXTrjyXSo3JsQWNZRmy fADzMZAKs2JtWoLEmPXYXCeh7YeqEvCFexTTYXsTDuMyoPXPPfi86bobmh9f391J7SB9 PQcjlYCkEDKrnoqtekiwKuirbCcEoFZ9kODiLMxSe3ZkCeL0LvcUsPAMQKplzJ1bOVb/ mEl5cqGhR9HF+EhF7Pu1Wf3WygeWVQ0aB/PV9javgMihozfyT4Wp0xpg36gEOAxtbepj c2MA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767610800; x=1768215600; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=sgFnjjxok3hH0hllst2R9+ZDtEpVszUSR75AJx8qMMQ=; b=Do8rfradJ6mB7GzaHI2eJB3TlwSBWZ3Id7MHa0I5tlGdBAVl1CulMu0oWQE5l9Z0EL HDSdRSJRD34tfzOpU9HuN1qpisSUh6a3OuJIRaA0Bh74G9+xL2oX8dq1CtCzqS75g6Va ZECNwO31aUANp5RhWAnOQjwZXhNstQyfRikH+lWnVyG8j1DT0bRvBARmEsROFla3cs6M fRyqjOqHnnRHct0T0NfcNYbplBF3UyuvHts3YHUjsKC98sVHYj/CO2ORk93dgFHhOYl+ R+rdrMbeKSYKXzbPz+QwWKtN5MVXkeKLi4EEDPN/P+cUuzllbOEsGDZATY0vhHU66Hz6 7LZg== X-Forwarded-Encrypted: i=1; AJvYcCXnM5Yp0+IMm6xEex6EZ2Dv3d0TXjhxf3fXdPA0EGPT6J1VunXFjuQdtfQ3/StZjAuKerVIKf6vvSbw@nongnu.org X-Gm-Message-State: AOJu0YybprL0eL30aZ6lEDT9rCgYhk6kRL2pGhwghX/7QlSetoc8MNma IePbqQNFqEsU75HeO58Sl461IQztqAksPuCJAqd3fPex9VNaF96xk+KB2HgSbNrTP3o= X-Gm-Gg: AY/fxX7sXBtQtVK3J6QdARN+nJOAnHR63gZYcnLJV6UEV8xU5KezCvOMPQqoB/tR6WF vJuf76aMKDWACOeNRhnmWcY0mLc50pcQUqRkghMAwm22WRWsgfMxVLtgKSU3bYfU9RGG15Hx9v+ rQGKfF+MBD8lm0NHYCpVL4swGGo7t81ZGx9vHPZV33Yg86IGdu1uyZuD8YJ+JmmpBlOxsOtPaN0 HXxc/8lnuSRZw0YWPOeaKgj9mO6cC2PnJpmh/HWbl3YTqMIVX0ef3OZ4PB9E4vb2kvAkFt/hwuf cYSoFJaTq6WOpoyVpD+CIi9qmomw3+/uEkExacg4TIpDJMxJQjtrI2N86t2zibAHH1BqbN1wTvK pIVt4MjKVMOHm9cSpfOKVvif5OUXfPkM+d4d4x9ngSZVZZ7LCslJWxu99N2x243ZYToRDCsnfUP ciN7oGJS1Zrd9KvmGcOF4fTrrxEeHCWAl8q5TV X-Google-Smtp-Source: AGHT+IGsQ7LNRPCLuIwd7jmcSpBo5gTc4t4rb6kI4JkaygDS6k6VQwEEw3rj75zwGdTBVWyN/VvqiA== X-Received: by 2002:a17:902:f54f:b0:29d:584e:6349 with SMTP id d9443c01a7336-2a2f2231accmr544763805ad.13.1767610800485; Mon, 05 Jan 2026 03:00:00 -0800 (PST) From: Kito Cheng To: qemu-riscv@nongnu.org, qemu-devel@nongnu.org Cc: palmer@dabbelt.com, alistair.francis@wdc.com, liwei1518@gmail.com, dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com, kito.cheng@gmail.com, Kito Cheng Subject: [PATCH 5/5] target/riscv: Add zvl*b extension support in arch= property Date: Mon, 5 Jan 2026 18:59:40 +0800 Message-ID: <20260105105940.3567112-6-kito.cheng@sifive.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260105105940.3567112-1-kito.cheng@sifive.com> References: <20260105105940.3567112-1-kito.cheng@sifive.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::62e; envelope-from=kito.cheng@sifive.com; helo=mail-pl1-x62e.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @sifive.com) X-ZM-MESSAGEID: 1767610935045154100 Content-Type: text/plain; charset="utf-8" Add support for specifying vector length (VLEN) using zvl*b extensions in the arch=3D property. This allows explicit VLEN configuration when using ISA strings or profiles. Examples: -cpu rv64,arch=3Drv64gcv_zvl256b # V with VLEN=3D256 -cpu rv64,arch=3Drv64i_zve64f_zvl128b # Zve64f with VLEN=3D128 -cpu rv64,arch=3Drva23u64_zvl512b # RVA23 profile with VLEN=3D512 Key features: - zvlb where N is VLEN in bits (must be power of 2, 32-65536) - Valid extensions: zvl32b, zvl64b, zvl128b, zvl256b, zvl512b, etc. - zvl*b requires v or zve* extension to also be specified - Multiple zvl*b extensions take the maximum value - Extensions imply minimum VLEN: v implies 128, zve64* implies 64, zve32* implies 32 The arch=3Ddump output now shows: - Vector length configuration (VLEN=3DN bits) - zvlb in the full ISA string The arch=3Dhelp output now lists available zvl*b extensions with documentation. Signed-off-by: Kito Cheng --- docs/system/target-riscv.rst | 2 + target/riscv/cpu.c | 23 ++++- target/riscv/tcg/tcg-cpu.c | 116 +++++++++++++++++++++- tests/functional/riscv64/test_cpu_arch.py | 68 +++++++++++++ 4 files changed, 207 insertions(+), 2 deletions(-) diff --git a/docs/system/target-riscv.rst b/docs/system/target-riscv.rst index 12807974a8a..6734c86848a 100644 --- a/docs/system/target-riscv.rst +++ b/docs/system/target-riscv.rst @@ -134,6 +134,8 @@ extensions: Special extensions: =20 - ``g`` expands to ``imafd_zicsr_zifencei`` (General purpose) + - ``zvlb`` specifies vector length (VLEN) in bits, where N must + be a power of 2 (e.g., ``zvl128b``, ``zvl256b``, ``zvl512b``) =20 The ISA string must match the CPU's XLEN. For example, ``arch=3Drv32i`` = will fail on a 64-bit CPU. diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 092635b1050..8c3a0c94483 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1028,6 +1028,11 @@ G_NORETURN void riscv_cpu_list_supported_extensions(= void) riscv_cpu_help_multiext("Experimental Extensions", riscv_cpu_experimental_exts); =20 + /* Print vector length extensions */ + qemu_printf("Vector Length Extensions (zvl*b):\n"); + qemu_printf(" zvl32b, zvl64b, zvl128b, zvl256b, zvl512b, zvl1024b, ..= .\n"); + qemu_printf(" (Specifies VLEN in bits, must be power of 2)\n\n"); + /* Print available profiles */ qemu_printf("Profiles (64-bit only):\n"); for (int i =3D 0; riscv_profiles[i] !=3D NULL; i++) { @@ -1062,7 +1067,14 @@ static G_NORETURN void riscv_cpu_dump_isa_config(RIS= CVCPU *cpu) =20 /* Print base information */ qemu_printf("Base: RV%d\n", xlen); - qemu_printf("Privilege spec: %s\n\n", priv_spec_to_str(env->priv_ver)); + qemu_printf("Privilege spec: %s\n", priv_spec_to_str(env->priv_ver)); + + /* Print vector length configuration */ + if (cpu->cfg.vlenb > 0) { + uint16_t vlen =3D cpu->cfg.vlenb << 3; + qemu_printf("Vector length: VLEN=3D%u bits (zvl%ub)\n", vlen, vlen= ); + } + qemu_printf("\n"); =20 /* Print single-letter extensions */ qemu_printf("Standard Extensions (single-letter):\n"); @@ -3053,6 +3065,15 @@ static void riscv_isa_string_ext(RISCVCPU *cpu, char= **isa_str, } } =20 + /* Add zvl*b if vector length is configured */ + if (cpu->cfg.vlenb > 0) { + uint16_t vlen =3D cpu->cfg.vlenb << 3; + g_autofree char *zvl_ext =3D g_strdup_printf("zvl%ub", vlen); + new =3D g_strconcat(old, "_", zvl_ext, NULL); + g_free(old); + old =3D new; + } + *isa_str =3D new; } =20 diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index aa947337cf1..03a748b7dcc 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -1596,6 +1596,73 @@ static void riscv_cpu_disable_all_extensions(RISCVCP= U *cpu) for (const RISCVIsaExtData *edata =3D isa_edata_arr; edata->name; edat= a++) { isa_ext_update_enabled(cpu, edata->ext_enable_offset, false); } + + /* Reset vector length to 0 (will be set by zvl*b or implied by zve/v)= */ + cpu->cfg.vlenb =3D 0; +} + +/* + * Parse zvl*b extension name and return the minimum VLEN in bits. + * Returns 0 if the extension name is not a valid zvl*b pattern. + * Valid patterns: zvl32b, zvl64b, zvl128b, zvl256b, zvl512b, zvl1024b, et= c. + */ +static int riscv_parse_zvl_vlen(const char *ext_name) +{ + int vlen; + char suffix; + + if (g_ascii_strncasecmp(ext_name, "zvl", 3) !=3D 0) { + return 0; + } + + if (sscanf(ext_name + 3, "%d%c", &vlen, &suffix) !=3D 2) { + return 0; + } + + if (g_ascii_tolower(suffix) !=3D 'b') { + return 0; + } + + /* Validate VLEN is a power of 2 and within reasonable range */ + if (vlen < 32 || vlen > 65536 || (vlen & (vlen - 1)) !=3D 0) { + return 0; + } + + return vlen; +} + +/* + * Get the implied minimum VLEN (in bits) for an extension. + * Returns 0 if the extension doesn't imply a minimum VLEN. + * + * According to RISC-V specification: + * - zve32x, zve32f imply zvl32b (VLEN >=3D 32) + * - zve64x, zve64f, zve64d imply zvl64b (VLEN >=3D 64) + * - v implies zvl128b (VLEN >=3D 128) + */ +static int riscv_ext_implied_vlen(const char *ext_name) +{ + if (g_ascii_strcasecmp(ext_name, "v") =3D=3D 0) { + return 128; + } + if (g_ascii_strncasecmp(ext_name, "zve64", 5) =3D=3D 0) { + return 64; + } + if (g_ascii_strncasecmp(ext_name, "zve32", 5) =3D=3D 0) { + return 32; + } + return 0; +} + +/* + * Update vlenb if the new VLEN is larger than the current one. + */ +static void riscv_update_vlen(RISCVCPU *cpu, int vlen) +{ + uint16_t current_vlen =3D cpu->cfg.vlenb << 3; + if (vlen > current_vlen) { + cpu->cfg.vlenb =3D vlen >> 3; + } } =20 /* @@ -1700,6 +1767,9 @@ static bool riscv_cpu_parse_isa_string(RISCVCPU *cpu,= const char *isa_str, =20 uint32_t bit =3D riscv_get_misa_bit_from_name(ext_char); riscv_cpu_write_misa_bit(cpu, bit, true); + if (ext_char =3D=3D 'v') { + riscv_update_vlen(cpu, 128); + } is_first_ext =3D false; } =20 @@ -1711,6 +1781,13 @@ static bool riscv_cpu_parse_isa_string(RISCVCPU *cpu= , const char *isa_str, /* Process the remaining multi-letter extension */ const char *multi_ext =3D ext_name + single_count; =20 + /* Check for zvl*b extension (vector length) */ + int zvl_vlen =3D riscv_parse_zvl_vlen(multi_ext); + if (zvl_vlen > 0) { + riscv_update_vlen(cpu, zvl_vlen); + continue; + } + /* Look up the extension */ const RISCVIsaExtData *edata =3D riscv_find_ext_data(multi_ext); if (edata =3D=3D NULL) { @@ -1720,6 +1797,29 @@ static bool riscv_cpu_parse_isa_string(RISCVCPU *cpu= , const char *isa_str, =20 /* Enable the extension */ isa_ext_update_enabled(cpu, edata->ext_enable_offset, true); + + /* Check for implied minimum VLEN (zve32*, zve64*) */ + int implied_vlen =3D riscv_ext_implied_vlen(multi_ext); + if (implied_vlen > 0) { + riscv_update_vlen(cpu, implied_vlen); + } + } + + /* + * Validate that zvl*b is only specified with a vector extension. + * zvl*b requires v or zve* extension to also be specified. + */ + if (cpu->cfg.vlenb > 0) { + CPURISCVState *env =3D &cpu->env; + bool has_vector =3D (env->misa_ext & RVV) || + cpu->cfg.ext_zve32x || cpu->cfg.ext_zve32f || + cpu->cfg.ext_zve64x || cpu->cfg.ext_zve64f || + cpu->cfg.ext_zve64d; + if (!has_vector) { + error_setg(errp, "zvl*b requires v or zve* extension to also b= e " + "specified"); + return false; + } } =20 return true; @@ -1799,6 +1899,13 @@ static bool riscv_cpu_parse_profile_string(RISCVCPU = *cpu, const char *str, size_t ext_len =3D p - ext_start; g_autofree char *ext_name =3D g_strndup(ext_start, ext_len); =20 + /* Check for zvl*b extension */ + int zvl_vlen =3D riscv_parse_zvl_vlen(ext_name); + if (zvl_vlen > 0) { + riscv_update_vlen(cpu, zvl_vlen); + continue; + } + /* Look up the extension */ const RISCVIsaExtData *edata =3D riscv_find_ext_data(ext_name); if (edata =3D=3D NULL) { @@ -1809,6 +1916,12 @@ static bool riscv_cpu_parse_profile_string(RISCVCPU = *cpu, const char *str, =20 /* Enable the extension */ isa_ext_update_enabled(cpu, edata->ext_enable_offset, true); + + /* Check for implied minimum VLEN */ + int implied_vlen =3D riscv_ext_implied_vlen(ext_name); + if (implied_vlen > 0) { + riscv_update_vlen(cpu, implied_vlen); + } } =20 return true; @@ -1856,7 +1969,8 @@ static void riscv_cpu_add_arch_property(Object *obj) "ISA configuration (write-only). " "Use 'help' to list extensions, 'dump' to show current config, " "provide an ISA string (e.g., rv64gc_zba_zbb), " - "or use a profile (e.g., rva23u64)."); + "or a profile with optional extensions (e.g., rva23u64, " + "rva23u64_zbkb_zkne)."); } =20 /* diff --git a/tests/functional/riscv64/test_cpu_arch.py b/tests/functional/r= iscv64/test_cpu_arch.py index c12e1c7fce4..b1f02db9dd2 100644 --- a/tests/functional/riscv64/test_cpu_arch.py +++ b/tests/functional/riscv64/test_cpu_arch.py @@ -266,6 +266,13 @@ def test_arch_isa_string_underscore_separated_single(s= elf): self.assertRegex(res.stdout, r'd\s+enabled') self.assertRegex(res.stdout, r'c\s+enabled') =20 + def test_arch_isa_string_zvl_requires_vector(self): + """Test zvl*b requires v or zve* extension""" + res =3D self.run_qemu('rv64,arch=3Drv64g_zvl128b') + + self.assertNotEqual(res.returncode, 0) + self.assertIn("zvl*b requires v or zve* extension", res.stderr) + def test_arch_profile_rva23u64(self): """Test arch=3Drva23u64 enables RVA23 profile extensions""" res =3D self.run_qemu('rv64,arch=3Drva23u64,arch=3Ddump') @@ -338,6 +345,67 @@ def test_arch_profile_with_unknown_extension(self): self.assertNotEqual(res.returncode, 0) self.assertIn("unknown extension 'unknown'", res.stderr) =20 + def test_arch_help_shows_zvl(self): + """Test arch=3Dhelp lists zvl*b extensions""" + res =3D self.run_qemu('rv64,arch=3Dhelp') + + self.assertEqual(res.returncode, 0) + self.assertIn('Vector Length Extensions', res.stdout) + self.assertIn('zvl32b', res.stdout) + self.assertIn('zvl128b', res.stdout) + + def test_arch_isa_string_zvl(self): + """Test arch=3DISA-STRING accepts zvl*b extensions""" + res =3D self.run_qemu('rv64,arch=3Drv64gcv_zvl256b,arch=3Ddump') + + self.assertEqual(res.returncode, 0) + self.assertIn('VLEN=3D256', res.stdout) + self.assertIn('zvl256b', res.stdout) + # Check zvl*b is included in Full ISA string + self.assertRegex(res.stdout, r'Full ISA string:.*_zvl256b') + + def test_arch_dump_shows_vlen(self): + """Test arch=3Ddump shows vector length configuration""" + res =3D self.run_qemu('rv64,arch=3Drv64gcv_zvl512b,arch=3Ddump') + + self.assertEqual(res.returncode, 0) + self.assertIn('Vector length:', res.stdout) + self.assertIn('VLEN=3D512', res.stdout) + + def test_arch_isa_string_zvl_takes_max(self): + """Test multiple zvl*b extensions take maximum value""" + # zvl128b followed by zvl512b - should use 512 + res1 =3D self.run_qemu('rv64,arch=3Drv64gcv_zvl128b_zvl512b,arch= =3Ddump') + self.assertEqual(res1.returncode, 0) + self.assertIn('VLEN=3D512', res1.stdout) + + # zvl512b followed by zvl128b - should still use 512 + res2 =3D self.run_qemu('rv64,arch=3Drv64gcv_zvl512b_zvl128b,arch= =3Ddump') + self.assertEqual(res2.returncode, 0) + self.assertIn('VLEN=3D512', res2.stdout) + + # Three zvl extensions - should use maximum (1024) + res3 =3D self.run_qemu('rv64,arch=3Drv64gcv_zvl256b_zvl1024b_zvl51= 2b,arch=3Ddump') + self.assertEqual(res3.returncode, 0) + self.assertIn('VLEN=3D1024', res3.stdout) + + def test_arch_isa_string_implied_vlen(self): + """Test extensions imply minimum VLEN correctly""" + # zve64f implies zvl64b, so zvl32b should be ignored + res1 =3D self.run_qemu('rv64,arch=3Drv64i_zve64f_zvl32b,arch=3Ddum= p') + self.assertEqual(res1.returncode, 0) + self.assertIn('VLEN=3D64', res1.stdout) + + # v implies zvl128b, so zvl64b should be ignored + res2 =3D self.run_qemu('rv64,arch=3Drv64gcv_zvl64b,arch=3Ddump') + self.assertEqual(res2.returncode, 0) + self.assertIn('VLEN=3D128', res2.stdout) + + # zve64x alone should have VLEN=3D64 + res3 =3D self.run_qemu('rv64,arch=3Drv64i_zve64x,arch=3Ddump') + self.assertEqual(res3.returncode, 0) + self.assertIn('VLEN=3D64', res3.stdout) + =20 if __name__ =3D=3D '__main__': QemuUserTest.main() --=20 2.52.0