diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 212187881..572cdb945 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -71,14 +71,22 @@ jobs: run: ./do gen:profile[RVI20] - name: Copy RVI20 Profile Release PDF run: cp gen/profile_doc/pdf/RVA20.pdf _site/pdfs/RVI20.pdf - - name: Create MC100 PDF Spec - run: ./do gen:cert_model_pdf[MC100] - - name: Copy MC100 PDF - run: cp gen/certificate_doc/pdf/MC100.pdf _site/pdfs/MC100.pdf - - name: Create MC100 HTML Spec - run: ./do gen:cert_model_html[MC100] - - name: Copy MC100 HTML - run: cp gen/certificate_doc/html/MC100.html _site/htmls/MC100.html + - name: Create MC100-32 PDF Spec + run: ./do gen:cert_model_pdf[MC100-32] + - name: Copy MC100-32 PDF + run: cp gen/certificate_doc/pdf/MC100-32.pdf _site/pdfs/MC100-32.pdf + - name: Create MC100-32 HTML Spec + run: ./do gen:cert_model_html[MC100-32] + - name: Copy MC100-32 HTML + run: cp gen/certificate_doc/html/MC100-32.html _site/htmls/MC100-32.html + - name: Create MC100-64 PDF Spec + run: ./do gen:cert_model_pdf[MC100-64] + - name: Copy MC100-64 PDF + run: cp gen/certificate_doc/pdf/MC100-64.pdf _site/pdfs/MC100-64.pdf + - name: Create MC100-64 HTML Spec + run: ./do gen:cert_model_html[MC100-64] + - name: Copy MC100-64 HTML + run: cp gen/certificate_doc/html/MC100-64.html _site/htmls/MC100-64.html - name: Copy manual html run: cp -R gen/manual/isa/top/all/html _site/manual - name: Setup Pages diff --git a/.gitignore b/.gitignore index ddd1aa6a7..a9bdc6be4 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ gen node_modules _site images +*.log diff --git a/.vscode/launch.json b/.vscode/launch.json index 49049c116..09d8dae10 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -3,7 +3,25 @@ "configurations": [ { "type": "rdbg", - "name": "RVA20 Profile", + "name": "MC100-32", + "request": "launch", + "command": "bundle exec rake", + "script": "gen:cert_model_pdf[MC100-32]", + "args": [], + "askParameters": false + }, + { + "type": "rdbg", + "name": "MC200-32", + "request": "launch", + "command": "bundle exec rake", + "script": "gen:cert_model_pdf[MC200-32]", + "args": [], + "askParameters": false + }, + { + "type": "rdbg", + "name": "RVA20", "request": "launch", "command": "bundle exec rake", "script": "gen:profile[RVA20]", diff --git a/README.adoc b/README.adoc index 816a2fc4f..bca01db3b 100644 --- a/README.adoc +++ b/README.adoc @@ -11,7 +11,8 @@ The following artifacts have been generated from the top of the `main` branch: * https://riscv-software-src.github.io/riscv-unified-db/pdfs/RVI20.pdf[RVI20 Profile Release] * https://riscv-software-src.github.io/riscv-unified-db/pdfs/RVA20.pdf[RVA20 Profile Release] * https://riscv-software-src.github.io/riscv-unified-db/pdfs/RVA22.pdf[RVA22 Profile Release] -* https://riscv-software-src.github.io/riscv-unified-db/pdfs/MC100.pdf[MC100 Certification Requirements Document] +* https://riscv-software-src.github.io/riscv-unified-db/pdfs/MC100-32.pdf[MC100-32 Certification Requirements Document] +* https://riscv-software-src.github.io/riscv-unified-db/pdfs/MC100-64.pdf[MC100-64 Certification Requirements Document] == Overview diff --git a/Rakefile b/Rakefile index a0358f82f..f9a3d858c 100644 --- a/Rakefile +++ b/Rakefile @@ -327,68 +327,63 @@ namespace :test do DESC task :nightly do Rake::Task["regress"].invoke - - Rake::Task["#{$root}/gen/certificate_doc/pdf/MC100.pdf"].invoke - Rake::Task["#{$root}/gen/profile_doc/pdf/RVA20.pdf"].invoke - Rake::Task["#{$root}/gen/profile_doc/pdf/RVA22.pdf"].invoke - Rake::Task["#{$root}/gen/profile_doc/pdf/RVI20.pdf"].invoke - + Rake::Task["portfolios"].invoke puts puts "Nightly regression test PASSED" end end desc <<~DESC - Generate all portfolio-based PDFs (certificates and profiles). + Generate all portfolio-based PDF artifacts (certificates and profiles) DESC -task :portfolio_pdfs do - puts "" - puts "===================================" - puts "Generating MC100" - puts "===================================" - puts "" - Rake::Task["#{$root}/gen/certificate_doc/pdf/MC100.pdf"].invoke - - puts "" - puts "==================================================" - puts "Generating MockCertificateModel" - puts "==================================================" - puts "" +task :portfolios do + portfolio_start_msg("MockCertificateModel") Rake::Task["#{$root}/gen/certificate_doc/pdf/MockCertificateModel.pdf"].invoke - - puts "" - puts "===================================" - puts "Generating RVA20" - puts "===================================" - puts "" + portfolio_start_msg("MockProfileRelease") + Rake::Task["#{$root}/gen/profile_doc/pdf/MockProfileRelease.pdf"].invoke + portfolio_start_msg("MC100-32") + Rake::Task["#{$root}/gen/certificate_doc/pdf/MC100-32.pdf"].invoke + portfolio_start_msg("MC100-64") + Rake::Task["#{$root}/gen/certificate_doc/pdf/MC100-64.pdf"].invoke + portfolio_start_msg("MC200-32") + Rake::Task["#{$root}/gen/certificate_doc/pdf/MC200-32.pdf"].invoke + portfolio_start_msg("MC200-64") + Rake::Task["#{$root}/gen/certificate_doc/pdf/MC200-64.pdf"].invoke + portfolio_start_msg("MC300-32") + Rake::Task["#{$root}/gen/certificate_doc/pdf/MC300-32.pdf"].invoke + portfolio_start_msg("MC300-64") + Rake::Task["#{$root}/gen/certificate_doc/pdf/MC300-64.pdf"].invoke + portfolio_start_msg("RVI20") + Rake::Task["#{$root}/gen/profile_doc/pdf/RVI20.pdf"].invoke + portfolio_start_msg("RVA20") Rake::Task["#{$root}/gen/profile_doc/pdf/RVA20.pdf"].invoke - - puts "" - puts "===================================" - puts "Generating RVA22" - puts "===================================" - puts "" + portfolio_start_msg("RVA22") Rake::Task["#{$root}/gen/profile_doc/pdf/RVA22.pdf"].invoke + portfolio_start_msg("RVA23") + Rake::Task["#{$root}/gen/profile_doc/pdf/RVA23.pdf"].invoke + portfolio_start_msg("RVB23") + Rake::Task["#{$root}/gen/profile_doc/pdf/RVB23.pdf"].invoke +end +def portfolio_start_msg(name) puts "" - puts "===================================" - puts "Generating RVI20" - puts "===================================" - puts "" - Rake::Task["#{$root}/gen/profile_doc/pdf/RVI20.pdf"].invoke - - puts "" - puts "===================================" - puts "Generating MockProfileRelease" - puts "===================================" + puts "=================================================================================================" + puts "#{name}" + puts "=================================================================================================" puts "" - Rake::Task["#{$root}/gen/profile_doc/pdf/MockProfileRelease.pdf"].invoke end # Shortcut targets for building profiles and certificates. -task MC100: "#{$root}/gen/certificate_doc/pdf/MC100.pdf" -task MockCertificateModel: "#{$root}/gen/certificate_doc/pdf/MockCertificateModel.pdf" -task RVI20: "#{$root}/gen/profile_doc/pdf/RVI20.pdf" -task RVA20: "#{$root}/gen/profile_doc/pdf/RVA20.pdf" -task RVA22: "#{$root}/gen/profile_doc/pdf/RVA22.pdf" -task MockProfileRelease: "#{$root}/gen/profile_doc/pdf/MockProfileRelease.pdf" +task "MockCertificateModel": "#{$root}/gen/certificate_doc/pdf/MockCertificateModel.pdf" +task "MC100-32": "#{$root}/gen/certificate_doc/pdf/MC100-32.pdf" +task "MC100-64": "#{$root}/gen/certificate_doc/pdf/MC100-64.pdf" +task "MC200-32": "#{$root}/gen/certificate_doc/pdf/MC200-32.pdf" +task "MC200-64": "#{$root}/gen/certificate_doc/pdf/MC200-64.pdf" +task "MC300-32": "#{$root}/gen/certificate_doc/pdf/MC300-32.pdf" +task "MC300-64": "#{$root}/gen/certificate_doc/pdf/MC300-64.pdf" +task "MockProfileRelease": "#{$root}/gen/profile_doc/pdf/MockProfileRelease.pdf" +task "RVI20": "#{$root}/gen/profile_doc/pdf/RVI20.pdf" +task "RVA20": "#{$root}/gen/profile_doc/pdf/RVA20.pdf" +task "RVA22": "#{$root}/gen/profile_doc/pdf/RVA22.pdf" +task "RVA23": "#{$root}/gen/profile_doc/pdf/RVA23.pdf" +task "RVB23": "#{$root}/gen/profile_doc/pdf/RVB23.pdf" diff --git a/arch/certificate_class/MC.yaml b/arch/certificate_class/MC.yaml index 97a82ca6e..ae5eb1977 100644 --- a/arch/certificate_class/MC.yaml +++ b/arch/certificate_class/MC.yaml @@ -1,38 +1,13 @@ # yaml-language-server: $schema=../../schemas/cert_class_schema.json $schema: cert_class_schema.json# -kind: certificate class +kind: Processor CRD +processor_kind: Microcontroller name: MC -long_name: Microcontroller Certificate Class +long_name: Microcontroller Class CRD introduction: | - This certification class specifies requirements for microcontrollers. - It targets microcontrollers running low-level software on an RTOS or bare-metal. - This CRD is not intended for the smallest possible microcontrollers but rather for applications - benefiting from a standardized microcontroller. - See the https://docs.google.com/document/d/133SZKc18tLsQcT1o6gEmBUkjwrtg2ow63me54RQ1jiY[RISC-V CRDs] - document for information relevant to all RISC-V CRDs. - -naming_scheme: | - The MC (M = Microcontroller, C = Certificate) has the following naming scheme (suffixes after MC - are optional but in the below order): - - MC[v] - - Where: - - * Left & right square braces denote optional. - * \ is a 3 digit integer. It is changed only when mandatory extensions are added to a CRD. - ** The one's digit is incremented when a small mandatory extension is added (e.g., Zicond) - ** The ten's digit is incremented when a medium mandatory extension is added (e.g., PMP) - ** The hundreds's digit is incremented when a large mandatory extension is added (e.g., V or H) - * \ is a semantic version (see semver.org) formatted as [..[patch]]. If \ is omitted, the reference applies equally to all versions. - ** A release indicates support for a new optional extension. - ** A release indicates one or more of the following changes to the certification tests associated with the CRD. - *** Fix test bug or increase test coverage - *** Add more allowed parameter values - *** Support new extension version - ** A release indicates just CRD specification changes without any difference in functional behavior + The MC (Microcontroller Class) targets processors running low-level software on an RTOS or bare-metal. mandatory_priv_modes: - M diff --git a/arch/certificate_class/MockCertificateClass.yaml b/arch/certificate_class/MockCertificateClass.yaml index 4dc404972..e358b8684 100644 --- a/arch/certificate_class/MockCertificateClass.yaml +++ b/arch/certificate_class/MockCertificateClass.yaml @@ -1,16 +1,13 @@ # yaml-language-server: $schema=../../schemas/cert_class_schema.json $schema: cert_class_schema.json# -kind: certificate class +kind: Processor CRD +processor_kind: Apps Processor name: MockCertificateClass long_name: Mock Certificate Class Long Name introduction: | Here's the Mock Certificate Class introduction. -naming_scheme: | - Here's the Mock Certificate Class naming scheme. - A Mock certificate class or model can have any name as long as it can be a hash key. - mandatory_priv_modes: - M diff --git a/arch/certificate_model/MC100.yaml b/arch/certificate_model/MC100-32.yaml similarity index 86% rename from arch/certificate_model/MC100.yaml rename to arch/certificate_model/MC100-32.yaml index b3dba5128..a2a0d00db 100644 --- a/arch/certificate_model/MC100.yaml +++ b/arch/certificate_model/MC100-32.yaml @@ -2,8 +2,8 @@ $schema: cert_model_schema.json# kind: certificate model -name: MC100 -long_name: Basic Microcontroller Certificate +name: MC100-32 +long_name: Basic 32-bit Microcontroller Certificate class: $ref: certificate_class/MC.yaml# @@ -67,18 +67,17 @@ revision_history: changes: - Initial version -description: | - MC100 can be though of as minimal 32-bit RISC-V processors with M-mode support: +introduction: | + The MC100 Processor CRD (Certification Requirements Document) defines the requirements + a processor implementation must meet in order to be eligible for the associated MC100 certificate. + MC100 is a basic RISC-V processor with minimal M-mode support and has 32-bit and 64-bit variants. - * The Unprivileged ISA is RV32I with a few extensions suitable for a basic microcontroller - * The M-mode features are those listed as mandatory in the associated RISC-V Privileged ISA manual + MC100 is not intended for the smallest possible microcontrollers but rather for applications + benefiting from a minimal but standardized microcontroller. It consists of: - Key features not included in MC100 (i.e., OUT OF SCOPE): - - * Interrupt Controller (e.g., CLIC, CLINT, PLIC) - * Features for modes other than M-mode - * PMP - * Debug & trace (TBD) + * Unprivileged ISA: RV32I for MC100-32 and RV64I for MC100-64 with a few extensions suitable + for a basic microcontroller. + * Privileged ISA: Only the M-mode features listed as mandatory in the RISC-V Privileged ISA manual # Specification versions tsc_profile: null # None for MC100 diff --git a/arch/certificate_model/MC100-64.yaml b/arch/certificate_model/MC100-64.yaml new file mode 100644 index 000000000..bede0a7a0 --- /dev/null +++ b/arch/certificate_model/MC100-64.yaml @@ -0,0 +1,20 @@ +# yaml-language-server: $schema=../../schemas/cert_model_schema.json + +$schema: cert_model_schema.json# +kind: certificate model +name: MC100-64 +long_name: Basic 64-bit Microcontroller Certificate +class: + $ref: certificate_class/MC.yaml# + +$inherits: "certificate_model/MC100-32.yaml#" + +# XLEN used by rakefile +base: 64 + +extensions: + Sm: + parameters: + XLEN: + schema: + const: 64 diff --git a/arch/certificate_model/MC200-32.yaml b/arch/certificate_model/MC200-32.yaml new file mode 100644 index 000000000..ee2d1049a --- /dev/null +++ b/arch/certificate_model/MC200-32.yaml @@ -0,0 +1,50 @@ +# yaml-language-server: $schema=../../schemas/cert_model_schema.json + +$schema: cert_model_schema.json# +kind: certificate model +name: MC200-32 +long_name: Intermediate 32-bit Microcontroller Certificate +class: + $ref: certificate_class/MC.yaml# + +# Semantic versions within the model +versions: + - version: "1.0.0" + +# XLEN used by rakefile +base: 32 + +$inherits: "certificate_model/MC100-32.yaml#" + +revision_history: + - revision: "0.1.0" + date: "2024-11-27" + changes: + - First created + +introduction: | + MC200 is an intermedicate RISC-V microcontroller that adds the following mandatory extensions to the MC100-series: + + * U extension (User-mode privilege level) + * Smpmp extension (M-mode PMP) + * B (Bitfield) extension + * Zce extension (additional 16-bit instructions suitable for microcontrollers) + * CLIC extension (if/when ratified) + +# Specification versions +tsc_profile: null # None for MC200 +unpriv_isa_manual_revision: "20191213" +priv_isa_manual_revision: "20190608-Priv-MSU-Ratified" +debug_manual_revision: "0.13.2" + +# TODO: No ratified CLIC yet. It will be multiple extensions. + +extensions: + B: + presence: mandatory + Zce: + presence: mandatory + U: + presence: mandatory + Smpmp: + presence: mandatory diff --git a/arch/certificate_model/MC200-64.yaml b/arch/certificate_model/MC200-64.yaml new file mode 100644 index 000000000..a4925bdb8 --- /dev/null +++ b/arch/certificate_model/MC200-64.yaml @@ -0,0 +1,20 @@ +# yaml-language-server: $schema=../../schemas/cert_model_schema.json + +$schema: cert_model_schema.json# +kind: certificate model +name: MC200-64 +long_name: Intermediate 64-bit Microcontroller Certificate +class: + $ref: certificate_class/MC.yaml# + +$inherits: "certificate_model/MC200-32.yaml#" + +# XLEN used by rakefile +base: 64 + +extensions: + Sm: + parameters: + XLEN: + schema: + const: 64 diff --git a/arch/certificate_model/MC300-32.yaml b/arch/certificate_model/MC300-32.yaml new file mode 100644 index 000000000..512dd0b61 --- /dev/null +++ b/arch/certificate_model/MC300-32.yaml @@ -0,0 +1,35 @@ +# yaml-language-server: $schema=../../schemas/cert_model_schema.json + +$schema: cert_model_schema.json# +kind: certificate model +name: MC300-32 +long_name: Advanced 32-bit Microcontroller Certificate +class: + $ref: certificate_class/MC.yaml# + +# Semantic versions within the model +versions: + - version: "1.0.0" + +# XLEN used by rakefile +base: 32 + +$inherits: "certificate_model/MC200-32.yaml#" + +revision_history: + - revision: "0.1.0" + date: "2024-11-27" + changes: + - First created + +introduction: | + MC300 is an advanced RISC-V microcontroller that adds the following mandatory extensions to the MC200-series: + + * S extension (Supervisor-mode privilege level) + * Sspmp extension (S-mode PMP, not ratified yet) + +# TODO: No ratified sPMP yet. + +extensions: + S: + presence: mandatory diff --git a/arch/certificate_model/MC300-64.yaml b/arch/certificate_model/MC300-64.yaml new file mode 100644 index 000000000..251b49782 --- /dev/null +++ b/arch/certificate_model/MC300-64.yaml @@ -0,0 +1,20 @@ +# yaml-language-server: $schema=../../schemas/cert_model_schema.json + +$schema: cert_model_schema.json# +kind: certificate model +name: MC300-64 +long_name: Advanced 64-bit Microcontroller Certificate +class: + $ref: certificate_class/MC.yaml# + +$inherits: "certificate_model/MC300-32.yaml#" + +# XLEN used by rakefile +base: 64 + +extensions: + Sm: + parameters: + XLEN: + schema: + const: 64 diff --git a/arch/certificate_model/MockCertificateModel.yaml b/arch/certificate_model/MockCertificateModel.yaml index 86b2601ec..b9c072e70 100644 --- a/arch/certificate_model/MockCertificateModel.yaml +++ b/arch/certificate_model/MockCertificateModel.yaml @@ -25,8 +25,8 @@ revision_history: changes: - Also created to test CRDs -description: | - Mock CRD description: +introduction: | + Mock CRD introduction: * Hello * Bob! @@ -135,7 +135,7 @@ extensions: M_MODE_ENDIANESS: schema: const: little - # Uncomment when GitHub issue # is fixed. + # TODO: Uncomment when GitHub issue # is fixed. #schema: #- when: # version: "=1.0.0" diff --git a/arch/ext/S.yaml b/arch/ext/S.yaml index 641121013..e176bf3ea 100644 --- a/arch/ext/S.yaml +++ b/arch/ext/S.yaml @@ -18,6 +18,12 @@ versions: requires: name: U version: "= 1.0.0" +- version: "1.13.0" + state: ratified + ratification_date: null + requires: + name: U + version: "= 1.0.0" description: | This chapter describes the RISC-V supervisor-level architecture, which contains a common core that is used with various supervisor-level diff --git a/arch/ext/Sdtrig.yaml b/arch/ext/Sdtrig.yaml new file mode 100644 index 000000000..28c25794f --- /dev/null +++ b/arch/ext/Sdtrig.yaml @@ -0,0 +1,30 @@ +# yaml-language-server: $schema=../../schemas/ext_schema.json + +$schema: "ext_schema.json#" +kind: extension +name: Sdtrig +long_name: Debug triggers +description: | + Triggers can cause a breakpoint exception, entry into Debug Mode, or a + trace action without having to execute a special instruction. This makes + them invaluable when debugging code from ROM. They can trigger on + execution of instructions at a given memory address, or on the + address/data in loads/stores. + + If Sdtrig is implemented, the Trigger Module must support at least one + trigger. Accessing trigger CSRs that are not used by any of the + implemented triggers must result in an illegal instruction exception. + M-Mode and Debug Mode accesses to trigger CSRs that are used by any of + the implemented triggers must succeed, regardless of the current type of + the currently selected trigger. + + A trigger matches when the conditions that it specifies (e.g. a load + from a specific address) are met. A trigger fires when a trigger that + matches performs the action configured for that trigger. + + Triggers do not fire while in Debug Mode. +type: privileged +versions: + - version: "1.0.0" + state: ratified + ratification_date: null diff --git a/arch/ext/Sha.yaml b/arch/ext/Sha.yaml new file mode 100644 index 000000000..e0dc46d05 --- /dev/null +++ b/arch/ext/Sha.yaml @@ -0,0 +1,56 @@ +# yaml-language-server: $schema=../../schemas/ext_schema.json + +$schema: "ext_schema.json#" +kind: extension +name: Sha +long_name: The augmented hypervisor extension +description: | + *Sha* comprises the following extensions: + + ** *H* The hypervisor extension. + + ** *Ssstateen* Supervisor-mode view of the state-enable extension. The + supervisor-mode (`sstateen0-3`) and hypervisor-mode (`hstateen0-3`) + state-enable registers must be provided. + + ** *Shcounterenw* For any `hpmcounter` that is not read-only zero, the corresponding bit in `hcounteren` must be writable. + + ** *Shvstvala* `vstval` must be written in all cases described above for `stval`. + + ** *Shtvala* `htval` must be written with the faulting guest physical + address in all circumstances permitted by the ISA. + + ** *Shvstvecd* `vstvec.MODE` must be capable of holding the value 0 (Direct). + When `vstvec.MODE`=Direct, `vstvec.BASE` must be capable of holding + any valid four-byte-aligned address. + + ** *Shvsatpa* All translation modes supported in `satp` must be supported in `vsatp`. + + ** *Shgatpa* For each supported virtual memory scheme SvNN supported in + `satp`, the corresponding hgatp SvNNx4 mode must be supported. The + `hgatp` mode Bare must also be supported. + + [NOTE] + Sha is a new profile-defined extension that captures the + full set of features that are mandated to be supported along with the + H extension. There is no change to the features added by including + the hypervisor extension in a profile--the new name is solely to + simplify the text of the profiles. The definition has been added to + the RVA22 profile text, where the hypervisor extension was first + added, and will be added to the hypervisor section of the combined ISA + manual. + +versions: + - version: "1.0.0" + state: ratified + ratification_date: null + requires: + allOf: + - H + - Ssstateen + - Shcounterenw + - Shvstvala + - Shtvala + - Shvstvecd + - Shvsatpa + - Shgatpa diff --git a/arch/ext/Smdbltrp.yaml b/arch/ext/Smdbltrp.yaml index 0f1b1227b..37fb09242 100644 --- a/arch/ext/Smdbltrp.yaml +++ b/arch/ext/Smdbltrp.yaml @@ -9,7 +9,7 @@ description: | When the `Smrnmi` extension is implemented, it enables invocation of the RNMI handler on a double trap in M-mode to handle the critical error. If the `Smrnmi` extension is not implemented or if a double trap occurs during the RNMI - handler’s execution, this extension helps transition the hart to a critical error state and + handler's execution, this extension helps transition the hart to a critical error state and enables signaling the critical error to the platform. To improve error diagnosis and resolution, this extension supports debugging harts in a critical diff --git a/arch/ext/Smmpm.yaml b/arch/ext/Smmpm.yaml new file mode 100644 index 000000000..c7b49f8ad --- /dev/null +++ b/arch/ext/Smmpm.yaml @@ -0,0 +1,21 @@ +# yaml-language-server: $schema=../../schemas/ext_schema.json + +$schema: "ext_schema.json#" +kind: extension +name: Smmpm +long_name: Pointer masking for M-mode +description: | + A machine-level extension that provides pointer masking for M-mode. +type: privileged +versions: + - version: "1.0.0" + state: ratified + ratification_date: null +params: + PMLEN: + description: | + The number of high-order bits of an address that are masked by the + pointer masking facility. + schema: + type: integer + also_defined_in: [Ssnpm, Smmpm] diff --git a/arch/ext/Smnpm.yaml b/arch/ext/Smnpm.yaml new file mode 100644 index 000000000..fa47b05a1 --- /dev/null +++ b/arch/ext/Smnpm.yaml @@ -0,0 +1,22 @@ +# yaml-language-server: $schema=../../schemas/ext_schema.json + +$schema: "ext_schema.json#" +kind: extension +name: Smnpm +long_name: Pointer masking for next privilege level less than M-mode +description: | + A machine-level extension that provides pointer masking for the next lower privilege mode + (S/HS if S-mode is implemented, or U-mode otherwise). +type: privileged +versions: + - version: "1.0.0" + state: ratified + ratification_date: null +params: + PMLEN: + description: | + The number of high-order bits of an address that are masked by the + pointer masking facility. + schema: + type: integer + also_defined_in: [Ssnpm, Smmpm] diff --git a/arch/ext/Ssnpm.yaml b/arch/ext/Ssnpm.yaml new file mode 100644 index 000000000..652e87912 --- /dev/null +++ b/arch/ext/Ssnpm.yaml @@ -0,0 +1,22 @@ +# yaml-language-server: $schema=../../schemas/ext_schema.json + +$schema: "ext_schema.json#" +kind: extension +name: Ssnpm +long_name: Pointer masking for next privilege level less than S-mode +description: | + A supervisor-level extension that provides pointer masking for the next lower privilege mode (U-mode), + and for VS-modes and VU-modes if the H extension is present. +type: privileged +versions: + - version: "1.0.0" + state: ratified + ratification_date: null +params: + PMLEN: + description: | + The number of high-order bits of an address that are masked by the + pointer masking facility. + schema: + type: integer + also_defined_in: [Smnpm, Smmpm] diff --git a/arch/ext/Sspm.yaml b/arch/ext/Sspm.yaml new file mode 100644 index 000000000..01e0835cf --- /dev/null +++ b/arch/ext/Sspm.yaml @@ -0,0 +1,20 @@ +# yaml-language-server: $schema=../../schemas/ext_schema.json + +$schema: "ext_schema.json#" +kind: extension +name: Sspm +long_name: Pointer masking available in supervisor mode +description: | + Indicates that there is pointer-masking support available in supervisor mode, + with some facility provided in the application execution environment to control pointer masking. + + This extension describes an execution environment but has no bearing on hardware implementations. + It is intended to be used in profile specifications where a Supervisor profile + can only reference Supervisor level pointer masking functionality, + and not the associated CSR controls that exist at a higher privilege level (i.e., in the execution environment). + +type: privileged +versions: + - version: "1.0.0" + state: ratified + ratification_date: null diff --git a/arch/ext/Ssstrict.yaml b/arch/ext/Ssstrict.yaml new file mode 100644 index 000000000..8856e08f3 --- /dev/null +++ b/arch/ext/Ssstrict.yaml @@ -0,0 +1,38 @@ +# yaml-language-server: $schema=../../schemas/ext_schema.json + +$schema: "ext_schema.json#" +kind: extension +name: Ssstrict +long_name: Unimplemented reserved encodings trap and no no-conforming extensions +description: | + No non-conforming extensions are present. Attempts to + execute unimplemented opcodes or access unimplemented CSRs in the + standard or reserved encoding spaces raises an illegal instruction + exception that results in a contained trap to the supervisor-mode + trap handler. + + [NOTE] + Ssstrict does not prescribe behavior for the custom encoding + spaces or CSRs. + + [NOTE] + Ssstrict definition applies to the execution environment + claiming to be RVA23/RVB23-compatible. + If the hypervisor extension is present, that execution environment will take a contained trap to + supervisor-mode (however that trap is implemented, including, but not + limited to, emulation/delegation in the outer execution + environment). Ssstrict (and all the other RVA23/RVB23 mandates and options) + do not apply to any guest VMs run by a hypervisor. An RVA23/RVB23 hypervisor + can provide guest VMs that are also RVA23/RVB23-compatible but with an + expanded set of emulated standard instructions. An RVA23/RVB23 hypervisor + can also choose to implement guest VMs that are not RVA23/RVB23 compatible + (e.g., lacking H, or only RVA20). + + [NOTE] + Ssstrict is a new RVA23/RVB23 profile-defined extension that restricts the + behavior of reserved encoding spaces. The extension will be added to + the supervisor chapter of the privileged architecture. +versions: + - version: "1.0.0" + state: ratified + ratification_date: null diff --git a/arch/ext/Supm.yaml b/arch/ext/Supm.yaml new file mode 100644 index 000000000..428195abc --- /dev/null +++ b/arch/ext/Supm.yaml @@ -0,0 +1,20 @@ +# yaml-language-server: $schema=../../schemas/ext_schema.json + +$schema: "ext_schema.json#" +kind: extension +name: Supm +long_name: Pointer masking available in user mode +description: | + Indicates that there is pointer-masking support available in user mode, + with some facility provided in the application execution environment to control pointer masking. + + This extension describes an execution environment but has no bearing on hardware implementations. + It is intended to be used in profile specifications where a User profile + can only reference User level pointer masking functionality, + and not the associated CSR controls that exist at a higher privilege level (i.e., in the execution environment). + +type: privileged +versions: + - version: "1.0.0" + state: ratified + ratification_date: null diff --git a/arch/ext/Svvptc.yaml b/arch/ext/Svvptc.yaml new file mode 100644 index 000000000..4715a7da4 --- /dev/null +++ b/arch/ext/Svvptc.yaml @@ -0,0 +1,34 @@ +# yaml-language-server: $schema=../../schemas/ext_schema.json + +$schema: "ext_schema.json#" +kind: extension +name: Svvptc +long_name: Guarantees visibility of PTE transitions from invalid to valid +description: | + When the Svvptc extension is implemented, explicit stores by a hart that update + the Valid bit of leaf and/or non-leaf PTEs from 0 to 1 and are visible to a hart + will eventually become visible within a bounded timeframe to subsequent implicit + accesses by that hart to such PTEs. + + [NOTE] + Svvptc relieves an operating system from executing certain memory-management + instructions, such as `SFENCE.VMA` or `SINVAL.VMA`, which would normally be used + to synchronize the hart's address-translation caches when a memory-resident PTE + is changed from Invalid to Valid. Synchronizing the hart's address-translation + caches with other forms of updates to a memory-resident PTE, including when a + PTE is changed from Valid to Invalid, requires the use of suitable + memory-management instructions. Svvptc guarantees that a change to a PTE from + Invalid to Valid is made visible within a bounded time, thereby making the + execution of these memory-management instructions redundant. The performance + benefit of eliding these instructions outweighs the cost of an occasional + gratuitous additional page fault that may occur.+ + Depending on the microarchitecture, some possible ways to facilitate + implementation of Svvptc include: not having any address-translation caches, not + storing Invalid PTEs in the address-translation caches, automatically evicting + Invalid PTEs using a bounded timer, or making address-translation caches + coherent with store instructions that modify PTEs. +type: privileged +versions: + - version: "1.0.0" + state: ratified + ratification_date: null diff --git a/arch/ext/Za64rs.yaml b/arch/ext/Za64rs.yaml new file mode 100644 index 000000000..ea833511a --- /dev/null +++ b/arch/ext/Za64rs.yaml @@ -0,0 +1,25 @@ +# yaml-language-server: $schema=../../schemas/ext_schema.json + +$schema: "ext_schema.json#" +kind: extension +name: Za64rs +long_name: Reservation set requirement for RVA profiles +description: | + Reservation sets must be contiguous, naturally aligned, and at most 64 bytes in size. + + [NOTE] + This extension was ratified as part of the RVA22 profile. + + [NOTE] + The minimum reservation set size is effectively determined by the size of atomic accesses in + the A extension. +versions: + - version: "1.0.0" + state: ratified + ratification_date: null + param_constraints: + LRSC_RESERVATION_STRATEGY: + schema: + oneOf: + - const: reserve exactly enough to cover the access + - const: reserve naturally-aligned 64-byte region diff --git a/arch/ext/Zama16b.yaml b/arch/ext/Zama16b.yaml new file mode 100644 index 000000000..10812d449 --- /dev/null +++ b/arch/ext/Zama16b.yaml @@ -0,0 +1,20 @@ +# yaml-language-server: $schema=../../schemas/ext_schema.json + +$schema: "ext_schema.json#" +kind: extension +name: Zama16b +long_name: Misaligned load/store/AMO within aligned 16-byte address are atomic +description: | + Misaligned loads, stores, and AMOs to main memory regions that do not cross a + naturally-aligned 16-byte boundary are atomic. + + [NOTE] + Zama16b is a new RVA23 profile-defined extension that represents + the presence of the new Misaligned Atomicity Granule feature added in + Sm1p13. The extension will be added to the PMA section of the + privileged architecture manual. + +versions: + - version: "1.0.0" + state: ratified + ratification_date: null diff --git a/arch/ext/Zce.yaml b/arch/ext/Zce.yaml index 442018759..4eeb34b99 100644 --- a/arch/ext/Zce.yaml +++ b/arch/ext/Zce.yaml @@ -11,14 +11,13 @@ description: | * Specifying `Zce` on RV32 without `F` includes `Zca`, `Zcb`, `Zcmp`, `Zcmt` * Specifying `Zce` on RV32 with `F` includes `Zca`, `Zcb`, `Zcmp`, `Zcmt` and `Zcf` * Specifying `Zce` on RV64 always includes `Zca`, `Zcb`, `Zcmp`, `Zcmt` - * `Zcf` doesn’t exist for RV64 + * `Zcf` doesn't exist for RV64 Therefore common ISA strings can be updated as follows to include the relevant Zc extensions, for example: * RV32IMC becomes RV32IM_Zce * RV32IMCF becomes RV32IMF_Zce - type: unprivileged company: name: RISC-V International diff --git a/arch/ext/Zcmop.yaml b/arch/ext/Zcmop.yaml new file mode 100644 index 000000000..70e8fbfa0 --- /dev/null +++ b/arch/ext/Zcmop.yaml @@ -0,0 +1,53 @@ +# yaml-language-server: $schema=../../schemas/ext_schema.json + +$schema: "ext_schema.json#" +kind: extension +name: Zcmop +long_name: 16-bit May-be Operations +description: | + The "Zcmop" extension, which defines eight 16-bit MOP + instructions named C.MOP.__n__, where __n__ is an odd integer between 1 and + 15, inclusive. C.MOP.__n__ is encoded in the reserved encoding space + corresponding to C.LUI x__n__, 0, as shown in <>. + Unlike the MOPs defined in the Zimop extension, the C.MOP.__n__ instructions + are defined to _not_ write any register. + Their encoding allows future extensions to define them to read register + `x[__n__]`. + + The Zcmop extension depends upon the Zca extension. + + NOTE: Very few suitable 16-bit encoding spaces exist. This space was chosen + because it already has unusual behavior with respect to the `rd`/`rs1` + field--it encodes `c.addi16sp` when the field contains `x2`--and is + therefore of lower value for most purposes. + + [[tab:c-mop]] + .C.MOP.__n__ instruction encoding. + + |=== + |Mnemonic | Encoding | Redefinable to read register + + |C.MOP.1 | `0110000010000001` | `x1` + |C.MOP.3 | `0110000110000001` | `x3` + |C.MOP.5 | `0110001010000001` | `x5` + |C.MOP.7 | `0110001110000001` | `x7` + |C.MOP.9 | `0110010010000001` | `x9` + |C.MOP.11 | `0110010110000001` | `x11` + |C.MOP.13 | `0110011010000001` | `x13` + |C.MOP.15 | `0110011110000001` | `x15` + |=== + + NOTE: The recommended assembly syntax for C.MOP.__n__ is simply the nullary + C.MOP.__n__. The possibly accessed register is implicitly `x__n__`. + + NOTE: The expectation is that each Zcmop instruction is equivalent to some + Zimop instruction, but the choice of expansion (if any) is left to the + extension that redefines the MOP. + Note, a Zcmop instruction that does not write a value can expand into a write + to `x0`. +type: unprivileged +versions: + - version: "1.0.0" + state: ratified + ratification_date: null + requires: C diff --git a/arch/ext/Zcmp.yaml b/arch/ext/Zcmp.yaml new file mode 100644 index 000000000..115720ec8 --- /dev/null +++ b/arch/ext/Zcmp.yaml @@ -0,0 +1,90 @@ +# yaml-language-server: $schema=../../schemas/ext_schema.json + +$schema: "ext_schema.json#" +kind: extension +name: Zcmp +long_name: 16-bit Push/Pop instructions +description: | + The Zcmp extension is a set of instructions which may be executed as a series of existing 32-bit RISC-V instructions. + + This extension reuses some encodings from _c.fsdsp_. Therefore it is _incompatible_ with <>, + which is included when C and D extensions are both present. + + NOTE: Zcmp is primarily targeted at embedded class CPUs due to implementation complexity. Additionally, it is not compatible with architecture class profiles. + + The Zcmp extension depends on the <> extension. + + The PUSH/POP assembly syntax uses several variables, the meaning of which are: + + * _reg_list_ is a list containing 1 to 13 registers (ra and 0 to 12 s registers) + ** valid values: {ra}, {ra, s0}, {ra, s0-s1}, {ra, s0-s2}, ..., {ra, s0-s8}, {ra, s0-s9}, {ra, s0-s11} + ** note that {ra, s0-s10} is _not_ valid, giving 12 lists not 13 for better encoding + * _stack_adj_ is the total size of the stack frame. + ** valid values vary with register list length and the specific encoding, see the instruction pages for details. + + [%header,cols="^1,^1,4,8"] + |=== + |RV32 + |RV64 + |Mnemonic + |Instruction + + |yes + |yes + |cm.push _{reg_list}, -stack_adj_ + |<<#insns-cm_push>> + + |yes + |yes + |cm.pop _{reg_list}, stack_adj_ + |<<#insns-cm_pop>> + + |yes + |yes + |cm.popret _{reg_list}, stack_adj_ + |<<#insns-cm_popret>> + + |yes + |yes + |cm.popretz _{reg_list}, stack_adj_ + |<<#insns-cm_popretz>> + + |yes + |yes + |cm.mva01s _rs1', rs2'_ + |<<#insns-cm_mva01s>> + + |yes + |yes + |cm.mvsa01 _r1s', r2s'_ + |<<#insns-cm_mvsa01>> + + |=== + +type: unprivileged +company: + name: RISC-V International + url: https://riscv.org +versions: + - version: "1.0.0" + state: ratified + ratification_date: 2023-04 + repositories: + - url: https://github.com/riscv/riscv-code-size-reduction + branch: main + contributors: + - name: Tariq Kurd + - name: Ibrahim Abu Kharmeh + - name: Torbjørn Viem Ness + - name: Matteo Perotti + - name: Nidal Faour + - name: Bill Traynor + - name: Rafael Sene + - name: Xinlong Wu + - name: sinan + - name: Jeremy Bennett + - name: Heda Chen + - name: Alasdair Armstrong + - name: Graeme Smecher + - name: Nicolas Brunie + - name: Jiawei diff --git a/arch/ext/Zcmt.yaml b/arch/ext/Zcmt.yaml new file mode 100644 index 000000000..c3a7912de --- /dev/null +++ b/arch/ext/Zcmt.yaml @@ -0,0 +1,90 @@ +# yaml-language-server: $schema=../../schemas/ext_schema.json + +$schema: "ext_schema.json#" +kind: extension +name: Zcmt +long_name: 16-bit Table Jump +description: | + Zcmt adds the table jump instructions and also adds the jvt CSR. The jvt CSR requires a + state enable if Smstateen is implemented. See <> for details. + + This extension reuses some encodings from _c.fsdsp_. Therefore it is _incompatible_ with <>, + which is included when C and D extensions are both present. + + NOTE: Zcmt is primarily targeted at embedded class CPUs due to implementation complexity. Additionally, it is not compatible with RVA profiles. + + The Zcmt extension depends on the <> and Zicsr extensions. + + [%header,cols="^1,^1,4,8"] + |=== + |RV32 + |RV64 + |Mnemonic + |Instruction + + |yes + |yes + |cm.jt _index_ + |<<#insns-cm_jt>> + + |yes + |yes + |cm.jalt _index_ + |<<#insns-cm_jalt>> + + |=== + +type: unprivileged +company: + name: RISC-V International + url: https://riscv.org +versions: + - version: "1.0.0" + state: ratified + ratification_date: 2023-04 + repositories: + - url: https://github.com/riscv/riscv-code-size-reduction + branch: main + contributors: + - name: Tariq Kurd + - name: Ibrahim Abu Kharmeh + - name: Torbjørn Viem Ness + - name: Matteo Perotti + - name: Nidal Faour + - name: Bill Traynor + - name: Rafael Sene + - name: Xinlong Wu + - name: sinan + - name: Jeremy Bennett + - name: Heda Chen + - name: Alasdair Armstrong + - name: Graeme Smecher + - name: Nicolas Brunie + - name: Jiawei + implies: + - [Zca, "1.0.0"] + - [Zcb, "1.0.0"] + - [Zcmp, "1.0.0"] + - [Zcmt, "1.0.0"] + + # TODO: this implication is conditional!!! (see description) + # So it should look something like this: + + # if: + # allOf: + # param: + # XLEN: 32 + # extensions: + # - F + # then: + # - [Zca, "1.0.0"] + # - [Zcb, "1.0.0"] + # - [Zcmp, "1.0.0"] + # - [Zcmt, "1.0.0"] + # - [Zf, "1.0.0"] + # else: + # # TODO: this implication is conditional!!! (see description) + # - [Zca, "1.0.0"] + # - [Zcb, "1.0.0"] + # - [Zcmp, "1.0.0"] + # - [Zcmt, "1.0.0"] diff --git a/arch/ext/Ziccamoc.yaml b/arch/ext/Ziccamoc.yaml new file mode 100644 index 000000000..373ec4fd6 --- /dev/null +++ b/arch/ext/Ziccamoc.yaml @@ -0,0 +1,19 @@ +# yaml-language-server: $schema=../../schemas/ext_schema.json + +$schema: "ext_schema.json#" +kind: extension +name: Ziccamoc +long_name: Cacheable and coherent PMAs provide `AMOCASQ` level PMA support +description: | + Main memory regions with both the cacheability and coherence PMAs + must provide `AMOCASQ` level PMA support. + + [NOTE] + Ziccamoc is a new RVA23 profile-defined extension that ensures + Compare and Swap instructions are properly supported in main memory + regions. The extension will be added to the PMA section of the + privileged architecture manual. +versions: + - version: "1.0.0" + state: ratified + ratification_date: null diff --git a/arch/ext/Zihintntl.yaml b/arch/ext/Zihintntl.yaml new file mode 100644 index 000000000..8df21228f --- /dev/null +++ b/arch/ext/Zihintntl.yaml @@ -0,0 +1,197 @@ +# yaml-language-server: $schema=../../schemas/ext_schema.json + +$schema: "ext_schema.json#" +kind: extension +name: Zihintntl +long_name: NTL (Non-Temporal Locality) Hint Instructions +description: | + The NTL instructions are HINTs that indicate that the explicit memory + accesses of the immediately subsequent instruction (henceforth "target + instruction") exhibit poor temporal locality of reference. The NTL + instructions do not change architectural state, nor do they alter the + architecturally visible effects of the target instruction. Four variants + are provided: + + The NTL.P1 instruction indicates that the target instruction does not + exhibit temporal locality within the capacity of the innermost level of + private cache in the memory hierarchy. NTL.P1 is encoded as + ADD _x0, x0, x2_. + + The NTL.PALL instruction indicates that the target instruction does not + exhibit temporal locality within the capacity of any level of private + cache in the memory hierarchy. NTL.PALL is encoded as ADD _x0, x0, x3_. + + The NTL.S1 instruction indicates that the target instruction does not + exhibit temporal locality within the capacity of the innermost level of + shared cache in the memory hierarchy. NTL.S1 is encoded as + ADD _x0, x0, x4_. + + The NTL.ALL instruction indicates that the target instruction does not + exhibit temporal locality within the capacity of any level of cache in + the memory hierarchy. NTL.ALL is encoded as ADD _x0, x0, x5_. + + [NOTE] + ==== + The NTL instructions can be used to avoid cache pollution when streaming + data or traversing large data structures, or to reduce latency in + producer-consumer interactions. + + A microarchitecture might use the NTL instructions to inform the cache + replacement policy, or to decide which cache to allocate into, or to + avoid cache allocation altogether. For example, NTL.P1 might indicate + that an implementation should not allocate a line in a private L1 cache, + but should allocate in L2 (whether private or shared). In another + implementation, NTL.P1 might allocate the line in L1, but in the + least-recently used state. + + NTL.ALL will typically inform implementations not to allocate anywhere + in the cache hierarchy. Programmers should use NTL.ALL for accesses that + have no exploitable temporal locality. + + Like any HINTs, these instructions may be freely ignored. Hence, + although they are described in terms of cache-based memory hierarchies, + they do not mandate the provision of caches. + + Some implementations might respect these HINTs for some memory accesses + but not others: e.g., implementations that implement LR/SC by acquiring + a cache line in the exclusive state in L1 might ignore NTL instructions + on LR and SC, but might respect NTL instructions for AMOs and regular + loads and stores. + ==== + + <> lists several software use cases and the recommended NTL variant that _portable_ software—i.e., software not tuned for any specific implementation's memory hierarchy—should use in each case. + + [[ntl-portable]] + .Recommended NTL variant for portable software to employ in various scenarios. + [%autowidth,float="center",align="center",cols="<,<",options="header",] + |=== + |Scenario |Recommended NTL variant + |Access to a working set between and in size |NTL.P1 + |Access to a working set between and in size |NTL.PALL + |Access to a working set greater than in size |NTL.S1 + |Access with no exploitable temporal locality (e.g., streaming) |NTL.ALL + |Access to a contended synchronization variable |NTL.PALL + |=== + + [NOTE] + ==== + The working-set sizes listed in <> are not meant to + constrain implementers' cache-sizing decisions. + Cache sizes will obviously vary between implementations, and so software + writers should only take these working-set sizes as rough guidelines. + ==== + + <> lists several sample memory hierarchies and + recommends how each NTL variant maps onto each cache level. The table + also recommends which NTL variant that implementation-tuned software + should use to avoid allocating in a particular cache level. For example, + for a system with a private L1 and a shared L2, it is recommended that + NTL.P1 and NTL.PALL indicate that temporal locality cannot be exploited + by the L1, and that NTL.S1 and NTL.ALL indicate that temporal locality + cannot be exploited by the L2. Furthermore, software tuned for such a + system should use NTL.P1 to indicate a lack of temporal locality + exploitable by the L1, or should use NTL.ALL indicate a lack of temporal + locality exploitable by the L2. + + If the C extension is provided, compressed variants of these HINTs are + also provided: C.NTL.P1 is encoded as C.ADD _x0, x2_; C.NTL.PALL is + encoded as C.ADD _x0, x3_; C.NTL.S1 is encoded as C.ADD _x0, x4_; and + C.NTL.ALL is encoded as C.ADD _x0, x5_. + + The NTL instructions affect all memory-access instructions except the + cache-management instructions in the Zicbom extension. + + [NOTE] + ==== + As of this writing, there are no other exceptions to this rule, and so + the NTL instructions affect all memory-access instructions defined in + the base ISAs and the A, F, D, Q, C, and V standard extensions, as well + as those defined within the hypervisor extension in Volume II. + + The NTL instructions can affect cache-management operations other than + those in the Zicbom extension. For example, NTL.PALL followed by + CBO.ZERO might indicate that the line should be allocated in L3 and + zeroed, but not allocated in L1 or L2. + ==== + + <<< + + [[ntl]] + [%autowidth,float="center",align="center",cols="<,^,^,^,^,^,^,^,^",options="header"] + .Mapping of NTL variants to various memory hierarchies. + |=== + | Memory hierarchy 4+| Recommended mapping of NTL + + variant to actual cache level 4+| Recommended NTL variant for + + explicit cache management + | + |P1 |PALL |S1 |ALL + |L1 |L2 |L3 |L4/L5 + 9+^| Common Scenarios + | No caches 4+|--- 4+|none + |Private L1 only |L1 |L1 |L1 |L1| ALL |--- |--- |--- + |Private L1; shared L2 |L1 |L1 |L2 |L2 |P1|ALL|---|--- + |Private L1; shared L2/L3 |L1 | L1 | L2 | L3 |P1 |S1 |ALL |--- + |Private L1/L2 |L1 |L2 |L2 |L2 | P1 |ALL |--- |--- + |Private L1/L2; shared L3 |L1 | L2 | L3 | L3 | P1 | PALL| ALL |--- + |Private L1/L2; shared L3/L4 | L1 | L2| L3 | L4 | P1 | PALL | S1 | ALL + 9+^| Uncommon Scenarios + |Private L1/L2/L3; shared L4 | L1 | L3 |L4 |L4 |P1 |P1 |PALL |ALL + |Private L1; shared L2/L3/L4 |L1 | L1 |L2 |L4 |P1 |S1 |ALL |ALL + |Private L1/L2; shared L3/L4/L5 |L1 | L2 | L3 | L5 |P1 | PALL |S1 |ALL + |Private L1/L2/L3; shared L4/L5 |L1 |L3 |L4 |L5 |P1 |P1 |PALL |ALL + |=== + + When an NTL instruction is applied to a prefetch hint in the Zicbop + extension, it indicates that a cache line should be prefetched into a + cache that is _outer_ from the level specified by the NTL. + + [NOTE] + ==== + For example, in a system with a private L1 and shared L2, NTL.P1 + followed by PREFETCH.R might prefetch into L2 with read intent. + + To prefetch into the innermost level of cache, do not prefix the + prefetch instruction with an NTL instruction. + + In some systems, NTL.ALL followed by a prefetch instruction might + prefetch into a cache or prefetch buffer internal to a memory + controller. + ==== + + Software is discouraged from following an NTL instruction with an + instruction that does not explicitly access memory. Nonadherence to this + recommendation might reduce performance but otherwise has no + architecturally visible effect. + + In the event that a trap is taken on the target instruction, + implementations are discouraged from applying the NTL to the first + instruction in the trap handler. Instead, implementations are + recommended to ignore the HINT in this case. + + [NOTE] + ==== + If an interrupt occurs between the execution of an NTL instruction and + its target instruction, execution will normally resume at the target + instruction. That the NTL instruction is not reexecuted does not change + the semantics of the program. + + Some implementations might prefer not to process the NTL instruction + until the target instruction is seen (e.g., so that the NTL can be fused + with the memory access it modifies). Such implementations might + preferentially take the interrupt before the NTL, rather than between + the NTL and the memory access. + ==== + ''' + [NOTE] + ==== + Since the NTL instructions are encoded as ADDs, they can be used within + LR/SC loops without voiding the forward-progress guarantee. But, since + using other loads and stores within an LR/SC loop _does_ void the + forward-progress guarantee, the only reason to use an NTL within such a + loop is to modify the LR or the SC. + ==== +type: unprivileged +versions: + - version: "1.0.0" + state: ratified + ratification_date: null diff --git a/arch/ext/Zimop.yaml b/arch/ext/Zimop.yaml index f67973291..7a6a57180 100644 --- a/arch/ext/Zimop.yaml +++ b/arch/ext/Zimop.yaml @@ -5,10 +5,61 @@ kind: extension name: Zimop long_name: May-be Operations description: | - Instructions that may be operations (MOPs). - MOPs are initially defined to simply write zero to x[rd], but are designed to be redefined by - later extensions to perform some other action. + The "Zimop" extension introduces the concept of + instructions that _may be operations_ (MOPs). MOPs are initially defined to + simply write zero to `x[rd]`, but are designed to be redefined by later + extensions to perform some other action. The Zimop extension defines an encoding space for 40 MOPs. + + [NOTE] + ==== + It is sometimes desirable to define instruction-set extensions whose + instructions, rather than raising illegal-instruction exceptions when the extension is + not implemented, take no useful action (beyond writing `x[rd]`). + For example, programs with control-flow integrity checks can + execute correctly on implementations without the corresponding extension, + provided the checks are simply ignored. Implementing these checks as MOPs + allows the same programs to run on implementations with or without the + corresponding extension. + + Although similar in some respects to HINTs, MOPs cannot be encoded as HINTs, + because unlike HINTs, MOPs are allowed to alter architectural state. + + Because MOPs may be redefined by later extensions, standard software should + not execute a MOP unless it is deliberately targeting an extension that has + redefined that MOP. + ==== + + The Zimop extension defines 32 MOP instructions named MOP.R.__n__, where + __n__ is an integer between 0 and 31, inclusive. + Unless redefined by another extension, these instructions simply write 0 to + `x[rd]`. Their encoding allows future extensions to define them to read `x[rs1]`, + as well as write `x[rd]`. + + The Zimop extension additionally defines 8 MOP instructions named + MOP.RR.__n__, where __n__ is an integer between 0 and 7, inclusive. + Unless redefined by another extension, these instructions simply + write 0 to `x[rd]`. Their encoding allows future extensions to define them to + read `x[rs1]` and `x[rs2]`, as well as write `x[rd]`. + + NOTE: The recommended assembly syntax for MOP.R.__n__ is MOP.R.__n__ rd, rs1, + with any `x`-register specifier being valid for either argument. Similarly for + MOP.RR.__n__, the recommended syntax is MOP.RR.__n__ rd, rs1, rs2. + The extension that redefines a MOP may define an alternate assembly mnemonic. + + NOTE: These MOPs are encoded in the SYSTEM major opcode in part because it is + expected their behavior will be modulated by privileged CSR state. + + NOTE: These MOPs are defined to write zero to `x[rd]`, rather than performing + no operation, to simplify instruction decoding and to allow testing the + presence of features by branching on the zeroness of the result. + + The MOPs defined in the Zimop extension do not carry a syntactic dependency + from `x[rs1]` or `x[rs2]` to `x[rd]`, though an extension that redefines the + MOP may impose such a requirement. + + NOTE: Not carrying a syntactic dependency relieves straightforward + implementations of reading `x[rs1]` and `x[rs2]`. type: unprivileged versions: - version: "1.0.0" diff --git a/arch/ext/Zvfh.yaml b/arch/ext/Zvfh.yaml new file mode 100644 index 000000000..583f86ca6 --- /dev/null +++ b/arch/ext/Zvfh.yaml @@ -0,0 +1,39 @@ +# yaml-language-server: $schema=../../schemas/ext_schema.json + +$schema: "ext_schema.json#" +kind: extension +name: Zvfh +long_name: Vector Extension for Half-Precision Floating-Point +description: | + This extension provides support for vectors of IEEE 754-2008 + binary16 values. + When the Zvfh extension is implemented, all instructions in Sections + <>, <>, + <>, <>, + <>, and <> + become defined when SEW=16. + The EEW=16 floating-point operands of these instructions use the binary16 + format. + + Additionally, conversions between 8-bit integers and binary16 values are + provided. The floating-point-to-integer narrowing conversions + (`vfncvt[.rtz].x[u].f.w`) and integer-to-floating-point + widening conversions (`vfwcvt.f.x[u].v`) become defined when SEW=8. + + The Zvfh extension depends on the Zve32f and Zfhmin extensions. + + [NOTE] + Requiring basic scalar half-precision support makes Zvfh's + vector-scalar instructions substantially more useful. + We considered requiring more complete scalar half-precision support, but we + reasoned that, for many half-precision vector workloads, performing the scalar + computation in single-precision will suffice. +type: unprivileged +versions: + - version: "1.0.0" + state: ratified + ratification_date: null + requires: + allOf: + - Zve32f + - Zfhmin diff --git a/arch/ext/Zvfhmin.yaml b/arch/ext/Zvfhmin.yaml new file mode 100644 index 000000000..36985e525 --- /dev/null +++ b/arch/ext/Zvfhmin.yaml @@ -0,0 +1,21 @@ +# yaml-language-server: $schema=../../schemas/ext_schema.json + +$schema: "ext_schema.json#" +kind: extension +name: Zvfhmin +long_name: Vector Extension for Minimal Half-Precision Floating-Point +description: | + This extension provides minimal support for vectors of IEEE 754-2008 + binary16 values, adding conversions to and from binary32. + When the Zvfhmin extension is implemented, the `vfwcvt.f.f.v` and + `vfncvt.f.f.w` instructions become defined when SEW=16. + The EEW=16 floating-point operands of these instructions use the binary16 + format. + + This extension depends on the Zve32f extension. +type: unprivileged +versions: + - version: "1.0.0" + state: ratified + ratification_date: null + requires: Zve32f diff --git a/arch/ext/Zvknc.yaml b/arch/ext/Zvknc.yaml new file mode 100644 index 000000000..2e9ce11dc --- /dev/null +++ b/arch/ext/Zvknc.yaml @@ -0,0 +1,20 @@ +# yaml-language-server: $schema=../../schemas/ext_schema.json + +$schema: "ext_schema.json#" +kind: extension +name: Zvknc +long_name: NIST Algorithm Suite with carryless multiply +description: | + This extension is shorthand for the following set of other extensions: + + * `Zvkn` + * `Zvbc` + +type: unprivileged +versions: + - version: "1.0.0" + state: ratified + ratification_date: null + implies: + - [Zvkn, "1.0.0"] + - [Zvbc, "1.0.0"] diff --git a/arch/ext/Zvkng.yaml b/arch/ext/Zvkng.yaml new file mode 100644 index 000000000..5cae63706 --- /dev/null +++ b/arch/ext/Zvkng.yaml @@ -0,0 +1,20 @@ +# yaml-language-server: $schema=../../schemas/ext_schema.json + +$schema: "ext_schema.json#" +kind: extension +name: Zvkng +long_name: NIST Algorithm Suite with GCM +description: | + This extension is shorthand for the following set of other extensions: + + * `Zvkn` + * `Zvkg` + +type: unprivileged +versions: + - version: "1.0.0" + state: ratified + ratification_date: null + implies: + - [Zvkn, "1.0.0"] + - [Zvkg, "1.0.0"] diff --git a/arch/ext/Zvksc.yaml b/arch/ext/Zvksc.yaml new file mode 100644 index 000000000..2e272745a --- /dev/null +++ b/arch/ext/Zvksc.yaml @@ -0,0 +1,20 @@ +# yaml-language-server: $schema=../../schemas/ext_schema.json + +$schema: "ext_schema.json#" +kind: extension +name: Zvksc +long_name: ShangMi Algorithm Suite with carryless multiplication +description: | + This extension is shorthand for the following set of other extensions: + + * `Zvks` + * `Zvbc` + +type: unprivileged +versions: + - version: "1.0.0" + state: ratified + ratification_date: null + implies: + - [Zvks, "1.0.0"] + - [Zvbc, "1.0.0"] diff --git a/arch/ext/Zvksg.yaml b/arch/ext/Zvksg.yaml new file mode 100644 index 000000000..4577e0957 --- /dev/null +++ b/arch/ext/Zvksg.yaml @@ -0,0 +1,20 @@ +# yaml-language-server: $schema=../../schemas/ext_schema.json + +$schema: "ext_schema.json#" +kind: extension +name: Zvksg +long_name: ShangMi Algorithm Suite with GCM +description: | + This extension is shorthand for the following set of other extensions: + + * `Zvks` + * `Zvkg` + +type: unprivileged +versions: + - version: "1.0.0" + state: ratified + ratification_date: null + implies: + - [Zvks, "1.0.0"] + - [Zvkg, "1.0.0"] diff --git a/arch/inst/Zcb/c.not.yaml b/arch/inst/Zcb/c.not.yaml index 8841c116a..97df445c6 100644 --- a/arch/inst/Zcb/c.not.yaml +++ b/arch/inst/Zcb/c.not.yaml @@ -6,7 +6,7 @@ name: c.not long_name: Bitwise not, 16-bit encoding description: | This instruction takes a single source/destination operand. - This instruction takes the one’s complement of rd'/rs1' and writes the result to the same register. + This instruction takes the one's complement of rd'/rs1' and writes the result to the same register. definedBy: anyOf: diff --git a/arch/profile/RVA22S64.yaml b/arch/profile/RVA22S64.yaml index 6b558f6b9..e2de79e2a 100644 --- a/arch/profile/RVA22S64.yaml +++ b/arch/profile/RVA22S64.yaml @@ -90,15 +90,12 @@ extensions: Technically, Zk is also a privileged-mode option capturing that Zkr, Zkn, and Zkt are all implemented. However, the Zk rollup is less descriptive than specifying the individual extensions explicitly. - H: + Sha: presence: optional - version: "~> 1.0" + version: "~>1.0" note: | - The following extensions become mandatory when H is implemented: - - * Ssstateen - * Shcounterenw - * Shvstvala - * Shtvala - * Shvstvecd - * Shgatpa + The set of augmented hypervisor extensions: H, Ssstateen, + Shcounterenw, Shvstvala, Shtvala, Shvstvecd, Shvsatpa, Shgatpa. + The Sha extension name was introduced in RVA23/RVB23 and wasn't + in the ratified RVA22 profile but has since been added retroactively + as a documentation-only change (doesn't affect requirements or functionality). diff --git a/arch/profile/RVA23S64.yaml b/arch/profile/RVA23S64.yaml new file mode 100644 index 000000000..2484cafa9 --- /dev/null +++ b/arch/profile/RVA23S64.yaml @@ -0,0 +1,29 @@ +$schema: profile_schema.json# +kind: profile +name: RVA23S64 +marketing_name: RVA23S64 +mode: S +base: 64 +release: { $ref: profile_release/RVA23.yaml# } +introduction: | + The RVA23S64 profile specifies the ISA features available to supervisor-mode + execution environments in 64-bit applications processors. + An ECALL in user mode causes a contained trap to supervisor mode. + An ECALL in supervisor mode causes a requested trap to the execution environment. +extensions: + ######################################################################### + # imported from RVB23U64 + ######################################################################### + $inherits: "profile/RVB23S64.yaml#/extensions" + + ######################################################################### + # MANDATORY extensions in RVA23S64 (that were optional in RVB23S64) + ######################################################################### + + Ssnpm: + presence: mandatory + # Pointer masking, with *senvcfg*.PME supporting, at minimum + + Sha: + presence: mandatory + # collection of Hypervisor extensions diff --git a/arch/profile/RVA23U64.yaml b/arch/profile/RVA23U64.yaml new file mode 100644 index 000000000..00c9206bc --- /dev/null +++ b/arch/profile/RVA23U64.yaml @@ -0,0 +1,64 @@ +$schema: profile_schema.json# +kind: profile +name: RVA23U64 +marketing_name: RVA23U64 +mode: Unpriv +base: 64 +release: { $ref: profile_release/RVA23.yaml# } +introduction: | + The RVA23U64 profile specifies the ISA features available to user-mode + execution environments in 64-bit applications processors. This is the + most important profile within application processors in + terms of the amount of software that targets this profile. +extensions: + ######################################################################### + # imported from RVB23U64 + ######################################################################### + $inherits: "profile/RVB23U64.yaml#/extensions" + $remove: + - Zvkg + - Zvknc + - Zvksc + - Zkn + - Zks + + ######################################################################### + # MANDATORY extensions in RVA23U64 (that were optional in RVB23U64) + ######################################################################### + + Zfhmin: + presence: mandatory + + V: + presence: mandatory + + Zvfhmin: + presence: mandatory + + Zvbb: + presence: mandatory + + Zvkt: + presence: mandatory + + Supm: + presence: mandatory + + #-------------------------------------------- + # Zvbc is an expansion option in RVB23U64 + # (but is not intended to be made mandatory in future RVB Profiles) + # + # It is listed in RVA23U64 as a *development* option, + # as it *is* intended to become mandatory in future RVA Profiles. + #-------------------------------------------- + Zvbc: + presence: + optional: development + + ######################################################################### + # TRANSITORY EXPANSION extensions in RVA23U64 + ######################################################################### + + #-------------------------------------------- + # (there are no Transitory expansion options in RVA23U64) + #-------------------------------------------- diff --git a/arch/profile/RVB23S64.yaml b/arch/profile/RVB23S64.yaml new file mode 100644 index 000000000..404096b7a --- /dev/null +++ b/arch/profile/RVB23S64.yaml @@ -0,0 +1,268 @@ +$schema: profile_schema.json# +kind: profile +name: RVB23S64 +marketing_name: RVB23S64 +mode: S +base: 64 +release: { $ref: profile_release/RVB23.yaml# } +introduction: | + The RVB23S64 profile specifies the ISA features available to supervisor-mode + execution environments in 64-bit applications processors. + An ECALL in user mode causes a contained trap to supervisor mode. + An ECALL in supervisor mode causes a requested trap to the execution environment. +extensions: + ######################################################################### + # imported from RVA22S64 + ######################################################################### + $inherits: "profile/RVA22S64.yaml#/extensions" + + ######################################################################### + # MANDATORY extensions in RVB23 (and RVA23) + ######################################################################### + Zifencei: + presence: mandatory + version: "~>1.0" + note: | + Instruction-Fetch fence instruction. + + Zifencei is mandated as it is the only standard way to support + instruction-cache coherence in RVB23 application processors. + A new instruction-cache coherence mechanism is under development + (tentatively named Zjid), which might be added as an option in the future. + + S: + presence: mandatory + version: "~>1.13" + note: | + Supervisor version 1.13 + + Svnapot: + presence: mandatory + version: "~>1.0" + note: | + NAPOT translation contiguity. + Svnapot is very low cost to provide, so is made mandatory even in RVB. + + Svbare: + presence: mandatory + version: "~>1.0" + note: | + The *satp* mode Bare must be supported + + Sv39: + presence: mandatory + version: "~>1.0" + note: | + Page-Based 39-bit Virtual-Memory System + + Svade: + presence: mandatory + version: "~>1.0" + note: | + A page-fault exception is raised when a page is accessed when A bit = 0 , + or when a page is written when D bit = 0 + + Ssccptr: + presence: mandatory + version: "~>1.0" + note: | + Main memory regions with both the cacheability and coherence PMAs must + support hardware page-table reads + + Sstvecd: + presence: mandatory + version: "~>1.0" + note: | + *stvec*.MODE must be capable of holding the value 0 (Direct). + When *stvec*.MODE=Direct, + *stvec*.BASE must be capable of holding any valid four-byte-aligned address + + Sstvala: + presence: mandatory + version: "~>1.0" + note: | + *stval* must be written with the faulting virtual address for load, store, + and instruction page-fault, access-fault, and misaligned exceptions, + and for breakpoint exceptions other than those caused by execution of + the EBREAK or C.EBREAK instructions. + For virtual-instruction and illegal instruction exceptions, + *stval* must be written with the faulting instruction . + + Sscounterenw: + presence: mandatory + version: "~>1.0" + note: | + For any *hpmcounter* that is not read-only zero, + the corresponding bit in *scounteren* must be writable. + + Svpbmt: + presence: mandatory + version: "~>1.0" + note: | + Page-based memory types + + Svinval: + presence: mandatory + version: "~>1.0" + note: | + Fine-grained address-translation cache invalidation + + Sstc: + presence: mandatory + version: "~>1.0" + note: | + Supervisor-mode timer interrupts. + + NOTE: Sstc was not made mandatory in RVB23S64 as it is a more + disruptive change affecting system-level architecture, and will take + longer for implementations to adopt. It is expected to be made + mandatory in the next profile release. + + Sscofpmf: + presence: mandatory + version: "~>1.0" + note: | + Count overflow and mode-based filtering. + Platforms may choose to mandate the presence of Sscofpmf. + + Ssu64xl: + presence: mandatory + version: "~>1.0" + note: | + *sstatus*.UXL must be capable of holding the value 2 + (that is, UXLEN=64 must be supported) + + ######################################################################### + # OPTIONAL LOCALIZED extensions in RVB23S64 + ######################################################################### + + # there are no Optional Localized extensions in RVB23S64 + + ######################################################################### + # OPTIONAL DEVELOPMENT extensions in RVB23S64 + ######################################################################### + + # there are no Optional Development extensions in RVB23S64 + + ######################################################################### + # OPTIONAL EXPANSION extensions in RVB23S64 (mandatory in RVA23S64) + ######################################################################### + + Ssnpm: + presence: + optional: expansion + version: "~>1.0" + note: | + Pointer masking, with *senvcfg*.PME supporting, at minimum, + settings PMLEN=0 and PMLEN=7 + + Sha: + presence: + optional: expansion + note: | + The set of augmented hypervisor extensions: H, Ssstateen, + Shcounterenw, Shvstvala, Shtvala, Shvstvecd, Shvsatpa, Shgatpa + + # TODO: See https://github.com/riscv-software-src/riscv-unified-db/issues/373 + # __NEED_AN_EXTENSION_NAME_HERE__: + # presence: + # optional: expansion + # version: "~>1.0" + # when: + # allOf: + # - implemented: H + # - implemented: Ssnpm + # note: | + # If the hypervisor extension is implemented + # and pointer masking (Ssnpm) is supported + # then *henvcfg*.PME must support at minimum, settings PMLEN=0 and PMLEN=7 + + ######################################################################### + # OPTIONAL EXPANSION extensions in both RVB23S64 and RVA23S64 + ######################################################################### + + Sv48: + presence: + optional: expansion + version: "~>1.0" + note: | + Page-based 48-bit virtual-memory system + + Sv57: + presence: + optional: expansion + version: "~>1.0" + note: | + Page-based 57-bit virtual-memory system + + Svadu: + presence: + optional: expansion + version: "~>1.0" + note: | + Hardware A/D bit updates + + Zkr: + presence: + optional: expansion + version: "~>1.0" + note: | + Entropy CSR + + NOTE: Technically, Zk is also a privileged-mode option, capturing that + Zkr, Zkn, and Zkt are all implemented. However, the Zk rollup is less + descriptive than specifying the individual extensions explicitly. + + Sdtrig: + presence: + optional: expansion + version: "~>1.0" + note: | + Debug triggers + + Ssstrict: + presence: + optional: expansion + version: "~>1.0" + note: | + No non-conforming extensions are present. + Attempts to execute unimplemented opcodes or access unimplemented CSRs in the + standard or reserved encoding spaces raises an illegal instruction exception + that results in a contained trap to the supervisor-mode trap handler + + NOTE: Ssstrict does not prescribe behavior for the custom encoding spaces or CSRs. + + NOTE: Ssstrict definition applies to the execution environment claiming to be + RVB23-compatible, which must have the hypervisor extension. + That execution environment will take a contained trap to supervisor-mode + (however that trap is implemented, including, but not limited to, + emulation/delegation in the outer execution environment). + Ssstrict (and all the other RVB23 mandates and options) do not apply to + any guest VMs run by a hypervisor. + An RVB23 hypervisor can provide guest VMs that are also RVB23-compatible + but with an expanded set of emulated standard instructions. + An RVB23 hypervisor can also choose to implement guest VMs that are not + RVB23 compatible (for example, only RVA20 or only RVA22) + # that last parenthesized phrase for the RVA23 Profile would change to: + # (for example, lacking H, or only RVA20) + + Svvptc: + presence: + optional: expansion + version: "~>1.0" + note: | + Transitions from invalid to valid PTEs will be visible in bounded time + without an explicit memory-management fence. + + Sspm: + presence: + optional: expansion + version: "~>1.0" + note: | + Supervisor-mode pointer masking, with the supervisor execution environment + providing a means to select PMLEN=0 and PMLEN=7 (at minimum). + +recommendations: + - text: | + Implementations are strongly recommended to raise illegal-instruction + exceptions on attempts to execute unimplemented opcodes. diff --git a/arch/profile/RVB23U64.yaml b/arch/profile/RVB23U64.yaml new file mode 100644 index 000000000..b133ce78a --- /dev/null +++ b/arch/profile/RVB23U64.yaml @@ -0,0 +1,288 @@ +$schema: profile_schema.json# +kind: profile +name: RVB23U64 +marketing_name: RVB23U64 +mode: Unpriv +base: 64 +release: { $ref: profile_release/RVB23.yaml# } +introduction: | + The RVB23U64 profile specifies the ISA features available to user-mode + execution environments in 64-bit applications processors. This is the + most important profile within application processors in + terms of the amount of software that targets this profile. +extensions: + ######################################################################### + # imported from RVA22U64 + ######################################################################### + $inherits: "profile/RVA22U64.yaml#/extensions" + $remove: Za128rs + + ######################################################################### + # MANDATORY extensions in RVB23 (and RVA23) + ######################################################################### + Zihintntl: + presence: mandatory + version: "~>1.0" + note: | + Non-temporal memory-access locality hints + Zicond: + presence: mandatory + version: "~>1.0" + note: | + Integer conditional operations + Zimop: + presence: mandatory + version: "~>1.0" + note: | + May-be operations + Zcmop: + presence: mandatory + version: "~>1.0" + note: | + Commpressed (16-bit) may-be operations + Zcb: + presence: mandatory + version: "~>1.0" + note: | + Additional compressed (16-bit) instructions + Zfa: + presence: mandatory + version: "~>1.0" + note: | + Additional floating-point instructions + Zawrs: + presence: mandatory + version: "~>1.0" + note: | + Wait-on-reservation-set (WRS) instructions + Za64rs: + presence: mandatory + version: "~>1.0" + note: | + Reservation sets are contiguous, naturally aligned, and a maximum of 64 bytes + + ######################################################################### + # OPTIONAL LOCALIZED extensions + ######################################################################### + + #--------------------------------- + # In RVB23 (and RVA23) + #--------------------------------- + Zvkng: + presence: + optional: localized + version: "~>1.0" + note: | + Vector crypto NIST Algorithms with GCM + Zvksg: + presence: + optional: localized + version: "~>1.0" + note: | + Vector crypto Shang-Mi Algorithms with GCM + + #--------------------------------- + # In RVB23 (but not in RVA23) + #--------------------------------- + Zvkg: + presence: + optional: localized + version: "~>1.0" + note: | + Vector GCM/GMAC instructions + + Zvknc: + presence: + optional: localized + version: "~>1.0" + note: | + Vector crypto NIST algorithms with carryless multiply. + To reduce implementation cost, RVB profiles allow this carryless multiply option to + implement GCM efficiently, with GHASH available as a separate option. + # RVA23 does not include Zvknc because it mandates the higher-performing + # but more expensive GHASH options when adding vector crypto. + Zvksc: + presence: + optional: localized + version: "~>1.0" + note: | + Vector crypto Shang-Mi algorithms with carryless multiply. + To reduce implementation cost, RVB profiles allow this carryless multiply option to + implement GCM efficiently, with GHASH available as a separate option. + # RVA23 does not include Zvksc because it mandates the higher-performing + # but more expensive GHASH options when adding vector crypto. + + Zkn: + presence: + optional: localized + version: "~>1.0" + note: | + Scalar crypto NIST algorithms + Zks: + presence: + optional: localized + version: "~>1.0" + note: | + Scalar crypto Shang-Mi algorithms + # RVA23 profiles drop support for the above scalar crypto as an option, as the vector + # extension is now mandatory in RVA23. + # RVB23 profiles do support scalar crypto as an option, as the vector extension is optional in RVB23. + + ######################################################################### + # OPTIONAL DEVELOPMENT extensions in RVB23 + ######################################################################### + # The following are new development options, intended to become mandatory in a later RVB profile: + Zabha: + presence: + optional: development + version: "~>1.0" + note: | + Byte and halfword atomic memory operations + Zacas: + presence: + optional: development + version: "~>1.0" + note: | + Compare-and-Swap instructions + Ziccamoc: + presence: + optional: development + version: "~>1.0" + note: | + Main memory regions with both the cacheability and coherence PMAs + must provide AMOCASQ-level PMA support + Zama16b: + presence: + optional: development + version: "~>1.0" + note: | + Misaligned loads, stores, and AMOs to main memory regions that do not cross + Daaaa naturally aligned 16-byte boundary are atomic + + ######################################################################### + # OPTIONAL EXPANSION extensions in RVB23 + ######################################################################### + + #--------------------------------- + # Optional in RVB23U64 (but Mandatory in RVA23U64) + #--------------------------------- + Zfhmin: + presence: + optional: expansion + version: "~> 1.0" + note: | + Zfhmin is a small extension that adds support to load/store and convert + IEEE 754 half-precision numbers to and from the IEEE 754 single-precision + format. The hardware cost for this extension is low, and mandating the + extension avoids adding an option to the profile. + V: + presence: + optional: expansion + version: "~> 1.0" + note: | + The Vector extension + # Note: it is unclear if other Zve* extensions should also be supported in RVB + Zvfhmin: + presence: + optional: expansion + version: "~>1.0" + note: | + Vector minimal half-precision floating-point + Zvbb: + presence: + optional: expansion + version: "~>1.0" + note: | + Vector basic bit-manipulation instructions + Zvkt: + presence: + optional: expansion + version: "~>1.0" + note: | + Vector basic bit-manipulation instructions + Supm: + presence: + optional: expansion + version: "~>1.0" + note: | + Pointer masking, with the execution environment providing + a means to select PMLEN=0 and PMLEN=7 at minimum + + #-------------------------------------------- + # Expansion options in RVB23 (and also RVA23) + #-------------------------------------------- + Zfh: + presence: + optional: expansion + version: "~>1.0" + note: A future RVB profile might mandate V. + Zbc: + presence: + optional: expansion + version: "~>1.0" + note: Scalar carryless multiplication + Zicfilp: + presence: + optional: expansion + version: "~>1.0" + note: Landing Pads + Zicfiss: + presence: + optional: expansion + version: "~>1.0" + note: Shadow Stack + Zvfh: + presence: + optional: expansion + version: "~>1.0" + note: Vector half-precision floating-point + Zfbfmin: + presence: + optional: expansion + version: "~>1.0" + note: Scalar BF16 conversion instructions + Zvfbfmin: + presence: + optional: expansion + version: "~>1.0" + note: Vector BF16 conversion instructions + Zvfbfwma: + presence: + optional: expansion + version: "~>1.0" + note: Vector BF16 widening mul-add instruction + + #-------------------------------------------- + # Zvbc is an expansion option in RVB23U64 + # (but is not intended to be made mandatory in future RVB Profiles) + # It will be listed in RVA23U64 as a *development* option, + # as it is intended to become mandatory in future RVA Profiles. + #-------------------------------------------- + Zvbc: + presence: + optional: expansion + version: "~>1.0" + note: Vector carryless multiplication + + #-------------------------------------------- + # Ssstrict is an expansion option in RVB2U64 and RVA23U64 + # (but is not intended to be made mandatory in future RVB or RVA Profiles) + #-------------------------------------------- + Ssstrict: + presence: + optional: expansion + version: "~>1.0" + note: | + all opcodes in the Standard and Reserved opcode spaces (SROS), + other than those identified in a Profile as Mandatory or Optional, + cause a trap. + # should the above say "current or subsequent Profile" rather than just "Profile"? + # (where is the official definition of Ssstrict?) + + ######################################################################### + # TRANSITORY EXPANSION extensions in RVB23 + ######################################################################### + + #-------------------------------------------- + # (there are no Transitory expansion options in RVB23) + #-------------------------------------------- diff --git a/arch/profile_class/MockProfileClass.yaml b/arch/profile_class/MockProfileClass.yaml index 6c6355bf3..36da53ffa 100644 --- a/arch/profile_class/MockProfileClass.yaml +++ b/arch/profile_class/MockProfileClass.yaml @@ -1,5 +1,6 @@ $schema: profile_class_schema.json# kind: profile class +processor_kind: Microcontroller name: MockProfileClass marketing_name: Mock Profile Class introduction: Here's the Mock Profile Class introduction. diff --git a/arch/profile_class/RVA.yaml b/arch/profile_class/RVA.yaml index 96791a932..f90ddfe13 100644 --- a/arch/profile_class/RVA.yaml +++ b/arch/profile_class/RVA.yaml @@ -2,6 +2,7 @@ $schema: profile_class_schema.json# kind: profile class +processor_kind: Apps Processor name: RVA marketing_name: RVA introduction: | diff --git a/arch/profile_class/RVB.yaml b/arch/profile_class/RVB.yaml index 9a9517b70..3aa2786fd 100644 --- a/arch/profile_class/RVB.yaml +++ b/arch/profile_class/RVB.yaml @@ -1,5 +1,6 @@ $schema: profile_class_schema.json# kind: profile class +processor_kind: Apps Processor name: RVB marketing_name: RVB introduction: | diff --git a/arch/profile_class/RVI.yaml b/arch/profile_class/RVI.yaml index 7c77a558f..7bcf2aad3 100644 --- a/arch/profile_class/RVI.yaml +++ b/arch/profile_class/RVI.yaml @@ -1,5 +1,6 @@ $schema: profile_class_schema.json# kind: profile class +processor_kind: Generic Unprivileged name: RVI marketing_name: RVI introduction: The RVI profile class documents the initial set of unprivileged instructions. diff --git a/arch/profile_release/RVA23.yaml b/arch/profile_release/RVA23.yaml new file mode 100644 index 000000000..102ad13b3 --- /dev/null +++ b/arch/profile_release/RVA23.yaml @@ -0,0 +1,33 @@ +$schema: profile_schema.json# +kind: profile +name: RVA23 +marketing_name: RVA23 +class: RVA +release: 23 +state: ratified # current status ["ratified", "development"] +ratification_date: "2023-04-03" +# Semantic versions within the release +versions: + - version: "1.0.0" + +introduction: | + This profile release targets 64-bit application processors for markets + requiring a high-degree of binary compatibility between compliant implementations. +description: | + This profile release is intended to be used for 64-bit application + processors running rich OS stacks. Only user-mode and + supervisor-mode profiles are specified in this release. + + NOTE: There is no machine-mode profile currently defined for this release. + A machine-mode profile for application processors would only be used in specifying platforms for + portable machine-mode software. Given the relatively low volume of + portable M-mode software in this domain, the wide variety of potential + M-mode code, and the very specific needs of each type of M-mode + software, we are not specifying individual M-mode ISA requirements in this release. + + NOTE: Only XLEN=64 application processor profiles are currently defined. + It would be possible to also define very similar XLEN=32 variants. + +profiles: + - { $ref: profile/RVA23U64.yaml# } + - { $ref: profile/RVA23S64.yaml# } diff --git a/arch/profile_release/RVB23.yaml b/arch/profile_release/RVB23.yaml new file mode 100644 index 000000000..98e453eac --- /dev/null +++ b/arch/profile_release/RVB23.yaml @@ -0,0 +1,33 @@ +$schema: profile_schema.json# +kind: profile +name: RVB23 +marketing_name: RVB23 +class: RVB +release: 23 +state: ratified # current status ["ratified", "development"] +ratification_date: "2023-04-03" +# Semantic versions within the release +versions: + - version: "1.0.0" + +introduction: | + This profile release targets 64-bit application processors for markets + requiring a high-degree of binary compatibility between compliant implementations. +description: | + This profile release is intended to be used for 64-bit application + processors running rich OS stacks. Only user-mode and + supervisor-mode profiles are specified in this release. + + NOTE: There is no machine-mode profile currently defined for this release. + A machine-mode profile for application processors would only be used in specifying platforms for + portable machine-mode software. Given the relatively low volume of + portable M-mode software in this domain, the wide variety of potential + M-mode code, and the very specific needs of each type of M-mode + software, we are not specifying individual M-mode ISA requirements in this release. + + NOTE: Only XLEN=64 application processor profiles are currently defined. + It would be possible to also define very similar XLEN=32 variants. + +profiles: + - { $ref: profile/RVB23U64.yaml# } + - { $ref: profile/RVB23S64.yaml# } diff --git a/backends/certificate_doc/tasks.rake b/backends/certificate_doc/tasks.rake index df4c6562c..31766c0cd 100644 --- a/backends/certificate_doc/tasks.rake +++ b/backends/certificate_doc/tasks.rake @@ -24,16 +24,29 @@ Dir.glob("#{$root}/arch/certificate_model/*.yaml") do |f| "#{CERT_DOC_DIR}/templates/certificate.adoc.erb", __FILE__ ] do |t| - # TODO: schema validation - base_cert_model = cfg_arch_for("rv#{base}").cert_model(cert_model_name) - raise "No certificate model named '#{cert_model_name}'" if base_cert_model.nil? + puts "UPDATE: Creating bootstrap objects for #{cert_model_name}" - # Ask base certification model to create an in-memory config arch for this model. - # XXX - Add this to profile releases - cfg_arch = base_cert_model.to_cfg_arch + # Create bootstrap ConfiguredArchitecture object which also creates and contains + # a PartialConfig object for the rv32/rv64 configuration. + bootstrap_cfg_arch = cfg_arch_for("rv#{base}") - # Set globals for ERB template. + # Creates CertModel object for every certificate model in the database + # using rv32/rv64 PartialConfig object and then returns named CertModel object. + bootstrap_cert_model = bootstrap_cfg_arch.cert_model(cert_model_name) + raise "No certificate model named '#{cert_model_name}'" if bootstrap_cert_model.nil? + + puts "UPDATE: Creating real objects for #{cert_model_name}" + + # Use bootstrap CertModel to create a ConfiguredArchitecture for this CertModel + # to use instead of the the bootstrap one created based on the rv32/rv64 configuration. + cfg_arch = bootstrap_cert_model.to_cfg_arch + + # Use model-specific ConfiguredArchitecture to create CertModel objects again + # for every certificate model in the database and then return named CertModel object. cert_model = cfg_arch.cert_model(cert_model_name) + + # Set globals for ERB template. + portfolio = cert_model cert_class = cert_model.cert_class portfolio = cert_model portfolio_class = cert_class @@ -44,7 +57,15 @@ Dir.glob("#{$root}/arch/certificate_model/*.yaml") do |f| erb.filename = "#{CERT_DOC_DIR}/templates/certificate.adoc.erb" FileUtils.mkdir_p File.dirname(t.name) - File.write t.name, AsciidocUtils.resolve_links(cfg_arch.find_replace_links(erb.result(binding))) + + # Convert ERB to final ASCIIDOC. Note that this code is broken up into separate function calls + # each with a variable name to aid in running a command-line debugger on this code. + erb_result = erb.result(binding) + erb_result_monospace_converted_to_links = cfg_arch.find_replace_links(erb_result) + erb_result_with_links_added = cfg_arch.find_replace_links(erb_result_monospace_converted_to_links) + erb_result_with_links_resolved = AsciidocUtils.resolve_links(erb_result_with_links_added) + + File.write t.name, erb_result_with_links_resolved puts "Generated adoc source at #{t.name}" end diff --git a/backends/certificate_doc/templates/certificate.adoc.erb b/backends/certificate_doc/templates/certificate.adoc.erb index b37cf7f18..4b695f722 100644 --- a/backends/certificate_doc/templates/certificate.adoc.erb +++ b/backends/certificate_doc/templates/certificate.adoc.erb @@ -15,7 +15,7 @@ // TODO: needs to be changed :imagesoutdir: images -= <%= cert_model.name %> Certification Requirements Document += <%= cert_model.name %> Processor Certification Requirements Document [Preface] == Revision History @@ -58,19 +58,181 @@ CSR field types:: == Introduction +<%= cert_model.introduction %> + <%= cert_class.introduction %> -=== <%= cert_class.name %> Naming Scheme +=== What's a CRD? + +Certification Requirements Documents (CRDs) list requirements an implementation must meet +to obtain an associated RVI (RISC-V International) certificate. +CRDs are developed by the RVI CSC (Certification Steering Committee) organization in collaboration +with the RVI TSC (Technical Steering Committee) organization who creates RISC-V standards. + +The CRDs refer to and augment information provided in existing ratified RVI standards. + +There are a variety of certificates offered by RVI to accomodate the various RVI standards. +There are certificates for processors, non-processor system IP (e.g., IOMMU), +and system platforms (processor + system IP) hardware standards. +There are multiple classes of processor certificates available to accomodate the wide range of +RISC-V implementations from basic microcontrollers to advanced Applications-class processors. + +Each CRD has a list of mandatory behaviors along with a list of optional behaviors. +Note that not all behaviors allowed in RISC-V standards are supported by a particular CRD. + +=== CRD Naming Scheme + +CRDs have the following naming scheme: + + Format: [v] + +Where: + +* Left & right square braces denote optional. +* Less-than & greater-than signs just separate fields (i.e., they aren't present in the CRD name). +* identifies the type of RISC-V standard (processor, non-processor system IP, or platform) along with + any other information required to identify the variant of that standard. +* identifies a particular CRD release +** Format is [.[.]] +** Follows semantic versioning scheme (https://semver.org/) +** The release is updated when certification test changes are made that *could* cause a previously certified + implementation to now fail. + Examples are fixing a test bug, or increasing test coverage, or requiring a new version of a standard + A release of 0 is used for pre-release versions of a CRD and release versions start with 1. +** The release is updated when a CRD increases support for optional behaviors. + Examples are supporting for new optional standards or + supporting additional optional behaviors for standards already in a certificate. +** The release is updated when certification test changes are made that *can't* cause a previously certified + implementation to now fail. + Examples are test changes not designed to increase coverage or fixing a documentation typo. +** If omitted, defaults to v1.0.0 +** Examples: v1, v1.1, v2.3.1, 0.3.4 (pre-release) + +=== CRD Terminology + +.Requirement Types +[%autowidth] +|=== +| Term | Meaning + +| MANDATORY | You have to implement it to get a certificate and the certificate tests will cover it +| OPTIONAL | It's up to you if you implement or not. If you claim to implement it, certificate tests will cover it +| IN-SCOPE | Either MANDATORY or OPTIONAL +| OUT-OF-SCOPE | It's up to you if you implement or not. If you implement it, it won't be certified but make sure you don't mess up anything we are certifying. +| INCOMPATIBLE | If you implement it you won't get a certificate +|=== + +.Glossary +[%autowidth] +|=== +| Term | Meaning + +| CRD | Certification Requirements Document +| N/A | “Not Applicable” +| AKA | “Also Known As” +|=== + +=== Processor CRDs + +There are Processor CRDs for different classes of RISC-V processors. +These documents augment information in the related TSC Profile when available and/or other RVI standards documents +(e.g., Priv and Unpriv ISA manuals). +Only ratified extensions are candidates for certification. +This implies all custom extensions are also OUT-OF-SCOPE. + +==== Processor CRD Naming Scheme -<%= cert_class.naming_scheme %> +Processor CRD names have the following format: -=== <%= cert_class.name %> Class Description + [<-base>] -<%= cert_class.description %> +Where: -=== <%= cert_model.name %> Description +* is MC for Microcontroller Class and AC for Apps-processor Class +* is 3-digit integer defined as follows: +** The hundreds's digit indicates the series +** The ten's digit identifies large differences in mandatory extensions (e.g., V, H) within the series +** The one's digit indentifies small/medium differences in mandatory extensions (e.g., Zicond, PMP) within the series +* is optional and is 32 for RV32I, 64 for RV64I, and 32E for RV32E +** If a CRD supports multiple bases and is omitted in a reference, it applies to all supported bases +** If a CRD only supports one base then is generally omitted -<%= cert_model.description %> +[%autowidth] +|=== +| CRD | TSC Profile | Description + +| MC100-series | TBD | 32/64-bit minimal microcontroller that runs low-level software on an RTOS or bare-metal (no virtual memory) +| MC200-series | TBD | 32/64-bit intermediate microcontroller +| MC300-series | TBD | 32/64-bit advanced microcontroller +| AC100-series | RVB23 | 64-bit Apps-processor running Bespoke rich operating systems (e.g., Yocto Linux) +| AC200-series | RVA23 | 64-bit Apps-processor running standard rich operating systems (e.g., commercial Linux distributions, Android) +|=== + +==== CSR Field Terminology + +.Definition of CSR Fields +[%autowidth] +|=== +| Field Type | Read Value After Writing Illegal Value | Read Value Function Of | Illegal Instruction Exception | Priv ISA Manual Quote + +| WLRL | Any deterministic legal or illegal value | Value before write and illegal value written | Optional +| Implementations are permitted but not required to raise an illegal-instruction exception if an instruction attempts to write a non-supported value to a WLRL field. Implementations can return arbitrary bit patterns on the read of a WLRL field when the last write was of an illegal value, but the value returned should deterministically depend on the illegal written value and the value of the field prior to the write. +| WARL | Any deterministic legal value | Any architectural hart state | Prohibited +| Implementations will not raise an exception on writes of unsupported values to a WARL field. Implementations can return any legal value on the read of a WARL field when the last write was of an illegal value, but the legal value returned should deterministically depend on the illegal written value and the architectural state of the hart. +| WPRI | 0 | Nothing | Not specified +| Some whole read/write fields are reserved for future use. Implementations that do not furnish these fields must make them read-only zero. +|=== + +*WARL (Write Anything, Read Legal)*: + +The Priv ISA requires reads of WARL fields to return some implementation-dependent deterministic legal value +after the field is written with an illegal value. +Certifying such behaviors is expensive and provides low value for a certificate since software can't rely +on a particular behavior from one implementation to another. + +Processor CRDs define writes to WARL fields of illegal values to be OUT-OF-SCOPE unless otherwise stated +(i.e., certification tests will only ever write legal values to WARL fields except for the special cases listed below). +When not OUT-OF-SCOPE, the required behavior is defined as this might be more constrained in implementations than +in the standard. + +The following special cases for WARL are supported when explicitly listed in the corresponding CRD CSR field requirements: + +1. Probing for Field Width + +* Some WARL fields are variable length such as the ASID field in the virtual memory extension. +* Here's the algorithm recommended to discover the ASID width: +** The number of implemented ASID bits, termed ASIDLEN, may be determined by writing one to every bit position in + the ASID field, then reading back the value in the satp CSR to see which bit positions in the ASID field hold a one. +* The RVCP-provided certification materials (certification tests, certification reference models) can map writes of + illegal values to the ASID field to the corresponding read value as long as they are provided the ASIDLEN value + for an implementation. + +2. Probing for Options + +* E.g., Writable misa bits + +3. Allowed values are a function of extension presence and/or their parameters + +* E.g., satp.mode legal write values + +*WLRL (Write Legal, Read Legal)*: + +The Priv ISA requires reads of WLRL fields to return some implementation-dependent deterministic arbitrary value +after the field is written with an illegal value. +Certifying such behaviors is expensive and provides low value for a certificate since software can't rely +on a particular behavior. +Processor CRDs define writes to WLRL fields of illegal values to be OUT-OF-SCOPE unless otherwise stated +(i.e., certification tests will only ever write legal values to WLRL fields). + +*WPRI (Write Preserve, Read Ignore)*: + +The Priv ISA requires reads of WPRI fields to return a value of 0. +Such WPRI fields are always unimplemented by definition. +Certification tests are aware of which fields in the CSRs are WPRI and normally write them with 0 but will +also write them with ~0 (all ones) and ensure that reads return 0 in both cases. +It is OUT-OF-SCOPE for certification tests to write all possible values of WPRI fields +(especially if they are more than just a few bits) and certification tests aren't designed to be comprehensive +verification test suites anyways. === Related Specifications @@ -101,8 +263,8 @@ CSR field types:: <<< == Extensions -Any RISC-V extension not listed in this section is OUT-OF-SCOPE so the <%= cert_model.name %> -certificate doesn't cover its associated behaviors. +Any RISC-V extensions not listed in this section are OUT-OF-SCOPE. +The <%= cert_model.name %> certificate doesn't cover their behaviors. <% ExtensionPresence.presence_types_obj.each do |presence_obj| -%> @@ -199,8 +361,42 @@ None |=== <% end # if table -%> +== Traps + +RISC-V supports both synchronous exceptions and asynchronous interrupts. +TODO: List only traps that exist in this certificate model (currently lists all possible in present extensions). +See https://github.com/riscv-software-src/riscv-unified-db/issues/291 and https://github.com/riscv-software-src/riscv-unified-db/issues/324 +TODO: Show traps per privilege mode + +=== Synchronous Exceptions + +|=== +| `xcause.CODE` CSR Field Value | Name +<% cfg_arch.exception_codes.sort_by{ |code| code.num }.each do |code| -%> +| <%= code.num %> | <%= code.name %> +<% end -%> +|=== + +=== Asynchronous Interrupts + +|=== +| `xcause.CODE` CSR Field Value | Name +<% cfg_arch.interrupt_codes.sort_by{ |code| code.num }.each do |code| -%> +| <%= code.num %> | <%= code.name %> +<% end -%> +|=== + == Instruction Summary +TODO: List only instructions that exist in this certificate model. +Currently lists all possible in present extensions so the I extension is providing both RV32I and RV64I instructions. +See https://github.com/riscv-software-src/riscv-unified-db/issues/291 and https://github.com/riscv-software-src/riscv-unified-db/issues/324 + +<% + insts = cert_model.in_scope_extensions.map { |ext_cert_model| ext_cert_model.instructions }.flatten.uniq + insts.sort_by!(&:name) +-%> + [%autowidth] |=== | Name | Long Name diff --git a/backends/portfolio_doc/templates/family_intro.erb b/backends/portfolio_doc/templates/family_intro.erb deleted file mode 100644 index 837125fb6..000000000 --- a/backends/portfolio_doc/templates/family_intro.erb +++ /dev/null @@ -1,11 +0,0 @@ -== <%= portfolio_class.name %> Introduction - -<%= portfolio_class.introduction %> - -=== <%= portfolio_class.name %> Naming Scheme - -<%= portfolio_class.naming_scheme %> - -=== <%= portfolio_class.name %> Class Description - -<%= portfolio_class.description %> diff --git a/backends/profile_doc/tasks.rake b/backends/profile_doc/tasks.rake index 26f1fb869..b18fc3993 100644 --- a/backends/profile_doc/tasks.rake +++ b/backends/profile_doc/tasks.rake @@ -10,23 +10,25 @@ rule %r{#{$root}/gen/profile_doc/adoc/.*\.adoc} => [ profile_release = cfg_arch_for("_").profile_release(profile_release_name) raise ArgumentError, "No profile release named '#{profile_release_name}'" if profile_release.nil? - # Set globals for ERB template. - profile_class = profile_release.profile_class - portfolio_class = profile_class - portfolio = profile_release - template_path = Pathname.new "#{$root}/backends/profile_doc/templates/profile.adoc.erb" erb = ERB.new(template_path.read, trim_mode: "-") erb.filename = template_path.to_s + # Switch to the generated profile certificate cfg arch and set some variables available to ERB template. cfg_arch = cfg_arch_for("_") - # XXX - Add call to to_cfg_arch() in portfolio instance class. - # But somehow have to merge the multiple portofolios in one profile release to one since - # to_cfg_arch used to provide coloring of fields in CSRs in appendices that apply to all profiles in a release. + # Create empty binding and then specify explicitly which variables the ERB template can access. + def create_empty_binding + binding + end + erb_binding = create_empty_binding + erb_binding.local_variable_set(:cfg_arch, cfg_arch) + erb_binding.local_variable_set(:profile_class, profile_release.profile_class) + erb_binding.local_variable_set(:profile_release, profile_release) + erb_binding.local_variable_set(:portfolio_class, profile_release.profile_class) FileUtils.mkdir_p File.dirname(t.name) - File.write t.name, AsciidocUtils.resolve_links(cfg_arch.find_replace_links(erb.result(binding))) + File.write t.name, AsciidocUtils.resolve_links(cfg_arch.find_replace_links(erb.result(erb_binding))) puts "Generated adoc source at #{t.name}" end diff --git a/backends/profile_doc/templates/profile.adoc.erb b/backends/profile_doc/templates/profile.adoc.erb index 1d24b8a1c..beed6be90 100644 --- a/backends/profile_doc/templates/profile.adoc.erb +++ b/backends/profile_doc/templates/profile.adoc.erb @@ -77,6 +77,7 @@ Copyright <%= profile_release.ratification_date.year %> <% end -%> by <%= profile_class.company.name %>. +<% unless profile_release.contributors.nil? -%> [preface] == Acknowledgements @@ -88,6 +89,7 @@ Contributors to the <%= profile_release.marketing_name %> Profile (in alphabetic We express our gratitude to everyone that contributed to, reviewed or improved this specification through their comments and questions. +<% end # no contributors -%> == RISC-V Profiles @@ -401,7 +403,21 @@ associated implementation-defined parameters. [appendix] == Profile Comparisons -=== Release Comparison +=== <%= profile_class.processor_kind %> Profile Releases + +The <%= profile_class.processor_kind %> processor kind has <%= profile_class.profile_releases_matching_processor_kind.size %> processor +profile releases that reference a total of <%= profile_class.referenced_extensions_matching_processor_kind.size %> extensions. + +.Extension Presence +|=== +| Extension | <%= profile_class.profile_releases_matching_processor_kind.map(&:marketing_name).join(" | ") %> + +<% profile_class.referenced_extensions_matching_processor_kind.sort_by(&:name).each do |ext| -%> +| <%= ext.name %> | <%= profile_class.profile_releases_matching_processor_kind.map { |profile_release| profile_release.extension_presence(ext.name) }.join(" | ") %> +<% end -%> +|=== + +=== <%= profile_class.marketing_name %> Profile Releases The <%= profile_class.marketing_name %> Profile Class has <%= profile_class.profile_releases.size %> releases that reference a total of <%= profile_class.referenced_extensions.size %> extensions. @@ -415,7 +431,7 @@ reference a total of <%= profile_class.referenced_extensions.size %> extensions. <% end -%> |=== -=== Profile Comparison +=== <%= profile_release.marketing_name %> Profiles The <%= profile_release.marketing_name %> Profile Release has <%= profile_release.profiles.size %> profiles that reference a total of <%= profile_release.referenced_extensions.size %> extensions. @@ -455,7 +471,7 @@ Extensions present in a profile are also present in higher-privileged profiles i <%= v.canonical_version %>:: State::: <%= v.state %> - <% if v.state == "ratified" -%> + <% if v.state == "ratified" && !v.ratification_date.nil? -%> Ratification date::: <%= v.ratification_date %> <% end # if %> diff --git a/cert_flow.txt b/cert_flow.txt new file mode 100644 index 000000000..20d4be77a --- /dev/null +++ b/cert_flow.txt @@ -0,0 +1,82 @@ +backends/certificate_doc/tasks.rake +bootstrap_cfg_arch = cfg_arch_for("rv#{base}") # rv32 or rv64 + Rakefile + Calls ConfiguredArchitecture.new("gen/resolved_arch/rv32") + Calls Architecture.new # Parent class + Calls Config.create("cfgs/rv32/cfg.yaml") # Factory class method + Loads config yaml file into @data # File specifies if fully, partially, or unconfigured + Calls PartialConfig.new(cfg path, @data) # Uses Ruby send() method + @mxlen = @data["params"].xlen + @name = "rv32" +bootstrap_cert_model = bootstrap_cfg_arch.cert_model(cert_model_name = "MC100-32") + Calls self.generate_obj_methods("cert_model", "certificate_model", CertModel) in Architecture # Magic + Calls define_method("cert_model") + Calls define_method("cert_models") + Creates @cert_models array and @cert_model_hash # Per arch_dir + For every certificiate model in the database + Loads yaml under gen/resolved_arch/rv32 into @cert_models hash + Calls cert_model.new() -> DatabaseObject.initialize(yaml, yaml_path, arch=base_cfg_arch) + @data = yaml + @arch = arch # rv32 +cfg_arch = bootstrap_cert_model.to_cfg_arch # In Portfolio class + Creates hash with mandatory extensions (with version requirement) and fully-constrained params (single_value?) + Uses in_scope_ext_reqs() and all_in_scope_ext_params() in Portfolio + Writes hash to yaml file in /tmp/.../MC100-32/cfg.yaml + Passes yaml file to ConfiguredArchitecture.new() + Creates Architecture (base class), Config, and PartialConfig again (see above) +cert_model = cfg_arch.cert_model(cert_model_name) + Creates CertModel for every model in the database and stores it in the real ConfiguredArchitecture object +Calls ERB template +Converts ERB result to ASCIIDOC + + +============================================================================================== +Actual rv32/cfg.yaml +--- +$schema: config_schema.json# +kind: architecture configuration +type: partially configured +name: rv32 +description: A generic RV32 system; only MXLEN is known +params: + XLEN: 32 +mandatory_extensions: + - name: "I" + version: ">= 0" + - name: "Sm" + version: ">= 0" +=============================================================================================== +Bootstrap /tmp/.../MC100-32/cfg.yaml +--- +"$schema": config_schema.json +type: partially configured +kind: architecture configuration +name: MC100-32 +description: A partially configured architecture definition corresponding to the MC100-32 + portfolio. +mandatory_extensions: +- name: I + version: + - "~> 2.1" +- name: C + version: + - "~> 2.2" +- name: M + version: + - "~> 2.0" +- name: Zicsr + version: + - "~> 2.0" +- name: Zicntr + version: + - "~> 2.0" +- name: Sm + version: + - "~> 1.11.0" +params: + MISALIGNED_SPLIT_STRATEGY: by_byte + PRECISE_SYNCHRONOUS_EXCEPTIONS: true + TRAP_ON_ECALL_FROM_M: true + TRAP_ON_EBREAK: true + M_MODE_ENDIANESS: little + XLEN: 32 diff --git a/lib/arch_obj_models/certificate.rb b/lib/arch_obj_models/certificate.rb index 80856b6f3..68d8a47cf 100644 --- a/lib/arch_obj_models/certificate.rb +++ b/lib/arch_obj_models/certificate.rb @@ -19,7 +19,25 @@ def mandatory_priv_modes = @data["mandatory_priv_modes"] # Holds information about a certificate model YAML file. # The inherited "data" member is the database of extensions, instructions, CSRs, etc. -class CertModel < PortfolioInstance +class CertModel < Portfolio + # @param obj_yaml [Hash] Contains contents of Certificate Model yaml file (put in @data) + # @param data_path [String] Path to yaml file + # @param cfg_arch [ConfiguredArchitecture] Architecture for a specific configuration + def initialize(obj_yaml, yaml_path, arch: nil) + super # Calls parent class with the same args I got + + # TODO: XXX: Don't allow Architecture class. + # See https://github.com/riscv-software-src/riscv-unified-db/pull/371 + unless arch.is_a?(ConfiguredArchitecture) || arch.is_a?(Architecture) + raise ArgumentError, "For #{name} arch is a #{arch.class} but must be a ConfiguredArchitecture" + end + + # TODO: XXX: Add back in arch.name. + # See https://github.com/riscv-software-src/riscv-unified-db/pull/371 + #puts "UPDATE: Creating CertModel object for #{name} using cfg #{cfg_arch.name}" + puts "UPDATE: Creating CertModel object for #{name}" + end + def unpriv_isa_manual_revision = @data["unpriv_isa_manual_revision"] def priv_isa_manual_revision = @data["priv_isa_manual_revision"] def debug_manual_revision = @data["debug_manual_revision"] diff --git a/lib/arch_obj_models/csr.rb b/lib/arch_obj_models/csr.rb index 2d8a84166..38bbc99e5 100644 --- a/lib/arch_obj_models/csr.rb +++ b/lib/arch_obj_models/csr.rb @@ -3,7 +3,7 @@ require_relative "obj" # CSR definition -class Csr < DatabaseObjectect +class Csr < DatabaseObject def ==(other) if other.is_a?(Csr) name == other.name @@ -56,7 +56,7 @@ def format_changes_with_xlen?(cfg_arch) end # @param cfg_arch [ConfiguredArchitecture] A configuration - # @return [Array] List of functions reachable from this CSR's sw_read or a field's sw_wirte function + # @return [Array] List of functions reachable from this CSR's sw_read or a field's sw_write function def reachable_functions(cfg_arch) return @reachable_functions unless @reachable_functions.nil? diff --git a/lib/arch_obj_models/csr_field.rb b/lib/arch_obj_models/csr_field.rb index af4a73e0c..df4b53261 100644 --- a/lib/arch_obj_models/csr_field.rb +++ b/lib/arch_obj_models/csr_field.rb @@ -5,7 +5,7 @@ require_relative "../idl/passes/gen_option_adoc" # A CSR field object -class CsrField < DatabaseObjectect +class CsrField < DatabaseObject # @return [Csr] The Csr that defines this field attr_reader :parent diff --git a/lib/arch_obj_models/extension.rb b/lib/arch_obj_models/extension.rb index ec327a9ab..120154da7 100644 --- a/lib/arch_obj_models/extension.rb +++ b/lib/arch_obj_models/extension.rb @@ -6,8 +6,8 @@ # A parameter (AKA option, AKA implementation-defined value) supported by an extension class ExtensionParameter - # @return [ConfiguredArchitecture] The defining configured architecture - attr_reader :cfg_arch + # @return [Architecture] The defining architecture + attr_reader :arch # @return [String] Parameter name attr_reader :name @@ -36,8 +36,11 @@ def schema_type @schema.to_pretty_s end + # @param ext [Extension] + # @param name [String] + # @param data [Hash] Array of extensions implied by any version of this extension meeting version_requirement def implies(version_requirement = nil) if version_requirement.nil? - return [] unless ExtensionRequirement.new(@new, cfg_arch: @cfg_arch).satisfied_by?(max_version.version) + return [] unless ExtensionRequirement.new(@new, arch: @arch).satisfied_by?(max_version.version) else - return [] unless ExtensionRequirement.new(@new, version_requirement, cfg_arch: @cfg_arch).satisfied_by?(max_version.version) + return [] unless ExtensionRequirement.new(@new, version_requirement, arch: @arch).satisfied_by?(max_version.version) end max_version.implications @@ -208,15 +208,15 @@ def conflicts return [] if @data["conflicts"].nil? if @data["conflicts"].is_a?(String) - [ExtensionRequirement.new(@data["conflicts"], cfg_arch: @cfg_arch)] + [ExtensionRequirement.new(@data["conflicts"], arch: @arch)] elsif @data["conflicts"].is_a?(Hash) - [ExtensionRequirement.new(@data["conflicts"]["name"], @data["conflicts"]["version"], cfg_arch: @cfg_arch)] + [ExtensionRequirement.new(@data["conflicts"]["name"], @data["conflicts"]["version"], arch: @arch)] elsif @data["conflicts"].is_a?(Array) @data["conflicts"].map do |conflict| if conflict.is_a?(String) - ExtensionRequirement.new(conflict, cfg_arch: @cfg_arch) + ExtensionRequirement.new(conflict, arch: @arch) elsif conflict.is_a?(Array) - ExtensionRequirement.new(conflict["name"], conflict["version"], cfg_arch: @cfg_arch) + ExtensionRequirement.new(conflict["name"], conflict["version"], arch: @arch) else raise "Invalid conflicts data: #{conflict.inspect}" end @@ -230,14 +230,14 @@ def conflicts def instructions return @instructions unless @instructions.nil? - @instructions = cfg_arch.instructions.select { |i| versions.any? { |v| i.defined_by?(v) }} + @instructions = arch.instructions.select { |i| versions.any? { |v| i.defined_by?(v) }} end # @return [Array] the list of CSRs implemented by *any version* of this extension (may be empty) def csrs return @csrs unless @csrs.nil? - @csrs = cfg_arch.csrs.select { |csr| versions.any? { |v| csr.defined_by?(v) } } + @csrs = arch.csrs.select { |csr| versions.any? { |v| csr.defined_by?(v) } } end # return the set of reachable functions from any of this extensions's CSRs or instructions in the given evaluation context @@ -258,6 +258,8 @@ def reachable_functions(symtab) funcs += inst.reachable_functions(symtab, 64) if inst.defined_in_base?(64) end + # The one place in this file that needs a ConfiguredArchitecture object instead of just Architecture. + raise "In #{name}, need to provide ConfiguredArchitecture" if cfg_arch.nil? csrs.each do |csr| funcs += csr.reachable_functions(cfg_arch) end @@ -282,25 +284,24 @@ class ExtensionVersion # @param name [#to_s] The extension name # @param version [String] The version specifier - # @param cfg_arch [ConfiguredArchitecture] The architecture definition - def initialize(name, version_str, cfg_arch, fail_if_version_does_not_exist: false) + # @param arch [Architecture] The architecture definition + def initialize(name, version_str, arch, fail_if_version_does_not_exist: false) @name = name.to_s @version_str = version_str @version_spec = VersionSpec.new(version_str) - raise ArgumentError, "Must supply arch" if cfg_arch.nil? - - @cfg_arch = cfg_arch + raise ArgumentError, "Must supply arch" if arch.nil? + @arch = arch - @ext = @cfg_arch.extension(@name) - raise "Extension #{name} not found in configured architecture #{cfg_arch.name}" if @ext.nil? + @ext = @arch.extension(@name) + raise "Extension #{name} not found in architecture" if @ext.nil? @data = @ext.data["versions"].find { |v| VersionSpec.new(v["version"]) == @version_spec } if fail_if_version_does_not_exist && @data.nil? - raise ArgumentError, "Version #{version_str} of #{@name} extension in #{cfg_arch.name} is not defined" + raise ArgumentError, "Version #{version_str} of #{@name} extension is not defined" elsif @data.nil? - warn "Version #{version_str} of #{@name} extension in #{cfg_arch.name} is not defined" + warn "Version #{version_str} of #{@name} extension is not defined" end end @@ -391,14 +392,14 @@ def requirement_condition when nil AlwaysTrueSchemaCondition.new when Hash - SchemaCondition.new(@data["requires"], @cfg_arch) + SchemaCondition.new(@data["requires"], @arch) else - SchemaCondition.new({ "oneOf" => [@data["requires"]] }, @cfg_arch) + SchemaCondition.new({ "oneOf" => [@data["requires"]] }, @arch) end if @data.key?("implies") rs = [r] + implications.map(&:requirement_condition) rs = rs.reject(&:empty?) - r = SchemaCondition.all_of(*rs.map(&:to_h), cfg_arch: @cfg_arch) unless rs.empty? + r = SchemaCondition.all_of(*rs.map(&:to_h), arch: @arch) unless rs.empty? end r end @@ -439,9 +440,9 @@ def implications return @implications when Array if @data["implies"][0].is_a?(Array) - @implications.concat(@data["implies"].map { |e| ExtensionVersion.new(e[0], e[1], @cfg_arch) }) + @implications.concat(@data["implies"].map { |e| ExtensionVersion.new(e[0], e[1], @arch) }) else - @implications << ExtensionVersion.new(@data["implies"][0], @data["implies"][1], @cfg_arch) + @implications << ExtensionVersion.new(@data["implies"][0], @data["implies"][1], @arch) end end @implications.sort! @@ -460,14 +461,14 @@ def transitive_implications return @transitive_implications when Array if @data["implies"][0].is_a?(Array) - impls = @data["implies"].map { |e| ExtensionVersion.new(e[0], e[1], @cfg_arch) } + impls = @data["implies"].map { |e| ExtensionVersion.new(e[0], e[1], @arch) } @transitive_implications.concat(impls) impls.each do |i| transitive_impls = i.implications @transitive_implications.concat(transitive_impls) unless transitive_impls.empty? end else - impl = ExtensionVersion.new(@data["implies"][0], @data["implies"][1], @cfg_arch) + impl = ExtensionVersion.new(@data["implies"][0], @data["implies"][1], @arch) @transitive_implications << impl transitive_impls = impl.implications @transitive_implications.concat(transitive_impls) unless transitive_impls.empty? @@ -502,9 +503,7 @@ def <=>(other) def implemented_csrs return @implemented_csrs unless @implemented_csrs.nil? - raise "implemented_csrs needs an cfg_arch" if @cfg_arch.nil? - - @implemented_csrs = @cfg_arch.csrs.select do |csr| + @implemented_csrs = @arch.csrs.select do |csr| csr.defined_by?(self) end end @@ -513,9 +512,7 @@ def implemented_csrs def implemented_instructions return @implemented_instructions unless @implemented_instructions.nil? - raise "implemented_instructions needs an cfg_arch" if @cfg_arch.nil? - - @implemented_instructions = @cfg_arch.instructions.select do |inst| + @implemented_instructions = @arch.instructions.select do |inst| inst.defined_by?(self) end end @@ -694,22 +691,23 @@ def to_s def extension return @extension unless @extension.nil? - raise "Cannot get extension; cfg_arch was not initialized" if @cfg_arch.nil? + raise "Cannot get extension; arch was not initialized" if @arch.nil? - @extension = @cfg_arch.extension(@name) + @extension = @arch.extension(@name) end # @param name [#to_s] Extension name # @param requirements [String] Single requirement # @param requirements [Array] List of requirements, all of which must hold - def initialize(name, *requirements, cfg_arch: nil, note: nil, req_id: nil, presence: nil) - raise ArgumentError, "Arch is required" if cfg_arch.nil? + # @param arch [Architecture] + def initialize(name, *requirements, arch: nil, note: nil, req_id: nil, presence: nil) + raise ArgumentError, "For #{name}, arch not allowed to be nil" if arch.nil? + raise ArgumentError, "For #{name}, Architecture is required" unless arch.is_a?(Architecture) @name = name.to_s.freeze - @cfg_arch = cfg_arch - @ext = @cfg_arch.extension(@name) - - raise ArgumentError, "Could not find extension named '#{@name}' in #{@cfg_arch.name}" if @ext.nil? + @arch = arch + @ext = @arch.extension(@name) + raise ArgumentError, "Could not find extension named '#{@name}'" if @ext.nil? requirements = if requirements.empty? @@ -724,12 +722,12 @@ def initialize(name, *requirements, cfg_arch: nil, note: nil, req_id: nil, prese @presence = presence.freeze end - # @return [Array] The list of extension versions that satisfy this requirement + # @return [Array] The list of extension versions that satisfy this extension requirement def satisfying_versions - ext = @cfg_arch.extension(@name) + ext = @arch.extension(@name) return [] if ext.nil? - ext.versions.select { |v| @requirements.all? { |r| r.satisfied_by?(v.version_spec, ext) } } + ext.versions.select { |v| satisfied_by?(v) } end # @overload @@ -773,7 +771,7 @@ def satisfied_by?(*args) # @return [Array] List of CSRs defined by any extension satisfying this requirement def csrs - @csrs ||= @cfg_arch.csrs.select do |csr| + @csrs ||= @arch.csrs.select do |csr| satisfying_versions.any? do |ext_ver| csr.defined_by?(ext_ver) end diff --git a/lib/arch_obj_models/instruction.rb b/lib/arch_obj_models/instruction.rb index 175406e52..077a60f6c 100644 --- a/lib/arch_obj_models/instruction.rb +++ b/lib/arch_obj_models/instruction.rb @@ -6,7 +6,7 @@ # model of a specific instruction in a specific base (RV32/RV64) -class Instruction < DatabaseObjectect +class Instruction < DatabaseObject def self.ary_from_location(location_str_or_int) return [location_str_or_int] if location_str_or_int.is_a?(Integer) diff --git a/lib/arch_obj_models/manual.rb b/lib/arch_obj_models/manual.rb index 0a276c5f6..396cb041d 100644 --- a/lib/arch_obj_models/manual.rb +++ b/lib/arch_obj_models/manual.rb @@ -4,16 +4,11 @@ require_relative "obj" -class Manual < DatabaseObjectect +class Manual < DatabaseObject def versions return @versions unless @versions.nil? - @versions = - if @cfg_arch.nil? - @specification.manual_versions.select { |mv| mv.manual == self } - else - @cfg_arch.manual_versions.select { |mv| mv.manual == self } - end + @versions = @arch.manual_versions.select { |mv| mv.manual == self } end def version(name) @@ -121,17 +116,12 @@ def repo_path=(path) end end -class ManualVersion < DatabaseObjectect +class ManualVersion < DatabaseObject # @return [Manual] The manual this version belongs to def manual return @manual unless @manual.nil? - @manual = - if @cfg_arch.nil? - @specification.ref(@data["manual"]["$ref"]) - else - @cfg_arch.ref(@data["manual"]["$ref"]) - end + @manual = @arch.ref(@data["manual"]["$ref"]) raise "Error: manual #{@data['manual']['$ref']} is not found" if @manual.nil? @manual diff --git a/lib/arch_obj_models/obj.rb b/lib/arch_obj_models/obj.rb index 459d4b769..d26cff70d 100644 --- a/lib/arch_obj_models/obj.rb +++ b/lib/arch_obj_models/obj.rb @@ -11,7 +11,7 @@ # ... # } # -# obj = DatabaseObjectect.new(data) +# obj = DatabaseObject.new(data) # obj['name'] # 'mstatus' # obj['address'] # 0x320 # @@ -24,7 +24,7 @@ # Subclasses may override the accessors when a more complex data structure # is warranted, e.g., the CSR Field 'alias' returns a CsrFieldAlias object # instead of a simple string -class DatabaseObjectect +class DatabaseObject # Exception raised when there is a problem with a schema file class SchemaError < ::StandardError # result from JsonSchemer.validate @@ -90,11 +90,16 @@ def initialize(path, result) end end - attr_reader :data, :data_path, :specification, :cfg_arch, :name, :long_name, :description + attr_reader :data, :data_path, :name, :long_name, :description # @return [Architecture] If only a specification (no config) is known # @return [ConfiguredArchitecture] If a specification and config is known - attr_reader :arch + # @return [nil] If neither is known + attr_reader :arch # Use when Architecture class is sufficient + + # @return [ConfiguredArchitecture] If a specification and config is known + # @return [nil] Otherwise + attr_reader :cfg_arch # Use when extra stuff provided by ConfiguredArchitecture is required def kind = @data["kind"] @@ -151,11 +156,11 @@ def validate end end - # clone this, and set the cfg_arch at the same time + # clone this, and set the arch at the same time # @return [ExtensionRequirement] The new object - def clone(cfg_arch: nil) + def clone(arch: nil) obj = super() - obj.instance_variable_set(:@cfg_arch, cfg_arch) + obj.instance_variable_set(:@arch, arch) obj end @@ -182,15 +187,12 @@ def definedBy # @param data [Hash] Hash with fields to be added # @param data_path [Pathname] Path to the data file def initialize(data, data_path, arch: nil) - raise "Bad data" unless data.is_a?(Hash) + raise ArgumentError, "Bad data" unless data.is_a?(Hash) @data = data @data_path = data_path if arch.is_a?(ConfiguredArchitecture) @cfg_arch = arch - @specification = arch - elsif arch.is_a?(Architecture) - @specification = arch end @arch = arch @name = data["name"] @@ -206,7 +208,7 @@ def inspect extend Forwardable def_delegator :@data, :[] - # @return [Array] List of keys added by this DatabaseObjectect + # @return [Array] List of keys added by this DatabaseObject def keys = @data.keys # @param k (see Hash#key?) @@ -230,7 +232,7 @@ def defined_by?(*args) raise ArgumentError, "First parameter must be an extension name" unless args[0].respond_to?(:to_s) raise ArgumentError, "First parameter must be an extension version" unless args[1].respond_to?(:to_s) - ExtensionVersion.new(args[0], args[1], cfg_arch) + ExtensionVersion.new(args[0], args[1], arch) else raise ArgumentError, "Unsupported number of arguments (#{args.size})" end @@ -243,7 +245,7 @@ def defined_by?(*args) # def defined_by # raise "ERROR: definedBy is nul for #{name}" if @data["definedBy"].nil? - # SchemaCondition.new(@data["definedBy"], @cfg_arch).satisfying_ext_versions + # SchemaCondition.new(@data["definedBy"], @arch).satisfying_ext_versions # end # @return [SchemaCondition] Extension(s) that define the instruction. If *any* requirement is met, the instruction is defined. @@ -252,7 +254,7 @@ def defined_by_condition begin raise "ERROR: definedBy is nul for #{name}" if @data["definedBy"].nil? - SchemaCondition.new(@data["definedBy"], @cfg_arch) + SchemaCondition.new(@data["definedBy"], @arch) end end @@ -384,7 +386,7 @@ def <=>(other) # class SchemaCondition # @param composition_hash [Hash] A possibly recursive hash of "allOf", "anyOf", "oneOf" - def initialize(composition_hash, cfg_arch) + def initialize(composition_hash, arch) raise ArgumentError, "composition_hash is nil" if composition_hash.nil? unless is_a_condition?(composition_hash) @@ -392,7 +394,7 @@ def initialize(composition_hash, cfg_arch) end @hsh = composition_hash - @cfg_arch = cfg_arch + @arch = arch end def to_h = @hsh @@ -467,13 +469,13 @@ def is_a_condition?(hsh) def first_requirement(req = @hsh) case req when String - ExtensionRequirement.new(req, cfg_arch: @cfg_arch) + ExtensionRequirement.new(req, arch: @arch) when Hash if req.key?("name") if req["version"].nil? - ExtensionRequirement.new(req["name"], cfg_arch: @cfg_arch) + ExtensionRequirement.new(req["name"], arch: @arch) else - ExtensionRequirement.new(req["name"], req["version"], cfg_arch: @cfg_arch) + ExtensionRequirement.new(req["name"], req["version"], arch: @arch) end else first_requirement(req[req.keys[0]]) @@ -486,12 +488,12 @@ def first_requirement(req = @hsh) end # combine all conds into one using AND - def self.all_of(*conds, cfg_arch:) + def self.all_of(*conds, arch:) cond = SchemaCondition.new({ "allOf" => conds - }, cfg_arch) + }, arch) - SchemaCondition.new(cond.minimize, cfg_arch) + SchemaCondition.new(cond.minimize, arch) end # @return [Object] Schema for this condition, with basic logic minimization @@ -529,14 +531,14 @@ def to_rb_helper(hsh) if hsh.key?("name") if hsh.key?("version") if hsh["version"].is_a?(String) - "(yield ExtensionRequirement.new('#{hsh["name"]}', '#{hsh["version"]}', cfg_arch: @cfg_arch))" + "(yield ExtensionRequirement.new('#{hsh["name"]}', '#{hsh["version"]}', arch: @arch))" elsif hsh["version"].is_a?(Array) - "(yield ExtensionRequirement.new('#{hsh["name"]}', #{hsh["version"].map { |v| "'#{v}'" }.join(', ')}, cfg_arch: @cfg_arch))" + "(yield ExtensionRequirement.new('#{hsh["name"]}', #{hsh["version"].map { |v| "'#{v}'" }.join(', ')}, arch: @arch))" else raise "unexpected" end else - "(yield ExtensionRequirement.new('#{hsh["name"]}', cfg_arch: @cfg_arch))" + "(yield ExtensionRequirement.new('#{hsh["name"]}', arch: @arch))" end else key = hsh.keys[0] @@ -557,7 +559,7 @@ def to_rb_helper(hsh) end end else - "(yield ExtensionRequirement.new('#{hsh}', cfg_arch: @cfg_arch))" + "(yield ExtensionRequirement.new('#{hsh}', arch: @arch))" end end @@ -598,7 +600,7 @@ def satisfied_by?(&block) def satisfying_ext_versions list = [] - cfg_arch.extensions.each do |ext| + arch.extensions.each do |ext| ext.versions.each do |ext_ver| list << ext_ver if satisfied_by? { |ext_req| ext_req.satisfied_by?(ext_ver) } end diff --git a/lib/arch_obj_models/portfolio.rb b/lib/arch_obj_models/portfolio.rb index cab00be8f..5c5747f20 100644 --- a/lib/arch_obj_models/portfolio.rb +++ b/lib/arch_obj_models/portfolio.rb @@ -1,13 +1,13 @@ -# Classes for Porfolios which form a common base class for profiles and certificates. +# Classes for Portfolios which form a common base class for profiles and certificates. # A "Portfolio" is a named & versioned grouping of extensions (each with a name and version). -# Each Portfolio Instance is a member of a Portfolio Class: -# RVA20U64 and MC100 are examples of portfolio instances +# Each Portfolio is a member of a Portfolio Class: +# RVA20U64 and MC100 are examples of portfolios # RVA and MC are examples of portfolio classes # -# Many classes inherit from the DatabaseObjectect class. This provides facilities for accessing the contents of a -# Portfolio Class YAML or Portfolio Model YAML file via the "data" member (hash holding related YAML file contents). +# Many classes inherit from the DatabaseObject class. This provides facilities for accessing the contents of a +# Portfolio Class YAML or Portfolio Model YAML file via the "data" member (hash holding releated YAML file contents). # -# A variable name with a "_data" suffix indicates it is the raw hash data from the porfolio YAML file. +# A variable name with a "_data" suffix indicates it is the raw hash data from the portfolio YAML file. require "tmpdir" @@ -20,33 +20,49 @@ # Holds information from Portfolio class YAML file (certificate class or profile class). # The inherited "data" member is the database of extensions, instructions, CSRs, etc. -class PortfolioClass < DatabaseObjectect - # @return [ConfiguredArchitecture] The defining ConfiguredArchitecture - attr_reader :cfg_arch +class PortfolioClass < DatabaseObject + # @return [String] What kind of processor portfolio is this? + def processor_kind = @data["processor_kind"] + # @return [String] Small enough (~1 paragraph) to be suitable immediately after a higher-level heading. def introduction = @data["introduction"] - def naming_scheme = @data["naming_scheme"] + + # @return [String] Large enough to need its own heading (generally one level deeper than the "introduction"). def description = @data["description"] # Returns true if other is the same class (not a derived class) and has the same name. def eql?(other) other.instance_of?(self.class) && other.name == name end + + # @return [Array] Contains contents of Portfolio yaml file (put in @data) + # @param data_path [String] Path to yaml file + # @param arch [Architecture] Entire database of RISC-V architecture standards + def initialize(obj_yaml, yaml_path, arch: nil) + super # Calls parent class with same args I got + end + # @return [String] Small enough (~1 paragraph) to be suitable immediately after a higher-level heading. + def introduction = @data["introduction"] + + # @return [String] Large enough to need its own heading (generally one level deeper than the "introduction"). def description = @data["description"] - # @return [Gem::Version] Semantic version of the PortfolioInstance + # @return [Gem::Version] Semantic version of the Portfolio def version = Gem::Version.new(@data["version"]) # @return [ExtensionPresence] Given an extension +ext_name+, return the presence. @@ -107,6 +123,10 @@ def extension_note(ext_name) return ext_data["note"] unless ext_data.nil? end + def mandatory_ext_reqs = in_scope_ext_reqs(ExtensionPresence.mandatory) + def optional_ext_reqs = in_scope_ext_reqs(ExtensionPresence.optional) + def optional_type_ext_reqs = in_scope_ext_reqs(ExtensionPresence.optional) + # @param desired_presence [String, Hash, ExtensionPresence] # @return [Array] - # Extensions with their portfolio information. # If desired_presence is provided, only returns extensions with that presence. @@ -128,68 +148,66 @@ def in_scope_ext_reqs(desired_presence = nil) # Does extension even exist? # If not, don't raise an error right away so we can find all of the missing extensions and report them all. - ext = cfg_arch.extension(ext_name) + ext = arch.extension(ext_name) if ext.nil? puts "Extension #{ext_name} for #{name} not found in database" missing_ext = true - end - - actual_presence = ext_data["presence"] # Could be a String or Hash - raise "Missing extension presence for extension #{ext_name}" if actual_presence.nil? - - # Convert presence String or Hash to object. - actual_presence_obj = ExtensionPresence.new(actual_presence) + else + actual_presence = ext_data["presence"] # Could be a String or Hash + raise "Missing extension presence for extension #{ext_name}" if actual_presence.nil? - match = - if desired_presence.nil? - true # Always match - else - actual_presence_obj == desired_presence_converted - end + # Convert presence String or Hash to object. + actual_presence_obj = ExtensionPresence.new(actual_presence) - if match - in_scope_ext_reqs << - if ext_data.key?("version") - ExtensionRequirement.new( - ext_name, ext_data["version"], cfg_arch: @cfg_arch, - presence: actual_presence_obj, note: ext_data["note"], req_id: "REQ-EXT-#{ext_name}") + match = + if desired_presence.nil? + true # Always match else - ExtensionRequirement.new( - ext_name, cfg_arch: @cfg_arch, - presence: actual_presence_obj, note: ext_data["note"], req_id: "REQ-EXT-#{ext_name}") + actual_presence_obj == desired_presence_converted end + + if match + in_scope_ext_reqs << + if ext_data.key?("version") + ExtensionRequirement.new( + ext_name, ext_data["version"], arch: @arch, + presence: actual_presence_obj, note: ext_data["note"], req_id: "REQ-EXT-#{ext_name}") + else + ExtensionRequirement.new( + ext_name, arch: @arch, + presence: actual_presence_obj, note: ext_data["note"], req_id: "REQ-EXT-#{ext_name}") + end + end end end - # TODO: Change to "raise" when missing extensions added to database so we can make progress until then. - # See https://github.com/riscv-software-src/riscv-unified-db/issues/320 - puts "One or more extensions referenced by #{name} missing in database" if missing_ext + raise "One or more extensions referenced by #{name} missing in database" if missing_ext in_scope_ext_reqs end - def mandatory_ext_reqs = in_scope_ext_reqs(ExtensionPresence.mandatory) - def optional_ext_reqs = in_scope_ext_reqs(ExtensionPresence.optional) - def optional_type_ext_reqs = in_scope_ext_reqs(ExtensionPresence.optional) + # @return [Array] Sorted list of all instructions associated with extensions listed as + # mandatory or optional in portfolio. Uses minimum version of + # extension version that meets extension requirement specified in portfolio. + def in_scope_instructions + return @in_scope_instructions unless @in_scope_instructions.nil? + + # XXX + # @in_scope_instructions = in_scope_ext_reqs.map { |ext_req| ext_req.instructions }.flatten.uniq.sort + @in_scope_instructions = in_scope_extensions.map { |ext| ext.instructions }.flatten.uniq.sort + end # @return [Array] List of all extensions listed in portfolio. def in_scope_extensions return @in_scope_extensions unless @in_scope_extensions.nil? @in_scope_extensions = in_scope_ext_reqs.map do |ext_req| - cfg_arch.extension(ext_req.name) + arch.extension(ext_req.name) end.reject(&:nil?) # Filter out extensions that don't exist yet. @in_scope_extensions end - # @return [Array] Sorted list of all instructions associated with extensions listed as - # mandatory or optional in portfolio. Uses minimum version of - # extension version that meets extension requirement specified in portfolio. - def in_scope_instructions - in_scope_extensions.map { |ext| ext.instructions }.flatten.uniq.sort - end - # @return [Boolean] Does the profile differentiate between different types of optional. def uses_optional_types? return @uses_optional_types unless @uses_optional_types.nil? @@ -207,7 +225,7 @@ def uses_optional_types? @uses_optional_types end - # Called by rakefile when generating a particular portfolio instance. + # Called by rakefile when generating a portfolio. # Creates an in-memory data structure used by all portfolio routines that access a cfg_arch. # # @return [ConfiguredArchitecture] A partially-configured architecture definition corresponding to this portfolio. @@ -236,7 +254,7 @@ def to_cfg_arch Dir.mktmpdir do |dir| FileUtils.mkdir("#{dir}/#{name}") File.write("#{dir}/#{name}/cfg.yaml", YAML.safe_dump(config_data, permitted_classes: [Date])) - @generated_cfg_arch = ConfiguredArchitecture.new(name, @cfg_arch.path, cfg_path: dir) + @generated_cfg_arch = ConfiguredArchitecture.new(name, @arch.path, cfg_path: dir) end end @@ -276,7 +294,7 @@ def value # @return [String] - # What parameter values are allowed by the portfolio. def allowed_values if (@schema_portfolio.empty?) - # PortfolioInstance doesn't add any constraints on parameter's value. + # Portfolio doesn't add any constraints on parameter's value. return "Any" end @@ -313,7 +331,7 @@ def all_in_scope_ext_params next if ext_name[0] == "$" # Find Extension object from database - ext = @cfg_arch.extension(ext_name) + ext = @arch.extension(ext_name) raise "Cannot find extension named #{ext_name}" if ext.nil? ext_data["parameters"]&.each do |param_name, param_data| @@ -322,7 +340,7 @@ def all_in_scope_ext_params next unless ext.versions.any? do |ext_ver| ver_req = ext_data["version"] || ">= #{ext.min_version.version_spec}" - ExtensionRequirement.new(ext_name, ver_req, cfg_arch: @cfg_arch).satisfied_by?(ext_ver) && + ExtensionRequirement.new(ext_name, ver_req, arch: @arch).satisfied_by?(ext_ver) && param.defined_in_extension_version?(ext_ver) end @@ -345,7 +363,7 @@ def in_scope_ext_params(ext_req) raise "Cannot find extension named #{ext_req.name}" if ext_data.nil? # Find Extension object from database - ext = @cfg_arch.extension(ext_req.name) + ext = @arch.extension(ext_req.name) raise "Cannot find extension named #{ext_req.name}" if ext.nil? # Loop through an extension's parameter constraints (hash) from the portfolio. @@ -373,7 +391,7 @@ def all_out_of_scope_params @all_out_of_scope_params = [] in_scope_ext_reqs.each do |ext_req| - ext = @cfg_arch.extension(ext_req.name) + ext = @arch.extension(ext_req.name) ext.params.each do |param| next if all_in_scope_ext_params.any? { |c| c.param.name == param.name } diff --git a/lib/arch_obj_models/profile.rb b/lib/arch_obj_models/profile.rb index 4e7e4910e..05acb3433 100644 --- a/lib/arch_obj_models/profile.rb +++ b/lib/arch_obj_models/profile.rb @@ -7,6 +7,9 @@ # that each include an unprivileged profile (e.g., RVA20U64) and one more # privileged profiles (e.g., RVA20S64). class ProfileClass < PortfolioClass + # @return [String] Naming scheme for profile class + def naming_scheme = @data["naming_scheme"] + # @return [String] Name of the class def marketing_name = @data["marketing_name"] @@ -27,21 +30,35 @@ def profile_releases @profile_releases end + # @return [Array] Defined profile releases of this processor class + def profile_releases_matching_processor_kind + return @profile_releases_matching_processor_kind unless @profile_releases_matching_processor_kind.nil? + + matching_classes = portfolio_classes_matching_portfolio_kind_and_processor_kind + + # Look for all profile releases that are from any of the matching classes. + @profile_releases_matching_processor_kind = @cfg_arch.profile_releases.select { |pr| + matching_classes.any? { |matching_class| matching_class.name == pr.profile_class.name } + } + + @profile_releases_matching_processor_kind + end + # @return [Array] All profiles in this profile class (for all releases). def profiles return @profiles unless @profiles.nil? - @profiles = [] - @cfg_arch.profiles.each do |profile| - if profile.profile_class.name == name - @profiles << profile - end - end + @profiles = @cfg_arch.profiles.select {|profile| profile.profile_class.name == name} + end - @profiles + # @return [Array] All profiles in database matching my processor kind + def profiles_matching_processor_kind + return @profiles_matching_processor_kind unless @profiles_matching_processor_kind.nil? + + @profiles_matching_processor_kind = @cfg_arch.profiles.select {|profile| profile.profile_class.processor_kind == processor_kind} end - # @return [Array] List of all extensions referenced by the class + # @return [Array] List of all extensions referenced by the profile class def referenced_extensions return @referenced_extensions unless @referenced_extensions.nil? @@ -55,15 +72,31 @@ def referenced_extensions @referenced_extensions end + # @return [Array] List of all extensions referenced by any profile class in the database with my processor kind + def referenced_extensions_matching_processor_kind + return @reference_extensions_matching_processor_kind unless @reference_extensions_matching_processor_kind.nil? + + @reference_extensions_matching_processor_kind = [] + profiles_matching_processor_kind.each do |profile| + @reference_extensions_matching_processor_kind += profile.in_scope_extensions + end + + @reference_extensions_matching_processor_kind.uniq!(&:name) + + @reference_extensions_matching_processor_kind + end end # A profile release consists of a number of releases each with one or more profiles. # For example, the RVA20 profile release has profiles RVA20U64 and RVA20S64. # Note there is no Portfolio* base class for a ProfileRelease to inherit from since there is no # equivalent to a ProfileRelease in a Certificate so no potential for a shared base class. -class ProfileRelease < DatabaseObjectect +class ProfileRelease < DatabaseObject def marketing_name = @data["marketing_name"] + + # @return [String] Small enough (~1 paragraph) to be suitable immediately after a higher-level heading. def introduction = @data["introduction"] + def state = @data["state"] # @return [Date] Ratification date @@ -76,6 +109,8 @@ def ratification_date # @return [Array] Contributors to the profile spec def contributors + return nil if @data["contributors"].nil? + @data["contributors"].map { |data| Person.new(data) } end @@ -135,10 +170,8 @@ def extension_presence(ext_name) end # Representation of a specific profile in a profile release. -class Profile < PortfolioInstance - +class Profile < Portfolio # @return [String] The marketing name of the Profile - def introduction = @data["introduction"] def marketing_name = @data["marketing_name"] # @return [ProfileRelease] The profile release this profile belongs to diff --git a/lib/architecture.rb b/lib/architecture.rb index 21e1b2c97..0ff77ba80 100644 --- a/lib/architecture.rb +++ b/lib/architecture.rb @@ -1,5 +1,37 @@ # frozen_string_literal: true +# Contains the "database" of RISC-V standards including extensions, instructions, +# CSRs, Profiles, and Certificates. Could be either the standard spec (defined by RISC-V International) +# of a custom spec (defined as an arch_overlay in /cfgs dir). +# +# Creates Ruby functions at runtime (see generate_obj_methods() and OBJS array). +# 1) Function to return Array (every klass in database) +# 2) Function to return Hash (hash entry is nil if name doesn't exist) +# 3) Function to return Klass given name (nil if name doesn't exist) +# +# klass Array Hash Klass func(String name) +# =============== ================== ======================= ========================= +# Extension extensions() extension_hash() extension(name) +# Instruction instructions() instruction_hash() instruction(name) +# Csr csrs() csr_hash() csr(name) +# CertClass cert_classes() cert_class_hash() cert_class(name) +# CertModel cert_models() cert_model_hash() cert_model(name) +# ProfileClass profile_classes() profile_class_hash() profile_class(name) +# ProfileRelease profile_releases() profile_release_hash() profile_release(name) +# Profile profiles() profile_hash() profile(name) +# Manual manuals() manual_hash() manual(name) +# ManualVersion manual_versions() manual_version_hash() manual_version(name) +# +# Normal Ruby functions: +# +# klass Array Hash Klass func(String name) +# ================== ================== ======================= ========================= +# ExtensionParameter params() param_hash() param(name) +# PortfolioClass portfolio_classes() portfolio_class_hash() portfolio_class(name) +# Portfolio portfolios() portfolio_hash() portfolio(name) +# ExceptionCodes exception_codes() +# InterruptCodes interrupt_codes() + require "active_support/inflector/methods" require "json" @@ -19,10 +51,6 @@ require_relative "arch_obj_models/portfolio" require_relative "arch_obj_models/profile" -# Represents the entire RISC-V Architecture. -# -# Could be either the standard spec (defined by RISC-V International) -# of a custom spec (defined as an arch_overlay in cfgs/) class Architecture # @return [Pathname] Path to the directory with the standard YAML files attr_reader :path @@ -150,7 +178,7 @@ def self.generate_obj_methods(fn_name, arch_dir, obj_class) generate_obj_methods(obj_info[:fn_name], obj_info[:arch_dir], obj_info[:klass]) end - # @return [Array] All known objects + # @return [Array] All known objects def objs return @objs unless @objs.nil? @@ -169,12 +197,12 @@ def params end # @return [Hash] Hash of all extension parameters defined in the architecture - def params_hash - return @params_hash unless @params_hash.nil? + def param_hash + return @param_hash unless @param_hash.nil? - @params_hash = {} + @param_hash = {} params.each do |param| - @params_hash[param.name] = param + @param_hash[param.name] = param end @param_hash end @@ -182,7 +210,53 @@ def params_hash # @return [ExtensionParameter] Parameter named +name+ # @return [nil] if there is no parameter named +name+ def param(name) - params_hash[name] + param_hash[name] + end + + # @return [Array] Alphabetical list of all portfolio classes defined in the architecture + def portfolio_classes + return @portfolio_classes unless @portfolio_classes.nil? + + @portfolio_classes = profile_classes.concat(cert_classes).sort_by!(&:name) + end + + # @return [Hash] Hash of all portfolio classes defined in the architecture + def portfolio_class_hash + return @portfolio_class_hash unless @portfolio_class_hash.nil? + + @portfolio_class_hash = {} + portfolio_classes.each do |portfolio_class| + @portfolio_class_hash[portfolio_class.name] = portfolio_class + end + @portfolio_class_hash + end + + # @return [PortfolioClass] Portfolio class named +name+ + # @return [nil] if there is no Portfolio class named +name+ + def portfolio_class(name) = portfolio_class_hash[name] + + # @return [Array] Alphabetical list of all portfolios defined in the architecture + def portfolios + return @portfolios unless @portfolios.nil? + + @portfolios = @profiles.concat(@certificates).sort_by!(&:name) + end + + # @return [Hash] Hash of all portfolios defined in the architecture + def portfolio_hash + return @portfolio_hash unless @portfolio_hash.nil? + + @portfolio_hash = {} + portfolios.each do |portfolio| + @portfolio_hash[portfolio.name] = portfolio + end + @portfolio_hash + end + + # @return [PortfolioClass] Portfolio named +name+ + # @return [nil] if there is no Portfolio named +name+ + def portfolio(name) + portfolio_hash[name] end # @return [Array] All exception codes defined by the spec diff --git a/lib/cfg_arch.rb b/lib/cfg_arch.rb index 7eb4e959b..01c70ad94 100644 --- a/lib/cfg_arch.rb +++ b/lib/cfg_arch.rb @@ -1,28 +1,9 @@ # frozen_string_literal: true -# Many classes have an "cfg_arch" member which is an ConfiguredArchitecture (not DatabaseObjectect) class. -# The "cfg_arch" member contains the "database" of RISC-V standards including extensions, instructions, -# CSRs, Profiles, and Certificates. -# -# The cfg_arch member has methods such as: -# extensions() Array of all extensions known to the database (even if not implemented). -# extension(name) Extension object for "name" and nil if none. -# parameters() Array of all parameters defined in the architecture -# param(name) ExtensionParameter object for "name" and nil if none. -# csrs() Array of all CSRs defined by RISC-V, whether or not they are implemented -# csr(name) Csr object for "name" and nil if none. -# instructions() Array of all instructions, whether or not they are implemented -# inst(name) Instruction object for "name" and nil if none. -# profile_classes Array of all known profile classes. -# profile_class(class_name) ProfileClass object for "class_name" and nil if none. -# profile_releases Array of all profile releases for all profile classes -# profile_release(release_name) ProfileRelease object for "release_name" and nil if none. -# profiles Array of all profiles in all releases in all classes -# profile(name) Profile object for profile "name" and nil if none. -# cert_classes Array of all known certificate classes -# cert_class(name) CertClass object for "name" and nil if none. -# cert_models Array of all known certificate models across all classes. -# cert_model(name) CertModel object for "name" and nil if none. +# Many classes include DatabaseObject have an "cfg_arch" member which is a ConfiguredArchitecture class. +# It combines knowledge of the RISC-V Architecture with a particular configuration. +# A configuration is an instance of the Config object either located in the /cfg directory +# or created at runtime for things like profiles and certificate models. require "forwardable" require "ruby-prof" @@ -210,6 +191,10 @@ def initialize(config_name, arch_path, overlay_path: nil, cfg_path: "#{$root}/cf @global_ast.freeze_tree(@symtab) end + # Returns a string representation of the object, suitable for debugging. + # @return [String] A string representation of the object. + def inspect = "ConfiguredArchitecture##{name}" + # type check all IDL, including globals, instruction ops, and CSR functions # # @param config [Config] Configuration @@ -277,7 +262,7 @@ def type_check(show_progress: true, io: $stdout) puts "done" if show_progress end - # @return [Array] List of all available parameters with known values for the config + # @return [Array] List of all parameters with one known value in the config def params_with_value return @params_with_value unless @params_with_value.nil? @@ -300,6 +285,7 @@ def params_with_value mandatory_extensions.each do |ext_requirement| ext = extension(ext_requirement.name) ext.params.each do |ext_param| + # Params listed in the config always only have one value. next unless @config.param_values.key?(ext_param.name) @params_with_value << ExtensionParameterWithValue.new( @@ -314,13 +300,14 @@ def params_with_value @params_with_value end - # @return [Array] List of all available parameters without known values for the config + # @return [Array] List of all available parameters without one known value in the config def params_without_value return @params_without_value unless @params_without_value.nil? @params_without_value = [] extensions.each do |ext| ext.params.each do |ext_param| + # Params listed in the config always only have one value. next if @config.param_values.key?(ext_param.name) @params_without_value << ext_param @@ -329,10 +316,6 @@ def params_without_value @params_without_value end - # Returns a string representation of the object, suitable for debugging. - # @return [String] A string representation of the object. - def inspect = "ConfiguredArchitecture##{name}" - def implemented_extensions @implemented_extensions ||= @config.implemented_extensions.map do |e| @@ -361,7 +344,7 @@ def mandatory_extensions ext = extension(e["name"]) raise "Cannot find extension #{e['name']} in the architecture definition" if ext.nil? - ExtensionRequirement.new(e["name"], *e["version"], presence: "mandatory", cfg_arch: self) + ExtensionRequirement.new(e["name"], *e["version"], presence: "mandatory", arch: self) end end @@ -377,7 +360,7 @@ def prohibited_extensions ext = extension(e["name"]) raise "Cannot find extension #{e['name']} in the architecture definition" if ext.nil? - ExtensionRequirement.new(e["name"], *e["version"], presence: "mandatory", cfg_arch: self) + ExtensionRequirement.new(e["name"], *e["version"], presence: "mandatory", arch: self) end # now add any extensions that are prohibited by a mandatory extension @@ -411,7 +394,7 @@ def prohibited_extensions @prohibited_extensions << ExtensionRequirement.new( ext_ver_list[0].ext.name, ">= #{ext_ver_list.min.version_spec.canonical}", - presence: "prohibited", cfg_arch: self + presence: "prohibited", arch: self ) elsif ext_ver_list.size == (ext_ver_list[0].ext.versions.size - 1) # excludes all but one version @@ -422,7 +405,7 @@ def prohibited_extensions @prohibited_extensions << ExtensionRequirement.new( ext_ver_list[0].ext.name, "!= #{allowed_version.version_spec.canonical}", - presence: "prohibited", cfg_arch: self + presence: "prohibited", arch: self ) else # need to group @@ -462,11 +445,11 @@ def prohibited_ext?(ext) # @param ext_version_requirements [Number,String,Array] Extension version requirements # @return [Boolean] True if the extension `name` meeting `ext_version_requirements` is implemented # @example Checking extension presence with a version requirement - # cfg_arch.ext?(:S, ">= 1.12") + # ConfigurationArchitecture.ext?(:S, ">= 1.12") # @example Checking extension presence with multiple version requirements - # cfg_arch.ext?(:S, ">= 1.12", "< 1.15") + # ConfigurationArchitecture.ext?(:S, ">= 1.12", "< 1.15") # @example Checking extension precsence with a precise version requirement - # cfg_arch.ext?(:S, 1.12) + # ConfigurationArchitecture.ext?(:S, 1.12) def ext?(ext_name, *ext_version_requirements) @ext_cache ||= {} cached_result = @ext_cache[[ext_name, ext_version_requirements]] @@ -478,7 +461,7 @@ def ext?(ext_name, *ext_version_requirements) if ext_version_requirements.empty? e.name == ext_name.to_s else - requirement = ExtensionRequirement.new(ext_name, *ext_version_requirements, cfg_arch: self) + requirement = ExtensionRequirement.new(ext_name, *ext_version_requirements, arch: self) requirement.satisfied_by?(e) end end @@ -487,7 +470,7 @@ def ext?(ext_name, *ext_version_requirements) if ext_version_requirements.empty? e.name == ext_name.to_s else - requirement = ExtensionRequirement.new(ext_name, *ext_version_requirements, cfg_arch: self) + requirement = ExtensionRequirement.new(ext_name, *ext_version_requirements, arch: self) e.satisfying_versions.all? do |ext_ver| requirement.satisfied_by?(ext_ver) end diff --git a/lib/config.rb b/lib/config.rb index a0411863d..5efe7b684 100644 --- a/lib/config.rb +++ b/lib/config.rb @@ -2,7 +2,8 @@ require "pathname" -# this class represents a configuration file (e.g., cfgs/*/cfg.yaml), independent of the Architecture +# This class represents a configuration file (e.g., cfgs/*/cfg.yaml), independent of the Architecture. +# Can either be in the /cfg directory or created at runtime in memory by the certificate tasks.rake file. class Config # @return [Hash] A hash mapping parameter name to value for any parameter that has # been configured with a value. May be empty. @@ -62,8 +63,10 @@ def configured? = @data["type"] != "unconfigured" def type = @data["type"] end -# this class represents a configuration file (e.g., cfgs/*/cfg.yaml) that is "unconfigured" -# (i.e., we don't know any implemented/mandatory extensions or parameter values) +################################################################# +# This class represents a configuration that is "unconfigured". # +# It doesn't know anything about extensions or parameters. # +################################################################# class Unconfig < Config attr_reader :param_values @@ -80,10 +83,10 @@ def mandatory_extensions = raise "mandatory_extensions is only available for a P def prohibited_extensions = raise "prohibited_extensions is only available for a PartialConfig" end -# this class represents a configuration file (e.g., cfgs/*/cfg.yaml) that is "partially configured" -# (i.e., we have a list of mandatory/prohibited extensions and a partial list of parameter values) -# -# This would, for example, represent a Profile or configurable IP +############################################################################################################## +# This class represents a configuration that is "partially-configured" (e.g., portfolio or configurable IP). # +# It only lists mandatory & prohibited extensions and fully-constrained parameters (single value). +############################################################################################################## class PartialConfig < Config attr_reader :param_values, :mxlen @@ -106,7 +109,8 @@ def implemented_extensions = raise "implemented_extensions is only available for # The second entry in the nested array is an Extension version requirement # # @example - # partial_config.mandatory_extensions #=> [{ "name" => "A", "version" => ["~> 2.0"] }, { "name" => "B", "version" => ["~> 1.0"] }, ...] + # partial_config.mandatory_extensions => + # [{ "name" => "A", "version" => ["~> 2.0"] }, { "name" => "B", "version" => ["~> 1.0"] }, ...] def mandatory_extensions @mandatory_extensions ||= if @data["mandatory_extensions"].nil? @@ -125,7 +129,8 @@ def mandatory_extensions # The second entry in the nested array is an Extension version requirement. # # @example - # partial_config.prohibited_extensions #=> [{ "name" => "F", "version" => [">= 2.0"] }, { "name" => "Zfa", "version" => ["> = 1.0"] }, ...] + # partial_config.prohibited_extensions => + # [{ "name" => "F", "version" => [">= 2.0"] }, { "name" => "Zfa", "version" => ["> = 1.0"] }, ...] def prohibited_extensions @prohibited_extensions ||= if @data["prohibited_extensions"].nil? @@ -143,10 +148,10 @@ def prohibited_extensions # def ext?(ext_name, cfg_arch) = mandatory_extensions(cfg_arch).any? { |e| e.name == ext_name.to_s } end -# this class represents a configuration file (e.g., cfgs/*/cfg.yaml) that is "fully configured" -# (i.e., we have a complete list of implemented extensions and a complete list of parameter values) -# -# This would, for example, represent a specific silicon tapeout/SKU +################################################################################################################ +# This class represents a configuration that is "fully-configured" (e.g., SoC tapeout or fully-configured IP). # +# It has a complete list of extensions and parameters (all are a single value at this point). # +################################################################################################################ class FullConfig < Config attr_reader :param_values, :mxlen diff --git a/lib/idl/symbol_table.rb b/lib/idl/symbol_table.rb index 5237ffe32..466183f9f 100644 --- a/lib/idl/symbol_table.rb +++ b/lib/idl/symbol_table.rb @@ -90,7 +90,10 @@ def hash end def initialize(cfg_arch) - raise if cfg_arch.nil? + raise "Must provide cfg_arch" if cfg_arch.nil? + # TODO: XXX: Put this check back in when replaced by Design class. + # See https://github.com/riscv-software-src/riscv-unified-db/pull/371 + #raise "The cfg_arch must be a ConfiguredArchitecture but is a #{cfg_arch.class}" unless (cfg_arch.is_a?(ConfiguredArchitecture) || cfg_arch.is_a?(MockConfiguredArchitecture)) @cfg_arch = cfg_arch @mxlen = cfg_arch.unconfigured? ? nil : cfg_arch.mxlen diff --git a/lib/test/test_yaml_loader.rb b/lib/test/test_yaml_loader.rb index 593a95fd2..c5831736a 100644 --- a/lib/test/test_yaml_loader.rb +++ b/lib/test/test_yaml_loader.rb @@ -251,6 +251,30 @@ def test_inherits_in_the_different_document assert_equal({ "$child_of" => "test/test2.yaml#/$defs/target2", "a" => "Should take precedence" }, doc["obj3"]) end + def test_inherits_entire_object + yaml2 = <<~YAML + target1: A string + target2: + a: hash + sub1: + key_a: old_value_a + key_b: old_value_b + YAML + + yaml1 = <<~YAML + $inherits: "YAML2_REL_PATH#" + target1: Should take precedence + target2: + sub1: + key_a: new_value_a + YAML + + doc = resolve_multi_yaml(yaml1, yaml2) + assert_equal("test/test2.yaml#", doc["$child_of"]) + assert_equal("Should take precedence", doc["target1"]) + assert_equal({ "a" => "hash", "sub1" => { "key_a" => "new_value_a", "key_b" => "old_value_b" }}, doc["target2"]) + end + def test_multi_inherits_in_the_same_document yaml = <<~YAML $defs: @@ -286,4 +310,62 @@ def test_that_invalid_inherits_raise doc = resolve_yaml(yaml) assert_nil doc end + + # Commented out until https://github.com/riscv-software-src/riscv-unified-db/issues/369 is fixed. +# def test_copy_in_the_same_document +# yaml = <<~YAML +# $defs: +# target1: A string +# target2: +# a: hash +# target3: Another string +# +# obj1: +# target10: abc +# target11: +# $copy: "#/$defs/target1" +# target12: def +# target13: +# $copy: "#/$defs/target3" +# +# YAML +# +# doc = resolve_yaml(yaml) +# assert_equal({ +# "$child_of" => "#/$defs", +# "target10" => "abc", +# "target11" => "A string", +# "target12" => "def", +# "target13" => "Another string" +# }, doc["obj1"]) +# end +# +# def test_copy_in_the_different_document +# yaml2 = <<~YAML +# $defs: +# target1: A string +# target2: +# a: hash +# target3: Another string +# YAML +# +# yaml1 = <<~YAML +# obj1: +# target10: abc +# target11: +# $copy: "YAML2_REL_PATH#/$defs/target1" +# target12: def +# target13: +# $copy: "YAML2_REL_PATH#/$defs/target3" +# YAML +# +# doc = resolve_multi_yaml(yaml1, yaml2) +# assert_equal({ +# "$child_of" => "test/test2.yaml#/$defs", +# "target10" => "abc", +# "target11" => "A string", +# "target12" => "def", +# "target13" => "Another string" +# }, doc["obj1"]) +# end end diff --git a/lib/yaml_resolver.py b/lib/yaml_resolver.py index 1983496ce..7983012d6 100644 --- a/lib/yaml_resolver.py +++ b/lib/yaml_resolver.py @@ -306,6 +306,8 @@ def _resolve(obj, obj_path, obj_file_path, doc_obj, arch_root, do_checks): del final_obj["$remove"] return final_obj + #elif "$copy" in obj: + # raise "$copy support was lost by https://github.com/riscv-software-src/riscv-unified-db/pull/350" else: for key in obj: obj[key] = _resolve(obj[key], obj_path + [key], obj_file_path, doc_obj, arch_root, do_checks) @@ -417,6 +419,7 @@ def resolve_file(rel_path : str | Path, arch_dir: str | Path, resolved_dir: str resolved_obj = resolve(rel_path, args.arch_dir, do_checks) resolved_obj["$source"] = os.path.join(args.arch_dir, rel_path) + write_yaml(resolved_path, resolved_obj) if do_checks and ("$schema" in resolved_obj): schema = _get_schema(resolved_obj["$schema"]) try: @@ -426,7 +429,6 @@ def resolve_file(rel_path : str | Path, arch_dir: str | Path, resolved_dir: str print(best_match(schema.iter_errors(resolved_obj)).message) exit(1) - write_yaml(resolved_path, resolved_obj) os.chmod(resolved_path, 0o444) if __name__ == '__main__': diff --git a/schemas/cert_class_schema.json b/schemas/cert_class_schema.json index 8fc5a4c9d..a816c4333 100644 --- a/schemas/cert_class_schema.json +++ b/schemas/cert_class_schema.json @@ -11,7 +11,7 @@ }, "kind": { "type": "string", - "const": "certificate class" + "const": "Processor CRD" }, "name": { "type": "string", @@ -22,13 +22,14 @@ "type": "string", "description": "Descriptive name of the class" }, - "introduction": { + "processor_kind": { "type": "string", - "description": "Asciidoc text containing the introduction prose for the class" + "enum": ["Generic Unprivileged", "Microcontroller", "Apps Processor"], + "description": "What kind of class is this?" }, - "naming_scheme": { + "introduction": { "type": "string", - "description": "Asciidoc text describing the naming scheme for the class" + "description": "Asciidoc text containing the introduction prose for the class" }, "mandatory_priv_modes": { "type": "array", diff --git a/schemas/cert_model_schema.json b/schemas/cert_model_schema.json index 1da6fac39..65383a4e2 100644 --- a/schemas/cert_model_schema.json +++ b/schemas/cert_model_schema.json @@ -5,6 +5,54 @@ "required": ["$schema", "kind", "name", "long_name"], "additionalProperties": false, "properties": { + "$inherits": { + "oneOf": [ + { + "type": "string", + "pattern": "^(profile|certificate_model)/.*\\.yaml#.*" + }, + { + "type": "array", + "items": { + "type": "string", + "pattern": "^(profile|certificate_model)/.*\\.yaml#.*" + }, + "uniqueItems": true + } + ] + }, + "$child_of": { + "oneOf": [ + { + "type": "string", + "pattern": "^(profile|certificate_model)/.*\\.yaml#.*" + }, + { + "type": "array", + "items": { + "type": "string", + "pattern": "^(profile|certificate_model)/.*\\.yaml#.*" + }, + "uniqueItems": true + } + ] + }, + "$parent_of": { + "oneOf": [ + { + "type": "string", + "pattern": "^(profile|certificate_model)/.*\\.yaml#.*" + }, + { + "type": "array", + "items": { + "type": "string", + "pattern": "^(profile|certificate_model)/.*\\.yaml#.*" + }, + "uniqueItems": true + } + ] + }, "$schema": { "type": "string", "const": "cert_model_schema.json#" @@ -15,7 +63,7 @@ }, "name": { "type": "string", - "pattern": "^[A-Z][a-zA-Z0-9_]*$", + "pattern": "^[A-Z][a-zA-Z0-9_-]*$", "description": "The short name of the model, used as a database key" }, "long_name": { @@ -60,9 +108,9 @@ "minItems": 1, "description": "Revisions of the model document" }, - "description": { + "introduction": { "type": "string", - "description": "Asciidoc description" + "description": "Asciidoc text containing the introduction prose for the model" }, "tsc_profile": { "oneOf": [ @@ -75,7 +123,7 @@ "properties": { "$ref": { "type": "string", - "pattern": "^profile_release/[A-Z][a-zA-Z0-9_]*\\.yaml#" + "pattern": "^profile_release|certificate_model/[A-Z][a-zA-Z0-9_]*\\.yaml#" } }, "additionalProperties": false @@ -96,29 +144,37 @@ "type": "object", "additionalProperties": false, "patternProperties": { - "^\\$inherits": { + "\\$inherits": { "oneOf": [ { "type": "string", - "pattern": "^profile/.*\\.yaml#.*" + "pattern": "^(profile|certificate_model)/.*\\.yaml#.*" }, { "type": "array", "items": { "type": "string", - "pattern": "^profile/.*\\.yaml#.*" + "pattern": "^(profile|certificate_model)/.*\\.yaml#.*" }, "uniqueItems": true } ] }, - "^\\$child_of": { - "type": "array", - "items": { - "type": "string", - "pattern": "^profile/.*\\.yaml#.*" - }, - "uniqueItems": true + "\\$child_of": { + "oneOf": [ + { + "type": "string", + "pattern": "^(profile|certificate_model)/.*\\.yaml#.*" + }, + { + "type": "array", + "items": { + "type": "string", + "pattern": "^(profile|certificate_model)/.*\\.yaml#.*" + }, + "uniqueItems": true + } + ] }, "^([A-WY])|([SXZ][a-z0-9]+)$": { "type": "object", diff --git a/schemas/profile_class_schema.json b/schemas/profile_class_schema.json index 10875bf35..663b65cb3 100644 --- a/schemas/profile_class_schema.json +++ b/schemas/profile_class_schema.json @@ -12,6 +12,11 @@ "type": "string", "const": "profile class" }, + "processor_kind": { + "type": "string", + "enum": ["Generic Unprivileged", "Microcontroller", "Apps Processor"], + "description": "What kind of class is this?" + }, "name": { "type": "string", "description": "Name (database key) of this Profile Class" @@ -22,11 +27,11 @@ }, "introduction": { "type": "string", - "description": "Asciidoc introduction to this Profile Class" + "description": "Asciidoc text containing the introduction prose for the class" }, "description": { "type": "string", - "description": "Prose introduction, in asciidoc" + "description": "Asciidoc text containing longer description prose for the class" }, "naming_scheme": { "type": "string",