diff --git a/.github/workflows/docs-preview.yml b/.github/workflows/docs-preview.yml new file mode 100644 index 0000000000..f1b27c09ba --- /dev/null +++ b/.github/workflows/docs-preview.yml @@ -0,0 +1,46 @@ +name: Docs Preview +on: + push: + branches: [doc_next] + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: "docs-preview" + cancel-in-progress: true + +jobs: + build-and-deploy: + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + submodules: recursive + + - name: Install Node dependencies + run: npm ci + + - name: Build Docusaurus site + env: + DOCUSAURUS_URL: https://dhower-qc.github.io + DOCUSAURUS_BASE_URL: /riscv-unified-db/ + run: npm run build --workspace=doc + + - name: Setup Pages + uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0 + + - name: Upload Pages artifact + uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4.0.0 + with: + path: doc/build + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5 diff --git a/.github/workflows/regress.yml b/.github/workflows/regress.yml index 6978619a12..66df38d17b 100644 --- a/.github/workflows/regress.yml +++ b/.github/workflows/regress.yml @@ -762,6 +762,15 @@ jobs: uses: "./.github/actions/mise-setup" - name: Check schema versions against published URLs run: "./do gen:schemas && ./bin/ruby tools/scripts/check_schema_versions.rb" + regress-schema-docs: + runs-on: ubuntu-latest + steps: + - name: Clone Github Repo Action + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + - name: Set up mise environment + uses: "./.github/actions/mise-setup" + - name: Generate schema documentation + run: "./bin/chore gen -f schema-docs" build-idl-doc: runs-on: ubuntu-latest if: (github.event_name == 'merge_group') || ((github.event_name == 'push') && (github.ref_name == 'main')) @@ -864,6 +873,7 @@ jobs: - build-instruction-appendix - build-profile - regress-schema-versions + - regress-schema-docs - build-idl-doc - check-gem-versions - regress-smoke-perf diff --git a/.mise.toml b/.mise.toml index c311e352a5..5e0bc22206 100644 --- a/.mise.toml +++ b/.mise.toml @@ -16,9 +16,6 @@ shellcheck = "0.11.0" [env] RUBY_YJIT_ENABLE = "1" -# Prevent Bundler from modifying lockfiles during normal commands (e.g. bundle exec). -# Lockfiles are only updated explicitly via `bundle lock` / `bundle install`. -BUNDLE_FROZEN = "1" # Disable the CHECKSUMS section in lockfiles — checksums can't be fully populated # across all platforms (e.g. aarch64 variants on an x86 machine) so we opt out entirely. BUNDLE_LOCKFILE_CHECKSUMS = "false" diff --git a/Gemfile b/Gemfile index 26282375f2..4f75998793 100644 --- a/Gemfile +++ b/Gemfile @@ -4,9 +4,12 @@ ruby "~> 3.2" source "https://rubygems.org" -# local gems in UDB +# external gems (published/publishable) gemspec path: "tools/ruby-gems/idlc" gemspec path: "tools/ruby-gems/idl_highlighter" gemspec path: "tools/ruby-gems/udb" gemspec path: "tools/ruby-gems/udb-gen" gemspec path: "tools/ruby-gems/udb_helpers" + +# internal gems (build/tooling only) +gemspec path: "tools/internal-gems/schema_doc_gen" diff --git a/Gemfile.lock b/Gemfile.lock index dbef6916f1..53378d32d4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,3 +1,10 @@ +PATH + remote: tools/internal-gems/schema_doc_gen + specs: + schema_doc_gen (0.1.0) + tty-exit + tty-option + PATH remote: tools/ruby-gems/idl_highlighter specs: @@ -114,6 +121,7 @@ GEM drb (2.2.3) erb (6.0.2) erubi (1.13.1) + ffi (1.17.4-aarch64-linux-gnu) ffi (1.17.4-x86_64-linux-gnu) hana (1.3.7) hashery (2.1.2) @@ -263,6 +271,7 @@ GEM sorbet (0.6.13096) sorbet-static (= 0.6.13096) sorbet-runtime (0.6.13096) + sorbet-static (0.6.13096-aarch64-linux) sorbet-static (0.6.13096-x86_64-linux) sorbet-static-and-runtime (0.6.13096) sorbet (= 0.6.13096) @@ -352,6 +361,7 @@ DEPENDENCIES rubocop-sorbet ruby-lsp ruby-prof + schema_doc_gen! simplecov simplecov-cobertura sorbet @@ -363,7 +373,6 @@ DEPENDENCIES yard yard-sorbet - RUBY VERSION ruby 3.4.8 diff --git a/README.adoc b/README.adoc index 59751c48d1..e73b461cbd 100644 --- a/README.adoc +++ b/README.adoc @@ -2,6 +2,12 @@ image::doc/udb.svg[UDB banner] image::https://api.reuse.software/badge/github.com/riscv/riscv-unified-db[REUSE status, link="https://api.reuse.software/info/github.com/riscv/riscv-unified-db"] +[NOTE] +---- +A new from-scratch documentation site for this project is under construction. +It is available at https://riscv.github.io/riscv-unified-db/docs-preview/[riscv.github.io/riscv-unified-db/docs-preview]. +Content is incomplete and actively being developed, but is likely still helpful. +---- [WARNING] ---- diff --git a/REUSE.toml b/REUSE.toml index f933aaaf57..b13f68e213 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -78,9 +78,10 @@ SPDX-License-Identifier = "CC0-1.0" [[annotations]] path = [ - "doc/package.json", - "doc/tsconfig.json", - "doc/**/*.mdx" + "doc/**/*.json", + "doc/**/*.mdx", + "doc/**/*.md", + "tools/internal-gems/README.md" ] SPDX-FileCopyrightText = "Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries." SPDX-License-Identifier = "BSD-3-Clause-Clear" diff --git a/backends/proc_crd/tasks.rake b/backends/proc_crd/tasks.rake index 217a6d9308..3d7cea8492 100644 --- a/backends/proc_crd/tasks.rake +++ b/backends/proc_crd/tasks.rake @@ -7,6 +7,8 @@ require "pathname" PROC_CRD_DOC_DIR = Pathname.new "#{$root}/backends/proc_crd" PROC_CRD_GEN_DIR = $resolver.gen_path / "proc_crd" +UDB_GEM_SRC = $root / "tools/ruby-gems/udb" + Dir.glob("#{$resolver.std_path}/proc_cert_model/*.yaml") do |f| model_name = File.basename(f, ".yaml") model_obj = YAML.load_file(f, permitted_classes: [Date]) @@ -17,9 +19,9 @@ Dir.glob("#{$resolver.std_path}/proc_cert_model/*.yaml") do |f| __FILE__, "#{$resolver.std_path}/proc_cert_class/#{class_name}.yaml", "#{$resolver.std_path}/proc_cert_model/#{model_name}.yaml", - "#{Udb.gem_path}/lib/udb/obj/certificate.rb", - "#{Udb.gem_path}/lib/udb/obj/portfolio.rb", - "#{Udb.gem_path}/lib/udb/portfolio_design.rb", + "#{UDB_GEM_SRC}/lib/udb/obj/certificate.rb", + "#{UDB_GEM_SRC}/lib/udb/obj/portfolio.rb", + "#{UDB_GEM_SRC}/lib/udb/portfolio_design.rb", "#{$root}/backends/portfolio/templates/ext_appendix.adoc.erb", "#{$root}/backends/portfolio/templates/inst_appendix.adoc.erb", "#{$root}/backends/portfolio/templates/csr_appendix.adoc.erb", diff --git a/backends/proc_ctp/tasks.rake b/backends/proc_ctp/tasks.rake index ceda992f00..644a875695 100644 --- a/backends/proc_ctp/tasks.rake +++ b/backends/proc_ctp/tasks.rake @@ -7,6 +7,8 @@ require "pathname" PROC_CTP_DOC_DIR = Pathname.new "#{$root}/backends/proc_ctp" PROC_CTP_GEN_DIR = $resolver.gen_path / "proc_ctp" +UDB_GEM_SRC ||= $root / "tools/ruby-gems/udb" + Dir.glob("#{$resolver.std_path}/proc_cert_model/*.yaml") do |f| model_name = File.basename(f, ".yaml") model_obj = YAML.load_file(f, permitted_classes: [Date]) @@ -17,9 +19,9 @@ Dir.glob("#{$resolver.std_path}/proc_cert_model/*.yaml") do |f| __FILE__, "#{$resolver.std_path}/proc_cert_class/#{class_name}.yaml", "#{$resolver.std_path}/proc_cert_model/#{model_name}.yaml", - "#{Udb.gem_path}/lib/udb/obj/certificate.rb", - "#{Udb.gem_path}/lib/udb/obj/portfolio.rb", - "#{Udb.gem_path}/lib/udb/portfolio_design.rb", + "#{UDB_GEM_SRC}/lib/udb/obj/certificate.rb", + "#{UDB_GEM_SRC}/lib/udb/obj/portfolio.rb", + "#{UDB_GEM_SRC}/lib/udb/portfolio_design.rb", "#{$root}/backends/portfolio/templates/ext_appendix.adoc.erb", "#{$root}/backends/portfolio/templates/inst_appendix.adoc.erb", "#{$root}/backends/portfolio/templates/csr_appendix.adoc.erb", diff --git a/backends/profile/tasks.rake b/backends/profile/tasks.rake index 45ad75d3d8..accc5db65d 100644 --- a/backends/profile/tasks.rake +++ b/backends/profile/tasks.rake @@ -10,6 +10,9 @@ require "udb/portfolio_design" PROFILE_DOC_DIR = Pathname.new "#{$root}/backends/profile" PROFILE_GEN_DIR = $resolver.gen_path / "profile" +UDB_GEM_SRC ||= $root / "tools/ruby-gems/udb" +UDB_HELPERS_GEM_SRC = $root / "tools/ruby-gems/udb_helpers" + Dir.glob("#{$resolver.std_path}/profile_release/*.yaml") do |f| release_name = File.basename(f, ".yaml") release_obj = YAML.load_file(f, permitted_classes: [Date]) @@ -29,10 +32,10 @@ Dir.glob("#{$resolver.std_path}/profile_release/*.yaml") do |f| __FILE__, "#{$resolver.std_path}/profile_family/#{family_name}.yaml", "#{$resolver.std_path}/profile_release/#{release_name}.yaml", - "#{Udb.gem_path}/lib/udb/obj/profile.rb", - "#{Udb.gem_path}/lib/udb/obj/portfolio.rb", - "#{Udb.gem_path}/lib/udb/portfolio_design.rb", - "#{Udb::Helpers.gem_path}/lib/udb_helpers/backend_helpers.rb", + "#{UDB_GEM_SRC}/lib/udb/obj/profile.rb", + "#{UDB_GEM_SRC}/lib/udb/obj/portfolio.rb", + "#{UDB_GEM_SRC}/lib/udb/portfolio_design.rb", + "#{UDB_HELPERS_GEM_SRC}/lib/udb_helpers/backend_helpers.rb", "#{$root}/backends/portfolio/templates/ext_appendix.adoc.erb", "#{$root}/backends/portfolio/templates/inst_appendix.adoc.erb", "#{$root}/backends/portfolio/templates/csr_appendix.adoc.erb", diff --git a/bin/chore b/bin/chore index 519b8342a1..21bffb54d9 100755 --- a/bin/chore +++ b/bin/chore @@ -110,6 +110,7 @@ gen_subcmd_usage() { echo " vscode-idl: Generate tools/vscode/idl/syntaxes/idl.tmLanguage.json" echo " regress: Generate .github/workflows/regress.yml" echo " ruby-type-def: Generate Ruby type signatutres" + echo " schema-docs: Generate schema documentation from JSON Schema files" echo " xqci Generate Xqci spec used for Golden regressions" echo "" } @@ -297,29 +298,27 @@ do_gen_vscode_idl() { } # -# Lock all Gemfiles with consistent platforms. +# Generate schema documentation from JSON Schema files # -# The root Gemfile is a union of all per-gem gemspecs and is used as the -# authoritative dependency resolution context. It must be locked first so that -# when Bundler locks each per-gem Gemfile (which runs under `bundle exec` from -# the root context), it resolves transitive dependencies (e.g. activesupport, -# sorbet) to the same versions as the root. If the per-gem locks ran first, -# they could resolve to different versions and diverge from the root, causing -# failures in tools like sorbet that compare the installed gem version against -# committed RBI files. -# -# Args: extra args to pass to each `bundle lock` call (e.g. --update --bundler) -# -do_lock_all_gemfiles() { - # Always include both x86_64 and aarch64 Linux platforms so lock files are - # valid on both architectures. - local platforms="--add-platform x86_64-linux --add-platform x86_64-linux-gnu --add-platform aarch64-linux --add-platform aarch64-linux-gnu" - # BUNDLE_GEMFILE must be set to match --gemfile so that Bundler writes PATH - # remote: entries relative to the correct directory. - # Note: `bundle lock` (not `bundle exec bundle lock`) is used deliberately — - # `bundle exec` requires an existing lockfile to activate the bundle first, - # which breaks when lockfiles are missing or being regenerated from scratch. - env BUNDLE_GEMFILE="${UDB_ROOT}"/Gemfile "${UDB_ROOT}"/bin/bundle lock $platforms "$@" --gemfile "${UDB_ROOT}"/Gemfile +do_gen_schema_docs() { + source_setup + echo "Generating schema documentation" + if [ $fail_on_change -eq 1 ]; then + # Calculate checksum before generation + local sha_before + sha_before=$(find "$UDB_ROOT"/doc/docs/schemas -type f -name "*.mdx" -exec sha256sum {} \; 2>/dev/null | sort | sha256sum) + fi + $RUBY -I tools/internal-gems/schema_doc_gen/lib tools/internal-gems/schema_doc_gen/bin/schema-docs-all \ + --schema-dir "$UDB_ROOT/spec/schemas" \ + --output-dir "$UDB_ROOT/doc/docs/schemas" \ + --generate-index + if [ $fail_on_change -eq 1 ]; then + local sha_after + sha_after=$(find "$UDB_ROOT"/doc/docs/schemas -type f -name "*.mdx" -exec sha256sum {} \; 2>/dev/null | sort | sha256sum) + if [ "$sha_before" != "$sha_after" ]; then + exit 1 + fi + fi } # @@ -340,7 +339,6 @@ do_gen_gem_versions() { fi } -# # Auto-increment versions for gems with source changes (with cascade), # then sync inter-gem version pins in gemspecs and Gemfile.lock. # Args: $1 - base ref (optional; defaults to origin/main) @@ -364,6 +362,7 @@ do_gen_all() { do_gen_gem_versions do_ruby_type_def all do_gen_xqci_golden + do_gen_schema_docs } # @@ -586,6 +585,10 @@ case "$subcommand" in do_gen_regress exit 0 ;; + schema-docs ) + do_gen_schema_docs + exit 0 + ;; xqci ) do_gen_xqci_golden exit 0 diff --git a/doc/docs/concepts/_category_.json b/doc/docs/concepts/_category_.json new file mode 100644 index 0000000000..a6d44ffb8c --- /dev/null +++ b/doc/docs/concepts/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "Concepts", + "position": 2, + "link": { + "type": "generated-index", + "description": "Core concepts for working with the RISC-V Unified Database." + } +} diff --git a/doc/docs/concepts/configurations/_category_.json b/doc/docs/concepts/configurations/_category_.json new file mode 100644 index 0000000000..1a568a0d22 --- /dev/null +++ b/doc/docs/concepts/configurations/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "Configurations", + "position": 1, + "link": { + "type": "generated-index", + "description": "Understanding configuration files in UDB." + } +} diff --git a/doc/docs/concepts/configurations/overview.md b/doc/docs/concepts/configurations/overview.md new file mode 100644 index 0000000000..c512bccc06 --- /dev/null +++ b/doc/docs/concepts/configurations/overview.md @@ -0,0 +1,123 @@ +--- +sidebar_position: 1 +status: in-progress +--- + +# Configurations Overview + +:::warning[Status: In Progress] +This documentation is partially complete. Some sections may be missing or outdated. +::: + +A **configuration** is a YAML file that describes a RISC-V system or family of systems by specifying which extensions are implemented, what their parameter values are, and how implementation-defined behavior is resolved. Configurations control how UDB generates artifacts — from fully general tools to highly specialized ISS code — and also provide a **standard machine-readable format** for precisely describing RISC-V implementations (used, for example, in RISC-V certification applications). + +Configurations are also where **spec overlays** are enabled, allowing vendor-specific customizations to be applied on top of the standard specification data (see [The Data Pipeline](../data-pipeline/overview.md)). + +:::tip Schema Reference +For the complete technical schema definition including all fields and validation rules, see the [Configuration Schema Reference](/docs/schemas/v0.1/config_schema). +::: + +## Why Configurations Exist + +The RISC-V ISA is highly modular and leaves many details up to implementers: + +- **Extension selection**: Does this system support floating-point? Vector? Compressed instructions? +- **MXLEN**: Is this a 32-bit or 64-bit M-mode machine (or does it support both)? +- **Parameters**: How wide is the physical address space? Are misaligned accesses supported? What exceptions are reported in `mtval`? +- **Optional features**: Is the `misa` CSR implemented? Can extensions be dynamically enabled/disabled? + +UDB's specification data describes **all possible behaviors** across the entire RISC-V design space. A configuration lets you specify **how much you know** about the target system — from nothing (the full design space) to everything (a specific implementation) — and UDB generates artifacts appropriate to that level of specificity. + +## The Three Types of Configurations + +UDB supports three levels of specificity, each serving different use cases: + +### 1. Fully Configured (`type: fully configured`) + +**Specifies every parameter and extension** — represents a single concrete implementation. + +Every implementation-defined choice is pinned to a value. This is what you use to model a real hardware design or generate an ISS for a specific chip. + +**Example**: `cfgs/mc100-32-full-example.yaml` — a complete MC100-32 processor configuration with all extensions, parameters, and CSR behaviors fully specified. + +**Use cases**: +- Generating a configuration-specific ISS for a shipping product +- Producing documentation for a specific chip +- Validating that a design conforms to a RISC-V profile +- Submitting a design for certification + +**Key property**: All IDL code can be fully evaluated and optimized; no unknowns remain. Generated artifacts are tailored to this exact configuration. + +### 2. Partially Configured (`type: partially configured`) + +**Specifies some parameters and extensions, leaving others unspecified** — represents a family of implementations that share common characteristics. + +**Example**: `cfgs/rv32.yaml` — specifies `MXLEN: 32` and requires the `I` and `Sm` extensions, but leaves all other parameters and optional extensions unspecified. This describes "any RV32 system." + +**Use cases**: +- Generating documentation or test suites that apply to a range of implementations +- Building tools for a product line or processor family +- Exploring "what if" scenarios (e.g., "what instructions are available if we add the `V` extension?") +- Defining a baseline for vendor-specific customization + +**Key property**: Some IDL expressions can be evaluated (those depending only on known parameters), but code paths that depend on unknown parameters remain conditional. Generated artifacts must handle the full range of possibilities for unspecified parameters. + +### 3. Unconfigured (`type: unconfigured`) + +**Specifies nothing** — represents the entire RISC-V design space with no constraints. + +The special configuration **`_`** (underscore) is the canonical unconfigured architecture. + +**Example**: `cfgs/_.yaml` — describes "any RVI-standard architecture" with no parameters set, not even `MXLEN`. + +**Use cases**: +- Generating the full RISC-V specification manual (covering all possible behaviors) +- Building general-purpose tooling that works across all RISC-V systems (assemblers, disassemblers, debuggers) +- Studying the full scope of the ISA without implementation assumptions +- Generating schemas and abstract models + +**Key property**: No IDL expressions can be evaluated at compile time; all parameter-dependent behavior must be preserved in generated artifacts. Generated code must be maximally generic. + +## Configuration File Structure + +All configuration files share a common YAML structure: + +```yaml +$schema: config_schema.json# +kind: architecture configuration +type: fully configured | partially configured | unconfigured +name: MyConfig +description: A brief description of this configuration + +# Full configs only: exact extensions and versions +implemented_extensions: # Omit for partial/unconfigured + - [ExtName, "version"] + +# Partial configs only: minimum extension requirements +mandatory_extensions: # Omit for full/unconfigured + - name: "ExtName" + version: ">= min_version" + +# All configs: parameter values +params: # Omit for unconfigured + PARAM_NAME: value + +# Optional: spec overlay directory +arch_overlay: path/to/overlay # See Config File Format and Data Pipeline +``` + +:::note +`arch_overlay` is the current name for the spec overlay feature. This will be renamed to `spec_overlay` in a future version for clarity. +::: + +See [Config File Format](./config-file-format.md) for the complete reference. + +## What's Next + +More detailed documentation on configurations is coming soon, including: + +- Full Configurations — Detailed format and examples +- Partial Configurations — Specifying requirements without full detail +- Unconfigured — The `_` config and when to use it +- Config File Format — Complete YAML reference +- Validating Configs — Checking compliance and catching errors diff --git a/doc/docs/developer/tools-overview.mdx b/doc/docs/developer/tools-overview.mdx new file mode 100644 index 0000000000..df0a962b08 --- /dev/null +++ b/doc/docs/developer/tools-overview.mdx @@ -0,0 +1,25 @@ +--- +title: Tools & Directory Structure +sidebar_position: 1 +status: in-progress +--- + +import InternalGemsReadme from '../../../tools/internal-gems/README.md'; + +:::warning[Status: Incomplete] +This documentation is under construction. +::: + +UDB provides various tools for working with the database, including published Ruby gems and internal build tools. + +## Tool Organization + + + +## Command-Line Tools + +- **`bin/generate`** - Language-agnostic wrapper for all generators +- **`bin/regress`** - Regression test runner +- **`bin/chore`** - Repository maintenance and build automation + +See the individual tool documentation pages for detailed usage information. diff --git a/doc/docs/idl/builtins.mdx b/doc/docs/idl/builtins.mdx index e7c01df247..32e0139b37 100644 --- a/doc/docs/idl/builtins.mdx +++ b/doc/docs/idl/builtins.mdx @@ -16,10 +16,10 @@ Two special variables give access to the current instruction's context. They are ```idl # $pc: use the current PC to compute a branch target -jump(PC + $signed(imm)); +jump($pc + $signed(imm)); # $encoding: pass the current instruction encoding to a memory access -X[xd] = read_memory<32>(virtual_address, $encoding); +X[xd] = read_memory(32, virtual_address, $encoding); # raise() uses $encoding as the tval for illegal instruction exceptions raise(ExceptionCode::IllegalInstruction, mode(), $encoding); diff --git a/doc/docs/idl/common-misunderstandings.mdx b/doc/docs/idl/common-misunderstandings.mdx index b30c97830a..06f9a511b1 100644 --- a/doc/docs/idl/common-misunderstandings.mdx +++ b/doc/docs/idl/common-misunderstandings.mdx @@ -37,7 +37,7 @@ See [Naming Rules](./variables#naming-rules). `if (x)` is a compilation error. An `if` condition must have type `Boolean`. You must write an explicit comparison: ```idl -XReg src1 = X[rs1]; +XReg src1 = X[xs1]; if (src1 != 0) { ... } # correct # if (src1) { ... } # compilation error @@ -135,7 +135,7 @@ A Verilog-style literal with an explicit width that is too narrow to hold the va ```idl Bits<4> x = 4'd-1; # -1 in 4 bits = 0b1111 = 15 (unsigned) — OK -Bits<3> y = 3'd-1; # truncates to 3 bits: 0b111 = 7 — sign bit lost +Bits<3> y = 4'd-1; # truncates to 3 bits: 0b111 = 7 — sign bit lost ``` When encoding negative values, ensure the width is sufficient to hold the sign bit. Or use the 2's complement positive equivalent: diff --git a/doc/docs/idl/control-flow.mdx b/doc/docs/idl/control-flow.mdx index 708299a02c..e90a4d04f8 100644 --- a/doc/docs/idl/control-flow.mdx +++ b/doc/docs/idl/control-flow.mdx @@ -13,7 +13,7 @@ An `if` statement condition must be a `Boolean` type. Unlike C, a non-zero integer does **not** count as `true`. Using an integer directly as a condition is a compilation error — you must write an explicit comparison: ```idl -XReg src1 = X[rs1]; +XReg src1 = X[xs1]; if (src1 != 0) { ... } # correct: explicit comparison # if (src1) { ... } # compilation error: src1 is not Boolean diff --git a/doc/docs/idl/data-types.mdx b/doc/docs/idl/data-types.mdx index 1bb8e75999..a142ce4e3f 100644 --- a/doc/docs/idl/data-types.mdx +++ b/doc/docs/idl/data-types.mdx @@ -1,8 +1,13 @@ --- sidebar_position: 2 title: Data Types +status: complete --- +:::info[Status: Complete] +This documentation is complete and ready to use. +::: + IDL has the following types: - **Primitive** diff --git a/doc/docs/idl/for-spec-writers.mdx b/doc/docs/idl/for-spec-writers.mdx index 858e40e4df..cf9ef6e0e0 100644 --- a/doc/docs/idl/for-spec-writers.mdx +++ b/doc/docs/idl/for-spec-writers.mdx @@ -13,15 +13,15 @@ IDL source files use the `.idl` extension and live alongside the YAML/ADOC defin ## Anatomy of an `operation()` body -Every instruction has an `operation()` block. Decode fields (`rd`, `rs1`, `rs2`, `imm`, etc.) are injected automatically from the instruction encoding before the body runs — you do not declare them: +Every instruction has an `operation()` block. Decode fields (`xd`, `xs1`, `xs2`, `imm`, etc.) are defined in scope automatically from the instruction encoding before the body runs — you do not declare them: ```idl -# From: arch/inst/I/add.yaml +# From: spec/std/isa/inst/I/add.yaml # operation(): -Bits src1 = X[rs1]; # rs1 is a decode field — already available -Bits src2 = X[rs2]; # rs2 likewise -X[rd] = src1 + src2; # write result to destination register +Bits src1 = X[xs1]; # xs1 is a decode field — already available +Bits src2 = X[xs2]; # xs2 likewise +X[xd] = src1 + src2; # write result to destination register ``` The `operation()` body runs sequentially. When it returns, the instruction is complete and the PC advances to the next instruction (unless `jump()` or `raise()` was called). @@ -31,8 +31,8 @@ The `operation()` body runs sequentially. When it returns, the instruction is co ### Reading and writing x registers ```idl -Bits src = X[rs1]; # read -X[rd] = result; # write (writes to x0 are silently discarded) +Bits src = X[xs1]; # read +X[xd] = result; # write (writes to x0 are silently discarded) ``` When `MXLEN != XLEN`, writes are automatically sign-extended to `MXLEN` and reads ignore the upper bits. You do not need to handle this manually. @@ -57,7 +57,7 @@ if (implemented?(ExtensionName::C) && CSR[misa].C == 1'b1) { } ``` -Use `implemented?()` for static (compile-time) presence checks and `CSR[misa]` for dynamic enable/disable via software. +Use `implemented?()` for static (compile-time) checks of whether an extension is implemented and `CSR[misa]` for dynamic (runtime) checks of whether an extension is enabled. ### Raising exceptions @@ -71,27 +71,28 @@ raise(ExceptionCode::LoadAddressMisaligned, vaddr); # with tval ### Memory access ```idl -Bits<32> word = read_memory<32>(vaddr, $encoding); # load 32-bit word -write_memory<64>(vaddr, value, $encoding); # store 64-bit value +Bits<32> word = read_memory(32, vaddr, $encoding); # load 32-bit word +write_memory(64, vaddr, value, $encoding); # store 64-bit value ``` -The template parameter is the access width in bits. `$encoding` passes the raw instruction word for trapping purposes. +The first argument is the access width in bits. `$encoding` passes the raw instruction word for trapping purposes. ### Jumping ```idl -jump(PC + $signed(imm)); # PC-relative jump -jump(target); # absolute jump +jump($pc + $signed(imm)); # PC-relative jump +jump(target); # absolute jump (word-aligned) +jump_halfword(target); # halfword-aligned jump (for C extension) ``` -`jump()` is a standard IDL function defined in the global scope. It validates alignment and raises `InstructionAddressMisaligned` if needed. +`jump()` is a standard IDL function defined in the global scope. It validates alignment and raises `InstructionAddressMisaligned` if needed. Use `jump_halfword()` when the target may be halfword-aligned (e.g., for compressed instructions in the C extension). ### Sign-extending immediates Immediates decoded from instruction fields are `Bits` — unsigned by default. Use `$signed()` when you need them treated as signed in arithmetic: ```idl -X[rd] = X[rs1] + $signed(imm); # sign-extend imm before adding +X[xd] = X[xs1] + $signed(imm); # sign-extend imm before adding ``` ## Writing CSR callbacks diff --git a/doc/docs/idl/functions.mdx b/doc/docs/idl/functions.mdx index 9809d2345f..e848b13a6d 100644 --- a/doc/docs/idl/functions.mdx +++ b/doc/docs/idl/functions.mdx @@ -9,7 +9,7 @@ Functions are called using standard call syntax. Arguments are passed positional ```idl jump(PC + $signed(imm)); # void function call -Bits<32> val = read_memory<32>(vaddr, $encoding); # call with return value +Bits<32> val = read_memory(32, vaddr, $encoding); # call with return value ``` All arguments are passed **by value**. There are no references. @@ -89,7 +89,7 @@ function NAME { **Pass by value — no references or pointers** -All arguments and return values are passed by value. There are no references, pointers, or heap allocation in IDL. This follows directly from what IDL describes: all architectural state — registers, CSRs, memory — is accessed via built-in syntax (`X[rs1]`, `CSR[mstatus]`, `read_memory`), not through addresses. Since there is no general-purpose addressable memory for local variables, references have no meaning in IDL's execution model. +All arguments and return values are passed by value. There are no references, pointers, or heap allocation in IDL. This follows directly from what IDL describes: all architectural state — registers, CSRs, memory — is accessed via built-in syntax (`X[xs1]`, `CSR[mstatus]`, `read_memory`), not through addresses. Since there is no general-purpose addressable memory for local variables, references have no meaning in IDL's execution model. **Functions live in global scope and cannot be nested** @@ -97,7 +97,7 @@ All functions are declared at the top level of `.idl` files. Nesting functions w **No function pointers** -Functions have no address and cannot be assigned to a variable. Dynamic dispatch requires runtime indirection, which is incompatible with static hardware description and the backends IDL targets. +Functions have no address and cannot be assigned to a variable. Dynamic dispatch requires runtime indirection, which is incompatible with static hardware description and the targets that consume IDL (backends such as instruction set simulators, formal verification tools, and hardware generators). **No recursion** @@ -112,7 +112,7 @@ Builtin functions are used for: 1. Functionality that is not architecturally visible (e.g., prefetch an address). 2. Functionality that is highly implementation-dependent (e.g., fence). -Builtin functions look like a normal function but with the `builtin` keyword before `function` and no `body`: +Builtin functions look like normal functions but with the `builtin` keyword before `function` and no `body`: ```idl title="Builtin function definition" builtin function sfence_asid { diff --git a/doc/docs/idl/guide-for-c-users.mdx b/doc/docs/idl/guide-for-c-users.mdx index eb2d055404..6bd99814cc 100644 --- a/doc/docs/idl/guide-for-c-users.mdx +++ b/doc/docs/idl/guide-for-c-users.mdx @@ -61,7 +61,7 @@ x = x + 1; # end-of-line comment An `if` condition must be a `Boolean` type. Using an integer where a boolean is expected is a compilation error: ```idl -XReg src1 = X[rs1]; +XReg src1 = X[xs1]; if (src1 != 0) { ... } # correct # if (src1) { ... } # compilation error: not Boolean @@ -76,6 +76,20 @@ count = count + 1; mask = mask & 0xFF; ``` +### Post-increment/decrement in for loops only + +Post-increment (`i++`) and post-decrement (`i--`) are supported, but **only** in the update expression of a `for` loop on the iteration variable: + +```idl +for (U32 i = 0; i < 10; i++) { # valid: i++ in for loop update + # ... +} + +# count++; # compilation error: not allowed outside for loop update +``` + +Pre-increment (`++i`) and pre-decrement (`--i`) are not supported. + ### Assignment is a statement, not an expression You cannot use assignment inside a condition or as a subexpression: @@ -86,7 +100,10 @@ You cannot use assignment inside a condition or as a subexpression: # IDL form: x = read(); -if (x != 0) { ... } +while (x != 0) { + # ... process x ... + x = read(); +} ``` ### Case determines the kind of identifier @@ -111,7 +128,7 @@ SatpMode mode = SatpMode::Sv39; # correct ### No pointers, references, or heap allocation -All architectural state — registers, CSRs, memory — is accessed through built-in syntax (`X[rs1]`, `CSR[mstatus]`, `read_memory`). There is no general-purpose addressable memory for local variables, so references and pointers have no meaning. +All architectural state — registers, CSRs, memory — is accessed through built-in syntax (`X[xs1]`, `CSR[mstatus]`, `read_memory`). There is no general-purpose addressable memory for local variables, so references and pointers have no meaning. ### No recursion @@ -144,8 +161,10 @@ Verilog-style literals are the preferred form when the bit width matters. |---|-----| | `uint32_t x = 0;` | `Bits<32> x = 0;` | | `// comment` | `# comment` | +| `/* comment */` | Not supported | | `if (x) { }` | `if (x != 0) { }` | | `x += 1;` | `x = x + 1;` | +| `i++` | `i++` (for loop update only) | | `(int) x` | `$signed(x)` | | `A` (enum member) | `MyEnum::A` | | `struct Foo { ... };` | `struct Foo { ... }` (no `;`) | diff --git a/doc/docs/idl/guide-for-verilog-users.mdx b/doc/docs/idl/guide-for-verilog-users.mdx index c6440a16b1..8f11947629 100644 --- a/doc/docs/idl/guide-for-verilog-users.mdx +++ b/doc/docs/idl/guide-for-verilog-users.mdx @@ -5,7 +5,7 @@ title: IDL for Verilog Users IDL borrows heavily from Verilog and SystemVerilog: the bit-vector type model, Verilog-style numeric literals, bit-select and slice syntax, concatenation, and replication all work exactly as you would expect. If you have written RTL or verification code in Verilog or SV, the low-level data manipulation in IDL will feel immediately natural. -The key shift is one of abstraction level. Verilog describes how logic is connected and how signals propagate through gates over time. IDL describes what an instruction *does* at the ISA level — the architectural state before and after execution. There are no modules, no ports, no clocks, no `always` blocks. What replaces them is a sequential, behavioral model where functions read and write architectural state (registers, CSRs, memory) directly. +The key difference is the level of abstraction. Verilog describes how logic is connected and how signals propagate through gates over time. IDL describes what an instruction *does* at the ISA level — the architectural state before and after execution. There are no modules, no ports, no clocks, no `always` blocks. What replaces them is a sequential, behavioral model where functions read and write architectural state (registers, CSRs, memory) directly. ## What carries over @@ -97,7 +97,7 @@ Recursive functions are a compilation error. Use `for` loops for iteration. ### Widening operators for carry-free results -Standard arithmetic `+`, `-`, `*` truncate to the result width (like Verilog). IDL provides widening operators that produce a wider result to preserve carries and prevent overflow: +Standard arithmetic `+`, `-`, `*` truncate to the result width (like Verilog). IDL provides widening operators that produce a wider result to preserve carries and prevent truncation: | Operator | Result width | |----------|-------------| @@ -109,7 +109,7 @@ Standard arithmetic `+`, `-`, `*` truncate to the result width (like Verilog). I ```idl Bits<8> a = 200; Bits<8> b = 100; -Bits<9> sum = a `+ b; # 9-bit result; no overflow +Bits<9> sum = a `+ b; # 9-bit result; no truncation ``` ## Quick reference @@ -123,7 +123,7 @@ Bits<9> sum = a `+ b; # 9-bit result; no overflow | `{a, b}` concatenation | Same: `{a, b}` | | `struct packed { ... }` | `bitfield (N) Name { ... }` | | `typedef enum { A=0 } T;` | `enum T { A 0 }` (members uppercase) | -| `typedef struct { ... } T;` | `struct T { ... }` | +| `typedef struct { ... } T;` | `struct T { ... }` (note: no semicolon) | | `parameter WIDTH = 32;` | Compile-time constant (`MXLEN`, etc.) | | Parameterized modules | No templates — use constants | | `always_comb` blocks | `operation()` body in instruction defs | diff --git a/doc/docs/idl/idlc.md b/doc/docs/idl/idlc.md new file mode 100644 index 0000000000..67fe7c9836 --- /dev/null +++ b/doc/docs/idl/idlc.md @@ -0,0 +1,638 @@ +--- +sidebar_position: 15 +status: in-progress +--- + +# The IDL Compiler + +:::warning[Status: In Progress] +This documentation is partially complete. Some sections may be missing or outdated. +::: + +The IDL compiler (`idlc`) is the Ruby-based compiler that parses IDL source code, builds an abstract syntax tree (AST), performs type checking, and runs analysis passes to extract semantic information. This page describes how the compiler works internally — its architecture, compilation pipeline, and extension points for building custom analysis tools. + +:::info +This page is about **compiler internals**. For IDL language syntax, see the [Language Reference](./overview.mdx). For CLI usage and gem installation, see the Tools section. +::: + +## Overview + +The `idlc` compiler transforms IDL source code into a typed, analyzable AST. It is used throughout the UDB toolchain: + +- **During data resolution**: to compile instruction `operation()` bodies and CSR `sw_read()`/`sw_write()` functions +- **By generators**: to analyze instruction semantics (register dependencies, reachable functions, exception conditions) +- **For validation**: to type-check IDL code and report errors with precise file/line information + +You typically interact with `idlc` **indirectly** through UDB tools like `udb` and `udb-gen`, but you can also use it **programmatically** via its Ruby API to build custom analysis tools. + +## Compilation Pipeline + +The compiler processes IDL code in several phases: + +### 1. Parse + +The parser is generated from a [Treetop](https://github.com/nathansobo/treetop) PEG grammar (`idl.treetop`). It reads IDL source and produces a concrete syntax tree, reporting syntax errors with line/column precision if parsing fails. + +The grammar is automatically recompiled if `idl.treetop` is newer than the generated parser. + +### 2. AST Construction + +The concrete syntax tree is transformed into a semantic AST by calling `to_ast` on the root node. Each syntax node type knows how to construct its corresponding AST node. The result is a tree of `AstNode` subclasses that preserve source location information and support semantic queries. + +### 3. Type Check + +The AST is walked recursively, calling `type_check(symtab)` on each node. The compiler: + +- Infers types bottom-up from expressions +- Validates type compatibility (e.g., ensuring operands to `+` can be widened to a common type) +- Checks function call signatures +- Detects undefined variables and type mismatches + +Type checking is symbol-table-aware: it uses the current scope to resolve names and track variable types. + +**Configuration sensitivity**: Type checking with `strict: false` (the default) skips unreachable code. This means the same IDL source can type-check differently depending on the configuration. For example: + +```idl +if (implemented?(ExtensionName::C)) { + // This code is not type-checked if compressed instructions are known to be disabled at compile time + Bits<16> instr = ...; +} +``` + +This allows IDL code to be conditionally valid based on configuration parameters, and avoids type checking issues where IDL code is only valid under certain conditions (e.g., accessing page table bits that are only defined in RV64). + +### 4. Analysis Passes (Optional) + +After type checking, you can run analysis passes to extract information or transform the AST: + +- **Reachable functions**: trace the call graph from an instruction/CSR to find all functions it uses +- **Prune**: constant-fold expressions and eliminate dead branches when configuration values are known +- **Find referenced CSRs**: list all CSRs accessed by an operation +- **Find source registers**: extract register operands (for dependency analysis) + +Passes are implemented as methods added to `AstNode` subclasses (see [Analysis Passes](#analysis-passes) below). + +## The Abstract Syntax Tree (AST) + +Every node in the AST is a subclass of `Idl::AstNode`. The base class provides: + +### Core Attributes + +- **`text_value`**: The original IDL source text for this node +- **`input_file`**: Path to the source file (as a `Pathname`) +- **`lineno`**: Starting line number in the source file +- **`interval`**: Character range within the input +- **`parent`**: Parent node (or `nil` for the root) +- **`children`**: Array of child `AstNode` instances + +### Semantic Methods + +- **`type(symtab)`**: Returns the `Type` of this expression (e.g., `Bits<32>`, `Boolean`) +- **`value(symtab)`**: Attempts to evaluate the expression at compile time, returning a Ruby value (Integer, Boolean, String, Array, or Hash). Raises a `ValueError` if the value depends on runtime state. + +### Error Types + +The AST defines two error classes: + +- **`AstNode::TypeError`**: Raised when type checking detects a type error (e.g., incompatible operand types) +- **`AstNode::InternalError`**: Raised when the compiler encounters an unexpected state (indicates a compiler bug) + +Both capture a backtrace starting from the error call site for debugging. + +### Tree Traversal Pattern + +Most compiler operations walk the tree recursively: + +```ruby +class AstNode + def some_analysis(symtab) + # Default: recursively visit children + children.each { |child| child.some_analysis(symtab) } + end +end + +class IfAst < AstNode + def some_analysis(symtab) + # Override for specific node types + if_cond.some_analysis(symtab) + if_body.some_analysis(symtab) + elseifs.each { |eif| eif.some_analysis(symtab) } + final_else_body.some_analysis(symtab) + end +end +``` + +This pattern makes it easy to add new analyses without modifying the core AST structure. + +## The Symbol Table + +The `SymbolTable` tracks all visible names at the current point in the program. It manages: + +### Scoping + +IDL has four scope levels (see [Scope](./scope.mdx) for details): + +1. **Global scope**: functions, enumerations, bitfields defined in `.idl` files +2. **Function scope**: arguments and local variables inside a function +3. **Instruction scope**: decode variables inside an instruction's `operation()` body +4. **CSR scope**: CSR fields inside a CSR's `sw_read()`/`sw_write()` functions + +The symbol table is a stack: `symtab.push(node)` opens a new scope, `symtab.pop` closes it. + +### Compile-Time vs. Runtime Values + +A symbol table entry (`Var`) stores: + +- **Name**: the variable identifier +- **Type**: its IDL type (e.g., `Bits<5>`, `Boolean`) +- **Value**: its compile-time value (if known) or `nil` (if unknown) + +The compiler tracks values **optimistically**: whenever it can evaluate an expression at compile time, it does. This enables constant folding, dead code elimination, and conditional compilation. + +## Compile-Time Value Tracking and Unknown Values + +The compiler distinguishes between **known** and **unknown** information at compile time. There are **two categories of "unknown"**: + +### 1. Unknown Values + +A variable has an **unknown value** when its value depends on runtime state. For example: + +```idl +Bits<5> rs1 = X[rs1_idx]; // rs1_idx comes from the instruction encoding +if (rs1 == 5'd0) { + // Compiler doesn't know if this branch will execute +} +``` + +The compiler tracks which variables have known values and propagates them through expressions. When a value depends on an unknown, the result is also unknown. + +### 2. Unknown Bit Widths + +A `Bits` type has an **unknown width** when `N` depends on a runtime parameter: + +```idl +Bits result; // XLEN is a configuration parameter (32 or 64) +``` + +If the configuration is not fully specified (e.g., building an "unconfig" that supports both RV32 and RV64), the compiler must treat the width as **`:unknown`**. This affects certain optimizations like constant folding (since the bit width determines wraparound behavior), but **does not prevent type checking** — operations between `Bits` of different widths are allowed, with automatic widening (see [Operators](./operators.mdx)). + +### The `value_try` / `value_else` Pattern + +The compiler uses a value-error mechanism (similar to exceptions, but lighter-weight) to handle unknowns gracefully: + +```ruby +value_result = value_try do + v = some_expression.value(symtab) + # Use v here +end +value_else(value_result) do + # Expression has unknown value; handle the fallback +end +``` + +This pattern allows the compiler to attempt optimistic evaluation and fall back cleanly when information is missing. + +### Value Snapshotting + +**Problem**: When the compiler analyzes control flow (if/else, loops), it needs to track how variable values change along different execution paths. But the compiler doesn't know which path will execute at runtime. + +**Solution**: The symbol table supports **snapshotting**: capturing the current state of all variable values, and later restoring that snapshot. + +#### Why Snapshotting is Needed + +Consider this code: + +```idl +Bits<32> x = 10; +if (some_condition) { + x = 20; +} +// What is the value of x here? +``` + +If `some_condition` is unknown at compile time, the compiler cannot assume `x` is either `10` or `20` after the `if` — it must mark `x` as **unknown** because the assignment may or may not have happened. + +#### Snapshot API + +```ruby +snapshot = symtab.snapshot_values # Capture current state +# ... modify variable values ... +symtab.restore_values(snapshot) # Restore to captured state +``` + +This is used in: + +- **If statements**: Each branch gets a snapshot; after analyzing all branches, values assigned in uncertain branches are nullified +- **Loops**: The loop body may execute 0 or N times, so any assignments inside the loop invalidate outer-scope variables (they're set to `nil`) +- **Conditional statements**: `if (cond) x = y;` — if `cond` is unknown, `x` becomes unknown after the statement + +#### Nullification + +When control flow is uncertain, the compiler **nullifies** variables by setting their `value` to `nil`. This prevents incorrect constant propagation. + +Example from the prune pass: + +```ruby +class ForLoopAst < AstNode + def prune(symtab, forced_type: nil) + # Nullify any outer-scope variable assigned in the loop body + stmts.each { |stmt| stmt.nullify_assignments(symtab) } + + # Snapshot AFTER nullification, so restore brings back nil values + snapshot = symtab.snapshot_values + # ... analyze loop body ... + symtab.restore_values(snapshot) + end +end +``` + +### Example: If Statement Value Propagation + +Here's how the compiler handles an `if` statement: + +```ruby +class IfAst < AstNode + def prune(symtab, forced_type: nil) + value_result = value_try do + if if_cond.value(symtab) + # Condition is true at compile time; only the if-body is reachable + return if_body.prune(symtab, restore: false) + elsif !elseifs.empty? + # Condition is false; check else-if branches + # ... + elsif !final_else_body.stmts.empty? + # Condition is false; only else-body is reachable + return final_else_body.prune(symtab, restore: false) + else + # Condition is false and no else; this is a no-op + return NoopAst.new + end + end + value_else(value_result) do + # Condition is unknown; all branches are potentially reachable + # Nullify any variable assigned in any branch + if_body.nullify_assignments(symtab) + unknown_elsifs.each { |eif| eif.body.nullify_assignments(symtab) } + final_else_body.nullify_assignments(symtab) + # Return pruned if statement with all branches intact + # ... + end + end +end +``` + +## Analysis Passes + +Analysis passes extract information from or transform the AST. They are implemented by defining methods on `AstNode` subclasses. + +### Built-in Passes + +The compiler includes several standard passes: + +#### Reachable Functions + +**File**: `idlc/passes/reachable_functions.rb` + +Traces the function call graph starting from a given AST node (e.g., an instruction's `operation()` body) and returns the list of all functions that may be called, directly or transitively. + +**Usage**: Generators use this to determine which global functions must be included when compiling an instruction for an ISS or formal model. + +**Implementation pattern**: Recursively visits function calls, applies arguments to build a context-specific symbol table, and analyzes each function body in that context. Uses caching to handle recursion cycles. + +#### Reachable Exceptions + +**File**: `idlc/passes/reachable_exceptions.rb` + +Determines which exceptions can be raised by a given piece of IDL code. Returns a set of `ExceptionCode` values. + +**Usage**: Generators use this to know which exception handling code is required for an instruction. + +#### Find Referenced CSRs + +**File**: `idlc/passes/find_referenced_csrs.rb` + +Returns a list of CSR names accessed (read or written) by the code. + +**Usage**: Dependency analysis for instruction scheduling or ISS optimization. + +#### Find Source Registers + +**File**: `idlc/passes/find_src_registers.rb` + +Extracts the register operands read by an instruction (e.g., `X[rs1]`, `X[rs2]`). + +**Usage**: Dependency analysis for out-of-order execution models. + +#### Prune + +**File**: `idlc/passes/prune.rb` + +Performs **constant folding** and **dead code elimination** when configuration parameters are known. Returns a simplified AST with: + +- Known expressions replaced by their literal values +- Dead branches removed (e.g., `if (false) { ... }` → deleted) +- Unreachable code after early returns eliminated + +**Requires**: Known values (not just known widths). If a variable has an unknown value, pruning preserves the expression. + +**Usage**: Generating configuration-specific ISS code where parameters like `XLEN` or extension support are fixed. + +**Example**: + +```idl +// Original +if (MISA.C) { + // Compressed instructions supported +} else { + raise(IllegalInstruction); +} + +// After pruning with MISA.C = 1 +// (only the if-body remains) +``` + +### Writing a Custom Pass + +To add a new pass: + +1. Define a method on `AstNode` with a default implementation that recursively visits children +2. Override the method on specific node types to extract or transform information +3. Call your pass on the root of the tree + +#### Example: Counting Assignments + +Let's write a pass that counts how many assignments appear in an AST: + +```ruby +module Idl + class AstNode + # Default: sum counts from children + def count_assignments + children.sum(0) { |child| child.count_assignments } + end + end + + class VariableAssignmentAst < AstNode + def count_assignments + 1 + super # Count this assignment, plus any in the RHS + end + end + + class AryElementAssignmentAst < AstNode + def count_assignments + 1 + super + end + end + + class FieldAssignmentAst < AstNode + def count_assignments + 1 + super + end + end +end + +# Usage: +ast = compiler.compile_func_body(idl_source, symtab: symtab) +num_assignments = ast.count_assignments +puts "Found #{num_assignments} assignments" +``` + +#### Tips for Writing Passes + +- **Use the symbol table**: Most passes need type or value information — pass `symtab` as an argument +- **Handle scoping correctly**: If your pass needs to evaluate expressions, push/pop scopes as you traverse function bodies and loops +- **Use `value_try`**: If your pass depends on compile-time values, wrap calls to `value(symtab)` in `value_try` and provide a fallback +- **Consider caching**: If your pass is expensive and may visit the same subtree multiple times (e.g., function bodies), use a cache keyed by node identity or argument values + +## Type Checking + +Type checking is the process of verifying that every expression has a well-defined type and that operations are type-compatible. + +### How Types are Inferred + +Types flow **bottom-up** through the AST: + +- Literals have intrinsic types: `32'd10` is `Bits<32>`, `true` is `Boolean` +- Variables have the type they were declared with +- Function calls have the return type declared in the function signature +- Binary operators infer their result type from their operands (see [Operators](./operators.mdx) for widening rules) + +### Widening Rules for Bit-Vectors + +When two `Bits` values of different widths are combined, the result is widened to the larger width: + +```idl +Bits<5> a = 5'd10; +Bits<32> b = 32'd100; +Bits<32> result = a + b; // a is zero-extended to 32 bits +``` + +Widening is **zero-extension** by default. Use the `$signed()` cast for sign-extension (see [Type Conversions](./type-conversions.mdx)). + +### Error Reporting with File/Line Information + +Type errors include precise source locations: + +``` +TypeError: Type mismatch: expected Bits<32>, got Boolean + at my_instruction.yaml:42 + in operation() body +``` + +The AST preserves `input_file` and `lineno` for every node, allowing errors to point directly to the problematic source line. + +## Using the Compiler Programmatically (Ruby API) + +The `Idl::Compiler` class provides a Ruby API for parsing and compiling IDL code. + +### Creating a Compiler Instance + +```ruby +require 'idlc' + +compiler = Idl::Compiler.new +``` + +### Key Methods + +#### `compile_file(path, source_mapper = nil)` + +Compiles an entire `.idl` file. + +**Arguments**: +- `path` (Pathname): Path to the file +- `source_mapper` (Hash, optional): If provided, stores the file contents keyed by path (useful for error reporting) + +**Returns**: The root `AstNode` of the file + +**Raises**: `SyntaxError` if parsing fails + +**Example**: + +```ruby +ast = compiler.compile_file(Pathname.new("spec/std/isa/inst.idl")) +``` + +#### `compile_func_body(body, return_type:, symtab:, name:, input_file:, input_line:)` + +Compiles a function body (a sequence of statements). + +**Arguments**: +- `body` (String): IDL source code for the function body +- `return_type` (Type, optional): Expected return type +- `symtab` (SymbolTable): Symbol table with global definitions +- `name` (String): Function name (for error messages) +- `input_file` (String/Pathname): Source file path +- `input_line` (Integer): Starting line number in the source file + +**Returns**: A `FunctionBodyAst` node + +**Example**: + +```ruby +ast = compiler.compile_func_body( + inst["operation()"], + symtab: global_symtab, + name: "#{inst.name}::operation()", + input_file: inst_file_path, + input_line: line_number +) +``` + +#### `compile_inst_scope(idl, symtab:, input_file:, input_line:)` + +Compiles an instruction `operation()` body, which includes decode variable declarations in addition to statements. + +**Arguments**: +- `idl` (String): IDL source code +- `symtab` (SymbolTable): Symbol table with global definitions +- `input_file` (String/Pathname): Source file path +- `input_line` (Integer): Starting line number + +**Returns**: An instruction-scope AST node + +#### `compile_expression(expression, symtab)` + +Compiles a single expression (e.g., for evaluating a parameter default value). + +**Arguments**: +- `expression` (String): IDL expression +- `symtab` (SymbolTable): Symbol table for name resolution + +**Returns**: An expression AST node + +**Example**: + +```ruby +expr_ast = compiler.compile_expression("XLEN / 8", global_symtab) +num_bytes = expr_ast.value(global_symtab) +``` + +#### `type_check(ast, symtab, what)` + +Type-checks an already-constructed AST. + +**Arguments**: +- `ast` (AstNode): The root of the tree to check +- `symtab` (SymbolTable): Symbol table for name resolution +- `what` (String): Description of what is being checked (for error messages) + +**Raises**: `AstNode::TypeError` if type checking fails + +**Example**: + +```ruby +compiler.type_check(ast, symtab, "instruction ADD operation()") +``` + +### Complete Example: Compiling an Instruction + +```ruby +require 'idlc' +require 'pathname' + +# Assume we have: +# - global_symtab: a SymbolTable with global function and type definitions +# - inst_data: a hash with instruction metadata, including inst_data["operation()"] + +compiler = Idl::Compiler.new + +ast = compiler.compile_inst_scope( + inst_data["operation()"], + symtab: global_symtab, + input_file: "spec/std/isa/inst/RV32I/add.yaml", + input_line: 15 +) + +# Type-check the AST +compiler.type_check(ast, global_symtab, "ADD operation()") + +# Run a pass to find reachable functions +functions = ast.reachable_functions(global_symtab) +puts "ADD calls: #{functions.map(&:name).join(', ')}" + +# Run the prune pass (assumes configuration parameters are set in global_symtab) +pruned_ast = ast.prune(global_symtab) +puts "Pruned AST:\n#{pruned_ast.text_value}" +``` + +## Error Handling + +The compiler reports three categories of errors: + +### `SyntaxError` + +Raised during parsing when the input does not match the IDL grammar. + +**Includes**: +- File path +- Line and column number +- Reason (e.g., "Expected 'end', found '}'") + +**Example**: + +``` +SyntaxError: While parsing spec/std/isa/inst/RV32I/add.yaml:18:5 + +Expected ';' after statement +``` + +### `AstNode::TypeError` + +Raised during type checking when an operation is applied to incompatible types. + +**Includes**: +- Error message describing the type mismatch +- Compiler backtrace showing where the error was detected + +**Example**: + +```ruby +begin + compiler.type_check(ast, symtab, "SUB operation()") +rescue Idl::AstNode::TypeError => e + puts e.what # "Cannot apply operator '+' to Boolean and Bits<32>" + puts e.bt # Backtrace from the type_error call site +end +``` + +### `AstNode::InternalError` + +Raised when the compiler encounters an unexpected state, indicating a compiler bug (not a user error). + +**Includes**: +- Error message +- Compiler backtrace + +**If you encounter an `InternalError`**: Please report it as a bug with a minimal reproducible example. + +--- + +## Further Reading + +- [IDL Overview](./overview.mdx) — Design goals and language basics +- [IDL Data Types](./data-types.mdx) — Type system reference +- [IDL Functions](./functions.mdx) — Function declarations and rules +- [Scope](./scope.mdx) — Scoping rules for global, function, instruction, and CSR contexts +- [Operators](./operators.mdx) — Operator precedence and widening rules +- [Type Conversions](./type-conversions.mdx) — Implicit widening and explicit casts diff --git a/doc/docs/idl/in-csrs.mdx b/doc/docs/idl/in-csrs.mdx index 98d27f2a06..6ea8f94d8a 100644 --- a/doc/docs/idl/in-csrs.mdx +++ b/doc/docs/idl/in-csrs.mdx @@ -3,7 +3,7 @@ sidebar_position: 13 title: IDL in CSRs --- -IDL is used in several places within CSR definitions in `arch/csr/`. Each use executes in **CSR scope**. +IDL is used in several places within CSR definitions in `spec/std/isa/csr/`. Each use executes in **CSR scope**. :::note `sw_read()` is specified for the entire CSR; `sw_write(csr_value)` is specified per CSR field. @@ -31,7 +31,7 @@ The `sw_write(csr_value)` function of a CSR field executes when a software write | Value | Meaning | |-------|---------| | `UNDEFINED_LEGAL` | The written value is unpredictable but guaranteed to be a legal value for the field. Use when hardware is free to write anything legal. | -| `UNDEFINED_LEGAL_DETERMINISTIC` | The written value is legal and deterministically determined by the implementation's prior instruction sequence, but not architecturally defined. Use when the outcome is reproducible on a given implementation but not specified across implementations. | +| `UNDEFINED_LEGAL_DETERMINISTIC` | The written value is legal and determined by the implementation's prior instruction sequence, but not architecturally defined. Use when the outcome is reproducible on a given implementation but not specified across implementations. | ```yaml title="Example field.sw_write(csr_value) (mepc.yaml)" mepc: @@ -65,7 +65,12 @@ mstatus: The `reset_value()` function specifies the reset value of a CSR field when the value is configuration-dependent. It takes no arguments and returns a `Bits` value (where N is the width of the field). -`reset_value()` may also return `UNDEFINED_LEGAL` to indicate that the reset value is unpredictable but guaranteed to be a legal value for the field (as opposed to `UNDEFINED_LEGAL_DETERMINISTIC`, which would imply a reproducible but implementation-defined value). +`reset_value()` may also return one of two special values instead of a concrete `Bits`: + +| Value | Meaning | +|-------|---------| +| `UNDEFINED_LEGAL` | The reset value is unpredictable but guaranteed to be a legal value for the field. Use when the reset value is truly non-deterministic. | +| `UNDEFINED_LEGAL_DETERMINISTIC` | The reset value is legal and determined by implementation details, but not architecturally defined. Use when the reset value is reproducible on a given implementation but not specified across implementations. | ```yaml title="Example field.reset_value() (mstatus.yaml)" mstatus: diff --git a/doc/docs/idl/in-instructions.mdx b/doc/docs/idl/in-instructions.mdx index d99942dde8..5360e9179f 100644 --- a/doc/docs/idl/in-instructions.mdx +++ b/doc/docs/idl/in-instructions.mdx @@ -3,11 +3,11 @@ sidebar_position: 12 title: IDL in Instructions --- -Instruction definitions in `arch/inst/` use IDL to formally specify execution behavior via the `operation()` key. See also [IDL in CSRs](./in-csrs.mdx) and [Scope](./scope.mdx) for how IDL source is organized across `.idl` files. +Instruction definitions in `spec/std/isa/inst/` use IDL to formally specify execution behavior via the `operation()` key. See also [IDL in CSRs](./in-csrs.mdx) and [Scope](./scope.mdx) for how IDL source is organized across `.idl` files. ## Instruction `operation()` -Instruction definitions in `arch/inst/` use IDL to formally specify execution behavior via the `operation()` key. The IDL executes at **Instruction scope** when the instruction executes on a hart. +Instruction definitions in `spec/std/isa/inst/` use IDL to formally specify execution behavior via the `operation()` key. The IDL executes at **Instruction scope** when the instruction executes on a hart. `operation()` has no arguments and no return value, though decode variables are automatically populated from the encoding before execution begins. @@ -17,14 +17,14 @@ add: encoding: # ... variables: - - name: rs2 + - name: xs2 location: 24-20 - - name: rs1 + - name: xs1 location: 19-15 - - name: rd + - name: xd location: 11-7 operation(): | - X[rd] = X[rs1] + X[rs2]; + X[xd] = X[xs1] + X[xs2]; ``` -In the `operation()` body, the decoded fields (`rs1`, `rs2`, `rd`) are automatically available as variables. The `$encoding` and `$pc` builtins are also available. +In the `operation()` body, the decoded fields (`xs1`, `xs2`, `xd`) are automatically available as variables. The `$encoding` and `$pc` builtins are also available. diff --git a/doc/docs/idl/literals.mdx b/doc/docs/idl/literals.mdx index 755286ed58..804c5d94b6 100644 --- a/doc/docs/idl/literals.mdx +++ b/doc/docs/idl/literals.mdx @@ -1,8 +1,13 @@ --- sidebar_position: 4 title: Literals +status: complete --- +:::info[Status: Complete] +This documentation is complete and ready to use. +::: + ## Integer Literals Integer literal values can be expressed using either C style or Verilog style. @@ -30,6 +35,7 @@ Literals may contain any number of underscores after the initial digit for clari 32'h80000000 # 0x80000000, unsigned, 32-bit wide 32'h8000_0000 # same as above (underscores ignored) +32'd4_294_967_295 # 2^32-1, unsigned, 32-bit wide (underscores for readability) 8'13 # 13 decimal, 8-bit wide (default radix is 10) @@ -44,14 +50,21 @@ Literals may contain any number of underscores after the initial digit for clari ``` :::warning Negating an unsigned literal discards the sign bit -To negate a Verilog-style literal and get a negative value, the literal must be declared signed (prefix `s`). Without `s`, the literal is unsigned — negation wraps in two's complement and the sign bit is lost: +To negate a Verilog-style literal and get a negative value, the literal must be declared signed (prefix `s`). The `s` prefix unconditionally adds a sign bit, making the literal `N+1` bits wide for an `N`-bit base width. Without `s`, the literal is unsigned — negation wraps in two's complement and the sign bit is lost: ```idl --8'sd13 # -13: literal is signed, negation works correctly +-8'sd13 # -13: literal is signed (9 bits), negation works correctly -4'd13 # 3: literal is 13 unsigned in 4 bits → negated → sign bit lost ``` Use the `s` prefix whenever you intend a negative literal. + +The `s` prefix does not help when the declared width is already too narrow to represent the value. The width must be sufficient to hold both the value and the sign bit: + +```idl +-3'sd13 # still wrong: 13 needs at least 4 bits, plus sign bit = 5 bits minimum +-5'sd13 # correct: wide enough for value + sign bit +``` ::: ### C style @@ -93,6 +106,23 @@ A bare negative C-style literal like `-13` is **not** a negative number. It is t Use the `s` suffix (e.g., `-13s`, `-0xds`) whenever you need a true negative C-style literal. ::: +## Boolean Literals + +Boolean values are represented by the keywords `true` and `false`. These are the only two `Boolean` literal values in IDL. + +```idl title="Boolean literals" +Boolean flag = true; +Boolean ready = false; + +if (flag == true) { # explicit comparison (can also write: if (flag)) + # ... +} +``` + +:::note +Unlike C, integers are **not** implicitly boolean. You must use explicit comparisons (e.g., `x != 0`) in conditional expressions. +::: + ## Array Literals Array literals are composed of a comma-separated list of values in brackets, similar to C/C++/Verilog. diff --git a/doc/docs/idl/operators.mdx b/doc/docs/idl/operators.mdx index 2d8c01c308..ce1d0c3e02 100644 --- a/doc/docs/idl/operators.mdx +++ b/doc/docs/idl/operators.mdx @@ -1,8 +1,13 @@ --- sidebar_position: 5 title: Operators +status: complete --- +:::info[Status: Complete] +This documentation is complete and ready to use. +::: + Integer types (`Bits`, `U64`) support most of the same operators as Verilog and use the same order of precedence. Notably excluded are many bitwise reduction operators (e.g., and-reduce, or-reduce). Binary operators between operands of different bit widths extend the smaller operand to the size of the larger operand prior to the operation. When the smaller operand is signed, the extension is a sign extension; otherwise it is a zero extension. @@ -13,6 +18,8 @@ The result of a binary operation is signed if both operands are signed; otherwis IDL includes widening variants of several binary operators, indicated by a backtick (`` ` ``) prefix. These are unique to IDL and have no direct C or Verilog equivalent. They are useful when you need to preserve the full result of an operation that would otherwise overflow or lose bits. +In the table below, `L(i)` denotes the bit width of operand `i`, and `value(j)` denotes the compile-time constant value of `j`. + | Operator | Operation | Result width | |----------|-----------|-------------| | `` i `* j `` | Widening multiply | `L(i) + L(j)` | @@ -31,7 +38,7 @@ Bits<32> narrow_mul = a * b; # 0xFFFFFFFE (truncated) Bits<64> wide_mul = a `* b; # 0x00000001FFFFFFFE # Standard addition: carry bit lost -Bits<32> wrapped_add = a + b; # 0x00000001 (overflow) +Bits<32> wrapped_add = a + b; # 0x00000001 (truncation) # Widening addition: carry preserved in extra bit, result is 33 bits Bits<33> wide_add = a `+ b; # 0x100000001 diff --git a/doc/docs/idl/overview.mdx b/doc/docs/idl/overview.mdx index 9ae0ad3689..faebeeae10 100644 --- a/doc/docs/idl/overview.mdx +++ b/doc/docs/idl/overview.mdx @@ -1,18 +1,23 @@ --- sidebar_position: 1 title: IDL Overview +status: complete --- # ISA Description Language (IDL) +:::info[Status: Complete] +This documentation is complete and ready to use. +::: + The **ISA Description Language (IDL)** is a domain-specific language for formally specifying RISC-V instruction set architectures. IDL is designed to be: - **Human readable** — serves as a reliable documentation source alongside the spec. - **Familiar** — syntax resembles a mix of Verilog and C++, so hardware and software designers can read it with minimal ramp-up. - **Strongly typed** — reduces ambiguity as a documentation source. -- **Modular** — reflects RISC-V's modular ISA structure. IDL can describe a wide range of devices, then be customized with configuration variables to generate an implementation-specific description. +- **Configurable** — reflects RISC-V's configurable ISA structure. IDL can describe a wide range of devices, then be customized with configuration variables to generate an implementation-specific description. -IDL is used to describe the behavior of RISC-V instructions, fetch, and (in cases where behavior is specialized) CSRs. Taken together, the IDL can be converted into a fully functioning Instruction Set Simulator (ISS) that is a golden model of execution. +IDL is used to describe the behavior of RISC-V instructions and (in cases where behavior is specialized) CSRs. Taken together, the IDL can be converted into a fully functioning Instruction Set Simulator (ISS) that is a golden model of execution. :::tip Choose your starting point - **Hardware engineers** — see [IDL for Verilog Users](./guide-for-verilog-users) @@ -63,20 +68,20 @@ Enable software development before hardware availability: ## Worked Example -The following example shows how the Branch if Less Than or Equal Unsigned (`BLTU`) instruction is specified in IDL. `rs1`, `rs2`, and `imm` are decode fields extracted automatically from the instruction encoding before execution. +The following example shows how the Branch if Less Than or Equal Unsigned (`BLTU`) instruction is specified in IDL. `xs1`, `xs2`, and `imm` are decode fields extracted automatically from the instruction encoding before execution. ```idl title="BLTU instruction" -Bits src1 = X[rs1]; # (1) Read X[rs1] -Bits src2 = X[rs2]; # (2) Read X[rs2] +Bits src1 = X[xs1]; # (1) Read X[xs1] +Bits src2 = X[xs2]; # (2) Read X[xs2] if (src1 <= src2) { # (3) Unsigned comparison - jump(PC + $signed(imm)); # (4) Jump to target + jump($pc + $signed(imm)); # (4) Jump to target } # fall through: advance to next instruction ``` -1. Read general-purpose register `rs1` into an MXLEN-bit variable `src1`. `MXLEN` is a configuration parameter available as a global constant. -2. Read general-purpose register `rs2` into `src2`. +1. Read general-purpose register `xs1` into an MXLEN-bit variable `src1`. `MXLEN` is a configuration parameter available as a global constant. +2. Read general-purpose register `xs2` into `src2`. 3. Check if unsigned `src1` is less than or equal to unsigned `src2`. 4. Call `jump` with a target address formed by adding a signed immediate to the PC. @@ -142,7 +147,8 @@ description builtin body for if else enum bitfield -struct +struct true +false ``` --- diff --git a/doc/docs/idl/quick-reference.mdx b/doc/docs/idl/quick-reference.mdx index 13a0b9cd88..831060c275 100644 --- a/doc/docs/idl/quick-reference.mdx +++ b/doc/docs/idl/quick-reference.mdx @@ -66,6 +66,9 @@ See [Literals](./literals). # Logical (Boolean operands only) && || ! +# Increment/Decrement (for loop update only) +i++ i-- # post-increment/decrement on iteration variable + # Ternary condition ? a : b @@ -159,8 +162,8 @@ See [Builtins](./builtins). ```idl # Architectural register file -X[rs1] # read x register (Bits) -X[rd] = value; # write x register (x0 writes are discarded) +X[xs1] # read x register (Bits) +X[xd] = value; # write x register (x0 writes are discarded) # CSR access CSR[mstatus] # read/write entire CSR @@ -177,8 +180,8 @@ raise(ExceptionCode::IllegalInstruction); raise(ExceptionCode::LoadAccessFault, vaddr); # with tval # Memory -read_memory<32>(vaddr, $encoding) # read N bits from virtual address -write_memory<32>(vaddr, value, $encoding) # write N bits to virtual address +read_memory(32, vaddr, $encoding) # read N bits from virtual address +write_memory(32, vaddr, value, $encoding) # write N bits to virtual address ``` See [Standard Library](./standard-library). diff --git a/doc/docs/idl/scope.mdx b/doc/docs/idl/scope.mdx index 9ecd8b631b..75360cc45a 100644 --- a/doc/docs/idl/scope.mdx +++ b/doc/docs/idl/scope.mdx @@ -23,7 +23,7 @@ Function scope is created by declaring a function in an `.idl` file. It includes ### Instruction Scope -Instruction execution — specified in an instruction's `operation()` — occurs in Instruction scope. Decode variables are automatically populated from the encoding before the `operation()` body begins. The `$encoding` builtin variable is available in Instruction scope. +Instruction execution — specified in an instruction's `operation()` — occurs in Instruction scope. Decode variables are predefined in scope from the encoding before the `operation()` body begins. The `$encoding` and `$pc` builtin variables are available in Instruction scope. ### CSR Scope diff --git a/doc/docs/idl/standard-library.mdx b/doc/docs/idl/standard-library.mdx index afff1fe1b2..39cfb5a569 100644 --- a/doc/docs/idl/standard-library.mdx +++ b/doc/docs/idl/standard-library.mdx @@ -16,7 +16,7 @@ Bits<1> mie_bit = CSR[mstatus].MIE; # Write a CSR field CSR[mstatus].MIE = 1'b0; -# Write an entire CSR +# Write a CSR field (BASE field of mtvec) CSR[mtvec].BASE = handler_addr[MXLEN-1:2]; ``` @@ -54,7 +54,7 @@ Returns `true` if the given extension is present in the implementation. ```idl if (implemented?(ExtensionName::C) && (CSR[misa].C == 1'b0)) { - # C is implemented in hardware but disabled by software + # C is implemented in hardware but unimplemented (disabled) by software via misa raise(ExceptionCode::IllegalInstruction, mode(), $encoding); } ``` @@ -116,34 +116,34 @@ The full list is defined in `spec/std/isa/exception_code/`. Memory access functions handle virtual-to-physical address translation, PMP/PMA checks, and misalignment handling automatically. They should be used in preference to direct physical memory access in most instruction implementations. -### `read_memory(virtual_address, encoding)` +### `read_memory(len, virtual_address, encoding)` -Reads `LEN` bits from virtual memory. `LEN` must be 8, 16, 32, or 64. +Reads `len` bits from virtual memory. `len` must be 8, 16, 32, or 64. ```idl # Load byte (zero-extended) -X[xd] = read_memory<8>(virtual_address, $encoding); +X[xd] = read_memory(8, virtual_address, $encoding); # Load word (sign-extended via sext helper) -X[xd] = sext(read_memory<32>(virtual_address, $encoding), 32); +X[xd] = sext(read_memory(32, virtual_address, $encoding), 32); # Load doubleword -Bits<64> data = read_memory<64>(virtual_address, $encoding); +Bits<64> data = read_memory(64, virtual_address, $encoding); ``` -### `write_memory(virtual_address, value, encoding)` +### `write_memory(len, virtual_address, value, encoding)` -Writes `LEN` bits to virtual memory. +Writes `len` bits to virtual memory. ```idl # Store byte -write_memory<8>(virtual_address, X[xs2][7:0], $encoding); +write_memory(8, virtual_address, X[xs2][7:0], $encoding); # Store halfword -write_memory<16>(virtual_address, X[xs2][15:0], $encoding); +write_memory(16, virtual_address, X[xs2][15:0], $encoding); # Store word -write_memory<32>(virtual_address, X[xs2][31:0], $encoding); +write_memory(32, virtual_address, X[xs2][31:0], $encoding); ``` :::note diff --git a/doc/docs/idl/type-conversions.mdx b/doc/docs/idl/type-conversions.mdx index c365b1aab7..d0d6cec371 100644 --- a/doc/docs/idl/type-conversions.mdx +++ b/doc/docs/idl/type-conversions.mdx @@ -16,6 +16,10 @@ Type conversions occur when dissimilar types are used in binary operators or ass When expansion occurs, the value is **zero extended** when the type is unsigned and **sign extended** when the type is signed. +:::note Widening operators are an exception +Widening operators (`` `+ ``, `` `- ``, `` `* ``, `` `<< ``) produce a result wider than both operands and do not follow the standard conversion rules above. See [Widening Operators](./operators#widening-operators) for details. +::: + :::warning Narrowing assignments silently discard high bits Assigning a wider value into a narrower variable truncates without warning: diff --git a/doc/docs/idl/variables.mdx b/doc/docs/idl/variables.mdx index 9e9474ec9c..188ae57486 100644 --- a/doc/docs/idl/variables.mdx +++ b/doc/docs/idl/variables.mdx @@ -3,13 +3,17 @@ sidebar_position: 3 title: Variables and Constants --- +Variables and constants are the primary way to name and store values during execution. Variables are mutable; constants are immutable. + +Variable declarations can appear anywhere an IDL statement can — at the top level of an `.idl` file (global scope), within function bodies, within instruction `operation()` bodies, or within `if`/`for` block bodies. + ## Assignment Variables are assigned using `=`. Assignment is a statement, not an expression — it cannot appear inside a condition or as a subexpression. ```idl XReg result; -result = X[rs1] + X[rs2]; # assign after declaration +result = X[xs1] + X[xs2]; # assign after declaration Bits<8> flags = 0xFF; # assign at declaration flags = flags & mask; # re-assign @@ -26,7 +30,7 @@ mask = mask & 0xFF; ``` :::note -The x register file is assigned through `X[rd] = value`. The x0 register is hardwired to zero — writes to it are silently discarded. +The x register file is assigned through `X[xd] = value`. The x0 register is hardwired to zero — writes to it are silently discarded, and reads from it always return `XLEN'd0`. ::: ## Mutable Variables @@ -48,7 +52,7 @@ Bits<8> ary[2]; # declare ary, initialized to [8'd0, 8'd0] The general-purpose RISC-V x registers are builtin state for IDL (rather than being declared state). This avoids needing special language support (e.g., operator overloading) or verbose function calls on every x register access. Three special cases apply: -1. The x0 register is hardwired to 0. +1. The x0 register is hardwired to 0. Writes to x0 are ignored, and reads from it always return `XLEN'd0`. 2. All writes to an x register when `MXLEN != XLEN` are sign-extended to `MXLEN`. 3. All reads from an x register when `MXLEN != XLEN` ignore the upper bits of the register. diff --git a/doc/docs/intro/doc-status.md b/doc/docs/intro/doc-status.md new file mode 100644 index 0000000000..a3f06f82a5 --- /dev/null +++ b/doc/docs/intro/doc-status.md @@ -0,0 +1,126 @@ +--- +sidebar_position: 2 +title: Documentation Status +--- + +# Documentation Status + +🚧 **The UDB documentation site is under active construction.** This page tracks the completion status of all planned documentation sections, so you can see at a glance what exists and what's coming. + +## Status Legend + +- ✅ **Complete** — Documentation is written, reviewed, and ready to use +- 🚧 **In Progress** — Partially complete; some sections may be missing or outdated +- 📋 **Planned** — Documentation is planned but not yet written + +--- + +## Introduction + +| Section | Status | Notes | +|---------|--------|-------| +| What is UDB? | ✅ Complete | Core overview complete | +| Current State | 📋 Planned | Maturity and use case coverage | + +## Getting Started + +| Section | Status | Notes | +|---------|--------|-------| +| For Users | 📋 Planned | CLI, Ruby gem, Python bindings | +| For Specification Writers | 📋 Planned | Adding extensions, instructions, CSRs | +| For Developers | 📋 Planned | Contributing code, writing generators | +| FAQ / How-Do-I | 📋 Planned | Common questions and solutions | + +## Concepts + +| Section | Status | Notes | +|---------|--------|-------| +| Configurations | 🚧 In Progress | Overview exists, details pending | +| Data Pipeline | 📋 Planned | Overlay merge, resolution, inheritance | +| Conditions System | 📋 Planned | How conditions work in the database | + +## The Database (spec/) + +| Section | Status | Notes | +|---------|--------|-------| +| Overview | 📋 Planned | Database structure and organization | +| Table Reference | 📋 Planned | Documentation for each table | +| Custom Overlays | 📋 Planned | How to customize the database | +| Schema Reference | 🚧 In Progress | Auto-generated from JSON Schema | + +## IDL Language + +| Section | Status | Notes | +|---------|--------|-------| +| Overview | ✅ Complete | Core concepts and use cases | +| Data Types | ✅ Complete | Bits, Boolean, structs, enums | +| Literals | ✅ Complete | Integer, array, string literals | +| Operators | ✅ Complete | Full precedence table | +| Variables & Constants | ✅ Complete | Declaration and usage | +| Type Conversions | ✅ Complete | Casting and implicit conversions | +| Builtins | ✅ Complete | Built-in functions reference | +| Control Flow | ✅ Complete | if/else, loops, switch | +| Functions | ✅ Complete | Declaration, calls, generated functions | +| Scope Rules | ✅ Complete | Variable and function scoping | +| In Instructions | ✅ Complete | How IDL appears in instruction definitions | +| In CSRs | ✅ Complete | CSR-specific IDL usage | +| For Spec Writers | ✅ Complete | Guide for writing IDL specs | +| For C Users | ✅ Complete | IDL from a C perspective | +| For Verilog Users | ✅ Complete | IDL from a hardware perspective | +| Common Misunderstandings | ✅ Complete | FAQ and gotchas | +| Quick Reference | ✅ Complete | Cheat sheet | +| Standard Library | ✅ Complete | Standard library functions | +| idlc Compiler | 🚧 In Progress | Compiler tool documentation | + +## Tools + +| Section | Status | Notes | +|---------|--------|-------| +| Overview | 📋 Planned | Tool ecosystem overview | +| udb gem | 📋 Planned | Main database interface | +| udb-gen gem | 📋 Planned | Artifact generation | +| idlc gem | 📋 Planned | IDL compiler | +| udb_helpers gem | 📋 Planned | Template helpers | +| idl_highlighter gem | 📋 Planned | Syntax highlighting | +| bin/generate | 📋 Planned | Generator wrapper script | +| bin/regress | 📋 Planned | Regression test runner | +| bin/chore | 📋 Planned | Repository maintenance | + +## Generators + +| Section | Status | Notes | +|---------|--------|-------| +| Overview | 📋 Planned | What generators produce | +| PRM PDF | 📋 Planned | Programmer's Reference Manual | +| HTML Config Docs | 📋 Planned | Configuration documentation | +| C++ ISS | 📋 Planned | Instruction Set Simulator | +| C Header | 📋 Planned | Encoding headers | +| Go | 📋 Planned | Go definitions | +| SystemVerilog | 📋 Planned | Decode packages | +| Profile Docs | 📋 Planned | RISC-V profile documentation | +| Instructions Appendix | 📋 Planned | AsciiDoc instruction appendix | + +## Contributing + +| Section | Status | Notes | +|---------|--------|-------| +| Code Contributions | 📋 Planned | How to contribute code | +| Data Contributions | 📋 Planned | Adding spec data | +| Commit Conventions | 📋 Planned | Commit message format | +| Code Review | 📋 Planned | Review process | +| Docs Site Architecture | 📋 Planned | How this site is built | + +--- + +## Timeline + +This documentation is being written incrementally as the site is built. The IDL language documentation is mostly complete (converted from existing AsciiDoc sources), while other sections are being written from scratch. + +**Priority order:** +1. Introduction and Getting Started (enabling new users) +2. Concepts (understanding the architecture) +3. Tools and Generators (practical usage) +4. Database reference (for advanced users) +5. Contributing guides (for contributors) + +Check back regularly for updates, or [watch the repository](https://github.com/riscv/riscv-unified-db) to be notified of new documentation. diff --git a/doc/docs/intro/what-is-udb.mdx b/doc/docs/intro/what-is-udb.mdx index 524c435b15..a4ce376aa5 100644 --- a/doc/docs/intro/what-is-udb.mdx +++ b/doc/docs/intro/what-is-udb.mdx @@ -1,8 +1,13 @@ --- sidebar_position: 1 title: What is UDB? +status: complete --- +:::info[Status: Complete] +This documentation is complete and ready to use. +::: + The **RISC-V Unified Database (UDB)** is a machine-readable database of the RISC-V ISA specification and a suite of tools for working with that data. Think of it as the "source code" for the RISC-V architecture — structured, validated, and ready to generate whatever you need. UDB eliminates manual transcription and interpretation errors by letting you query instruction encodings, generate CSR headers, produce documentation, and build tooling directly from the database. Chip designers, compiler developers, and spec writers can all work from the same validated source, ensuring consistency across the entire RISC-V ecosystem. diff --git a/doc/docs/schemas/_category_.json b/doc/docs/schemas/_category_.json new file mode 100644 index 0000000000..8a0e52fb06 --- /dev/null +++ b/doc/docs/schemas/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "Schema Reference", + "position": 10, + "link": { + "type": "doc", + "id": "schemas/index" + } +} diff --git a/doc/docs/schemas/index.mdx b/doc/docs/schemas/index.mdx new file mode 100644 index 0000000000..85b5f0cb24 --- /dev/null +++ b/doc/docs/schemas/index.mdx @@ -0,0 +1,151 @@ +--- +title: Schema Reference +sidebar_position: 1 +--- + + +# Schema Reference + +UDB uses JSON Schema to define and validate the structure of YAML files in `spec/`. Each schema is versioned independently — the version shown on each card is that schema's current version. + + +## About Schema Versions + +Schemas are versioned independently of the UDB repository. Each schema file declares its version in the `$id` field. When a schema format changes, a new version is created to maintain backward compatibility with existing data files. + + +## Schemas + +
+ +
+ Config Schema
+ v0.1 +
+ +
+ Csr Schema
+ v0.2 +
+ + + +
+ Ext Schema
+ v0.1 +
+ +
+ Inst Opcode Schema
+ v0.1 +
+ +
+ Inst Schema
+ v0.2 +
+ +
+ Inst Schema
+ v0.1 +
+ + + +
+ Inst Type Schema
+ v0.1 +
+ +
+ Inst Var Schema
+ v0.1 +
+ + + + + + + +
+ Manual Schema
+ v0.1 +
+ + + +
+ Mmr Schema
+ v0.1 +
+ +
+ Non Isa Schema
+ v0.1 +
+ +
+ Param Schema
+ v0.1 +
+ +
+ Prm Schema
+ v0.1 +
+ + + + + + + + + +
+ Profile Schema
+ v0.1 +
+ + + +
+ Schema Defs
+ v0.1 +
+ +
diff --git a/doc/docs/schemas/v0.1/_category_.json b/doc/docs/schemas/v0.1/_category_.json new file mode 100644 index 0000000000..9a2179c64f --- /dev/null +++ b/doc/docs/schemas/v0.1/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "v0.1", + "position": 2, + "collapsible": true, + "collapsed": false +} diff --git a/doc/docs/schemas/v0.1/config_schema.mdx b/doc/docs/schemas/v0.1/config_schema.mdx new file mode 100644 index 0000000000..0b00c9def5 --- /dev/null +++ b/doc/docs/schemas/v0.1/config_schema.mdx @@ -0,0 +1,299 @@ +--- +title: Configuration Schema (v0.1) +sidebar_label: Configuration Schema +custom_edit_url: null +# This file is auto-generated from config_schema.json +# Do not edit manually - run `bin/chore gen schema-docs` to regenerate +--- + + +import AnchorOpenDetails from '@site/src/components/AnchorOpenDetails'; + + + +# Configuration Schema + +v0.1 + +
+ +:::note Auto-generated +This page is generated from [`config_schema.json`](https://github.com/riscv/riscv-unified-db/blob/main/spec/schemas/config_schema.json) by the [schema doc generator](https://github.com/riscv/riscv-unified-db/blob/main/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen.rb). To update this page, edit the schema file and run `bin/chore gen schema-docs`. +::: + +A configuration represents RISC-V architectural choices - ranging from complete design specifications to requirement sets to unconstrained baselines. + +> **See also:** Configurations Overview for a narrative introduction with examples and use cases. + +Configurations come in three forms: + +- **Fully configured**: Concrete implementations with all extensions and parameters explicitly specified. These represent actual processor implementations where every architectural detail is known. Each extension must specify an exact version (e.g., `2.1.0` or `2.1`). Used for generating implementations, documentation, and test suites for specific hardware. + +- **Partially configured**: Profiles or configurable IP that define mandatory, optional, and prohibited extensions using version constraints (e.g., `>= 2.0`). These specify requirements that multiple implementations can satisfy. Can restrict whether additional extensions beyond those listed are allowed. Used for RISC-V compliance profiles, configurable IP offerings (a class of implementations a vendor may offer), and platform requirements. + +- **Unconfigured**: Special case representing the entire RISC-V specification without any implementation choices. Used to model the complete RISC-V architecture space before any configuration decisions are made. + +The variant is selected by the `type` field. Fields common to all variants: `name`, `description`, `arch_overlay`. The `params` field is available on `fully configured` and `partially configured` variants. + +> **Note:** Schema validation checks structural correctness only. A schema-valid file can still be semantically invalid - for example, referencing an extension version that does not exist in the database, or omitting a parameter that is required by the implemented extensions. + + +## Quick Start + +**Minimal Fully Configured:** +```yaml +"$schema": config_schema.json# +kind: architecture configuration +type: fully configured +name: MyProcessor +description: A minimal 64-bit RISC-V processor +params: + MXLEN: 64 +implemented_extensions: +- name: I + version: '2.1' +- name: Sm + version: '1.12' + +``` + +**Minimal Partially Configured:** +```yaml +"$schema": config_schema.json# +kind: architecture configuration +type: partially configured +name: MyProfile +description: A minimal profile requiring base integer instructions +mandatory_extensions: +- name: I + version: ">= 2.1" + +``` + +**Minimal Unconfigured:** +```yaml +"$schema": config_schema.json# +kind: architecture configuration +type: unconfigured +name: generic +description: The complete RISC-V specification with no implementation choices + +``` + + + +## Variants + +This schema accepts **one of** the following variants, distinguished by the `type` field: + +- [fully configured](#fully-configured) +- [partially configured](#partially-configured) +- [unconfigured](#unconfigured) + +### `fully configured` + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `$schema` | `string` (const: `config_schema.json#`) | ✓ | Schema reference - must be `config_schema.json#` | +| `kind` | `string` (const: `architecture configuration`) | ✓ | Document type identifier - must be `architecture configuration` | +| `type` | `string` (const: `fully configured`) | ✓ | Configuration specificity level - `fully configured` means all extensions and parameters are explicitly specified | +| `name` | `string` | ✓ | Name of the configuration | +| `description` | `string` | ✓ | Human-readable description of this configuration (AsciiDoc format) | +| `params` | `object` | ✓ | Architecture parameters that define implementation choices (e.g., `MXLEN: 64`, privilege modes, physical address width, etc.). Parameter names and valid values are defined by the parameter data files in `spec/std/isa/param/`. | +| `implemented_extensions` | Array<\{`name`, `version`\}> [↓ schema](#implemented-extensions-schema) | ✓ | Extensions implemented by this architecture [↓ example](#implemented-extensions-example) | +| `arch_overlay` | `string` | | Optional arch overlay to apply. Can be either the name of a directory under arch_overlay/ or an absolute or relative path to an overlay directory | + +
+implemented_extensions item schema + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `name` | `string` | ✓ | Extension name | +| `version` | `string` | ✓ | Exact version in `MAJOR[.MINOR[.PATCH]]` format (e.g., `2.1.0`, `2.1`, `2`) | + +
+ +
+implemented_extensions example + +```yaml +- name: I + version: 2.1.0 +- name: M + version: 2.0.0 +- name: Zicsr + version: 2.0.0 + +``` + +
+ + +:::note Tooling field +`$source` is an optional field set automatically by UDB tooling to record the file path this object was loaded from. You do not need to set it manually. +::: + +### `partially configured` + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `$schema` | `string` (const: `config_schema.json#`) | ✓ | Schema reference - must be `config_schema.json#` | +| `kind` | `string` (const: `architecture configuration`) | ✓ | Document type identifier - must be `architecture configuration` | +| `type` | `string` (const: `partially configured`) | ✓ | Configuration specificity level - `partially configured` means some extensions/parameters are specified as requirements while others are left open | +| `name` | `string` | ✓ | Name of the configuration | +| `description` | `string` | ✓ | Human-readable description of this configuration (AsciiDoc format) | +| `mandatory_extensions` | Array<\{`name`, `version`\}> [↓ schema](#mandatory-extensions-schema) | ✓ | Extensions mandatory in this architecture | +| `params` | `object` | | Architecture parameters that constrain compliant implementations. The entire `params` key may be omitted if no parameter constraints are needed. Parameter names and valid values are defined by the parameter data files in `spec/std/isa/param/`. | +| `arch_overlay` | `string` | | Optional arch overlay to apply. Can be either the name of a directory under arch_overlay/ or an absolute or relative path to an overlay directory | +| `non_mandatory_extensions` | Array<\{`name`, `version`\}> [↓ schema](#non-mandatory-extensions-schema) | | Optional extensions with special significance in this architecture. For configurable IP, these are optionally supported extensions. For profiles, these are profile-optional extensions. | +| `prohibited_extensions` | Array<\{`name`, `version`\}> [↓ schema](#prohibited-extensions-schema) | | Extensions explicitly prohibited in this architecture. Does *not* need to include extensions that are excluded because of a conflict-by-definition with a mandatory extension, as those will be calculated automatically | +| `additional_extensions` | `boolean` | | Whether a compliant instance may implement extensions beyond those listed in `mandatory_extensions`/`non_mandatory_extensions`. Defaults to `true` if omitted. | +| `requirements` | A condition (YAML structure or IDL function). See the conditions reference for details. | | Additional condition that must be satisfied for this configuration to be valid (e.g., a parameter constraint or extension dependency). | + +
+mandatory_extensions item schema + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `name` | `string` | ✓ | Extension name (e.g., `I`, `M`, `Zicsr`, `Smstateen`) | +| `version` | `string` \| Array<`string`> | | Version requirement or list of requirements (e.g., `>= 2.0` or `['>= 2.0', '< 3.0']`) | + +
+ +
+non_mandatory_extensions item schema + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `name` | `string` | ✓ | Extension name (e.g., `I`, `M`, `Zicsr`, `Smstateen`) | +| `version` | `string` \| Array<`string`> | | Version requirement or list of requirements (e.g., `>= 2.0` or `['>= 2.0', '< 3.0']`) | + +
+ +
+prohibited_extensions item schema + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `name` | `string` | ✓ | Extension name (e.g., `I`, `M`, `Zicsr`, `Smstateen`) | +| `version` | `string` \| Array<`string`> | | Version requirement or list of requirements (e.g., `>= 2.0` or `['>= 2.0', '< 3.0']`) | + +
+ + +:::note Tooling field +`$source` is an optional field set automatically by UDB tooling to record the file path this object was loaded from. You do not need to set it manually. +::: + +### `unconfigured` + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `$schema` | `string` (const: `config_schema.json#`) | ✓ | Schema reference - must be `config_schema.json#` | +| `kind` | `string` (const: `architecture configuration`) | ✓ | Document type identifier - must be `architecture configuration` | +| `type` | `string` (const: `unconfigured`) | ✓ | Configuration specificity level - `unconfigured` represents the entire RISC-V specification with no implementation choices | +| `name` | `string` | ✓ | Name of the configuration | +| `description` | `string` | ✓ | Human-readable description of this configuration (AsciiDoc format) | +| `arch_overlay` | `string` | | Optional arch overlay to apply. Can be either the name of a directory under arch_overlay/ or an absolute or relative path to an overlay directory | + +:::note Tooling field +`$source` is an optional field set automatically by UDB tooling to record the file path this object was loaded from. You do not need to set it manually. +::: + + + +## Examples + +
+Full Configuration Example (RV64) + +```yaml +"$schema": config_schema.json# +kind: architecture configuration +type: fully configured +name: RV64GC +description: 64-bit RISC-V with General-purpose and Compressed extensions +params: + XLEN: 64 + MXLEN: 64 + SXLEN: 64 + UXLEN: 64 +implemented_extensions: +- name: I + version: '2.1' +- name: M + version: '2.0' +- name: A + version: '2.1' +- name: F + version: '2.2' +- name: D + version: '2.2' +- name: C + version: '2.0' +- name: Zicsr + version: '2.0' +- name: Zifencei + version: '2.0' + +``` + +
+ +
+Partial Configuration Example (Profile) + +```yaml +"$schema": config_schema.json# +kind: architecture configuration +type: partially configured +name: RVA22U64 +description: RISC-V Application Profile for 64-bit Unix-like systems +mandatory_extensions: +- name: I + version: ">= 2.1" +- name: M + version: ">= 2.0" +- name: A + version: ">= 2.1" +- name: F + version: ">= 2.2" +- name: D + version: ">= 2.2" +- name: C + version: ">= 2.0" +- name: Zicsr + version: ">= 2.0" +non_mandatory_extensions: +- name: V + version: ">= 1.0" +params: + XLEN: 64 +additional_extensions: false + +``` + +
+ +
+Unconfigured Example + +```yaml +"$schema": config_schema.json# +kind: architecture configuration +type: unconfigured +name: generic +description: Generic unconfigured RISC-V architecture + +``` + +
+ + + +## Schema Information + +| Property | Value | +|----------|-------| +| Version | `v0.1` | +| JSON Schema Version | [Draft 07](https://json-schema.org/draft-07) | diff --git a/doc/docs/schemas/v0.1/exception_code_schema.mdx b/doc/docs/schemas/v0.1/exception_code_schema.mdx new file mode 100644 index 0000000000..69a49d8712 --- /dev/null +++ b/doc/docs/schemas/v0.1/exception_code_schema.mdx @@ -0,0 +1,42 @@ +--- +title: Exception Code Schema (v0.1) +sidebar_label: Exception Code Schema +custom_edit_url: null +# This file is auto-generated from exception_code_schema.json +# Do not edit manually - run `bin/chore gen schema-docs` to regenerate +--- + + +# Exception Code Schema + +v0.1 + +
+ +:::note Auto-generated +This page is generated from [`exception_code_schema.json`](https://github.com/riscv/riscv-unified-db/blob/main/spec/schemas/exception_code_schema.json) by the [schema doc generator](https://github.com/riscv/riscv-unified-db/blob/main/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen.rb). To update this page, edit the schema file and run `bin/chore gen schema-docs`. +::: + + +## Properties + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `$schema` | `any` | ✓ | | +| `kind` | `any` | ✓ | | +| `name` | `string` | ✓ | Name of the exception, as a legal IDL variable name | +| `display_name` | `string` | ✓ | Pretty display version of the name | +| `num` | `integer` | ✓ | Exception number, as reported in the `*cause` CSRs | +| `definedBy` | A condition (YAML structure or IDL function). See the conditions reference for details. | ✓ | | + +:::note Tooling field +`$source` is an optional field set automatically by UDB tooling to record the file path this object was loaded from. You do not need to set it manually. +::: + + +## Schema Information + +| Property | Value | +|----------|-------| +| Version | `v0.1` | +| JSON Schema Version | [Draft 07](https://json-schema.org/draft-07) | diff --git a/doc/docs/schemas/v0.1/ext_schema.mdx b/doc/docs/schemas/v0.1/ext_schema.mdx new file mode 100644 index 0000000000..6738d4e425 --- /dev/null +++ b/doc/docs/schemas/v0.1/ext_schema.mdx @@ -0,0 +1,142 @@ +--- +title: Ext Schema (v0.1) +sidebar_label: Ext Schema +custom_edit_url: null +# This file is auto-generated from ext_schema.json +# Do not edit manually - run `bin/chore gen schema-docs` to regenerate +--- + + +import AnchorOpenDetails from '@site/src/components/AnchorOpenDetails'; + + + +# Ext Schema + +v0.1 + +
+ +:::note Auto-generated +This page is generated from [`ext_schema.json`](https://github.com/riscv/riscv-unified-db/blob/main/spec/schemas/ext_schema.json) by the [schema doc generator](https://github.com/riscv/riscv-unified-db/blob/main/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen.rb). To update this page, edit the schema file and run `bin/chore gen schema-docs`. +::: + +An ISA extension defines a named set of instructions, CSRs, and behaviors that can be implemented by a RISC-V processor. Each extension has one or more versioned releases, with various ratification states (development, frozen, public-review, ratification-ready, ratified, or nonstandard-released). + +## Key Fields + +- `name`: Short identifier used throughout the database (e.g., `I`, `M`, `Zicsr`, `Smstateen`) +- `long_name`: Human-readable one-line description +- `description`: Full AsciiDoc documentation of the extension +- `type`: Whether the extension is `unprivileged` or `privileged` +- `versions`: Array of versioned releases, each with a `state` and optional `ratification_date` +- `requirements`: Optional condition that must be true for the extension to be implementable (e.g., requires another extension) +- `company`: Organization that developed the extension (defaults to RISC-V International for standard extensions) +- `doc_license`: License for the extension documentation + + +## Quick Start + +**Minimal Extension (Zicsr):** +```yaml +"$schema": ext_schema.json# +kind: extension +name: Zicsr +long_name: Control and status register instructions +description: Control and status register instructions +type: unprivileged +versions: +- version: 2.0.0 + state: ratified + ratification_date: 2019-04 + +``` + + + +## Properties + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `$schema` | `string` (const: `ext_schema.json#`) | ✓ | Schema reference - must be `ext_schema.json#` | +| `kind` | `string` (const: `extension`) | ✓ | Document type identifier - must be `extension` | +| `name` | Extension name (e.g., `I`, `M`, `Zicsr`, `Smstateen`) | ✓ | | +| `long_name` | `string` | ✓ | One-line human-readable name for the extension (e.g., `Address generation`, `Bit Manipulation`) | +| `description` | `string` \| Array<[`conditional_text`](#conditional-text)> | ✓ | Full AsciiDoc documentation of the extension. May include multiple paragraphs, code examples, and cross-references. | +| `type` | `unprivileged` \| `privileged` | ✓ | Privilege level of the extension. `unprivileged` extensions add instructions or behaviors accessible in user mode; `privileged` extensions add supervisor- or machine-mode functionality. | +| `versions` | Array<object> [↓ schema](#versions-schema) | ✓ | Ordered list of versioned releases of this extension, from oldest to newest. | +| `rvi_jira_issue` | `string` | | JIRA issue number tracking this extension in the RISC-V International issue tracker | +| `company` | A company | | Organization that developed this extension. Omit for RISC-V International standard extensions. | +| `doc_license` | License that applies to the textual documentation for this extension | | License for the extension documentation | +| `requirements` | A condition (YAML structure or IDL function). See the conditions reference for details. | | Condition that must be true for this extension to be implementable. If the condition is false, the extension cannot be implemented. Typically used to express that one extension requires another (e.g., `D` requires `F`). | +| `cert_normative_rules` | Architecturally visible behaviors requiring validation by certification tests | | | + +
+versions item schema + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `version` | `string` | ✓ | Version number in `MAJOR.MINOR.PATCH` format (e.g., `1.0.0`, `2.1.0`) | +| `state` | `development` \| `frozen` \| `public-review` \| `ratification-ready` \| `ratified` \| `nonstandard-released` | ✓ | Ratification state of this version. See `spec_state` in schema_defs for all possible values and their meanings. | +| `repositories` | Array<object> | | Source repositories where this version of the extension is developed | +| `ratification_date` | One of: `string` \| `string` \| `null` | | Month when this version was ratified, in `YYYY-MM` format. Use `unknown` if the date is not recorded. Required when `state` is `ratified`. | +| `release_date` | One of: `string` \| `string` \| `null` | | | +| `changes` | Array<`string`> | | List of changes introduced in this version relative to the previous version | +| `url` | `string` | | URL to the ratified specification document (e.g., a PDF on the RISC-V website) | +| `contributors` | Array<object> | | People who contributed to this version of the extension | +| `requirements` | `object` \| `object` \| `object` \| `object` \| `object` \| `object` | | Additional condition that must be true for this specific version to be implementable, beyond any requirements on the extension overall. If the condition is false, this version cannot be implemented. | + +
+ + +:::note Tooling field +`$source` is an optional field set automatically by UDB tooling to record the file path this object was loaded from. You do not need to set it manually. +::: + + +## Examples + +
+Extension with Requirements (B) + +```yaml +"$schema": ext_schema.json# +kind: extension +name: B +long_name: Bit Manipulation +description: The B standard extension comprises instructions provided by the Zba, + Zbb, and Zbs extensions. +type: unprivileged +company: + name: RISC-V International + url: https://riscv.org +doc_license: + name: Creative Commons Attribution 4.0 International License + url: https://creativecommons.org/licenses/by/4.0/ +versions: +- version: 1.0.0 + state: ratified + ratification_date: 2024-04 + url: https://drive.google.com/file/d/1SgLoasaBjs5WboQMaU3wpHkjUwV71UZn/view + requirements: + extension: + allOf: + - name: Zba + version: "= 1.0.0" + - name: Zbb + version: "= 1.0.0" + - name: Zbs + version: "= 1.0.0" + +``` + +
+ + + +## Schema Information + +| Property | Value | +|----------|-------| +| Version | `v0.1` | +| JSON Schema Version | [Draft 07](https://json-schema.org/draft-07) | diff --git a/doc/docs/schemas/v0.1/inst_opcode_schema.mdx b/doc/docs/schemas/v0.1/inst_opcode_schema.mdx new file mode 100644 index 0000000000..85162ed334 --- /dev/null +++ b/doc/docs/schemas/v0.1/inst_opcode_schema.mdx @@ -0,0 +1,38 @@ +--- +title: Instruction Opcode Schema (v0.1) +sidebar_label: Instruction Opcode Schema +custom_edit_url: null +# This file is auto-generated from inst_opcode_schema.json +# Do not edit manually - run `bin/chore gen schema-docs` to regenerate +--- + + +# Instruction Opcode Schema + +v0.1 + +
+ +:::note Auto-generated +This page is generated from [`inst_opcode_schema.json`](https://github.com/riscv/riscv-unified-db/blob/main/spec/schemas/inst_opcode_schema.json) by the [schema doc generator](https://github.com/riscv/riscv-unified-db/blob/main/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen.rb). To update this page, edit the schema file and run `bin/chore gen schema-docs`. +::: + +Schema for instruction opcode definitions + + +## Properties + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `$schema` | `any` | ✓ | | +| `kind` | `any` | ✓ | | +| `data` | `object` | ✓ | | +| `name` | `string` | | | + + +## Schema Information + +| Property | Value | +|----------|-------| +| Version | `v0.1` | +| JSON Schema Version | [Draft 07](https://json-schema.org/draft-07) | diff --git a/doc/docs/schemas/v0.1/inst_schema.mdx b/doc/docs/schemas/v0.1/inst_schema.mdx new file mode 100644 index 0000000000..d0e2f61963 --- /dev/null +++ b/doc/docs/schemas/v0.1/inst_schema.mdx @@ -0,0 +1,147 @@ +--- +title: Inst Schema (v0.1) +sidebar_label: Inst Schema +custom_edit_url: null +# This file is auto-generated from inst_schema.json +# Do not edit manually - run `bin/chore gen schema-docs` to regenerate +--- + + +import AnchorOpenDetails from '@site/src/components/AnchorOpenDetails'; + + + +# Inst Schema + +v0.1 + +
+ +:::note Auto-generated +This page is generated from [`inst_schema.json`](https://github.com/riscv/riscv-unified-db/blob/main/spec/schemas/inst_schema.json) by the [schema doc generator](https://github.com/riscv/riscv-unified-db/blob/main/tools/ruby-gems/schema_doc_gen/lib/schema_doc_gen.rb). To update this page, edit the schema file and run `bin/chore gen schema-docs`. +::: + + +## Definitions + +
+fully_resolved_opcodes + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `location` | `schema_defs.json#/$defs/field_location` | ✓ | | +| `display_name` | `string` | ✓ | field name, displayed in encoding drawings | +| `value` | One of: An integer, either native to JSON or a number-like string \| `object` | ✓ | | +| `$child_of` | One of: `string` \| Array<`string`> | | | + +
+ +
+fully_resolved_variables + + +
+ +
+fully_resolved_format + +
+ +
+old_encoding + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `match` | One of: `string` \| `string` \| `string` | | | +| `variables` | Array<[`field`](#field)> | | | +| `additionalProperties` | `never` | | | + +
+ +
+type + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `$ref` | `string` | ✓ | Reference to an instruction type definition | + +
+ +
+subtype + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `$ref` | `string` | ✓ | Reference to an instruction subtype definition | + +
+ +
+variable_metadata + +
+ +
+field — Decode field + +Decode field + + +
+ + + +## Properties + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `$schema` | `string` (const: `inst_schema.json#`) | ✓ | Path to schema, relative to <UDB ROOT>/schemas | +| `kind` | `string` (const: `instruction`) | ✓ | | +| `name` | `string` | ✓ | Instruction mnemonic (must be lowercase) | +| `long_name` | `string` | ✓ | One line description of the instruction | +| `description` | `string` \| Array<[`conditional_text`](#conditional-text)> | ✓ | Detailed description of the instruction | +| `definedBy` | A condition (YAML structure or IDL function). See the conditions reference for details. | ✓ | Extension(s) that defines the instruction | +| `access` | `object` | ✓ | | +| `assembly` | `string` | ✓ | Assembly format of the instruction. Can use decode variables | +| `encoding` | One of: [`old_encoding`](#old-encoding) \| `object` | | Instruction encoding and decode variables | +| `format` | `object` | | | +| `pseudoinstructions` | Array<\{`when`, `to`\}> [↓ schema](#pseudoinstructions-schema) | | Variations of this instruction that form a pseudoinstruction | +| `data_independent_timing` | `boolean` | | Whether or not the instruction must execute with data-independent timing when the Zkt extension is supported | +| `cert_normative_rules` | Architecturally visible behaviors requiring validation by certification tests | | | +| `sail()` | `string` | | Functional description of the instruction using Sail | +| `operation_ast` | `object` | | | +| `operation()` | `string` | | Functional description of the instruction using IDL language | +| `access_detail` | `string` | | Extra detail about access when at least one mode is 'sometimes' | +| `hints` | Array<\{`$ref`\}> [↓ schema](#hints-schema) | | List of HINTs that use this instruction's codepoints | + +
+pseudoinstructions item schema + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `when` | `string` | | Condition when the instruction has an alias | +| `to` | `string` | | pseudoinstruction format | + +
+ +
+hints item schema + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `$ref` | `string` | ✓ | Ref to an instruction that is using a HINT codepoint(s) of this instruction | + +
+ + +:::note Tooling field +`$source` is an optional field set automatically by UDB tooling to record the file path this object was loaded from. You do not need to set it manually. +::: + + +## Schema Information + +| Property | Value | +|----------|-------| +| Version | `v0.1` | +| JSON Schema Version | [Draft 07](https://json-schema.org/draft-07) | diff --git a/doc/docs/schemas/v0.1/inst_subtype_schema.mdx b/doc/docs/schemas/v0.1/inst_subtype_schema.mdx new file mode 100644 index 0000000000..f3353a4a98 --- /dev/null +++ b/doc/docs/schemas/v0.1/inst_subtype_schema.mdx @@ -0,0 +1,75 @@ +--- +title: Instruction Subtype Schema (v0.1) +sidebar_label: Instruction Subtype Schema +custom_edit_url: null +# This file is auto-generated from inst_subtype_schema.json +# Do not edit manually - run `bin/chore gen schema-docs` to regenerate +--- + + +import AnchorOpenDetails from '@site/src/components/AnchorOpenDetails'; + + + +# Instruction Subtype Schema + +v0.1 + +
+ +:::note Auto-generated +This page is generated from [`inst_subtype_schema.json`](https://github.com/riscv/riscv-unified-db/blob/main/spec/schemas/inst_subtype_schema.json) by the [schema doc generator](https://github.com/riscv/riscv-unified-db/blob/main/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen.rb). To update this page, edit the schema file and run `bin/chore gen schema-docs`. +::: + +Schema for instruction subtype definitions + + +## Definitions + +
+fully_resolved_data + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `type` | `object` | ✓ | Instruction format type (I-type, R-type, etc.) | +| `subtype` | `object` | ✓ | Instruction format subtype (R-x-type, etc.) | +| `opcodes` | `object` | ✓ | | +| `variables` | `object` | | | +| `$parent_of` | `string` (pattern: `^.*/.*\.yaml#.*$`) \| Array<[`ref_url`](#ref-url)> | | | + +
+ +
+polymorphic_data + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `type` | `object` | ✓ | Instruction format type (I-type, R-type, etc.) | +| `subtype` | `object` | ✓ | Instruction format subtype (R-x-type, etc.) | +| `opcodes` | `object` | ✓ | | +| `variables` | One of: `object` \| `object` | | | + +
+ + + +## Properties + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `$schema` | `any` | ✓ | Pointer to schema | +| `kind` | `any` | ✓ | Kind of the database object | +| `name` | `string` | ✓ | Name of the subtype; also serves as database key | +| `data` | One of: [`polymorphic_data`](#polymorphic-data) \| [`fully_resolved_data`](#fully-resolved-data) | ✓ | | + +:::note Tooling field +`$source` is an optional field set automatically by UDB tooling to record the file path this object was loaded from. You do not need to set it manually. +::: + + +## Schema Information + +| Property | Value | +|----------|-------| +| Version | `v0.1` | +| JSON Schema Version | [Draft 07](https://json-schema.org/draft-07) | diff --git a/doc/docs/schemas/v0.1/inst_type_schema.mdx b/doc/docs/schemas/v0.1/inst_type_schema.mdx new file mode 100644 index 0000000000..80237edcd8 --- /dev/null +++ b/doc/docs/schemas/v0.1/inst_type_schema.mdx @@ -0,0 +1,45 @@ +--- +title: Instruction Type Schema (v0.1) +sidebar_label: Instruction Type Schema +custom_edit_url: null +# This file is auto-generated from inst_type_schema.json +# Do not edit manually - run `bin/chore gen schema-docs` to regenerate +--- + + +# Instruction Type Schema + +v0.1 + +
+ +:::note Auto-generated +This page is generated from [`inst_type_schema.json`](https://github.com/riscv/riscv-unified-db/blob/main/spec/schemas/inst_type_schema.json) by the [schema doc generator](https://github.com/riscv/riscv-unified-db/blob/main/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen.rb). To update this page, edit the schema file and run `bin/chore gen schema-docs`. +::: + +Schema for instruction type definitions + + +## Properties + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `$schema` | `any` | ✓ | | +| `kind` | `any` | ✓ | | +| `name` | `string` (pattern: `[A-Z][A-Za-z0-9\-]*`) | ✓ | | +| `description` | `string` | ✓ | | +| `length` | `16` \| `32` | ✓ | Length, in bits, of the encoding | +| `opcodes` | `object` | ✓ | | +| `variables` | `object` | | | + +:::note Tooling field +`$source` is an optional field set automatically by UDB tooling to record the file path this object was loaded from. You do not need to set it manually. +::: + + +## Schema Information + +| Property | Value | +|----------|-------| +| Version | `v0.1` | +| JSON Schema Version | [Draft 07](https://json-schema.org/draft-07) | diff --git a/doc/docs/schemas/v0.1/inst_var_schema.mdx b/doc/docs/schemas/v0.1/inst_var_schema.mdx new file mode 100644 index 0000000000..e96dbc8ba6 --- /dev/null +++ b/doc/docs/schemas/v0.1/inst_var_schema.mdx @@ -0,0 +1,69 @@ +--- +title: Instruction Variable Schema (v0.1) +sidebar_label: Instruction Variable Schema +custom_edit_url: null +# This file is auto-generated from inst_var_schema.json +# Do not edit manually - run `bin/chore gen schema-docs` to regenerate +--- + + +import AnchorOpenDetails from '@site/src/components/AnchorOpenDetails'; + + + +# Instruction Variable Schema + +v0.1 + +
+ +:::note Auto-generated +This page is generated from [`inst_var_schema.json`](https://github.com/riscv/riscv-unified-db/blob/main/spec/schemas/inst_var_schema.json) by the [schema doc generator](https://github.com/riscv/riscv-unified-db/blob/main/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen.rb). To update this page, edit the schema file and run `bin/chore gen schema-docs`. +::: + +Schema for instruction decode variable definitions + + +## Definitions + +
+fully_resolved_data + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `location` | Location specifier for a field | ✓ | | +| `type` | `object` | ✓ | | +| `$parent_of` | `string` (pattern: `^.*/.*\.yaml#.*$`) \| Array<[`ref_url`](#ref-url)> | | | +| `$child_of` | `string` (pattern: `^.*/.*\.yaml#.*$`) \| Array<[`ref_url`](#ref-url)> | | | + +
+ +
+polymorphic_data + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `location` | Location specifier for a field | | | +| `$inherits` | One of: `string` \| Array<`string`> | | | +| `type` | `object` | | | + +
+ + + +## Properties + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `$schema` | `any` | ✓ | | +| `kind` | `any` | ✓ | | +| `name` | `string` | ✓ | | +| `data` | One of: [`fully_resolved_data`](#fully-resolved-data) \| [`polymorphic_data`](#polymorphic-data) | ✓ | | + + +## Schema Information + +| Property | Value | +|----------|-------| +| Version | `v0.1` | +| JSON Schema Version | [Draft 07](https://json-schema.org/draft-07) | diff --git a/doc/docs/schemas/v0.1/inst_var_type_schema.mdx b/doc/docs/schemas/v0.1/inst_var_type_schema.mdx new file mode 100644 index 0000000000..0b0544f096 --- /dev/null +++ b/doc/docs/schemas/v0.1/inst_var_type_schema.mdx @@ -0,0 +1,35 @@ +--- +title: Instruction Variable Type Schema (v0.1) +sidebar_label: Instruction Variable Type Schema +custom_edit_url: null +# This file is auto-generated from inst_var_type_schema.json +# Do not edit manually - run `bin/chore gen schema-docs` to regenerate +--- + + +# Instruction Variable Type Schema + +v0.1 + +
+ +:::note Auto-generated +This page is generated from [`inst_var_type_schema.json`](https://github.com/riscv/riscv-unified-db/blob/main/spec/schemas/inst_var_type_schema.json) by the [schema doc generator](https://github.com/riscv/riscv-unified-db/blob/main/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen.rb). To update this page, edit the schema file and run `bin/chore gen schema-docs`. +::: + +Schema for instruction variable type definitions + + +## Schema Structure + +This schema requires **all of** the following: + +- (Complex type) + + +## Schema Information + +| Property | Value | +|----------|-------| +| Version | `v0.1` | +| JSON Schema Version | [Draft 07](https://json-schema.org/draft-07) | diff --git a/doc/docs/schemas/v0.1/inst_variable_metadatas.mdx b/doc/docs/schemas/v0.1/inst_variable_metadatas.mdx new file mode 100644 index 0000000000..82a70731ec --- /dev/null +++ b/doc/docs/schemas/v0.1/inst_variable_metadatas.mdx @@ -0,0 +1,26 @@ +--- +title: Inst Variable Metadatas (v0.1) +sidebar_label: Inst Variable Metadatas +custom_edit_url: null +# This file is auto-generated from inst_variable_metadatas.json +# Do not edit manually - run `bin/chore gen schema-docs` to regenerate +--- + + +# Inst Variable Metadatas + +v0.1 + +
+ +:::note Auto-generated +This page is generated from [`inst_variable_metadatas.json`](https://github.com/riscv/riscv-unified-db/blob/main/spec/schemas/inst_variable_metadatas.json) by the [schema doc generator](https://github.com/riscv/riscv-unified-db/blob/main/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen.rb). To update this page, edit the schema file and run `bin/chore gen schema-docs`. +::: + + +## Schema Information + +| Property | Value | +|----------|-------| +| Version | `v0.1` | +| JSON Schema Version | [Draft 07](https://json-schema.org/draft-07) | diff --git a/doc/docs/schemas/v0.1/interrupt_code_schema.mdx b/doc/docs/schemas/v0.1/interrupt_code_schema.mdx new file mode 100644 index 0000000000..21ef3b5baf --- /dev/null +++ b/doc/docs/schemas/v0.1/interrupt_code_schema.mdx @@ -0,0 +1,42 @@ +--- +title: Interrupt Code Schema (v0.1) +sidebar_label: Interrupt Code Schema +custom_edit_url: null +# This file is auto-generated from interrupt_code_schema.json +# Do not edit manually - run `bin/chore gen schema-docs` to regenerate +--- + + +# Interrupt Code Schema + +v0.1 + +
+ +:::note Auto-generated +This page is generated from [`interrupt_code_schema.json`](https://github.com/riscv/riscv-unified-db/blob/main/spec/schemas/interrupt_code_schema.json) by the [schema doc generator](https://github.com/riscv/riscv-unified-db/blob/main/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen.rb). To update this page, edit the schema file and run `bin/chore gen schema-docs`. +::: + + +## Properties + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `$schema` | `any` | ✓ | | +| `kind` | `any` | ✓ | | +| `name` | `string` | ✓ | Name of the interrupt, as a legal IDL variable name | +| `display_name` | `string` | ✓ | Pretty display version of the name | +| `num` | `integer` | ✓ | Interrupt number, as reported in the `*cause` CSRs (not including the leading INT bit) | +| `definedBy` | A condition (YAML structure or IDL function). See the conditions reference for details. | ✓ | | + +:::note Tooling field +`$source` is an optional field set automatically by UDB tooling to record the file path this object was loaded from. You do not need to set it manually. +::: + + +## Schema Information + +| Property | Value | +|----------|-------| +| Version | `v0.1` | +| JSON Schema Version | [Draft 07](https://json-schema.org/draft-07) | diff --git a/doc/docs/schemas/v0.1/manual_schema.mdx b/doc/docs/schemas/v0.1/manual_schema.mdx new file mode 100644 index 0000000000..db0838a69d --- /dev/null +++ b/doc/docs/schemas/v0.1/manual_schema.mdx @@ -0,0 +1,44 @@ +--- +title: Manual Schema (v0.1) +sidebar_label: Manual Schema +custom_edit_url: null +# This file is auto-generated from manual_schema.json +# Do not edit manually - run `bin/chore gen schema-docs` to regenerate +--- + + +# Manual Schema + +v0.1 + +
+ +:::note Auto-generated +This page is generated from [`manual_schema.json`](https://github.com/riscv/riscv-unified-db/blob/main/spec/schemas/manual_schema.json) by the [schema doc generator](https://github.com/riscv/riscv-unified-db/blob/main/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen.rb). To update this page, edit the schema file and run `bin/chore gen schema-docs`. +::: + + +## Properties + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `$schema` | `any` | ✓ | | +| `kind` | `any` | ✓ | | +| `name` | `string` | ✓ | Name (database key) of this manual | +| `long_name` | `string` | ✓ | One line description of the manual | +| `marketing_name` | `string` | | The publicly displayed manual name | +| `state` | Ratification state of a specification or extension version: `development` (actively being worked on), `frozen` (feature-complete, under review), `public-review` (open for public comment), `ratification-ready` (approved by the task group, awaiting board vote), `ratified` (officially approved by RISC-V International), or `nonstandard-released` (released but not part of the RISC-V standard). | | State of this version | +| `url` | `string` | | URL to the repository | +| `license` | License that applies to the textual documentation for this extension | | | + +:::note Tooling field +`$source` is an optional field set automatically by UDB tooling to record the file path this object was loaded from. You do not need to set it manually. +::: + + +## Schema Information + +| Property | Value | +|----------|-------| +| Version | `v0.1` | +| JSON Schema Version | [Draft 07](https://json-schema.org/draft-07) | diff --git a/doc/docs/schemas/v0.1/manual_version_schema.mdx b/doc/docs/schemas/v0.1/manual_version_schema.mdx new file mode 100644 index 0000000000..9afd4b3a81 --- /dev/null +++ b/doc/docs/schemas/v0.1/manual_version_schema.mdx @@ -0,0 +1,101 @@ +--- +title: Manual Version Schema (v0.1) +sidebar_label: Manual Version Schema +custom_edit_url: null +# This file is auto-generated from manual_version_schema.json +# Do not edit manually - run `bin/chore gen schema-docs` to regenerate +--- + + +import AnchorOpenDetails from '@site/src/components/AnchorOpenDetails'; + + + +# Manual Version Schema + +v0.1 + +
+ +:::note Auto-generated +This page is generated from [`manual_version_schema.json`](https://github.com/riscv/riscv-unified-db/blob/main/spec/schemas/manual_version_schema.json) by the [schema doc generator](https://github.com/riscv/riscv-unified-db/blob/main/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen.rb). To update this page, edit the schema file and run `bin/chore gen schema-docs`. +::: + + +## Definitions + +
+volume + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `title` | `string` | ✓ | Title of the volume | +| `description` | `string` | ✓ | Description of the volume | +| `authors` | Array<\{`name`, `email`, `organization`\}> [↓ schema](#authors-schema) | ✓ | | +| `chapters` | Array<[`chapter`](#chapter)> | | Ordered (in display order) list of chapters | +| `extensions` | Array<\{`name`, `version`\}> [↓ schema](#extensions-schema) | | List of extensions defined in this volume, with version numbers | +| `changes` | Array<`string`> | | List of changes made since the last version | + +
+authors item schema + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `name` | `string` | ✓ | Author's full name | +| `email` | `string` | | Author's email address | +| `organization` | `object` | | Author's organization, which should be an RVI member (or individual) | + +
+ +
+extensions item schema + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `name` | `string` | ✓ | Extension name (e.g., `I`, `M`, `Zicsr`, `Smstateen`) | +| `version` | `string` | ✓ | Exact version in `MAJOR[.MINOR[.PATCH]]` format (e.g., `2.1.0`, `2.1`, `2`) | + +
+ + +
+ +
+chapter — Relative (to the contents.yaml file) path to the chapter source + +Relative (to the contents.yaml file) path to the chapter source + +**Type:** `string` + +
+ + + +## Properties + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `$schema` | `any` | ✓ | | +| `kind` | `any` | ✓ | | +| `name` | `string` | ✓ | Name (database key) of this version | +| `long_name` | `string` | ✓ | One line description of the instruction | +| `manual` | `object` | ✓ | | +| `version` | `string` (pattern: `^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$`) | ✓ | Semantic version number within the manual | +| `marketing_version` | `string` | ✓ | The publicly displayed version number | +| `state` | Ratification state of a specification or extension version: `development` (actively being worked on), `frozen` (feature-complete, under review), `public-review` (open for public comment), `ratification-ready` (approved by the task group, awaiting board vote), `ratified` (officially approved by RISC-V International), or `nonstandard-released` (released but not part of the RISC-V standard). | ✓ | State of this version | +| `volumes` | Array<[`volume`](#volume)> | ✓ | List of volumes in this version | +| `url` | `string` | | URL to the version, if stored external to the database | +| `uses_isa_manual` | `boolean` | | Whether or not this manual version is derived from riscv-isa-manual | +| `isa_manual_tree` | `string` | | The git tree-ish of the riscv-isa-manual repository used to generate this version | + +:::note Tooling field +`$source` is an optional field set automatically by UDB tooling to record the file path this object was loaded from. You do not need to set it manually. +::: + + +## Schema Information + +| Property | Value | +|----------|-------| +| Version | `v0.1` | +| JSON Schema Version | [Draft 07](https://json-schema.org/draft-07) | diff --git a/doc/docs/schemas/v0.1/mmr_schema.mdx b/doc/docs/schemas/v0.1/mmr_schema.mdx new file mode 100644 index 0000000000..b53d2901b1 --- /dev/null +++ b/doc/docs/schemas/v0.1/mmr_schema.mdx @@ -0,0 +1,48 @@ +--- +title: MMR description (v0.1) +sidebar_label: MMR description +custom_edit_url: null +# This file is auto-generated from mmr_schema.json +# Do not edit manually - run `bin/chore gen schema-docs` to regenerate +--- + + +# MMR description + +v0.1 + +
+ +:::note Auto-generated +This page is generated from [`mmr_schema.json`](https://github.com/riscv/riscv-unified-db/blob/main/spec/schemas/mmr_schema.json) by the [schema doc generator](https://github.com/riscv/riscv-unified-db/blob/main/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen.rb). To update this page, edit the schema file and run `bin/chore gen schema-docs`. +::: + +A memory-mapped register specification + + +## Properties + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `$schema` | `any` | ✓ | Path to schema, relative to <UDB ROOT>/schemas | +| `kind` | `any` | ✓ | Object type | +| `name` | `string` | ✓ | MMR name | +| `long_name` | `string` | ✓ | One line description for the MMR | +| `description` | `string` \| Array<[`conditional_text`](#conditional-text)> | ✓ | Function of the register | +| `definedBy` | A condition (YAML structure or IDL function). See the conditions reference for details. | ✓ | Extension(s) that define the MMR | +| `physical_address` | `integer` | ✓ | Physical memory address of the register | +| `writable` | `boolean` | ✓ | Whether or not the register can be written by software | +| `length` | `8` \| `16` \| `32` \| `64` \| `128` | ✓ | Length, in bits, of the register. Must be a fixed integer (no XLEN-dependent lengths for MMIO). | +| `fields` | `object` | | fields of this MMR | + +:::note Tooling field +`$source` is an optional field set automatically by UDB tooling to record the file path this object was loaded from. You do not need to set it manually. +::: + + +## Schema Information + +| Property | Value | +|----------|-------| +| Version | `v0.1` | +| JSON Schema Version | [Draft 07](https://json-schema.org/draft-07) | diff --git a/doc/docs/schemas/v0.1/non_isa_schema.mdx b/doc/docs/schemas/v0.1/non_isa_schema.mdx new file mode 100644 index 0000000000..02e77ddd4d --- /dev/null +++ b/doc/docs/schemas/v0.1/non_isa_schema.mdx @@ -0,0 +1,82 @@ +--- +title: Schema for Non-ISA specification definitions (v0.1) +sidebar_label: Schema for Non-ISA specification definitions +custom_edit_url: null +# This file is auto-generated from non_isa_schema.json +# Do not edit manually - run `bin/chore gen schema-docs` to regenerate +--- + + +import AnchorOpenDetails from '@site/src/components/AnchorOpenDetails'; + + + +# Schema for Non-ISA specification definitions + +v0.1 + +
+ +:::note Auto-generated +This page is generated from [`non_isa_schema.json`](https://github.com/riscv/riscv-unified-db/blob/main/spec/schemas/non_isa_schema.json) by the [schema doc generator](https://github.com/riscv/riscv-unified-db/blob/main/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen.rb). To update this page, edit the schema file and run `bin/chore gen schema-docs`. +::: + + +## Properties + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `$schema` | `string` (const: `non_isa_schema.json#`) | ✓ | | +| `kind` | `string` (const: `non-isa specification`) | ✓ | | +| `name` | `string` | ✓ | Name of the non-ISA specification | +| `description` | `string` \| Array<[`conditional_text`](#conditional-text)> | ✓ | AsciiDoc description of the specification | +| `sections` | Array<object> [↓ schema](#sections-schema) | ✓ | Organized sections of the specification | +| `long_name` | `string` | | Human-readable name for the specification | +| `version` | `string` (pattern: `^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$`) | | Version of this non-ISA specification | +| `ratification_date` | A specific day in YYYY-MM-DD format | | Date this specification was ratified or released | +| `references` | Array<\{`title`, `url`, `description`\}> [↓ schema](#references-schema) | | External references and links | +| `authors` | Array<\{`name`, `email`, `organization`\}> [↓ schema](#authors-schema) | | Authors of this specification | +| `license` | License that applies to the textual documentation for this extension | | License under which this specification is released | + +
+sections item schema + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `title` | `string` | ✓ | Section title | +| `level` | `integer` | | AsciiDoc heading level (1-6) | +| `content` | `string` \| Array<`object`> | ✓ | AsciiDoc content for this section | +| `when()` | `string` | | IDL boolean expression. When true, this section applies | + +
+ +
+references item schema + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `title` | `string` | ✓ | | +| `url` | `string` | ✓ | | +| `description` | `string` | | | + +
+ +
+authors item schema + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `name` | `string` | ✓ | Author's full name | +| `email` | `string` | | Author's email address | +| `organization` | `object` | | Author's organization, which should be an RVI member (or individual) | + +
+ + + +## Schema Information + +| Property | Value | +|----------|-------| +| Version | `v0.1` | +| JSON Schema Version | [Draft 07](https://json-schema.org/draft-07) | diff --git a/doc/docs/schemas/v0.1/param_schema.mdx b/doc/docs/schemas/v0.1/param_schema.mdx new file mode 100644 index 0000000000..a1a9d5ba78 --- /dev/null +++ b/doc/docs/schemas/v0.1/param_schema.mdx @@ -0,0 +1,44 @@ +--- +title: Param Schema (v0.1) +sidebar_label: Param Schema +custom_edit_url: null +# This file is auto-generated from param_schema.json +# Do not edit manually - run `bin/chore gen schema-docs` to regenerate +--- + + +# Param Schema + +v0.1 + +
+ +:::note Auto-generated +This page is generated from [`param_schema.json`](https://github.com/riscv/riscv-unified-db/blob/main/spec/schemas/param_schema.json) by the [schema doc generator](https://github.com/riscv/riscv-unified-db/blob/main/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen.rb). To update this page, edit the schema file and run `bin/chore gen schema-docs`. +::: + + +## Properties + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `$schema` | `any` | ✓ | | +| `kind` | `any` | ✓ | | +| `long_name` | `string` | ✓ | Short description of the parameter | +| `description` | `string` \| Array<[`conditional_text`](#conditional-text)> | ✓ | Parameter description, including list of valid values | +| `definedBy` | A condition (YAML structure or IDL function). See the conditions reference for details. | ✓ | Extension requirement condition that must be met for parameter to exist. The condition that the defining extension is implemented is implicit, and does not need to be explicitly listed | +| `schema` | [`json-schema-draft-07`](http://json-schema.org/draft-07/schema#) | ✓ | | +| `name` | `string` (pattern: `^[A-Z][A-Z_0-9]*$`) | | | +| `requirements` | A condition (YAML structure or IDL function). See the conditions reference for details. | | | + +:::note Tooling field +`$source` is an optional field set automatically by UDB tooling to record the file path this object was loaded from. You do not need to set it manually. +::: + + +## Schema Information + +| Property | Value | +|----------|-------| +| Version | `v0.1` | +| JSON Schema Version | [Draft 07](https://json-schema.org/draft-07) | diff --git a/doc/docs/schemas/v0.1/prm_schema.mdx b/doc/docs/schemas/v0.1/prm_schema.mdx new file mode 100644 index 0000000000..1c56daca84 --- /dev/null +++ b/doc/docs/schemas/v0.1/prm_schema.mdx @@ -0,0 +1,122 @@ +--- +title: Prm Schema (v0.1) +sidebar_label: Prm Schema +custom_edit_url: null +# This file is auto-generated from prm_schema.json +# Do not edit manually - run `bin/chore gen schema-docs` to regenerate +--- + + +import AnchorOpenDetails from '@site/src/components/AnchorOpenDetails'; + + + +# Prm Schema + +v0.1 + +
+ +:::note Auto-generated +This page is generated from [`prm_schema.json`](https://github.com/riscv/riscv-unified-db/blob/main/spec/schemas/prm_schema.json) by the [schema doc generator](https://github.com/riscv/riscv-unified-db/blob/main/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen.rb). To update this page, edit the schema file and run `bin/chore gen schema-docs`. +::: + + +## Definitions + +
+identifier + +**Type:** `string` + +
+ +
+specification_name + +**Type:** `string` + +
+ +
+prm_chapter + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `id` | [`identifier`](#identifier) | ✓ | Unique identifier for the chapter | +| `title` | `string` | ✓ | Human-readable title for the chapter | +| `description` | `string` | | Optional description of the chapter | +| `level` | `integer` | | AsciiDoc heading level (1-6) | +| `type` | `standard` \| `appendix` | | Type of chapter - standard or appendix | +| `auto_generate` | Array<`instructions` \| `csrs`> | | Auto-generate reference content for instructions and/or CSRs | +| `external_documentation` | Array<[`external_documentation`](#external-documentation)> | | External documentation sources to include | +| `non_isa_specifications` | Array<[`non_isa_specification`](#non-isa-specification)> | | UDB non-ISA specification references | + +
+ +
+external_documentation — External documentation source (ISA manuals, external specs, etc.) + +External documentation source (ISA manuals, external specs, etc.) + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `source` | `string` | ✓ | Source identifier (e.g., 'riscv-isa-manual', 'riscv-elf-psabi-doc') | +| `type` | `isa_manual` \| `external_spec` | ✓ | Type of external documentation | +| `path` | `string` | ✓ | Relative path from workspace root to documentation directory | +| `version` | Version requirement or list of requirements (e.g., `>= 2.0` or `['>= 2.0', '< 3.0']`) | | Version requirement | +| `chapters` | Array<[`external_chapter`](#external-chapter)> | | Specific chapters or sections to include | +| `resolve_includes` | `boolean` | | Resolve AsciiDoc include directives | + +
+ +
+non_isa_specification — UDB non-ISA specification reference + +UDB non-ISA specification reference + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `name` | [`specification_name`](#specification-name) | ✓ | Name of the UDB non-ISA specification | +| `version` | Version requirement or list of requirements (e.g., `>= 2.0` or `['>= 2.0', '< 3.0']`) | ✓ | Version requirement for the specification | + +
+ +
+external_chapter — Reference to external chapter or section + +Reference to external chapter or section + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `file` | `string` | ✓ | Filename to include (e.g., 'riscv-cc.adoc', 'rv32.adoc') | +| `title` | `string` | | Custom title for this chapter | +| `exclude_content` | Array<`string`> | | Content IDs to exclude (excludes entire sections/chapters and their subsections by AsciiDoc ID) | +| `level_offset` | `integer` | | Heading level offset | + +
+ + + +## Properties + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `$schema` | `any` | ✓ | | +| `kind` | `any` | ✓ | | +| `name` | [`specification_name`](#specification-name) | ✓ | Name (database key) of this PRM | +| `description` | `string` | ✓ | Brief description of this PRM | +| `processor_config` | `object` | ✓ | | +| `chapters` | Array<[`prm_chapter`](#prm-chapter)> | ✓ | Ordered list of chapters in the PRM | + +:::note Tooling field +`$source` is an optional field set automatically by UDB tooling to record the file path this object was loaded from. You do not need to set it manually. +::: + + +## Schema Information + +| Property | Value | +|----------|-------| +| Version | `v0.1` | +| JSON Schema Version | [Draft 07](https://json-schema.org/draft-07) | diff --git a/doc/docs/schemas/v0.1/proc_cert_class_schema.mdx b/doc/docs/schemas/v0.1/proc_cert_class_schema.mdx new file mode 100644 index 0000000000..271dbb1a55 --- /dev/null +++ b/doc/docs/schemas/v0.1/proc_cert_class_schema.mdx @@ -0,0 +1,42 @@ +--- +title: Proc Cert Class Schema (v0.1) +sidebar_label: Proc Cert Class Schema +custom_edit_url: null +# This file is auto-generated from proc_cert_class_schema.json +# Do not edit manually - run `bin/chore gen schema-docs` to regenerate +--- + + +# Proc Cert Class Schema + +v0.1 + +
+ +:::note Auto-generated +This page is generated from [`proc_cert_class_schema.json`](https://github.com/riscv/riscv-unified-db/blob/main/spec/schemas/proc_cert_class_schema.json) by the [schema doc generator](https://github.com/riscv/riscv-unified-db/blob/main/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen.rb). To update this page, edit the schema file and run `bin/chore gen schema-docs`. +::: + + +## Properties + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `$schema` | `any` | ✓ | | +| `kind` | `any` | ✓ | | +| `name` | `string` | ✓ | The short name of the class, used as a database key | +| `long_name` | `string` | ✓ | Descriptive name of the class | +| `introduction` | `string` | ✓ | Asciidoc text containing the introduction prose for the class | +| `processor_kind` | `Generic Unprivileged` \| `Microcontroller` \| `Apps Processor` | | What kind of class is this? | + +:::note Tooling field +`$source` is an optional field set automatically by UDB tooling to record the file path this object was loaded from. You do not need to set it manually. +::: + + +## Schema Information + +| Property | Value | +|----------|-------| +| Version | `v0.1` | +| JSON Schema Version | [Draft 07](https://json-schema.org/draft-07) | diff --git a/doc/docs/schemas/v0.1/proc_cert_model_schema.mdx b/doc/docs/schemas/v0.1/proc_cert_model_schema.mdx new file mode 100644 index 0000000000..3be8400017 --- /dev/null +++ b/doc/docs/schemas/v0.1/proc_cert_model_schema.mdx @@ -0,0 +1,102 @@ +--- +title: Proc Cert Model Schema (v0.1) +sidebar_label: Proc Cert Model Schema +custom_edit_url: null +# This file is auto-generated from proc_cert_model_schema.json +# Do not edit manually - run `bin/chore gen schema-docs` to regenerate +--- + + +import AnchorOpenDetails from '@site/src/components/AnchorOpenDetails'; + + + +# Proc Cert Model Schema + +v0.1 + +
+ +:::note Auto-generated +This page is generated from [`proc_cert_model_schema.json`](https://github.com/riscv/riscv-unified-db/blob/main/spec/schemas/proc_cert_model_schema.json) by the [schema doc generator](https://github.com/riscv/riscv-unified-db/blob/main/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen.rb). To update this page, edit the schema file and run `bin/chore gen schema-docs`. +::: + + +## Properties + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `$schema` | `any` | ✓ | | +| `kind` | `any` | ✓ | | +| `name` | `string` | ✓ | The short name of the model, used as a database key | +| `long_name` | `string` | ✓ | One line description of certificate model | +| `base` | `32` \| `64` | ✓ | Base of the model | +| `recommendations` | Array<\{`text`\}> [↓ schema](#recommendations-schema) | | | +| `extra_notes` | Array<\{`presence`, `text`\}> [↓ schema](#extra-notes-schema) | | | +| `requirement_groups` | `object` | | | +| `param_constraints` | `object` | | | +| `extensions` | `object` | | | +| `in_scope_priv_modes` | Array<`M` \| `S` \| `U` \| `HS` \| `VS` \| `VU`> | | List of in-scope privilege modes for the certificate | +| `debug_manual_revision` | `string` | | | +| `priv_isa_manual_revision` | `string` | | | +| `unpriv_isa_manual_revision` | `string` | | | +| `tsc_profile_release` | One of: `null` \| `object` | | Profile release associated with this certificate | +| `introduction` | `string` | | Asciidoc text containing the introduction prose for the model | +| `revision_history` | Array<\{`revision`, `date`, `changes`\}> [↓ schema](#revision-history-schema) | | Revisions of the model document | +| `versions` | Array<\{`version`\}> [↓ schema](#versions-schema) | | List of semantic versions within the model | +| `class` | `object` | | Reference to the class this model belongs to | +| `$parent_of` | One of: `string` \| Array<`string`> | | | +| `$child_of` | One of: `string` \| Array<`string`> | | | +| `$inherits` | One of: `string` \| Array<`string`> | | | + +
+recommendations item schema + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `text` | `string` | | | + +
+ +
+extra_notes item schema + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `presence` | `mandatory` \| `optional` \| `prohibited` \| `object` | | | +| `text` | `string` | | | + +
+ +
+revision_history item schema + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `revision` | `string` | ✓ | Revision number | +| `date` | `string` | ✓ | The date of the change | +| `changes` | Array<`string`> | ✓ | List of changes | + +
+ +
+versions item schema + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `version` | `string` | ✓ | | + +
+ + +:::note Tooling field +`$source` is an optional field set automatically by UDB tooling to record the file path this object was loaded from. You do not need to set it manually. +::: + + +## Schema Information + +| Property | Value | +|----------|-------| +| Version | `v0.1` | +| JSON Schema Version | [Draft 07](https://json-schema.org/draft-07) | diff --git a/doc/docs/schemas/v0.1/profile_family_schema.mdx b/doc/docs/schemas/v0.1/profile_family_schema.mdx new file mode 100644 index 0000000000..91aeaba649 --- /dev/null +++ b/doc/docs/schemas/v0.1/profile_family_schema.mdx @@ -0,0 +1,47 @@ +--- +title: Profile Family Schema (v0.1) +sidebar_label: Profile Family Schema +custom_edit_url: null +# This file is auto-generated from profile_family_schema.json +# Do not edit manually - run `bin/chore gen schema-docs` to regenerate +--- + + +# Profile Family Schema + +v0.1 + +
+ +:::note Auto-generated +This page is generated from [`profile_family_schema.json`](https://github.com/riscv/riscv-unified-db/blob/main/spec/schemas/profile_family_schema.json) by the [schema doc generator](https://github.com/riscv/riscv-unified-db/blob/main/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen.rb). To update this page, edit the schema file and run `bin/chore gen schema-docs`. +::: + + +## Properties + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `$schema` | `any` | ✓ | | +| `kind` | `any` | ✓ | | +| `name` | `string` | ✓ | Name (database key) of this Profile Family | +| `long_name` | `string` | ✓ | One line description of family | +| `processor_kind` | `Generic Unprivileged` \| `Microcontroller` \| `Apps Processor` | | What kind of processor is this? | +| `marketing_name` | `string` | | The publicly displayed profile family name | +| `introduction` | `string` | | Asciidoc text containing the introduction prose for the family | +| `description` | `string` \| Array<[`conditional_text`](#conditional-text)> | | Asciidoc text containing longer description prose for the family | +| `naming_scheme` | `string` | | Commentary on how profile releases in the family are named | +| `company` | A company | | | +| `doc_license` | License that applies to the textual documentation for this extension | | | + +:::note Tooling field +`$source` is an optional field set automatically by UDB tooling to record the file path this object was loaded from. You do not need to set it manually. +::: + + +## Schema Information + +| Property | Value | +|----------|-------| +| Version | `v0.1` | +| JSON Schema Version | [Draft 07](https://json-schema.org/draft-07) | diff --git a/doc/docs/schemas/v0.1/profile_release_schema.mdx b/doc/docs/schemas/v0.1/profile_release_schema.mdx new file mode 100644 index 0000000000..d839bf8aca --- /dev/null +++ b/doc/docs/schemas/v0.1/profile_release_schema.mdx @@ -0,0 +1,36 @@ +--- +title: Profile Release Schema (v0.1) +sidebar_label: Profile Release Schema +custom_edit_url: null +# This file is auto-generated from profile_release_schema.json +# Do not edit manually - run `bin/chore gen schema-docs` to regenerate +--- + + +# Profile Release Schema + +v0.1 + +
+ +:::note Auto-generated +This page is generated from [`profile_release_schema.json`](https://github.com/riscv/riscv-unified-db/blob/main/spec/schemas/profile_release_schema.json) by the [schema doc generator](https://github.com/riscv/riscv-unified-db/blob/main/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen.rb). To update this page, edit the schema file and run `bin/chore gen schema-docs`. +::: + + +## Properties + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `$schema` | `any` | ✓ | | +| `kind` | `any` | ✓ | | +| `name` | `string` | ✓ | Name (database key) of this Profile Release | +| `long name` | `string` | | One line description of this Profile Release | + + +## Schema Information + +| Property | Value | +|----------|-------| +| Version | `v0.1` | +| JSON Schema Version | [Draft 07](https://json-schema.org/draft-07) | diff --git a/doc/docs/schemas/v0.1/profile_schema.mdx b/doc/docs/schemas/v0.1/profile_schema.mdx new file mode 100644 index 0000000000..c55ca3ddf6 --- /dev/null +++ b/doc/docs/schemas/v0.1/profile_schema.mdx @@ -0,0 +1,77 @@ +--- +title: Profile Schema (v0.1) +sidebar_label: Profile Schema +custom_edit_url: null +# This file is auto-generated from profile_schema.json +# Do not edit manually - run `bin/chore gen schema-docs` to regenerate +--- + + +import AnchorOpenDetails from '@site/src/components/AnchorOpenDetails'; + + + +# Profile Schema + +v0.1 + +
+ +:::note Auto-generated +This page is generated from [`profile_schema.json`](https://github.com/riscv/riscv-unified-db/blob/main/spec/schemas/profile_schema.json) by the [schema doc generator](https://github.com/riscv/riscv-unified-db/blob/main/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen.rb). To update this page, edit the schema file and run `bin/chore gen schema-docs`. +::: + + +## Properties + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `$schema` | `any` | ✓ | | +| `kind` | `any` | ✓ | | +| `name` | `string` | ✓ | Name (database key) of this Profile | +| `long_name` | `string` | ✓ | One line description of profile | +| `base` | `integer` | ✓ | 32 for RV32I or 64 for RV64I | +| `extensions` | `object` | | | +| `extra_notes` | Array<\{`text`, `presence`\}> [↓ schema](#extra-notes-schema) | | | +| `recommendations` | Array<\{`text`\}> [↓ schema](#recommendations-schema) | | | +| `introduction` | `string` | | | +| `release` | `object` | | | +| `mode` | `M` \| `S` \| `U` \| `Unpriv` | | | +| `marketing_name` | `string` | | | +| `requirements` | A condition (YAML structure or IDL function). See the conditions reference for details. | | | +| `cert_normative_rules` | Architecturally visible behaviors requiring validation by certification tests | | | +| `$child_of` | `string` | | | +| `$parent_of` | `string` | | | +| `$inherits` | `string` | | | + +
+extra_notes item schema + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `text` | `string` | ✓ | | +| `presence` | `optional` \| `mandatory` | ✓ | | + +
+ +
+recommendations item schema + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `text` | `string` | ✓ | | + +
+ + +:::note Tooling field +`$source` is an optional field set automatically by UDB tooling to record the file path this object was loaded from. You do not need to set it manually. +::: + + +## Schema Information + +| Property | Value | +|----------|-------| +| Version | `v0.1` | +| JSON Schema Version | [Draft 07](https://json-schema.org/draft-07) | diff --git a/doc/docs/schemas/v0.1/register_file_schema.mdx b/doc/docs/schemas/v0.1/register_file_schema.mdx new file mode 100644 index 0000000000..776572b074 --- /dev/null +++ b/doc/docs/schemas/v0.1/register_file_schema.mdx @@ -0,0 +1,74 @@ +--- +title: Register File Schema (v0.1) +sidebar_label: Register File Schema +custom_edit_url: null +# This file is auto-generated from register_file_schema.json +# Do not edit manually - run `bin/chore gen schema-docs` to regenerate +--- + + +import AnchorOpenDetails from '@site/src/components/AnchorOpenDetails'; + + + +# Register File Schema + +v0.1 + +
+ +:::note Auto-generated +This page is generated from [`register_file_schema.json`](https://github.com/riscv/riscv-unified-db/blob/main/spec/schemas/register_file_schema.json) by the [schema doc generator](https://github.com/riscv/riscv-unified-db/blob/main/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen.rb). To update this page, edit the schema file and run `bin/chore gen schema-docs`. +::: + +Schema for describing a register file + + +## Definitions + +
+register_entry + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `name` | Register name | ✓ | | +| `abi_mnemonics` | Array<Register alias or ABI mnemonic> | | ABI mnemonic names for the register | +| `description` | `string` \| Array<[`conditional_text`](#conditional-text)> | | | +| `when` | A requirement on an extension. Can either specify just an extension name, in which case version '>= 0' is implied, or both a name and a requirement \| `object` | | | +| `arch_read()` | `string` | | Function describing the architecturally defined read behavior. Use this for architecturally mandated effects (e.g., x0 always reads as zero). | +| `arch_write(value)` | `string` | | Function describing the architecturally defined write behavior. Given a 'value', return the architecturally required result (e.g., x0 ignores writes and always yields zero). | +| `caller_saved` | `boolean` | | Whether the register is caller-saved | +| `callee_saved` | `boolean` | | Whether the register is callee-saved | +| `roles` | Array<`zero` \| `return_address` \| `alternate_link_register` \| `stack_pointer` \| `global_pointer` \| `thread_pointer` \| `frame_pointer` \| `return_value` \| `argument` \| `temporary`> | | | + +
+ +
+register_file + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `$schema` | `any` | ✓ | Path to schema, relative to <UDB ROOT>/schemas | +| `kind` | `any` | ✓ | | +| `name` | Register file name | ✓ | | +| `long_name` | `string` | ✓ | | +| `description` | `string` \| Array<[`conditional_text`](#conditional-text)> | ✓ | | +| `register_length` | Bit width value for a register or field | ✓ | | +| `registers` | Array<[`register_entry`](#register-entry)> | ✓ | | +| `definedBy` | A requirement on an extension. Can either specify just an extension name, in which case version '>= 0' is implied, or both a name and a requirement \| `object` | | | +| `register_class` | `general_purpose` \| `floating_point` \| `vector` | | | + +:::note Tooling field +`$source` is an optional field set automatically by UDB tooling to record the file path this object was loaded from. You do not need to set it manually. +::: + +
+ + + +## Schema Information + +| Property | Value | +|----------|-------| +| Version | `v0.1` | +| JSON Schema Version | [Draft 07](https://json-schema.org/draft-07) | diff --git a/doc/docs/schemas/v0.1/schema_defs.mdx b/doc/docs/schemas/v0.1/schema_defs.mdx new file mode 100644 index 0000000000..290937177e --- /dev/null +++ b/doc/docs/schemas/v0.1/schema_defs.mdx @@ -0,0 +1,592 @@ +--- +title: Common patterns used by all schemas (v0.1) +sidebar_label: Common patterns used by all schemas +custom_edit_url: null +# This file is auto-generated from schema_defs.json +# Do not edit manually - run `bin/chore gen schema-docs` to regenerate +--- + + +import AnchorOpenDetails from '@site/src/components/AnchorOpenDetails'; + + + +# Common patterns used by all schemas + +v0.1 + +
+ +:::note Auto-generated +This page is generated from [`schema_defs.json`](https://github.com/riscv/riscv-unified-db/blob/main/spec/schemas/schema_defs.json) by the [schema doc generator](https://github.com/riscv/riscv-unified-db/blob/main/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen.rb). To update this page, edit the schema file and run `bin/chore gen schema-docs`. +::: + + +## Definitions + +
+$source — Path to the source file containing this object + +Path to the source file containing this object + +**Type:** `string` + +
+ +
+semantic_version + +**Type:** `string` + +
+ +
+rvi_version + +**Type:** `string` + +
+ +
+csr_name — CSR name + +CSR name + +**Type:** `string` + +
+ +
+csr_field — CSR field + +CSR field + +**Type:** `string` + +
+ +
+csr_field_bits — CSR field + +CSR field + +**Type:** `string` + +
+ +
+field_location — Location of a field in a register + +Location of a field in a register + +
+ +
+bit_length_value — Bit width value for a register or field + +Bit width value for a register or field + +
+ +
+register_name — Register name + +Register name + +**Type:** `string` + +
+ +
+register_file_name — Register file name + +Register file name + +**Type:** `string` + +
+ +
+register_alias — Register alias or ABI mnemonic + +Register alias or ABI mnemonic + +**Type:** `string` + +
+ +
+possibly_split_field_location — Location specifier for a field + +Location specifier for a field + +
+ +
+revision_history_entry + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `revision` | [`semantic_version`](#semantic-version) | ✓ | Revision number | +| `date` | `string` | ✓ | The date of the change | +| `changes` | Array<`string`> | ✓ | List of changes | + +
+ +
+spec_state — Ratification state of a specification or extension version: `development` (actively being worked on), `frozen` (feature-complete, under review), `public-review` (open for public comment), `ratification-ready` (approved by the task group, awaiting board vote), `ratified` (officially approved by RISC-V International), or `nonstandard-released` (released but not part of the RISC-V standard). + +Ratification state of a specification or extension version: `development` (actively being worked on), `frozen` (feature-complete, under review), `public-review` (open for public comment), `ratification-ready` (approved by the task group, awaiting board vote), `ratified` (officially approved by RISC-V International), or `nonstandard-released` (released but not part of the RISC-V standard). + +**Allowed values:** + +- `development` +- `frozen` +- `public-review` +- `ratification-ready` +- `ratified` +- `nonstandard-released` + +
+ +
+spec_text + +
+ +
+conditional_text + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `text` | `string` | ✓ | Asciidoctor source | +| `when()` | `string` | | IDL boolean expression. When true, the text applies | +| `when_ast` | `object` | | | + +
+ +
+license — License that applies to the textual documentation for this extension + +License that applies to the textual documentation for this extension + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `name` | `string` | | License name | +| `id` | `string` | | License identifier | +| `url` | `string` | | Link to license text | +| `text_url` | `string` | | Link to license text | + +
+ +
+company — A company + +A company + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `name` | `string` | | Name of the company. Should be "RISC-V International" for standard extensions | +| `url` | `string` | | Website of the company. Should be "https://riscv.org" for standard extensions | + +
+ +
+extension_presence + +
+ +
+date — A specific day in YYYY-MM-DD format + +A specific day in YYYY-MM-DD format + +**Type:** `string` + +
+ +
+extension_name — Extension name (e.g., `I`, `M`, `Zicsr`, `Smstateen`) + +Extension name (e.g., `I`, `M`, `Zicsr`, `Smstateen`) + +**Type:** `string` + +
+ +
+extension_version — Exact version in `MAJOR[.MINOR[.PATCH]]` format (e.g., `2.1.0`, `2.1`, `2`) + +Exact version in `MAJOR[.MINOR[.PATCH]]` format (e.g., `2.1.0`, `2.1`, `2`) + +
+ +
+requirement_string — Version requirement string (e.g., `>= 2.0`, `~> 1.5`, `= 2.1`) + +Version requirement string (e.g., `>= 2.0`, `~> 1.5`, `= 2.1`) + +**Type:** `string` + +
+ +
+version_requirements — Version requirement or list of requirements (e.g., `>= 2.0` or `['>= 2.0', '< 3.0']`) + +Version requirement or list of requirements (e.g., `>= 2.0` or `['>= 2.0', '< 3.0']`) + +
+ +
+extension_requirement — A requirement on an extension. Can either specify just an extension name, in which case version '>= 0' is implied, or both a name and a requirement + +A requirement on an extension. Can either specify just an extension name, in which case version '>= 0' is implied, or both a name and a requirement + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `name` | [`extension_name`](#extension-name) | ✓ | | +| `version` | [`version_requirements`](#version-requirements) | | | + +
+ +
+param_name + +**Type:** `string` + +
+ +
+param_requirement + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `name` | [`param_name`](#param-name) | ✓ | | +| `schema` | [`json-schema-draft-07`](http://json-schema.org/draft-07/schema#) | ✓ | | + +
+ +
+requires_entry + +
+ +
+extension_with_version + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `name` | [`extension_name`](#extension-name) | ✓ | | +| `version` | [`extension_version`](#extension-version) | ✓ | | + +
+ +
+author + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `name` | `string` | ✓ | Author's full name | +| `email` | `string` | | Author's email address | +| `organization` | [`organization`](#organization) | | Author's organization, which should be an RVI member (or individual) | + +
+ +
+organization + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `name` | `string` | ✓ | Organization name | +| `url` | `string` | | Organization URL | + +
+ +
+when_condition + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `version` | [`version_requirements`](#version-requirements) | | | + +
+ +
+parameter_constraint + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `schema` | [`json-schema-draft-07`](http://json-schema.org/draft-07/schema#) | | | +| `when` | [`when_condition`](#when-condition) | | | + +
+ +
+cert_normative_rules — Architecturally visible behaviors requiring validation by certification tests + +Architecturally visible behaviors requiring validation by certification tests + +**Type:** `array` + +
+ +
+encoding_match + +
+ +
+inst_type_name + +**Type:** `string` + +
+ +
+inst_subtype_name + +**Type:** `string` + +
+ +
+reference — reference to another database object, as a JSON Reference + +reference to another database object, as a JSON Reference + +**Type:** `string` + +
+ +
+integer — An integer, either native to JSON or a number-like string + +An integer, either native to JSON or a number-like string + +
+ +
+ref_url + +**Type:** `string` + +
+ +
+ref_url_list + +
+ +
+extension_condition — A logic condition specifying certain extension version requirements + +A logic condition specifying certain extension version requirements + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `extension` | One of: [`extension_requirement`](#extension-requirement) \| `object` \| `object` | ✓ | | + +
+ +
+param_condition + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `param` | One of: `object` \| `object` | ✓ | | + +
+ +
+idl — IDL code + +IDL code + +**Type:** `string` + +
+ +
+idl_condition — A condition expressed with IDL + +A condition expressed with IDL + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `idl()` | [`idl`](#idl) | ✓ | IDL function containing one or more implications (e.g., A -> B). | +| `idl_ast` | `object` | | | +| `reason` | `string` | | Why the constraint exists | + +
+ +
+yaml_condition + +
+ +
+xlen_condition + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `xlen` | `32` \| `64` | ✓ | | + +
+ +
+condition — A condition (YAML structure or IDL function). See the conditions reference for details. + +A condition (YAML structure or IDL function). See the conditions reference for details. + +
+ +
+extension_requirement_list_item — A list of extension requirements, possibly with a condition + +A list of extension requirements, possibly with a condition + +
+ +
+extension_requirement_list + +
+ +
+uint32 + +**Type:** `integer` + +
+ +
+uint64 + +**Type:** `integer` + +
+ +
+32bit_unsigned_pow2 — An unsigned power of 2 that fits in 32 bits + +An unsigned power of 2 that fits in 32 bits + +**Allowed values:** + +- `1` +- `2` +- `4` +- `8` +- `16` +- `32` +- `64` +- `128` +- `256` +- `512` +- `1024` +- `2048` +- `4095` +- `8192` +- `16384` +- `32768` +- `65536` +- `131072` +- `262144` +- `524288` +- `1048576` +- `2097152` +- `4194304` +- `8388608` +- `16777216` +- `33554432` +- `67108864` +- `134217728` +- `268435456` +- `536870912` +- `1073741824` +- `2147483648` + +
+ +
+64bit_unsigned_pow2 — An unsigned power of 2 that fits in 64 bits + +An unsigned power of 2 that fits in 64 bits + +**Allowed values:** + +- `1` +- `2` +- `4` +- `8` +- `16` +- `32` +- `64` +- `128` +- `256` +- `512` +- `1024` +- `2048` +- `4095` +- `8192` +- `16384` +- `32768` +- `65536` +- `131072` +- `262144` +- `524288` +- `1048576` +- `2097152` +- `4194304` +- `8388608` +- `16777216` +- `33554432` +- `67108864` +- `134217728` +- `268435456` +- `536870912` +- `1073741824` +- `2147483648` +- `4294967296` +- `8589934592` +- `17179869184` +- `34359738368` +- `68719476736` +- `137438953472` +- `274877906944` +- `549755813888` +- `1099511627776` +- `2199023255552` +- `4398046511104` +- `8796093022208` +- `17592186044416` +- `35184372088832` +- `70368744177664` +- `140737488355328` +- `281474976710656` +- `562949953421312` +- `1125899906842624` +- `2251799813685248` +- `4503599627370496` +- `9007199254740992` +- `18014398509481984` +- `36028797018963968` +- `72057594037927936` +- `144115188075855872` +- `288230376151711744` +- `576460752303423488` +- `1152921504606846976` +- `2305843009213693952` +- `4611686018427387904` +- `9223372036854775808` + +
+ + + +## Schema Information + +| Property | Value | +|----------|-------| +| Version | `v0.1` | +| JSON Schema Version | [Draft 07](https://json-schema.org/draft-07) | diff --git a/doc/docs/schemas/v0.2/_category_.json b/doc/docs/schemas/v0.2/_category_.json new file mode 100644 index 0000000000..a58bd58ecc --- /dev/null +++ b/doc/docs/schemas/v0.2/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "v0.2", + "position": 1, + "collapsible": true, + "collapsed": false +} diff --git a/doc/docs/schemas/v0.2/csr_schema.mdx b/doc/docs/schemas/v0.2/csr_schema.mdx new file mode 100644 index 0000000000..a22752b647 --- /dev/null +++ b/doc/docs/schemas/v0.2/csr_schema.mdx @@ -0,0 +1,72 @@ +--- +title: CSR description (v0.2) +sidebar_label: CSR description +custom_edit_url: null +# This file is auto-generated from csr_schema.json +# Do not edit manually - run `bin/chore gen schema-docs` to regenerate +--- + + +import AnchorOpenDetails from '@site/src/components/AnchorOpenDetails'; + + + +# CSR description + +v0.2 + +
+ +:::note Auto-generated +This page is generated from [`csr_schema.json`](https://github.com/riscv/riscv-unified-db/blob/main/spec/schemas/csr_schema.json) by the [schema doc generator](https://github.com/riscv/riscv-unified-db/blob/main/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen.rb). To update this page, edit the schema file and run `bin/chore gen schema-docs`. +::: + +A CSR register specification + + +## Schema Structure + +This schema requires **all of** the following: + +- (Complex type) +- (Complex type) + + +## Definitions + +
+csr_field — Field in a CSR register + +Field in a CSR register + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `description` | `string` \| Array<[`conditional_text`](#conditional-text)> | ✓ | Function of the field | +| `cert_normative_rules` | Architecturally visible behaviors requiring validation by certification tests | | | +| `affectedBy` | One of: `string` \| Array<`string`> | | Extension(s) that affect the definition of the field beyond the extension (or base) the field is originally defined in | +| `definedBy` | A condition (YAML structure or IDL function). See the conditions reference for details. | | Where this field is defined: indicates that the field is only present if the extension(s) are implemented. If definedBy is not given, defaults to the definedBy field of the parent CSR | +| `alias` | One of: CSR field \| CSR field \| Array<One of: CSR field \| CSR field> | | When specified, indicates that this field aliases (a portion of) another CSR field | +| `type_ast` | `object` | | | +| `type()` | `string` | | Function that returns a configuration-dependent type. The return value should be a CsrFieldType enum, and must be compile-time-known. | +| `type` | `RO` \| `RO-H` \| `RW` \| `RW-R` \| `RW-H` \| `RW-RH` | | Type of the field. One of: * RO: Read-only immutable * RO-H: Read-only, updated by hardware * RW: Read-write, not updated by hardware * RW-R: Read-write, but values are restricted. sw_write(value) must be provided * RW-H: Read-write, with hardware updates * RW-RH: Read-write, with hardware updates, but values are restricted. sw_write(value) must be provided | +| `sw_write_ast` | `object` | | | +| `sw_write(csr_value)` | `string` | | Function implementing custom write behavior for the CSR. Given a 'value', return either the value to be written in the field or false if the write would be illegal. 'value' is the value of the entire CSR, which is sometimes needed to detect illegal writes | +| `reset_value_ast` | `object` | | | +| `reset_value()` | `string` | | Configuration-dependent value of the state after reset. Can be UNDEFINED_LEGAL for the generic architecture spec, but must have an integer value for the implementation spec. | +| `reset_value` | One of: `integer` \| `string` (const: `UNDEFINED_LEGAL`) | | Value of the state after reset. Can be UNDEFINED_LEGAL for the generic architecture spec, but must have an integer value for the implementation spec | +| `location_rv64` | Location of a field in a register | | Location of the field within the CSR register when the effective XLEN of the current mode is 64 | +| `location_rv32` | Location of a field in a register | | Location of the field within the CSR register when the effective XLEN of the current mode is 32 | +| `location` | Location of a field in a register | | Location of the field within the CSR register | +| `long_name` | `string` | | One line description of the CSR field | +| `name` | `string` | | Name of the field. Optional because it is implied by the object key of the CSR object holding the field | + +
+ + + +## Schema Information + +| Property | Value | +|----------|-------| +| Version | `v0.2` | +| JSON Schema Version | [Draft 07](https://json-schema.org/draft-07) | diff --git a/doc/docs/schemas/v0.2/inst_schema.mdx b/doc/docs/schemas/v0.2/inst_schema.mdx new file mode 100644 index 0000000000..7854d97fb5 --- /dev/null +++ b/doc/docs/schemas/v0.2/inst_schema.mdx @@ -0,0 +1,146 @@ +--- +title: Inst Schema (v0.2) +sidebar_label: Inst Schema +custom_edit_url: null +# This file is auto-generated from inst_schema.json +# Do not edit manually - run `bin/chore gen schema-docs` to regenerate +--- + + +import AnchorOpenDetails from '@site/src/components/AnchorOpenDetails'; + + + +# Inst Schema + +v0.2 + +
+ +:::note Auto-generated +This page is generated from [`inst_schema.json`](https://github.com/riscv/riscv-unified-db/blob/main/spec/schemas/inst_schema.json) by the [schema doc generator](https://github.com/riscv/riscv-unified-db/blob/main/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen.rb). To update this page, edit the schema file and run `bin/chore gen schema-docs`. +::: + + +## Definitions + +
+fully_resolved_opcodes + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `location` | `schema_defs.json#/$defs/field_location` | ✓ | | +| `display_name` | `string` | ✓ | field name, displayed in encoding drawings | +| `value` | One of: An integer, either native to JSON or a number-like string \| `object` | ✓ | | +| `$child_of` | One of: `string` \| Array<`string`> | | | + +
+ +
+fully_resolved_variables + + +
+ +
+fully_resolved_format + +
+ +
+old_encoding + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `match` | One of: `string` \| `string` \| `string` | | | +| `variables` | Array<[`field`](#field)> | | | +| `additionalProperties` | `never` | | | + +
+ +
+type + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `$ref` | `string` | ✓ | Reference to an instruction type definition | + +
+ +
+subtype + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `$ref` | `string` | ✓ | Reference to an instruction subtype definition | + +
+ +
+variable_metadata + +
+ +
+field — Decode field + +Decode field + + +
+ + + +## Properties + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `$schema` | `string` (const: `inst_schema.json#`) | ✓ | Path to schema, relative to <UDB ROOT>/schemas | +| `kind` | `string` (const: `instruction`) | ✓ | | +| `name` | `string` | ✓ | Instruction mnemonic (must be lowercase) | +| `long_name` | `string` | ✓ | One line description of the instruction | +| `description` | `string` \| Array<[`conditional_text`](#conditional-text)> | ✓ | Detailed description of the instruction | +| `definedBy` | A condition (YAML structure or IDL function). See the conditions reference for details. | ✓ | Extension(s) that defines the instruction | +| `access` | `object` | ✓ | | +| `assembly` | `string` | ✓ | Assembly format of the instruction. Can use decode variables | +| `encoding` | One of: [`old_encoding`](#old-encoding) \| `object` | | Instruction encoding and decode variables | +| `format` | `object` | | | +| `pseudoinstructions` | Array<\{`when`, `to`\}> [↓ schema](#pseudoinstructions-schema) | | Variations of this instruction that form a pseudoinstruction | +| `data_independent_timing` | `boolean` | | Whether or not the instruction must execute with data-independent timing when the Zkt extension is supported | +| `cert_normative_rules` | Architecturally visible behaviors requiring validation by certification tests | | | +| `operation_ast` | `object` | | | +| `operation()` | `string` | | Functional description of the instruction using IDL language | +| `access_detail` | `string` | | Extra detail about access when at least one mode is 'sometimes' | +| `hints` | Array<\{`$ref`\}> [↓ schema](#hints-schema) | | List of HINTs that use this instruction's codepoints | + +
+pseudoinstructions item schema + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `when` | `string` | | Condition when the instruction has an alias | +| `to` | `string` | | pseudoinstruction format | + +
+ +
+hints item schema + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `$ref` | `string` | ✓ | Ref to an instruction that is using a HINT codepoint(s) of this instruction | + +
+ + +:::note Tooling field +`$source` is an optional field set automatically by UDB tooling to record the file path this object was loaded from. You do not need to set it manually. +::: + + +## Schema Information + +| Property | Value | +|----------|-------| +| Version | `v0.2` | +| JSON Schema Version | [Draft 07](https://json-schema.org/draft-07) | diff --git a/doc/docusaurus.config.ts b/doc/docusaurus.config.ts index fbe4daa426..45edc1d526 100644 --- a/doc/docusaurus.config.ts +++ b/doc/docusaurus.config.ts @@ -14,8 +14,8 @@ const config: Config = { v4: true, }, - url: 'https://riscv.github.io', - baseUrl: '/riscv-unified-db/docs-preview/', + url: process.env.DOCUSAURUS_URL ?? 'https://riscv.github.io', + baseUrl: process.env.DOCUSAURUS_BASE_URL ?? '/riscv-unified-db/docs-preview/', organizationName: 'riscv', projectName: 'riscv-unified-db', @@ -54,11 +54,17 @@ const config: Config = { themeConfig: { image: 'img/udb-social-card.jpg', + announcementBar: { + id: 'under_construction', + content: '🚧 This documentation site is under active construction. See Documentation Status for details.', + backgroundColor: '#ffa500', + textColor: '#000000', + isCloseable: true, + }, colorMode: { respectPrefersColorScheme: true, }, navbar: { - title: 'UDB', logo: { alt: 'UDB Logo', src: 'img/udb.svg', @@ -80,8 +86,8 @@ const config: Config = { position: 'left', items: [ {label: 'Introduction', to: '/docs/intro/what-is-udb'}, - {label: 'Schemas', to: '/docs/schemas/overview'}, - {label: 'Configuration', to: '/docs/configuration/overview'}, + {label: 'Schema Reference', to: '/docs/schemas'}, + {label: 'Configurations', to: '/docs/concepts/configurations/overview'}, {label: 'Tools', to: '/docs/tools/overview'}, {label: 'Generators', to: '/docs/generators/overview'}, ], @@ -143,6 +149,7 @@ const config: Config = { prism: { theme: prismThemes.github, darkTheme: prismThemes.dracula, + additionalLanguages: ['yaml', 'json', 'bash'], }, } satisfies Preset.ThemeConfig, }; diff --git a/doc/planning/decisions.md b/doc/planning/decisions.md index 27413faf9b..8055d7c5a7 100644 --- a/doc/planning/decisions.md +++ b/doc/planning/decisions.md @@ -272,3 +272,92 @@ IDL has its own top-level navbar entry pointing to `/docs/idl`, separate from th 2. Update the IDL navbar item to point to `/docs/idl/overview` instead of `/docs/idl`. 3. Remove the `.idl-landing-*` CSS classes from `doc/src/css/custom.css`. 4. Optionally remove `react-icons` from `doc/package.json` if no other pages use it. + +--- + +## D7 — Schema documentation: custom Ruby generator + +**Status**: Decided +**Resolved from**: Phase 10.1 +**Date**: 2026-03 + +### Decision +Schema documentation is generated by a custom Ruby gem (`tools/internal-gems/schema_doc_gen/`) rather than an off-the-shelf tool. The generator is invoked via `bin/chore gen schema-docs` and produces MDX files under `doc/docs/schemas//`. Generated files are committed to the repo. + +### Rationale +- `@adobe/jsonschema2md` was evaluated and rejected: its output is plain Markdown with limited formatting control, no MDX support, and no way to inline cross-schema references. +- The custom generator gives full control over MDX output, section ordering, collapsible definitions, inline type expansion, and the `_quick_start` / `_title` example tagging convention. +- Committing generated files keeps the Docusaurus build self-contained (no Docker dependency at build time — see D4). + +### Key design choices made during implementation + +**Generator behavior:** +- Section order: Overview → Quick Start → Schema Structure → Definitions → Examples → Schema Information (metadata moved to bottom as least important) +- `type: null` properties are hidden from tables (used to mark fields that are intentionally absent in a given config type) +- `$source` properties are hidden from tables; a `:::note Tooling field` admonition appears below each table explaining the field is set automatically by tooling +- Required properties are sorted before optional properties within each table, preserving original order within each group +- Schema `$defs` references to `schema_defs.json` are inlined in type columns rather than linked, using descriptions from `schema_defs.json` when available (avoids broken cross-page anchor links) +- In item schema blocks (array-of-objects), `$ref` properties are split: the underlying type goes in the Type column, the def's description goes in the Description column +- Array items that are objects are expanded inline: `Array<{name: ..., version: ...}>` rather than `Array` +- Markdown blockquotes (`>` at line start) and comparison operators (`>=`, `<=`) are preserved when escaping HTML angle brackets in descriptions +- Backtick-enclosed content is never HTML-escaped +- MDX curly braces in table cells are escaped as `\{` and `\}` to prevent JSX parse errors +- Variants TOC uses plain links (not backtick-wrapped) since type names are not code identifiers +- `oneOf`/`anyOf` within `format_inline_definition` resolves sub-refs against `schema_defs` rather than producing dangling page-local anchor links + +**Page header design:** +- Schema version appears as a `` below the `

`, not inside it — the breadcrumb already shows the version +- A `
` provides vertical space between the badge and the first paragraph +- `custom_edit_url: null` suppresses the "Edit this page" footer link +- A `:::note Auto-generated` admonition below the badge links to both the source schema file and the generator script on GitHub +- The frontmatter YAML comment (`# This file is auto-generated...`) is retained for tooling/grep discoverability + +**Index page design:** +- Flat alphabetical grid of all schemas; each card shows its own version badge +- Version directory categories in the sidebar are labeled `v0.1`, `v0.2`, etc. — no "(Latest)" suffix, since schemas are versioned independently and there is no single "latest" version + +**Schema content conventions (established while reviewing `config_schema.json`):** +- Top-level `description` supports markdown headings (`##`) for sections within the overview (Quick Start, Key Fields, etc.) +- `_title` field on examples sets the collapsible summary label +- `_quick_start: true` on examples causes them to appear in the Quick Start section (as plain code blocks) rather than the Examples section (as collapsible details) +- All `_`-prefixed fields are stripped from displayed YAML +- Cross-links between schema reference and concepts docs: schema description links to concepts overview via blockquote; concepts overview links to schema reference via `:::tip` admonition +- `$schema`, `kind`, and `type` fields get descriptions explaining their constant values +- `params` field gets a description explaining what kinds of values it contains +- Semantic validation note added to `config_schema.json` top-level description, linking to the future `validating-configs.md` page +- `condition` def in `schema_defs.json` has a placeholder description pending task 4.3.0 (extract conditions into their own schema file) + +### Implemented in +- `tools/internal-gems/schema_doc_gen/lib/schema_doc_gen.rb` — main generator +- `tools/internal-gems/schema_doc_gen/lib/schema_doc_gen/index_generator.rb` — index page generator +- `tools/internal-gems/schema_doc_gen/bin/schema-docs-all` — category file generation +- `doc/docs/schemas/` — generated output (committed) +- `spec/schemas/config_schema.json` — fully reviewed and improved +- `spec/schemas/schema_defs.json` — `extension_name`, `requirement_string`, `version_requirements`, `extension_version`, `condition` descriptions added/corrected + +### Reversal: switch to a different generator +1. Delete `tools/internal-gems/schema_doc_gen/`. +2. Remove the `gen schema-docs` case from `bin/chore`. +3. Install and configure the replacement tool (e.g., `@adobe/jsonschema2md`). +4. Update `doc/docs/schemas/` with the new output format. +5. Update any cross-links that relied on the generated anchor structure. + +--- + +## D8 — Navbar: logo only, no title text + +**Status**: Decided +**Date**: 2026-03 + +### Decision +The Docusaurus navbar shows only the UDB logo SVG, with no `title` text next to it. The logo alone links to the home page. + +### Rationale +- The logo already contains the "UDB" wordmark as part of the SVG artwork. Showing "UDB" as text immediately next to the logo is redundant. +- Removing the text gives the navbar more horizontal space for navigation items. + +### Implemented in +- `doc/docusaurus.config.ts` — `title` key removed from the `navbar` config object + +### Reversal: restore the title text +Add `title: 'UDB'` back to the `navbar` object in `doc/docusaurus.config.ts`. diff --git a/doc/planning/documentation-implementation-plan.md b/doc/planning/documentation-implementation-plan.md index 83b4d2fe92..f12f167d8c 100644 --- a/doc/planning/documentation-implementation-plan.md +++ b/doc/planning/documentation-implementation-plan.md @@ -47,10 +47,10 @@ Set up the Docusaurus project, CI/CD, and scaffolding before writing any content - `organizationName`: `riscv`, `projectName`: `riscv-unified-db` - `favicon`: `/img/udb-block.svg` - Note: `onBrokenLinks` is set to `warn` during scaffolding; change to `throw` once content pages exist (Phase 13+). -- [x] **0.2.2** Configure navbar: `[UDB logo] [Docs] [API Reference] [Browse Spec ↗] [GitHub ↗]` +- [x] **0.2.2** Configure navbar: `[UDB logo] [Docs] [API Reference] [Browse Spec ↗] [GitHub ↗]`. Note: the `title: 'UDB'` text next to the logo was later removed (the logo alone links home) — see D8. - [x] **0.2.3** Configure footer with license info and GitHub link. - [x] **0.2.4** Configure `plugin-content-docs` with `sidebarPath` pointing to `doc/sidebars.ts`. Added `planning/**` to the `exclude` list so Docusaurus does not treat `doc/planning/` as content. -- [x] **0.2.5** Set `editUrl` to `https://github.com/riscv/riscv-unified-db/tree/main/doc/` so every page has an "Edit this page" link. +- [x] **0.2.5** Set `editUrl` to `https://github.com/riscv/riscv-unified-db/tree/main/doc/` so every page has an "Edit this page" link. Note: auto-generated schema doc pages suppress this link via `custom_edit_url: null` and instead show an inline `:::note Auto-generated` admonition — see D7. ### 0.3 — Search @@ -177,6 +177,54 @@ All four use CSS custom properties (`var(--idl-logo-bg)`, `var(--idl-logo-fg)`) --- +## Phase 0.9 — Documentation Status Indicators + +Make it clear to readers which documentation is complete vs. in-progress while the site is under active development. + +**Goal**: Set proper expectations for visitors during the construction phase and make the site feel professional rather than incomplete. + +- [x] **0.9.1** Create a `PageStatus` component (or use Docusaurus admonitions) to indicate completion status at the top of pages. Status values: "complete", "in-progress", "planned". Start with admonitions for MVP: + ```markdown + :::info[Status: Complete] + This documentation is complete and reviewed. + ::: + + :::warning[Status: In Progress] + This documentation is partially complete. Some sections may be missing or outdated. + ::: + + :::caution[Status: Planned] + This documentation is planned but not yet written. Check back soon. + ::: + ``` + Can be upgraded to a custom React component later for more polish. + +- [ ] **0.9.2** Add status indicators to the sidebar using custom CSS or sidebar item customization. Consider emoji (✅/🚧/📋) or colored dots for quick scanning. This makes status visible during navigation without requiring users to open each page. + +- [x] **0.9.3** Create a "Documentation Status" page at `docs/intro/doc-status.md` that lists all planned documentation sections with their current status, so readers can see at a glance what exists and what's coming. Structure it by the main categories from the site design (Getting Started, Concepts, Database, IDL, Tools, Generators). Use a table format: + | Section | Status | + |---------|--------| + | Getting Started for Users | 🚧 In Progress | + | Getting Started for Spec Writers | 📋 Planned | + | ... | ... | + +- [x] **0.9.4** Add a frontmatter field `status: complete|in-progress|planned` to all documentation pages. This can be consumed by the PageStatus component (if built) or by a build script that validates status consistency. Added to key pages as they are created. + +- [x] **0.9.5** (Optional) Add a global banner at the top of the site (using Docusaurus announcement bar) that says "🚧 This documentation site is under active construction. See [Documentation Status](/intro/doc-status) for details." Remove this once the site reaches stable status. Configure in `docusaurus.config.ts`: + ```typescript + announcementBar: { + id: 'under_construction', + content: '🚧 This documentation site is under active construction. See Documentation Status for details.', + backgroundColor: '#ffa500', + textColor: '#000000', + isCloseable: true, + } + ``` + +**Acceptance**: Readers can immediately see which pages are trustworthy vs. incomplete. Status is visible both at the page level and in navigation. The Documentation Status page provides a roadmap of what's coming. + +--- + ## Phase 1 — Landing Page Build the custom landing page (`src/pages/index.tsx`). @@ -275,12 +323,12 @@ Build the custom landing page (`src/pages/index.tsx`). ### 4.1 — Configurations (`docs/concepts/configurations/`) -- [ ] **4.1.1** Write `overview.md`: what configurations are, the three types, why they exist. +- [x] **4.1.1** Write `overview.md`: what configurations are, the three types, why they exist. *(Exists at `doc/docs/concepts/configurations/overview.md`; cross-linked to schema reference.)* - [ ] **4.1.2** Write `full-configs.md`: format, required fields, example (`cfgs/mc100-32-full-example.yaml`). - [ ] **4.1.3** Write `partial-configs.md`: format, `mandatory_extensions`, example. - [ ] **4.1.4** Write `unconfig.md`: what `_` means and when to use it. - [ ] **4.1.5** Write `config-file-format.md`: complete reference for the config YAML format, including overlays (`cfgs/NAME/arch_overlay/`). Reference `cfgs/example_rv64_with_overlay.yaml`. -- [ ] **4.1.6** Write `validating-configs.md`: how to validate a config, compatibility checking against profiles. +- [ ] **4.1.6** Write `validating-configs.md`: how to validate a config, compatibility checking against profiles. Must cover two levels of validation: (1) **Schema validation** — structural correctness checked by `bin/validate`; (2) **Semantic validation** — data-dependency rules that the schema cannot express, including: extension versions must exist in the database, the required set of `params` depends on which extensions are implemented (and on other parameter values), extension `requirements` conditions must be satisfied, and version constraints in partial configs must be satisfiable. Explain that a file can be schema-valid but semantically invalid, and that `bin/validate` checks both. ### 4.2 — The data pipeline (`docs/concepts/data-pipeline/`) @@ -292,6 +340,7 @@ Build the custom landing page (`src/pages/index.tsx`). ### 4.3 — Conditions system (`docs/concepts/conditions.md`) +- [ ] **4.3.0** Extract condition types (`condition`, `yaml_condition`, `idl_condition`, `xlen_condition`, `extension_condition`, `param_condition`) from `schema_defs.json` into a dedicated `spec/schemas/condition_schema.json`. Update all `$ref` paths in other schemas. This enables the schema doc generator to produce a standalone conditions reference page that can be linked from the `requirements` field in `config_schema.json` and other schemas. - [ ] **4.3.1** Convert `doc/schema/conditions.adoc` → Markdown. - [ ] **4.3.2** Review and update for accuracy/completeness. @@ -332,12 +381,34 @@ For each table, create a page with: description, schema summary (auto-generated - [ ] **5.4.1** Write `overview.md`: what schemas are, where they live (`spec/schemas/`), how they are enforced. - [ ] **5.4.2** Convert `doc/schema/versioning.adoc` → `versioning.md`. -- [ ] **5.4.3** Set up auto-generation of per-schema documentation from the JSON Schema files in `spec/schemas/`. There are 26 files total (including `json-schema-draft-07.json` and `schema_defs.json` which are meta/shared — these may not need individual pages). Options: - - Use `jsonschema2md` or `@adobe/jsonschema2md` to generate Markdown from each schema. - - Or write a custom Ruby/Node script that reads each schema and emits a Markdown page. - - Integrate into the Docusaurus build so schema docs are always up to date. - - Note: `mmr_schema.json` (memory-mapped registers) and `prm_schema.json` (PRM structure) are present but have no corresponding ISA table — document them as standalone schema reference pages. -- [ ] **5.4.4** Add a schema index page listing all documented schemas with links. +- [x] **5.4.3** Set up auto-generation of per-schema documentation from the JSON Schema files in `spec/schemas/`. Implemented as a custom Ruby gem (`tools/internal-gems/schema_doc_gen/`) invoked via `bin/chore gen schema-docs`. Generates MDX pages under `doc/docs/schemas//`. See D7 in `decisions.md`. +- [x] **5.4.4** Add a schema index page listing all documented schemas with links. *(Auto-generated at `doc/docs/schemas/index.mdx`.)* + +**Schema content review status** (improving `description` fields and `examples` in each schema file): +- [x] `config_schema.json` — Fully reviewed and improved: top-level description with overview and semantic validation note, Quick Start examples, field descriptions for all properties, version format corrected (`MAJOR[.MINOR[.PATCH]]`), `additional_extensions` default documented, `requirements` description added, `arch_overlay` grammar fixed, `$source` hidden with tooling note, cross-link to concepts overview and validating-configs page. +- [~] `schema_defs.json` — Partially improved: `extension_name`, `requirement_string`, `version_requirements`, `extension_version` (corrected format), `condition` (placeholder description pending 4.3.0), `spec_state` (full description with all enum values) descriptions added. +- [ ] `exception_code_schema.json` +- [~] `ext_schema.json` — Generator improved: bare `enum` (without `type`) now renders as pipe-separated values instead of `any`; `type` + `enum` together also renders enum values. Schema content review in progress. +- [ ] `inst_schema.json` +- [ ] `inst_opcode_schema.json` +- [ ] `inst_subtype_schema.json` +- [ ] `inst_type_schema.json` +- [ ] `inst_var_schema.json` +- [ ] `inst_var_type_schema.json` +- [ ] `inst_variable_metadatas.json` +- [ ] `interrupt_code_schema.json` +- [ ] `manual_schema.json` +- [ ] `manual_version_schema.json` +- [ ] `mmr_schema.json` +- [ ] `non_isa_schema.json` +- [ ] `param_schema.json` +- [ ] `prm_schema.json` +- [ ] `proc_cert_class_schema.json` +- [ ] `proc_cert_model_schema.json` +- [ ] `profile_family_schema.json` +- [ ] `profile_release_schema.json` +- [ ] `profile_schema.json` +- [ ] `register_file_schema.json` --- @@ -367,7 +438,7 @@ All content sourced from `doc/idl.adoc` (41.6 KB — comprehensive). Convert to - [x] `common-misunderstandings.mdx` — Eight common mistakes with examples and fixes - [x] `for-spec-writers.mdx` — Patterns for writing new instructions and CSR definitions - [x] `quick-reference.mdx` — Dense syntax cheat sheet covering all language constructs -- [ ] **6.4** Write `docs/idl/idlc.md` — the `idlc` compiler: CLI, AST API, installation. +- [x] **6.4** Write `docs/idl/idlc.md` — the `idlc` compiler: compilation pipeline, AST, symbol table, value tracking/snapshotting, analysis passes, Ruby API, error handling. - [x] **6.5** IDL syntax highlighting in Docusaurus — see D5 in `decisions.md`. --- @@ -473,11 +544,13 @@ This phase sets up the tooling to keep docs in sync with source automatically. ### 10.1 — Schema documentation generation -- [ ] **10.1.1** Evaluate `@adobe/jsonschema2md` for generating Markdown from the 27 JSON Schema files. -- [ ] **10.1.2** If suitable, add it as a dev dependency and write a generation script. -- [ ] **10.1.3** If not suitable, write a custom script (Ruby or Node) that reads each schema and emits structured Markdown. -- [ ] **10.1.4** Add generation step to the pre-build pipeline. -- [ ] **10.1.5** Improve schema files with better `description` fields and `examples` where missing (this is a data quality task, not just a docs task). +- [x] **10.1.1** Evaluated `@adobe/jsonschema2md` — not suitable (poor MDX output, limited control over formatting). Chose custom Ruby implementation instead. +- [-] **10.1.2** N/A — `@adobe/jsonschema2md` not used. +- [x] **10.1.3** Wrote custom Ruby gem `tools/internal-gems/schema_doc_gen/` that reads each JSON Schema file and emits structured MDX. Invoked via `bin/chore gen schema-docs`. See D7 in `decisions.md` for design decisions. +- [x] **10.1.4** Generation step added: `bin/chore gen schema-docs` (run manually; not yet wired into the Docusaurus pre-build step — see note below). +- [~] **10.1.5** Improving schema files with better `description` fields and `examples`: `config_schema.json` fully done; `schema_defs.json` partially done (`extension_name`, `requirement_string`, `version_requirements`, `extension_version`, `condition` updated); remaining schemas not yet reviewed. See schema content review status in Phase 5.4. + + **Note**: Schema docs are currently regenerated manually via `bin/chore gen schema-docs` and committed. Wiring into the Docusaurus pre-build step requires the Docker container to be available during `npm run build`, which is not the case in the current CI setup (see D4). Options: (a) keep committing generated files, (b) add a CI step that runs `bin/chore gen schema-docs` before the Docusaurus build, (c) move generation to a Node.js script that runs without Docker. ### 10.2 — CLI documentation generation @@ -563,7 +636,7 @@ Components that need a `DOCS.md`: - [ ] **14.3** Verify mobile responsiveness. - [ ] **14.4** Verify dark mode. - [ ] **14.5** Add a "last updated" timestamp to pages (Docusaurus `showLastUpdateTime: true`). -- [ ] **14.6** Add a "edit this page" link to all pages (configured via `editUrl` in Phase 0). +- [ ] **14.6** Verify "Edit this page" links work on all hand-authored pages. Auto-generated pages (schema docs) suppress the edit link via `custom_edit_url: null` and show an inline provenance note instead — this is intentional. - [ ] **14.7** Write a redirect map for any URLs from the old Pages site that should continue to work. - [ ] **14.8** Announce the new site in the project README and update the README's documentation links. @@ -619,6 +692,17 @@ Resolved decisions are recorded in [`decisions.md`](decisions.md) with rationale - [ ] **Q8** What is the exact destination path for generators after the `backends/` migration? Currently only `ext-doc`, `isa-explorer`, and `manual` are accessible via `bin/generate`. Update Phase 8.2 generator pages with correct invocation once the migration is complete. - [ ] **Q9** What is the disposition of `doc/idl.html` (the AsciiDoc-rendered IDL reference, built by `asciidoctor` in CI and published to the Pages site)? Once Phase 6 (IDL docs in Docusaurus) is complete, this artifact and its CI build step can be removed. Confirm before removing. - [ ] **Q10** `doc/prose-schema.adoc` documents the structured prose encoding system. The `prose` table in `spec/std/isa/` is being removed. Confirm whether `prose-schema.adoc` should be converted, archived, or dropped. +- [ ] **Q11** Rename `arch_overlay` to `spec_overlay` globally in the repository (tools, configuration schema, and documentation). The current name is confusing; "spec overlay" more clearly indicates that this feature overlays the specification data, not the architecture itself. This is a breaking change for configuration files and requires coordination. + +--- + +## Known Issues / Future Work + +Items identified during PR reviews or implementation that should be addressed in future updates: + +- **IDL examples using misa checks**: Several IDL code examples (e.g., in `overview.mdx` and `standard-library.mdx`) use `CSR[misa].C` checks to demonstrate dynamic extension enabling/disabling. However, the handling of mutable vs. immutable `misa` is still being finalized in the specification. These examples should be reviewed and potentially replaced with examples that don't depend on misa mutability semantics once the spec is settled. (Identified in PR 1723 review, comments 56-57) + +- **ERB syntax in function descriptions**: Function descriptions in `.idl` files may be processed through ERB templates. If ERB delimiters (like `<%-`) appear in a description, they could be interpreted as ERB code. Consider documenting this as a known limitation or adding validation to warn about ERB syntax in descriptions. (Identified in PR 1723 review, comment 55) --- diff --git a/doc/planning/documentation-plan.md b/doc/planning/documentation-plan.md index 2bfeb1a995..ab086d8c53 100644 --- a/doc/planning/documentation-plan.md +++ b/doc/planning/documentation-plan.md @@ -198,6 +198,8 @@ Should include overview, usage details, installation details (if relevant), and Tools to document: +**Published Ruby Gems** (located in `tools/ruby-gems/`): + | Tool | Location | Description | |---|---|---| | `udb` gem | `tools/ruby-gems/udb/` | Main database interface library; CLI and Ruby API | @@ -205,6 +207,17 @@ Tools to document: | `idlc` gem | `tools/ruby-gems/idlc/` | IDL compiler; CLI and AST API | | `udb_helpers` gem | `tools/ruby-gems/udb_helpers/` | Template helpers used by generators | | `idl_highlighter` gem | `tools/ruby-gems/idl_highlighter/` | Syntax highlighting for IDL | + +**Internal Build Tools** (located in `tools/internal-gems/`): + +| Tool | Location | Description | +|---|---|---| +| `schema_doc_gen` gem | `tools/internal-gems/schema_doc_gen/` | Generates schema documentation (not published to RubyGems) | + +**Command-line Tools**: + +| Tool | Location | Description | +|---|---|---| | `bin/generate` | `bin/generate` | Language-agnostic wrapper exposing all generators (Ruby via `udb-gen`, Python tools, etc.) | | `bin/regress` | `bin/regress` | Regression test runner | | `bin/chore` | `bin/chore` | Repository maintenance tool | diff --git a/doc/src/components/AnchorOpenDetails/index.tsx b/doc/src/components/AnchorOpenDetails/index.tsx new file mode 100644 index 0000000000..a1e605628f --- /dev/null +++ b/doc/src/components/AnchorOpenDetails/index.tsx @@ -0,0 +1,79 @@ +// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +// SPDX-License-Identifier: BSD-3-Clause-Clear + +import { useEffect } from 'react'; +import BrowserOnly from '@docusaurus/BrowserOnly'; + +function getNavbarHeight(): number { + // --ifm-navbar-height is in rem (e.g. "3.75rem") — convert to px + const cssVar = getComputedStyle(document.documentElement) + .getPropertyValue('--ifm-navbar-height').trim(); + if (cssVar.endsWith('rem')) { + const rem = parseFloat(cssVar); + const rootFontSize = parseFloat(getComputedStyle(document.documentElement).fontSize); + return rem * rootFontSize; + } + if (cssVar.endsWith('px')) return parseFloat(cssVar); + // Fallback: measure the navbar element directly + const navbar = document.querySelector('.navbar--fixed-top') as HTMLElement | null; + return navbar ? navbar.offsetHeight : 0; +} + +function openDetailsForId(id: string): void { + const target = document.getElementById(id); + if (!target) return; + + // Walk up the DOM looking for Docusaurus's
component wrapper + // or native HTML
elements. + // Docusaurus renders
as a div with data-collapsed="true" when closed. + let el: HTMLElement | null = target.parentElement; + while (el) { + if (el.dataset.collapsed === 'true') { + const summary = el.querySelector(':scope > summary') as HTMLElement | null; + if (summary) summary.click(); + } + // Also handle native HTML
elements + if (el instanceof HTMLDetailsElement && !el.open) { + el.open = true; + } + el = el.parentElement; + } + + // Scroll after the Docusaurus expand animation completes. + // --ifm-transition-fast is 200ms; wait a little longer to be safe. + setTimeout(() => { + const navbarHeight = getNavbarHeight(); + const top = target.getBoundingClientRect().top + window.scrollY - navbarHeight - 8; + window.scrollTo({ top, behavior: 'smooth' }); + }, 250); +} + +function AnchorOpenDetailsInner(): null { + useEffect(() => { + // Handle hash present on initial page load + if (window.location.hash) { + openDetailsForId(window.location.hash.slice(1)); + } + + // Intercept anchor clicks directly — Docusaurus's router may not fire hashchange + // for same-page anchor navigation. preventDefault stops the browser's own + // instant scroll so our post-animation scroll takes over. + function onClick(e: MouseEvent): void { + const anchor = (e.target as HTMLElement).closest('a'); + if (!anchor) return; + const href = anchor.getAttribute('href'); + if (!href?.startsWith('#')) return; + e.preventDefault(); + openDetailsForId(href.slice(1)); + } + + document.addEventListener('click', onClick); + return () => document.removeEventListener('click', onClick); + }, []); + + return null; +} + +export default function AnchorOpenDetails(): JSX.Element { + return {() => }; +} diff --git a/doc/src/css/custom.css b/doc/src/css/custom.css index 23b8d2dc14..8938b943b9 100644 --- a/doc/src/css/custom.css +++ b/doc/src/css/custom.css @@ -90,3 +90,38 @@ --ifm-color-primary-lightest: #c1c9f0; --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); } + +/* YAML syntax highlighting improvements */ +.language-yaml .token.key.atrule { + color: #0451a5; /* Blue for keys in light mode */ +} + +[data-theme='dark'] .language-yaml .token.key.atrule { + color: #9cdcfe; /* Light blue for keys in dark mode */ +} + +.language-yaml .token.punctuation { + color: #808080; /* Gray for punctuation (colons, dashes) */ +} + +.language-yaml .token.string { + color: #a31515; /* Red for string values in light mode */ +} + +[data-theme='dark'] .language-yaml .token.string { + color: #ce9178; /* Light red/orange for strings in dark mode */ +} + +.language-yaml .token.number, +.language-yaml .token.boolean { + color: #098658; /* Green for numbers/booleans in light mode */ +} + +[data-theme='dark'] .language-yaml .token.number, +[data-theme='dark'] .language-yaml .token.boolean { + color: #b5cea8; /* Light green for numbers/booleans in dark mode */ +} + +.language-yaml .token.important { + color: #e90; /* Orange for important tokens */ +} diff --git a/doc/src/theme/Logo/index.tsx b/doc/src/theme/Logo/index.tsx index f49cb26446..5656ae1084 100644 --- a/doc/src/theme/Logo/index.tsx +++ b/doc/src/theme/Logo/index.tsx @@ -6,12 +6,16 @@ import Link from '@docusaurus/Link'; import useBaseUrl from '@docusaurus/useBaseUrl'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import {useThemeConfig} from '@docusaurus/theme-common'; -import ThemedImage from '@theme/ThemedImage'; // Import the SVG as a React component so CSS variables work import UdbLogoSvg from '@site/static/img/udb-navbar.svg'; -export default function Logo(props: {imageClassName?: string; titleClassName?: string}): React.JSX.Element { +type LogoProps = { + imageClassName?: string; + titleClassName?: string; +} & React.ComponentProps; + +export default function Logo({imageClassName, titleClassName, ...rest}: LogoProps): React.JSX.Element { const { siteConfig: {title}, } = useDocusaurusContext(); @@ -20,23 +24,19 @@ export default function Logo(props: {imageClassName?: string; titleClassName?: s } = useThemeConfig(); const logoLink = useBaseUrl(logo?.href || '/'); - const sources = { - light: useBaseUrl(logo?.src || ''), - dark: useBaseUrl(logo?.srcDark || logo?.src || ''), - }; return ( {/* Use the imported SVG component so CSS variables apply */} - {navbarTitle != null && {navbarTitle}} + {navbarTitle != null && {navbarTitle}} ); } diff --git a/doc/src/theme/prism-include-languages.js b/doc/src/theme/prism-include-languages.js index f2f9fdc187..aa1d7eeb56 100644 --- a/doc/src/theme/prism-include-languages.js +++ b/doc/src/theme/prism-include-languages.js @@ -9,8 +9,23 @@ export default function prismIncludeLanguages(PrismObject) { } = siteConfig; const {additionalLanguages} = prism; + // Set up global Prism BEFORE loading any components + globalThis.Prism = PrismObject; + if (typeof window !== 'undefined') { + window.Prism = PrismObject; + } + + // Now dynamically import and load YAML additionalLanguages.forEach((lang) => { - require(`prismjs/components/prism-${lang}`); + try { + const langModule = require(`prismjs/components/prism-${lang}`); + // If the module exports a function, call it with PrismObject + if (typeof langModule === 'function') { + langModule(PrismObject); + } + } catch (e) { + console.error(`Failed to load Prism language: ${lang}`, e); + } }); // Load IDL language definition (canonical source: doc/src/prism/idl.js) diff --git a/spec/schemas/config_schema.json b/spec/schemas/config_schema.json index abdc8dbac1..46c928b2e9 100644 --- a/spec/schemas/config_schema.json +++ b/spec/schemas/config_schema.json @@ -1,6 +1,8 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "$id": "v0.1", + "title": "Configuration Schema", + "description": "A configuration represents RISC-V architectural choices - ranging from complete design specifications to requirement sets to unconstrained baselines.\n\n> **See also:** Configurations Overview for a narrative introduction with examples and use cases.\n\nConfigurations come in three forms:\n\n- **Fully configured**: Concrete implementations with all extensions and parameters explicitly specified. These represent actual processor implementations where every architectural detail is known. Each extension must specify an exact version (e.g., `2.1.0` or `2.1`). Used for generating implementations, documentation, and test suites for specific hardware.\n\n- **Partially configured**: Profiles or configurable IP that define mandatory, optional, and prohibited extensions using version constraints (e.g., `>= 2.0`). These specify requirements that multiple implementations can satisfy. Can restrict whether additional extensions beyond those listed are allowed. Used for RISC-V compliance profiles, configurable IP offerings (a class of implementations a vendor may offer), and platform requirements.\n\n- **Unconfigured**: Special case representing the entire RISC-V specification without any implementation choices. Used to model the complete RISC-V architecture space before any configuration decisions are made.\n\nThe variant is selected by the `type` field. Fields common to all variants: `name`, `description`, `arch_overlay`. The `params` field is available on `fully configured` and `partially configured` variants.\n\n> **Note:** Schema validation checks structural correctness only. A schema-valid file can still be semantically invalid - for example, referencing an extension version that does not exist in the database, or omitting a parameter that is required by the implemented extensions.", "$defs": { "full_configuration": { "type": "object", @@ -17,15 +19,18 @@ "$schema": { "type": "string", "format": "uri-reference", - "const": "config_schema.json#" + "const": "config_schema.json#", + "description": "Schema reference - must be `config_schema.json#`" }, "kind": { "type": "string", - "const": "architecture configuration" + "const": "architecture configuration", + "description": "Document type identifier - must be `architecture configuration`" }, "type": { "type": "string", - "const": "fully configured" + "const": "fully configured", + "description": "Configuration specificity level - `fully configured` means all extensions and parameters are explicitly specified" }, "name": { "type": "string", @@ -33,19 +38,20 @@ }, "description": { "type": "string", - "description": "An asciidoc description of the configuration" + "description": "Human-readable description of this configuration (AsciiDoc format)" }, "arch_overlay": { "type": "string", - "description": "Optional arch overlay to apply. Can be either the name of a directory under arch_overlay/ or a (absolute or relative) path to an overlay directory" + "description": "Optional arch overlay to apply. Can be either the name of a directory under arch_overlay/ or an absolute or relative path to an overlay directory" }, "$source": { "type": "string", "format": "uri", - "description": "Path to original file, when this is a copy" + "description": "Source file path when this configuration was generated or copied from another file" }, "params": { - "type": "object" + "type": "object", + "description": "Architecture parameters that define implementation choices (e.g., `MXLEN: 64`, privilege modes, physical address width, etc.). Parameter names and valid values are defined by the parameter data files in `spec/std/isa/param/`." }, "implemented_extensions": { "description": "Extensions implemented by this architecture", @@ -62,7 +68,23 @@ "$ref": "schema_defs.json#/$defs/extension_version" } } - } + }, + "examples": [ + [ + { + "name": "I", + "version": "2.1.0" + }, + { + "name": "M", + "version": "2.0.0" + }, + { + "name": "Zicsr", + "version": "2.0.0" + } + ] + ] } }, "additionalProperties": false @@ -81,15 +103,18 @@ "$schema": { "type": "string", "format": "uri-reference", - "const": "config_schema.json#" + "const": "config_schema.json#", + "description": "Schema reference - must be `config_schema.json#`" }, "kind": { "type": "string", - "const": "architecture configuration" + "const": "architecture configuration", + "description": "Document type identifier - must be `architecture configuration`" }, "type": { "type": "string", - "const": "partially configured" + "const": "partially configured", + "description": "Configuration specificity level - `partially configured` means some extensions/parameters are specified as requirements while others are left open" }, "name": { "type": "string", @@ -97,19 +122,20 @@ }, "description": { "type": "string", - "description": "An asciidoc description of the configuration" + "description": "Human-readable description of this configuration (AsciiDoc format)" }, "params": { - "type": "object" + "type": "object", + "description": "Architecture parameters that constrain compliant implementations. The entire `params` key may be omitted if no parameter constraints are needed. Parameter names and valid values are defined by the parameter data files in `spec/std/isa/param/`." }, "arch_overlay": { "type": "string", - "description": "Optional arch overlay to apply. Can be either the name of a directory under arch_overlay/ or a (absolute or relative) path to an overlay directory" + "description": "Optional arch overlay to apply. Can be either the name of a directory under arch_overlay/ or an absolute or relative path to an overlay directory" }, "$source": { "type": "string", "format": "uri", - "description": "Path to original file, when this is a copy" + "description": "Source file path when this configuration was generated or copied from another file" }, "mandatory_extensions": { "description": "Extensions mandatory in this architecture", @@ -119,7 +145,7 @@ } }, "non_mandatory_extensions": { - "description": "Extensions that are not mandatory but are still _special_ in this architecture. This could mean different things depending on the context: for certificates or generated IP, this would correspond to _optional supported_, and extensions not in non_mandatory are not possible. For profiles, this corresponds to some type of _profile optional_, but extensions in non_mandatory are still possible.", + "description": "Optional extensions with special significance in this architecture. For configurable IP, these are optionally supported extensions. For profiles, these are profile-optional extensions.", "type": "array", "items": { "$ref": "schema_defs.json#/$defs/extension_requirement" @@ -138,10 +164,11 @@ "additional_extensions": { "type": "boolean", "default": true, - "description": "Whether or not a compliant instance of this partial config can have more extensions than those listed in mandatory_extensions/non_mandatory_extensions" + "description": "Whether a compliant instance may implement extensions beyond those listed in `mandatory_extensions`/`non_mandatory_extensions`. Defaults to `true` if omitted." }, "requirements": { - "$ref": "schema_defs.json#/$defs/condition" + "$ref": "schema_defs.json#/$defs/condition", + "description": "Additional condition that must be satisfied for this configuration to be valid (e.g., a parameter constraint or extension dependency)." } }, "additionalProperties": false @@ -153,15 +180,18 @@ "$schema": { "type": "string", "format": "uri-reference", - "const": "config_schema.json#" + "const": "config_schema.json#", + "description": "Schema reference - must be `config_schema.json#`" }, "kind": { "type": "string", - "const": "architecture configuration" + "const": "architecture configuration", + "description": "Document type identifier - must be `architecture configuration`" }, "type": { "type": "string", - "const": "unconfigured" + "const": "unconfigured", + "description": "Configuration specificity level - `unconfigured` represents the entire RISC-V specification with no implementation choices" }, "name": { "type": "string", @@ -169,16 +199,16 @@ }, "arch_overlay": { "type": "string", - "description": "Optional arch overlay to apply. Can be either the name of a directory under arch_overlay/ or a (absolute or relative) path to an overlay directory" + "description": "Optional arch overlay to apply. Can be either the name of a directory under arch_overlay/ or an absolute or relative path to an overlay directory" }, "$source": { "type": "string", "format": "uri", - "description": "Path to original file, when this is a copy" + "description": "Source file path when this configuration was generated or copied from another file" }, "description": { "type": "string", - "description": "An asciidoc description of the configuration" + "description": "Human-readable description of this configuration (AsciiDoc format)" } }, "additionalProperties": false @@ -194,5 +224,146 @@ { "$ref": "#/$defs/unconfiguration" } + ], + "examples": [ + { + "_title": "Minimal Fully Configured", + "_quick_start": true, + "$schema": "config_schema.json#", + "kind": "architecture configuration", + "type": "fully configured", + "name": "MyProcessor", + "description": "A minimal 64-bit RISC-V processor", + "params": { + "MXLEN": 64 + }, + "implemented_extensions": [ + { "name": "I", "version": "2.1" }, + { "name": "Sm", "version": "1.12" } + ] + }, + { + "_title": "Minimal Partially Configured", + "_quick_start": true, + "$schema": "config_schema.json#", + "kind": "architecture configuration", + "type": "partially configured", + "name": "MyProfile", + "description": "A minimal profile requiring base integer instructions", + "mandatory_extensions": [{ "name": "I", "version": ">= 2.1" }] + }, + { + "_title": "Minimal Unconfigured", + "_quick_start": true, + "$schema": "config_schema.json#", + "kind": "architecture configuration", + "type": "unconfigured", + "name": "generic", + "description": "The complete RISC-V specification with no implementation choices" + }, + { + "_title": "Full Configuration Example (RV64)", + "$schema": "config_schema.json#", + "kind": "architecture configuration", + "type": "fully configured", + "name": "RV64GC", + "description": "64-bit RISC-V with General-purpose and Compressed extensions", + "params": { + "XLEN": 64, + "MXLEN": 64, + "SXLEN": 64, + "UXLEN": 64 + }, + "implemented_extensions": [ + { + "name": "I", + "version": "2.1" + }, + { + "name": "M", + "version": "2.0" + }, + { + "name": "A", + "version": "2.1" + }, + { + "name": "F", + "version": "2.2" + }, + { + "name": "D", + "version": "2.2" + }, + { + "name": "C", + "version": "2.0" + }, + { + "name": "Zicsr", + "version": "2.0" + }, + { + "name": "Zifencei", + "version": "2.0" + } + ] + }, + { + "_title": "Partial Configuration Example (Profile)", + "$schema": "config_schema.json#", + "kind": "architecture configuration", + "type": "partially configured", + "name": "RVA22U64", + "description": "RISC-V Application Profile for 64-bit Unix-like systems", + "mandatory_extensions": [ + { + "name": "I", + "version": ">= 2.1" + }, + { + "name": "M", + "version": ">= 2.0" + }, + { + "name": "A", + "version": ">= 2.1" + }, + { + "name": "F", + "version": ">= 2.2" + }, + { + "name": "D", + "version": ">= 2.2" + }, + { + "name": "C", + "version": ">= 2.0" + }, + { + "name": "Zicsr", + "version": ">= 2.0" + } + ], + "non_mandatory_extensions": [ + { + "name": "V", + "version": ">= 1.0" + } + ], + "params": { + "XLEN": 64 + }, + "additional_extensions": false + }, + { + "_title": "Unconfigured Example", + "$schema": "config_schema.json#", + "kind": "architecture configuration", + "type": "unconfigured", + "name": "generic", + "description": "Generic unconfigured RISC-V architecture" + } ] } diff --git a/spec/schemas/ext_schema.json b/spec/schemas/ext_schema.json index d2f270e508..aa821093bd 100644 --- a/spec/schemas/ext_schema.json +++ b/spec/schemas/ext_schema.json @@ -1,6 +1,7 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "$id": "v0.1", + "description": "An ISA extension defines a named set of instructions, CSRs, and behaviors that can be implemented by a RISC-V processor. Each extension has one or more versioned releases, with various ratification states (development, frozen, public-review, ratification-ready, ratified, or nonstandard-released).\n\n## Key Fields\n\n- `name`: Short identifier used throughout the database (e.g., `I`, `M`, `Zicsr`, `Smstateen`)\n- `long_name`: Human-readable one-line description\n- `description`: Full AsciiDoc documentation of the extension\n- `type`: Whether the extension is `unprivileged` or `privileged`\n- `versions`: Array of versioned releases, each with a `state` and optional `ratification_date`\n- `requirements`: Optional condition that must be true for the extension to be implementable (e.g., requires another extension)\n- `company`: Organization that developed the extension (defaults to RISC-V International for standard extensions)\n- `doc_license`: License for the extension documentation", "type": "object", "required": [ "$schema", @@ -11,50 +12,105 @@ "long_name", "versions" ], + "examples": [ + { + "_title": "Minimal Extension (Zicsr)", + "_quick_start": true, + "$schema": "ext_schema.json#", + "kind": "extension", + "name": "Zicsr", + "long_name": "Control and status register instructions", + "description": "Control and status register instructions", + "type": "unprivileged", + "versions": [ + { + "version": "2.0.0", + "state": "ratified", + "ratification_date": "2019-04" + } + ] + }, + { + "_title": "Extension with Requirements (B)", + "$schema": "ext_schema.json#", + "kind": "extension", + "name": "B", + "long_name": "Bit Manipulation", + "description": "The B standard extension comprises instructions provided by the Zba, Zbb, and Zbs extensions.", + "type": "unprivileged", + "company": { + "name": "RISC-V International", + "url": "https://riscv.org" + }, + "doc_license": { + "name": "Creative Commons Attribution 4.0 International License", + "url": "https://creativecommons.org/licenses/by/4.0/" + }, + "versions": [ + { + "version": "1.0.0", + "state": "ratified", + "ratification_date": "2024-04", + "url": "https://drive.google.com/file/d/1SgLoasaBjs5WboQMaU3wpHkjUwV71UZn/view", + "requirements": { + "extension": { + "allOf": [ + { "name": "Zba", "version": "= 1.0.0" }, + { "name": "Zbb", "version": "= 1.0.0" }, + { "name": "Zbs", "version": "= 1.0.0" } + ] + } + } + } + ] + } + ], "properties": { "$schema": { "type": "string", "format": "uri-reference", - "description": "Path to schema, relative to /schemas", + "description": "Schema reference - must be `ext_schema.json#`", "const": "ext_schema.json#" }, "kind": { "type": "string", "const": "extension", - "description": "Object type" + "description": "Document type identifier - must be `extension`" }, "name": { "$ref": "schema_defs.json#/$defs/extension_name" }, "long_name": { "type": "string", - "description": "One line description for the extension" + "description": "One-line human-readable name for the extension (e.g., `Address generation`, `Bit Manipulation`)" }, "description": { "$ref": "schema_defs.json#/$defs/spec_text", - "description": "Full documentation of the extension" + "description": "Full AsciiDoc documentation of the extension. May include multiple paragraphs, code examples, and cross-references." }, "rvi_jira_issue": { "type": "string", - "description": "JIRA issue number for the RVI issue that tracks this extension" + "description": "JIRA issue number tracking this extension in the RISC-V International issue tracker" }, "company": { - "description": "The company that developed this extension", + "description": "Organization that developed this extension. Omit for RISC-V International standard extensions.", "$ref": "schema_defs.json#/$defs/company" }, "doc_license": { + "description": "License for the extension documentation", "$ref": "schema_defs.json#/$defs/license" }, "type": { "enum": ["unprivileged", "privileged"], - "description": "Either unprivileged or privileged" + "description": "Privilege level of the extension. `unprivileged` extensions add instructions or behaviors accessible in user mode; `privileged` extensions add supervisor- or machine-mode functionality." }, "requirements": { - "description": "Condition represeting requirements of this extension. If the condition is false, the extension cannot be implemented", + "description": "Condition that must be true for this extension to be implementable. If the condition is false, the extension cannot be implemented. Typically used to express that one extension requires another (e.g., `D` requires `F`).", "$ref": "schema_defs.json#/$defs/condition" }, "versions": { "type": "array", + "description": "Ordered list of versioned releases of this extension, from oldest to newest.", "items": { "type": "object", "required": ["version", "state"], @@ -100,31 +156,34 @@ ], "properties": { "version": { - "$ref": "schema_defs.json#/$defs/extension_version" + "$ref": "schema_defs.json#/$defs/extension_version", + "description": "Version number in `MAJOR.MINOR.PATCH` format (e.g., `1.0.0`, `2.1.0`)" }, "state": { "$ref": "schema_defs.json#/$defs/spec_state", - "description": "Current state of this version" + "description": "Ratification state of this version. See `spec_state` in schema_defs for all possible values and their meanings." }, "repositories": { - "description": "Repositories associated with this extension", + "description": "Source repositories where this version of the extension is developed", "type": "array", "items": { "type": "object", "properties": { "url": { "type": "string", - "format": "uri" + "format": "uri", + "description": "Repository URL" }, "branch": { "type": "string", - "description": "Branch/tag where the work is done" + "description": "Branch or tag containing the work for this version" } }, "additionalProperties": false } }, "ratification_date": { + "description": "Month when this version was ratified, in `YYYY-MM` format. Use `unknown` if the date is not recorded. Required when `state` is `ratified`.", "oneOf": [ { "type": "string", @@ -169,37 +228,37 @@ "items": { "type": "string" }, - "description": "Changes since last version" + "description": "List of changes introduced in this version relative to the previous version" }, "url": { "type": "string", "format": "uri", - "description": "Link to ratified document" + "description": "URL to the ratified specification document (e.g., a PDF on the RISC-V website)" }, "contributors": { - "description": "List of contributors to this version of the extension", + "description": "People who contributed to this version of the extension", "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", - "description": "Contributor name, in 'GIVEN_NAME SURNAME' format" + "description": "Contributor name in `GIVEN_NAME SURNAME` format" }, "company": { "type": "string", - "description": "Company the contributor worked for, or 'Individual'" + "description": "Company the contributor worked for at the time, or `Individual`" }, "email": { "type": "string", "format": "email", - "description": "E-mail address for the contributor" + "description": "Contributor email address" } } } }, "requirements": { - "description": "Condition represeting requirements of this extension version _in addition to any specified for the extension overall_. If the condition is false, the extension version cannot be implemented", + "description": "Additional condition that must be true for this specific version to be implementable, beyond any requirements on the extension overall. If the condition is false, this version cannot be implemented.", "$ref": "schema_defs.json#/$defs/condition" } }, @@ -208,7 +267,7 @@ }, "$source": { "type": "string", - "description": "Source file where this extension was defined" + "description": "Source file path when this extension was generated or copied from another file" }, "cert_normative_rules": { "$ref": "schema_defs.json#/$defs/cert_normative_rules" diff --git a/spec/schemas/schema_defs.json b/spec/schemas/schema_defs.json index af172ce4b7..7fc94f8b2e 100644 --- a/spec/schemas/schema_defs.json +++ b/spec/schemas/schema_defs.json @@ -115,6 +115,7 @@ }, "spec_state": { "type": "string", + "description": "Ratification state of a specification or extension version: `development` (actively being worked on), `frozen` (feature-complete, under review), `public-review` (open for public comment), `ratification-ready` (approved by the task group, awaiting board vote), `ratified` (officially approved by RISC-V International), or `nonstandard-released` (released but not part of the RISC-V standard).", "enum": [ "development", "frozen", @@ -223,17 +224,20 @@ }, "extension_name": { "type": "string", + "description": "Extension name (e.g., `I`, `M`, `Zicsr`, `Smstateen`)", "pattern": "^(([A-WY])|([SXZ][a-z0-9]+))$" }, "extension_version": { - "$ref": "#/$defs/rvi_version" + "$ref": "#/$defs/rvi_version", + "description": "Exact version in `MAJOR[.MINOR[.PATCH]]` format (e.g., `2.1.0`, `2.1`, `2`)" }, "requirement_string": { "type": "string", + "description": "Version requirement string (e.g., `>= 2.0`, `~> 1.5`, `= 2.1`)", "pattern": "^((>=)|(>)|(~>)|(<)|(<=)|(=))?\\s*[0-9]+(\\.[0-9]+(\\.[0-9]+(-[a-fA-F0-9]+)?)?)?$" }, "version_requirements": { - "description": "A (set of) version requirements", + "description": "Version requirement or list of requirements (e.g., `>= 2.0` or `['>= 2.0', '< 3.0']`)", "oneOf": [ { "$ref": "#/$defs/requirement_string" @@ -434,7 +438,7 @@ "reference": { "type": "string", "pattern": "^.+\\.yaml#(/.*)?$", - "description": "refrence to another database object, as a JSON Reference" + "description": "reference to another database object, as a JSON Reference" }, "integer": { "description": "An integer, either native to JSON or a number-like string", @@ -808,6 +812,7 @@ "additionalProperties": false }, "condition": { + "description": "A condition (YAML structure or IDL function). See the conditions reference for details.", "oneOf": [ { "$ref": "#/$defs/yaml_condition" diff --git a/tools/internal-gems/README.md b/tools/internal-gems/README.md new file mode 100644 index 0000000000..5ed39bc76b --- /dev/null +++ b/tools/internal-gems/README.md @@ -0,0 +1,40 @@ +# Internal Gems + +This directory contains Ruby gems used internally for UDB development, build processes, and tooling. These gems are **not** published to RubyGems.org and are **not** intended for external use. + +## Directory Purpose + +- **External/published gems**: Located in `tools/ruby-gems/` + - `udb` - Core UDB library + - `idlc` - IDL compiler + - `udb-gen` - UDB generator framework + - `idl_highlighter` - Syntax highlighting for IDL + - `udb_helpers` - Helper utilities + +- **Internal/build gems**: Located in `tools/internal-gems/` (this directory) + - `schema_doc_gen` - Generates documentation from JSON schemas + - (Future internal tooling gems) + +## When to Add a Gem Here + +Place a gem in `tools/internal-gems/` if it is: +- Used only during the build/CI process +- Generates documentation or build artifacts +- Not intended to be used by external consumers +- Specific to UDB's development workflow + +## Usage + +Internal gems are included in the top-level `Gemfile`: + +```ruby +# internal gems (build/tooling only) +gemspec path: "tools/internal-gems/schema_doc_gen" +``` + +Run `bundle install` from the repository root to install all dependencies. + +## See Also + +- `tools/ruby-gems/` - Published/external gems +- `tools/scripts/` - Simple standalone scripts for chores diff --git a/tools/internal-gems/schema_doc_gen/bin/schema-doc-gen b/tools/internal-gems/schema_doc_gen/bin/schema-doc-gen new file mode 100755 index 0000000000..996dfa1bab --- /dev/null +++ b/tools/internal-gems/schema_doc_gen/bin/schema-doc-gen @@ -0,0 +1,93 @@ +#!/usr/bin/env ruby +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause-Clear + +# frozen_string_literal: true + +require "schema_doc_gen" +require "tty-option" +require "tty-exit" +require "fileutils" + +class SchemaDocCLI + include TTY::Option + include TTY::Exit + + usage do + program "schema-doc-gen" + desc "Generate Markdown documentation from JSON Schema files" + example <<~EXAMPLE + Generate documentation for config_schema.json: + $ #{File.basename($PROGRAM_NAME)} spec/schemas/config_schema.json + + Specify custom output location: + $ #{File.basename($PROGRAM_NAME)} spec/schemas/config_schema.json -o doc/docs/reference/config-schema.md + + Specify custom ref base path: + $ #{File.basename($PROGRAM_NAME)} config_schema.json --ref-base /path/to/schemas + EXAMPLE + end + + argument :schema_file do + required + desc "Path to the JSON Schema file" + validate ->(path) { File.exist?(path) } + end + + option :output do + short "-o" + long "--output=FILE" + desc "Output file path (overrides --output-dir; use for one-off generation)" + end + + option :ref_base do + long "--ref-base=DIR" + desc "Base directory for resolving $ref references (default: spec/schemas)" + default "spec/schemas" + convert :path + end + + option :output_dir do + long "--output-dir=DIR" + desc "Base output directory (default: doc/docs/schemas). Ignored if --output is specified. Generates to //.mdx" + default "doc/docs/schemas" + convert :path + end + + def run + parse + + schema_path = params[:schema_file] + ref_base = params[:ref_base] + output_base = params[:output_dir] + + begin + generator = SchemaDocGen::Generator.new(schema_path, ref_base: ref_base) + markdown = generator.generate + + # Determine output path + # --output takes precedence over --output-dir + output_path = if params[:output] + params[:output] + else + # Extract version from schema and generate path + version = generator.schema_version || "unknown" + schema_name = File.basename(schema_path, ".json") + File.join(output_base, version, "#{schema_name}.mdx") + end + + # Ensure output directory exists + FileUtils.mkdir_p(File.dirname(output_path)) + + File.write(output_path, markdown) + puts "Generated documentation: #{output_path}" + rescue => e + $stderr.puts "Error generating documentation: #{e.message}" + $stderr.puts e.backtrace if ENV["DEBUG"] + exit_with(:software_error) + end + end +end + +cli = SchemaDocCLI.new +cli.run diff --git a/tools/internal-gems/schema_doc_gen/bin/schema-docs-all b/tools/internal-gems/schema_doc_gen/bin/schema-docs-all new file mode 100755 index 0000000000..c0118b3d46 --- /dev/null +++ b/tools/internal-gems/schema_doc_gen/bin/schema-docs-all @@ -0,0 +1,125 @@ +#!/usr/bin/env ruby +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause-Clear + +# frozen_string_literal: true + +require "schema_doc_gen" +require "tty-option" +require "tty-exit" +require "fileutils" +require "pathname" +require "set" + +class SchemaDocsAllCLI + include TTY::Option + include TTY::Exit + + usage do + program "schema-docs-all" + desc "Generate Markdown documentation for all JSON Schema files in a directory" + example <<~EXAMPLE + Generate docs for all schemas in spec/schemas: + $ #{File.basename($PROGRAM_NAME)} + + Specify custom schema directory and output: + $ #{File.basename($PROGRAM_NAME)} --schema-dir /path/to/schemas --output-dir doc/docs/reference + EXAMPLE + end + + option :schema_dir do + long "--schema-dir=DIR" + desc "Directory containing JSON Schema files (default: spec/schemas)" + default "spec/schemas" + convert :path + end + + option :output_dir do + long "--output-dir=DIR" + desc "Base output directory (default: doc/docs/schemas)" + default "doc/docs/schemas" + convert :path + end + + flag :generate_index do + long "--generate-index" + desc "Generate an index.mdx page listing all schemas and versions" + end + + def run + parse + + schema_dir = params[:schema_dir] + output_dir = params[:output_dir] + should_generate_index = params.fetch(:generate_index, true) + + unless Dir.exist?(schema_dir) + $stderr.puts "Error: Schema directory not found: #{schema_dir}" + exit_with(:usage_error) + end + + begin + # Find all JSON schema files + schema_files = Pathname.new(schema_dir).glob("*.json") + .reject { |f| f.basename.to_s.start_with?("json-schema-draft") } # Skip meta-schemas + + puts "Found #{schema_files.length} schema files in #{schema_dir}" + + # Track versions encountered for category file generation + versions_found = Set.new + + # Generate documentation for each schema + schema_files.each do |schema_file| + generator = SchemaDocGen::Generator.new(schema_file, ref_base: schema_dir) + markdown = generator.generate + + version = generator.schema_version || "unknown" + versions_found.add(version) + schema_name = schema_file.basename(".json") + output_path = File.join(output_dir, version, "#{schema_name}.mdx") + + FileUtils.mkdir_p(File.dirname(output_path)) + File.write(output_path, markdown) + + puts " Generated: #{output_path}" + end + + # Generate category files for each version directory + versions_sorted = versions_found.sort.reverse # highest version first + versions_sorted.each_with_index do |version, idx| + version_dir = File.join(output_dir, version) + category_path = File.join(version_dir, "_category_.json") + + category_content = { + "label" => version, + "position" => idx + 1, + "collapsible" => true, + "collapsed" => false + } + + File.write(category_path, JSON.pretty_generate(category_content) + "\n") + puts " Generated category: #{category_path}" + end + + # Generate index page + if should_generate_index + index_generator = SchemaDocGen::IndexGenerator.new(output_dir) + index_content = index_generator.generate + + index_path = File.join(output_dir, "index.mdx") + File.write(index_path, index_content) + + puts " Generated index: #{index_path}" + end + + puts "\nSchema documentation generation complete!" + rescue => e + $stderr.puts "Error generating documentation: #{e.message}" + $stderr.puts e.backtrace if ENV["DEBUG"] + exit_with(:software_error) + end + end +end + +cli = SchemaDocsAllCLI.new +cli.run diff --git a/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen.rb b/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen.rb new file mode 100644 index 0000000000..07678b1d02 --- /dev/null +++ b/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen.rb @@ -0,0 +1,904 @@ +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause-Clear + +# frozen_string_literal: true + +require "json" +require "yaml" +require_relative "schema_doc_gen/version" +require_relative "schema_doc_gen/index_generator" + +module SchemaDocGen + # Generates MDX documentation from a JSON Schema file for Docusaurus + class Generator + attr_reader :schema, :schema_path, :ref_base + + def initialize(schema_path, ref_base: "spec/schemas") + @schema_path = schema_path + @ref_base = ref_base + @schema = JSON.parse(File.read(schema_path)) + @schema_defs_cache = nil # Lazy-loaded cache for schema_defs.json + end + + # Get the schema version from $id + def schema_version + @schema_version ||= @schema["$id"] + end + + # Load schema_defs.json definitions (cached) + def schema_defs + return @schema_defs_cache if @schema_defs_cache + + schema_defs_path = File.join(@ref_base, "schema_defs.json") + if File.exist?(schema_defs_path) + schema_defs_content = JSON.parse(File.read(schema_defs_path)) + @schema_defs_cache = schema_defs_content["$defs"] || {} + else + @schema_defs_cache = {} + end + + @schema_defs_cache + end + + # Generate MDX documentation for this schema + # @return [String] MDX content + def generate + frontmatter = generate_frontmatter + body_parts = [] + + # Title and description (Overview) + body_parts << generate_header + + # Quick Start examples (tagged with _quick_start: true) + body_parts << generate_quick_start_section if @schema["examples"] + + # Composition schemas (oneOf/anyOf/allOf) + if @schema["oneOf"] || @schema["anyOf"] || @schema["allOf"] + composition_key = @schema["oneOf"] ? "oneOf" : (@schema["anyOf"] ? "anyOf" : "allOf") + variants = @schema[composition_key] + + if all_internal_object_refs?(variants) + # All variants are internal $defs references to object types — render inline as named sections + body_parts << generate_variants_section(composition_key, variants) + # Any $defs that are NOT referenced by the composition (e.g., shared types) still get a Definitions section + referenced_def_names = variants.map { |v| v["$ref"].split("/").last } + remaining_defs = (@schema["$defs"] || {}).reject { |name, _| referenced_def_names.include?(name) } + body_parts << generate_defs_section(remaining_defs) unless remaining_defs.empty? + else + # Mixed or external refs — fall back to the original Schema Structure + Definitions rendering + body_parts << generate_composition_section + body_parts << generate_defs_section(@schema["$defs"]) if @schema["$defs"] + end + elsif @schema["$defs"] + # No composition, but has $defs — render them + body_parts << generate_defs_section(@schema["$defs"]) + end + + # Top-level properties (for simple object schemas with no composition) + if @schema["type"] == "object" && @schema["properties"] && !@schema["oneOf"] && !@schema["anyOf"] && !@schema["allOf"] + body_parts << generate_properties_section(@schema) + end + + # Full examples (non-quick-start) + body_parts << generate_examples_section if @schema["examples"] + + # Schema metadata + body_parts << generate_metadata if @schema["$id"] || @schema["$schema"] + + body = body_parts.compact.join("\n\n") + + # If the page has any
blocks, inject the AnchorOpenDetails component + # so that anchor links to collapsed blocks open them automatically + if body.include?("", body].join("\n\n") + else + [frontmatter, body].join("\n\n") + end + end + + private + + # Escape HTML angle brackets while preserving markdown syntax + def escape_html_in_markdown(text) + # Preserve markdown blockquotes (> at line start) and comparison operators (>=, <=) + # Also preserve content inside backticks + result = "" + in_backtick = false + + text.split("\n").each_with_index do |line, idx| + result += "\n" if idx > 0 + + if line.strip.start_with?(">") + # This is a markdown blockquote, don't escape + result += line + else + # Process character by character to handle backticks + line_result = "" + i = 0 + while i < line.length + char = line[i] + + if char == '`' + in_backtick = !in_backtick + line_result += char + elsif in_backtick + # Inside backticks, don't escape + line_result += char + elsif char == '>' && i + 1 < line.length && line[i + 1] == '=' + # >= operator + line_result += ">=" + i += 1 # Skip the = + elsif char == '<' && i + 1 < line.length && line[i + 1] == '=' + # <= operator + line_result += "<=" + i += 1 # Skip the = + elsif char == '<' + line_result += "<" + elsif char == '>' + line_result += ">" + else + line_result += char + end + + i += 1 + end + result += line_result + end + end + + result + end + + def generate_frontmatter + title = @schema["title"] || File.basename(@schema_path, ".json").split("_").map(&:capitalize).join(" ") + + <<~FRONTMATTER + --- + title: #{title}#{schema_version ? " (#{schema_version})" : ""} + sidebar_label: #{title} + custom_edit_url: null + # This file is auto-generated from #{File.basename(@schema_path)} + # Do not edit manually - run `bin/chore gen schema-docs` to regenerate + --- + FRONTMATTER + end + + def generate_header + title = @schema["title"] || File.basename(@schema_path, ".json").split("_").map(&:capitalize).join(" ") + description = @schema["description"] || "" + + md = "# #{title}\n" + if schema_version + schema_filename = File.basename(@schema_path) + github_schema_url = "https://github.com/riscv/riscv-unified-db/blob/main/spec/schemas/#{schema_filename}" + github_gen_url = "https://github.com/riscv/riscv-unified-db/blob/main/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen.rb" + md += "\n#{schema_version}\n" + md += "\n
\n" + md += "\n:::note Auto-generated\n" + md += "This page is generated from [`#{schema_filename}`](#{github_schema_url}) by the [schema doc generator](#{github_gen_url}). " + md += "To update this page, edit the schema file and run `bin/chore gen schema-docs`.\n" + md += ":::\n" + end + unless description.empty? + escaped_desc = escape_html_in_markdown(description) + md += "\n#{escaped_desc}\n" + end + md + end + + def generate_metadata + md = "## Schema Information\n\n" + md += "| Property | Value |\n" + md += "|----------|-------|\n" + md += "| Version | `#{@schema['$id']}` |\n" if @schema["$id"] + if @schema["$schema"] + # Link to the metaschema documentation + schema_url = @schema["$schema"] + # Extract draft version and create user-friendly link to json-schema.org + if schema_url =~ %r{/draft/(\d{4}-\d{2})/} + # Year-based version (e.g., 2020-12, 2019-09) + version = $1 + friendly_url = "https://json-schema.org/draft/#{version}" + md += "| JSON Schema Version | [Draft #{version}](#{friendly_url}) |\n" + elsif schema_url =~ /draft-(\d+)/ + # Numbered draft version (e.g., draft-07, draft-04) + draft_num = $1 + friendly_url = "https://json-schema.org/draft-#{draft_num}" + md += "| JSON Schema Version | [Draft #{draft_num}](#{friendly_url}) |\n" + else + # Fallback to original URL if pattern doesn't match + md += "| JSON Schema Version | [`#{schema_url}`](#{schema_url}) |\n" + end + end + md + end + + # Returns true if all variants in a oneOf/anyOf are internal $defs references to object types + def all_internal_object_refs?(variants) + return false if variants.nil? || variants.empty? + variants.all? do |v| + next false unless v.is_a?(Hash) && v["$ref"]&.start_with?("#/$defs/") + def_name = v["$ref"].split("/").last + def_schema = @schema.dig("$defs", def_name) + def_schema && def_schema["type"] == "object" + end + end + + # Human-readable label for a $def variant. + # Prefers the value of the `type` const property (e.g., "fully configured"), + # falling back to the def name with underscores replaced by spaces. + def variant_label(def_name, def_schema) + type_prop = def_schema.dig("properties", "type") + if type_prop.is_a?(Hash) && type_prop["const"] + type_prop["const"].to_s + else + def_name.gsub("_", " ") + end + end + + # Render all composition variants as inline named sections (### headings + property tables). + # Used when all variants are internal $defs references to object types. + def generate_variants_section(composition_key, variants) + label = case composition_key + when "oneOf" then "one of" + when "anyOf" then "any of" + when "allOf" then "all of" + else composition_key + end + + md = "## Variants\n\n" + md += "This schema accepts **#{label}** the following variants, distinguished by the `type` field:\n\n" + + # TOC list — plain links, no backticks (these are type names, not code identifiers) + variants.each do |variant| + def_name = variant["$ref"].split("/").last + def_schema = @schema.dig("$defs", def_name) + label_str = variant_label(def_name, def_schema) + anchor = label_str.downcase.gsub(/[^a-z0-9]+/, "-").gsub(/^-|-$/, "") + md += "- [#{label_str}](##{anchor})\n" + end + md += "\n" + + # Each variant as a subsection + variants.each do |variant| + def_name = variant["$ref"].split("/").last + def_schema = @schema.dig("$defs", def_name) + next unless def_schema + + label_str = variant_label(def_name, def_schema) + md += "### `#{label_str}`\n\n" + + if def_schema["description"] + escaped_desc = escape_html_in_markdown(def_schema["description"]) + md += "#{escaped_desc}\n\n" + end + + md += generate_properties_table(def_schema) + md += "\n" + end + + md + end + + def generate_composition_section + md = "## Schema Structure\n\n" + + if @schema["oneOf"] + md += "This schema accepts **one of** the following types:\n\n" + @schema["oneOf"].each do |variant| + md += format_composition_variant(variant) + end + elsif @schema["anyOf"] + md += "This schema accepts **any of** the following types:\n\n" + @schema["anyOf"].each do |variant| + md += format_composition_variant(variant) + end + elsif @schema["allOf"] + md += "This schema requires **all of** the following:\n\n" + @schema["allOf"].each do |variant| + md += format_composition_variant(variant) + end + end + + md + end + + def format_composition_variant(variant) + if variant["$ref"] && variant["$ref"].start_with?("#/$defs/") + # Internal reference to a definition + def_name = variant["$ref"].split("/").last + anchor = def_name.downcase.gsub("_", "-") + "- [`#{def_name}`](##{anchor})\n" + elsif variant["type"] + "- Type: `#{variant['type']}`\n" + else + "- (Complex type)\n" + end + end + + def generate_defs_section(defs) + return "" if defs.nil? || defs.empty? + + md = "## Definitions\n\n" + + defs.each do |def_name, def_schema| + anchor_id = def_name.downcase.gsub("_", "-") + # Use collapsible details for each definition, with anchor inside so + # clicking an anchor link to this block opens it automatically (via AnchorOpenDetails) + md += "
\n" + md += "#{def_name}" + if def_schema["description"] + first_line = def_schema['description'].split("\n").first + md += " — #{first_line.gsub("<", "<").gsub(">", ">")}" + end + md += "\n\n" + + if def_schema["description"] + escaped_desc = def_schema['description'].gsub("<", "<").gsub(">", ">") + md += "#{escaped_desc}\n\n" + end + + if def_schema["type"] == "object" + md += generate_properties_table(def_schema) + md += "\n" + elsif def_schema["enum"] + md += generate_enum_section(def_schema) + md += "\n" + elsif def_schema["type"] + md += "**Type:** `#{def_schema['type']}`\n\n" + end + + md += "
\n\n" + end + + md + end + + def generate_properties_section(schema) + return "" unless schema["properties"] + + md = "## Properties\n\n" + md += generate_properties_table(schema) + md + end + + def generate_properties_table(schema) + return "" unless schema["properties"] + + md = "| Property | Type | Required | Description |\n" + md += "|----------|------|----------|-------------|\n" + + required_fields = schema["required"] || [] + properties_with_examples = [] + properties_with_item_schemas = [] + has_source_field = false + + # Sort: required fields first, then optional, preserving original order within each group + sorted_props = schema["properties"].sort_by { |name, _| required_fields.include?(name) ? 0 : 1 } + + sorted_props.each do |prop_name, prop_schema| + # Skip non-schema properties + next unless prop_schema.is_a?(Hash) || prop_schema.is_a?(TrueClass) || prop_schema.is_a?(FalseClass) + + # Skip properties with type: null (they're placeholders to prevent usage) + next if prop_schema.is_a?(Hash) && prop_schema["type"] == "null" + + # Skip $source — it's a tooling field, documented in a note below the table + if prop_name == "$source" + has_source_field = true + next + end + + required_str = required_fields.include?(prop_name) ? "✓" : "" + description = prop_schema.is_a?(Hash) ? (prop_schema["description"] || "") : "" + + # Clean up description for table cell - take first sentence or line + description = description.to_s.split(/\n\n/).first.to_s.gsub("\n", " ").strip + # Escape angle brackets to prevent MDX from interpreting them as JSX tags + description = description.gsub("<", "<").gsub(">", ">") + + # Check if this is an array-of-objects — if so, use short type + collapsible schema block + item_obj = prop_schema.is_a?(Hash) ? resolve_array_item_object(prop_schema) : nil + if item_obj + item_props = item_obj[:properties] + item_required = item_obj[:required] + anchor_id = "#{prop_name.downcase.gsub('_', '-')}-schema" + type_str = "#{format_array_object_type(item_props, anchor_id)} [↓ schema](##{anchor_id})" + properties_with_item_schemas << {name: prop_name, properties: item_props, required: item_required, anchor_id: anchor_id} + else + type_str = format_type(prop_schema) + end + + # Mark properties that have examples - we'll add them after the table + if prop_schema.is_a?(Hash) && prop_schema["examples"] + description += " [↓ example](##{prop_name.downcase.gsub('_', '-')}-example)" unless description.empty? + properties_with_examples << {name: prop_name, examples: prop_schema["examples"]} + end + + md += "| `#{prop_name}` | #{type_str} | #{required_str} | #{description} |\n" + end + + # Add item schema blocks and examples after the table + unless properties_with_item_schemas.empty? && properties_with_examples.empty? + md += "\n" + properties_with_item_schemas.each do |prop| + md += format_item_schema_block(prop[:name], prop[:properties], prop[:required], prop[:anchor_id]) + end + properties_with_examples.each do |prop| + md += format_property_example(prop[:name], prop[:examples]) + end + end + + # Note about $source if present + if has_source_field + md += "\n:::note Tooling field\n`$source` is an optional field set automatically by UDB tooling to record the file path this object was loaded from. You do not need to set it manually.\n:::\n" + end + + md + end + + # Resolve the item schema of an array property to an object with properties, if possible. + # Returns {properties:, required:} or nil. + def resolve_array_item_object(prop_schema) + return nil unless prop_schema["type"] == "array" && prop_schema["items"].is_a?(Hash) + + items = prop_schema["items"] + + # Inline object + if items["type"] == "object" && items["properties"] + return {properties: items["properties"], required: items["required"] || []} + end + + # $ref to schema_defs object + if items["$ref"]&.include?("schema_defs.json#/$defs/") + def_name = items["$ref"].split("/").last + def_schema = schema_defs[def_name] + if def_schema && def_schema["type"] == "object" && def_schema["properties"] + return {properties: def_schema["properties"], required: def_schema["required"] || []} + end + end + + nil + end + + # Short type string for an array-of-objects cell. + # ≤3 keys: Array<{name, version}>; >3 keys: Array + INLINE_KEY_THRESHOLD = 3 + + def format_array_object_type(item_props, anchor_id) + if item_props.size <= INLINE_KEY_THRESHOLD + keys = item_props.keys.map { |k| "`#{k}`" }.join(", ") + "Array<\\{#{keys}\\}>" + else + "Array<object>" + end + end + + # Collapsible mini-table showing the item schema fields for an array-of-objects property + def format_item_schema_block(prop_name, item_props, item_required, anchor_id) + md = "
\n" + md += "#{prop_name} item schema\n\n" + + md += "| Property | Type | Required | Description |\n" + md += "|----------|------|----------|-------------|\n" + + item_props.each do |key, key_schema| + next if key_schema.is_a?(Hash) && key_schema["type"] == "null" + req = item_required.include?(key) ? "✓" : "" + + # For $ref properties, split type and description cleanly: + # - Type column: the underlying scalar type (string, integer, etc.) + # - Description column: the def's description (or the property's own description) + if key_schema.is_a?(Hash) && key_schema["$ref"] + ref = key_schema["$ref"] + if ref.start_with?("#/$defs/") + # Internal ref within schema_defs — resolve for description + def_name = ref.split("/").last + def_schema = schema_defs[def_name] + if def_schema + type_str = format_ref_type(def_name, def_schema) + desc = key_schema["description"] || format_ref_description(def_name, def_schema) + else + type_str = format_type(key_schema) + desc = key_schema["description"] || "" + end + elsif ref.include?("schema_defs.json#/$defs/") + # External ref to schema_defs + def_name = ref.split("/").last + def_schema = schema_defs[def_name] + if def_schema + type_str = format_ref_type(def_name, def_schema) + desc = key_schema["description"] || format_ref_description(def_name, def_schema) + else + type_str = format_type(key_schema) + desc = key_schema["description"] || "" + end + else + type_str = format_type(key_schema) + desc = key_schema["description"] || "" + end + else + type_str = format_type(key_schema) + desc = key_schema.is_a?(Hash) ? (key_schema["description"] || "") : "" + end + + desc = desc.to_s.split(/\n\n/).first.to_s.gsub("\n", " ").strip + desc = desc.gsub("<", "<").gsub(">", ">") + md += "| `#{key}` | #{type_str} | #{req} | #{desc} |\n" + end + + md += "\n
\n\n" + md + end + + # Format a property example as a collapsible details section after the table + def format_property_example(prop_name, examples) + example = examples.first # Use first example + anchor_id = "#{prop_name.downcase.gsub('_', '-')}-example" + + md = "
\n" + md += "#{prop_name} example\n\n" + md += "```yaml\n" + if example.is_a?(Hash) || example.is_a?(Array) + display_example = example.is_a?(Hash) ? example.reject { |k, _| k.start_with?("_") } : example + md += YAML.dump(display_example).sub(/^---\n/, '') + else + md += example.to_s + end + md += "\n```\n\n" + md += "
\n\n" + md + end + + def generate_enum_section(schema) + return "" unless schema["enum"] + + md = "**Allowed values:**\n\n" + schema["enum"].each do |value| + md += "- `#{value}`\n" + end + md + end + + def generate_quick_start_section + return "" unless @schema["examples"] + + quick_start = @schema["examples"].select { |e| e.is_a?(Hash) && e["_quick_start"] } + return "" if quick_start.empty? + + md = "## Quick Start\n\n" + quick_start.each do |example| + title = example["_title"] || "Example" + md += "**#{title}:**\n" + md += "```yaml\n" + display_example = example.reject { |k, _| k.start_with?("_") } + md += YAML.dump(display_example).sub(/^---\n/, '') + md += "\n```\n\n" + end + md + end + + def generate_examples_section + return "" unless @schema["examples"] + + # Only show non-quick-start examples + examples = @schema["examples"].reject { |e| e.is_a?(Hash) && e["_quick_start"] } + return "" if examples.empty? + + md = "## Examples\n\n" + examples.each_with_index do |example, idx| + md += "
\n" + + # Add a descriptive summary if the example has a title/description + title = if example.is_a?(Hash) && example["_title"] + example["_title"] + else + "Example #{idx + 1}" + end + md += "#{title}\n\n" + + md += "```yaml\n" + if example.is_a?(Hash) || example.is_a?(Array) + # Remove meta fields like _title before displaying + display_example = example.is_a?(Hash) ? example.reject { |k, _| k.start_with?("_") } : example + # Convert to YAML for better readability of config files + md += YAML.dump(display_example).sub(/^---\n/, '') # Remove YAML document separator + else + md += example.to_s + end + md += "\n```\n\n" + md += "
\n\n" + end + + md + end + + # Return the underlying scalar type string for a schema_defs definition, + # for use in the Type column of a property table. + # Follows $ref chains until a type, enum, or oneOf/anyOf is found. + def format_ref_type(def_name, def_schema) + return "`string`" unless def_schema.is_a?(Hash) + if def_schema["$ref"]&.start_with?("#/$defs/") + nested = schema_defs[def_schema["$ref"].split("/").last] + return format_ref_type(def_schema["$ref"].split("/").last, nested) if nested + end + if def_schema["type"] + if def_schema["type"] == "array" && def_schema["items"].is_a?(Hash) + items = def_schema["items"] + if items["$ref"]&.start_with?("#/$defs/") + item_def_name = items["$ref"].split("/").last + item_def = schema_defs[item_def_name] + item_type = item_def ? format_ref_type(item_def_name, item_def) : "`string`" + else + item_type = format_type(items) + end + "Array<#{item_type}>" + elsif def_schema["enum"] + def_schema["enum"].map { |v| "`#{v}`" }.join(" \\| ") + else + "`#{def_schema['type']}`" + end + elsif def_schema["enum"] + def_schema["enum"].map { |v| "`#{v}`" }.join(" \\| ") + elsif def_schema["oneOf"] || def_schema["anyOf"] + key = def_schema["oneOf"] ? "oneOf" : "anyOf" + def_schema[key].map { |s| + if s.is_a?(Hash) && s["$ref"]&.start_with?("#/$defs/") + rn = s["$ref"].split("/").last + rd = schema_defs[rn] + rd ? format_ref_type(rn, rd) : format_type(s) + elsif s.is_a?(Hash) && s["type"] == "array" && s["items"].is_a?(Hash) && s["items"]["$ref"]&.start_with?("#/$defs/") + item_def_name = s["items"]["$ref"].split("/").last + item_def = schema_defs[item_def_name] + item_type = item_def ? format_ref_type(item_def_name, item_def) : "`string`" + "Array<#{item_type}>" + else + format_type(s) + end + }.join(" \\| ") + else + "`any`" + end + end + + # Return the human-readable description for a schema_defs definition, + # for use in the Description column of a property table. + # Returns the first definition in the chain that has a description. + def format_ref_description(def_name, def_schema) + return "" unless def_schema.is_a?(Hash) + return def_schema["description"] if def_schema["description"] + if def_schema["$ref"]&.start_with?("#/$defs/") + nested_name = def_schema["$ref"].split("/").last + nested = schema_defs[nested_name] + return format_ref_description(nested_name, nested) if nested + end + "" + end + + # Format a sub-schema that may be a #/$defs/ ref within schema_defs. + # Used when expanding oneOf/anyOf inside format_inline_definition, where + # #/$defs/ refs point into schema_defs (not the current page's $defs). + def format_inline_or_type(sub_schema) + if sub_schema.is_a?(Hash) && sub_schema["$ref"]&.start_with?("#/$defs/") + def_name = sub_schema["$ref"].split("/").last + def_schema = schema_defs[def_name] + return format_inline_definition(def_name, def_schema) if def_schema + end + format_type(sub_schema) + end + + # Format an inlined definition from schema_defs + def format_inline_definition(def_name, def_schema) + # If the def has its own description, use it directly — don't follow $ref chains + return def_schema["description"] if def_schema["description"] + + # Handle nested $ref in def_schema (e.g., extension_version -> rvi_version) + if def_schema["$ref"] + ref = def_schema["$ref"] + if ref.start_with?("#/$defs/") + nested_def_name = ref.split("/").last + nested_def_schema = schema_defs[nested_def_name] + return format_inline_definition(nested_def_name, nested_def_schema) if nested_def_schema + end + end + + parts = [] + + # Add type if present + if def_schema["type"] + # If enum is present, show the allowed values regardless of type + if def_schema["enum"] + parts << def_schema["enum"].map { |v| "`#{v}`" }.join(" \\| ") + elsif def_schema["type"] == "string" + # If there's a description, use it as the human-readable type label + if def_schema["description"] + parts << def_schema["description"] + else + # For strings, show any constraints + constraints = [] + constraints << "pattern: `#{def_schema['pattern']}`" if def_schema["pattern"] + constraints << "format: `#{def_schema['format']}`" if def_schema["format"] + constraints << "min: #{def_schema['minLength']}" if def_schema["minLength"] + constraints << "max: #{def_schema['maxLength']}" if def_schema["maxLength"] + + if constraints.empty? + parts << "`string`" + else + parts << "`string` (#{constraints.join(", ")})" + end + end + elsif def_schema["type"] == "integer" || def_schema["type"] == "number" + # For numbers, show any constraints + constraints = [] + constraints << "min: #{def_schema['minimum']}" if def_schema["minimum"] + constraints << "max: #{def_schema['maximum']}" if def_schema["maximum"] + + if constraints.empty? + parts << "`#{def_schema['type']}`" + else + parts << "`#{def_schema['type']}` (#{constraints.join(", ")})" + end + elsif def_schema["type"] == "object" + # For open objects, use description if available + if def_schema["description"] + parts << def_schema["description"].split(/\n\n/).first.to_s.gsub("\n", " ").strip + else + parts << "`object`" + end + else + parts << "`#{def_schema['type']}`" + end + elsif def_schema["enum"] + # Show enum values + parts << def_schema["enum"].map { |v| "`#{v}`" }.join(" \\| ") + elsif def_schema["oneOf"] + # Use description if available, otherwise expand the oneOf + if def_schema["description"] + parts << def_schema["description"] + else + types = def_schema["oneOf"].map { |s| format_inline_or_type(s) }.join(" \\| ") + parts << types + end + elsif def_schema["anyOf"] + # Use description if available, otherwise expand the anyOf + if def_schema["description"] + parts << def_schema["description"] + else + types = def_schema["anyOf"].map { |s| format_inline_or_type(s) }.join(" \\| ") + parts << types + end + else + parts << "`any`" + end + + parts.join(" ") + end + + def format_type(schema) + # Handle boolean shorthand (true/false in JSON Schema) + return "`any`" if schema == true + return "`never`" if schema == false + + if schema["type"] + type = schema["type"] + + # Handle const - show type with the constant value + if schema["const"] + return "`#{type}` (const: `#{schema['const']}`)" + end + + # Handle enum - show allowed values + if schema["enum"] + return schema["enum"].map { |v| "`#{v}`" }.join(" \\| ") + end + + # Handle arrays + if type == "array" && schema["items"] + items_schema = schema["items"] + if items_schema == true + return "Array<`any`>" + elsif items_schema == false + return "Array<`never`>" + elsif items_schema["$ref"] && items_schema["$ref"].include?("schema_defs.json#/$defs/") + # $ref to schema_defs — inline the definition type (non-object refs, e.g. simple strings) + def_name = items_schema["$ref"].split("/").last + def_schema = schema_defs[def_name] + if def_schema && !(def_schema["type"] == "object" && def_schema["properties"]) + return "Array<#{format_inline_definition(def_name, def_schema)}>" if def_schema + end + # Object refs are handled by resolve_array_item_object in generate_properties_table + return "Array<object>" + elsif items_schema["type"] == "object" && items_schema["properties"] + # Inline object items are handled by resolve_array_item_object in generate_properties_table + return "Array<object>" + else + item_type = format_type(items_schema) + return "Array<#{item_type}>" + end + end + + "`#{type}`" + elsif schema["$ref"] + # Reference to another definition + ref = schema["$ref"] + if ref.start_with?("#") + # Internal reference - link to anchor + ref_name = ref.split("/").last + "[`#{ref_name}`](##{ref_name.downcase.gsub("_", "-")})" + else + # External reference + # Check if this is an absolute URL (http:// or https://) BEFORE splitting + if ref.start_with?("http://", "https://") + # Link directly to the external URL + return "[`#{ref}`](#{ref})" + end + + # Split at # first to separate file from anchor + parts = ref.split("#", 2) + ref_file_name = File.basename(parts[0], ".json") + + # Check if this is a reference to schema_defs - if so, inline it + if ref_file_name == "schema_defs" && parts.length > 1 + # Extract the definition name from the anchor + # Handle both draft-07 /definitions/ and draft-2020-12 /$defs/ + def_path = parts[1].split("/") + if def_path[0] == "" && (def_path[1] == "$defs" || def_path[1] == "definitions") && def_path.length == 3 + def_name = def_path[2] + # Get the definition from schema_defs + def_schema = schema_defs[def_name] + if def_schema + # Inline the definition + return format_inline_definition(def_name, def_schema) + end + end + end + + # Not schema_defs or couldn't inline - create a link + ref_anchor = parts.length > 1 ? parts[1].gsub("/", "-").downcase : "" + + # Determine the version of the referenced schema + ref_schema_path = File.join(@ref_base, parts[0]) + ref_version = schema_version # default to same version + if File.exist?(ref_schema_path) + begin + ref_schema = JSON.parse(File.read(ref_schema_path)) + ref_version = ref_schema["$id"] if ref_schema["$id"] + rescue + # If we can't read it, assume same version + end + end + + # If the referenced schema's $id is a URL, link to it directly + if ref_version&.start_with?("http://", "https://") + return "[`#{ref_file_name}`](#{ref_version})" + end + + # Build the relative path + path_prefix = if ref_version == schema_version + "./" + else + "../#{ref_version}/" + end + + if ref_anchor.empty? + "[`#{ref_file_name}`](#{path_prefix}#{ref_file_name}.mdx)" + else + "[`#{ref_file_name}##{ref_anchor}`](#{path_prefix}#{ref_file_name}.mdx##{ref_anchor})" + end + end + elsif schema["enum"] + # Infer type from enum values and display them + schema["enum"].map { |v| "`#{v}`" }.join(" \\| ") + elsif schema["oneOf"] + types = schema["oneOf"].map { |s| format_type(s) }.join(" \\| ") + "One of: #{types}" + elsif schema["anyOf"] + types = schema["anyOf"].map { |s| format_type(s) }.join(" \\| ") + "Any of: #{types}" + else + "`any`" + end + end + end +end diff --git a/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen/index_generator.rb b/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen/index_generator.rb new file mode 100644 index 0000000000..450ec16381 --- /dev/null +++ b/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen/index_generator.rb @@ -0,0 +1,114 @@ +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause-Clear + +# frozen_string_literal: true + +require "pathname" + +module SchemaDocGen + # Generates an index page for schema documentation + class IndexGenerator + attr_reader :output_dir + + def initialize(output_dir) + @output_dir = Pathname(output_dir.to_s) + end + + # Scan the output directory for generated schema docs and create an index + # @return [String] MDX content for the index page + def generate + versions = scan_versions + schemas_by_version = scan_schemas(versions) + + parts = [] + parts << generate_frontmatter + parts << generate_header + parts << generate_overview + parts << generate_schemas_section(versions, schemas_by_version) + + parts.join("\n\n").rstrip + "\n" + end + + private + + def scan_versions + return [] unless @output_dir.exist? + + @output_dir.children + .select(&:directory?) + .map { |d| d.basename.to_s } + .select { |d| d.start_with?("v") } + .sort + .reverse # Highest version first + end + + def scan_schemas(versions) + schemas = {} + + versions.each do |version| + version_dir = @output_dir / version + schema_files = version_dir.glob("*.mdx").map { |f| f.basename(".mdx").to_s }.sort + + schemas[version] = schema_files + end + + schemas + end + + def generate_frontmatter + <<~FRONTMATTER + --- + title: Schema Reference + sidebar_position: 1 + --- + FRONTMATTER + end + + def generate_header + <<~HEADER + # Schema Reference + + UDB uses JSON Schema to define and validate the structure of YAML files in `spec/`. Each schema is versioned independently — the version shown on each card is that schema's current version. + HEADER + end + + def generate_overview + <<~OVERVIEW + ## About Schema Versions + + Schemas are versioned independently of the UDB repository. Each schema file declares its version in the `$id` field. When a schema format changes, a new version is created to maintain backward compatibility with existing data files. + OVERVIEW + end + + def generate_schemas_section(versions, schemas_by_version) + return "No schema documentation found." if versions.empty? + + # Collect all schemas across all versions, sorted alphabetically by name. + # Each entry: {name:, version:, path:} + all_schemas = [] + versions.each do |version| + (schemas_by_version[version] || []).each do |schema| + all_schemas << {name: schema, version: version} + end + end + all_schemas.sort_by! { |s| s[:name] } + + md = "## Schemas\n\n" + md += "
\n\n" + + all_schemas.each do |schema| + schema_title = schema[:name].split("_").map(&:capitalize).join(" ") + md += <<~CARD +
+ #{schema_title}
+ #{schema[:version]} +
+ + CARD + end + + md += "
\n\n" + md + end + end +end diff --git a/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen/version.rb b/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen/version.rb new file mode 100644 index 0000000000..04de285dea --- /dev/null +++ b/tools/internal-gems/schema_doc_gen/lib/schema_doc_gen/version.rb @@ -0,0 +1,8 @@ +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause-Clear + +# frozen_string_literal: true + +module SchemaDocGen + VERSION = "0.1.0" +end diff --git a/tools/internal-gems/schema_doc_gen/schema_doc_gen.gemspec b/tools/internal-gems/schema_doc_gen/schema_doc_gen.gemspec new file mode 100644 index 0000000000..62e69b9b0d --- /dev/null +++ b/tools/internal-gems/schema_doc_gen/schema_doc_gen.gemspec @@ -0,0 +1,36 @@ +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause-Clear + +# frozen_string_literal: true + +require_relative "lib/schema_doc_gen/version" + +Gem::Specification.new do |s| + s.name = "schema_doc_gen" + s.version = SchemaDocGen::VERSION + s.summary = "JSON Schema documentation generator for UDB" + s.description = <<~DESC + Generates Markdown documentation from JSON Schema files for the + RISC-V Unified Database documentation site. + DESC + s.date = "2024-01-01" + s.authors = ["Derek Hower"] + s.email = ["dhower@qti.qualcomm.com"] + s.homepage = "https://github.com/riscv/riscv-unified-db" + s.files = Dir["lib/**/*.rb", "bin/*"] + s.license = "BSD-3-Clause-Clear" + s.metadata = { + "homepage_uri" => "https://github.com/riscv/riscv-unified-db", + "bug_tracker_uri" => "https://github.com/riscv/riscv-unified-db/issues" + } + s.required_ruby_version = "~> 3.2" + + s.require_paths = ["lib"] + s.bindir = "bin" + s.executables << "schema-doc-gen" + + s.add_dependency "tty-option" + s.add_dependency "tty-exit" + + s.add_development_dependency "rake" +end diff --git a/tools/ruby-gems/udb_helpers/REUSE.toml b/tools/ruby-gems/udb_helpers/REUSE.toml deleted file mode 100644 index 99eb1c9003..0000000000 --- a/tools/ruby-gems/udb_helpers/REUSE.toml +++ /dev/null @@ -1,10 +0,0 @@ -version = 1 - -# Computer-generated files that are checked in -[[annotations]] -path = [ - "sorbet/**", - "Gemfile.lock", -] -SPDX-FileCopyrightText = "NONE" -SPDX-License-Identifier = "CC0-1.0" diff --git a/tools/test/regress-tests.yaml b/tools/test/regress-tests.yaml index b5accad7f4..800177563d 100644 --- a/tools/test/regress-tests.yaml +++ b/tools/test/regress-tests.yaml @@ -366,6 +366,14 @@ tests: - name: Check schema versions against published URLs run: ./do gen:schemas && ./bin/ruby tools/scripts/check_schema_versions.rb + regress-schema-docs: + ci_stage: pr + tags: + - smoke + test: + - name: Generate schema documentation + run: ./bin/chore gen -f schema-docs + build-idl-doc: ci_stage: merge_queue gh_save_artifact: