Skip to content

About

A simple and intuitive approach to visualize RISC-V Extensions and Profiles.

Resources

Code of conduct

Contributing

Security policy

Stars

34 stars

Watchers

0 watching

Forks

Latest commit

 

History

314 Commits

Folders and files

RISC-V ISA Explorer

An interactive reference for RISC-V extensions, profiles, and per-instruction encodings. Pick a base ISA or start from a supported profile, add extensions, and get a dependency-resolved configuration with a valid -march string.

Open the live site

The explorer showing the extension catalogue with Zba selected, its description, use case and instruction set alongside

CI License DCO

What it does

  • Browse every catalogued extension, grouped and searchable by name, mnemonic, or hex encoding.
  • Build a configuration. Select extensions and dependencies resolve automatically, with conflicts blocked and a reason shown for every implied extension.
  • Start from a profile. RVA23, RVB23, their frozen 23.1 minor profiles, and the other supported profiles load as a starting point rather than being rebuilt by hand. Profiles are Volume III of the ISA manual, so each ratified profile links to its specification on docs.riscv.org.
  • Highlight a profile to see everything in it: mandatory extensions in full, implied ones tagged with the extension that pulls them in, optional ones tagged and outlined. The grid, the download and the comparison all use the same classification.
  • Share a view. Selecting an extension puts ?ext= in the address bar, a highlighted profile puts ?profile= there (?profile=rva23.1 works), and Share copies a link to either the highlighted profile or the whole builder configuration. A configuration link records the profile it started from, the extensions added and removed, and the parameters chosen. If the visitor already has a different configuration saved, the page asks before replacing it.
  • Export a -march string, a YAML configuration (optionally with every instruction), or a UDB architecture configuration for riscv-arch-test. Parameters chosen in the ISA Configuration Builder go into both files.
  • Compare entries. Pin extensions, instructions or profiles and read them side by side; a comparison has its own URL and can be shared. With Compare switched on, Compare profiles opens a profile comparison directly, grouping extensions under Mandatory, Implied and Optional (or A–Z), and Show narrows it to required or optional extensions only.
  • Download a profile. While a profile is highlighted, download its extensions (mandatory, implied and optional, with status and spec links) as YAML, JSON, CSV or Excel.
  • Check an encoding. The Encoder Validator tests a proposed instruction pattern against every existing one and reports overlaps.
  • See the encoding space. The Encoding Map draws the 32 base opcode slots, shaded by how many instructions each holds, and shows what is still free.
  • Design an extension that does not exist yet. The Custom Extension Sandbox lets you draft a custom vendor extension or an addition to a ratified one, lay out the bit encodings, check them against every instruction in the catalogue, and export riscv-opcodes JSON plus a proposal document. See docs/sandbox.md.
  • Read the registers and instructions. CSR chips open each register's fields, and instructions carry descriptions taken from riscv-unified-db, each with a link to its source.
  • Write an instruction. Each instruction shows its assembly syntax with a concrete example, whether it is RV32- or RV64-only or has data-independent timing, the C intrinsic that emits it (from the RVV intrinsics and RISC-V C API specifications), and a link that opens the example compiled in Compiler Explorer with the right -march. Links to its code in the two reference models, the Sail formal model and the Spike simulator, and to its Architectural Certification Test (ACT) sit beside these; one that does not cover the instruction yet is shown greyed out.
  • Know which tools take it, and what runs it. Each extension shows the first release of Clang and GCC that accept it in -march, of binutils that assembles it, of QEMU that emulates it, and of Linux that detects it, marking the ones Clang and QEMU still treat as experimental and the ones LLVM documents as assembly-only (accepted and assembled, but no code generated, as for RV32E and RV64E). Under the builder's -march string, Accepted by gives the oldest Clang, GCC and binutils that accept all of it, or names the extensions no release takes yet. Accepting a -march is not the same as generating code for every extension in it. The versions are read from each release's own source.
  • Watch the ISA grow. Evolution plots every dated extension on the month it was ratified, over a cumulative curve banded by family. Below it, one stepped line per tool shows how many extensions each Clang, GCC, binutils, QEMU and Linux release knew, against how many had been ratified by then.
  • Link out to the specification. Each extension's Read Online button opens the page that defines it: docs.riscv.org when it is published there, otherwise the specification's source repository, and the button says which.

Something look wrong?

The catalogue is the product, so a bad description, a missing dependency or a wrong encoding matters more here than most bugs. Open an issue and cite the specification section or the riscv-unified-db file that says otherwise. That turns a report into a fix, and it is usually a small change.

Quickstart

Node.js and npm are the only requirements.

npm ci
npm run build
python3 -m http.server 8080 -d dist

Then open http://localhost:8080.

Where the data comes from

These files carry the data, and they do not have the same authority. Worth knowing before changing anything:

