From nobody Tue Feb 10 11:13:08 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