Browse Source

Refactor ISA parser extension handling

Replace the long hard-coded extension dispatch chain in isa_parser.cc with
table-driven extension metadata. The table now records the extension name,
the extension bits it enables, direct implied extensions, and simple XLEN
requirements. This makes the parser behavior closer to LLVM, where
extension parsing and implication are represented as data rather than
as a large sequence of adhoc conditionals.

Move MISA single-letter extensions into the same table as multi-letter
extensions. The parser now expands `g` to `imafd`, validates that the base
extension is `i`, `e`, or `g`, and then lets the normal single-letter parsing
loop consume the base extension through the table.  This also centralizes
common MISA implications such as `a -> zaamo,zalrsc`, `b -> zba,zbb,zbs`,
`d -> f`, `q -> d,f`, `c -> zca`, and `v -> zve64d,zvl128b`.

Model the Zve implication chain explicitly in the extension table

  zve32f -> zve32x, f
  zve32x -> zicsr, zvl32b
  zve64d -> zve64f, d
  zve64f -> zve32f, zve64x
  zve64x -> zve32x, zvl64b
  v      -> zve64d, zvl128b

Keep the Spike-specific Zve state updates out of the table by deriving
VLEN, ELEN, zvf, and zvd from the Zve extension name in a small helper.

Add a separate combine pass for reverse combination rules that reconstruct
combined extension bits from their component bits. This keeps combine logic
separate from forward implication while preserving existing Spike behavior:

  zaamo + zalrsc -> A
  zba + zbb + zbs -> B
  C + D -> Zcd
  Zicfiss + Zca -> Zcmop

Retain explicit Spike-specific post-parse checks and derived state where they
remain clearer than table entries, including RV32-only `C/Zce + F -> Zcf`,
`Zfbfmin/Zfhmin -> EXT_INTERNAL_ZFH_MOVE`, incompatibility checks, privilege
mode handling, and VLEN limit validation.

Signed-off-by: Jerry Zhang Jian <jerry.zhangjian@sifive.com>
pull/2287/head
Jerry Zhang Jian 2 weeks ago
parent
commit
a6a59f81db
  1. 655
      disasm/isa_parser.cc
  2. 1
      riscv/isa_parser.h

655
disasm/isa_parser.cc

@ -1,6 +1,10 @@
#include "isa_parser.h"
#include <cstring>
#include <initializer_list>
#include <stdexcept>
#include <vector>
namespace {
static std::string strtolower(const char* str)
{
@ -48,315 +52,250 @@ static void bad_priv_string(const char* priv)
abort();
}
struct extension_info_t {
const char* name;
std::vector<unsigned> enables;
std::vector<const char*> implies;
unsigned required_xlen = 0;
const char* required_xlen_msg = nullptr;
extension_info_t(const char* name,
std::initializer_list<unsigned> enables = {},
std::initializer_list<const char*> implies = {},
unsigned required_xlen = 0,
const char* required_xlen_msg = nullptr)
: name(name), enables(enables), implies(implies),
required_xlen(required_xlen), required_xlen_msg(required_xlen_msg) {}
};
struct extension_combination_t {
unsigned enable;
std::vector<unsigned> components;
extension_combination_t(unsigned enable,
std::initializer_list<unsigned> components = {})
: enable(enable), components(components) {}
};
// Entries without enables are accepted ISA names whose behavior is always present
// in Spike, currently unmodeled, or handled by later parser checks.
static const extension_info_t extension_infos[] = {
{"i", {'I'}},
{"e", {'E'}},
{"m", {'M'}},
{"a", {'A'}, {"zaamo", "zalrsc"}},
{"f", {'F'}},
{"d", {'D', 'F'}},
{"q", {'Q', 'D', 'F'}},
{"c", {'C'}, {"zca"}},
{"b", {'B'}, {"zba", "zbb", "zbs"}},
{"p", {'P'}},
{"v", {'V'}, {"zve64d", "zvl128b"}},
{"h", {'H'}},
{"zfh", {EXT_ZFH}, {"zfhmin"}},
{"zfhmin", {'F', EXT_ZFHMIN}},
{"zvfh", {EXT_ZVFH}, {"zvfhmin", "zfhmin"}},
{"zvfhmin", {EXT_ZVFHMIN}, {"zve32f"}},
{"zvfbfa", {EXT_ZVFBFA}, {"zve32f", "zfbfmin"}},
{"zvfofp4min", {EXT_ZVFOFP4MIN}, {"zve32f"}},
{"zvfofp8min", {EXT_ZVFOFP8MIN}, {"zve32f"}},
{"zicsr"},
{"zifencei"},
{"zihintpause"},
{"zihintntl"},
{"ziccid", {EXT_ZICCID}},
{"ziccif"},
{"zve32x", {}, {"zicsr", "zvl32b"}},
{"zve32f", {}, {"zve32x", "f"}},
{"zve64x", {}, {"zve32x", "zvl64b"}},
{"zve64f", {}, {"zve32f", "zve64x"}},
{"zve64d", {}, {"zve64f", "d"}},
{"zaamo", {EXT_ZAAMO}},
{"zalrsc", {EXT_ZALRSC}},
{"zacas", {EXT_ZACAS, EXT_ZAAMO}},
{"zabha", {EXT_ZABHA, EXT_ZAAMO}},
{"zawrs", {EXT_ZAWRS, EXT_ZALRSC}},
{"zama16b", {EXT_ZAMA16B}},
{"zmmul", {EXT_ZMMUL}},
{"zba", {EXT_ZBA}},
{"zbb", {EXT_ZBB}},
{"zbc", {EXT_ZBC}},
{"zbs", {EXT_ZBS}},
{"zbkb", {EXT_ZBKB}},
{"zbkc", {EXT_ZBKC}},
{"zbkx", {EXT_ZBKX}},
{"zdinx", {EXT_ZFINX, EXT_ZDINX}},
{"zfbfmin", {'F', EXT_ZFBFMIN}},
{"zfinx", {EXT_ZFINX}},
{"zhinx", {EXT_ZFINX, EXT_ZHINX, EXT_ZHINXMIN}},
{"zhinxmin", {EXT_ZFINX, EXT_ZHINXMIN}},
{"zce", {EXT_ZCE}, {"zcb", "zcmp", "zcmt"}},
{"zca", {EXT_ZCA}},
{"zcf", {'F', EXT_ZCF}, {"zca"}, 32, "'Zcf' requires RV32"},
{"zcb", {EXT_ZCB}, {"zca"}},
{"zcd", {EXT_ZCD, 'F', 'D'}, {"zca"}},
{"zcmp", {EXT_ZCMP}, {"zca"}},
{"zcmt", {EXT_ZCMT}, {"zca", "zicsr"}},
{"zibi", {EXT_ZIBI}},
{"zk", {EXT_ZBKB, EXT_ZBKC, EXT_ZBKX, EXT_ZKND, EXT_ZKNE, EXT_ZKNH, EXT_ZKR}},
{"zkn", {EXT_ZBKB, EXT_ZBKC, EXT_ZBKX, EXT_ZKND, EXT_ZKNE, EXT_ZKNH}},
{"zknd", {EXT_ZKND}},
{"zkne", {EXT_ZKNE}},
{"zknh", {EXT_ZKNH}},
{"zks", {EXT_ZBKB, EXT_ZBKC, EXT_ZBKX, EXT_ZKSED, EXT_ZKSH}},
{"zksed", {EXT_ZKSED}},
{"zksh", {EXT_ZKSH}},
{"zkr", {EXT_ZKR}},
{"zkt"},
{"smepmp", {EXT_SMEPMP}},
{"smstateen", {EXT_SMSTATEEN}},
{"smpmpmt", {EXT_SMPMPMT}},
{"smrnmi", {EXT_SMRNMI}},
{"sscofpmf", {EXT_SSCOFPMF}},
{"svadu", {EXT_SVADU}},
{"svade", {EXT_SVADE}},
{"svnapot", {EXT_SVNAPOT}},
{"svpbmt", {EXT_SVPBMT}},
{"svinval", {EXT_SVINVAL}},
{"svukte", {EXT_SVUKTE}, {}, 64, "'svukte' requires RV64"},
{"zfa", {EXT_ZFA}},
{"zicbom", {EXT_ZICBOM}},
{"zicboz", {EXT_ZICBOZ}},
{"zicbop"},
{"zicclsm", {EXT_ZICCLSM}},
{"zicntr", {EXT_ZICNTR}},
{"zicond", {EXT_ZICOND}},
{"zihpm", {EXT_ZIHPM}},
{"zilsd", {EXT_ZILSD}, {}, 32, "'Zilsd' requires RV32"},
{"zclsd", {EXT_ZCLSD}, {"zilsd", "zca"}, 32, "'Zclsd' requires RV32"},
{"zvabd", {EXT_ZVABD}},
{"zvkb", {EXT_ZVKB}},
{"zvbb", {EXT_ZVKB, EXT_ZVBB}},
{"zvbc", {EXT_ZVBC}},
{"zvfbfmin", {EXT_ZVFBFMIN}, {"zve32f"}},
{"zvfbfwma", {EXT_ZVFBFWMA}, {"zfbfmin", "zvfbfmin"}},
{"zvkg", {EXT_ZVKG}},
{"zvkn", {EXT_ZVKB, EXT_ZVKNED, EXT_ZVKNHB}},
{"zvknc", {EXT_ZVKB, EXT_ZVBC, EXT_ZVKNED, EXT_ZVKNHB}},
{"zvkng", {EXT_ZVKB, EXT_ZVKG, EXT_ZVKNED, EXT_ZVKNHB}},
{"zvkned", {EXT_ZVKNED}},
{"zvknha", {EXT_ZVKNHA}},
{"zvknhb", {EXT_ZVKNHB}},
{"zvks", {EXT_ZVKB, EXT_ZVKSED, EXT_ZVKSH}},
{"zvksc", {EXT_ZVKB, EXT_ZVBC, EXT_ZVKSED, EXT_ZVKSH}},
{"zvksg", {EXT_ZVKB, EXT_ZVKG, EXT_ZVKSED, EXT_ZVKSH}},
{"zvksed", {EXT_ZVKSED}},
{"zvksh", {EXT_ZVKSH}},
{"zvqdotq", {EXT_ZVQDOTQ}},
{"zvqbdot8i", {EXT_ZVQBDOT8I}},
{"zvqbdot16i", {EXT_ZVQBDOT16I}},
{"zvfqbdot8f", {EXT_ZVFQBDOT8F}},
{"zvfwbdot16bf", {EXT_ZVFWBDOT16BF}},
{"zvfbdot32f", {EXT_ZVFBDOT32F}},
{"zvqldot8i", {EXT_ZVQLDOT8I}},
{"zvqldot16i", {EXT_ZVQLDOT16I}},
{"zvfqldot8f", {EXT_ZVFQLDOT8F}},
{"zvfwldot16bf", {EXT_ZVFWLDOT16BF}},
{"zvkt"},
{"zvzip", {EXT_ZVZIP}},
{"sstc", {EXT_SSTC}},
{"smcsrind", {EXT_SMCSRIND}},
{"sscsrind", {EXT_SSCSRIND}},
{"smcntrpmf", {EXT_SMCNTRPMF}},
{"smcdeleg", {EXT_SMCDELEG}},
{"ssccfg", {EXT_SSCCFG}},
{"zimop", {EXT_ZIMOP}},
{"zcmop", {EXT_ZCMOP}, {"zca"}},
{"zalasr", {EXT_ZALASR}},
{"ssqosid", {EXT_SSQOSID}},
{"zicfilp", {EXT_ZICFILP}},
{"zicfiss", {EXT_ZICFISS}, {"zaamo", "zimop"}},
{"smmpm", {EXT_SMMPM}},
{"smnpm", {EXT_SMNPM}},
{"ssnpm", {EXT_SSNPM}},
{"ssdbltrp", {EXT_SSDBLTRP}},
{"smdbltrp", {EXT_SMDBLTRP}},
{"smaia", {EXT_SMAIA, EXT_SSAIA, EXT_SMCSRIND, EXT_SSCSRIND}},
{"ssaia", {EXT_SSAIA, EXT_SSCSRIND}},
{"svvptc"},
};
static const extension_combination_t extension_combinations[] = {
{'A', {EXT_ZAAMO, EXT_ZALRSC}},
{'B', {EXT_ZBA, EXT_ZBB, EXT_ZBS}},
{EXT_ZCD, {'C', 'D'}},
{EXT_ZCMOP, {EXT_ZICFISS, EXT_ZCA}},
};
static const extension_info_t* find_extension_info(const std::string& ext)
{
for (const auto& info : extension_infos)
if (ext == info.name)
return &info;
return nullptr;
}
static void apply_extension_combinations(std::bitset<NUM_ISA_EXTENSIONS>& extension_table)
{
for (const auto& combination : extension_combinations) {
if (combination.components.empty())
continue;
bool has_all_components = true;
for (const auto component : combination.components) {
has_all_components &= extension_table[component];
}
if (has_all_components)
extension_table[combination.enable] = true;
}
}
} // namespace
void isa_parser_t::apply_zve_properties(const std::string& ext_str, const char* str)
{
if (ext_str.size() != 6)
bad_isa_string(str, ("Invalid Zve string: " + ext_str).c_str());
reg_t new_elen;
try {
new_elen = safe_stoul(ext_str.substr(3, ext_str.size() - 4));
} catch (std::logic_error& e) {
new_elen = 0;
}
switch (ext_str.back()) {
case 'd':
zvd |= true;
[[fallthrough]];
case 'f':
zvf |= true;
break;
case 'x':
break;
default:
new_elen = 0;
}
if (new_elen != 32 && new_elen != 64)
bad_isa_string(str, ("Invalid Zve string: " + ext_str).c_str());
elen = std::max(elen, new_elen);
vlen = std::max(vlen, new_elen);
}
void isa_parser_t::add_extension(const std::string& ext_str, const char* str)
{
if (ext_str == "zfh") {
extension_table[EXT_ZFH] = true;
add_extension("zfhmin", str);
} else if (ext_str == "zfhmin") {
extension_table['F'] = true;
extension_table[EXT_ZFHMIN] = true;
} else if (ext_str == "zvfh") {
extension_table[EXT_ZVFH] = true;
add_extension("zvfhmin", str);
add_extension("zfhmin", str);
} else if (ext_str == "zvfhmin") {
extension_table[EXT_ZVFHMIN] = true;
add_extension("zve32f", str);
} else if (ext_str == "zvfbfa") {
extension_table[EXT_ZVFBFA] = true;
add_extension("zve32f", str);
add_extension("zfbfmin", str);
} else if (ext_str == "zvfofp4min") {
extension_table[EXT_ZVFOFP4MIN] = true;
add_extension("zve32f", str);
} else if (ext_str == "zvfofp8min") {
extension_table[EXT_ZVFOFP8MIN] = true;
add_extension("zve32f", str);
} else if (ext_str == "zicsr") {
// Spike necessarily has Zicsr, because
// Zicsr is implied by the privileged architecture
} else if (ext_str == "zifencei") {
// For compatibility with version 2.0 of the base ISAs, we
// unconditionally include FENCE.I, so Zifencei adds nothing more.
} else if (ext_str == "zihintpause") {
// HINTs encoded in base-ISA instructions are always present.
} else if (ext_str == "zihintntl") {
// HINTs encoded in base-ISA instructions are always present.
} else if (ext_str == "ziccid") {
extension_table[EXT_ZICCID] = true;
} else if (ext_str == "ziccif") {
// aligned instruction fetch is always atomic in Spike
} else if (ext_str == "zaamo") {
extension_table[EXT_ZAAMO] = true;
} else if (ext_str == "zalrsc") {
extension_table[EXT_ZALRSC] = true;
} else if (ext_str == "zacas") {
extension_table[EXT_ZACAS] = true;
extension_table[EXT_ZAAMO] = true;
} else if (ext_str == "zabha") {
extension_table[EXT_ZABHA] = true;
extension_table[EXT_ZAAMO] = true;
} else if (ext_str == "zawrs") {
extension_table[EXT_ZAWRS] = true;
extension_table[EXT_ZALRSC] = true;
} else if (ext_str == "zama16b") {
extension_table[EXT_ZAMA16B] = true;
} else if (ext_str == "zmmul") {
extension_table[EXT_ZMMUL] = true;
} else if (ext_str == "zba") {
extension_table[EXT_ZBA] = true;
} else if (ext_str == "zbb") {
extension_table[EXT_ZBB] = true;
} else if (ext_str == "zbc") {
extension_table[EXT_ZBC] = true;
} else if (ext_str == "zbs") {
extension_table[EXT_ZBS] = true;
} else if (ext_str == "zbkb") {
extension_table[EXT_ZBKB] = true;
} else if (ext_str == "zbkc") {
extension_table[EXT_ZBKC] = true;
} else if (ext_str == "zbkx") {
extension_table[EXT_ZBKX] = true;
} else if (ext_str == "zdinx") {
extension_table[EXT_ZFINX] = true;
extension_table[EXT_ZDINX] = true;
} else if (ext_str == "zfbfmin") {
extension_table['F'] = true;
extension_table[EXT_ZFBFMIN] = true;
} else if (ext_str == "zfinx") {
extension_table[EXT_ZFINX] = true;
} else if (ext_str == "zhinx") {
extension_table[EXT_ZFINX] = true;
extension_table[EXT_ZHINX] = true;
extension_table[EXT_ZHINXMIN] = true;
} else if (ext_str == "zhinxmin") {
extension_table[EXT_ZFINX] = true;
extension_table[EXT_ZHINXMIN] = true;
} else if (ext_str == "zce") {
extension_table[EXT_ZCA] = true;
extension_table[EXT_ZCB] = true;
extension_table[EXT_ZCMT] = true;
extension_table[EXT_ZCMP] = true;
extension_table[EXT_ZCE] = true;
} else if (ext_str == "zca") {
extension_table[EXT_ZCA] = true;
} else if (ext_str == "zcf") {
if (max_xlen != 32)
bad_isa_string(str, "'Zcf' requires RV32");
extension_table['F'] = true;
extension_table[EXT_ZCA] = true;
extension_table[EXT_ZCF] = true;
} else if (ext_str == "zcb") {
extension_table[EXT_ZCB] = true;
extension_table[EXT_ZCA] = true;
} else if (ext_str == "zcd") {
extension_table[EXT_ZCD] = true;
extension_table[EXT_ZCA] = true;
extension_table['F'] = true;
extension_table['D'] = true;
} else if (ext_str == "zcmp") {
extension_table[EXT_ZCMP] = true;
extension_table[EXT_ZCA] = true;
} else if (ext_str == "zcmt") {
extension_table[EXT_ZCMT] = true;
extension_table[EXT_ZCA] = true;
} else if (ext_str == "zibi") {
extension_table[EXT_ZIBI] = true;
} else if (ext_str == "zk") {
extension_table[EXT_ZBKB] = true;
extension_table[EXT_ZBKC] = true;
extension_table[EXT_ZBKX] = true;
extension_table[EXT_ZKND] = true;
extension_table[EXT_ZKNE] = true;
extension_table[EXT_ZKNH] = true;
extension_table[EXT_ZKR] = true;
} else if (ext_str == "zkn") {
extension_table[EXT_ZBKB] = true;
extension_table[EXT_ZBKC] = true;
extension_table[EXT_ZBKX] = true;
extension_table[EXT_ZKND] = true;
extension_table[EXT_ZKNE] = true;
extension_table[EXT_ZKNH] = true;
} else if (ext_str == "zknd") {
extension_table[EXT_ZKND] = true;
} else if (ext_str == "zkne") {
extension_table[EXT_ZKNE] = true;
} else if (ext_str == "zknh") {
extension_table[EXT_ZKNH] = true;
} else if (ext_str == "zks") {
extension_table[EXT_ZBKB] = true;
extension_table[EXT_ZBKC] = true;
extension_table[EXT_ZBKX] = true;
extension_table[EXT_ZKSED] = true;
extension_table[EXT_ZKSH] = true;
} else if (ext_str == "zksed") {
extension_table[EXT_ZKSED] = true;
} else if (ext_str == "zksh") {
extension_table[EXT_ZKSH] = true;
} else if (ext_str == "zkr") {
extension_table[EXT_ZKR] = true;
} else if (ext_str == "zkt") {
} else if (ext_str == "smepmp") {
extension_table[EXT_SMEPMP] = true;
} else if (ext_str == "smstateen") {
extension_table[EXT_SMSTATEEN] = true;
} else if (ext_str == "smpmpmt") {
extension_table[EXT_SMPMPMT] = true;
} else if (ext_str == "smrnmi") {
extension_table[EXT_SMRNMI] = true;
} else if (ext_str == "sscofpmf") {
extension_table[EXT_SSCOFPMF] = true;
} else if (ext_str == "svadu") {
extension_table[EXT_SVADU] = true;
} else if (ext_str == "svade") {
extension_table[EXT_SVADE] = true;
} else if (ext_str == "svnapot") {
extension_table[EXT_SVNAPOT] = true;
} else if (ext_str == "svpbmt") {
extension_table[EXT_SVPBMT] = true;
} else if (ext_str == "svinval") {
extension_table[EXT_SVINVAL] = true;
} else if (ext_str == "svukte") {
if (max_xlen != 64)
bad_isa_string(str, "'svukte' requires RV64");
extension_table[EXT_SVUKTE] = true;
} else if (ext_str == "zfa") {
extension_table[EXT_ZFA] = true;
} else if (ext_str == "zicbom") {
extension_table[EXT_ZICBOM] = true;
} else if (ext_str == "zicboz") {
extension_table[EXT_ZICBOZ] = true;
} else if (ext_str == "zicbop") {
} else if (ext_str == "zicclsm") {
extension_table[EXT_ZICCLSM] = true;
} else if (ext_str == "zicntr") {
extension_table[EXT_ZICNTR] = true;
} else if (ext_str == "zicond") {
extension_table[EXT_ZICOND] = true;
} else if (ext_str == "zihpm") {
extension_table[EXT_ZIHPM] = true;
} else if (ext_str == "zilsd") {
if (max_xlen != 32)
bad_isa_string(str, "'Zilsd' requires RV32");
extension_table[EXT_ZILSD] = true;
} else if (ext_str == "zclsd") {
if (max_xlen != 32)
bad_isa_string(str, "'Zclsd' requires RV32");
extension_table[EXT_ZCLSD] = true;
extension_table[EXT_ZCA] = true;
extension_table[EXT_ZILSD] = true;
} else if (ext_str == "zvabd") {
extension_table[EXT_ZVABD] = true;
} else if (ext_str == "zvkb") {
extension_table[EXT_ZVKB] = true;
} else if (ext_str == "zvbb") {
extension_table[EXT_ZVKB] = true;
extension_table[EXT_ZVBB] = true;
} else if (ext_str == "zvbc") {
extension_table[EXT_ZVBC] = true;
} else if (ext_str == "zvfbfmin") {
extension_table[EXT_ZVFBFMIN] = true;
add_extension("zve32f", str);
} else if (ext_str == "zvfbfwma") {
extension_table[EXT_ZVFBFWMA] = true;
add_extension("zfbfmin", str);
add_extension("zvfbfmin", str);
} else if (ext_str == "zvkg") {
extension_table[EXT_ZVKG] = true;
} else if (ext_str == "zvkn") {
extension_table[EXT_ZVKB] = true;
extension_table[EXT_ZVKNED] = true;
extension_table[EXT_ZVKNHB] = true;
} else if (ext_str == "zvknc") {
extension_table[EXT_ZVKB] = true;
extension_table[EXT_ZVBC] = true;
extension_table[EXT_ZVKNED] = true;
extension_table[EXT_ZVKNHB] = true;
} else if (ext_str == "zvkng") {
extension_table[EXT_ZVKB] = true;
extension_table[EXT_ZVKG] = true;
extension_table[EXT_ZVKNED] = true;
extension_table[EXT_ZVKNHB] = true;
} else if (ext_str == "zvkned") {
extension_table[EXT_ZVKNED] = true;
} else if (ext_str == "zvknha") {
extension_table[EXT_ZVKNHA] = true;
} else if (ext_str == "zvknhb") {
extension_table[EXT_ZVKNHB] = true;
} else if (ext_str == "zvks") {
extension_table[EXT_ZVKB] = true;
extension_table[EXT_ZVKSED] = true;
extension_table[EXT_ZVKSH] = true;
} else if (ext_str == "zvksc") {
extension_table[EXT_ZVKB] = true;
extension_table[EXT_ZVBC] = true;
extension_table[EXT_ZVKSED] = true;
extension_table[EXT_ZVKSH] = true;
} else if (ext_str == "zvksg") {
extension_table[EXT_ZVKB] = true;
extension_table[EXT_ZVKG] = true;
extension_table[EXT_ZVKSED] = true;
extension_table[EXT_ZVKSH] = true;
} else if (ext_str == "zvksed") {
extension_table[EXT_ZVKSED] = true;
} else if (ext_str == "zvksh") {
extension_table[EXT_ZVKSH] = true;
} else if (ext_str == "zvqdotq") {
extension_table[EXT_ZVQDOTQ] = true;
} else if (ext_str == "zvqbdot8i") {
extension_table[EXT_ZVQBDOT8I] = true;
} else if (ext_str == "zvqbdot16i") {
extension_table[EXT_ZVQBDOT16I] = true;
} else if (ext_str == "zvfqbdot8f") {
extension_table[EXT_ZVFQBDOT8F] = true;
} else if (ext_str == "zvfwbdot16bf") {
extension_table[EXT_ZVFWBDOT16BF] = true;
} else if (ext_str == "zvfbdot32f") {
extension_table[EXT_ZVFBDOT32F] = true;
} else if (ext_str == "zvqldot8i") {
extension_table[EXT_ZVQLDOT8I] = true;
} else if (ext_str == "zvqldot16i") {
extension_table[EXT_ZVQLDOT16I] = true;
} else if (ext_str == "zvfqldot8f") {
extension_table[EXT_ZVFQLDOT8F] = true;
} else if (ext_str == "zvfwldot16bf") {
extension_table[EXT_ZVFWLDOT16BF] = true;
} else if (ext_str == "zvkt") {
} else if (ext_str == "zvzip") {
extension_table[EXT_ZVZIP] = true;
} else if (ext_str == "sstc") {
extension_table[EXT_SSTC] = true;
} else if (ext_str == "smcsrind") {
extension_table[EXT_SMCSRIND] = true;
} else if (ext_str == "sscsrind") {
extension_table[EXT_SSCSRIND] = true;
} else if (ext_str == "smcntrpmf") {
extension_table[EXT_SMCNTRPMF] = true;
} else if (ext_str == "smcdeleg") {
extension_table[EXT_SMCDELEG] = true;
} else if (ext_str == "ssccfg") {
extension_table[EXT_SSCCFG] = true;
} else if (ext_str == "zimop") {
extension_table[EXT_ZIMOP] = true;
} else if (ext_str == "zcmop") {
extension_table[EXT_ZCMOP] = true;
} else if (ext_str == "zalasr") {
extension_table[EXT_ZALASR] = true;
} else if (ext_str == "ssqosid") {
extension_table[EXT_SSQOSID] = true;
} else if (ext_str == "zicfilp") {
extension_table[EXT_ZICFILP] = true;
} else if (ext_str == "zicfiss") {
extension_table[EXT_ZICFISS] = true;
extension_table[EXT_ZAAMO] = true;
extension_table[EXT_ZIMOP] = true;
} else if (ext_str == "smmpm") {
extension_table[EXT_SMMPM] = true;
} else if (ext_str == "smnpm") {
extension_table[EXT_SMNPM] = true;
} else if (ext_str == "ssnpm") {
extension_table[EXT_SSNPM] = true;
if (const auto* info = find_extension_info(ext_str)) {
if (info->required_xlen && max_xlen != info->required_xlen)
bad_isa_string(str, info->required_xlen_msg);
for (const auto ext : info->enables) {
extension_table[ext] = true;
}
for (const auto implied : info->implies) {
add_extension(implied, str);
}
if (ext_str.substr(0, 3) == "zve")
apply_zve_properties(ext_str, str);
} else if (ext_str.substr(0, 3) == "zvl") {
reg_t new_vlen;
try {
@ -367,47 +306,7 @@ void isa_parser_t::add_extension(const std::string& ext_str, const char* str)
if ((new_vlen & (new_vlen - 1)) != 0 || new_vlen < 32 || ext_str.back() != 'b')
bad_isa_string(str, ("Invalid Zvl string: " + ext_str).c_str());
vlen = std::max(vlen, new_vlen);
} else if (ext_str.substr(0, 3) == "zve") {
if (ext_str.size() != 6) {
bad_isa_string(str, ("Invalid Zve string: " + ext_str).c_str());
}
reg_t new_elen;
try {
new_elen = safe_stoul(ext_str.substr(3, ext_str.size() - 4));
} catch (std::logic_error& e) {
new_elen = 0;
}
if (ext_str.substr(5) == "d") {
zvd |= true;
zvf |= true;
extension_table['F'] = true;
extension_table['D'] = true;
} else if (ext_str.substr(5) == "f") {
zvf |= true;
extension_table['F'] = true;
} else if (ext_str.substr(5) == "x") {
/* do nothing */
} else {
new_elen = 0;
}
if (new_elen != 32 && new_elen != 64)
bad_isa_string(str, ("Invalid Zve string: " + ext_str).c_str());
elen = std::max(elen, new_elen);
vlen = std::max(vlen, new_elen);
} else if (ext_str == "ssdbltrp") {
extension_table[EXT_SSDBLTRP] = true;
} else if (ext_str == "smdbltrp") {
extension_table[EXT_SMDBLTRP] = true;
} else if (ext_str == "smaia") {
extension_table[EXT_SMAIA] = true;
extension_table[EXT_SSAIA] = true;
extension_table[EXT_SMCSRIND] = true;
extension_table[EXT_SSCSRIND] = true;
} else if (ext_str == "ssaia") {
extension_table[EXT_SSAIA] = true;
extension_table[EXT_SSCSRIND] = true;
} else if (ext_str == "svvptc") {
} else if (ext_str[0] == 'x') {
} else if (!ext_str.empty() && ext_str[0] == 'x') {
extension_table['X'] = true;
if (ext_str.size() == 1) {
bad_isa_string(str, "single 'X' is not a proper name");
@ -436,23 +335,14 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv)
zvf = false;
zvd = false;
switch (isa_string[4]) {
case 'g':
// G = IMAFD_Zicsr_Zifencei, but Spike includes the latter two
// unconditionally, so they need not be explicitly added here.
isa_string = isa_string.substr(0, 4) + "imafd" + isa_string.substr(5);
[[fallthrough]];
case 'i':
extension_table['I'] = true;
break;
case 'e':
extension_table['E'] = true;
break;
default:
bad_isa_string(str, ("'" + isa_string.substr(0, 4) + "' must be followed by I, E, or G").c_str());
if (isa_string[4] == 'g') {
// G = IMAFD_Zicsr_Zifencei, but Spike includes the latter two
// unconditionally, so they need not be explicitly added here.
isa_string = isa_string.substr(0, 4) + "imafd" + isa_string.substr(5);
} else if (isa_string[4] != 'i' && isa_string[4] != 'e') {
bad_isa_string(str, ("'" + isa_string.substr(0, 4) + "' must be followed by I, E, or G").c_str());
}
add_extension(std::string(1, isa_string[4]), str);
const char* isa_str = isa_string.c_str();
auto p = isa_str, subset = all_subsets;
@ -467,14 +357,7 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv)
bad_isa_string(str, ("Unsupported extension '" + std::string(1, *p) + "'").c_str());
}
switch (*p) {
case 'v': add_extension("zve64d", str); vlen = 128;
[[fallthrough]];
case 'q': extension_table['D'] = true;
[[fallthrough]];
case 'd': extension_table['F'] = true;
}
extension_table[toupper(*p)] = true;
add_extension(std::string(1, *p), str);
while (isdigit(*(p + 1))) {
++p; // skip major version, point, and minor version if presented
if (*(p + 1) == 'p') ++p;
@ -494,25 +377,10 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv)
bad_isa_string(str, ("can't parse: " + std::string(p)).c_str());
}
if (extension_table['A']) {
extension_table[EXT_ZAAMO] = true;
extension_table[EXT_ZALRSC] = true;
} else if (extension_table[EXT_ZAAMO] && extension_table[EXT_ZALRSC]) {
extension_table['A'] = true;
}
apply_extension_combinations(extension_table);
if (extension_table['B']) {
extension_table[EXT_ZBA] = true;
extension_table[EXT_ZBB] = true;
extension_table[EXT_ZBS] = true;
} else if (extension_table[EXT_ZBA] && extension_table[EXT_ZBB] && extension_table[EXT_ZBS]) {
extension_table['B'] = true;
}
if (extension_table['C']) {
extension_table[EXT_ZCA] = true;
if (extension_table['D'])
extension_table[EXT_ZCD] = true;
if (extension_table[EXT_ZFBFMIN] || extension_table[EXT_ZFHMIN]) {
extension_table[EXT_INTERNAL_ZFH_MOVE] = true;
}
if (extension_table['C'] || extension_table[EXT_ZCE]) {
@ -520,13 +388,6 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv)
extension_table[EXT_ZCF] = true;
}
if (extension_table[EXT_ZICFISS] && extension_table[EXT_ZCA])
extension_table[EXT_ZCMOP] = true;
if (extension_table[EXT_ZFBFMIN] || extension_table[EXT_ZFHMIN]) {
extension_table[EXT_INTERNAL_ZFH_MOVE] = true;
}
if (extension_table[EXT_ZCLSD] && extension_table[EXT_ZCF]) {
bad_isa_string(str, "'Zclsd' extension conflicts with 'Zcf' extensions");
}

1
riscv/isa_parser.h

@ -159,6 +159,7 @@ protected:
private:
void add_extension(const std::string&, const char*);
void apply_zve_properties(const std::string&, const char*);
};
#endif

Loading…
Cancel
Save