file holds source of truth
src/riscv_extensions.json the extension catalogue, plus the instruction encodings routed into each extension riscv-unified-db for metadata and ratification state; src/instr_dict.json for encodings
src/instr_dict.json the instruction encodings themselves hand-maintained. Checked against riscv-opcodes, but it carries entries upstream lacks and is never regenerated
src/isa-dependency-graph.json dependencies, conflicts and parameter constraints, with a citation on every edge riscv-unified-db
src/isa-params.json parameter definitions: type, admissible values, when each exists riscv-unified-db, generated; never edited by hand
src/instruction-metadata.json instruction descriptions, ownership and assembly syntax riscv-unified-db, generated
src/isa-manual-status.json what each ISA manual preface lists as ratified, to check the catalogue's states against riscv-isa-manual prefaces, generated, pinned to a commit
src/toolchain-support.json the first Clang, GCC, binutils, QEMU and Linux release that knows each extension each release's extension table in llvm-project (from 14), gcc (from 12), binutils (from 2.38), qemu (from 7.0) and linux (from 6.6), generated
src/instruction-references.json where each instruction is implemented in Sail and Spike, and its ACT test sail-riscv, riscv-isa-sim and riscv-arch-test, generated, pinned to a commit of each
src/instruction-intrinsics.json the C intrinsics that emit each instruction rvv-intrinsic-doc and riscv-c-api-doc, generated
src/profiles.js supported profiles, mandatory extensions, spec links the profile specifications (Volume III), by hand
src/profile-optional.json each profile's optional extensions riscv-unified-db, resolved through its profile inheritance

Two things fall outside that table, because no upstream carries them. The Zve* embedded vector subsets are derived from V by the EEW/FP rules in unpriv §30.1.18.2 — riscv-opcodes has no rv_zve* tag and unified-db attributes every vector instruction to a single owner, so neither can say what belongs in Zve32x. And the SPMP family (Sspmp, Sspmpen, Smpmpdeleg) is ratified in a specification of its own that unified-db does not model at all; its dependency edges cite that document through the graph's spec provenance source. Both are places where the usual checks cannot help, so both are pinned by tests.

riscv-unified-db is normative for dependencies. clang is the check that what we emit is actually usable: CI feeds every generated -march string to a real compiler. riscv-config, RISC-V International's own validator, disagrees with clang in a few places, and where it does both opinions are recorded rather than one being quietly preferred.

Regenerate with:

npm run sync          # route src/instr_dict.json into the catalogue
npm run sync:udb      # extension metadata from riscv-unified-db
npm run sync:params -- <path-to-riscv-unified-db>
npm run sync:instruction-metadata -- <path-to-riscv-unified-db>
npm run sync:intrinsics -- <rvv-intrinsic-doc> <riscv-c-api-doc>
npm run sync:references -- <sail-riscv> <riscv-isa-sim> <riscv-arch-test>
npm run sync:toolchains                       # fetches LLVM, GCC, binutils, QEMU and Linux sources
node scripts/sync-profile-optional.mjs <path-to-riscv-unified-db>
node scripts/seed-dependency-graph.mjs --udb <path-to-riscv-unified-db>
node scripts/map-doc-links.mjs                # documentation links

Or check for drift without writing anything:

npm run sync:check
npm run sync:instruction-metadata:check   # expects riscv-unified-db beside this repo
npm run sync:references:check -- <sail-riscv> <riscv-isa-sim> <riscv-arch-test>
npm run graph:check -- <path-to-riscv-unified-db>
npm run links:check
npm run opcodes:check -- <path-to-riscv-opcodes>
npm run udb:check -- <path-to-riscv-unified-db> [--published]   # ratified extensions/instructions we lack; --published also checks drafts we list

map-doc-links.mjs reads the ISA manual and profile pages on docs.riscv.org and links each extension to the page that names it. Entries no page names keep a hand-written link to their specification's repository.

What updates itself, and what does not

how it refreshes
extension metadata, CSRs, ratification state the sync-udb-extensions workflow, Mondays at 06:00 UTC, opens or updates a PR when a file changes
the published site any push to main rebuilds and publishes to gh-pages
static extension pages and sitemap.xml generated from the catalogue on every build, for search engines and AI crawlers; nothing to run by hand
toolchain support the sync-toolchain-support workflow, the 1st of each month at 10:00 UTC, opens or updates a PR when a new Clang, GCC, binutils, QEMU or Linux release ships or an extension's standing changes
Sail, Spike and ACT links the sync-reference-impls workflow, Mondays at 08:00 UTC, opens or updates a PR when an instruction gains or loses a link; new upstream commits alone do not, since the links are pinned
instruction encodings by hand. The check-opcodes-drift workflow, Mondays at 07:00 UTC, files an issue when upstream is ahead, or carries different bits under a name we list (drafts included)
new extensions by hand. The weekly sync only enriches entries we already have; the check-udb-completeness workflow, Mondays at 09:00 UTC, keeps one issue updated with what riscv-unified-db has and we do not

src/instr_dict.json is hand-maintained on purpose and is not regenerated from riscv-opcodes. It carries entries upstream does not: 252 expanded vector segment load/store forms, which riscv-opcodes does not express individually, and the MOP and C.MOP encodings expanded from upstream's three _n templates. A regenerate would delete them, so the drift check reports and leaves the decision to a person.

It compares mnemonics rather than encodings, ignores upstream's $pseudo_op aliases (mv is addi rd, rs, 0, an encoding we already carry), and counts extensions/unratified/ separately rather than treating drafts as gaps to fill.

Code layout

file responsibility
src/risc_v_visualizer.jsx the main view
src/ExtensionTile.jsx a single extension tile, memoised per tile
src/WorkspacePanel.jsx the ISA Configuration Builder panel
src/isaGraph.js dependency resolution: resolveSelection, closure, explain, validateGraph
src/marchUtils.js -march assembly and canonical ordering
src/exportUtils.js YAML and UDB configuration export
src/profiles.js profile definitions
src/profileExport.js profile membership (mandatory, implied, optional) and the profile download
src/CompareView.jsx, src/compareModel.js side-by-side comparison
src/EncodingMap.jsx, src/encodingMap.js the opcode-space map
src/SandboxPanel.jsx, src/sandboxModel.js the Custom Extension Sandbox
scripts/static-pages.mjs the per-extension static pages and sitemap, run by the build

AGENTS.md has the full map and the gotchas.

Tests

npm test

CI runs the tests, builds, then validates generated -march strings with both the distro clang and clang 21. The modern job covers every profile and every ratified catalogue entry; its small CLANG21_UNSUPPORTED allowlist is checked for staleness on every run. The suite covers dependency closure, graph integrity, profile correctness, riscv-config conventions, export formats, documentation links, and a jsdom smoke test that fails if the page renders blank.

Adding an extension

Add an entry to the appropriate group in src/riscv_extensions.json:

{
  "id": "Zfoo",
  "name": "Zfoo",
  "tags": ["rv_zfoo"],
  "desc": "Short description",
  "use": "What it enables",
  "url": "https://docs.riscv.org/reference/..."
}
  • tags are riscv-opcodes extension names. Instruction membership is derived from them, so a wrong tag produces a wrong instruction count.
  • url points at the extension's page on docs.riscv.org, or at its specification's source when docs.riscv.org does not carry it; npm run links:check verifies it resolves.
  • discontinued: 1 adds the "Discontinued" badge.

Then add a graph node, or the tests fail:

node scripts/seed-dependency-graph.mjs --udb <path-to-riscv-unified-db>
npm test

Adding an instruction

Encodings live in src/instr_dict.json, keyed by the mnemonic lowercased with . replaced by _, so SC.W becomes sc_w:

"sc_w": {
  "encoding": "00011------------010-----0101111",
  "variable_fields": ["rd", "rs1", "rs2", "aq", "rl"],
  "extension": ["rv_a"],
  "match": "0x1800202f",
  "mask": "0xf800707f"
}

The extension values match the tags on a catalogue entry, and that is what places the instruction. Merge it in and verify:

npm run sync
npm test && npm run build

Encoder Validator

The Encoder Validator in the header checks a proposed encoding against every instruction in the database. Give it either a 32-bit pattern of 0, 1 and -, or a match and mask pair in hex; supplying both cross-checks them against each other.

Overlaps are reported as identical, proposed_subset_of_existing, existing_subset_of_proposed, or partial_overlap, each with a plain-language reason and an example 32-bit word that satisfies both patterns.

Encoding Map

The Encoding Map, also in the header, answers the question the extension list cannot: how much of the base encoding space is spoken for. It lays the 32 opcode slots out as the ISA manual does, rows inst[4:2] and columns inst[6:5], with every cell implying inst[1:0]=11, and shades each by occupancy on a log scale. Compressed instructions sit outside that grid and are summarised by quadrant. Selecting a cell lists its instructions and links through to the extensions that define them.

It is computed from src/riscv_extensions.json at runtime, so there is nothing to regenerate: sync the catalogue and the map follows.

Deployment

Every push to main is built by CI and published to the gh-pages branch, which GitHub Pages serves at tech.riscv.org/isa-explorer. Nothing is published by hand. Releases are tagged and described in CHANGELOG.md.

Contributing

Contributions are welcome, data corrections especially. See CONTRIBUTING.md for setup, the invariants the tests enforce, and the sign-off requirement.

All commits must be signed off under the Developer Certificate of Origin:

git commit -s

Participation is governed by our Code of Conduct. To report a vulnerability, see SECURITY.md.

Licence

Apache License 2.0.

About

A simple and intuitive approach to visualize RISC-V Extensions and Profiles.

Resources

Code of conduct

Contributing

Security policy

Stars

34 stars

Watchers

0 watching

Forks

Releases

Used by

Contributors

Languages