diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index fd69190b25..74fe11ae21 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -62,13 +62,13 @@ jobs: - name: Copy RVA Family PDF run: cp gen/profile_doc/pdf/rva.pdf _site/pdfs/rva.pdf - name: Create MC-1 PDF Spec - run: ./do gen:csc_crd_pdf[MC-1] + run: ./do gen:crd_pdf[MC-1] - name: Copy MC-1 PDF - run: cp gen/csc_crd_doc/pdf/MC-1.pdf _site/pdfs/MC-1.pdf + run: cp gen/crd_doc/pdf/MC-1.pdf _site/pdfs/MC-1.pdf - name: Create MC-1 HTML Spec - run: ./do gen:csc_crd_html[MC-1] + run: ./do gen:crd_html[MC-1] - name: Copy MC-1 HTML - run: cp gen/csc_crd_doc/html/MC-1.html _site/htmls/MC-1.html + run: cp gen/crd_doc/html/MC-1.html _site/htmls/MC-1.html - name: Copy manual html run: cp -R gen/manual/isa/top/all/html _site/manual - name: Setup Pages diff --git a/.github/workflows/regress.yml b/.github/workflows/regress.yml index e1fda903bf..9973e14c33 100644 --- a/.github/workflows/regress.yml +++ b/.github/workflows/regress.yml @@ -37,7 +37,9 @@ jobs: run: ./do validate - name: Build html documentation for generic_rv64 run: ./do gen:html[generic_rv64] + - name: Build PDF documentation for MockCRD-1 + run: ./do gen:crd_pdf[MockCRD-1] - name: Build PDF documentation for MC-1 - run: ./do gen:csc_crd_pdf[MC-1] + run: ./do gen:crd_pdf[MC-1] - name: Build PDF documentation for RVA Profile Family run: ./do gen:profile_pdf[rva] diff --git a/Gemfile b/Gemfile index 3916f9ac43..8ad6850125 100644 --- a/Gemfile +++ b/Gemfile @@ -23,4 +23,5 @@ group :development do gem "solargraph" gem 'rubocop-minitest' gem 'ruby-prof' + gem "ruby-prof-flamegraph" end diff --git a/Gemfile.lock b/Gemfile.lock index 5ebc2cea9d..f2664dee0d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -107,7 +107,9 @@ GEM rubocop-minitest (0.35.1) rubocop (>= 1.61, < 2.0) rubocop-ast (>= 1.31.1, < 2.0) - ruby-prof (1.7.0) + ruby-prof (0.18.0) + ruby-prof-flamegraph (0.3.0) + ruby-prof (~> 0.13) ruby-progressbar (1.13.0) ruby-rc4 (0.1.5) simpleidn (0.2.3) @@ -152,6 +154,7 @@ DEPENDENCIES rouge rubocop-minitest ruby-prof + ruby-prof-flamegraph ruby-progressbar (~> 1.13) solargraph treetop (= 1.6.12) diff --git a/Rakefile b/Rakefile index 4636aee04f..d960a3fcd8 100644 --- a/Rakefile +++ b/Rakefile @@ -1,5 +1,7 @@ # frozen_string_literal: true +require "etc" + $root = Pathname.new(__FILE__).dirname.realpath $lib = $root / "lib" @@ -82,45 +84,84 @@ namespace :validate do end puts "All files validate against their schema" end - task idl: "gen:arch" do - puts "Type checking IDL code..." - arch_def = arch_def_for("_") - progressbar = ProgressBar.create(title: "Instructions", total: arch_def.instructions.size) - arch_def.instructions.each do |inst| - progressbar.increment - inst.type_checked_operation_ast(arch_def.idl_compiler, arch_def.sym_table_32, 32) if inst.rv32? - inst.type_checked_operation_ast(arch_def.idl_compiler, arch_def.sym_table_64, 64) if inst.rv64? - # also need to check for an RV64 machine running with effective XLEN of 32 - inst.type_checked_operation_ast(arch_def.idl_compiler, arch_def.sym_table_64, 32) if inst.rv64? && inst.rv32? - end - progressbar = ProgressBar.create(title: "CSRs", total: arch_def.csrs.size) - arch_def.csrs.each do |csr| - progressbar.increment - if csr.has_custom_sw_read? - csr.type_checked_sw_read_ast(arch_def.sym_table_32) if csr.defined_in_base32? - csr.type_checked_sw_read_ast(arch_def.sym_table_64) if csr.defined_in_base64? - end - csr.fields.each do |field| - unless field.type_ast(arch_def.idl_compiler).nil? - field.type_checked_type_ast(arch_def.sym_table_32) if csr.defined_in_base32? && field.defined_in_base32? - field.type_checked_type_ast(arch_def.sym_table_64) if csr.defined_in_base64? && field.defined_in_base64? - end - unless field.reset_value_ast(arch_def.idl_compiler).nil? - field.type_checked_reset_value_ast(arch_def.sym_table_32) if csr.defined_in_base32? && field.defined_in_base32? - field.type_checked_reset_value_ast(arch_def.sym_table_64) if csr.defined_in_base64? && field.defined_in_base64? - end - unless field.sw_write_ast(arch_def.idl_compiler).nil? - field.type_checked_sw_write_ast(arch_def.sym_table_32, 32) if csr.defined_in_base32? && field.defined_in_base32? - field.type_checked_sw_write_ast(arch_def.sym_table_64, 64) if csr.defined_in_base64? && field.defined_in_base64? - end - end - end - progressbar = ProgressBar.create(title: "Functions", total: arch_def.functions.size) - arch_def.functions.each do |func| - progressbar.increment - func.type_check_body(arch_def.sym_table_32) - func.type_check_body(arch_def.sym_table_64) - end + task idl: ["gen:arch", "#{$root}/.stamps/arch-gen-_32.stamp", "#{$root}/.stamps/arch-gen-_64.stamp"] do + print "Parsing IDL code for RV32..." + arch_def_32 = arch_def_for("_32") + puts "done" + + arch_def_32.type_check + + print "Parsing IDL code for RV64..." + arch_def_64 = arch_def_for("_64") + puts "done" + + arch_def_64.type_check + + # arch_def_64 = arch_def_for("_64") + # arch_def_64.type_check + + # puts "Type checking IDL code..." + # progressbar = ProgressBar.create(title: "Instructions", total: arch_def_32.instructions.size + arch_def_64.instructions.size) + # arch_def_32.instructions.each do |inst| + # progressbar.increment + # inst.type_checked_operation_ast(arch_def_32.idl_compiler, arch_def_32.symtab, 32) if inst.rv32? + # end + # arch_def_64.instructions.each do |inst| + # progressbar.increment + # inst.type_checked_operation_ast(arch_def_64.idl_compiler, arch_def_64.symtab, 64) if inst.rv64? + # # also need to check for an RV64 machine running with effective XLEN of 32 + # inst.type_checked_operation_ast(arch_def_64.idl_compiler, arch_def_64.symtab, 32) if inst.rv64? && inst.rv32? + # end + + # progressbar = ProgressBar.create(title: "CSRs", total: arch_def_32.csrs.size + arch_def_64.csrs.size) + # arch_def_32.csrs.each do |csr| + # progressbar.increment + # profile = RubyProf::Profile.new + # result = profile.profile do + # if csr.has_custom_sw_read? + # csr.type_checked_sw_read_ast(arch_def_32.symtab) if csr.defined_in_base32? + # end + # csr.fields.each do |field| + # unless field.type_ast(arch_def_32.symtab).nil? + # field.type_checked_type_ast(arch_def_32.symtab) if csr.defined_in_base32? && field.defined_in_base32? + # end + # unless field.reset_value_ast(arch_def_32.symtab).nil? + # field.type_checked_reset_value_ast(arch_def_32.symtab) if csr.defined_in_base32? && field.defined_in_base32? + # end + # unless field.sw_write_ast(arch_def_32.symtab).nil? + # field.type_checked_sw_write_ast(arch_def_32.symtab, 32) if csr.defined_in_base32? && field.defined_in_base32? + # end + # end + # end + # RubyProf::GraphHtmlPrinter.new(result).print(File.open("#{csr.name}-prof.html", "w+"), {}) + # end + # arch_def_64.csrs.each do |csr| + # progressbar.increment + # if csr.has_custom_sw_read? + # csr.type_checked_sw_read_ast(arch_def_64.symtab) if csr.defined_in_base64? + # end + # csr.fields.each do |field| + # unless field.type_ast(arch_def_64.symtab).nil? + # field.type_checked_type_ast(arch_def_64.symtab) if csr.defined_in_base64? && field.defined_in_base64? + # end + # unless field.reset_value_ast(arch_def_64.symtab).nil? + # field.type_checked_reset_value_ast(arch_def_64.symtab) if csr.defined_in_base64? && field.defined_in_base64? + # end + # unless field.sw_write_ast(arch_def_64.symtab).nil? + # field.type_checked_sw_write_ast(arch_def_64.symtab, 32) if csr.defined_in_base32? && field.defined_in_base32? + # field.type_checked_sw_write_ast(arch_def_64.symtab, 64) if csr.defined_in_base64? && field.defined_in_base64? + # end + # end + # end + # progressbar = ProgressBar.create(title: "Functions", total: arch_def_32.functions.size + arch_def_64.functions.size) + # arch_def_32.functions.each do |func| + # progressbar.increment + # func.type_check(arch_def_32.symtab) + # end + # arch_def_64.functions.each do |func| + # progressbar.increment + # func.type_check(arch_def_64.symtab) + # end puts "All IDL passed type checking" end end diff --git a/arch/csc_crd/MC-1.yaml b/arch/crd/MC-1.yaml similarity index 62% rename from arch/csc_crd/MC-1.yaml rename to arch/crd/MC-1.yaml index a3f6f79010..e88401064c 100644 --- a/arch/csc_crd/MC-1.yaml +++ b/arch/crd/MC-1.yaml @@ -29,71 +29,56 @@ MC-1: # XXX - Remove version information since specifying priv/unpriv ISA manual should imply this. extensions: - mandatory: - - name: I - version: "~> 2.1" - - name: C - version: "~> 2.2" - param_constraints: - MUTABLE_MISA_C: - schema: - const: false - - name: M - version: "~> 2.0" - - name: Zicsr - version: "~> 2.0" - - name: Zicntr - version: "~> 2.0" - - name: Sm - version: "~> 1.11" - param_constraints: - MTVEC_BASE_ALIGNMENT_DIRECT: {} # Unconstrained - MTVEC_BASE_ALIGNMENT_VECTORED: {} # Unconstrained - ARCH_ID: {} # Unconstrained - IMP_ID: {} # Unconstrained - VENDOR_ID_BANK: {} # Unconstrained - VENDOR_ID_OFFSET: {} # Unconstrained - MISA_CSR_IMPLEMENTED: {} # Unconstrained - TIME_CSR_IMPLEMENTED: {} # Unconstrained - MTVAL_WIDTH: {} # Unconstrained - PHYS_ADDR_WIDTH: {} # Unconstrained - PRECISE_SYNCHRONOUS_EXCEPTIONS: - schema: - const: true - TRAP_ON_ECALL_FROM_M: - schema: - const: true - TRAP_ON_EBREAK: - schema: - const: true - REPORT_VA_IN_MTVAL_ON_BREAKPOINT: - schema: - const: true - REPORT_VA_IN_MTVAL_ON_INSTRUCTION_ACCESS_FAULT: - schema: - const: true - REPORT_VA_IN_MTVAL_ON_LOAD_ACCESS_FAULT: - schema: - const: true - REPORT_VA_IN_MTVAL_ON_STORE_AMO_ACCESS_FAULT: - schema: - const: true - REPORT_ENCODING_IN_MTVAL_ON_ILLEGAL_INSTRUCTION: - schema: - const: true - M_MODE_ENDIANESS: - schema: - const: little - XLEN: - schema: - const: 32 - CONFIG_PTR_ADDRESS: - schema: - const: 0 - #XXX optional: {} # None - optional: - - name: Zifencei - note: "This is just for testing. Zifencei extension isn't really optional for MC-1." + - name: I + version: "~> 2.1" + presence: mandatory + - name: C + version: "~> 2.2" + presence: mandatory + - name: M + version: "~> 2.0" + presence: mandatory + - name: Zicsr + version: "~> 2.0" + presence: mandatory + - name: Zicntr + version: "~> 2.0" + presence: mandatory + parameters: + TIME_CSR_IMPLEMENTED: {} # Unconstrained + - name: Sm + version: "~> 1.11" + presence: mandatory + parameters: + MTVEC_BASE_ALIGNMENT_DIRECT: {} # Unconstrained + MTVEC_BASE_ALIGNMENT_VECTORED: {} # Unconstrained + ARCH_ID: {} # Unconstrained + IMP_ID: {} # Unconstrained + VENDOR_ID_BANK: {} # Unconstrained + VENDOR_ID_OFFSET: {} # Unconstrained + MISA_CSR_IMPLEMENTED: {} # Unconstrained + MTVAL_WIDTH: {} # Unconstrained + MTVEC_MODES: {} # Unconstrained + PHYS_ADDR_WIDTH: {} # Unconstrained + CONFIG_PTR_ADDRESS: + schema: + const: 0xdeadbeef + note: "This parameter and its associated CSR shouldn't be here. See GitHub issue #53." + PRECISE_SYNCHRONOUS_EXCEPTIONS: + schema: + const: true + TRAP_ON_ECALL_FROM_M: + schema: + const: true + TRAP_ON_EBREAK: + schema: + const: true + M_MODE_ENDIANESS: + schema: + const: little + XLEN: + schema: + const: 32 requirement_groups: - name: MC-Unpriv diff --git a/arch/crd/MockCRD-1.yaml b/arch/crd/MockCRD-1.yaml new file mode 100644 index 0000000000..65f803fa02 --- /dev/null +++ b/arch/crd/MockCRD-1.yaml @@ -0,0 +1,188 @@ +# yaml-language-server: $schema=../../schemas/testplan_schema.json + +MockCRD-1: + name: MockCRD-1 + long_name: Mock CRD Long Name + + family: MockCRDFamily + + # semantic version within the CRD family + version: "1.0" + + description: | + Mock CRD description: + + * Hello + * Bob! + + # Specification versions + tsc_profile: null + unpriv_isa_manual_revision: "20191213" + priv_isa_manual_revision: "20190608-Priv-MSU-Ratified" + debug_manual_revision: "0.13.2" + +# XXX - Remove version information since specifying priv/unpriv ISA manual should imply this. + extensions: + - name: MockExt + presence: mandatory + parameters: + MOCK_ENUM_2_INTS: {} + MOCK_ENUM_2_STRINGS: {} + MOCK_BOOL_1: {} + MOCK_BOOL_2: + schema: + const: true + MOCK_1_BIT_INT: {} + MOCK_2_BIT_INT: {} + MOCK_25_BIT_INT: {} + MOCK_32_BIT_INT: + schema: + const: 0xdeadbeef + MOCK_64_BIT_INT: {} + MOCK_INT_RANGE_0_TO_127: {} + MOCK_INT_RANGE_0_TO_128: {} + MOCK_INT_RANGE_1_TO_128: {} + MOCK_INT_RANGE_0_TO_999: {} + MOCK_INT_RANGE_0_TO_1023: {} + MOCK_INT_RANGE_1000_TO_2048: {} + MOCK_ARRAY_INT_ENUM: {} + MOCK_ARRAY_BOOL_ARRAY_OF_8_FIRST_2_FALSE: {} + MOCK_ARRAY_STRING_ENUM1: + schema: + const : DEF + MOCK_ARRAY_STRING_ENUM2: + schema: + contains: { const : DEF } + - name: I + version: "~> 2.1" + presence: mandatory + note: Here's a note for the I extension. + - name: C + version: "~> 2.2" + presence: mandatory + parameters: + MUTABLE_MISA_C: + schema: + const: false + note: | + Here's a multi-line note + + for the C extension. + - name: M + presence: mandatory + version: "~> 2.0" + - name: Zicsr + version: "~> 2.0" + presence: mandatory + - name: Zicntr + version: "~> 2.0" + presence: mandatory + parameters: + TIME_CSR_IMPLEMENTED: {} # Unconstrained + - name: Sm + version: "~> 1.11" + presence: mandatory + parameters: + MTVEC_BASE_ALIGNMENT_DIRECT: {} # Unconstrained + MTVEC_BASE_ALIGNMENT_VECTORED: {} # Unconstrained + ARCH_ID: {} # Unconstrained + IMP_ID: {} # Unconstrained + VENDOR_ID_BANK: {} # Unconstrained + VENDOR_ID_OFFSET: {} # Unconstrained + MISA_CSR_IMPLEMENTED: {} # Unconstrained + MTVAL_WIDTH: {} # Unconstrained + MTVEC_MODES: + note: Here's a note for MTVEC_MODES parameter. + schema: + contains: { const : 0 } + PHYS_ADDR_WIDTH: {} # Unconstrained + PRECISE_SYNCHRONOUS_EXCEPTIONS: + schema: + const: true + TRAP_ON_ECALL_FROM_M: + schema: + const: true + TRAP_ON_EBREAK: + schema: + const: true + REPORT_VA_IN_MTVAL_ON_BREAKPOINT: + schema: + const: true + REPORT_VA_IN_MTVAL_ON_INSTRUCTION_ACCESS_FAULT: + schema: + const: true + REPORT_VA_IN_MTVAL_ON_LOAD_ACCESS_FAULT: + schema: + const: true + REPORT_VA_IN_MTVAL_ON_STORE_AMO_ACCESS_FAULT: + schema: + const: true + REPORT_ENCODING_IN_MTVAL_ON_ILLEGAL_INSTRUCTION: + schema: + const: true + M_MODE_ENDIANESS: + schema: + const: little + XLEN: + schema: + const: 32 + CONFIG_PTR_ADDRESS: + schema: + const: 0xdeadbeef + note: "This parameter and its associated CSR shouldn't be here. See GitHub issue #53." + - name: Zifencei + presence: optional + note: "Here's a note for Zifencei" + - name: Zicbop + presence: optional + note: "Testing CACHE_BLOCK_SIZE parameter which is also defined by Zicbom." + parameters: + CACHE_BLOCK_SIZE: + schema: + const: 64 + - name: Zicbom + presence: optional + note: "Testing CACHE_BLOCK_SIZE parameter which is also defined by Zicbop." + parameters: + CACHE_BLOCK_SIZE: + schema: + const: 64 + - name: Zba + presence: mandatory + version: "~> 1.0" + note: "Added these as mandatory to see if bug in profiles not listing instructions in appendix is here in CRD too." + - name: Zbb + presence: mandatory + version: "~> 1.0" + note: "Added these as mandatory to see if bug in profiles not listing instructions in appendix is here in CRD too." + - name: Zbs + presence: mandatory + version: "~> 1.0" + note: "Added these as mandatory to see if bug in profiles not listing instructions in appendix is here in CRD too." + + requirement_groups: + - name: Req-Grp-Any-XLEN + description: | + A bunch of additional requirements not associated with an extension. + requirements: + - name: REQ-ANY-XLEN-001 + description: Must pay your taxes on time + - name: REQ-ANY-XLEN-002 + description: Don't count your chickens before they're hatched! + + - name: Req-Grp-XLEN32 + when: + xlen: 32 + description: | + A bunch of additional requirements only that should show up for XLEN=32 + requirements: + - name: REQ-XLEN32-001 + description: Need lots of extra CSRs with `h` suffix + + - name: Req-Grp-XLEN64 + when: + xlen: 64 + description: | + A bunch of additional requirements only that should show up for XLEN=64 + requirements: + - name: REQ-XLEN64-001 + description: Can avoid adding extra CSRs with `h` suffix \ No newline at end of file diff --git a/arch/csc_crd_family/Microcontroller.yaml b/arch/crd_family/Microcontroller.yaml similarity index 100% rename from arch/csc_crd_family/Microcontroller.yaml rename to arch/crd_family/Microcontroller.yaml diff --git a/arch/crd_family/MockCRDFamily.yaml b/arch/crd_family/MockCRDFamily.yaml new file mode 100644 index 0000000000..d2a2bdeca7 --- /dev/null +++ b/arch/crd_family/MockCRDFamily.yaml @@ -0,0 +1,21 @@ +MockCRDFamily: + name: MockCRDFamily + long_name: Mock CRD Family Long Name + revision_history: + - version: "0.1" + date: 2024-10-04 + changes: + - Created to test CRDs + - version: "0.2" + date: 2024-10-05 + changes: + - Also created to test CRDs + + introduction: | + Here's the Mock CRD Family's introduction. + + naming_scheme: | + Here's the Mock CRD Family's naming scheme. + + mandatory_priv_modes: + - M \ No newline at end of file diff --git a/arch/csr/H/henvcfg.yaml b/arch/csr/H/henvcfg.yaml index f7587563f7..092ed3554c 100644 --- a/arch/csr/H/henvcfg.yaml +++ b/arch/csr/H/henvcfg.yaml @@ -89,7 +89,11 @@ henvcfg: priv_mode: S length: 64 - definedBy: H + definedBy: + allOf: + - name: Sm + version: ">=1.12" + - name: H fields: STCE: location: 63 diff --git a/arch/csr/H/henvcfgh.yaml b/arch/csr/H/henvcfgh.yaml new file mode 100644 index 0000000000..420e825f6d --- /dev/null +++ b/arch/csr/H/henvcfgh.yaml @@ -0,0 +1,105 @@ +# yaml-language-server: $schema=../../../schemas/csr_schema.json + +henvcfgh: + address: 0x61A + long_name: most-significant 32 bits of Hypervisor Environment Configuration + description: | + The henvcfgh CSR is a 32-bit read/write register for the most-significant 32 bits of `henvcfg`. + priv_mode: S + length: 32 + definedBy: + allOf: + - name: Sm + version: ">=1.12" + - name: H + fields: + STCE: + location: 31 + alias: henvcfg.STCE + description: | + *STimecmp Enable* + + When set, `stimecmp` is operational in VS-mode if `menvcfg.STCE` is also set. + + When `menvcfg.STCE` is zero: + * `henvcfg.STCE` reads-as-zero + * `vstimecmp` access raises an `IllegalInstruction` exception. + * `hip.VSTIP` reverts to its defined behavior as if Sstc is not implemented. + * VS-mode timer interrupts will not be generated + + When `menvcfg.STCE` is one and `henvcfg.STCE` is zero: + * Accessing `stimecmp` in VS-mode or VU-mode (really `vstimecmp`) raises a VirtualInterrupt exception + * `hip.VSTIP` reverts to its defined behavior as if Sstc is not implemented. + * VS-mode timer interrupts will not be generated + + definedBy: Sstc + type(): | + return (implemented?(ExtensionName::Sstc)) ? CsrFieldType::RO : CsrFieldType::RW; + reset_value(): | + return (implemented?(ExtensionName::Sstc)) ? UNDEFINED_LEGAL : 0; + PBMTE: + location: 30 + alias: henvcfg.PBMTE + description: | + *Page Based Memory Type Enable* + + The PBMTE bit controls whether the `Svpbmt` extension is available for use in VS-stage + address translation. + + When PBMTE=1, Svpbmt is available for VS-stage address translation. + + When PBMTE=0, the implementation behaves as though `Svpbmt` were not implemented for + VS-stage address translation. + + If `Svpbmt` is not implemented, PBMTE is read-only zero. + + `henvcfg.PBMTE` is read-as-zero if `menvcfg.PBMTE` is zero. + + If the setting of the PBMTE bit in `menvcfg` is changed, an `hfence.gvma` instruction with + _rs1_=_x0_ and _rs2_=_x0_ suffices to synchronize with respect to the altered interpretation + of G-stage and VS-stage PTEs' PBMT fields. + + By contrast, if the PBMTE bit in `henvcfg` is changed, executing an `hfence.vvma` with + _rs1_=_x0_ and _rs2_=_x0_ suffices to synchronize with respect to the altered interpretation + of VS-stage PTEs' PBMT fields for the currently active VMID. + + [NOTE] + -- + No mechanism is provided to atomically change `vsatp` and `hgatp` together. + Hence, to prevent speculative execution causing one guest's VS-stage translations to be + cached under another guest's VMID, world-switch code should zero `vsatp`, then swap `hgatp`, + then finally write the new `vsatp` value. + Similarly, if `henvcfg.PBMTE` need be world-switched, it should be switched after zeroing + `vsatp` but before writing the new `vsatp` value, obviating the need to execute an + `hfence.vvma` instruction. + -- + definedBy: Svpbmt + type(): | + return (implemented?(ExtensionName::Svpbmt)) ? CsrFieldType::RO : CsrFieldType::RW; + reset_value(): | + return (implemented?(ExtensionName::Svpbmt)) ? UNDEFINED_LEGAL : 0; + ADUE: + location: 29 + alias: henvcfg.ADUE + description: | + If the `Svadu` extension is implemented, the ADUE bit controls whether hardware updating of + PTE A/D bits is enabled for VS-stage address translation. + + When ADUE=1, hardware updating of PTE A/D bits is enabled during VS-stage address + translation, and the implementation behaves as though the Svade extension were not + implemented for VS-mode address translation. + + When ADUE=0, the implementation behaves as though Svade were implemented for VS-stage + address translation. + + If Svadu is not implemented, ADUE is read-only zero. + + Furthermore, for implementations with the hypervisor extension, henvcfg.ADUE is read-only + zero if menvcfg.ADUE is zero. + definedBy: Svadu + type(): | + return (implemented?(ExtensionName::Svadu)) ? CsrFieldType::RO : CsrFieldType::RW; + reset_value(): | + return (implemented?(ExtensionName::Svadu)) ? UNDEFINED_LEGAL : 0; + sw_read(): | + return CSR[henvcfg].sw_read()[63:32]; \ No newline at end of file diff --git a/arch/csr/H/htinst.yaml b/arch/csr/H/htinst.yaml new file mode 100644 index 0000000000..1f8752aabb --- /dev/null +++ b/arch/csr/H/htinst.yaml @@ -0,0 +1,42 @@ +# yaml-language-server: $schema=../../../schemas/csr_schema.json + +htinst: + address: 0x64a + long_name: Hypervisor Trap Instruction Register + description: | + When a trap is taken into HS-mode, mtinst is written with a value that, if nonzero, + provides information about the instruction that trapped, to assist software in handling the trap. + The values that may be written to mtinst on a trap are documented in TODO. + + htinst is a WARL register that need only be able to hold the values that the implementation may automatically write to it on a trap. + priv_mode: S + length: SXLEN + definedBy: H + fields: + VALUE: + location_rv64: 63-0 + location_rv32: 31-0 + type(): | + if ( (TINST_VALUE_ON_FINAL_LOAD_GUEST_PAGE_FAULT != "always zero") + || (TINST_VALUE_ON_FINAL_STORE_AMO_GUEST_PAGE_FAULT != "always zero") + || (TINST_VALUE_ON_FINAL_INSTRUCTION_GUEST_PAGE_FAULT != "always zero") + || (TINST_VALUE_ON_INSTRUCTION_ADDRESS_MISALIGNED != "always zero") + || (TINST_VALUE_ON_BREAKPOINT != "always zero") + || (TINST_VALUE_ON_VIRTUAL_INSTRUCTION != "always zero") + || (TINST_VALUE_ON_LOAD_ADDRESS_MISALIGNED != "always zero") + || (TINST_VALUE_ON_LOAD_ACCESS_FAULT != "always zero") + || (TINST_VALUE_ON_STORE_AMO_ADDRESS_MISALIGNED != "always zero") + || (TINST_VALUE_ON_STORE_AMO_ACCESS_FAULT != "always_zero") + || (TINST_VALUE_ON_UCALL != "always zero") + || (TINST_VALUE_ON_SCALL != "always zero") + || (TINST_VALUE_ON_MCALL != "always zero") + || (TINST_VALUE_ON_VSCALL != "always zero") + || (TINST_VALUE_ON_LOAD_PAGE_FAULT != "always zero") + || (TINST_VALUE_ON_STORE_AMO_PAGE_FAULT != "always zero")) { + return CsrFieldType::RWH; + } else { + return CsrFieldType::RO; + } + description: | + Exception-speicific information for a trap into HS-mode. + reset_value: UNDEFINED_LEGAL diff --git a/arch/csr/H/htval.yaml b/arch/csr/H/htval.yaml new file mode 100644 index 0000000000..c2fcc250e8 --- /dev/null +++ b/arch/csr/H/htval.yaml @@ -0,0 +1,34 @@ +# yaml-language-server: $schema=../../../schemas/csr_schema.json + +htval: + address: 0x643 + long_name: Hypervisor Trap Value Register + description: | + When a trap is taken into HS-mode, htval is written with additional exception-specific information, alongside stval, to assist software in handling the trap. + + When a guest-page-fault trap is taken into HS-mode, htval is written with either zero or the guest physical address that faulted, shifted right by 2 bits. For other traps, htval is set to zero, but a future standard or extension may redefine htval's setting for other traps. + + A guest-page fault may arise due to an implicit memory access during first-stage (VS-stage) address translation, in which case a guest physical address written to htval is that of the implicit memory access that faulted-for example, the address of a VS-level page table entry that could not be read. (The guest physical address corresponding to the original virtual address is unknown when VS-stage translation fails to complete.) Additional information is provided in CSR htinst to disambiguate such situations. + + Otherwise, for misaligned loads and stores that cause guest-page faults, a nonzero guest physical address in htval corresponds to the faulting portion of the access as indicated by the virtual address in stval. For instruction guest-page faults on systems with variable-length instructions, a nonzero htval corresponds to the faulting portion of the instruction as indicated by the virtual address in stval. + + htval is a WARL register that must be able to hold zero and may be capable of holding only an arbitrary subset of other 2-bit-shifted guest physical addresses, if any. + priv_mode: M + length: MXLEN + definedBy: H + fields: + VALUE: + location_rv64: 63-0 + location_rv32: 31-0 + type(): | + if (REPORT_GPA_IN_TVAL_ON_LOAD_GUEST_PAGE_FAULT + || REPORT_GPA_IN_TVAL_ON_STORE_AMO_GUEST_PAGE_FAULT + || REPORT_GPA_IN_TVAL_ON_INSTRUCTION_GUEST_PAGE_FAULT + || REPORT_GPA_IN_TVAL_ON_INTERMEDIATE_GUEST_PAGE_FAULT) { + return CsrFieldType::RWH; + } else { + return CsrFieldType::RO; + } + description: | + Exception-speicific information for a trap into M-mode. + reset_value: UNDEFINED_LEGAL diff --git a/arch/csr/H/mtinst.yaml b/arch/csr/H/mtinst.yaml new file mode 100644 index 0000000000..ff3f34ed6a --- /dev/null +++ b/arch/csr/H/mtinst.yaml @@ -0,0 +1,42 @@ +# yaml-language-server: $schema=../../../schemas/csr_schema.json + +mtinst: + address: 0x34a + long_name: Machine Trap Instruction Register + description: | + When a trap is taken into M-mode, mtinst is written with a value that, if nonzero, + provides information about the instruction that trapped, to assist software in handling the trap. + The values that may be written to mtinst on a trap are documented in TODO. + + mtinst is a WARL register that need only be able to hold the values that the implementation may automatically write to it on a trap. + priv_mode: M + length: MXLEN + definedBy: H + fields: + VALUE: + location_rv64: 63-0 + location_rv32: 31-0 + type(): | + if ( (TINST_VALUE_ON_FINAL_LOAD_GUEST_PAGE_FAULT != "always zero") + || (TINST_VALUE_ON_FINAL_STORE_AMO_GUEST_PAGE_FAULT != "always zero") + || (TINST_VALUE_ON_FINAL_INSTRUCTION_GUEST_PAGE_FAULT != "always zero") + || (TINST_VALUE_ON_INSTRUCTION_ADDRESS_MISALIGNED != "always zero") + || (TINST_VALUE_ON_BREAKPOINT != "always zero") + || (TINST_VALUE_ON_VIRTUAL_INSTRUCTION != "always zero") + || (TINST_VALUE_ON_LOAD_ADDRESS_MISALIGNED != "always zero") + || (TINST_VALUE_ON_LOAD_ACCESS_FAULT != "always zero") + || (TINST_VALUE_ON_STORE_AMO_ADDRESS_MISALIGNED != "always zero") + || (TINST_VALUE_ON_STORE_AMO_ACCESS_FAULT != "always_zero") + || (TINST_VALUE_ON_UCALL != "always zero") + || (TINST_VALUE_ON_SCALL != "always zero") + || (TINST_VALUE_ON_MCALL != "always zero") + || (TINST_VALUE_ON_VSCALL != "always zero") + || (TINST_VALUE_ON_LOAD_PAGE_FAULT != "always zero") + || (TINST_VALUE_ON_STORE_AMO_PAGE_FAULT != "always zero")) { + return CsrFieldType::RWH; + } else { + return CsrFieldType::RO; + } + description: | + Exception-speicific information for a trap into M-mode. + reset_value: UNDEFINED_LEGAL diff --git a/arch/csr/H/mtval2.yaml b/arch/csr/H/mtval2.yaml new file mode 100644 index 0000000000..a80228520b --- /dev/null +++ b/arch/csr/H/mtval2.yaml @@ -0,0 +1,35 @@ +# yaml-language-server: $schema=../../../schemas/csr_schema.json + +mtval2: + address: 0x34b + long_name: Machine Second Trap Value Register + description: | + When a trap is taken into M-mode from a virtual mode, mtval2 is written with additional exception-specific information, + alongside mtval, to assist software in handling the trap. + + When a guest-page-fault trap is taken into M-mode, mtval2 is written with either zero or the guest physical address that faulted, shifted right by 2 bits. For other traps, mtval2 is set to zero, but a future standard or extension may redefine mtval2's setting for other traps. + + If a guest-page fault is due to an implicit memory access during first-stage (VS-stage) address translation, a guest physical address written to mtval2 is that of the implicit memory access that faulted. Additional information is provided in CSR mtinst to disambiguate such situations. + + Otherwise, for misaligned loads and stores that cause guest-page faults, a nonzero guest physical address in mtval2 corresponds to the faulting portion of the access as indicated by the virtual address in mtval. For instruction guest-page faults on systems with variable-length instructions, a nonzero mtval2 corresponds to the faulting portion of the instruction as indicated by the virtual address in mtval. + + mtval2 is a WARL register that must be able to hold zero and may be capable of holding only an arbitrary subset of other 2-bit-shifted guest physical addresses, if any. + priv_mode: M + length: MXLEN + definedBy: H + fields: + VALUE: + location_rv64: 63-0 + location_rv32: 31-0 + type(): | + if (REPORT_GPA_IN_TVAL_ON_LOAD_GUEST_PAGE_FAULT + || REPORT_GPA_IN_TVAL_ON_STORE_AMO_GUEST_PAGE_FAULT + || REPORT_GPA_IN_TVAL_ON_INSTRUCTION_GUEST_PAGE_FAULT + || REPORT_GPA_IN_TVAL_ON_INTERMEDIATE_GUEST_PAGE_FAULT) { + return CsrFieldType::RWH; + } else { + return CsrFieldType::RO; + } + description: | + Exception-speicific information for a trap into M-mode. + reset_value: UNDEFINED_LEGAL diff --git a/arch/csr/H/vsatp.yaml b/arch/csr/H/vsatp.yaml index 20be306f17..e70d506dee 100644 --- a/arch/csr/H/vsatp.yaml +++ b/arch/csr/H/vsatp.yaml @@ -1,4 +1,4 @@ -# yaml-language-server: $schema=../../schemas/csr_schema.json +# yaml-language-server: $schema=../../../schemas/csr_schema.json vsatp: address: 0x280 @@ -94,7 +94,7 @@ vsatp: return UNDEFINED_LEGAL_DETERMINISTIC; } } else { - XReg shamt = (CSR[mstatus].SXL == $bits(XRegWidth::XLEN64)) ? 16 : 9; + XReg shamt = ((XLEN == 32) || (CSR[mstatus].SXL == $bits(XRegWidth::XLEN32))) ? 9 : 16; XReg all_ones = ((1 << shamt) - 1); XReg largest_allowed_asid = (1 << shamt) - 1; diff --git a/arch/csr/I/pmpaddr0.yaml b/arch/csr/I/pmpaddr0.yaml index fd9ff48c0a..9a815baaba 100644 --- a/arch/csr/I/pmpaddr0.yaml +++ b/arch/csr/I/pmpaddr0.yaml @@ -10,7 +10,7 @@ pmpaddr0: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr1.yaml b/arch/csr/I/pmpaddr1.yaml index 39a8996a56..2b080f834c 100644 --- a/arch/csr/I/pmpaddr1.yaml +++ b/arch/csr/I/pmpaddr1.yaml @@ -10,7 +10,7 @@ pmpaddr1: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr10.yaml b/arch/csr/I/pmpaddr10.yaml index 31fca18c4f..f67f9d1017 100644 --- a/arch/csr/I/pmpaddr10.yaml +++ b/arch/csr/I/pmpaddr10.yaml @@ -10,7 +10,7 @@ pmpaddr10: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr11.yaml b/arch/csr/I/pmpaddr11.yaml index 6a76f247b0..40b919eb6b 100644 --- a/arch/csr/I/pmpaddr11.yaml +++ b/arch/csr/I/pmpaddr11.yaml @@ -10,7 +10,7 @@ pmpaddr11: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr12.yaml b/arch/csr/I/pmpaddr12.yaml index 778f8e8346..ed641e701a 100644 --- a/arch/csr/I/pmpaddr12.yaml +++ b/arch/csr/I/pmpaddr12.yaml @@ -10,7 +10,7 @@ pmpaddr12: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr13.yaml b/arch/csr/I/pmpaddr13.yaml index 4fac6b2f0f..e78733593d 100644 --- a/arch/csr/I/pmpaddr13.yaml +++ b/arch/csr/I/pmpaddr13.yaml @@ -10,7 +10,7 @@ pmpaddr13: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr14.yaml b/arch/csr/I/pmpaddr14.yaml index 65fdfe5b6e..34c46b1b38 100644 --- a/arch/csr/I/pmpaddr14.yaml +++ b/arch/csr/I/pmpaddr14.yaml @@ -10,7 +10,7 @@ pmpaddr14: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr15.yaml b/arch/csr/I/pmpaddr15.yaml index 5cc52450f0..1df6a76404 100644 --- a/arch/csr/I/pmpaddr15.yaml +++ b/arch/csr/I/pmpaddr15.yaml @@ -10,7 +10,7 @@ pmpaddr15: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr16.yaml b/arch/csr/I/pmpaddr16.yaml index 77c2bf7451..f06f3aaae5 100644 --- a/arch/csr/I/pmpaddr16.yaml +++ b/arch/csr/I/pmpaddr16.yaml @@ -10,7 +10,7 @@ pmpaddr16: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr17.yaml b/arch/csr/I/pmpaddr17.yaml index 95cebc16c3..bae6ef27f1 100644 --- a/arch/csr/I/pmpaddr17.yaml +++ b/arch/csr/I/pmpaddr17.yaml @@ -10,7 +10,7 @@ pmpaddr17: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr18.yaml b/arch/csr/I/pmpaddr18.yaml index 607cb2a0a7..886d8974b9 100644 --- a/arch/csr/I/pmpaddr18.yaml +++ b/arch/csr/I/pmpaddr18.yaml @@ -10,7 +10,7 @@ pmpaddr18: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr19.yaml b/arch/csr/I/pmpaddr19.yaml index 761e26d0eb..a9e11125d4 100644 --- a/arch/csr/I/pmpaddr19.yaml +++ b/arch/csr/I/pmpaddr19.yaml @@ -10,7 +10,7 @@ pmpaddr19: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr2.yaml b/arch/csr/I/pmpaddr2.yaml index de41750ce2..66293dfc9d 100644 --- a/arch/csr/I/pmpaddr2.yaml +++ b/arch/csr/I/pmpaddr2.yaml @@ -10,7 +10,7 @@ pmpaddr2: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr20.yaml b/arch/csr/I/pmpaddr20.yaml index b6a998c650..db5aa69779 100644 --- a/arch/csr/I/pmpaddr20.yaml +++ b/arch/csr/I/pmpaddr20.yaml @@ -10,7 +10,7 @@ pmpaddr20: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr21.yaml b/arch/csr/I/pmpaddr21.yaml index 5e1ad33451..91a2a945f8 100644 --- a/arch/csr/I/pmpaddr21.yaml +++ b/arch/csr/I/pmpaddr21.yaml @@ -10,7 +10,7 @@ pmpaddr21: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr22.yaml b/arch/csr/I/pmpaddr22.yaml index 1f4cdf01ab..bc8712a74d 100644 --- a/arch/csr/I/pmpaddr22.yaml +++ b/arch/csr/I/pmpaddr22.yaml @@ -10,7 +10,7 @@ pmpaddr22: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr23.yaml b/arch/csr/I/pmpaddr23.yaml index 8b3141566f..0889486c7f 100644 --- a/arch/csr/I/pmpaddr23.yaml +++ b/arch/csr/I/pmpaddr23.yaml @@ -10,7 +10,7 @@ pmpaddr23: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr24.yaml b/arch/csr/I/pmpaddr24.yaml index fa891d88be..9c141ba886 100644 --- a/arch/csr/I/pmpaddr24.yaml +++ b/arch/csr/I/pmpaddr24.yaml @@ -10,7 +10,7 @@ pmpaddr24: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr25.yaml b/arch/csr/I/pmpaddr25.yaml index 986811c4dd..ae76faa86f 100644 --- a/arch/csr/I/pmpaddr25.yaml +++ b/arch/csr/I/pmpaddr25.yaml @@ -10,7 +10,7 @@ pmpaddr25: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr26.yaml b/arch/csr/I/pmpaddr26.yaml index eb24a27a8d..8a90006b45 100644 --- a/arch/csr/I/pmpaddr26.yaml +++ b/arch/csr/I/pmpaddr26.yaml @@ -10,7 +10,7 @@ pmpaddr26: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr27.yaml b/arch/csr/I/pmpaddr27.yaml index 7e360369fb..cb8aa64621 100644 --- a/arch/csr/I/pmpaddr27.yaml +++ b/arch/csr/I/pmpaddr27.yaml @@ -10,7 +10,7 @@ pmpaddr27: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr28.yaml b/arch/csr/I/pmpaddr28.yaml index 45fc737416..99f3b5bd2b 100644 --- a/arch/csr/I/pmpaddr28.yaml +++ b/arch/csr/I/pmpaddr28.yaml @@ -10,7 +10,7 @@ pmpaddr28: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr29.yaml b/arch/csr/I/pmpaddr29.yaml index 411f7fe635..bc8f086817 100644 --- a/arch/csr/I/pmpaddr29.yaml +++ b/arch/csr/I/pmpaddr29.yaml @@ -10,7 +10,7 @@ pmpaddr29: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr3.yaml b/arch/csr/I/pmpaddr3.yaml index d1ca6017f5..c45b0de9e3 100644 --- a/arch/csr/I/pmpaddr3.yaml +++ b/arch/csr/I/pmpaddr3.yaml @@ -10,7 +10,7 @@ pmpaddr3: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr30.yaml b/arch/csr/I/pmpaddr30.yaml index 8607ff5351..fd640439a3 100644 --- a/arch/csr/I/pmpaddr30.yaml +++ b/arch/csr/I/pmpaddr30.yaml @@ -10,7 +10,7 @@ pmpaddr30: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr31.yaml b/arch/csr/I/pmpaddr31.yaml index 4ece09c90b..a792fe968c 100644 --- a/arch/csr/I/pmpaddr31.yaml +++ b/arch/csr/I/pmpaddr31.yaml @@ -10,7 +10,7 @@ pmpaddr31: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr32.yaml b/arch/csr/I/pmpaddr32.yaml index f050efe6b3..a920f8038b 100644 --- a/arch/csr/I/pmpaddr32.yaml +++ b/arch/csr/I/pmpaddr32.yaml @@ -10,7 +10,7 @@ pmpaddr32: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr33.yaml b/arch/csr/I/pmpaddr33.yaml index 53eddb7d82..cb52c645da 100644 --- a/arch/csr/I/pmpaddr33.yaml +++ b/arch/csr/I/pmpaddr33.yaml @@ -10,7 +10,7 @@ pmpaddr33: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr34.yaml b/arch/csr/I/pmpaddr34.yaml index 9663dda3e9..e993aeb348 100644 --- a/arch/csr/I/pmpaddr34.yaml +++ b/arch/csr/I/pmpaddr34.yaml @@ -10,7 +10,7 @@ pmpaddr34: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr35.yaml b/arch/csr/I/pmpaddr35.yaml index 601d9c263a..e8a742e7b6 100644 --- a/arch/csr/I/pmpaddr35.yaml +++ b/arch/csr/I/pmpaddr35.yaml @@ -10,7 +10,7 @@ pmpaddr35: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr36.yaml b/arch/csr/I/pmpaddr36.yaml index 4df3ceea33..24542cd14f 100644 --- a/arch/csr/I/pmpaddr36.yaml +++ b/arch/csr/I/pmpaddr36.yaml @@ -10,7 +10,7 @@ pmpaddr36: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr37.yaml b/arch/csr/I/pmpaddr37.yaml index d4b39b5081..32cdf97a2a 100644 --- a/arch/csr/I/pmpaddr37.yaml +++ b/arch/csr/I/pmpaddr37.yaml @@ -10,7 +10,7 @@ pmpaddr37: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr38.yaml b/arch/csr/I/pmpaddr38.yaml index 7dd35b7420..709a5ca5e1 100644 --- a/arch/csr/I/pmpaddr38.yaml +++ b/arch/csr/I/pmpaddr38.yaml @@ -10,7 +10,7 @@ pmpaddr38: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr39.yaml b/arch/csr/I/pmpaddr39.yaml index 481ddbfef2..15f0ac6923 100644 --- a/arch/csr/I/pmpaddr39.yaml +++ b/arch/csr/I/pmpaddr39.yaml @@ -10,7 +10,7 @@ pmpaddr39: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr4.yaml b/arch/csr/I/pmpaddr4.yaml index acdf87b02f..3e04fa08f7 100644 --- a/arch/csr/I/pmpaddr4.yaml +++ b/arch/csr/I/pmpaddr4.yaml @@ -10,7 +10,7 @@ pmpaddr4: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr40.yaml b/arch/csr/I/pmpaddr40.yaml index bb51e56f86..d065fb1390 100644 --- a/arch/csr/I/pmpaddr40.yaml +++ b/arch/csr/I/pmpaddr40.yaml @@ -10,7 +10,7 @@ pmpaddr40: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr41.yaml b/arch/csr/I/pmpaddr41.yaml index da5677c616..a32acf4f61 100644 --- a/arch/csr/I/pmpaddr41.yaml +++ b/arch/csr/I/pmpaddr41.yaml @@ -10,7 +10,7 @@ pmpaddr41: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr42.yaml b/arch/csr/I/pmpaddr42.yaml index 746cf3f97b..08ff950cf2 100644 --- a/arch/csr/I/pmpaddr42.yaml +++ b/arch/csr/I/pmpaddr42.yaml @@ -10,7 +10,7 @@ pmpaddr42: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr43.yaml b/arch/csr/I/pmpaddr43.yaml index 18d13f3dd8..3033b1f9fe 100644 --- a/arch/csr/I/pmpaddr43.yaml +++ b/arch/csr/I/pmpaddr43.yaml @@ -10,7 +10,7 @@ pmpaddr43: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr44.yaml b/arch/csr/I/pmpaddr44.yaml index 6032a94c3e..85b5c1bf83 100644 --- a/arch/csr/I/pmpaddr44.yaml +++ b/arch/csr/I/pmpaddr44.yaml @@ -10,7 +10,7 @@ pmpaddr44: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr45.yaml b/arch/csr/I/pmpaddr45.yaml index 7de68282c0..916b87e2f1 100644 --- a/arch/csr/I/pmpaddr45.yaml +++ b/arch/csr/I/pmpaddr45.yaml @@ -10,7 +10,7 @@ pmpaddr45: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr46.yaml b/arch/csr/I/pmpaddr46.yaml index d66cfe51d0..7bc21d2d76 100644 --- a/arch/csr/I/pmpaddr46.yaml +++ b/arch/csr/I/pmpaddr46.yaml @@ -10,7 +10,7 @@ pmpaddr46: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr47.yaml b/arch/csr/I/pmpaddr47.yaml index 4441193742..dd843a70c1 100644 --- a/arch/csr/I/pmpaddr47.yaml +++ b/arch/csr/I/pmpaddr47.yaml @@ -10,7 +10,7 @@ pmpaddr47: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr48.yaml b/arch/csr/I/pmpaddr48.yaml index b4ec14e0e9..ace42b7db2 100644 --- a/arch/csr/I/pmpaddr48.yaml +++ b/arch/csr/I/pmpaddr48.yaml @@ -10,7 +10,7 @@ pmpaddr48: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr49.yaml b/arch/csr/I/pmpaddr49.yaml index 24f17737f5..d74fdebc9d 100644 --- a/arch/csr/I/pmpaddr49.yaml +++ b/arch/csr/I/pmpaddr49.yaml @@ -10,7 +10,7 @@ pmpaddr49: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr5.yaml b/arch/csr/I/pmpaddr5.yaml index 219a03e069..b3cbbebe56 100644 --- a/arch/csr/I/pmpaddr5.yaml +++ b/arch/csr/I/pmpaddr5.yaml @@ -10,7 +10,7 @@ pmpaddr5: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr50.yaml b/arch/csr/I/pmpaddr50.yaml index ca359d7370..649ad63dc7 100644 --- a/arch/csr/I/pmpaddr50.yaml +++ b/arch/csr/I/pmpaddr50.yaml @@ -10,7 +10,7 @@ pmpaddr50: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr51.yaml b/arch/csr/I/pmpaddr51.yaml index 90569fcd2d..047fa2a562 100644 --- a/arch/csr/I/pmpaddr51.yaml +++ b/arch/csr/I/pmpaddr51.yaml @@ -10,7 +10,7 @@ pmpaddr51: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr52.yaml b/arch/csr/I/pmpaddr52.yaml index 208ed90e60..bb9a659e55 100644 --- a/arch/csr/I/pmpaddr52.yaml +++ b/arch/csr/I/pmpaddr52.yaml @@ -10,7 +10,7 @@ pmpaddr52: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr53.yaml b/arch/csr/I/pmpaddr53.yaml index 8db73b4f28..f9fd91c6d7 100644 --- a/arch/csr/I/pmpaddr53.yaml +++ b/arch/csr/I/pmpaddr53.yaml @@ -10,7 +10,7 @@ pmpaddr53: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr54.yaml b/arch/csr/I/pmpaddr54.yaml index 131579cf98..864d0155d2 100644 --- a/arch/csr/I/pmpaddr54.yaml +++ b/arch/csr/I/pmpaddr54.yaml @@ -10,7 +10,7 @@ pmpaddr54: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr55.yaml b/arch/csr/I/pmpaddr55.yaml index 7021837afa..ebfc4ed9c2 100644 --- a/arch/csr/I/pmpaddr55.yaml +++ b/arch/csr/I/pmpaddr55.yaml @@ -10,7 +10,7 @@ pmpaddr55: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr56.yaml b/arch/csr/I/pmpaddr56.yaml index ace37085ee..9f6aa90930 100644 --- a/arch/csr/I/pmpaddr56.yaml +++ b/arch/csr/I/pmpaddr56.yaml @@ -10,7 +10,7 @@ pmpaddr56: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr57.yaml b/arch/csr/I/pmpaddr57.yaml index c35aad2650..68ce2873e7 100644 --- a/arch/csr/I/pmpaddr57.yaml +++ b/arch/csr/I/pmpaddr57.yaml @@ -10,7 +10,7 @@ pmpaddr57: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr58.yaml b/arch/csr/I/pmpaddr58.yaml index 0d7754217c..4c41b889a5 100644 --- a/arch/csr/I/pmpaddr58.yaml +++ b/arch/csr/I/pmpaddr58.yaml @@ -10,7 +10,7 @@ pmpaddr58: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr59.yaml b/arch/csr/I/pmpaddr59.yaml index 534e1eea9b..9ca64d0558 100644 --- a/arch/csr/I/pmpaddr59.yaml +++ b/arch/csr/I/pmpaddr59.yaml @@ -10,7 +10,7 @@ pmpaddr59: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr6.yaml b/arch/csr/I/pmpaddr6.yaml index 4b868532ed..dc3c12f294 100644 --- a/arch/csr/I/pmpaddr6.yaml +++ b/arch/csr/I/pmpaddr6.yaml @@ -10,7 +10,7 @@ pmpaddr6: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr60.yaml b/arch/csr/I/pmpaddr60.yaml index 9cd342303a..eb3153bbfb 100644 --- a/arch/csr/I/pmpaddr60.yaml +++ b/arch/csr/I/pmpaddr60.yaml @@ -10,7 +10,7 @@ pmpaddr60: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr61.yaml b/arch/csr/I/pmpaddr61.yaml index 921e7806e6..3869c19496 100644 --- a/arch/csr/I/pmpaddr61.yaml +++ b/arch/csr/I/pmpaddr61.yaml @@ -10,7 +10,7 @@ pmpaddr61: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr62.yaml b/arch/csr/I/pmpaddr62.yaml index 5dd87d4962..1564bc57fe 100644 --- a/arch/csr/I/pmpaddr62.yaml +++ b/arch/csr/I/pmpaddr62.yaml @@ -10,7 +10,7 @@ pmpaddr62: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr63.yaml b/arch/csr/I/pmpaddr63.yaml index 4c939264cc..1179249210 100644 --- a/arch/csr/I/pmpaddr63.yaml +++ b/arch/csr/I/pmpaddr63.yaml @@ -10,7 +10,7 @@ pmpaddr63: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr7.yaml b/arch/csr/I/pmpaddr7.yaml index b94610c56e..209895ad28 100644 --- a/arch/csr/I/pmpaddr7.yaml +++ b/arch/csr/I/pmpaddr7.yaml @@ -10,7 +10,7 @@ pmpaddr7: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr8.yaml b/arch/csr/I/pmpaddr8.yaml index c36b4a9882..2ebaf11a56 100644 --- a/arch/csr/I/pmpaddr8.yaml +++ b/arch/csr/I/pmpaddr8.yaml @@ -10,7 +10,7 @@ pmpaddr8: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddr9.yaml b/arch/csr/I/pmpaddr9.yaml index f603a10ae3..51014c287d 100644 --- a/arch/csr/I/pmpaddr9.yaml +++ b/arch/csr/I/pmpaddr9.yaml @@ -10,7 +10,7 @@ pmpaddr9: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpaddrN.layout b/arch/csr/I/pmpaddrN.layout index faf75227be..31fbfc1e06 100644 --- a/arch/csr/I/pmpaddrN.layout +++ b/arch/csr/I/pmpaddrN.layout @@ -12,7 +12,7 @@ pmpaddr<%= pmpaddr_num %>: priv_mode: M length: MXLEN description: PMP entry address - definedBy: Sm + definedBy: Smpmp fields: ADDR: location_rv32: 31-0 diff --git a/arch/csr/I/pmpcfg0.yaml b/arch/csr/I/pmpcfg0.yaml index 752310fc8f..2c9ff29c8f 100644 --- a/arch/csr/I/pmpcfg0.yaml +++ b/arch/csr/I/pmpcfg0.yaml @@ -10,7 +10,7 @@ pmpcfg0: priv_mode: M length: MXLEN description: PMP entry configuration - definedBy: Sm + definedBy: Smpmp fields: pmp0cfg: location: 7-0 diff --git a/arch/csr/I/pmpcfg1.yaml b/arch/csr/I/pmpcfg1.yaml index acab3d9fd2..47061f3d3b 100644 --- a/arch/csr/I/pmpcfg1.yaml +++ b/arch/csr/I/pmpcfg1.yaml @@ -11,7 +11,7 @@ pmpcfg1: priv_mode: M length: MXLEN description: PMP entry configuration - definedBy: Sm + definedBy: Smpmp fields: pmp4cfg: location: 7-0 diff --git a/arch/csr/I/pmpcfg10.yaml b/arch/csr/I/pmpcfg10.yaml index cb133c3d02..eca9a60298 100644 --- a/arch/csr/I/pmpcfg10.yaml +++ b/arch/csr/I/pmpcfg10.yaml @@ -10,7 +10,7 @@ pmpcfg10: priv_mode: M length: MXLEN description: PMP entry configuration - definedBy: Sm + definedBy: Smpmp fields: pmp40cfg: location: 7-0 diff --git a/arch/csr/I/pmpcfg11.yaml b/arch/csr/I/pmpcfg11.yaml index b1c29a8206..63d38cc491 100644 --- a/arch/csr/I/pmpcfg11.yaml +++ b/arch/csr/I/pmpcfg11.yaml @@ -11,7 +11,7 @@ pmpcfg11: priv_mode: M length: MXLEN description: PMP entry configuration - definedBy: Sm + definedBy: Smpmp fields: pmp44cfg: location: 7-0 diff --git a/arch/csr/I/pmpcfg12.yaml b/arch/csr/I/pmpcfg12.yaml index 6432d371f5..15b3c2143d 100644 --- a/arch/csr/I/pmpcfg12.yaml +++ b/arch/csr/I/pmpcfg12.yaml @@ -10,7 +10,7 @@ pmpcfg12: priv_mode: M length: MXLEN description: PMP entry configuration - definedBy: Sm + definedBy: Smpmp fields: pmp48cfg: location: 7-0 diff --git a/arch/csr/I/pmpcfg13.yaml b/arch/csr/I/pmpcfg13.yaml index 8f2e1883e3..7b418cf864 100644 --- a/arch/csr/I/pmpcfg13.yaml +++ b/arch/csr/I/pmpcfg13.yaml @@ -11,7 +11,7 @@ pmpcfg13: priv_mode: M length: MXLEN description: PMP entry configuration - definedBy: Sm + definedBy: Smpmp fields: pmp52cfg: location: 7-0 diff --git a/arch/csr/I/pmpcfg14.yaml b/arch/csr/I/pmpcfg14.yaml index 821f21f49a..699900afe6 100644 --- a/arch/csr/I/pmpcfg14.yaml +++ b/arch/csr/I/pmpcfg14.yaml @@ -10,7 +10,7 @@ pmpcfg14: priv_mode: M length: MXLEN description: PMP entry configuration - definedBy: Sm + definedBy: Smpmp fields: pmp56cfg: location: 7-0 diff --git a/arch/csr/I/pmpcfg15.yaml b/arch/csr/I/pmpcfg15.yaml index dce38f7b0f..58f9a8d165 100644 --- a/arch/csr/I/pmpcfg15.yaml +++ b/arch/csr/I/pmpcfg15.yaml @@ -11,7 +11,7 @@ pmpcfg15: priv_mode: M length: MXLEN description: PMP entry configuration - definedBy: Sm + definedBy: Smpmp fields: pmp60cfg: location: 7-0 diff --git a/arch/csr/I/pmpcfg2.yaml b/arch/csr/I/pmpcfg2.yaml index 35f6b59983..4efc7473f8 100644 --- a/arch/csr/I/pmpcfg2.yaml +++ b/arch/csr/I/pmpcfg2.yaml @@ -10,7 +10,7 @@ pmpcfg2: priv_mode: M length: MXLEN description: PMP entry configuration - definedBy: Sm + definedBy: Smpmp fields: pmp8cfg: location: 7-0 diff --git a/arch/csr/I/pmpcfg3.yaml b/arch/csr/I/pmpcfg3.yaml index d6e72c9b4c..c118f5d90f 100644 --- a/arch/csr/I/pmpcfg3.yaml +++ b/arch/csr/I/pmpcfg3.yaml @@ -11,7 +11,7 @@ pmpcfg3: priv_mode: M length: MXLEN description: PMP entry configuration - definedBy: Sm + definedBy: Smpmp fields: pmp12cfg: location: 7-0 diff --git a/arch/csr/I/pmpcfg4.yaml b/arch/csr/I/pmpcfg4.yaml index 3e7505f66e..e1739752ad 100644 --- a/arch/csr/I/pmpcfg4.yaml +++ b/arch/csr/I/pmpcfg4.yaml @@ -10,7 +10,7 @@ pmpcfg4: priv_mode: M length: MXLEN description: PMP entry configuration - definedBy: Sm + definedBy: Smpmp fields: pmp16cfg: location: 7-0 diff --git a/arch/csr/I/pmpcfg5.yaml b/arch/csr/I/pmpcfg5.yaml index 4efd2b8ddf..9a4ff20f1c 100644 --- a/arch/csr/I/pmpcfg5.yaml +++ b/arch/csr/I/pmpcfg5.yaml @@ -11,7 +11,7 @@ pmpcfg5: priv_mode: M length: MXLEN description: PMP entry configuration - definedBy: Sm + definedBy: Smpmp fields: pmp20cfg: location: 7-0 diff --git a/arch/csr/I/pmpcfg6.yaml b/arch/csr/I/pmpcfg6.yaml index 842d937f86..c4f98dcf4f 100644 --- a/arch/csr/I/pmpcfg6.yaml +++ b/arch/csr/I/pmpcfg6.yaml @@ -10,7 +10,7 @@ pmpcfg6: priv_mode: M length: MXLEN description: PMP entry configuration - definedBy: Sm + definedBy: Smpmp fields: pmp24cfg: location: 7-0 diff --git a/arch/csr/I/pmpcfg7.yaml b/arch/csr/I/pmpcfg7.yaml index e11ea57832..6bc3cc76e2 100644 --- a/arch/csr/I/pmpcfg7.yaml +++ b/arch/csr/I/pmpcfg7.yaml @@ -11,7 +11,7 @@ pmpcfg7: priv_mode: M length: MXLEN description: PMP entry configuration - definedBy: Sm + definedBy: Smpmp fields: pmp28cfg: location: 7-0 diff --git a/arch/csr/I/pmpcfg8.yaml b/arch/csr/I/pmpcfg8.yaml index a65bb27a71..3f339a2e17 100644 --- a/arch/csr/I/pmpcfg8.yaml +++ b/arch/csr/I/pmpcfg8.yaml @@ -10,7 +10,7 @@ pmpcfg8: priv_mode: M length: MXLEN description: PMP entry configuration - definedBy: Sm + definedBy: Smpmp fields: pmp32cfg: location: 7-0 diff --git a/arch/csr/I/pmpcfg9.yaml b/arch/csr/I/pmpcfg9.yaml index 6a44984abc..768794a7ef 100644 --- a/arch/csr/I/pmpcfg9.yaml +++ b/arch/csr/I/pmpcfg9.yaml @@ -11,7 +11,7 @@ pmpcfg9: priv_mode: M length: MXLEN description: PMP entry configuration - definedBy: Sm + definedBy: Smpmp fields: pmp36cfg: location: 7-0 diff --git a/arch/csr/I/pmpcfgN.layout b/arch/csr/I/pmpcfgN.layout index 67bc769448..da1dd4a850 100644 --- a/arch/csr/I/pmpcfgN.layout +++ b/arch/csr/I/pmpcfgN.layout @@ -11,7 +11,7 @@ pmpcfg<%= pmpcfg_num %>: priv_mode: M length: MXLEN description: PMP entry configuration - definedBy: Sm + definedBy: Smpmp fields: <%- (pmpcfg_num.odd? ? 4 : 8).times do |i| -%> pmp<%= pmpcfg_num*4 + i %>cfg: diff --git a/arch/csr/Zicntr/mcountinhibit.layout b/arch/csr/Zicntr/mcountinhibit.layout index 4327a71a03..9fe4b431a6 100644 --- a/arch/csr/Zicntr/mcountinhibit.layout +++ b/arch/csr/Zicntr/mcountinhibit.layout @@ -37,10 +37,14 @@ mcountinhibit: cannot be inhibited with the `mcountinhibit` mechanism. ==== - definedBy: [Zicntr, Zihpm] + definedBy: + anyOf: + - name: Sm + - name: Smhpm fields: CY: location: 0 + definedBy: Sm description: When set, `mcycle.COUNT` stops counting in all privilege modes. type(): | return COUNTINHIBIT_EN[0] ? CsrFieldType::RW : CsrFieldType::RO; @@ -48,6 +52,7 @@ mcountinhibit: return COUNTINHIBIT_EN[0] ? UNDEFINED_LEGAL : 0; IR: location: 2 + definedBy: Sm description: When set, `minstret.COUNT` stops counting in all privilege modes. type(): | return COUNTINHIBIT_EN[2] ? CsrFieldType::RW : CsrFieldType::RO; @@ -56,6 +61,7 @@ mcountinhibit: <%- (3..31).each do |hpm_num| -%> HPM<%= hpm_num %>: location: <%= hpm_num %> + definedBy: Smhpm description: | [when="COUNTINHIBIT_EN[<%= hpm_num %>] == true"] When set, `hpmcounter<%= hpm_num %>.COUNT` stops counting in all privilege modes. diff --git a/arch/csr/Zicntr/mcountinhibit.yaml b/arch/csr/Zicntr/mcountinhibit.yaml index 6373c23d69..6d3f1e5957 100644 --- a/arch/csr/Zicntr/mcountinhibit.yaml +++ b/arch/csr/Zicntr/mcountinhibit.yaml @@ -40,10 +40,14 @@ mcountinhibit: cannot be inhibited with the `mcountinhibit` mechanism. ==== - definedBy: [Zicntr, Zihpm] + definedBy: + anyOf: + - name: Sm + - name: Smhpm fields: CY: location: 0 + definedBy: Sm description: When set, `mcycle.COUNT` stops counting in all privilege modes. type(): | return COUNTINHIBIT_EN[0] ? CsrFieldType::RW : CsrFieldType::RO; @@ -51,6 +55,7 @@ mcountinhibit: return COUNTINHIBIT_EN[0] ? UNDEFINED_LEGAL : 0; IR: location: 2 + definedBy: Sm description: When set, `minstret.COUNT` stops counting in all privilege modes. type(): | return COUNTINHIBIT_EN[2] ? CsrFieldType::RW : CsrFieldType::RO; @@ -58,6 +63,7 @@ mcountinhibit: return COUNTINHIBIT_EN[2] ? UNDEFINED_LEGAL : 0; HPM3: location: 3 + definedBy: Smhpm description: | [when="COUNTINHIBIT_EN[3] == true"] When set, `hpmcounter3.COUNT` stops counting in all privilege modes. @@ -70,6 +76,7 @@ mcountinhibit: return COUNTINHIBIT_EN[3] ? UNDEFINED_LEGAL : 0; HPM4: location: 4 + definedBy: Smhpm description: | [when="COUNTINHIBIT_EN[4] == true"] When set, `hpmcounter4.COUNT` stops counting in all privilege modes. @@ -82,6 +89,7 @@ mcountinhibit: return COUNTINHIBIT_EN[4] ? UNDEFINED_LEGAL : 0; HPM5: location: 5 + definedBy: Smhpm description: | [when="COUNTINHIBIT_EN[5] == true"] When set, `hpmcounter5.COUNT` stops counting in all privilege modes. @@ -94,6 +102,7 @@ mcountinhibit: return COUNTINHIBIT_EN[5] ? UNDEFINED_LEGAL : 0; HPM6: location: 6 + definedBy: Smhpm description: | [when="COUNTINHIBIT_EN[6] == true"] When set, `hpmcounter6.COUNT` stops counting in all privilege modes. @@ -106,6 +115,7 @@ mcountinhibit: return COUNTINHIBIT_EN[6] ? UNDEFINED_LEGAL : 0; HPM7: location: 7 + definedBy: Smhpm description: | [when="COUNTINHIBIT_EN[7] == true"] When set, `hpmcounter7.COUNT` stops counting in all privilege modes. @@ -118,6 +128,7 @@ mcountinhibit: return COUNTINHIBIT_EN[7] ? UNDEFINED_LEGAL : 0; HPM8: location: 8 + definedBy: Smhpm description: | [when="COUNTINHIBIT_EN[8] == true"] When set, `hpmcounter8.COUNT` stops counting in all privilege modes. @@ -130,6 +141,7 @@ mcountinhibit: return COUNTINHIBIT_EN[8] ? UNDEFINED_LEGAL : 0; HPM9: location: 9 + definedBy: Smhpm description: | [when="COUNTINHIBIT_EN[9] == true"] When set, `hpmcounter9.COUNT` stops counting in all privilege modes. @@ -142,6 +154,7 @@ mcountinhibit: return COUNTINHIBIT_EN[9] ? UNDEFINED_LEGAL : 0; HPM10: location: 10 + definedBy: Smhpm description: | [when="COUNTINHIBIT_EN[10] == true"] When set, `hpmcounter10.COUNT` stops counting in all privilege modes. @@ -154,6 +167,7 @@ mcountinhibit: return COUNTINHIBIT_EN[10] ? UNDEFINED_LEGAL : 0; HPM11: location: 11 + definedBy: Smhpm description: | [when="COUNTINHIBIT_EN[11] == true"] When set, `hpmcounter11.COUNT` stops counting in all privilege modes. @@ -166,6 +180,7 @@ mcountinhibit: return COUNTINHIBIT_EN[11] ? UNDEFINED_LEGAL : 0; HPM12: location: 12 + definedBy: Smhpm description: | [when="COUNTINHIBIT_EN[12] == true"] When set, `hpmcounter12.COUNT` stops counting in all privilege modes. @@ -178,6 +193,7 @@ mcountinhibit: return COUNTINHIBIT_EN[12] ? UNDEFINED_LEGAL : 0; HPM13: location: 13 + definedBy: Smhpm description: | [when="COUNTINHIBIT_EN[13] == true"] When set, `hpmcounter13.COUNT` stops counting in all privilege modes. @@ -190,6 +206,7 @@ mcountinhibit: return COUNTINHIBIT_EN[13] ? UNDEFINED_LEGAL : 0; HPM14: location: 14 + definedBy: Smhpm description: | [when="COUNTINHIBIT_EN[14] == true"] When set, `hpmcounter14.COUNT` stops counting in all privilege modes. @@ -202,6 +219,7 @@ mcountinhibit: return COUNTINHIBIT_EN[14] ? UNDEFINED_LEGAL : 0; HPM15: location: 15 + definedBy: Smhpm description: | [when="COUNTINHIBIT_EN[15] == true"] When set, `hpmcounter15.COUNT` stops counting in all privilege modes. @@ -214,6 +232,7 @@ mcountinhibit: return COUNTINHIBIT_EN[15] ? UNDEFINED_LEGAL : 0; HPM16: location: 16 + definedBy: Smhpm description: | [when="COUNTINHIBIT_EN[16] == true"] When set, `hpmcounter16.COUNT` stops counting in all privilege modes. @@ -226,6 +245,7 @@ mcountinhibit: return COUNTINHIBIT_EN[16] ? UNDEFINED_LEGAL : 0; HPM17: location: 17 + definedBy: Smhpm description: | [when="COUNTINHIBIT_EN[17] == true"] When set, `hpmcounter17.COUNT` stops counting in all privilege modes. @@ -238,6 +258,7 @@ mcountinhibit: return COUNTINHIBIT_EN[17] ? UNDEFINED_LEGAL : 0; HPM18: location: 18 + definedBy: Smhpm description: | [when="COUNTINHIBIT_EN[18] == true"] When set, `hpmcounter18.COUNT` stops counting in all privilege modes. @@ -250,6 +271,7 @@ mcountinhibit: return COUNTINHIBIT_EN[18] ? UNDEFINED_LEGAL : 0; HPM19: location: 19 + definedBy: Smhpm description: | [when="COUNTINHIBIT_EN[19] == true"] When set, `hpmcounter19.COUNT` stops counting in all privilege modes. @@ -262,6 +284,7 @@ mcountinhibit: return COUNTINHIBIT_EN[19] ? UNDEFINED_LEGAL : 0; HPM20: location: 20 + definedBy: Smhpm description: | [when="COUNTINHIBIT_EN[20] == true"] When set, `hpmcounter20.COUNT` stops counting in all privilege modes. @@ -274,6 +297,7 @@ mcountinhibit: return COUNTINHIBIT_EN[20] ? UNDEFINED_LEGAL : 0; HPM21: location: 21 + definedBy: Smhpm description: | [when="COUNTINHIBIT_EN[21] == true"] When set, `hpmcounter21.COUNT` stops counting in all privilege modes. @@ -286,6 +310,7 @@ mcountinhibit: return COUNTINHIBIT_EN[21] ? UNDEFINED_LEGAL : 0; HPM22: location: 22 + definedBy: Smhpm description: | [when="COUNTINHIBIT_EN[22] == true"] When set, `hpmcounter22.COUNT` stops counting in all privilege modes. @@ -298,6 +323,7 @@ mcountinhibit: return COUNTINHIBIT_EN[22] ? UNDEFINED_LEGAL : 0; HPM23: location: 23 + definedBy: Smhpm description: | [when="COUNTINHIBIT_EN[23] == true"] When set, `hpmcounter23.COUNT` stops counting in all privilege modes. @@ -310,6 +336,7 @@ mcountinhibit: return COUNTINHIBIT_EN[23] ? UNDEFINED_LEGAL : 0; HPM24: location: 24 + definedBy: Smhpm description: | [when="COUNTINHIBIT_EN[24] == true"] When set, `hpmcounter24.COUNT` stops counting in all privilege modes. @@ -322,6 +349,7 @@ mcountinhibit: return COUNTINHIBIT_EN[24] ? UNDEFINED_LEGAL : 0; HPM25: location: 25 + definedBy: Smhpm description: | [when="COUNTINHIBIT_EN[25] == true"] When set, `hpmcounter25.COUNT` stops counting in all privilege modes. @@ -334,6 +362,7 @@ mcountinhibit: return COUNTINHIBIT_EN[25] ? UNDEFINED_LEGAL : 0; HPM26: location: 26 + definedBy: Smhpm description: | [when="COUNTINHIBIT_EN[26] == true"] When set, `hpmcounter26.COUNT` stops counting in all privilege modes. @@ -346,6 +375,7 @@ mcountinhibit: return COUNTINHIBIT_EN[26] ? UNDEFINED_LEGAL : 0; HPM27: location: 27 + definedBy: Smhpm description: | [when="COUNTINHIBIT_EN[27] == true"] When set, `hpmcounter27.COUNT` stops counting in all privilege modes. @@ -358,6 +388,7 @@ mcountinhibit: return COUNTINHIBIT_EN[27] ? UNDEFINED_LEGAL : 0; HPM28: location: 28 + definedBy: Smhpm description: | [when="COUNTINHIBIT_EN[28] == true"] When set, `hpmcounter28.COUNT` stops counting in all privilege modes. @@ -370,6 +401,7 @@ mcountinhibit: return COUNTINHIBIT_EN[28] ? UNDEFINED_LEGAL : 0; HPM29: location: 29 + definedBy: Smhpm description: | [when="COUNTINHIBIT_EN[29] == true"] When set, `hpmcounter29.COUNT` stops counting in all privilege modes. @@ -382,6 +414,7 @@ mcountinhibit: return COUNTINHIBIT_EN[29] ? UNDEFINED_LEGAL : 0; HPM30: location: 30 + definedBy: Smhpm description: | [when="COUNTINHIBIT_EN[30] == true"] When set, `hpmcounter30.COUNT` stops counting in all privilege modes. @@ -394,6 +427,7 @@ mcountinhibit: return COUNTINHIBIT_EN[30] ? UNDEFINED_LEGAL : 0; HPM31: location: 31 + definedBy: Smhpm description: | [when="COUNTINHIBIT_EN[31] == true"] When set, `hpmcounter31.COUNT` stops counting in all privilege modes. diff --git a/arch/csr/Zihpm/hpmcounter10.yaml b/arch/csr/Zihpm/hpmcounter10.yaml index 612ae51067..ce104a53ce 100644 --- a/arch/csr/Zihpm/hpmcounter10.yaml +++ b/arch/csr/Zihpm/hpmcounter10.yaml @@ -5,7 +5,7 @@ hpmcounter10: - long_name: Cycle counter for RDCYCLE Instruction + long_name: User-mode Hardware Performance Counter 7 address: 0xC0A description: | Alias for M-mode CSR `mhpmcounter10`. diff --git a/arch/csr/Zihpm/hpmcounter10h.yaml b/arch/csr/Zihpm/hpmcounter10h.yaml index 8aba0b3805..0b72fa1e50 100644 --- a/arch/csr/Zihpm/hpmcounter10h.yaml +++ b/arch/csr/Zihpm/hpmcounter10h.yaml @@ -5,7 +5,7 @@ hpmcounter10h: - long_name: Cycle counter for RDCYCLE Instruction, high half + long_name: User-mode Hardware Performance Counter 7, high half address: 0xC8A description: | Alias for M-mode CSR `mhpmcounter10h`. diff --git a/arch/csr/Zihpm/hpmcounter11.yaml b/arch/csr/Zihpm/hpmcounter11.yaml index a86212b7f7..719474378d 100644 --- a/arch/csr/Zihpm/hpmcounter11.yaml +++ b/arch/csr/Zihpm/hpmcounter11.yaml @@ -5,7 +5,7 @@ hpmcounter11: - long_name: Cycle counter for RDCYCLE Instruction + long_name: User-mode Hardware Performance Counter 8 address: 0xC0B description: | Alias for M-mode CSR `mhpmcounter11`. diff --git a/arch/csr/Zihpm/hpmcounter11h.yaml b/arch/csr/Zihpm/hpmcounter11h.yaml index 07ba593467..3992b01bb7 100644 --- a/arch/csr/Zihpm/hpmcounter11h.yaml +++ b/arch/csr/Zihpm/hpmcounter11h.yaml @@ -5,7 +5,7 @@ hpmcounter11h: - long_name: Cycle counter for RDCYCLE Instruction, high half + long_name: User-mode Hardware Performance Counter 8, high half address: 0xC8B description: | Alias for M-mode CSR `mhpmcounter11h`. diff --git a/arch/csr/Zihpm/hpmcounter12.yaml b/arch/csr/Zihpm/hpmcounter12.yaml index bfbd462bd3..b08bb753b5 100644 --- a/arch/csr/Zihpm/hpmcounter12.yaml +++ b/arch/csr/Zihpm/hpmcounter12.yaml @@ -5,7 +5,7 @@ hpmcounter12: - long_name: Cycle counter for RDCYCLE Instruction + long_name: User-mode Hardware Performance Counter 9 address: 0xC0C description: | Alias for M-mode CSR `mhpmcounter12`. diff --git a/arch/csr/Zihpm/hpmcounter12h.yaml b/arch/csr/Zihpm/hpmcounter12h.yaml index dea45ca75a..ca5ee71360 100644 --- a/arch/csr/Zihpm/hpmcounter12h.yaml +++ b/arch/csr/Zihpm/hpmcounter12h.yaml @@ -5,7 +5,7 @@ hpmcounter12h: - long_name: Cycle counter for RDCYCLE Instruction, high half + long_name: User-mode Hardware Performance Counter 9, high half address: 0xC8C description: | Alias for M-mode CSR `mhpmcounter12h`. diff --git a/arch/csr/Zihpm/hpmcounter13.yaml b/arch/csr/Zihpm/hpmcounter13.yaml index a5449420c6..8a6f76f147 100644 --- a/arch/csr/Zihpm/hpmcounter13.yaml +++ b/arch/csr/Zihpm/hpmcounter13.yaml @@ -5,7 +5,7 @@ hpmcounter13: - long_name: Cycle counter for RDCYCLE Instruction + long_name: User-mode Hardware Performance Counter 10 address: 0xC0D description: | Alias for M-mode CSR `mhpmcounter13`. diff --git a/arch/csr/Zihpm/hpmcounter13h.yaml b/arch/csr/Zihpm/hpmcounter13h.yaml index b8cd87e7fa..cb821c29f6 100644 --- a/arch/csr/Zihpm/hpmcounter13h.yaml +++ b/arch/csr/Zihpm/hpmcounter13h.yaml @@ -5,7 +5,7 @@ hpmcounter13h: - long_name: Cycle counter for RDCYCLE Instruction, high half + long_name: User-mode Hardware Performance Counter 10, high half address: 0xC8D description: | Alias for M-mode CSR `mhpmcounter13h`. diff --git a/arch/csr/Zihpm/hpmcounter14.yaml b/arch/csr/Zihpm/hpmcounter14.yaml index 459d8bfdd9..d458fcd1ef 100644 --- a/arch/csr/Zihpm/hpmcounter14.yaml +++ b/arch/csr/Zihpm/hpmcounter14.yaml @@ -5,7 +5,7 @@ hpmcounter14: - long_name: Cycle counter for RDCYCLE Instruction + long_name: User-mode Hardware Performance Counter 11 address: 0xC0E description: | Alias for M-mode CSR `mhpmcounter14`. diff --git a/arch/csr/Zihpm/hpmcounter14h.yaml b/arch/csr/Zihpm/hpmcounter14h.yaml index 524bbdcf5c..50ca550331 100644 --- a/arch/csr/Zihpm/hpmcounter14h.yaml +++ b/arch/csr/Zihpm/hpmcounter14h.yaml @@ -5,7 +5,7 @@ hpmcounter14h: - long_name: Cycle counter for RDCYCLE Instruction, high half + long_name: User-mode Hardware Performance Counter 11, high half address: 0xC8E description: | Alias for M-mode CSR `mhpmcounter14h`. diff --git a/arch/csr/Zihpm/hpmcounter15.yaml b/arch/csr/Zihpm/hpmcounter15.yaml index 2be5e86b9d..f5a39336b5 100644 --- a/arch/csr/Zihpm/hpmcounter15.yaml +++ b/arch/csr/Zihpm/hpmcounter15.yaml @@ -5,7 +5,7 @@ hpmcounter15: - long_name: Cycle counter for RDCYCLE Instruction + long_name: User-mode Hardware Performance Counter 12 address: 0xC0F description: | Alias for M-mode CSR `mhpmcounter15`. diff --git a/arch/csr/Zihpm/hpmcounter15h.yaml b/arch/csr/Zihpm/hpmcounter15h.yaml index 80b7b4c3c0..04b4b681bc 100644 --- a/arch/csr/Zihpm/hpmcounter15h.yaml +++ b/arch/csr/Zihpm/hpmcounter15h.yaml @@ -5,7 +5,7 @@ hpmcounter15h: - long_name: Cycle counter for RDCYCLE Instruction, high half + long_name: User-mode Hardware Performance Counter 12, high half address: 0xC8F description: | Alias for M-mode CSR `mhpmcounter15h`. diff --git a/arch/csr/Zihpm/hpmcounter16.yaml b/arch/csr/Zihpm/hpmcounter16.yaml index 9afb2b94b0..5e3bdfaf5b 100644 --- a/arch/csr/Zihpm/hpmcounter16.yaml +++ b/arch/csr/Zihpm/hpmcounter16.yaml @@ -5,7 +5,7 @@ hpmcounter16: - long_name: Cycle counter for RDCYCLE Instruction + long_name: User-mode Hardware Performance Counter 13 address: 0xC10 description: | Alias for M-mode CSR `mhpmcounter16`. diff --git a/arch/csr/Zihpm/hpmcounter16h.yaml b/arch/csr/Zihpm/hpmcounter16h.yaml index 5765ea7dff..e0743e4fe0 100644 --- a/arch/csr/Zihpm/hpmcounter16h.yaml +++ b/arch/csr/Zihpm/hpmcounter16h.yaml @@ -5,7 +5,7 @@ hpmcounter16h: - long_name: Cycle counter for RDCYCLE Instruction, high half + long_name: User-mode Hardware Performance Counter 13, high half address: 0xC90 description: | Alias for M-mode CSR `mhpmcounter16h`. diff --git a/arch/csr/Zihpm/hpmcounter17.yaml b/arch/csr/Zihpm/hpmcounter17.yaml index 60f8fbe895..3dbff26248 100644 --- a/arch/csr/Zihpm/hpmcounter17.yaml +++ b/arch/csr/Zihpm/hpmcounter17.yaml @@ -5,7 +5,7 @@ hpmcounter17: - long_name: Cycle counter for RDCYCLE Instruction + long_name: User-mode Hardware Performance Counter 14 address: 0xC11 description: | Alias for M-mode CSR `mhpmcounter17`. diff --git a/arch/csr/Zihpm/hpmcounter17h.yaml b/arch/csr/Zihpm/hpmcounter17h.yaml index 46cc9a75c5..a6d9946416 100644 --- a/arch/csr/Zihpm/hpmcounter17h.yaml +++ b/arch/csr/Zihpm/hpmcounter17h.yaml @@ -5,7 +5,7 @@ hpmcounter17h: - long_name: Cycle counter for RDCYCLE Instruction, high half + long_name: User-mode Hardware Performance Counter 14, high half address: 0xC91 description: | Alias for M-mode CSR `mhpmcounter17h`. diff --git a/arch/csr/Zihpm/hpmcounter18.yaml b/arch/csr/Zihpm/hpmcounter18.yaml index 20277c5ef5..619ac99ffd 100644 --- a/arch/csr/Zihpm/hpmcounter18.yaml +++ b/arch/csr/Zihpm/hpmcounter18.yaml @@ -5,7 +5,7 @@ hpmcounter18: - long_name: Cycle counter for RDCYCLE Instruction + long_name: User-mode Hardware Performance Counter 15 address: 0xC12 description: | Alias for M-mode CSR `mhpmcounter18`. diff --git a/arch/csr/Zihpm/hpmcounter18h.yaml b/arch/csr/Zihpm/hpmcounter18h.yaml index a47f015841..2d72f8d46c 100644 --- a/arch/csr/Zihpm/hpmcounter18h.yaml +++ b/arch/csr/Zihpm/hpmcounter18h.yaml @@ -5,7 +5,7 @@ hpmcounter18h: - long_name: Cycle counter for RDCYCLE Instruction, high half + long_name: User-mode Hardware Performance Counter 15, high half address: 0xC92 description: | Alias for M-mode CSR `mhpmcounter18h`. diff --git a/arch/csr/Zihpm/hpmcounter19.yaml b/arch/csr/Zihpm/hpmcounter19.yaml index 827c3e73ba..65ef79de51 100644 --- a/arch/csr/Zihpm/hpmcounter19.yaml +++ b/arch/csr/Zihpm/hpmcounter19.yaml @@ -5,7 +5,7 @@ hpmcounter19: - long_name: Cycle counter for RDCYCLE Instruction + long_name: User-mode Hardware Performance Counter 16 address: 0xC13 description: | Alias for M-mode CSR `mhpmcounter19`. diff --git a/arch/csr/Zihpm/hpmcounter19h.yaml b/arch/csr/Zihpm/hpmcounter19h.yaml index f3f858d3b6..4e8d45e4bd 100644 --- a/arch/csr/Zihpm/hpmcounter19h.yaml +++ b/arch/csr/Zihpm/hpmcounter19h.yaml @@ -5,7 +5,7 @@ hpmcounter19h: - long_name: Cycle counter for RDCYCLE Instruction, high half + long_name: User-mode Hardware Performance Counter 16, high half address: 0xC93 description: | Alias for M-mode CSR `mhpmcounter19h`. diff --git a/arch/csr/Zihpm/hpmcounter20.yaml b/arch/csr/Zihpm/hpmcounter20.yaml index d2914152d5..fd7a916bee 100644 --- a/arch/csr/Zihpm/hpmcounter20.yaml +++ b/arch/csr/Zihpm/hpmcounter20.yaml @@ -5,7 +5,7 @@ hpmcounter20: - long_name: Cycle counter for RDCYCLE Instruction + long_name: User-mode Hardware Performance Counter 17 address: 0xC14 description: | Alias for M-mode CSR `mhpmcounter20`. diff --git a/arch/csr/Zihpm/hpmcounter20h.yaml b/arch/csr/Zihpm/hpmcounter20h.yaml index a50d386525..d3a8d09122 100644 --- a/arch/csr/Zihpm/hpmcounter20h.yaml +++ b/arch/csr/Zihpm/hpmcounter20h.yaml @@ -5,7 +5,7 @@ hpmcounter20h: - long_name: Cycle counter for RDCYCLE Instruction, high half + long_name: User-mode Hardware Performance Counter 17, high half address: 0xC94 description: | Alias for M-mode CSR `mhpmcounter20h`. diff --git a/arch/csr/Zihpm/hpmcounter21.yaml b/arch/csr/Zihpm/hpmcounter21.yaml index 8034dab364..9f184510a8 100644 --- a/arch/csr/Zihpm/hpmcounter21.yaml +++ b/arch/csr/Zihpm/hpmcounter21.yaml @@ -5,7 +5,7 @@ hpmcounter21: - long_name: Cycle counter for RDCYCLE Instruction + long_name: User-mode Hardware Performance Counter 18 address: 0xC15 description: | Alias for M-mode CSR `mhpmcounter21`. diff --git a/arch/csr/Zihpm/hpmcounter21h.yaml b/arch/csr/Zihpm/hpmcounter21h.yaml index 497d57becf..ef76be0189 100644 --- a/arch/csr/Zihpm/hpmcounter21h.yaml +++ b/arch/csr/Zihpm/hpmcounter21h.yaml @@ -5,7 +5,7 @@ hpmcounter21h: - long_name: Cycle counter for RDCYCLE Instruction, high half + long_name: User-mode Hardware Performance Counter 18, high half address: 0xC95 description: | Alias for M-mode CSR `mhpmcounter21h`. diff --git a/arch/csr/Zihpm/hpmcounter22.yaml b/arch/csr/Zihpm/hpmcounter22.yaml index d8b21c0d00..b40f8056d2 100644 --- a/arch/csr/Zihpm/hpmcounter22.yaml +++ b/arch/csr/Zihpm/hpmcounter22.yaml @@ -5,7 +5,7 @@ hpmcounter22: - long_name: Cycle counter for RDCYCLE Instruction + long_name: User-mode Hardware Performance Counter 19 address: 0xC16 description: | Alias for M-mode CSR `mhpmcounter22`. diff --git a/arch/csr/Zihpm/hpmcounter22h.yaml b/arch/csr/Zihpm/hpmcounter22h.yaml index ef1adc28e4..c45c109016 100644 --- a/arch/csr/Zihpm/hpmcounter22h.yaml +++ b/arch/csr/Zihpm/hpmcounter22h.yaml @@ -5,7 +5,7 @@ hpmcounter22h: - long_name: Cycle counter for RDCYCLE Instruction, high half + long_name: User-mode Hardware Performance Counter 19, high half address: 0xC96 description: | Alias for M-mode CSR `mhpmcounter22h`. diff --git a/arch/csr/Zihpm/hpmcounter23.yaml b/arch/csr/Zihpm/hpmcounter23.yaml index 69757bd730..87414b84de 100644 --- a/arch/csr/Zihpm/hpmcounter23.yaml +++ b/arch/csr/Zihpm/hpmcounter23.yaml @@ -5,7 +5,7 @@ hpmcounter23: - long_name: Cycle counter for RDCYCLE Instruction + long_name: User-mode Hardware Performance Counter 20 address: 0xC17 description: | Alias for M-mode CSR `mhpmcounter23`. diff --git a/arch/csr/Zihpm/hpmcounter23h.yaml b/arch/csr/Zihpm/hpmcounter23h.yaml index 7244021083..33c7fc76fc 100644 --- a/arch/csr/Zihpm/hpmcounter23h.yaml +++ b/arch/csr/Zihpm/hpmcounter23h.yaml @@ -5,7 +5,7 @@ hpmcounter23h: - long_name: Cycle counter for RDCYCLE Instruction, high half + long_name: User-mode Hardware Performance Counter 20, high half address: 0xC97 description: | Alias for M-mode CSR `mhpmcounter23h`. diff --git a/arch/csr/Zihpm/hpmcounter24.yaml b/arch/csr/Zihpm/hpmcounter24.yaml index d0c6afd33d..038e6b74fd 100644 --- a/arch/csr/Zihpm/hpmcounter24.yaml +++ b/arch/csr/Zihpm/hpmcounter24.yaml @@ -5,7 +5,7 @@ hpmcounter24: - long_name: Cycle counter for RDCYCLE Instruction + long_name: User-mode Hardware Performance Counter 21 address: 0xC18 description: | Alias for M-mode CSR `mhpmcounter24`. diff --git a/arch/csr/Zihpm/hpmcounter24h.yaml b/arch/csr/Zihpm/hpmcounter24h.yaml index cac953252d..530d0142f4 100644 --- a/arch/csr/Zihpm/hpmcounter24h.yaml +++ b/arch/csr/Zihpm/hpmcounter24h.yaml @@ -5,7 +5,7 @@ hpmcounter24h: - long_name: Cycle counter for RDCYCLE Instruction, high half + long_name: User-mode Hardware Performance Counter 21, high half address: 0xC98 description: | Alias for M-mode CSR `mhpmcounter24h`. diff --git a/arch/csr/Zihpm/hpmcounter25.yaml b/arch/csr/Zihpm/hpmcounter25.yaml index 4d018b47a4..2e57b47d56 100644 --- a/arch/csr/Zihpm/hpmcounter25.yaml +++ b/arch/csr/Zihpm/hpmcounter25.yaml @@ -5,7 +5,7 @@ hpmcounter25: - long_name: Cycle counter for RDCYCLE Instruction + long_name: User-mode Hardware Performance Counter 22 address: 0xC19 description: | Alias for M-mode CSR `mhpmcounter25`. diff --git a/arch/csr/Zihpm/hpmcounter25h.yaml b/arch/csr/Zihpm/hpmcounter25h.yaml index b305446811..6272bcbb3c 100644 --- a/arch/csr/Zihpm/hpmcounter25h.yaml +++ b/arch/csr/Zihpm/hpmcounter25h.yaml @@ -5,7 +5,7 @@ hpmcounter25h: - long_name: Cycle counter for RDCYCLE Instruction, high half + long_name: User-mode Hardware Performance Counter 22, high half address: 0xC99 description: | Alias for M-mode CSR `mhpmcounter25h`. diff --git a/arch/csr/Zihpm/hpmcounter26.yaml b/arch/csr/Zihpm/hpmcounter26.yaml index 98bdf26d95..72281cc56d 100644 --- a/arch/csr/Zihpm/hpmcounter26.yaml +++ b/arch/csr/Zihpm/hpmcounter26.yaml @@ -5,7 +5,7 @@ hpmcounter26: - long_name: Cycle counter for RDCYCLE Instruction + long_name: User-mode Hardware Performance Counter 23 address: 0xC1A description: | Alias for M-mode CSR `mhpmcounter26`. diff --git a/arch/csr/Zihpm/hpmcounter26h.yaml b/arch/csr/Zihpm/hpmcounter26h.yaml index b463ca1f3d..a95da6fad5 100644 --- a/arch/csr/Zihpm/hpmcounter26h.yaml +++ b/arch/csr/Zihpm/hpmcounter26h.yaml @@ -5,7 +5,7 @@ hpmcounter26h: - long_name: Cycle counter for RDCYCLE Instruction, high half + long_name: User-mode Hardware Performance Counter 23, high half address: 0xC9A description: | Alias for M-mode CSR `mhpmcounter26h`. diff --git a/arch/csr/Zihpm/hpmcounter27.yaml b/arch/csr/Zihpm/hpmcounter27.yaml index 19f738dd5f..238e04b9a1 100644 --- a/arch/csr/Zihpm/hpmcounter27.yaml +++ b/arch/csr/Zihpm/hpmcounter27.yaml @@ -5,7 +5,7 @@ hpmcounter27: - long_name: Cycle counter for RDCYCLE Instruction + long_name: User-mode Hardware Performance Counter 24 address: 0xC1B description: | Alias for M-mode CSR `mhpmcounter27`. diff --git a/arch/csr/Zihpm/hpmcounter27h.yaml b/arch/csr/Zihpm/hpmcounter27h.yaml index fd432c5e17..08dc698002 100644 --- a/arch/csr/Zihpm/hpmcounter27h.yaml +++ b/arch/csr/Zihpm/hpmcounter27h.yaml @@ -5,7 +5,7 @@ hpmcounter27h: - long_name: Cycle counter for RDCYCLE Instruction, high half + long_name: User-mode Hardware Performance Counter 24, high half address: 0xC9B description: | Alias for M-mode CSR `mhpmcounter27h`. diff --git a/arch/csr/Zihpm/hpmcounter28.yaml b/arch/csr/Zihpm/hpmcounter28.yaml index 72cef52fcf..a666a253a9 100644 --- a/arch/csr/Zihpm/hpmcounter28.yaml +++ b/arch/csr/Zihpm/hpmcounter28.yaml @@ -5,7 +5,7 @@ hpmcounter28: - long_name: Cycle counter for RDCYCLE Instruction + long_name: User-mode Hardware Performance Counter 25 address: 0xC1C description: | Alias for M-mode CSR `mhpmcounter28`. diff --git a/arch/csr/Zihpm/hpmcounter28h.yaml b/arch/csr/Zihpm/hpmcounter28h.yaml index 775eed2864..4fab76e02f 100644 --- a/arch/csr/Zihpm/hpmcounter28h.yaml +++ b/arch/csr/Zihpm/hpmcounter28h.yaml @@ -5,7 +5,7 @@ hpmcounter28h: - long_name: Cycle counter for RDCYCLE Instruction, high half + long_name: User-mode Hardware Performance Counter 25, high half address: 0xC9C description: | Alias for M-mode CSR `mhpmcounter28h`. diff --git a/arch/csr/Zihpm/hpmcounter29.yaml b/arch/csr/Zihpm/hpmcounter29.yaml index 8ca1b57abf..d2b0277475 100644 --- a/arch/csr/Zihpm/hpmcounter29.yaml +++ b/arch/csr/Zihpm/hpmcounter29.yaml @@ -5,7 +5,7 @@ hpmcounter29: - long_name: Cycle counter for RDCYCLE Instruction + long_name: User-mode Hardware Performance Counter 26 address: 0xC1D description: | Alias for M-mode CSR `mhpmcounter29`. diff --git a/arch/csr/Zihpm/hpmcounter29h.yaml b/arch/csr/Zihpm/hpmcounter29h.yaml index 352c999a07..13c6a2f3da 100644 --- a/arch/csr/Zihpm/hpmcounter29h.yaml +++ b/arch/csr/Zihpm/hpmcounter29h.yaml @@ -5,7 +5,7 @@ hpmcounter29h: - long_name: Cycle counter for RDCYCLE Instruction, high half + long_name: User-mode Hardware Performance Counter 26, high half address: 0xC9D description: | Alias for M-mode CSR `mhpmcounter29h`. diff --git a/arch/csr/Zihpm/hpmcounter3.yaml b/arch/csr/Zihpm/hpmcounter3.yaml index ac0050a56b..5effc68fa3 100644 --- a/arch/csr/Zihpm/hpmcounter3.yaml +++ b/arch/csr/Zihpm/hpmcounter3.yaml @@ -5,7 +5,7 @@ hpmcounter3: - long_name: Cycle counter for RDCYCLE Instruction + long_name: User-mode Hardware Performance Counter 0 address: 0xC03 description: | Alias for M-mode CSR `mhpmcounter3`. diff --git a/arch/csr/Zihpm/hpmcounter30.yaml b/arch/csr/Zihpm/hpmcounter30.yaml index 6139870280..4218256297 100644 --- a/arch/csr/Zihpm/hpmcounter30.yaml +++ b/arch/csr/Zihpm/hpmcounter30.yaml @@ -5,7 +5,7 @@ hpmcounter30: - long_name: Cycle counter for RDCYCLE Instruction + long_name: User-mode Hardware Performance Counter 27 address: 0xC1E description: | Alias for M-mode CSR `mhpmcounter30`. diff --git a/arch/csr/Zihpm/hpmcounter30h.yaml b/arch/csr/Zihpm/hpmcounter30h.yaml index e3d5721820..abbda24ee3 100644 --- a/arch/csr/Zihpm/hpmcounter30h.yaml +++ b/arch/csr/Zihpm/hpmcounter30h.yaml @@ -5,7 +5,7 @@ hpmcounter30h: - long_name: Cycle counter for RDCYCLE Instruction, high half + long_name: User-mode Hardware Performance Counter 27, high half address: 0xC9E description: | Alias for M-mode CSR `mhpmcounter30h`. diff --git a/arch/csr/Zihpm/hpmcounter31.yaml b/arch/csr/Zihpm/hpmcounter31.yaml index ff45e9227b..a77960f60c 100644 --- a/arch/csr/Zihpm/hpmcounter31.yaml +++ b/arch/csr/Zihpm/hpmcounter31.yaml @@ -5,7 +5,7 @@ hpmcounter31: - long_name: Cycle counter for RDCYCLE Instruction + long_name: User-mode Hardware Performance Counter 28 address: 0xC1F description: | Alias for M-mode CSR `mhpmcounter31`. diff --git a/arch/csr/Zihpm/hpmcounter31h.yaml b/arch/csr/Zihpm/hpmcounter31h.yaml index 0d67bfbe3b..1a9c33fd67 100644 --- a/arch/csr/Zihpm/hpmcounter31h.yaml +++ b/arch/csr/Zihpm/hpmcounter31h.yaml @@ -5,7 +5,7 @@ hpmcounter31h: - long_name: Cycle counter for RDCYCLE Instruction, high half + long_name: User-mode Hardware Performance Counter 28, high half address: 0xC9F description: | Alias for M-mode CSR `mhpmcounter31h`. diff --git a/arch/csr/Zihpm/hpmcounter3h.yaml b/arch/csr/Zihpm/hpmcounter3h.yaml index 4468d15275..67808e3059 100644 --- a/arch/csr/Zihpm/hpmcounter3h.yaml +++ b/arch/csr/Zihpm/hpmcounter3h.yaml @@ -5,7 +5,7 @@ hpmcounter3h: - long_name: Cycle counter for RDCYCLE Instruction, high half + long_name: User-mode Hardware Performance Counter 0, high half address: 0xC83 description: | Alias for M-mode CSR `mhpmcounter3h`. diff --git a/arch/csr/Zihpm/hpmcounter4.yaml b/arch/csr/Zihpm/hpmcounter4.yaml index 2a2090d69b..75a8c78f6e 100644 --- a/arch/csr/Zihpm/hpmcounter4.yaml +++ b/arch/csr/Zihpm/hpmcounter4.yaml @@ -5,7 +5,7 @@ hpmcounter4: - long_name: Cycle counter for RDCYCLE Instruction + long_name: User-mode Hardware Performance Counter 1 address: 0xC04 description: | Alias for M-mode CSR `mhpmcounter4`. diff --git a/arch/csr/Zihpm/hpmcounter4h.yaml b/arch/csr/Zihpm/hpmcounter4h.yaml index de41493953..11e2cf6f40 100644 --- a/arch/csr/Zihpm/hpmcounter4h.yaml +++ b/arch/csr/Zihpm/hpmcounter4h.yaml @@ -5,7 +5,7 @@ hpmcounter4h: - long_name: Cycle counter for RDCYCLE Instruction, high half + long_name: User-mode Hardware Performance Counter 1, high half address: 0xC84 description: | Alias for M-mode CSR `mhpmcounter4h`. diff --git a/arch/csr/Zihpm/hpmcounter5.yaml b/arch/csr/Zihpm/hpmcounter5.yaml index abe47a3e8a..13893d7d7e 100644 --- a/arch/csr/Zihpm/hpmcounter5.yaml +++ b/arch/csr/Zihpm/hpmcounter5.yaml @@ -5,7 +5,7 @@ hpmcounter5: - long_name: Cycle counter for RDCYCLE Instruction + long_name: User-mode Hardware Performance Counter 2 address: 0xC05 description: | Alias for M-mode CSR `mhpmcounter5`. diff --git a/arch/csr/Zihpm/hpmcounter5h.yaml b/arch/csr/Zihpm/hpmcounter5h.yaml index d2b35b003f..cd3e942a55 100644 --- a/arch/csr/Zihpm/hpmcounter5h.yaml +++ b/arch/csr/Zihpm/hpmcounter5h.yaml @@ -5,7 +5,7 @@ hpmcounter5h: - long_name: Cycle counter for RDCYCLE Instruction, high half + long_name: User-mode Hardware Performance Counter 2, high half address: 0xC85 description: | Alias for M-mode CSR `mhpmcounter5h`. diff --git a/arch/csr/Zihpm/hpmcounter6.yaml b/arch/csr/Zihpm/hpmcounter6.yaml index abb397fcce..9e69420ab1 100644 --- a/arch/csr/Zihpm/hpmcounter6.yaml +++ b/arch/csr/Zihpm/hpmcounter6.yaml @@ -5,7 +5,7 @@ hpmcounter6: - long_name: Cycle counter for RDCYCLE Instruction + long_name: User-mode Hardware Performance Counter 3 address: 0xC06 description: | Alias for M-mode CSR `mhpmcounter6`. diff --git a/arch/csr/Zihpm/hpmcounter6h.yaml b/arch/csr/Zihpm/hpmcounter6h.yaml index 29836774d0..3404fc2690 100644 --- a/arch/csr/Zihpm/hpmcounter6h.yaml +++ b/arch/csr/Zihpm/hpmcounter6h.yaml @@ -5,7 +5,7 @@ hpmcounter6h: - long_name: Cycle counter for RDCYCLE Instruction, high half + long_name: User-mode Hardware Performance Counter 3, high half address: 0xC86 description: | Alias for M-mode CSR `mhpmcounter6h`. diff --git a/arch/csr/Zihpm/hpmcounter7.yaml b/arch/csr/Zihpm/hpmcounter7.yaml index 446e20ff54..9f1fcc6a88 100644 --- a/arch/csr/Zihpm/hpmcounter7.yaml +++ b/arch/csr/Zihpm/hpmcounter7.yaml @@ -5,7 +5,7 @@ hpmcounter7: - long_name: Cycle counter for RDCYCLE Instruction + long_name: User-mode Hardware Performance Counter 4 address: 0xC07 description: | Alias for M-mode CSR `mhpmcounter7`. diff --git a/arch/csr/Zihpm/hpmcounter7h.yaml b/arch/csr/Zihpm/hpmcounter7h.yaml index 4bfc6c4c60..0fce0d221e 100644 --- a/arch/csr/Zihpm/hpmcounter7h.yaml +++ b/arch/csr/Zihpm/hpmcounter7h.yaml @@ -5,7 +5,7 @@ hpmcounter7h: - long_name: Cycle counter for RDCYCLE Instruction, high half + long_name: User-mode Hardware Performance Counter 4, high half address: 0xC87 description: | Alias for M-mode CSR `mhpmcounter7h`. diff --git a/arch/csr/Zihpm/hpmcounter8.yaml b/arch/csr/Zihpm/hpmcounter8.yaml index 822a000349..7e96d83e43 100644 --- a/arch/csr/Zihpm/hpmcounter8.yaml +++ b/arch/csr/Zihpm/hpmcounter8.yaml @@ -5,7 +5,7 @@ hpmcounter8: - long_name: Cycle counter for RDCYCLE Instruction + long_name: User-mode Hardware Performance Counter 5 address: 0xC08 description: | Alias for M-mode CSR `mhpmcounter8`. diff --git a/arch/csr/Zihpm/hpmcounter8h.yaml b/arch/csr/Zihpm/hpmcounter8h.yaml index 3b0de24c07..8ec5e6ad8a 100644 --- a/arch/csr/Zihpm/hpmcounter8h.yaml +++ b/arch/csr/Zihpm/hpmcounter8h.yaml @@ -5,7 +5,7 @@ hpmcounter8h: - long_name: Cycle counter for RDCYCLE Instruction, high half + long_name: User-mode Hardware Performance Counter 5, high half address: 0xC88 description: | Alias for M-mode CSR `mhpmcounter8h`. diff --git a/arch/csr/Zihpm/hpmcounter9.yaml b/arch/csr/Zihpm/hpmcounter9.yaml index b7fb428134..1ada56e25e 100644 --- a/arch/csr/Zihpm/hpmcounter9.yaml +++ b/arch/csr/Zihpm/hpmcounter9.yaml @@ -5,7 +5,7 @@ hpmcounter9: - long_name: Cycle counter for RDCYCLE Instruction + long_name: User-mode Hardware Performance Counter 6 address: 0xC09 description: | Alias for M-mode CSR `mhpmcounter9`. diff --git a/arch/csr/Zihpm/hpmcounter9h.yaml b/arch/csr/Zihpm/hpmcounter9h.yaml index bb00654646..99b91600ad 100644 --- a/arch/csr/Zihpm/hpmcounter9h.yaml +++ b/arch/csr/Zihpm/hpmcounter9h.yaml @@ -5,7 +5,7 @@ hpmcounter9h: - long_name: Cycle counter for RDCYCLE Instruction, high half + long_name: User-mode Hardware Performance Counter 6, high half address: 0xC89 description: | Alias for M-mode CSR `mhpmcounter9h`. diff --git a/arch/csr/Zihpm/hpmcounterN.layout b/arch/csr/Zihpm/hpmcounterN.layout index b39e27e50c..32282b45f1 100644 --- a/arch/csr/Zihpm/hpmcounterN.layout +++ b/arch/csr/Zihpm/hpmcounterN.layout @@ -3,7 +3,7 @@ <%- raise "'hpm_num' must be defined" if hpm_num.nil? -%> hpmcounter<%= hpm_num %>: - long_name: Cycle counter for RDCYCLE Instruction + long_name: User-mode Hardware Performance Counter <%= hpm_num - 3 %> address: 0x<%= (0xC03 + (hpm_num - 3)).to_s(16).upcase %> description: | Alias for M-mode CSR `mhpmcounter<%= hpm_num %>`. diff --git a/arch/csr/Zihpm/hpmcounterNh.layout b/arch/csr/Zihpm/hpmcounterNh.layout index a9b4280a06..f033726513 100644 --- a/arch/csr/Zihpm/hpmcounterNh.layout +++ b/arch/csr/Zihpm/hpmcounterNh.layout @@ -3,7 +3,7 @@ <%- raise "'hpm_num' must be defined" if hpm_num.nil? -%> hpmcounter<%= hpm_num %>h: - long_name: Cycle counter for RDCYCLE Instruction, high half + long_name: User-mode Hardware Performance Counter <%= hpm_num - 3 %>, high half address: 0x<%= (0xC83 + (hpm_num - 3)).to_s(16).upcase %> description: | Alias for M-mode CSR `mhpmcounter<%= hpm_num %>h`. diff --git a/arch/csr/Zihpm/mhpmcounter10.yaml b/arch/csr/Zihpm/mhpmcounter10.yaml index 97cc4b7765..124fd07268 100644 --- a/arch/csr/Zihpm/mhpmcounter10.yaml +++ b/arch/csr/Zihpm/mhpmcounter10.yaml @@ -10,7 +10,7 @@ mhpmcounter10: priv_mode: M length: 64 description: Programmable hardware performance counter. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 63-0 diff --git a/arch/csr/Zihpm/mhpmcounter10h.yaml b/arch/csr/Zihpm/mhpmcounter10h.yaml index a389c0e67d..595497b28d 100644 --- a/arch/csr/Zihpm/mhpmcounter10h.yaml +++ b/arch/csr/Zihpm/mhpmcounter10h.yaml @@ -12,7 +12,7 @@ mhpmcounter10h: base: 32 description: | Upper half of mhpmcounter10. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 32-0 diff --git a/arch/csr/Zihpm/mhpmcounter11.yaml b/arch/csr/Zihpm/mhpmcounter11.yaml index 5f8f2842b0..82519cd0bc 100644 --- a/arch/csr/Zihpm/mhpmcounter11.yaml +++ b/arch/csr/Zihpm/mhpmcounter11.yaml @@ -10,7 +10,7 @@ mhpmcounter11: priv_mode: M length: 64 description: Programmable hardware performance counter. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 63-0 diff --git a/arch/csr/Zihpm/mhpmcounter11h.yaml b/arch/csr/Zihpm/mhpmcounter11h.yaml index 42230bc8aa..8cc262a354 100644 --- a/arch/csr/Zihpm/mhpmcounter11h.yaml +++ b/arch/csr/Zihpm/mhpmcounter11h.yaml @@ -12,7 +12,7 @@ mhpmcounter11h: base: 32 description: | Upper half of mhpmcounter11. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 32-0 diff --git a/arch/csr/Zihpm/mhpmcounter12.yaml b/arch/csr/Zihpm/mhpmcounter12.yaml index 015a1caac8..ee241a5a2d 100644 --- a/arch/csr/Zihpm/mhpmcounter12.yaml +++ b/arch/csr/Zihpm/mhpmcounter12.yaml @@ -10,7 +10,7 @@ mhpmcounter12: priv_mode: M length: 64 description: Programmable hardware performance counter. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 63-0 diff --git a/arch/csr/Zihpm/mhpmcounter12h.yaml b/arch/csr/Zihpm/mhpmcounter12h.yaml index 1b44bf80f3..ec2d0af69b 100644 --- a/arch/csr/Zihpm/mhpmcounter12h.yaml +++ b/arch/csr/Zihpm/mhpmcounter12h.yaml @@ -12,7 +12,7 @@ mhpmcounter12h: base: 32 description: | Upper half of mhpmcounter12. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 32-0 diff --git a/arch/csr/Zihpm/mhpmcounter13.yaml b/arch/csr/Zihpm/mhpmcounter13.yaml index dc6baddf15..c50b9f88fa 100644 --- a/arch/csr/Zihpm/mhpmcounter13.yaml +++ b/arch/csr/Zihpm/mhpmcounter13.yaml @@ -10,7 +10,7 @@ mhpmcounter13: priv_mode: M length: 64 description: Programmable hardware performance counter. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 63-0 diff --git a/arch/csr/Zihpm/mhpmcounter13h.yaml b/arch/csr/Zihpm/mhpmcounter13h.yaml index 635bdce55b..5183d8a2d1 100644 --- a/arch/csr/Zihpm/mhpmcounter13h.yaml +++ b/arch/csr/Zihpm/mhpmcounter13h.yaml @@ -12,7 +12,7 @@ mhpmcounter13h: base: 32 description: | Upper half of mhpmcounter13. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 32-0 diff --git a/arch/csr/Zihpm/mhpmcounter14.yaml b/arch/csr/Zihpm/mhpmcounter14.yaml index 04d227ef91..ae91a6329c 100644 --- a/arch/csr/Zihpm/mhpmcounter14.yaml +++ b/arch/csr/Zihpm/mhpmcounter14.yaml @@ -10,7 +10,7 @@ mhpmcounter14: priv_mode: M length: 64 description: Programmable hardware performance counter. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 63-0 diff --git a/arch/csr/Zihpm/mhpmcounter14h.yaml b/arch/csr/Zihpm/mhpmcounter14h.yaml index 22883680d9..21ab862396 100644 --- a/arch/csr/Zihpm/mhpmcounter14h.yaml +++ b/arch/csr/Zihpm/mhpmcounter14h.yaml @@ -12,7 +12,7 @@ mhpmcounter14h: base: 32 description: | Upper half of mhpmcounter14. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 32-0 diff --git a/arch/csr/Zihpm/mhpmcounter15.yaml b/arch/csr/Zihpm/mhpmcounter15.yaml index c5d228e1dd..7453299d1a 100644 --- a/arch/csr/Zihpm/mhpmcounter15.yaml +++ b/arch/csr/Zihpm/mhpmcounter15.yaml @@ -10,7 +10,7 @@ mhpmcounter15: priv_mode: M length: 64 description: Programmable hardware performance counter. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 63-0 diff --git a/arch/csr/Zihpm/mhpmcounter15h.yaml b/arch/csr/Zihpm/mhpmcounter15h.yaml index 06578d20e5..a398cd893d 100644 --- a/arch/csr/Zihpm/mhpmcounter15h.yaml +++ b/arch/csr/Zihpm/mhpmcounter15h.yaml @@ -12,7 +12,7 @@ mhpmcounter15h: base: 32 description: | Upper half of mhpmcounter15. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 32-0 diff --git a/arch/csr/Zihpm/mhpmcounter16.yaml b/arch/csr/Zihpm/mhpmcounter16.yaml index cae2197df6..9ecb490afe 100644 --- a/arch/csr/Zihpm/mhpmcounter16.yaml +++ b/arch/csr/Zihpm/mhpmcounter16.yaml @@ -10,7 +10,7 @@ mhpmcounter16: priv_mode: M length: 64 description: Programmable hardware performance counter. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 63-0 diff --git a/arch/csr/Zihpm/mhpmcounter16h.yaml b/arch/csr/Zihpm/mhpmcounter16h.yaml index a1c124827e..6839ff6251 100644 --- a/arch/csr/Zihpm/mhpmcounter16h.yaml +++ b/arch/csr/Zihpm/mhpmcounter16h.yaml @@ -12,7 +12,7 @@ mhpmcounter16h: base: 32 description: | Upper half of mhpmcounter16. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 32-0 diff --git a/arch/csr/Zihpm/mhpmcounter17.yaml b/arch/csr/Zihpm/mhpmcounter17.yaml index e9c9272bf6..dddc551167 100644 --- a/arch/csr/Zihpm/mhpmcounter17.yaml +++ b/arch/csr/Zihpm/mhpmcounter17.yaml @@ -10,7 +10,7 @@ mhpmcounter17: priv_mode: M length: 64 description: Programmable hardware performance counter. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 63-0 diff --git a/arch/csr/Zihpm/mhpmcounter17h.yaml b/arch/csr/Zihpm/mhpmcounter17h.yaml index d2addb7af8..1dcc9db272 100644 --- a/arch/csr/Zihpm/mhpmcounter17h.yaml +++ b/arch/csr/Zihpm/mhpmcounter17h.yaml @@ -12,7 +12,7 @@ mhpmcounter17h: base: 32 description: | Upper half of mhpmcounter17. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 32-0 diff --git a/arch/csr/Zihpm/mhpmcounter18.yaml b/arch/csr/Zihpm/mhpmcounter18.yaml index 925b2ac193..4cc3e014b1 100644 --- a/arch/csr/Zihpm/mhpmcounter18.yaml +++ b/arch/csr/Zihpm/mhpmcounter18.yaml @@ -10,7 +10,7 @@ mhpmcounter18: priv_mode: M length: 64 description: Programmable hardware performance counter. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 63-0 diff --git a/arch/csr/Zihpm/mhpmcounter18h.yaml b/arch/csr/Zihpm/mhpmcounter18h.yaml index 38ab46e161..2a447e9308 100644 --- a/arch/csr/Zihpm/mhpmcounter18h.yaml +++ b/arch/csr/Zihpm/mhpmcounter18h.yaml @@ -12,7 +12,7 @@ mhpmcounter18h: base: 32 description: | Upper half of mhpmcounter18. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 32-0 diff --git a/arch/csr/Zihpm/mhpmcounter19.yaml b/arch/csr/Zihpm/mhpmcounter19.yaml index bc11a216ff..ba1c07d37d 100644 --- a/arch/csr/Zihpm/mhpmcounter19.yaml +++ b/arch/csr/Zihpm/mhpmcounter19.yaml @@ -10,7 +10,7 @@ mhpmcounter19: priv_mode: M length: 64 description: Programmable hardware performance counter. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 63-0 diff --git a/arch/csr/Zihpm/mhpmcounter19h.yaml b/arch/csr/Zihpm/mhpmcounter19h.yaml index a0ffd5a1e7..ea3dfdf355 100644 --- a/arch/csr/Zihpm/mhpmcounter19h.yaml +++ b/arch/csr/Zihpm/mhpmcounter19h.yaml @@ -12,7 +12,7 @@ mhpmcounter19h: base: 32 description: | Upper half of mhpmcounter19. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 32-0 diff --git a/arch/csr/Zihpm/mhpmcounter20.yaml b/arch/csr/Zihpm/mhpmcounter20.yaml index 08356be539..c8e33e9b4b 100644 --- a/arch/csr/Zihpm/mhpmcounter20.yaml +++ b/arch/csr/Zihpm/mhpmcounter20.yaml @@ -10,7 +10,7 @@ mhpmcounter20: priv_mode: M length: 64 description: Programmable hardware performance counter. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 63-0 diff --git a/arch/csr/Zihpm/mhpmcounter20h.yaml b/arch/csr/Zihpm/mhpmcounter20h.yaml index 1d53d08cbb..9754fff363 100644 --- a/arch/csr/Zihpm/mhpmcounter20h.yaml +++ b/arch/csr/Zihpm/mhpmcounter20h.yaml @@ -12,7 +12,7 @@ mhpmcounter20h: base: 32 description: | Upper half of mhpmcounter20. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 32-0 diff --git a/arch/csr/Zihpm/mhpmcounter21.yaml b/arch/csr/Zihpm/mhpmcounter21.yaml index 1d12023fff..f8c4bb73ea 100644 --- a/arch/csr/Zihpm/mhpmcounter21.yaml +++ b/arch/csr/Zihpm/mhpmcounter21.yaml @@ -10,7 +10,7 @@ mhpmcounter21: priv_mode: M length: 64 description: Programmable hardware performance counter. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 63-0 diff --git a/arch/csr/Zihpm/mhpmcounter21h.yaml b/arch/csr/Zihpm/mhpmcounter21h.yaml index a5cb4fea68..4daf180812 100644 --- a/arch/csr/Zihpm/mhpmcounter21h.yaml +++ b/arch/csr/Zihpm/mhpmcounter21h.yaml @@ -12,7 +12,7 @@ mhpmcounter21h: base: 32 description: | Upper half of mhpmcounter21. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 32-0 diff --git a/arch/csr/Zihpm/mhpmcounter22.yaml b/arch/csr/Zihpm/mhpmcounter22.yaml index 954ce5f804..aec2c85e62 100644 --- a/arch/csr/Zihpm/mhpmcounter22.yaml +++ b/arch/csr/Zihpm/mhpmcounter22.yaml @@ -10,7 +10,7 @@ mhpmcounter22: priv_mode: M length: 64 description: Programmable hardware performance counter. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 63-0 diff --git a/arch/csr/Zihpm/mhpmcounter22h.yaml b/arch/csr/Zihpm/mhpmcounter22h.yaml index 95c8d18003..9a7e3f6139 100644 --- a/arch/csr/Zihpm/mhpmcounter22h.yaml +++ b/arch/csr/Zihpm/mhpmcounter22h.yaml @@ -12,7 +12,7 @@ mhpmcounter22h: base: 32 description: | Upper half of mhpmcounter22. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 32-0 diff --git a/arch/csr/Zihpm/mhpmcounter23.yaml b/arch/csr/Zihpm/mhpmcounter23.yaml index f57072cbe4..e00604fbe2 100644 --- a/arch/csr/Zihpm/mhpmcounter23.yaml +++ b/arch/csr/Zihpm/mhpmcounter23.yaml @@ -10,7 +10,7 @@ mhpmcounter23: priv_mode: M length: 64 description: Programmable hardware performance counter. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 63-0 diff --git a/arch/csr/Zihpm/mhpmcounter23h.yaml b/arch/csr/Zihpm/mhpmcounter23h.yaml index 65d02dcdb1..3b38449a7d 100644 --- a/arch/csr/Zihpm/mhpmcounter23h.yaml +++ b/arch/csr/Zihpm/mhpmcounter23h.yaml @@ -12,7 +12,7 @@ mhpmcounter23h: base: 32 description: | Upper half of mhpmcounter23. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 32-0 diff --git a/arch/csr/Zihpm/mhpmcounter24.yaml b/arch/csr/Zihpm/mhpmcounter24.yaml index 0205f79f5c..6e605ed9f4 100644 --- a/arch/csr/Zihpm/mhpmcounter24.yaml +++ b/arch/csr/Zihpm/mhpmcounter24.yaml @@ -10,7 +10,7 @@ mhpmcounter24: priv_mode: M length: 64 description: Programmable hardware performance counter. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 63-0 diff --git a/arch/csr/Zihpm/mhpmcounter24h.yaml b/arch/csr/Zihpm/mhpmcounter24h.yaml index 8dde127bc2..c3ba869d9d 100644 --- a/arch/csr/Zihpm/mhpmcounter24h.yaml +++ b/arch/csr/Zihpm/mhpmcounter24h.yaml @@ -12,7 +12,7 @@ mhpmcounter24h: base: 32 description: | Upper half of mhpmcounter24. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 32-0 diff --git a/arch/csr/Zihpm/mhpmcounter25.yaml b/arch/csr/Zihpm/mhpmcounter25.yaml index 139cd5f67a..a7ebe7326b 100644 --- a/arch/csr/Zihpm/mhpmcounter25.yaml +++ b/arch/csr/Zihpm/mhpmcounter25.yaml @@ -10,7 +10,7 @@ mhpmcounter25: priv_mode: M length: 64 description: Programmable hardware performance counter. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 63-0 diff --git a/arch/csr/Zihpm/mhpmcounter25h.yaml b/arch/csr/Zihpm/mhpmcounter25h.yaml index 84b12c15ee..8eb4ce7427 100644 --- a/arch/csr/Zihpm/mhpmcounter25h.yaml +++ b/arch/csr/Zihpm/mhpmcounter25h.yaml @@ -12,7 +12,7 @@ mhpmcounter25h: base: 32 description: | Upper half of mhpmcounter25. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 32-0 diff --git a/arch/csr/Zihpm/mhpmcounter26.yaml b/arch/csr/Zihpm/mhpmcounter26.yaml index 4163d606ca..a61927f9aa 100644 --- a/arch/csr/Zihpm/mhpmcounter26.yaml +++ b/arch/csr/Zihpm/mhpmcounter26.yaml @@ -10,7 +10,7 @@ mhpmcounter26: priv_mode: M length: 64 description: Programmable hardware performance counter. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 63-0 diff --git a/arch/csr/Zihpm/mhpmcounter26h.yaml b/arch/csr/Zihpm/mhpmcounter26h.yaml index 3e628f8c44..a1acb91562 100644 --- a/arch/csr/Zihpm/mhpmcounter26h.yaml +++ b/arch/csr/Zihpm/mhpmcounter26h.yaml @@ -12,7 +12,7 @@ mhpmcounter26h: base: 32 description: | Upper half of mhpmcounter26. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 32-0 diff --git a/arch/csr/Zihpm/mhpmcounter27.yaml b/arch/csr/Zihpm/mhpmcounter27.yaml index e69452ce77..3566b567fc 100644 --- a/arch/csr/Zihpm/mhpmcounter27.yaml +++ b/arch/csr/Zihpm/mhpmcounter27.yaml @@ -10,7 +10,7 @@ mhpmcounter27: priv_mode: M length: 64 description: Programmable hardware performance counter. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 63-0 diff --git a/arch/csr/Zihpm/mhpmcounter27h.yaml b/arch/csr/Zihpm/mhpmcounter27h.yaml index d0f60b5706..f62c6c9baf 100644 --- a/arch/csr/Zihpm/mhpmcounter27h.yaml +++ b/arch/csr/Zihpm/mhpmcounter27h.yaml @@ -12,7 +12,7 @@ mhpmcounter27h: base: 32 description: | Upper half of mhpmcounter27. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 32-0 diff --git a/arch/csr/Zihpm/mhpmcounter28.yaml b/arch/csr/Zihpm/mhpmcounter28.yaml index 1c9f51a477..368d0ac85d 100644 --- a/arch/csr/Zihpm/mhpmcounter28.yaml +++ b/arch/csr/Zihpm/mhpmcounter28.yaml @@ -10,7 +10,7 @@ mhpmcounter28: priv_mode: M length: 64 description: Programmable hardware performance counter. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 63-0 diff --git a/arch/csr/Zihpm/mhpmcounter28h.yaml b/arch/csr/Zihpm/mhpmcounter28h.yaml index 450c372916..0e08592a5c 100644 --- a/arch/csr/Zihpm/mhpmcounter28h.yaml +++ b/arch/csr/Zihpm/mhpmcounter28h.yaml @@ -12,7 +12,7 @@ mhpmcounter28h: base: 32 description: | Upper half of mhpmcounter28. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 32-0 diff --git a/arch/csr/Zihpm/mhpmcounter29.yaml b/arch/csr/Zihpm/mhpmcounter29.yaml index fe47173fd3..db50e17f25 100644 --- a/arch/csr/Zihpm/mhpmcounter29.yaml +++ b/arch/csr/Zihpm/mhpmcounter29.yaml @@ -10,7 +10,7 @@ mhpmcounter29: priv_mode: M length: 64 description: Programmable hardware performance counter. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 63-0 diff --git a/arch/csr/Zihpm/mhpmcounter29h.yaml b/arch/csr/Zihpm/mhpmcounter29h.yaml index 846baa03c9..b68805332e 100644 --- a/arch/csr/Zihpm/mhpmcounter29h.yaml +++ b/arch/csr/Zihpm/mhpmcounter29h.yaml @@ -12,7 +12,7 @@ mhpmcounter29h: base: 32 description: | Upper half of mhpmcounter29. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 32-0 diff --git a/arch/csr/Zihpm/mhpmcounter3.yaml b/arch/csr/Zihpm/mhpmcounter3.yaml index 788e7ef3a5..a5eeaace7d 100644 --- a/arch/csr/Zihpm/mhpmcounter3.yaml +++ b/arch/csr/Zihpm/mhpmcounter3.yaml @@ -10,7 +10,7 @@ mhpmcounter3: priv_mode: M length: 64 description: Programmable hardware performance counter. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 63-0 diff --git a/arch/csr/Zihpm/mhpmcounter30.yaml b/arch/csr/Zihpm/mhpmcounter30.yaml index 8dc612806a..b9fd4f1a8b 100644 --- a/arch/csr/Zihpm/mhpmcounter30.yaml +++ b/arch/csr/Zihpm/mhpmcounter30.yaml @@ -10,7 +10,7 @@ mhpmcounter30: priv_mode: M length: 64 description: Programmable hardware performance counter. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 63-0 diff --git a/arch/csr/Zihpm/mhpmcounter30h.yaml b/arch/csr/Zihpm/mhpmcounter30h.yaml index fbb21243dc..6d9d7d2f6b 100644 --- a/arch/csr/Zihpm/mhpmcounter30h.yaml +++ b/arch/csr/Zihpm/mhpmcounter30h.yaml @@ -12,7 +12,7 @@ mhpmcounter30h: base: 32 description: | Upper half of mhpmcounter30. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 32-0 diff --git a/arch/csr/Zihpm/mhpmcounter31.yaml b/arch/csr/Zihpm/mhpmcounter31.yaml index 99926c1891..2452e30f84 100644 --- a/arch/csr/Zihpm/mhpmcounter31.yaml +++ b/arch/csr/Zihpm/mhpmcounter31.yaml @@ -10,7 +10,7 @@ mhpmcounter31: priv_mode: M length: 64 description: Programmable hardware performance counter. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 63-0 diff --git a/arch/csr/Zihpm/mhpmcounter31h.yaml b/arch/csr/Zihpm/mhpmcounter31h.yaml index e8af5fb4a3..d50b0827c5 100644 --- a/arch/csr/Zihpm/mhpmcounter31h.yaml +++ b/arch/csr/Zihpm/mhpmcounter31h.yaml @@ -12,7 +12,7 @@ mhpmcounter31h: base: 32 description: | Upper half of mhpmcounter31. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 32-0 diff --git a/arch/csr/Zihpm/mhpmcounter3h.yaml b/arch/csr/Zihpm/mhpmcounter3h.yaml index c26b5f60bb..32ff4884f5 100644 --- a/arch/csr/Zihpm/mhpmcounter3h.yaml +++ b/arch/csr/Zihpm/mhpmcounter3h.yaml @@ -12,7 +12,7 @@ mhpmcounter3h: base: 32 description: | Upper half of mhpmcounter3. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 32-0 diff --git a/arch/csr/Zihpm/mhpmcounter4.yaml b/arch/csr/Zihpm/mhpmcounter4.yaml index 9ca9d1361e..6f13e51998 100644 --- a/arch/csr/Zihpm/mhpmcounter4.yaml +++ b/arch/csr/Zihpm/mhpmcounter4.yaml @@ -10,7 +10,7 @@ mhpmcounter4: priv_mode: M length: 64 description: Programmable hardware performance counter. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 63-0 diff --git a/arch/csr/Zihpm/mhpmcounter4h.yaml b/arch/csr/Zihpm/mhpmcounter4h.yaml index a37024509f..96751620aa 100644 --- a/arch/csr/Zihpm/mhpmcounter4h.yaml +++ b/arch/csr/Zihpm/mhpmcounter4h.yaml @@ -12,7 +12,7 @@ mhpmcounter4h: base: 32 description: | Upper half of mhpmcounter4. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 32-0 diff --git a/arch/csr/Zihpm/mhpmcounter5.yaml b/arch/csr/Zihpm/mhpmcounter5.yaml index 72639fafa4..7bb0cb1d36 100644 --- a/arch/csr/Zihpm/mhpmcounter5.yaml +++ b/arch/csr/Zihpm/mhpmcounter5.yaml @@ -10,7 +10,7 @@ mhpmcounter5: priv_mode: M length: 64 description: Programmable hardware performance counter. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 63-0 diff --git a/arch/csr/Zihpm/mhpmcounter5h.yaml b/arch/csr/Zihpm/mhpmcounter5h.yaml index 91c492f09f..eefcf5c619 100644 --- a/arch/csr/Zihpm/mhpmcounter5h.yaml +++ b/arch/csr/Zihpm/mhpmcounter5h.yaml @@ -12,7 +12,7 @@ mhpmcounter5h: base: 32 description: | Upper half of mhpmcounter5. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 32-0 diff --git a/arch/csr/Zihpm/mhpmcounter6.yaml b/arch/csr/Zihpm/mhpmcounter6.yaml index f3abd1a371..c79e6f7d76 100644 --- a/arch/csr/Zihpm/mhpmcounter6.yaml +++ b/arch/csr/Zihpm/mhpmcounter6.yaml @@ -10,7 +10,7 @@ mhpmcounter6: priv_mode: M length: 64 description: Programmable hardware performance counter. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 63-0 diff --git a/arch/csr/Zihpm/mhpmcounter6h.yaml b/arch/csr/Zihpm/mhpmcounter6h.yaml index 471bc7aff1..218d4b474a 100644 --- a/arch/csr/Zihpm/mhpmcounter6h.yaml +++ b/arch/csr/Zihpm/mhpmcounter6h.yaml @@ -12,7 +12,7 @@ mhpmcounter6h: base: 32 description: | Upper half of mhpmcounter6. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 32-0 diff --git a/arch/csr/Zihpm/mhpmcounter7.yaml b/arch/csr/Zihpm/mhpmcounter7.yaml index 4e4f33cb5b..e26bfdcad4 100644 --- a/arch/csr/Zihpm/mhpmcounter7.yaml +++ b/arch/csr/Zihpm/mhpmcounter7.yaml @@ -10,7 +10,7 @@ mhpmcounter7: priv_mode: M length: 64 description: Programmable hardware performance counter. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 63-0 diff --git a/arch/csr/Zihpm/mhpmcounter7h.yaml b/arch/csr/Zihpm/mhpmcounter7h.yaml index 2eeeb919ef..7847f15fb7 100644 --- a/arch/csr/Zihpm/mhpmcounter7h.yaml +++ b/arch/csr/Zihpm/mhpmcounter7h.yaml @@ -12,7 +12,7 @@ mhpmcounter7h: base: 32 description: | Upper half of mhpmcounter7. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 32-0 diff --git a/arch/csr/Zihpm/mhpmcounter8.yaml b/arch/csr/Zihpm/mhpmcounter8.yaml index 570d99cd96..05ed7e02d6 100644 --- a/arch/csr/Zihpm/mhpmcounter8.yaml +++ b/arch/csr/Zihpm/mhpmcounter8.yaml @@ -10,7 +10,7 @@ mhpmcounter8: priv_mode: M length: 64 description: Programmable hardware performance counter. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 63-0 diff --git a/arch/csr/Zihpm/mhpmcounter8h.yaml b/arch/csr/Zihpm/mhpmcounter8h.yaml index 4c35ddeed6..75378f3a86 100644 --- a/arch/csr/Zihpm/mhpmcounter8h.yaml +++ b/arch/csr/Zihpm/mhpmcounter8h.yaml @@ -12,7 +12,7 @@ mhpmcounter8h: base: 32 description: | Upper half of mhpmcounter8. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 32-0 diff --git a/arch/csr/Zihpm/mhpmcounter9.yaml b/arch/csr/Zihpm/mhpmcounter9.yaml index edaad6c381..102138a9dc 100644 --- a/arch/csr/Zihpm/mhpmcounter9.yaml +++ b/arch/csr/Zihpm/mhpmcounter9.yaml @@ -10,7 +10,7 @@ mhpmcounter9: priv_mode: M length: 64 description: Programmable hardware performance counter. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 63-0 diff --git a/arch/csr/Zihpm/mhpmcounter9h.yaml b/arch/csr/Zihpm/mhpmcounter9h.yaml index bae4e35653..e5255ec848 100644 --- a/arch/csr/Zihpm/mhpmcounter9h.yaml +++ b/arch/csr/Zihpm/mhpmcounter9h.yaml @@ -12,7 +12,7 @@ mhpmcounter9h: base: 32 description: | Upper half of mhpmcounter9. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 32-0 diff --git a/arch/csr/Zihpm/mhpmcounterN.layout b/arch/csr/Zihpm/mhpmcounterN.layout index 61ef411af1..e55fef8287 100644 --- a/arch/csr/Zihpm/mhpmcounterN.layout +++ b/arch/csr/Zihpm/mhpmcounterN.layout @@ -8,7 +8,7 @@ priv_mode: M length: 64 description: Programmable hardware performance counter. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 63-0 diff --git a/arch/csr/Zihpm/mhpmcounterNh.layout b/arch/csr/Zihpm/mhpmcounterNh.layout index 3259756dbd..54dc2af205 100644 --- a/arch/csr/Zihpm/mhpmcounterNh.layout +++ b/arch/csr/Zihpm/mhpmcounterNh.layout @@ -10,7 +10,7 @@ base: 32 description: | Upper half of mhpmcounter<%= hpm_num %>. - definedBy: Zihpm + definedBy: Smhpm fields: COUNT: location: 32-0 diff --git a/arch/csr/Zihpm/mhpmevent10.yaml b/arch/csr/Zihpm/mhpmevent10.yaml index b97e3d4c86..49f943f1f2 100644 --- a/arch/csr/Zihpm/mhpmevent10.yaml +++ b/arch/csr/Zihpm/mhpmevent10.yaml @@ -13,7 +13,7 @@ mhpmevent10: description: | Programmable hardware performance counter event selector <% if ext?(:Sscofpmf) %> and overflow/filtering control<% end %> - definedBy: Sm + definedBy: Smhpm fields: OF: location: 63 diff --git a/arch/csr/Zihpm/mhpmevent11.yaml b/arch/csr/Zihpm/mhpmevent11.yaml index 124fc6f886..692b1a5b4a 100644 --- a/arch/csr/Zihpm/mhpmevent11.yaml +++ b/arch/csr/Zihpm/mhpmevent11.yaml @@ -13,7 +13,7 @@ mhpmevent11: description: | Programmable hardware performance counter event selector <% if ext?(:Sscofpmf) %> and overflow/filtering control<% end %> - definedBy: Sm + definedBy: Smhpm fields: OF: location: 63 diff --git a/arch/csr/Zihpm/mhpmevent12.yaml b/arch/csr/Zihpm/mhpmevent12.yaml index 4187adc594..93812b58b9 100644 --- a/arch/csr/Zihpm/mhpmevent12.yaml +++ b/arch/csr/Zihpm/mhpmevent12.yaml @@ -13,7 +13,7 @@ mhpmevent12: description: | Programmable hardware performance counter event selector <% if ext?(:Sscofpmf) %> and overflow/filtering control<% end %> - definedBy: Sm + definedBy: Smhpm fields: OF: location: 63 diff --git a/arch/csr/Zihpm/mhpmevent13.yaml b/arch/csr/Zihpm/mhpmevent13.yaml index 7225689bb9..55dadc5feb 100644 --- a/arch/csr/Zihpm/mhpmevent13.yaml +++ b/arch/csr/Zihpm/mhpmevent13.yaml @@ -13,7 +13,7 @@ mhpmevent13: description: | Programmable hardware performance counter event selector <% if ext?(:Sscofpmf) %> and overflow/filtering control<% end %> - definedBy: Sm + definedBy: Smhpm fields: OF: location: 63 diff --git a/arch/csr/Zihpm/mhpmevent14.yaml b/arch/csr/Zihpm/mhpmevent14.yaml index 29d06f1722..338a1a98dc 100644 --- a/arch/csr/Zihpm/mhpmevent14.yaml +++ b/arch/csr/Zihpm/mhpmevent14.yaml @@ -13,7 +13,7 @@ mhpmevent14: description: | Programmable hardware performance counter event selector <% if ext?(:Sscofpmf) %> and overflow/filtering control<% end %> - definedBy: Sm + definedBy: Smhpm fields: OF: location: 63 diff --git a/arch/csr/Zihpm/mhpmevent15.yaml b/arch/csr/Zihpm/mhpmevent15.yaml index d7f1dbb76c..52af89e2bb 100644 --- a/arch/csr/Zihpm/mhpmevent15.yaml +++ b/arch/csr/Zihpm/mhpmevent15.yaml @@ -13,7 +13,7 @@ mhpmevent15: description: | Programmable hardware performance counter event selector <% if ext?(:Sscofpmf) %> and overflow/filtering control<% end %> - definedBy: Sm + definedBy: Smhpm fields: OF: location: 63 diff --git a/arch/csr/Zihpm/mhpmevent16.yaml b/arch/csr/Zihpm/mhpmevent16.yaml index b6f3b71b35..2fd436ade9 100644 --- a/arch/csr/Zihpm/mhpmevent16.yaml +++ b/arch/csr/Zihpm/mhpmevent16.yaml @@ -13,7 +13,7 @@ mhpmevent16: description: | Programmable hardware performance counter event selector <% if ext?(:Sscofpmf) %> and overflow/filtering control<% end %> - definedBy: Sm + definedBy: Smhpm fields: OF: location: 63 diff --git a/arch/csr/Zihpm/mhpmevent17.yaml b/arch/csr/Zihpm/mhpmevent17.yaml index d0ec07e4c3..42fbcc358d 100644 --- a/arch/csr/Zihpm/mhpmevent17.yaml +++ b/arch/csr/Zihpm/mhpmevent17.yaml @@ -13,7 +13,7 @@ mhpmevent17: description: | Programmable hardware performance counter event selector <% if ext?(:Sscofpmf) %> and overflow/filtering control<% end %> - definedBy: Sm + definedBy: Smhpm fields: OF: location: 63 diff --git a/arch/csr/Zihpm/mhpmevent18.yaml b/arch/csr/Zihpm/mhpmevent18.yaml index d8640b9f08..c96e6b6056 100644 --- a/arch/csr/Zihpm/mhpmevent18.yaml +++ b/arch/csr/Zihpm/mhpmevent18.yaml @@ -13,7 +13,7 @@ mhpmevent18: description: | Programmable hardware performance counter event selector <% if ext?(:Sscofpmf) %> and overflow/filtering control<% end %> - definedBy: Sm + definedBy: Smhpm fields: OF: location: 63 diff --git a/arch/csr/Zihpm/mhpmevent19.yaml b/arch/csr/Zihpm/mhpmevent19.yaml index e86e752ca0..8116d7603e 100644 --- a/arch/csr/Zihpm/mhpmevent19.yaml +++ b/arch/csr/Zihpm/mhpmevent19.yaml @@ -13,7 +13,7 @@ mhpmevent19: description: | Programmable hardware performance counter event selector <% if ext?(:Sscofpmf) %> and overflow/filtering control<% end %> - definedBy: Sm + definedBy: Smhpm fields: OF: location: 63 diff --git a/arch/csr/Zihpm/mhpmevent20.yaml b/arch/csr/Zihpm/mhpmevent20.yaml index 67940c8184..fd59572d18 100644 --- a/arch/csr/Zihpm/mhpmevent20.yaml +++ b/arch/csr/Zihpm/mhpmevent20.yaml @@ -13,7 +13,7 @@ mhpmevent20: description: | Programmable hardware performance counter event selector <% if ext?(:Sscofpmf) %> and overflow/filtering control<% end %> - definedBy: Sm + definedBy: Smhpm fields: OF: location: 63 diff --git a/arch/csr/Zihpm/mhpmevent21.yaml b/arch/csr/Zihpm/mhpmevent21.yaml index 20a35d195f..61ad590193 100644 --- a/arch/csr/Zihpm/mhpmevent21.yaml +++ b/arch/csr/Zihpm/mhpmevent21.yaml @@ -13,7 +13,7 @@ mhpmevent21: description: | Programmable hardware performance counter event selector <% if ext?(:Sscofpmf) %> and overflow/filtering control<% end %> - definedBy: Sm + definedBy: Smhpm fields: OF: location: 63 diff --git a/arch/csr/Zihpm/mhpmevent22.yaml b/arch/csr/Zihpm/mhpmevent22.yaml index 86a66403e0..df980a1635 100644 --- a/arch/csr/Zihpm/mhpmevent22.yaml +++ b/arch/csr/Zihpm/mhpmevent22.yaml @@ -13,7 +13,7 @@ mhpmevent22: description: | Programmable hardware performance counter event selector <% if ext?(:Sscofpmf) %> and overflow/filtering control<% end %> - definedBy: Sm + definedBy: Smhpm fields: OF: location: 63 diff --git a/arch/csr/Zihpm/mhpmevent23.yaml b/arch/csr/Zihpm/mhpmevent23.yaml index fda54668df..f53e389f39 100644 --- a/arch/csr/Zihpm/mhpmevent23.yaml +++ b/arch/csr/Zihpm/mhpmevent23.yaml @@ -13,7 +13,7 @@ mhpmevent23: description: | Programmable hardware performance counter event selector <% if ext?(:Sscofpmf) %> and overflow/filtering control<% end %> - definedBy: Sm + definedBy: Smhpm fields: OF: location: 63 diff --git a/arch/csr/Zihpm/mhpmevent24.yaml b/arch/csr/Zihpm/mhpmevent24.yaml index f42bab9e30..8d1893cd33 100644 --- a/arch/csr/Zihpm/mhpmevent24.yaml +++ b/arch/csr/Zihpm/mhpmevent24.yaml @@ -13,7 +13,7 @@ mhpmevent24: description: | Programmable hardware performance counter event selector <% if ext?(:Sscofpmf) %> and overflow/filtering control<% end %> - definedBy: Sm + definedBy: Smhpm fields: OF: location: 63 diff --git a/arch/csr/Zihpm/mhpmevent25.yaml b/arch/csr/Zihpm/mhpmevent25.yaml index 302a08019b..84cf3a0bae 100644 --- a/arch/csr/Zihpm/mhpmevent25.yaml +++ b/arch/csr/Zihpm/mhpmevent25.yaml @@ -13,7 +13,7 @@ mhpmevent25: description: | Programmable hardware performance counter event selector <% if ext?(:Sscofpmf) %> and overflow/filtering control<% end %> - definedBy: Sm + definedBy: Smhpm fields: OF: location: 63 diff --git a/arch/csr/Zihpm/mhpmevent26.yaml b/arch/csr/Zihpm/mhpmevent26.yaml index 64c4aac7dc..3b16d2c81e 100644 --- a/arch/csr/Zihpm/mhpmevent26.yaml +++ b/arch/csr/Zihpm/mhpmevent26.yaml @@ -13,7 +13,7 @@ mhpmevent26: description: | Programmable hardware performance counter event selector <% if ext?(:Sscofpmf) %> and overflow/filtering control<% end %> - definedBy: Sm + definedBy: Smhpm fields: OF: location: 63 diff --git a/arch/csr/Zihpm/mhpmevent27.yaml b/arch/csr/Zihpm/mhpmevent27.yaml index 54f36bea5f..51b0c6288e 100644 --- a/arch/csr/Zihpm/mhpmevent27.yaml +++ b/arch/csr/Zihpm/mhpmevent27.yaml @@ -13,7 +13,7 @@ mhpmevent27: description: | Programmable hardware performance counter event selector <% if ext?(:Sscofpmf) %> and overflow/filtering control<% end %> - definedBy: Sm + definedBy: Smhpm fields: OF: location: 63 diff --git a/arch/csr/Zihpm/mhpmevent28.yaml b/arch/csr/Zihpm/mhpmevent28.yaml index 4edf6714a4..f63fdcc99a 100644 --- a/arch/csr/Zihpm/mhpmevent28.yaml +++ b/arch/csr/Zihpm/mhpmevent28.yaml @@ -13,7 +13,7 @@ mhpmevent28: description: | Programmable hardware performance counter event selector <% if ext?(:Sscofpmf) %> and overflow/filtering control<% end %> - definedBy: Sm + definedBy: Smhpm fields: OF: location: 63 diff --git a/arch/csr/Zihpm/mhpmevent29.yaml b/arch/csr/Zihpm/mhpmevent29.yaml index 248ad7a0f2..3c5fd3a70a 100644 --- a/arch/csr/Zihpm/mhpmevent29.yaml +++ b/arch/csr/Zihpm/mhpmevent29.yaml @@ -13,7 +13,7 @@ mhpmevent29: description: | Programmable hardware performance counter event selector <% if ext?(:Sscofpmf) %> and overflow/filtering control<% end %> - definedBy: Sm + definedBy: Smhpm fields: OF: location: 63 diff --git a/arch/csr/Zihpm/mhpmevent3.yaml b/arch/csr/Zihpm/mhpmevent3.yaml index 8ee84fa9e0..7fcc890787 100644 --- a/arch/csr/Zihpm/mhpmevent3.yaml +++ b/arch/csr/Zihpm/mhpmevent3.yaml @@ -13,7 +13,7 @@ mhpmevent3: description: | Programmable hardware performance counter event selector <% if ext?(:Sscofpmf) %> and overflow/filtering control<% end %> - definedBy: Sm + definedBy: Smhpm fields: OF: location: 63 diff --git a/arch/csr/Zihpm/mhpmevent30.yaml b/arch/csr/Zihpm/mhpmevent30.yaml index 2595d6e419..9946bd04bf 100644 --- a/arch/csr/Zihpm/mhpmevent30.yaml +++ b/arch/csr/Zihpm/mhpmevent30.yaml @@ -13,7 +13,7 @@ mhpmevent30: description: | Programmable hardware performance counter event selector <% if ext?(:Sscofpmf) %> and overflow/filtering control<% end %> - definedBy: Sm + definedBy: Smhpm fields: OF: location: 63 diff --git a/arch/csr/Zihpm/mhpmevent31.yaml b/arch/csr/Zihpm/mhpmevent31.yaml index aa9d251fdf..e85dd66d5e 100644 --- a/arch/csr/Zihpm/mhpmevent31.yaml +++ b/arch/csr/Zihpm/mhpmevent31.yaml @@ -13,7 +13,7 @@ mhpmevent31: description: | Programmable hardware performance counter event selector <% if ext?(:Sscofpmf) %> and overflow/filtering control<% end %> - definedBy: Sm + definedBy: Smhpm fields: OF: location: 63 diff --git a/arch/csr/Zihpm/mhpmevent4.yaml b/arch/csr/Zihpm/mhpmevent4.yaml index d03e228e43..8b75bca852 100644 --- a/arch/csr/Zihpm/mhpmevent4.yaml +++ b/arch/csr/Zihpm/mhpmevent4.yaml @@ -13,7 +13,7 @@ mhpmevent4: description: | Programmable hardware performance counter event selector <% if ext?(:Sscofpmf) %> and overflow/filtering control<% end %> - definedBy: Sm + definedBy: Smhpm fields: OF: location: 63 diff --git a/arch/csr/Zihpm/mhpmevent5.yaml b/arch/csr/Zihpm/mhpmevent5.yaml index 0a42a9e6a1..1599f5ea55 100644 --- a/arch/csr/Zihpm/mhpmevent5.yaml +++ b/arch/csr/Zihpm/mhpmevent5.yaml @@ -13,7 +13,7 @@ mhpmevent5: description: | Programmable hardware performance counter event selector <% if ext?(:Sscofpmf) %> and overflow/filtering control<% end %> - definedBy: Sm + definedBy: Smhpm fields: OF: location: 63 diff --git a/arch/csr/Zihpm/mhpmevent6.yaml b/arch/csr/Zihpm/mhpmevent6.yaml index 0e6217c418..f5f482c430 100644 --- a/arch/csr/Zihpm/mhpmevent6.yaml +++ b/arch/csr/Zihpm/mhpmevent6.yaml @@ -13,7 +13,7 @@ mhpmevent6: description: | Programmable hardware performance counter event selector <% if ext?(:Sscofpmf) %> and overflow/filtering control<% end %> - definedBy: Sm + definedBy: Smhpm fields: OF: location: 63 diff --git a/arch/csr/Zihpm/mhpmevent7.yaml b/arch/csr/Zihpm/mhpmevent7.yaml index ab11e346dc..eb5093137a 100644 --- a/arch/csr/Zihpm/mhpmevent7.yaml +++ b/arch/csr/Zihpm/mhpmevent7.yaml @@ -13,7 +13,7 @@ mhpmevent7: description: | Programmable hardware performance counter event selector <% if ext?(:Sscofpmf) %> and overflow/filtering control<% end %> - definedBy: Sm + definedBy: Smhpm fields: OF: location: 63 diff --git a/arch/csr/Zihpm/mhpmevent8.yaml b/arch/csr/Zihpm/mhpmevent8.yaml index da43598103..106928a0a7 100644 --- a/arch/csr/Zihpm/mhpmevent8.yaml +++ b/arch/csr/Zihpm/mhpmevent8.yaml @@ -13,7 +13,7 @@ mhpmevent8: description: | Programmable hardware performance counter event selector <% if ext?(:Sscofpmf) %> and overflow/filtering control<% end %> - definedBy: Sm + definedBy: Smhpm fields: OF: location: 63 diff --git a/arch/csr/Zihpm/mhpmevent9.yaml b/arch/csr/Zihpm/mhpmevent9.yaml index d76cdc62d6..b3227c6b75 100644 --- a/arch/csr/Zihpm/mhpmevent9.yaml +++ b/arch/csr/Zihpm/mhpmevent9.yaml @@ -13,7 +13,7 @@ mhpmevent9: description: | Programmable hardware performance counter event selector <% if ext?(:Sscofpmf) %> and overflow/filtering control<% end %> - definedBy: Sm + definedBy: Smhpm fields: OF: location: 63 diff --git a/arch/csr/Zihpm/mhpmeventN.layout b/arch/csr/Zihpm/mhpmeventN.layout index 3e3459786e..31b59fd724 100644 --- a/arch/csr/Zihpm/mhpmeventN.layout +++ b/arch/csr/Zihpm/mhpmeventN.layout @@ -11,7 +11,7 @@ description: | Programmable hardware performance counter event selector <%% if ext?(:Sscofpmf) %> and overflow/filtering control<%% end %> - definedBy: Sm + definedBy: Smhpm fields: OF: location: 63 diff --git a/arch/csr/cycleh.yaml b/arch/csr/cycleh.yaml index cdca452dd2..9bdc679311 100644 --- a/arch/csr/cycleh.yaml +++ b/arch/csr/cycleh.yaml @@ -27,7 +27,7 @@ cycleh: fields: COUNT: location: 31-0 - alias: mcycleh.COUNT + alias: mcycleh.COUNT[63:32] description: Alias of `mcycleh.COUNT`. type: RO-H reset_value: UNDEFINED_LEGAL diff --git a/arch/csr/mconfigptr.yaml b/arch/csr/mconfigptr.yaml index af48435845..7daee958b8 100644 --- a/arch/csr/mconfigptr.yaml +++ b/arch/csr/mconfigptr.yaml @@ -37,7 +37,9 @@ mconfigptr: priv_mode: M length: MXLEN - definedBy: Sm + definedBy: + name: Sm + version: ">=1.12" fields: ADDRESS: location_rv32: 31-0 diff --git a/arch/csr/menvcfg.yaml b/arch/csr/menvcfg.yaml index 9067d27569..96dda31664 100644 --- a/arch/csr/menvcfg.yaml +++ b/arch/csr/menvcfg.yaml @@ -126,7 +126,11 @@ menvcfg: not exist. priv_mode: M length: 64 - definedBy: U + definedBy: + allOf: + - name: Sm + version: ">=1.12" + - name: U fields: STCE: location: 63 diff --git a/arch/csr/menvcfgh.yaml b/arch/csr/menvcfgh.yaml index 3da46aede8..0062fae508 100644 --- a/arch/csr/menvcfgh.yaml +++ b/arch/csr/menvcfgh.yaml @@ -6,7 +6,11 @@ menvcfgh: description: Contains bits to enable/disable extensions priv_mode: M length: 32 - definedBy: Sm + definedBy: + allOf: + - name: Sm + version: ">=1.12" + - name: U fields: STCE: location: 31 diff --git a/arch/csr/mideleg.yaml b/arch/csr/mideleg.yaml index 5371ab0415..c72f8dfad4 100644 --- a/arch/csr/mideleg.yaml +++ b/arch/csr/mideleg.yaml @@ -6,9 +6,16 @@ mideleg: priv_mode: M length: MXLEN definedBy: - # after 1.9.1, mideleg does not exist whe S-mode is not implemented - - [S, "> 1.9.1"] - - [M, "< 1.0"] + # after 1.9.1, mideleg does not exist whe S-mode is not implemented + # we can represent that by making mideleg an S extension CSR post 1.9.1 + oneOf: + - name: Sm + version: "<= 1.9.1" + - allOf: + - name: S + version: "> 1.9.1" + - name: Sm + version: "> 1.9.1" description: | Controls exception delegation from M-mode to HS/S-mode diff --git a/arch/csr/misa.yaml b/arch/csr/misa.yaml index aaef5f8f3a..d82e3975a0 100644 --- a/arch/csr/misa.yaml +++ b/arch/csr/misa.yaml @@ -4,12 +4,13 @@ misa: long_name: Machine ISA Control address: 0x301 priv_mode: M - length: 64 + length: MXLEN description: Reports the XLEN and "major" extensions supported by the ISA. definedBy: Sm fields: MXL: - location: 63-62 + location_rv32: 31-30 + location_rv64: 63-62 description: XLEN in M-mode. type: RO reset_value: 2 @@ -89,7 +90,7 @@ misa: G: location: 6 description: | - Indicates support for all of the following extensions: `I`, `A`, `M`, `F`, 'D'. + Indicates support for all of the following extensions: `I`, `A`, `M`, `F`, `D`. type(): | if ((implemented?(ExtensionName::A) && MUTABLE_MISA_A) || (implemented?(ExtensionName::M) && MUTABLE_MISA_M) || diff --git a/arch/csr/mseccfg.yaml b/arch/csr/mseccfg.yaml index 5f1da43fca..7f90c9de3b 100644 --- a/arch/csr/mseccfg.yaml +++ b/arch/csr/mseccfg.yaml @@ -6,6 +6,8 @@ mseccfg: priv_mode: M length: 64 description: Machine Security Configuration - definedBy: M + definedBy: + name: Sm + version: ">=1.12" fields: {} \ No newline at end of file diff --git a/arch/csr/mseccfgh.yaml b/arch/csr/mseccfgh.yaml new file mode 100644 index 0000000000..6aa15924cb --- /dev/null +++ b/arch/csr/mseccfgh.yaml @@ -0,0 +1,13 @@ +# yaml-language-server: $schema=../../schemas/csr_schema.json + +mseccfgh: + long_name: Most significant 32 bits of Machine Security Configuration + address: 0x757 + priv_mode: M + length: 32 + description: Machine Security Configuration + definedBy: + name: Sm + version: ">=1.12" + fields: {} + \ No newline at end of file diff --git a/arch/csr/mstatus.yaml b/arch/csr/mstatus.yaml index 98701bec1b..3ffadc08e0 100644 --- a/arch/csr/mstatus.yaml +++ b/arch/csr/mstatus.yaml @@ -241,9 +241,29 @@ mstatus: *`hfence.vvma`, `sfence.w.inval`, or `sfence.inval.ir` to trap. * Any additional traps in VS-mode (controlled via `hstatus.VTVM` instead). - type: RW + type(): | + if (CSR[misa].S == 1'b0) { + return CsrFieldType::RO; + } else { + return CsrFieldType::RW; + } definedBy: S - reset_value: UNDEFINED_LEGAL + reset_value(): | + if (CSR[misa].S == 1'b0) { + return 0; + } else if (MSTATUS_TVM_IMPLEMENTED) { + return UNDEFINED_LEGAL; + } else { + return 0; + } + sw_write(csr_value): | + if (CSR[misa].S == 1'b0) { + return 0; + } else if (MSTATUS_TVM_IMPLEMENTED) { + return csr_value.TVM; + } else { + return 0; + } MXR: location: 19 description: | @@ -286,7 +306,8 @@ mstatus: `mstatus.MPRV` is cleared on any exception return (`mret` or `sret` instruction, regardless of the trap handler privilege mode). definedBy: U - type: RW-H + type(): | + return (CSR[misa].U == 1'b1) ? CsrFieldType::RWH : CsrFieldType::RO; reset_value: 0 XS: location: 16-15 @@ -308,9 +329,37 @@ mstatus: When a floating point register, or the fCSR register is written, FS obtains the value 3. Values 1 and 2 are valid write values for software, but are not interpreted by hardware other than to possibly enable a previously-disabled floating point unit. - type: RW-H + type(): | + if (CSR[misa].F == 1'b1){ + return CsrFieldType::RWH; + } else if ((CSR[misa].S == 1'b0) && (CSR[misa].F == 1'b0)) { + # must be read-only-0 + return CsrFieldType::RO; + } else { + # there will be no hardware update in this case because we know the F extension isn't implemented + return MSTATUS_FS_WRITEABLE ? CsrFieldType::RW : CsrFieldType::RO; + } definedBy: F - reset_value: UNDEFINED_LEGAL + reset_value(): | + if (CSR[misa].F == 1'b1){ + return UNDEFINED_LEGAL; + } else if ((CSR[misa].S == 1'b0) && (CSR[misa].F == 1'b0)) { + # must be read-only-0 + return 0; + } else { + # there will be no hardware update in this case because we know the F extension isn't implemented + return MSTATUS_FS_WRITEABLE ? UNDEFINED_LEGAL : 0; + } + sw_write(csr_value): | + if (CSR[misa].F == 1'b1){ + return ary_includes?<$array_size(MSTATUS_FS_LEGAL_VALUES), 2>(MSTATUS_FS_LEGAL_VALUES, csr_value.FS) ? csr_value.FS : UNDEFINED_LEGAL_DETERMINISTIC; + } else if ((CSR[misa].S == 1'b0) && (CSR[misa].F == 1'b0)) { + # must be read-only-0 + return 0; + } else { + # there will be no hardware update in this case because we know the F extension isn't implemented + return ary_includes?<$array_size(MSTATUS_FS_LEGAL_VALUES), 2>(MSTATUS_FS_LEGAL_VALUES, csr_value.FS) ? csr_value.FS : UNDEFINED_LEGAL_DETERMINISTIC; + } MPP: location: 12-11 description: | @@ -449,9 +498,11 @@ mstatus: Can also be written by software without immediate side effect. Other than serving as a record of nested traps as described above, `mstatus.SPIE` does not affect execution. - type: RW-H + type(): | + return (CSR[misa].S == 1'b1) ? CsrFieldType::RWH : CsrFieldType::RO; definedBy: S - reset_value: UNDEFINED_LEGAL + reset_value(): | + return (CSR[misa].S == 1'b1) ? UNDEFINED_LEGAL : 0; MIE: location: 3 description: | @@ -484,6 +535,8 @@ mstatus: * When 0, all (H)S-mode interrupts are disabled when the current privilege level is (H)S (M-mode interrupts are still enabled). * When 1, (H)S-mode interrupts that are not otherwise disabled with a field in `sie` are enabled. - type: RW-H + type(): | + return (CSR[misa].S == 1'b1) ? CsrFieldType::RWH : CsrFieldType::RO; definedBy: S - reset_value: UNDEFINED_LEGAL + reset_value(): | + return (CSR[misa].S == 1'b1) ? UNDEFINED_LEGAL : 0; diff --git a/arch/csr/satp.yaml b/arch/csr/satp.yaml index 4b0b43d84b..28906d04e1 100644 --- a/arch/csr/satp.yaml +++ b/arch/csr/satp.yaml @@ -119,7 +119,7 @@ satp: return UNDEFINED_LEGAL_DETERMINISTIC; } } else { - XReg shamt = (CSR[mstatus].SXL == $bits(XRegWidth::XLEN64)) ? 16 : 9; + XReg shamt = (XLEN == 32 || (CSR[mstatus].SXL == $bits(XRegWidth::XLEN32))) ? 9 : 16; XReg all_ones = ((1 << shamt) - 1); XReg largest_allowed_asid = (1 << shamt) - 1; diff --git a/arch/csr/senvcfg.yaml b/arch/csr/senvcfg.yaml index a06a95d35b..032fc52e0c 100644 --- a/arch/csr/senvcfg.yaml +++ b/arch/csr/senvcfg.yaml @@ -6,7 +6,11 @@ senvcfg: description: Contains bits to enable/disable extensions priv_mode: S length: 64 - definedBy: S + definedBy: + allOf: + - name: Sm + version: ">=1.12" + - name: S fields: CBZE: location: 7 diff --git a/arch/csr/time.yaml b/arch/csr/time.yaml index 7d5f5aa22f..7c31dc4858 100644 --- a/arch/csr/time.yaml +++ b/arch/csr/time.yaml @@ -28,7 +28,7 @@ time: -- priv_mode: U length: 64 - definedBy: U + definedBy: Zicntr fields: COUNT: location: 63-0 diff --git a/arch/csr/timeh.yaml b/arch/csr/timeh.yaml new file mode 100644 index 0000000000..8bab1a3190 --- /dev/null +++ b/arch/csr/timeh.yaml @@ -0,0 +1,80 @@ +# yaml-language-server: $schema=../../schemas/csr_schema.json + +timeh: + long_name: High-half timer for RDTIME Instruction + address: 0xC81 + description: | + [when,"TIME_CSR_IMPLEMENTED == false"] + This CSR does not exist, and access will cause an IllegalInstruction exception. + + [when,"TIME_CSR_IMPLEMENTED == true"] + -- + Shadow of the memory-mapped M-mode CSR `mtimeh`. + + Privilege mode access is controlled with `mcounteren.TM`, `scounteren.TM`, and `hcounteren.TM` as follows: + + [%autowidth,cols="1,1,1,1,1,1,1",separator="!"] + !=== + .2+h![.rotate]#`mcounteren.TM`# .2+h! [.rotate]#`scounteren.TM`# .2+h! [.rotate]#`scounteren.TM`# + 4+^.>h! `time` behavior + .^h! S-mode .^h! U-mode .^h! VS-mode .^h! VU-mode + + ! 0 ! - ! - ! `Illegal Instruction` ! `Illegal Instruction` ! `Illegal Instruction` ! `Illegal Instruction` + ! 1 ! 0 ! 0 ! read-only ! `Illegal Instruction` ! `Illegal Instruction` ! `Illegal Instruction` + ! 1 ! 1 ! 0 ! read-only ! read-only ! `Illegal Instruction` ! `Illegal Instruction` + ! 1 ! 0 ! 1 ! read-only ! `Illegal Instruction` ! read-only ! `Illegal Instruction` + ! 1 ! 1 ! 1 ! read-only ! read-only ! read-only ! read-only + !=== + -- + priv_mode: U + length: 32 + definedBy: Zicntr + fields: + COUNT: + location: 31-0 + alias: time.COUNT[63:32] + description: | + Reports the most significant 32 bits of the current wall-clock time from the timer device. + type: RO-H + reset_value: UNDEFINED_LEGAL + sw_read(): | + if (!TIME_CSR_IMPLEMENTED) { + unimplemented_csr($encoding); + } + + # access is determined by *counteren CSRs + if (mode() == PrivilegeMode::S) { + # S-mode is present -> + # mcounteren determines access in S-mode + if (CSR[mcounteren].TM == 1'b0) { + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } + } else if (mode() == PrivilegeMode::U) { + if (CSR[misa].S == 1'b1) { + # S-mode is present -> + # mcounteren and scounteren together determine access in U-mode + if ((CSR[mcounteren].TM & CSR[scounteren].TM) == 1'b0) { + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } + } else if (CSR[mcounteren].TM == 1'b0) { + # S-mode is not present -> + # mcounteren determines access in U-mode + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } + } else if (mode() == PrivilegeMode::VS) { + # access in VS mode + if (CSR[hcounteren].TM == 1'b0 && CSR[mcounteren] == 1'b1) { + raise(ExceptionCode::VirtualInstruction, mode(), $encoding); + } else if (CSR[mcounteren].TM == 1'b0) { + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } + } else if (mode() == PrivilegeMode::VU) { + # access in VU mode + if (((CSR[hcounteren].TM & CSR[scounteren].TM) == 1'b0) && (CSR[mcounteren].IR == 1'b1)) { + raise(ExceptionCode::VirtualInstruction, mode(), $encoding); + } else if (CSR[mcounteren].TM == 1'b0) { + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } + } + + return read_mtime()[63:32]; diff --git a/arch/ext/F.yaml b/arch/ext/F.yaml index f88bed272b..9586d500e0 100644 --- a/arch/ext/F.yaml +++ b/arch/ext/F.yaml @@ -238,4 +238,17 @@ F: description: | Indicates whether or not the `F` extension can be disabled with the `misa.F` bit. schema: - type: boolean \ No newline at end of file + type: boolean + MSTATUS_FS_LEGAL_VALUES: + description: | + The set of values that mstatus.FS will accept from a software write. + schema: + type: array + items: + type: integer + enum: [0,1,2,3] + maxItems: 4 + uniqueItems: true + also_defined_in: S + extra_validation: | + assert MSTATUS_FS_LEGAL_VALUES.include?(0) && MSTATUS_FS_LEGAL_VALUES.include?(3) if ext?(:F) \ No newline at end of file diff --git a/arch/ext/H.yaml b/arch/ext/H.yaml index 918db6efc2..dd8270b5bd 100644 --- a/arch/ext/H.yaml +++ b/arch/ext/H.yaml @@ -8,8 +8,8 @@ H: state: ratified ratification_date: 2019-12 requires: - oneOf: - - [S, '>= 1.12.0'] + name: S + version: '>= 1.12.0' interrupt_codes: - num: 2 name: Virtual supervisor software interrupt diff --git a/arch/ext/MockExt.yaml b/arch/ext/MockExt.yaml new file mode 100644 index 0000000000..bace6c7034 --- /dev/null +++ b/arch/ext/MockExt.yaml @@ -0,0 +1,151 @@ +# yaml-language-server: $schema=../../schemas/ext_schema.json + +MockExt: + type: privileged + long_name: Mock Extension (for testing database) + description: This is just for testing + versions: + - version: "1.0.0" + state: development + params: + MOCK_ENUM_2_INTS: + description: foo + schema: + type: integer + enum: [32, 64] + MOCK_ENUM_2_STRINGS: + description: foo + schema: + type: string + enum: ["low", "high"] + MOCK_BOOL_1: + description: foo + schema: + type: boolean + MOCK_BOOL_2: + description: foo + schema: + type: boolean + MOCK_32_BIT_INT: + description: foo + schema: + type: integer + minimum: 0 + maximum: 0xffffffff + MOCK_64_BIT_INT: + description: foo + schema: + type: integer + minimum: 0 + maximum: 0xffffffffffffffff + MOCK_1_BIT_INT: + description: foo + schema: + type: integer + minimum: 0 + maximum: 1 + MOCK_2_BIT_INT: + description: foo + schema: + type: integer + minimum: 0 + maximum: 3 + MOCK_25_BIT_INT: + description: foo + schema: + type: integer + minimum: 0 + maximum: 33554431 + MOCK_INT_RANGE_0_TO_2: + description: foo + schema: + type: integer + minimum: 0 + maximum: 2 + MOCK_INT_RANGE_0_TO_127: + description: foo + schema: + type: integer + minimum: 0 + maximum: 127 + MOCK_INT_RANGE_0_TO_999: + description: foo + schema: + type: integer + minimum: 0 + maximum: 999 + MOCK_INT_RANGE_0_TO_1023: + description: foo + schema: + type: integer + minimum: 0 + maximum: 1023 + MOCK_INT_RANGE_1000_TO_2048: + description: foo + schema: + type: integer + minimum: 1000 + maximum: 2048 + MOCK_INT_RANGE_0_TO_128: + description: foo + schema: + type: integer + minimum: 0 + maximum: 128 + MOCK_INT_RANGE_1_TO_128: + description: foo + schema: + type: integer + minimum: 1 + maximum: 128 + MOCK_ARRAY_INT_ENUM: + description: foo + schema: + type: array + items: + type: integer + enum: [0, 1] + minItems: 1 + maxItems: 2 + uniqueItems: true + MOCK_ARRAY_MIN_ONLY: + description: foo + schema: + type: array + items: + type: integer + enum: [0, 1] + minItems: 3 + MOCK_ARRAY_MAX_ONLY: + description: foo + schema: + type: array + items: + type: integer + enum: [0, 1] + maxItems: 10 + MOCK_ARRAY_STRING_ENUM1: + description: foo + schema: + type: array + items: + type: string + enum: [ABC, DEF, GHI] + MOCK_ARRAY_STRING_ENUM2: + description: foo + schema: + type: array + items: + type: string + enum: [ABC, DEF, GHI] + MOCK_ARRAY_BOOL_ARRAY_OF_8_FIRST_2_FALSE: + description: foo + schema: + type: array + items: + - const: false + - const: false + additionalItems: + type: boolean + maxItems: 8 + minItems: 8 \ No newline at end of file diff --git a/arch/ext/S.yaml b/arch/ext/S.yaml index c6b5d50ce3..4a7dc018d2 100644 --- a/arch/ext/S.yaml +++ b/arch/ext/S.yaml @@ -7,7 +7,9 @@ S: - version: "1.12.0" state: ratified ratification_date: 2021-12 - requires: [U, "= 1.12.0"] + requires: + name: U + version: "= 1.12.0" description: | This chapter describes the RISC-V supervisor-level architecture, which contains a common core that is used with various supervisor-level @@ -242,4 +244,33 @@ S: type: boolean default: false extra_validation: - assert TRAP_ON_SFENCE_VMA_WHEN_SATP_MODE_IS_READ_ONLY == false if ext?(:Sv32) || ext?(:Sv39) || ext?(:Sv48) || ext?(:Sv57) \ No newline at end of file + assert TRAP_ON_SFENCE_VMA_WHEN_SATP_MODE_IS_READ_ONLY == false if ext?(:Sv32) || ext?(:Sv39) || ext?(:Sv48) || ext?(:Sv57) + MSTATUS_FS_WRITEABLE: + description: | + When `S` is enabled but `F` is not, mstatus.FS is optionally writeable. + + This parameter only has an effect when both S and F mode are disabled. + schema: + type: boolean + extra_validation: + assert MSTATUS_FS_WRITEABLE == true if ext?(:F) + MSTATUS_FS_LEGAL_VALUES: + description: | + The set of values that mstatus.FS will accept from a software write. + schema: + type: array + items: + type: integer + enum: [0,1,2,3] + maxItems: 4 + uniqueItems: true + also_defined_in: F + extra_validation: | + assert MSTATUS_FS_LEGAL_VALUES.include?(0) && MSTATUS_FS_LEGAL_VALUES.include?(3) if ext?(:F) + MSTATUS_TVM_IMPLEMENTED: + description: | + Whether or not mstatus.TVM is implemented. + + When not implemented mstatus.TVM will be read-only-zero. + schema: + type: boolean diff --git a/arch/ext/Sm.yaml b/arch/ext/Sm.yaml index 81925eb0ab..1925b79989 100644 --- a/arch/ext/Sm.yaml +++ b/arch/ext/Sm.yaml @@ -18,7 +18,6 @@ Sm: - Made the `mstatus`.MPP field *WARL*, rather than *WLRL*. - Made the unused `__x__ip` fields *WPRI*, rather than *WIRI*. - Made the unused `misa` fields *WARL*, rather than *WIRI*. - - Made the unused `pmpaddr` and `pmpcfg` fields *WARL*, rather than *WIRI*. - Rectified an editing error that misdescribed the mechanism by which `mstatus.__x__IE` is written upon an exception. - Described scheme for emulating misaligned AMOs. @@ -26,9 +25,6 @@ Sm: with variable IALIGN. - Specified the behavior of writing self-contradictory values to the `misa` register. - - Defined the `mcountinhibit` CSR, which stops performance counters from - incrementing to reduce energy consumption. - - Specified semantics for PMP regions coarser than four bytes. - Specified contents of CSRs across XLEN modification. - Moved PLIC chapter into its own document. - version: "1.12.0" @@ -45,11 +41,11 @@ Sm: page-based virtual memory, even if VM is not currently enabled. - Removed the N extension. - Defined the mandatory RV32-only CSR `mstatush`, which contains most of - the same fields as the upper 32 bits of RV64’s `mstatus`. + the same fields as the upper 32 bits of RV64's `mstatus`. - Defined the mandatory CSR `mconfigptr`, which if nonzero contains the address of a configuration data structure. - Defined optional `mseccfg` and `mseccfgh` CSRs, which control the - machine’s security configuration. + machine's security configuration. - Defined `menvcfg` CSR (and RV32-only `menvcfgh`), which control various characteristics of the execution environment. - Designated part of SYSTEM major opcode for custom use. @@ -58,8 +54,6 @@ Sm: - Made priority of load/store/AMO address-misaligned exceptions implementation-defined relative to load/store/AMO page-fault and access-fault exceptions. - - PMP reset values are now platform-defined. - - An additional 48 optional PMP registers have been defined. - Software breakpoint exceptions are permitted to write either 0 or the `pc` to `__x__tval`. - Specified relaxed constraints for implicit reads of non-idempotent regions. @@ -249,8 +243,8 @@ Sm: [separator="!"] !=== - ! high ! Misaligned load/store/AMO exceptions are always higher priority than load/store/AMO page-fault and access-fault exceptions. ! low ! Misaligned load/store/AMO exceptions are always lower priority than load/store/AMO page-fault and access-fault exceptions. + ! high ! Misaligned load/store/AMO exceptions are always higher priority than load/store/AMO page-fault and access-fault exceptions. !=== MISALIGNED_LDST_EXCEPTION_PRIORITY cannot be "high" when MAX_MISALIGNED_ATOMICITY_GRANULE_SIZE @@ -258,19 +252,19 @@ Sm: address translation. schema: type: string - enum: ["high", "low"] + enum: ["low", "high"] extra_validation: | assert (MISALIGNED_LDST_EXCEPTION_PRIORITY == "low") if MAX_MISALIGNED_ATOMICITY_GRANULE_SIZE.positive? MAX_MISALIGNED_ATOMICITY_GRANULE_SIZE: description: | The maximum granule size, in bytes, that the hart can atomically perform a - misligned load/store/AMO without raising a Misaligned exception. When MAX_MISALIGNED_ATOMICITY_GRANULE_SIZE is 0, the hart + misaligned load/store/AMO without raising a Misaligned exception. When MAX_MISALIGNED_ATOMICITY_GRANULE_SIZE is 0, the hart cannot atomically perform a misaligned load/store/AMO. When a power of two, the hart can atomically load/store/AMO a misaligned access that is fully contained in a MAX_MISALIGNED_ATOMICITY_GRANULE_SIZE-aligned region. [NOTE] - Even if the hart is capable of performing a misligned load/store/AMO atomically, + Even if the hart is capable of performing a misaligned load/store/AMO atomically, a misaligned exception may still occur if the access does not have the appropriate Misaligned Atomicity Granule PMA set. schema: @@ -288,43 +282,6 @@ Sm: schema: type: string enum: ["by_byte", "custom"] - COUNTINHIBIT_EN: - description: | - Indicates which hardware performance monitor counters can be disabled from `mcountinhibit`. - - An unimplemented counter cannot be specified, i.e., if HPM_COUNTER_EN[3] is false, - it would be illegal to set COUNTINHIBIT_EN[3] to true. - - COUNTINHIBIT_EN[1] can never be true, since it corresponds to `mcountinhibit.TM`, - which is always read-only-0. - - COUNTINHIBIT_EN[3:31] must all be false if `Zihpm` is not implemented. - schema: - type: array - items: - - type: boolean - - const: false - - type: boolean - additionalItems: - type: boolean - maxItems: 32 - minItems: 32 - MCOUNTENABLE_EN: - description: | - Indicates which counters can be delegated via `mcounteren`. - - An unimplemented counter cannot be specified, i.e., if - HPM_COUNTER_EN[3] is false, it would be illegal to set - MCOUNTENABLE_EN[3] to true. - - MCOUNTENABLE_EN[0:2] must all be false if `Zicntr` is not implemented. - MCOUNTENABLE_EN[3:31] must all be false if `Zihpm` is not implemented. - schema: - type: array - items: - type: boolean - maxItems: 32 - minItems: 32 TRAP_ON_ILLEGAL_WLRL: description: | When true, writing an illegal value to a WLRL CSR field raises an `IllegalInstruction` exception. @@ -443,66 +400,24 @@ Sm: type: boolean MTVAL_WIDTH: description: | - The number of implemented bits in `mtval`. + The number of implemented bits in the `mtval` CSR. + This is the CSR that may be written when a trap is taken into M-mode with exception-specific information to + assist software in handling the trap (e.g., address associated with exception). Must be greater than or equal to _max_(`PHYS_ADDR_WIDTH`, `VA_SIZE`) schema: type: integer - maximum: 0xffffffffffffffff + maximum: 64 CONFIG_PTR_ADDRESS: description: | Physical address of the unified discovery configuration data structure. This address is reported in the `mconfigptr` CSR. + TODO: GitHub issue 53 schema: type: integer # GitHub issue 53 # when: # version: ">= 1.12.0" - NUM_PMP_ENTRIES: - description: | - Number of implemented PMP entries. Can be any value between 0-64, inclusive. - - The architecture mandates that the number of implemented PMP registers - must appear to be 0, 16, or 64. - - Therefore, pmp registers will behave as follows according to NUN_PMP_ENTRIES: - - [separator="!"] - !=== - ! NUM_PMP_ENTRIES ! pmpaddr<0-15> / pmpcfg<0-3> ! pmpaddr<16-63> / pmpcfg<4-15> - ! 0 ! N ! N - ! 1-16 ! Y ! N - ! 17-64 ! Y ! Y - !=== - - ** N = Not implemented; access will cause `IllegalInstruction` - if TRAP_ON_UNIMPLEMENTED_CSR is true - ** Y = Implemented; access will not cause an exception (from M-mode), but register - may be read-only-zero if NUM_PMP_ENTRIES is less than the corresponding register - - [NOTE] - `pmpcfgN` for an odd N never exists when XLEN == 64 - - When NUM_PMP_ENTRIES is not exactly 0, 16, or 64, some extant pmp registers, - and associated pmpNcfg, will be read-only zero (but will never cause an exception). - schema: - type: integer - minimum: 0 - maximum: 64 - PMP_GRANULARITY: - description: | - log2 of the smallest supported PMP region. - - Generally, for systems with an MMU, should not be smaller than 12, - as that would preclude caching PMP results in the TLB along with - virtual memory translations - - Note that PMP_GRANULARITY is equal to G+2 (not G) as described in - the privileged architecture. - schema: - type: integer - minimum: 2 - maximum: 66 PMA_GRANULARITY: description: | log2 of the smallest supported PMA region. @@ -535,23 +450,6 @@ Sm: schema: type: string enum: [little, big, dynamic] - TIME_CSR_IMPLEMENTED: - description: | - Whether or not a real hardware `time` CSR exists. Implementations can either provide a real - CSR or emulate access at M-mode. - - Possible values: - - true:: - `time`/`timeh` exists, and accessing it will not cause an IllegalInstruction trap - - false:: - `time`/`timeh` does not exist. - Accessing the CSR will cause an IllegalInstruction trap or enter an unpredictable state, - depending on TRAP_ON_UNIMPLEMENTED_CSR. - Privileged software may emulate the `time` CSR, or may pass the exception to a lower level. - schema: - type: boolean MISA_CSR_IMPLEMENTED: description: | Whether or not the `misa` CSR returns zero or a non-zero value. @@ -567,7 +465,7 @@ Sm: type: boolean MTVEC_MODES: description: | - The 2-bit `mtvec.MODE` field has several possibile treatments for an implementation. + Modes supported by `mtvec.MODE`. If only one, it is assumed to be read-only with that value. schema: type: array items: diff --git a/arch/ext/Smhpm.yaml b/arch/ext/Smhpm.yaml new file mode 100644 index 0000000000..4039a88847 --- /dev/null +++ b/arch/ext/Smhpm.yaml @@ -0,0 +1,89 @@ +# yaml-language-server: $schema=../../schemas/ext_schema.json + +Smhpm: + long_name: M-mode programmable hardware performance counters + description: M-mode programmable hardware performance counters + type: privileged + versions: + - version: "1.11.0" + state: ratified + ratification_date: 2019-12 + changes: + - Defined the `mcountinhibit` CSR, which stops performance counters from + incrementing to reduce energy consumption. + - version: "1.12.0" + state: ratified + ratification_date: 2021-12 + changes: + - PMP changes require an SFENCE.VMA on any hart that implements + page-based virtual memory, even if VM is not currently enabled. + - PMP reset values are now platform-defined. + - An additional 48 optional PMP registers have been defined. + - version: "1.13.0" + state: frozen + ratification_date: 2023-12 + params: + HPM_COUNTER_EN: + description: | + List of HPM counters that are enabled. + There is one entry for each hpmcounter. + + The first three entries *must* be false (as they correspond to CY, IR, TM in, _e.g._ `mhmpcountinhibit`) + Index 3 in HPM_COUNTER_EN corresponds to hpmcounter3. + Index 31 in HPM_COUNTER_EN corresponds to hpmcounter31. + schema: + type: array + items: + - const: false + - const: false + - const: false + additionalItems: + type: boolean + maxItems: 32 + minItems: 32 + HPM_EVENTS: + description: | + List of defined event numbers that can be written into hpmeventN + schema: + type: array + items: + type: integer + minimum: 0 + maximum: 0x03ffffffffffffff # bits 63-58 are used by `Sscofpmf` + COUNTINHIBIT_EN: + description: | + Indicates which hardware performance monitor counters can be disabled from `mcountinhibit`. + + An unimplemented counter cannot be specified, i.e., if HPM_COUNTER_EN[3] is false, + it would be illegal to set COUNTINHIBIT_EN[3] to true. + + COUNTINHIBIT_EN[1] can never be true, since it corresponds to `mcountinhibit.TM`, + which is always read-only-0. + + COUNTINHIBIT_EN[3:31] must all be false if `Zihpm` is not implemented. + schema: + type: array + items: + - type: boolean + - const: false + - type: boolean + additionalItems: + type: boolean + maxItems: 32 + minItems: 32 + MCOUNTENABLE_EN: + description: | + Indicates which counters can be delegated via `mcounteren`. + + An unimplemented counter cannot be specified, i.e., if + HPM_COUNTER_EN[3] is false, it would be illegal to set + MCOUNTENABLE_EN[3] to true. + + MCOUNTENABLE_EN[0:2] must all be false if `Zicntr` is not implemented. + MCOUNTENABLE_EN[3:31] must all be false if `Zihpm` is not implemented. + schema: + type: array + items: + type: boolean + maxItems: 32 + minItems: 32 \ No newline at end of file diff --git a/arch/ext/Smpmp.yaml b/arch/ext/Smpmp.yaml new file mode 100644 index 0000000000..8d92db00ff --- /dev/null +++ b/arch/ext/Smpmp.yaml @@ -0,0 +1,83 @@ +# yaml-language-server: $schema=../../schemas/ext_schema.json + +Smpmp: + type: privileged + long_name: Physical Memory Protection + versions: + - version: "1.11.0" + state: ratified + ratification_date: 2019-12 + changes: + - Made the unused `pmpaddr` and `pmpcfg` fields *WARL*, rather than *WIRI*. + - Specified semantics for PMP regions coarser than four bytes. + - version: "1.12.0" + state: ratified + ratification_date: 2021-12 + changes: + - PMP changes require an SFENCE.VMA on any hart that implements + page-based virtual memory, even if VM is not currently enabled. + - PMP reset values are now platform-defined. + - An additional 48 optional PMP registers have been defined. + - version: "1.13.0" + state: frozen + ratification_date: 2023-12 + description: | + To support secure processing and contain faults, it is desirable to limit the physical addresses + accessible by software running on a hart. The optional PMP (Physical Memory Protection) unit + provides per-hart machine-mode control registers to allow physical memory access privileges (read, + write, execute) to be specified for each physical memory region. The PMP values are checked in + parallel with the PMA checks. + + [NOTE] + -- + This is a placeholder extension name defined by the `riscv-unified-db` and isn't considered an extension in + the Privileged ISA manual. This was chosen as an extension rather than a M-mode parameter since the + PMP has no visible ISA features (such as read-only-0 CSRs) if not present in an implementation. + Making it an extension in the database prevents having the PMP CSRs show up in implementations that don't have a PMP. + -- + params: + NUM_PMP_ENTRIES: + description: | + Number of implemented PMP entries. Can be any value between 0-64, inclusive. + + The architecture mandates that the number of implemented PMP registers + must appear to be 0, 16, or 64. + + Therefore, pmp registers will behave as follows according to NUN_PMP_ENTRIES: + + [separator="!"] + !=== + ! NUM_PMP_ENTRIES ! pmpaddr<0-15> / pmpcfg<0-3> ! pmpaddr<16-63> / pmpcfg<4-15> + ! 0 ! N ! N + ! 1-16 ! Y ! N + ! 17-64 ! Y ! Y + !=== + + ** N = Not implemented; access will cause `IllegalInstruction` + if TRAP_ON_UNIMPLEMENTED_CSR is true + ** Y = Implemented; access will not cause an exception (from M-mode), but register + may be read-only-zero if NUM_PMP_ENTRIES is less than the corresponding register + + [NOTE] + `pmpcfgN` for an odd N never exists when XLEN == 64 + + When NUM_PMP_ENTRIES is not exactly 0, 16, or 64, some extant pmp registers, + and associated pmpNcfg, will be read-only zero (but will never cause an exception). + schema: + type: integer + minimum: 0 + maximum: 64 + PMP_GRANULARITY: + description: | + log2 of the smallest supported PMP region. + + Generally, for systems with an MMU, should not be smaller than 12, + as that would preclude caching PMP results in the TLB along with + virtual memory translations + + Note that PMP_GRANULARITY is equal to G+2 (not G) as described in + the privileged architecture. + schema: + type: integer + minimum: 2 + maximum: 66 \ No newline at end of file diff --git a/arch/ext/Ssaia.yaml b/arch/ext/Ssaia.yaml index 86b004f2f8..25b8c9bfef 100644 --- a/arch/ext/Ssaia.yaml +++ b/arch/ext/Ssaia.yaml @@ -9,4 +9,6 @@ Ssaia: state: ratified ratification_date: 2023-06 url: https://github.com/riscv/riscv-aia/releases/download/1.0/riscv-interrupts-1.0.pdf - requires: [S, ">= 1.12"] + requires: + name: S + version: ">= 1.12" diff --git a/arch/ext/Sscofpmf.yaml b/arch/ext/Sscofpmf.yaml index c93882617f..fe67494e69 100644 --- a/arch/ext/Sscofpmf.yaml +++ b/arch/ext/Sscofpmf.yaml @@ -9,3 +9,5 @@ Sscofpmf: state: ratified ratification_date: 2023-08 url: https://drive.google.com/file/d/1KcjgbLM5L1ZKY8934aJl8aQwGlMz6Cbo/view?usp=drive_link + requires: + name: Smhpm diff --git a/arch/ext/Sv48.yaml b/arch/ext/Sv48.yaml index 2a735f6eeb..9889a31352 100644 --- a/arch/ext/Sv48.yaml +++ b/arch/ext/Sv48.yaml @@ -9,4 +9,6 @@ Sv48: state: ratified ratification_date: unknown url: https://github.com/riscv/riscv-isa-manual/releases/download/Priv-v1.12/riscv-privileged-20211203.pdf - requires: [Sv39, ">= 1.12"] + requires: + name: Sv39 + version: ">= 1.12" diff --git a/arch/ext/Sv57.yaml b/arch/ext/Sv57.yaml index 45dac066a1..32dc19c242 100644 --- a/arch/ext/Sv57.yaml +++ b/arch/ext/Sv57.yaml @@ -9,4 +9,6 @@ Sv57: state: ratified ratification_date: unknown url: https://github.com/riscv/riscv-isa-manual/releases/download/Priv-v1.12/riscv-privileged-20211203.pdf - requires: [Sv48, ">= 1.12"] + requires: + name: Sv48 + version: ">= 1.12" diff --git a/arch/ext/Svade.yaml b/arch/ext/Svade.yaml index 896a393cda..75f5b6a837 100644 --- a/arch/ext/Svade.yaml +++ b/arch/ext/Svade.yaml @@ -33,7 +33,7 @@ Svade: - name: Paul Donahue - name: Ved Shanbhogue company: Rivos, Inc. - conflicts: Svadu + conflicts: Svadu doc_license: name: Creative Commons Attribution 4.0 International License (CC-BY 4.0) url: https://creativecommons.org/licenses/by/4.0/ diff --git a/arch/ext/Svadu.yaml b/arch/ext/Svadu.yaml index 0eed00c1fa..6dbb8cb07b 100644 --- a/arch/ext/Svadu.yaml +++ b/arch/ext/Svadu.yaml @@ -116,7 +116,7 @@ Svadu: - name: Paul Donahue - name: Ved Shanbhogue company: Rivos, Inc. - conflicts: Svade + conflicts: Svade doc_license: name: Creative Commons Attribution 4.0 International License (CC-BY 4.0) url: https://creativecommons.org/licenses/by/4.0/ diff --git a/arch/ext/Svbare.yaml b/arch/ext/Svbare.yaml index 1ce53d6620..4e6073a78b 100644 --- a/arch/ext/Svbare.yaml +++ b/arch/ext/Svbare.yaml @@ -12,7 +12,8 @@ Svbare: - version: "1.0.0" state: ratified ratification_date: null - requires: S + requires: + name: S param_constraints: SATP_MODE_BARE: schema: diff --git a/arch/ext/Svinval.yaml b/arch/ext/Svinval.yaml index 4630471369..dee3de30ed 100644 --- a/arch/ext/Svinval.yaml +++ b/arch/ext/Svinval.yaml @@ -74,4 +74,5 @@ Svinval: - version: "1.0.0" state: ratified ratification_date: 2021-11 - requires: S + requires: + name: S diff --git a/arch/ext/Svnapot.yaml b/arch/ext/Svnapot.yaml new file mode 100644 index 0000000000..14cf6cd621 --- /dev/null +++ b/arch/ext/Svnapot.yaml @@ -0,0 +1,173 @@ +# yaml-language-server: $schema=../../schemas/ext_schema.json + +Svnapot: + long_name: Naturally-aligned Power of Two Translation Contiguity + description: | + In Sv39, Sv48, and Sv57, when a PTE has N=1, the PTE represents a + translation that is part of a range of contiguous virtual-to-physical + translations with the same values for PTE bits 5-0. Such ranges must be + of a naturally aligned power-of-2 (NAPOT) granularity larger than the + base page size. + + The Svnapot extension depends on Sv39. + + [[ptenapot]] + .Page table entry encodings when __pte__.N=1 + [%autowidth,float="center",align="center",cols="^,^,<,^",options="header"] + |=== + |i |_pte_._ppn_[_i_] |Description |_pte_.__napot_bits__ + |0 + + 0 + + 0 + + 0 + + 0 + + ≥1 + |`x xxxx xxx1` + + `x xxxx xx1x` + + `x xxxx x1xx` + + `x xxxx 1000` + + `x xxxx 0xxx` + + `x xxxx xxxx` + |_Reserved_ + + _Reserved_ + + _Reserved_ + + 64 KiB contiguous region + + _Reserved_ + + _Reserved_ + | - + + - + + - + + 4 + + - + + - + |=== + + NAPOT PTEs behave identically to non-NAPOT PTEs within the + address-translation algorithm in <>, + except that: + + * If the encoding in _pte_ is valid according to + <>, then instead of returning the original + value of _pte_, implicit reads of a NAPOT PTE return a copy + of _pte_ in which __pte__.__ppn__[__i__][__pte__.__napot_bits__-1:0] is replaced by + __vpn__[__i__][__pte__.__napot_bits__-1:0]. If the encoding in _pte_ is reserved according to + <>, then a page-fault exception must be raised. + * Implicit reads of NAPOT page table entries may create + address-translation cache entries mapping + _a_ + _j_*PTESIZE to a copy of _pte_ in which _pte_._ppn_[_i_][_pte_.__napot_bits__-1:0] + is replaced by _vpn[i][pte.napot_bits_-1:0], for any or all _j_ such that + __j__ >> __napot_bits__ = __vpn__[__i__] >> __napot_bits__, all for the address space identified in _satp_ as loaded by step 1. + + [NOTE] + ==== + The motivation for a NAPOT PTE is that it can be cached in a TLB as one + or more entries representing the contiguous region as if it were a + single (large) page covered by a single translation. This compaction can + help relieve TLB pressure in some scenarios. The encoding is designed to + fit within the pre-existing Sv39, Sv48, and Sv57 PTE formats so as not + to disrupt existing implementations or designs that choose not to + implement the scheme. It is also designed so as not to complicate the + definition of the address-translation algorithm. + + The address translation cache abstraction captures the behavior that + would result from the creation of a single TLB entry covering the entire + NAPOT region. It is also designed to be consistent with implementations + that support NAPOT PTEs by splitting the NAPOT region into TLB entries + covering any smaller power-of-two region sizes. For example, a 64 KiB + NAPOT PTE might trigger the creation of 16 standard 4 KiB TLB entries, + all with contents generated from the NAPOT PTE (even if the PTEs for the + other 4 KiB regions have different contents). + + In typical usage scenarios, NAPOT PTEs in the same region will have the + same attributes, same PPNs, and same values for bits 5-0. RSW remains + reserved for supervisor software control. It is the responsibility of + the OS and/or hypervisor to configure the page tables in such a way that + there are no inconsistencies between NAPOT PTEs and other NAPOT or + non-NAPOT PTEs that overlap the same address range. If an update needs + to be made, the OS generally should first mark all of the PTEs invalid, + then issue SFENCE.VMA instruction(s) covering all 4 KiB regions within + the range (either via a single SFENCE.VMA with _rs1_=`x0`, or with + multiple SFENCE.VMA instructions with _rs1_≠`x0`), then update the PTE(s), as described in <>, unless any inconsistencies are known to be benign. If any inconsistencies do exist, then the effect is the same as when SFENCE.VMA + is used incorrectly: one of the translations will be chosen, but the + choice is unpredictable. + + If an implementation chooses to use a NAPOT PTE (or cached version + thereof), it might not consult the PTE directly specified by the + algorithm in <> at all. Therefore, the D + and A bits may not be identical across all mappings of the same address + range even in typical use cases The operating system must query all + NAPOT aliases of a page to determine whether that page has been accessed + and/or is dirty. If the OS manually sets the A and/or D bits for a page, + it is recommended that the OS also set the A and/or D bits for other + NAPOT aliases as appropriate in order to avoid unnecessary traps. + + Just as with normal PTEs, TLBs are permitted to cache NAPOT PTEs whose V + (Valid) bit is clear. + + Depending on need, the NAPOT scheme may be extended to other + intermediate page sizes and/or to other levels of the page table in the + future. The encoding is designed to accommodate other NAPOT sizes should + that need arise. For example: + + __ + + [%autowidth,float="center",align="center",cols="^,^,<,^",options="header"] + |=== + |i |_pte_._ppn_[_i_] |Description |_pte_.__napot_bits__ + |0 + + 0 + + 0 + + 0 + + 0 + + ... + + 1 + + 1 + + ... + |`x xxxx xxx1` + + `x xxxx xx10` + + `x xxxx x100` + + `x xxxx 1000` + + `x xxx1 0000` + + ... + + `x xxxx xxx1` + + `x xxxx xx10` + + ... + |8 KiB contiguous region + + 16 KiB contiguous region + + 32 KiB contiguous region + + 64 KiB contiguous region + + 128 KiB contiguous region + + ... + + 4 MiB contiguous region + + 8 MiB contiguous region + + ... + | 1 + + 2 + + 3 + + 4 + + 5 + + ... + + 1 + + 2 + + ... + |=== + + In such a case, an implementation may or may not support all options. + The discoverability mechanism for this extension would be extended to + allow system software to determine which sizes are supported. + + Other sizes may remain deliberately excluded, so that PPN bits not being + used to indicate a valid NAPOT region size (e.g., the least-significant + bit of _pte_._ppn_[_i_]) may be repurposed for other uses in the + future. + + However, in case finer-grained intermediate page size support proves not + to be useful, we have chosen to standardize only 64 KiB support as a + first step. + ==== + versions: + - version: "1.0.0" + state: ratified + ratification_date: 2021-11 + requires: + name: Sv39 diff --git a/arch/ext/Svpbmt.yaml b/arch/ext/Svpbmt.yaml index b10bc90e37..7d3b6abb94 100644 --- a/arch/ext/Svpbmt.yaml +++ b/arch/ext/Svpbmt.yaml @@ -13,7 +13,8 @@ Svpbmt: - version: "1.0.0" state: ratified ratification_date: null - requires: Sv39 + requires: + name: Sv39 param_constraints: SATP_MODE_BARE: schema: diff --git a/arch/ext/Zfhmin.yaml b/arch/ext/Zfhmin.yaml index 66e62775eb..1ec9dd0c8a 100644 --- a/arch/ext/Zfhmin.yaml +++ b/arch/ext/Zfhmin.yaml @@ -45,5 +45,7 @@ Zfhmin: - version: "1.0.0" state: ratified ratification_date: 2021-11 - requires: [F, ">= 2.2"] + requires: + name: F + version: ">= 2.2" diff --git a/arch/ext/Zic64b.yaml b/arch/ext/Zic64b.yaml index 4275760974..40cf2a5ebb 100644 --- a/arch/ext/Zic64b.yaml +++ b/arch/ext/Zic64b.yaml @@ -21,9 +21,9 @@ Zic64b: company: SiFive, Inc. requires: anyOf: - - Zicbom - - Zicboz - - Zicbop + - name: Zicbom + - name: Zicboz + - name: Zicbop param_constraints: CACHE_BLOCK_SIZE: schema: diff --git a/arch/ext/Zicntr.yaml b/arch/ext/Zicntr.yaml index 213b877bc5..3abf56fc93 100644 --- a/arch/ext/Zicntr.yaml +++ b/arch/ext/Zicntr.yaml @@ -8,4 +8,24 @@ Zicntr: - version: "2.0.0" state: ratified ratification_date: 2019-12 - requires: [Zicsr, ">= 2.0"] + requires: + name: Zicsr + version: ">= 2.0" + params: + TIME_CSR_IMPLEMENTED: + description: | + Whether or not a real hardware `time` CSR exists. Implementations can either provide a real + CSR or emulate access at M-mode. + + Possible values: + + true:: + `time`/`timeh` exists, and accessing it will not cause an IllegalInstruction trap + + false:: + `time`/`timeh` does not exist. + Accessing the CSR will cause an IllegalInstruction trap or enter an unpredictable state, + depending on TRAP_ON_UNIMPLEMENTED_CSR. + Privileged software may emulate the `time` CSR, or may pass the exception to a lower level. + schema: + type: boolean \ No newline at end of file diff --git a/arch/ext/Zihpm.yaml b/arch/ext/Zihpm.yaml index 37cf034061..d647d5958f 100644 --- a/arch/ext/Zihpm.yaml +++ b/arch/ext/Zihpm.yaml @@ -8,31 +8,5 @@ Zihpm: - version: "2.0.0" state: ratified ratification_date: unknown - params: - HPM_COUNTER_EN: - description: | - List of HPM counters that are enabled. - There is one entry for each hpmcounter. - - The first three entries *must* be false (as they correspond to CY, IR, TM in, _e.g._ `mhmpcountinhibit`) - Index 3 in HPM_COUNTER_EN corresponds to hpmcounter3. - Index 31 in HPM_COUNTER_EN corresponds to hpmcounter31. - schema: - type: array - items: - - const: false - - const: false - - const: false - additionalItems: - type: boolean - maxItems: 32 - minItems: 32 - HPM_EVENTS: - description: | - List of defined event numbers that can be written into hpmeventN - schema: - type: array - items: - type: integer - minimum: 0 - maximum: 0x03ffffffffffffff # bits 63-58 are used by `Sscofpmf` \ No newline at end of file + requires: + name: Smhpm \ No newline at end of file diff --git a/arch/inst/A/amoadd.d.yaml b/arch/inst/A/amoadd.d.yaml index d51383930e..c3c3c72969 100644 --- a/arch/inst/A/amoadd.d.yaml +++ b/arch/inst/A/amoadd.d.yaml @@ -9,7 +9,8 @@ amoadd.d: * Write the loaded value into _rd_ * Add the value of register _rs2_ to the loaded value * Write the sum to the address in _rs1_ - definedBy: [A, Zaamo] + definedBy: + anyOf: [A, Zaamo] base: 64 assembly: xd, xs2, (xs1) encoding: diff --git a/arch/inst/A/amoadd.w.yaml b/arch/inst/A/amoadd.w.yaml index df6008a2a3..cdcaeb9b79 100644 --- a/arch/inst/A/amoadd.w.yaml +++ b/arch/inst/A/amoadd.w.yaml @@ -9,7 +9,8 @@ amoadd.w: * Write the sign-extended value into _rd_ * Add the least-significant word of register _rs2_ to the loaded value * Write the sum to the address in _rs1_ - definedBy: [A, Zaamo] + definedBy: + anyOf: [A, Zaamo] assembly: xd, xs2, (xrs1) encoding: match: 00000------------010-----0101111 diff --git a/arch/inst/A/amoand.d.yaml b/arch/inst/A/amoand.d.yaml index 8770b8665c..4f7a09a8db 100644 --- a/arch/inst/A/amoand.d.yaml +++ b/arch/inst/A/amoand.d.yaml @@ -9,7 +9,8 @@ amoand.d: * Write the loaded value into _rd_ * AND the value of register _rs2_ to the loaded value * Write the result to the address in _rs1_ - definedBy: [A, Zaamo] + definedBy: + anyOf: [A, Zaamo] base: 64 assembly: xd, xs2, (xrs1) encoding: diff --git a/arch/inst/A/amoand.w.yaml b/arch/inst/A/amoand.w.yaml index c5d892985c..c6650eb974 100644 --- a/arch/inst/A/amoand.w.yaml +++ b/arch/inst/A/amoand.w.yaml @@ -9,7 +9,8 @@ amoand.w: * Write the sign-extended value into _rd_ * AND the least-significant word of register _rs2_ to the loaded value * Write the result to the address in _rs1_ - definedBy: [A, Zaamo] + definedBy: + anyOf: [A, Zaamo] assembly: xd, xs2, (xrs1) encoding: match: 01100------------010-----0101111 diff --git a/arch/inst/A/amomax.d.yaml b/arch/inst/A/amomax.d.yaml index 2618246183..cb22bbd68d 100644 --- a/arch/inst/A/amomax.d.yaml +++ b/arch/inst/A/amomax.d.yaml @@ -9,7 +9,8 @@ amomax.d: * Write the loaded value into _rd_ * Signed compare the value of register _rs2_ to the loaded value, and select the maximum value * Write the maximum to the address in _rs1_ - definedBy: [A, Zaamo] + definedBy: + anyOf: [A, Zaamo] base: 64 assembly: xd, xs2, (xrs1) encoding: diff --git a/arch/inst/A/amomax.w.yaml b/arch/inst/A/amomax.w.yaml index aeca3a274e..b1ece79cae 100644 --- a/arch/inst/A/amomax.w.yaml +++ b/arch/inst/A/amomax.w.yaml @@ -9,7 +9,8 @@ amomax.w: * Write the sign-extended value into _rd_ * Signed compare the least-significant word of register _rs2_ to the loaded value, and select the maximum value * Write the maximum to the address in _rs1_ - definedBy: [A, Zaamo] + definedBy: + anyOf: [A, Zaamo] assembly: xd, xs2, (xrs1) encoding: match: 10100------------010-----0101111 diff --git a/arch/inst/A/amomaxu.d.yaml b/arch/inst/A/amomaxu.d.yaml index daaa192b0c..e6ae5d0de9 100644 --- a/arch/inst/A/amomaxu.d.yaml +++ b/arch/inst/A/amomaxu.d.yaml @@ -9,7 +9,8 @@ amomaxu.d: * Write the loaded value into _rd_ * Unsigned compare the value of register _rs2_ to the loaded value, and select the maximum value * Write the maximum to the address in _rs1_ - definedBy: [A, Zaamo] + definedBy: + anyOf: [A, Zaamo] base: 64 assembly: xd, xs2, (xrs1) encoding: diff --git a/arch/inst/A/amomaxu.w.yaml b/arch/inst/A/amomaxu.w.yaml index a7cfc799bf..7f28e3f821 100644 --- a/arch/inst/A/amomaxu.w.yaml +++ b/arch/inst/A/amomaxu.w.yaml @@ -9,7 +9,8 @@ amomaxu.w: * Write the sign-extended value into _rd_ * Unsigned compare the least-significant word of register _rs2_ to the loaded value, and select the maximum value * Write the maximum to the address in _rs1_ - definedBy: [A, Zaamo] + definedBy: + anyOf: [A, Zaamo] assembly: xd, xs2, (xrs1) encoding: match: 11100------------010-----0101111 diff --git a/arch/inst/A/amomin.d.yaml b/arch/inst/A/amomin.d.yaml index 4dc06ea6df..6d08737d35 100644 --- a/arch/inst/A/amomin.d.yaml +++ b/arch/inst/A/amomin.d.yaml @@ -9,7 +9,8 @@ amomin.d: * Write the loaded value into _rd_ * Signed compare the value of register _rs2_ to the loaded value, and select the mimimum value * Write the minimum to the address in _rs1_ - definedBy: [A, Zaamo] + definedBy: + anyOf: [A, Zaamo] base: 64 assembly: xd, xs2, (xrs1) encoding: diff --git a/arch/inst/A/amomin.w.yaml b/arch/inst/A/amomin.w.yaml index 75f256728e..dfbff3c110 100644 --- a/arch/inst/A/amomin.w.yaml +++ b/arch/inst/A/amomin.w.yaml @@ -9,7 +9,8 @@ amomin.w: * Write the sign-extended value into _rd_ * Signed compare the least-significant word of register _rs2_ to the loaded value, and select the mimimum value * Write the result to the address in _rs1_ - definedBy: [A, Zaamo] + definedBy: + anyOf: [A, Zaamo] assembly: xd, xs2, (xrs1) encoding: match: 10000------------010-----0101111 diff --git a/arch/inst/A/amominu.d.yaml b/arch/inst/A/amominu.d.yaml index 06eab96ef7..c0499c83bd 100644 --- a/arch/inst/A/amominu.d.yaml +++ b/arch/inst/A/amominu.d.yaml @@ -9,7 +9,8 @@ amominu.d: * Write the loaded value into _rd_ * Unsigned compare the value of register _rs2_ to the loaded value, and select the mimimum value * Write the minimum to the address in _rs1_ - definedBy: [A, Zaamo] + definedBy: + anyOf: [A, Zaamo] base: 64 assembly: xd, xs2, (xrs1) encoding: diff --git a/arch/inst/A/amominu.w.yaml b/arch/inst/A/amominu.w.yaml index c123f0a728..c12c3a597e 100644 --- a/arch/inst/A/amominu.w.yaml +++ b/arch/inst/A/amominu.w.yaml @@ -9,7 +9,8 @@ amominu.w: * Write the sign-extended value into _rd_ * Unsigned compare the least-significant word of register _rs2_ to the loaded word, and select the mimimum value * Write the result to the address in _rs1_ - definedBy: [A, Zaamo] + definedBy: + anyOf: [A, Zaamo] assembly: xd, xs2, (xrs1) encoding: match: 11000------------010-----0101111 diff --git a/arch/inst/A/amoor.d.yaml b/arch/inst/A/amoor.d.yaml index 8821d43ba2..f9e18cbf7b 100644 --- a/arch/inst/A/amoor.d.yaml +++ b/arch/inst/A/amoor.d.yaml @@ -9,7 +9,8 @@ amoor.d: * Write the loaded value into _rd_ * OR the value of register _rs2_ to the loaded value * Write the result to the address in _rs1_ - definedBy: [A, Zaamo] + definedBy: + anyOf: [A, Zaamo] base: 64 assembly: xd, xs2, (xrs1) encoding: diff --git a/arch/inst/A/amoor.w.yaml b/arch/inst/A/amoor.w.yaml index bb8d95fcd3..030a8553c1 100644 --- a/arch/inst/A/amoor.w.yaml +++ b/arch/inst/A/amoor.w.yaml @@ -9,7 +9,8 @@ amoor.w: * Write the sign-extended value into _rd_ * OR the least-significant word of register _rs2_ to the loaded value * Write the result to the address in _rs1_ - definedBy: [A, Zaamo] + definedBy: + anyOf: [A, Zaamo] assembly: xd, xs2, (xrs1) encoding: match: 01000------------010-----0101111 diff --git a/arch/inst/A/amoswap.d.yaml b/arch/inst/A/amoswap.d.yaml index febb7d8c52..b42504b734 100644 --- a/arch/inst/A/amoswap.d.yaml +++ b/arch/inst/A/amoswap.d.yaml @@ -8,7 +8,8 @@ amoswap.d: * Load the doubleword at address _rs1_ * Write the value into _rd_ * Store the value of register _rs2_ to the address in _rs1_ - definedBy: [A, Zaamo] + definedBy: + anyOf: [A, Zaamo] base: 64 assembly: xd, xs2, (xrs1) encoding: diff --git a/arch/inst/A/amoswap.w.yaml b/arch/inst/A/amoswap.w.yaml index 586805d828..7bdacf259b 100644 --- a/arch/inst/A/amoswap.w.yaml +++ b/arch/inst/A/amoswap.w.yaml @@ -8,7 +8,8 @@ amoswap.w: * Load the word at address _rs1_ * Write the sign-extended value into _rd_ * Store the least-significant word of register _rs2_ to the address in _rs1_ - definedBy: [A, Zaamo] + definedBy: + anyOf: [A, Zaamo] assembly: xd, xs2, (xrs1) encoding: match: 00001------------010-----0101111 diff --git a/arch/inst/A/amoxor.d.yaml b/arch/inst/A/amoxor.d.yaml index 172451a2cb..f85a0f08c2 100644 --- a/arch/inst/A/amoxor.d.yaml +++ b/arch/inst/A/amoxor.d.yaml @@ -9,7 +9,8 @@ amoxor.d: * Write the loaded value into _rd_ * XOR the value of register _rs2_ to the loaded value * Write the result to the address in _rs1_ - definedBy: [A, Zaamo] + definedBy: + anyOf: [A, Zaamo] base: 64 assembly: xd, xs2, (xrs1) encoding: diff --git a/arch/inst/A/amoxor.w.yaml b/arch/inst/A/amoxor.w.yaml index 98f80cb584..4d998ff2d4 100644 --- a/arch/inst/A/amoxor.w.yaml +++ b/arch/inst/A/amoxor.w.yaml @@ -9,7 +9,8 @@ amoxor.w: * Write the sign-extended value into _rd_ * XOR the least-significant word of register _rs2_ to the loaded value * Write the result to the address in _rs1_ - definedBy: [A, Zaamo] + definedBy: + anyOf: [A, Zaamo] assembly: xd, xs2, (xrs1) encoding: match: 00100------------010-----0101111 diff --git a/arch/inst/A/lr.d.yaml b/arch/inst/A/lr.d.yaml index 90a7577a95..328e94f00f 100644 --- a/arch/inst/A/lr.d.yaml +++ b/arch/inst/A/lr.d.yaml @@ -40,7 +40,8 @@ lr.d: Software should not set the _rl_ bit on an LR instruction unless the _aq_ bit is also set. LR.rl and SC.aq instructions are not guaranteed to provide any stronger ordering than those with both bits clear, but may result in lower performance. - definedBy: [A, Zalrsc] + definedBy: + anyOf: [A, Zalrsc] base: 64 assembly: xd, xs1 encoding: diff --git a/arch/inst/B/add.uw.yaml b/arch/inst/B/add.uw.yaml index be23e0e362..8efc88373a 100644 --- a/arch/inst/B/add.uw.yaml +++ b/arch/inst/B/add.uw.yaml @@ -6,7 +6,8 @@ add.uw: description: | This instruction performs an XLEN-wide addition between rs2 and the zero-extended least-significant word of rs1. - definedBy: [B, Zba] + definedBy: + anyOf: [B, Zba] assembly: xd, xs1, xs2 encoding: match: 0000100----------000-----0111011 diff --git a/arch/inst/B/andn.yaml b/arch/inst/B/andn.yaml index 190c1a8428..89aba3d195 100644 --- a/arch/inst/B/andn.yaml +++ b/arch/inst/B/andn.yaml @@ -5,7 +5,8 @@ andn: description: | This instruction performs the bitwise logical AND operation between `rs1` and the bitwise inversion of `rs2`. - definedBy: [B, Zbb] + definedBy: + anyOf: [B, Zbb] assembly: xd, xs1, xs2 encoding: match: 0100000----------111-----0110011 diff --git a/arch/inst/B/bclr.yaml b/arch/inst/B/bclr.yaml index bdb8690944..4020c66802 100644 --- a/arch/inst/B/bclr.yaml +++ b/arch/inst/B/bclr.yaml @@ -5,7 +5,8 @@ bclr: description: | This instruction returns rs1 with a single bit cleared at the index specified in rs2. The index is read from the lower log2(XLEN) bits of rs2. - definedBy: [B, Zbs] + definedBy: + anyOf: [B, Zbs] assembly: xd, xs1, xs2 encoding: match: 0100100----------001-----0110011 diff --git a/arch/inst/B/bclri.yaml b/arch/inst/B/bclri.yaml index 8a71edf224..dd0eaa28b3 100644 --- a/arch/inst/B/bclri.yaml +++ b/arch/inst/B/bclri.yaml @@ -6,7 +6,8 @@ bclri: This instruction returns rs1 with a single bit cleared at the index specified in shamt. The index is read from the lower log2(XLEN) bits of shamt. For RV32, the encodings corresponding to shamt[5]=1 are reserved. - definedBy: [B, Zbs] + definedBy: + anyOf: [B, Zbs] assembly: xd, xs1, shamt encoding: RV32: diff --git a/arch/inst/B/bext.yaml b/arch/inst/B/bext.yaml index 54cf5c016f..00f7a7d703 100644 --- a/arch/inst/B/bext.yaml +++ b/arch/inst/B/bext.yaml @@ -5,7 +5,8 @@ bext: description: | This instruction returns a single bit extracted from rs1 at the index specified in rs2. The index is read from the lower log2(XLEN) bits of rs2. - definedBy: [B, Zbs] + definedBy: + anyOf: [B, Zbs] assembly: xd, xs1, xs2 encoding: match: 0100100----------101-----0110011 diff --git a/arch/inst/B/bexti.yaml b/arch/inst/B/bexti.yaml index 12b9a43510..ffbea8dedd 100644 --- a/arch/inst/B/bexti.yaml +++ b/arch/inst/B/bexti.yaml @@ -6,7 +6,8 @@ bexti: This instruction returns a single bit extracted from rs1 at the index specified in rs2. The index is read from the lower log2(XLEN) bits of shamt. For RV32, the encodings corresponding to shamt[5]=1 are reserved. - definedBy: [B, Zbs] + definedBy: + anyOf: [B, Zbs] assembly: xd, xs1, shamt encoding: RV32: diff --git a/arch/inst/B/binv.yaml b/arch/inst/B/binv.yaml index f73167e6cd..b99b4494e5 100644 --- a/arch/inst/B/binv.yaml +++ b/arch/inst/B/binv.yaml @@ -5,7 +5,8 @@ binv: description: | This instruction returns rs1 with a single bit inverted at the index specified in rs2. The index is read from the lower log2(XLEN) bits of rs2. - definedBy: [B, Zbs] + definedBy: + anyOf: [B, Zbs] assembly: xd, xs1, xs2 encoding: match: 0110100----------001-----0110011 diff --git a/arch/inst/B/binvi.yaml b/arch/inst/B/binvi.yaml index 6ec2b1e069..40f64b54f4 100644 --- a/arch/inst/B/binvi.yaml +++ b/arch/inst/B/binvi.yaml @@ -6,7 +6,8 @@ binvi: This instruction returns rs1 with a single bit inverted at the index specified in shamt. The index is read from the lower log2(XLEN) bits of shamt. For RV32, the encodings corresponding to shamt[5]=1 are reserved. - definedBy: [B, Zbs] + definedBy: + anyOf: [B, Zbs] assembly: xd, xs1, shamt encoding: RV32: diff --git a/arch/inst/B/bset.yaml b/arch/inst/B/bset.yaml index 68a05eab3c..0541506cf9 100644 --- a/arch/inst/B/bset.yaml +++ b/arch/inst/B/bset.yaml @@ -5,7 +5,8 @@ bset: description: | This instruction returns rs1 with a single bit set at the index specified in rs2. The index is read from the lower log2(XLEN) bits of rs2. - definedBy: [B, Zbs] + definedBy: + anyOf: [B, Zbs] assembly: xd, xs1, xs2 encoding: match: 0010100----------001-----0110011 diff --git a/arch/inst/B/bseti.yaml b/arch/inst/B/bseti.yaml index ac59622e62..53612487b4 100644 --- a/arch/inst/B/bseti.yaml +++ b/arch/inst/B/bseti.yaml @@ -6,7 +6,8 @@ bseti: This instruction returns rs1 with a single bit set at the index specified in shamt. The index is read from the lower log2(XLEN) bits of shamt. For RV32, the encodings corresponding to shamt[5]=1 are reserved. - definedBy: [B, Zbs] + definedBy: + anyOf: [B, Zbs] assembly: xd, xs1, shamt encoding: RV32: diff --git a/arch/inst/B/clmul.yaml b/arch/inst/B/clmul.yaml index 76494b1cfa..209f5160a0 100644 --- a/arch/inst/B/clmul.yaml +++ b/arch/inst/B/clmul.yaml @@ -4,7 +4,8 @@ clmul: long_name: Carry-less multiply (low-part) description: | `clmul` produces the lower half of the 2*XLEN carry-less product - definedBy: [B, Zbc] + definedBy: + anyOf: [B, Zbc] assembly: xd, xs1, xs2 encoding: match: 0000101----------001-----0110011 diff --git a/arch/inst/B/clmulh.yaml b/arch/inst/B/clmulh.yaml index 8931ccb7fb..7514310d18 100644 --- a/arch/inst/B/clmulh.yaml +++ b/arch/inst/B/clmulh.yaml @@ -4,7 +4,8 @@ clmulh: long_name: Carry-less multiply (high-part) description: | `clmulh` produces the upper half of the 2*XLEN carry-less product - definedBy: [B, Zbc] + definedBy: + anyOf: [B, Zbc] assembly: xd, xs1, xs2 encoding: match: 0000101----------011-----0110011 diff --git a/arch/inst/B/clmulr.yaml b/arch/inst/B/clmulr.yaml index 62ede99fd1..1ce97c1cca 100644 --- a/arch/inst/B/clmulr.yaml +++ b/arch/inst/B/clmulr.yaml @@ -4,7 +4,8 @@ clmulr: long_name: Carry-less multiply (reversed) description: | `clmulr` produces bits 2*XLEN-2:XLEN-1 of the 2*XLEN carry-less product - definedBy: [B, Zbc] + definedBy: + anyOf: [B, Zbc] assembly: xd, xs1, xs2 access: s: always diff --git a/arch/inst/B/clz.yaml b/arch/inst/B/clz.yaml index 7bc457b0d6..103c145dee 100644 --- a/arch/inst/B/clz.yaml +++ b/arch/inst/B/clz.yaml @@ -7,7 +7,8 @@ clz: starting at the most-significant bit (i.e., XLEN-1) and progressing to bit 0. Accordingly, if the input is 0, the output is XLEN, and if the most-significant bit of the input is a 1, the output is 0. - definedBy: [B, Zbb] + definedBy: + anyOf: [B, Zbb] assembly: xd, xs1 encoding: match: 011000000000-----001-----0010011 diff --git a/arch/inst/B/clzw.yaml b/arch/inst/B/clzw.yaml index 5c8b645116..6cdfe2867e 100644 --- a/arch/inst/B/clzw.yaml +++ b/arch/inst/B/clzw.yaml @@ -7,7 +7,8 @@ clzw: Accordingly, if the least-significant word is 0, the output is 32, and if the most-significant bit of the word (_i.e._, bit 31) is a 1, the output is 0. base: 64 - definedBy: [B, Zbb] + definedBy: + anyOf: [B, Zbb] assembly: xd, xs1 encoding: match: 011000000000-----001-----0011011 diff --git a/arch/inst/B/cpop.yaml b/arch/inst/B/cpop.yaml index fa3c62ad33..42aabf1cd8 100644 --- a/arch/inst/B/cpop.yaml +++ b/arch/inst/B/cpop.yaml @@ -16,7 +16,8 @@ cpop: function `__builtin_popcountl (unsigned long x)` for LP64 is implemented by cpop on RV64. ---- - definedBy: [B, Zbb] + definedBy: + anyOf: [B, Zbb] assembly: xd, xs1 encoding: match: 011000000010-----001-----0010011 diff --git a/arch/inst/B/cpopw.yaml b/arch/inst/B/cpopw.yaml index 563cb0f894..ad2d694657 100644 --- a/arch/inst/B/cpopw.yaml +++ b/arch/inst/B/cpopw.yaml @@ -16,7 +16,8 @@ cpopw: function `__builtin_popcountl (unsigned long x)` for LP64 is implemented by cpop on RV64. ---- - definedBy: [B, Zbb] + definedBy: + anyOf: [B, Zbb] base: 64 assembly: xd, xs1 encoding: diff --git a/arch/inst/B/ctz.yaml b/arch/inst/B/ctz.yaml index 57ab100a66..71fb076eb2 100644 --- a/arch/inst/B/ctz.yaml +++ b/arch/inst/B/ctz.yaml @@ -8,7 +8,8 @@ ctz: to the most-significant bit (i.e., XLEN-1). Accordingly, if the input is 0, the output is XLEN, and if the least-significant bit of the input is a 1, the output is 0. - definedBy: [B, Zbb] + definedBy: + anyOf: [B, Zbb] assembly: xd, xs1 encoding: match: 011000000001-----001-----0010011 diff --git a/arch/inst/B/ctzw.yaml b/arch/inst/B/ctzw.yaml index fdc4b19f74..65317c67de 100644 --- a/arch/inst/B/ctzw.yaml +++ b/arch/inst/B/ctzw.yaml @@ -8,7 +8,8 @@ ctzw: to the most-significant bit of the least-significant word (i.e., 31). Accordingly, if the least-significant word is 0, the output is 32, and if the least-significant bit of the input is a 1, the output is 0. - definedBy: [B, Zbb] + definedBy: + anyOf: [B, Zbb] base: 64 assembly: xd, xs1 encoding: diff --git a/arch/inst/B/max.yaml b/arch/inst/B/max.yaml index b40096785d..37aff18ecb 100644 --- a/arch/inst/B/max.yaml +++ b/arch/inst/B/max.yaml @@ -12,7 +12,8 @@ max: common sequence, it is suggested that they are scheduled with no intervening instructions so that implementations that are so optimized can fuse them together. - definedBy: [B, Zbb] + definedBy: + anyOf: [B, Zbb] assembly: xd, xs1, xs2 encoding: match: 0000101----------110-----0110011 diff --git a/arch/inst/B/maxu.yaml b/arch/inst/B/maxu.yaml index 879f02a24b..d8097c7524 100644 --- a/arch/inst/B/maxu.yaml +++ b/arch/inst/B/maxu.yaml @@ -4,7 +4,8 @@ maxu: long_name: Unsigned maximum description: | This instruction returns the larger of two unsigned integers. - definedBy: [B, Zbb] + definedBy: + anyOf: [B, Zbb] assembly: xd, xs1, xs2 encoding: match: 0000101----------111-----0110011 diff --git a/arch/inst/B/min.yaml b/arch/inst/B/min.yaml index 9381497be2..f92101212a 100644 --- a/arch/inst/B/min.yaml +++ b/arch/inst/B/min.yaml @@ -4,7 +4,8 @@ min: long_name: Minimum description: | This instruction returns the smaller of two signed integers. - definedBy: [B, Zbb] + definedBy: + anyOf: [B, Zbb] assembly: xd, xs1, xs2 encoding: match: 0000101----------100-----0110011 diff --git a/arch/inst/B/minu.yaml b/arch/inst/B/minu.yaml index 62580cfcd3..f5ecfd9394 100644 --- a/arch/inst/B/minu.yaml +++ b/arch/inst/B/minu.yaml @@ -4,7 +4,8 @@ minu: long_name: Unsigned minumum description: | This instruction returns the smaller of two unsigned integers. - definedBy: [B, Zbb] + definedBy: + anyOf: [B, Zbb] assembly: xd, xs1, xs2 encoding: match: 0000101----------101-----0110011 diff --git a/arch/inst/B/orc.b.yaml b/arch/inst/B/orc.b.yaml index 8557c2d5b9..bbdee65af3 100644 --- a/arch/inst/B/orc.b.yaml +++ b/arch/inst/B/orc.b.yaml @@ -6,7 +6,8 @@ orc.b: Combines the bits within each byte using bitwise logical OR. This sets the bits of each byte in the result rd to all zeros if no bit within the respective byte of rs is set, or to all ones if any bit within the respective byte of rs is set. - definedBy: [B, Zbb] + definedBy: + anyOf: [B, Zbb] assembly: xd, xs1, xs2 encoding: match: 001010000111-----101-----0010011 diff --git a/arch/inst/B/orn.yaml b/arch/inst/B/orn.yaml index 492d5e9565..92421851d5 100644 --- a/arch/inst/B/orn.yaml +++ b/arch/inst/B/orn.yaml @@ -4,7 +4,8 @@ orn: long_name: OR with inverted operand description: | This instruction performs the bitwise logical OR operation between rs1 and the bitwise inversion of rs2. - definedBy: [B, Zbb, Zbkb] + definedBy: + anyOf: [B, Zbb, Zbkb] assembly: xd, xs1, xs2 encoding: match: 0100000----------110-----0110011 diff --git a/arch/inst/B/rev8.yaml b/arch/inst/B/rev8.yaml index a63591453a..37954e750d 100644 --- a/arch/inst/B/rev8.yaml +++ b/arch/inst/B/rev8.yaml @@ -12,7 +12,8 @@ rev8: The byte-reverse operation is only available for the full register width. To emulate word-sized and halfword-sized byte-reversal, perform a `rev8 rd,rs` followed by a `srai rd,rd,K`, where K is XLEN-32 and XLEN-16, respectively. - definedBy: [B, Zbb, Zbkb] + definedBy: + anyOf: [B, Zbb, Zbkb] assembly: xd, xs1 encoding: RV32: diff --git a/arch/inst/B/rol.yaml b/arch/inst/B/rol.yaml index 3f29f6d95b..708c59028f 100644 --- a/arch/inst/B/rol.yaml +++ b/arch/inst/B/rol.yaml @@ -4,7 +4,8 @@ rol: long_name: Rotate left (Register) description: | This instruction performs a rotate left of rs1 by the amount in least-significant `log2(XLEN)` bits of rs2. - definedBy: [B, Zbb, Zbkb] + definedBy: + anyOf: [B, Zbb, Zbkb] assembly: xd, xs1, xs2 encoding: match: 0110000----------001-----0110011 diff --git a/arch/inst/B/rolw.yaml b/arch/inst/B/rolw.yaml index 52f868bfec..fdcb72f1ef 100644 --- a/arch/inst/B/rolw.yaml +++ b/arch/inst/B/rolw.yaml @@ -5,7 +5,8 @@ rolw: description: | This instruction performs a rotate left of the least-significant word of rs1 by the amount in least-significant 5 bits of rs2. The resulting word value is sign-extended by copying bit 31 to all of the more-significant bits. - definedBy: [B, Zbb, Zbkb] + definedBy: + anyOf: [B, Zbb, Zbkb] assembly: xd, xs1, xs2 base: 64 encoding: diff --git a/arch/inst/B/ror.yaml b/arch/inst/B/ror.yaml index 419683a22a..3960aea810 100644 --- a/arch/inst/B/ror.yaml +++ b/arch/inst/B/ror.yaml @@ -4,7 +4,8 @@ ror: long_name: Rotate right (Register) description: | This instruction performs a rotate right of rs1 by the amount in least-significant `log2(XLEN)` bits of rs2. - definedBy: [B, Zbb, Zbkb] + definedBy: + anyOf: [B, Zbb, Zbkb] assembly: xd, xs1, xs2 encoding: match: 0110000----------101-----0110011 diff --git a/arch/inst/B/rori.yaml b/arch/inst/B/rori.yaml index c900e08052..3ab97a3bae 100644 --- a/arch/inst/B/rori.yaml +++ b/arch/inst/B/rori.yaml @@ -5,7 +5,8 @@ rori: description: | This instruction performs a rotate right of rs1 by the amount in the least-significant log2(XLEN) bits of shamt. For RV32, the encodings corresponding to shamt[5]=1 are reserved. - definedBy: [B, Zbb, Zbkb] + definedBy: + anyOf: [B, Zbb, Zbkb] assembly: xd, xs1, shamt encoding: RV32: diff --git a/arch/inst/B/roriw.yaml b/arch/inst/B/roriw.yaml index b960832580..5fec787cfc 100644 --- a/arch/inst/B/roriw.yaml +++ b/arch/inst/B/roriw.yaml @@ -6,7 +6,8 @@ roriw: This instruction performs a rotate right on the least-significant word of rs1 by the amount in the least-significant log2(XLEN) bits of shamt. The resulting word value is sign-extended by copying bit 31 to all of the more-significant bits. - definedBy: [B, Zbb, Zbkb] + definedBy: + anyOf: [B, Zbb, Zbkb] assembly: xd, xs1, shamt base: 64 encoding: diff --git a/arch/inst/B/rorw.yaml b/arch/inst/B/rorw.yaml index 8fe070a5e3..030599414f 100644 --- a/arch/inst/B/rorw.yaml +++ b/arch/inst/B/rorw.yaml @@ -6,7 +6,8 @@ rorw: This instruction performs a rotate right on the least-significant word of rs1 by the amount in least-significant 5 bits of rs2. The resultant word is sign-extended by copying bit 31 to all of the more-significant bits. - definedBy: [B, Zbb, Zbkb] + definedBy: + anyOf: [B, Zbb, Zbkb] assembly: xd, xs1, xs2 base: 64 encoding: diff --git a/arch/inst/B/sext.b.yaml b/arch/inst/B/sext.b.yaml index 6b333624a5..10a1c1cfcc 100644 --- a/arch/inst/B/sext.b.yaml +++ b/arch/inst/B/sext.b.yaml @@ -5,7 +5,8 @@ sext.b: description: | This instruction sign-extends the least-significant byte in the source to XLEN by copying the most-significant bit in the byte (i.e., bit 7) to all of the more-significant bits. - definedBy: [B, Zbb] + definedBy: + anyOf: [B, Zbb] assembly: xd, xs1 encoding: match: 011000000100-----001-----0010011 diff --git a/arch/inst/B/sext.h.yaml b/arch/inst/B/sext.h.yaml index 19582f1e3b..faacc333ef 100644 --- a/arch/inst/B/sext.h.yaml +++ b/arch/inst/B/sext.h.yaml @@ -5,7 +5,8 @@ sext.h: description: | This instruction sign-extends the least-significant halfword in the source to XLEN by copying the most-significant bit in the halfword (i.e., bit 15) to all of the more-significant bits. - definedBy: [B, Zbb] + definedBy: + anyOf: [B, Zbb] assembly: xd, xs1 encoding: match: 011000000101-----001-----0010011 diff --git a/arch/inst/B/sh1add.uw.yaml b/arch/inst/B/sh1add.uw.yaml index e4cd84818f..363dff17eb 100644 --- a/arch/inst/B/sh1add.uw.yaml +++ b/arch/inst/B/sh1add.uw.yaml @@ -6,7 +6,8 @@ sh1add.uw: This instruction performs an XLEN-wide addition of two addends. The first addend is rs2. The second addend is the unsigned value formed by extracting the least-significant word of rs1 and shifting it left by 1 place. - definedBy: [B, Zba] + definedBy: + anyOf: [B, Zba] base: 64 encoding: match: 0010000----------010-----0111011 diff --git a/arch/inst/B/sh1add.yaml b/arch/inst/B/sh1add.yaml index bce0beddd6..6e48e50186 100644 --- a/arch/inst/B/sh1add.yaml +++ b/arch/inst/B/sh1add.yaml @@ -4,7 +4,8 @@ sh1add: long_name: Shift left by 1 and add description: | This instruction shifts `rs1` to the left by 1 bit and adds it to `rs2`. - definedBy: [B, Zba] + definedBy: + anyOf: [B, Zba] assembly: xd, xs1, xs2 encoding: match: 0010000----------010-----0110011 diff --git a/arch/inst/B/sh2add.uw.yaml b/arch/inst/B/sh2add.uw.yaml index 65d222e8d3..4c4ca92e90 100644 --- a/arch/inst/B/sh2add.uw.yaml +++ b/arch/inst/B/sh2add.uw.yaml @@ -6,7 +6,8 @@ sh2add.uw: This instruction performs an XLEN-wide addition of two addends. The first addend is rs2. The second addend is the unsigned value formed by extracting the least-significant word of rs1 and shifting it left by 2 places. - definedBy: [B, Zba] + definedBy: + anyOf: [B, Zba] base: 64 assembly: xd, xs1, xs2 encoding: diff --git a/arch/inst/B/sh2add.yaml b/arch/inst/B/sh2add.yaml index 54fcadc1f4..5d77ac4a02 100644 --- a/arch/inst/B/sh2add.yaml +++ b/arch/inst/B/sh2add.yaml @@ -4,7 +4,8 @@ sh2add: long_name: Shift left by 2 and add description: | This instruction shifts `rs1` to the left by 2 places and adds it to `rs2`. - definedBy: [B, Zba] + definedBy: + anyOf: [B, Zba] assembly: xd, xs1, xs2 encoding: match: 0010000----------100-----0110011 diff --git a/arch/inst/B/sh3add.uw.yaml b/arch/inst/B/sh3add.uw.yaml index ad0da73fb7..e62efe3924 100644 --- a/arch/inst/B/sh3add.uw.yaml +++ b/arch/inst/B/sh3add.uw.yaml @@ -6,7 +6,8 @@ sh3add.uw: This instruction performs an XLEN-wide addition of two addends. The first addend is rs2. The second addend is the unsigned value formed by extracting the least-significant word of rs1 and shifting it left by 3 places. - definedBy: [B, Zba] + definedBy: + anyOf: [B, Zba] base: 64 assembly: xd, xs1, xs2 encoding: diff --git a/arch/inst/B/sh3add.yaml b/arch/inst/B/sh3add.yaml index e57a8666ff..a5feb1b2a5 100644 --- a/arch/inst/B/sh3add.yaml +++ b/arch/inst/B/sh3add.yaml @@ -4,7 +4,8 @@ sh3add: long_name: Shift left by 3 and add description: | This instruction shifts `rs1` to the left by 3 places and adds it to `rs2`. - definedBy: [B, Zba] + definedBy: + anyOf: [B, Zba] assembly: xd, xs1, xs2 encoding: match: 0010000----------110-----0110011 diff --git a/arch/inst/B/slli.uw.yaml b/arch/inst/B/slli.uw.yaml index b23e34391e..ffa16f5625 100644 --- a/arch/inst/B/slli.uw.yaml +++ b/arch/inst/B/slli.uw.yaml @@ -8,7 +8,8 @@ slli.uw: [NOTE] This instruction is the same as `slli` with `zext.w` performed on rs1 before shifting. - definedBy: [B, Zba] + definedBy: + anyOf: [B, Zba] base: 64 encoding: match: 0000010----------001-----0011011 diff --git a/arch/inst/B/xnor.yaml b/arch/inst/B/xnor.yaml index 361d417070..59fffacc39 100644 --- a/arch/inst/B/xnor.yaml +++ b/arch/inst/B/xnor.yaml @@ -4,7 +4,8 @@ xnor: long_name: Exclusive NOR description: | This instruction performs the bit-wise exclusive-NOR operation on rs1 and rs2. - definedBy: [B, Zbb, Zbkb] + definedBy: + anyOf: [B, Zbb, Zbkb] assembly: xd, xs1, xs2 encoding: match: 0100000----------100-----0110011 diff --git a/arch/inst/B/zext.h.yaml b/arch/inst/B/zext.h.yaml index c6c3a00282..a5c801e894 100644 --- a/arch/inst/B/zext.h.yaml +++ b/arch/inst/B/zext.h.yaml @@ -11,7 +11,8 @@ zext.h: [NOTE] The *zext.h* instruction is a pseduo-op for `packw` when `Zbkb` is implmeneted and XLEN == 64. - definedBy: [B, Zbb] + definedBy: + anyOf: [B, Zbb] encoding: RV32: match: 000010000000-----100-----0110011 diff --git a/arch/inst/I/wfi.yaml b/arch/inst/I/wfi.yaml index 477154c6de..e62ab8cd57 100644 --- a/arch/inst/I/wfi.yaml +++ b/arch/inst/I/wfi.yaml @@ -27,13 +27,13 @@ wfi: [%autowidth,%footer] |=== - .2+| [.rotate]#`mstatus.TW`# 4+^.>| `wfi` behavior + .2+| [.rotate]#`mstatus.TW`# 2+^.>| `wfi` behavior h| S-mode h| U-mode | 0 | Wait | Trap (I) | 1 | Trap (I) | Trap (I) - 4+| Trap (I) - Trap with `Illegal Instruction` code + 3+| Trap (I) - Trap with `Illegal Instruction` code |=== <%- end -%> @@ -74,13 +74,13 @@ wfi: [%autowidth,%footer] |=== - .2+| [.rotate]#`mstatus.TW`# 4+^.>| `wfi` behavior + .2+| [.rotate]#`mstatus.TW`# 2+^.>| `wfi` behavior h| S-mode h| U-mode | 0 | Wait | Trap (I) | 1 | Trap (I) | Trap (I) - 4+| Trap (I) - Trap with `Illegal Instruction` code + 3+| Trap (I) - Trap with `Illegal Instruction` code |=== <%- end -%> diff --git a/arch/inst/M/mul.yaml b/arch/inst/M/mul.yaml index b3f2b8f475..02c6085848 100644 --- a/arch/inst/M/mul.yaml +++ b/arch/inst/M/mul.yaml @@ -15,7 +15,8 @@ mul: Microarchitectures can then fuse these into a single multiply operation instead of performing two separate multiplies. - definedBy: [M, Zmmul] + definedBy: + anyOf: [M, Zmmul] assembly: xd, xs1, xs2 encoding: match: 0000001----------000-----0110011 diff --git a/arch/inst/M/mulh.yaml b/arch/inst/M/mulh.yaml index 61c2d5e08c..2e97db0460 100644 --- a/arch/inst/M/mulh.yaml +++ b/arch/inst/M/mulh.yaml @@ -14,7 +14,8 @@ mulh: --- Microarchitectures may look for that sequence and fuse the operations. - definedBy: [M, Zmmul] + definedBy: + anyOf: [M, Zmmul] assembly: xd, xs1, xs2 encoding: match: 0000001----------001-----0110011 diff --git a/arch/inst/M/mulhsu.yaml b/arch/inst/M/mulhsu.yaml index 3d065b5627..80b4da7a39 100644 --- a/arch/inst/M/mulhsu.yaml +++ b/arch/inst/M/mulhsu.yaml @@ -14,7 +14,8 @@ mulhsu: --- Microarchitectures may look for that sequence and fuse the operations. - definedBy: [M, Zmmul] + definedBy: + anyOf: [M, Zmmul] assembly: xd, xs1, xs2 encoding: match: 0000001----------010-----0110011 diff --git a/arch/inst/M/mulhu.yaml b/arch/inst/M/mulhu.yaml index c6aedc8ea0..cf80a29d3b 100644 --- a/arch/inst/M/mulhu.yaml +++ b/arch/inst/M/mulhu.yaml @@ -14,7 +14,8 @@ mulhu: --- Microarchitectures may look for that sequence and fuse the operations. - definedBy: [M, Zmmul] + definedBy: + anyOf: [M, Zmmul] assembly: xd, xs1, xs2 encoding: match: 0000001----------011-----0110011 diff --git a/arch/inst/M/mulw.yaml b/arch/inst/M/mulw.yaml index 330ff473cc..4ef1e6b563 100644 --- a/arch/inst/M/mulw.yaml +++ b/arch/inst/M/mulw.yaml @@ -13,7 +13,8 @@ mulw: but signed arguments must be proper 32-bit signed values, whereas unsigned arguments must have their upper 32 bits clear. If the arguments are not known to be sign- or zero-extended, an alternative is to shift both arguments left by 32 bits, then use MULH[[S]U]. - definedBy: [M, Zmmul] + definedBy: + anyOf: [M, Zmmul] assembly: xd, xs1, xs2 encoding: match: 0000001----------000-----0111011 diff --git a/arch/inst/Svinval/hinval.gvma.yaml b/arch/inst/Svinval/hinval.gvma.yaml index 9ada9f3c94..8283ac6aa1 100644 --- a/arch/inst/Svinval/hinval.gvma.yaml +++ b/arch/inst/Svinval/hinval.gvma.yaml @@ -2,8 +2,10 @@ hinval.gvma: long_name: Invalidate cached address translations - definedBy: Svinval - requires: H + definedBy: + allOf: + - Svinval + - H encoding: match: 0110011----------000000001110011 variables: diff --git a/arch/inst/Svinval/hinval.vvma.yaml b/arch/inst/Svinval/hinval.vvma.yaml index a6ea5ffc18..eade8e9d73 100644 --- a/arch/inst/Svinval/hinval.vvma.yaml +++ b/arch/inst/Svinval/hinval.vvma.yaml @@ -2,8 +2,10 @@ hinval.vvma: long_name: Invalidate cached address translations - definedBy: Svinval - requires: H + definedBy: + allOf: + - Svinval + - H encoding: match: 0010011----------000000001110011 variables: diff --git a/arch/inst/Zfh/fcvt.h.s.yaml b/arch/inst/Zfh/fcvt.h.s.yaml index e8be5f532c..1393f94708 100644 --- a/arch/inst/Zfh/fcvt.h.s.yaml +++ b/arch/inst/Zfh/fcvt.h.s.yaml @@ -2,7 +2,8 @@ fcvt.h.s: long_name: Convert half-precision float to a single-precision float - definedBy: [Zfh, Zfhmin] + definedBy: + anyOf: [Zfh, Zfhmin] assembly: fd, xs1 description: | Converts a half-precision number in floating-point register _fs1_ into a single-precision floating-point number in diff --git a/arch/inst/Zfh/fcvt.s.h.yaml b/arch/inst/Zfh/fcvt.s.h.yaml index 83f017934d..489ea806fa 100644 --- a/arch/inst/Zfh/fcvt.s.h.yaml +++ b/arch/inst/Zfh/fcvt.s.h.yaml @@ -2,7 +2,8 @@ fcvt.s.h: long_name: Convert single-precision float to a half-precision float - definedBy: [Zfh, Zfhmin] + definedBy: + anyOf: [Zfh, Zfhmin] assembly: fd, xs1 description: | Converts a single-precision number in floating-point register _fs1_ into a half-precision floating-point number in diff --git a/arch/inst/Zfh/flh.yaml b/arch/inst/Zfh/flh.yaml index 1812367796..1d5ec8aa8f 100644 --- a/arch/inst/Zfh/flh.yaml +++ b/arch/inst/Zfh/flh.yaml @@ -9,7 +9,8 @@ flh: `flh` is only guaranteed to execute atomically if the effective address is naturally aligned. - definedBy: [Zfh, Zfhmin] + definedBy: + anyOf: [Zfh, Zfhmin] assembly: fd, imm(xs1) encoding: match: -----------------001-----0000111 diff --git a/arch/inst/Zfh/fmv.x.h.yaml b/arch/inst/Zfh/fmv.x.h.yaml index cbd70e56f2..1a32d71457 100644 --- a/arch/inst/Zfh/fmv.x.h.yaml +++ b/arch/inst/Zfh/fmv.x.h.yaml @@ -2,7 +2,8 @@ fmv.x.h: long_name: Move half-precision value from floating-point to integer register - definedBy: [Zfh, Zfhmin] + definedBy: + anyOf: [Zfh, Zfhmin] assembly: rd, fs1 description: | Moves the half-precision value in floating-point register rs1 represented in IEEE 754-2008 diff --git a/arch/inst/Zfh/fsh.yaml b/arch/inst/Zfh/fsh.yaml index 6e7efb1240..f115a96621 100644 --- a/arch/inst/Zfh/fsh.yaml +++ b/arch/inst/Zfh/fsh.yaml @@ -12,7 +12,8 @@ fsh: `fsh` is only guaranteed to execute atomically if the effective address is naturally aligned. - definedBy: [Zfh, Zfhmin] + definedBy: + anyOf: [Zfh, Zfhmin] assembly: fs2, imm(xs1) encoding: match: -----------------001-----0100111 diff --git a/arch/isa/builtin_functions.idl b/arch/isa/builtin_functions.idl index cf65a6bc3c..1af7555666 100644 --- a/arch/isa/builtin_functions.idl +++ b/arch/isa/builtin_functions.idl @@ -245,9 +245,9 @@ function nan_box { of smaller size by adding all 1's to the upper bits. } body { - assert(FROM_SIZE > TO_SIZE, "Bad template arugments; FROM_SIZE must be less than TO_SIZE"); + assert(FROM_SIZE < TO_SIZE, "Bad template arugments; FROM_SIZE must be less than TO_SIZE"); - return {{FROM_SIZE - TO_SIZE{1'b1}}, sp_value}; + return {{TO_SIZE - FROM_SIZE{1'b1}}, from_value}; } } Bits<32> SP_POS_INF = 32'b0_11111111_00000000000000000000000; diff --git a/arch/isa/globals.isa b/arch/isa/globals.isa index deab65bdbc..fb08d28059 100644 --- a/arch/isa/globals.isa +++ b/arch/isa/globals.isa @@ -277,15 +277,15 @@ function exception_handling_mode { # mode is M, the value of medeleg is irrelevant return PrivilegeMode::M; } else if (implemented?(ExtensionName::S) && ((mode() == PrivilegeMode::HS) || (mode() == PrivilegeMode::U))) { - if ((CSR[medeleg] & (1 << $bits(exception_code))) != 0) { + if (($bits(CSR[medeleg]) & (1 << $bits(exception_code))) != 0) { return PrivilegeMode::HS; } else { return PrivilegeMode::M; } } else { assert(implemented?(ExtensionName::H) && ((mode() == PrivilegeMode::VS) || (mode() == PrivilegeMode::VU)), "Unexpected mode"); - if ((CSR[medeleg] & (1 << $bits(exception_code))) != 0) { - if ((CSR[hedeleg] & (1 << $bits(exception_code))) != 0) { + if (($bits(CSR[medeleg]) & (1 << $bits(exception_code))) != 0) { + if (($bits(CSR[hedeleg]) & (1 << $bits(exception_code))) != 0) { return PrivilegeMode::VS; } else { return PrivilegeMode::HS; @@ -306,7 +306,7 @@ function unimplemented_csr { } body { if (TRAP_ON_UNIMPLEMENTED_CSR) { - raise(ExceptionCode::IllegalInstruction, encoding); + raise(ExceptionCode::IllegalInstruction, mode(), encoding); } else { unpredictable("Accessing an unimplmented CSR"); } @@ -322,21 +322,18 @@ function mtval_readonly? { return !( REPORT_VA_IN_MTVAL_ON_BREAKPOINT || REPORT_VA_IN_MTVAL_ON_LOAD_MISALIGNED || - REPORT_VA_IN_MTVAL_ON_STORE_MISALIGNED || - (implemented?(ExtensionName::Zaamo) && REPORT_VA_IN_MTVAL_ON_AMO_MISALIGNED) || + REPORT_VA_IN_MTVAL_ON_STORE_AMO_MISALIGNED || REPORT_VA_IN_MTVAL_ON_INSTRUCTION_MISALIGNED || REPORT_VA_IN_MTVAL_ON_LOAD_ACCESS_FAULT || - REPORT_VA_IN_MTVAL_ON_STORE_ACCESS_FAULT || - (implemented?(ExtensionName::Zaamo) && REPORT_VA_IN_MTVAL_ON_AMO_ACCESS_FAULT) || + REPORT_VA_IN_MTVAL_ON_STORE_AMO_ACCESS_FAULT || REPORT_VA_IN_MTVAL_ON_INSTRUCTION_ACCESS_FAULT || REPORT_VA_IN_MTVAL_ON_LOAD_PAGE_FAULT || - REPORT_VA_IN_MTVAL_ON_STORE_PAGE_FAULT || - (implemented?(ExtensionName::Zaamo) && REPORT_VA_IN_MTVAL_ON_AMO_PAGE_FAULT) || + REPORT_VA_IN_MTVAL_ON_STORE_AMO_PAGE_FAULT || REPORT_VA_IN_MTVAL_ON_INSTRUCTION_PAGE_FAULT || REPORT_ENCODING_IN_MTVAL_ON_ILLEGAL_INSTRUCTION || REPORT_CAUSE_IN_MTVAL_ON_SHADOW_STACK_SOFTWARE_CHECK || - REPORT_CAUSE_IN_MTVAL_ON_LANDING_PAD_SOFTWARE_CHECK || - implemented?(ExtensionName::Sdext) + REPORT_CAUSE_IN_MTVAL_ON_LANDING_PAD_SOFTWARE_CHECK + # || implemented?(ExtensionName::Sdext) ); } } @@ -361,8 +358,8 @@ function stval_readonly? { REPORT_VA_IN_STVAL_ON_INSTRUCTION_PAGE_FAULT || REPORT_ENCODING_IN_STVAL_ON_ILLEGAL_INSTRUCTION || REPORT_CAUSE_IN_STVAL_ON_SHADOW_STACK_SOFTWARE_CHECK || - REPORT_CAUSE_IN_STVAL_ON_LANDING_PAD_SOFTWARE_CHECK || - implemented?(ExtensionName::Sdext) + REPORT_CAUSE_IN_STVAL_ON_LANDING_PAD_SOFTWARE_CHECK + # || implemented?(ExtensionName::Sdext) ); } else { return true; @@ -390,8 +387,8 @@ function vstval_readonly? { REPORT_VA_IN_VSTVAL_ON_INSTRUCTION_PAGE_FAULT || REPORT_ENCODING_IN_VSTVAL_ON_ILLEGAL_INSTRUCTION || REPORT_CAUSE_IN_VSTVAL_ON_SHADOW_STACK_SOFTWARE_CHECK || - REPORT_CAUSE_IN_VSTVAL_ON_LANDING_PAD_SOFTWARE_CHECK || - implemented?(ExtensionName::Sdext) + REPORT_CAUSE_IN_VSTVAL_ON_LANDING_PAD_SOFTWARE_CHECK + # || implemented?(ExtensionName::Sdext) ); } else { return true; @@ -524,7 +521,9 @@ function raise_guest_page_fault { arguments MemoryOperation op, # op type XReg gpa, # guest physical address - XReg gva # guest virtual address + XReg gva, # guest virtual address + XReg tinst_value, # value for *tinst + PrivilegeMode from_mode # effective privilege mode for reporting description { Raise a guest page fault exception. } @@ -539,7 +538,7 @@ function raise_guest_page_fault { code = ExceptionCode::StoreAmoGuestPageFault; write_gpa_in_tval = REPORT_GPA_IN_TVAL_ON_STORE_AMO_GUEST_PAGE_FAULT; } else { - assert(op == MemoryOperation::Fetch); + assert(op == MemoryOperation::Fetch, "unexpected memory operation"); code = ExceptionCode::InstructionGuestPageFault; write_gpa_in_tval = REPORT_GPA_IN_TVAL_ON_INSTRUCTION_GUEST_PAGE_FAULT; } @@ -548,7 +547,7 @@ function raise_guest_page_fault { if (handling_mode == PrivilegeMode::S) { CSR[htval].VALUE = write_gpa_in_tval ? (gpa >> 2) : 0; - CSR[htinst].VALUE = tinst_value(code); + CSR[htinst].VALUE = tinst_value; CSR[sepc].PC = $pc; if (!stval_readonly?()) { CSR[stval].VALUE = stval_for(code, gva); @@ -558,14 +557,18 @@ function raise_guest_page_fault { CSR[scause].CODE = $bits(code); CSR[hstatus].GVA = 1; CSR[hstatus].SPV = 1; # guest page faults always come from a virtual mode - CSR[hstatus].SPVP = $bits(mode()); + CSR[hstatus].SPVP = $bits(from_mode)[0]; CSR[mstatus].SPP = $bits(from_mode)[0]; } else { - assert(handling_mode == PrivilegeMode::M); + assert(handling_mode == PrivilegeMode::M, "unexpected privilege mode"); CSR[mtval2].VALUE = write_gpa_in_tval ? (gpa >> 2) : 0; - CSR[mtinst].VALUE = tinst_value(code); + CSR[mtinst].VALUE = tinst_value; CSR[mstatus].MPP = $bits(from_mode)[1:0]; - CSR[mstatus].MPV = 1; + if (XLEN == 64) { + CSR[mstatus].MPV = 1; + } else { + CSR[mstatush].MPV = 1; + } } # abort the current instruction, and start to refetch from PC @@ -614,16 +617,24 @@ function raise_precise { } $pc = {CSR[mtvec].BASE, 2'b00}; CSR[mcause].INT = 1'b0; - CSR[mcause].CAUSE = $bits(exception_code); + CSR[mcause].CODE = $bits(exception_code); if (CSR[misa].H == 1) { # write zero into mtval2 and minst # (when these are non-zero values, raise_guest_page_fault should be callecd) CSR[mtval2].VALUE = 0; - CSR[minst].VALUE = 0; + CSR[mtinst].VALUE = 0; if (from_mode == PrivilegeMode::VU || from_mode == PrivilegeMode::VS) { - CSR[mstatus].MPV = 1; + if (XLEN == 32) { + CSR[mstatush].MPV = 1; + } else { + CSR[mstatus].MPV = 1; + } } else { - CSR[mstatus].MPV = 0; + if (XLEN == 32) { + CSR[mstatush].MPV = 0; + } else { + CSR[mstatus].MPV = 0; + } } } CSR[mstatus].MPP = $bits(from_mode); @@ -640,11 +651,11 @@ function raise_precise { # write zero into htval and hinst # (when these are non-zero values, raise_guest_page_fault should be callecd) CSR[htval].VALUE = 0; - CSR[hinst].VALUE = 0; - CSR[mstatus].SPV = $bits(from_mode)[2]; + CSR[htinst].VALUE = 0; + CSR[hstatus].SPV = $bits(from_mode)[2]; if (from_mode == PrivilegeMode::VU || from_mode == PrivilegeMode::VS) { CSR[hstatus].SPV = 1; - if (((exception_code == ExceptionCode::Breakpoint) && (REPORT_VA_IN_STVAL_ON_BREAKPOINT)) + if ( ((exception_code == ExceptionCode::Breakpoint) && (REPORT_VA_IN_STVAL_ON_BREAKPOINT)) || ((exception_code == ExceptionCode::LoadAddressMisaligned) && (REPORT_VA_IN_STVAL_ON_LOAD_MISALIGNED)) || ((exception_code == ExceptionCode::StoreAmoAddressMisaligned) && (REPORT_VA_IN_STVAL_ON_STORE_AMO_MISALIGNED)) || ((exception_code == ExceptionCode::InstructionAddressMisaligned) && (REPORT_VA_IN_STVAL_ON_INSTRUCTION_MISALIGNED)) @@ -659,7 +670,7 @@ function raise_precise { } else { CSR[hstatus].GVA = 0; } - CSR[hstatus].SPVP = from_mode; + CSR[hstatus].SPVP = $bits(from_mode)[0]; } else { CSR[hstatus].SPV = 0; CSR[hstatus].GVA = 0; @@ -785,37 +796,37 @@ function xlen { body { if (XLEN == 32) { return 32; - } - - if (mode() == PrivilegeMode::M) { - if (CSR[misa].MXL == $bits(XRegWidth::XLEN32)) { - return 32; - } else if (CSR[misa].MXL == $bits(XRegWidth::XLEN64)) { - return 64; - } - } else if (implemented?(ExtensionName::S) && mode() == PrivilegeMode::S) { - if (CSR[mstatus].SXL == $bits(XRegWidth::XLEN32)) { - return 32; - } else if (CSR[mstatus].SXL == $bits(XRegWidth::XLEN64)) { - return 64; - } - } else if (implemented?(ExtensionName::U) && mode() == PrivilegeMode::U) { - if (CSR[mstatus].UXL == $bits(XRegWidth::XLEN32)) { - return 32; - } else if (CSR[mstatus].UXL == $bits(XRegWidth::XLEN64)) { - return 64; - } - } else if (implemented?(ExtensionName::H) && mode() == PrivilegeMode::VS) { - if (CSR[hstatus].VSXL == $bits(XRegWidth::XLEN32)) { - return 32; - } else if (CSR[hstatus].VSXL == $bits(XRegWidth::XLEN64)) { - return 64; - } - } else if (implemented?(ExtensionName::H) && mode() == PrivilegeMode::VU) { - if (CSR[vsstatus].UXL == $bits(XRegWidth::XLEN32)) { - return 32; - } else if (CSR[vsstatus].UXL == $bits(XRegWidth::XLEN64)) { - return 64; + } else { + if (mode() == PrivilegeMode::M) { + if (CSR[misa].MXL == $bits(XRegWidth::XLEN32)) { + return 32; + } else if (CSR[misa].MXL == $bits(XRegWidth::XLEN64)) { + return 64; + } + } else if (implemented?(ExtensionName::S) && mode() == PrivilegeMode::S) { + if (CSR[mstatus].SXL == $bits(XRegWidth::XLEN32)) { + return 32; + } else if (CSR[mstatus].SXL == $bits(XRegWidth::XLEN64)) { + return 64; + } + } else if (implemented?(ExtensionName::U) && mode() == PrivilegeMode::U) { + if (CSR[mstatus].UXL == $bits(XRegWidth::XLEN32)) { + return 32; + } else if (CSR[mstatus].UXL == $bits(XRegWidth::XLEN64)) { + return 64; + } + } else if (implemented?(ExtensionName::H) && mode() == PrivilegeMode::VS) { + if (CSR[hstatus].VSXL == $bits(XRegWidth::XLEN32)) { + return 32; + } else if (CSR[hstatus].VSXL == $bits(XRegWidth::XLEN64)) { + return 64; + } + } else if (implemented?(ExtensionName::H) && mode() == PrivilegeMode::VU) { + if (CSR[vsstatus].UXL == $bits(XRegWidth::XLEN32)) { + return 32; + } else if (CSR[vsstatus].UXL == $bits(XRegWidth::XLEN64)) { + return 64; + } } } } @@ -1167,18 +1178,22 @@ function base32? { return True iff current effective XLEN == 32 } body { - XRegWidth xlen32 = XRegWidth::XLEN32; - if (mode() == PrivilegeMode::M) { - return CSR[misa].MXL == $bits(xlen32); - } else if (implemented?(ExtensionName::S) && mode() == PrivilegeMode::S) { - return CSR[mstatus].SXL == $bits(xlen32); - } else if (implemented?(ExtensionName::U) && mode() == PrivilegeMode::U) { - return CSR[mstatus].UXL == $bits(xlen32); - } else if (implemented?(ExtensionName::H) && mode() == PrivilegeMode::VS) { - return CSR[hstatus].VSXL == $bits(xlen32); + if (XLEN == 32) { + return true; } else { - assert(implemented?(ExtensionName::H) && mode() == PrivilegeMode::VU, "Unexpected mode"); - return CSR[vsstatus].UXL == $bits(xlen32); + XRegWidth xlen32 = XRegWidth::XLEN32; + if (mode() == PrivilegeMode::M) { + return CSR[misa].MXL == $bits(xlen32); + } else if (implemented?(ExtensionName::S) && mode() == PrivilegeMode::S) { + return CSR[mstatus].SXL == $bits(xlen32); + } else if (implemented?(ExtensionName::U) && mode() == PrivilegeMode::U) { + return CSR[mstatus].UXL == $bits(xlen32); + } else if (implemented?(ExtensionName::H) && mode() == PrivilegeMode::VS) { + return CSR[hstatus].VSXL == $bits(xlen32); + } else { + assert(implemented?(ExtensionName::H) && mode() == PrivilegeMode::VU, "Unexpected mode"); + return CSR[vsstatus].UXL == $bits(xlen32); + } } } } @@ -1215,13 +1230,15 @@ function current_translation_mode { Bits<4> mode_val = CSR[vsatp].MODE; if (mode_val == $bits(SatpMode::Sv32)) { # Sv32 is only defined when XLEN == 32 - if (effective_mode == PrivilegeMode::VS && CSR[hstatus].VSXL != $bits(XRegWidth::XLEN32)) { - # not supported in this XLEN - return SatpMode::Reserved; - } - if (effective_mode == PrivilegeMode::VU && CSR[vsstatus].UXL != $bits(XRegWidth::XLEN32)) { - # not supported in this XLEN - return SatpMode::Reserved; + if (XLEN == 64) { + if ((effective_mode == PrivilegeMode::VS) && (CSR[hstatus].VSXL != $bits(XRegWidth::XLEN32))) { + # not supported in this XLEN + return SatpMode::Reserved; + } + if ((effective_mode == PrivilegeMode::VU) && (CSR[vsstatus].UXL != $bits(XRegWidth::XLEN32))) { + # not supported in this XLEN + return SatpMode::Reserved; + } } if (!SV32_VSMODE_TRANSLATION) { # not supported in this configuration @@ -1230,7 +1247,7 @@ function current_translation_mode { # OK return SatpMode::Sv32; - } else if (mode_val == $bits(SatpMode::Sv39)) { + } else if ((XLEN == 64) && (mode_val == $bits(SatpMode::Sv39))) { # Sv39 is only defined when XLEN == 64 if (effective_mode == PrivilegeMode::VS && CSR[hstatus].VSXL != $bits(XRegWidth::XLEN64)) { # not supported in this XLEN @@ -1247,7 +1264,7 @@ function current_translation_mode { # OK return SatpMode::Sv39; - } else if (mode_val == $bits(SatpMode::Sv48)) { + } else if ((XLEN == 64) && (mode_val == $bits(SatpMode::Sv48))) { # Sv48 is only defined when XLEN == 64 if (effective_mode == PrivilegeMode::VS && CSR[hstatus].VSXL != $bits(XRegWidth::XLEN64)) { # not supported in this XLEN @@ -1264,7 +1281,7 @@ function current_translation_mode { # OK return SatpMode::Sv48; - } else if (mode_val == $bits(SatpMode::Sv57)) { + } else if ((XLEN == 64) && (mode_val == $bits(SatpMode::Sv57))) { # Sv57 is only defined when XLEN == 64 if (effective_mode == PrivilegeMode::VS && CSR[hstatus].VSXL != $bits(XRegWidth::XLEN64)) { # not supported in this XLEN @@ -1288,23 +1305,25 @@ function current_translation_mode { } # if we reach here, then the effective mode is S or U - assert(effective_mode == PrivilegeMode::S || effective_mode == PrivilegeMode::U); + assert(effective_mode == PrivilegeMode::S || effective_mode == PrivilegeMode::U, "unexpected priv mode"); Bits<4> mode_val = CSR[vsatp].MODE; if (mode_val == $bits(SatpMode::Sv32)) { # Sv32 is only defined when XLEN == 32 - if (effective_mode == PrivilegeMode::S && CSR[mstatus].SXL != $bits(XRegWidth::XLEN32)) { - # not supported in this XLEN - return SatpMode::Reserved; - } - if (effective_mode == PrivilegeMode::U && CSR[sstatus].UXL != $bits(XRegWidth::XLEN32)) { - # not supported in this XLEN - return SatpMode::Reserved; + if (XLEN == 64) { + if (effective_mode == PrivilegeMode::S && CSR[mstatus].SXL != $bits(XRegWidth::XLEN32)) { + # not supported in this XLEN + return SatpMode::Reserved; + } + if (effective_mode == PrivilegeMode::U && CSR[sstatus].UXL != $bits(XRegWidth::XLEN32)) { + # not supported in this XLEN + return SatpMode::Reserved; + } } if (!implemented?(ExtensionName::Sv32)) { # not supported in this configuration return SatpMode::Reserved; } - } else if (mode_val == $bits(SatpMode::Sv39)) { + } else if ((XLEN == 64) && (mode_val == $bits(SatpMode::Sv39))) { # Sv39 is only defined when XLEN == 64 if (effective_mode == PrivilegeMode::S && CSR[mstatus].SXL != $bits(XRegWidth::XLEN64)) { # not supported in this XLEN @@ -1320,7 +1339,7 @@ function current_translation_mode { } # OK return SatpMode::Sv39; - } else if (mode_val == $bits(SatpMode::Sv48)) { + } else if ((XLEN == 64) && (mode_val == $bits(SatpMode::Sv48))) { # Sv48 is only defined when XLEN == 64 if (effective_mode == PrivilegeMode::S && CSR[mstatus].SXL != $bits(XRegWidth::XLEN64)) { # not supported in this XLEN @@ -1336,7 +1355,7 @@ function current_translation_mode { } # OK return SatpMode::Sv48; - } else if (mode_val == $bits(SatpMode::Sv57)) { + } else if ((XLEN == 64) && (mode_val == $bits(SatpMode::Sv57))) { # Sv57 is only defined when XLEN == 64 if (effective_mode == PrivilegeMode::S && CSR[mstatus].SXL != $bits(XRegWidth::XLEN64)) { # not supported in this XLEN @@ -1390,7 +1409,7 @@ function translate_gstage { } # mstatus.MXR affects G-stage XR, but not hstatus.MXR - Boolean mxr = CSR[mstatus].MXR; + Boolean mxr = CSR[mstatus].MXR == 1; if (GSTAGE_MODE_BARE && CSR[hgatp].MODE == $bits(HgatpMode::Bare)) { # bare mode @@ -1411,12 +1430,12 @@ function translate_gstage { } else { # Invalid mode if (op == MemoryOperation::Read) { - raise_guest_page_fault(op, gpaddr, vaddr, tinst_value_for_guest_page_fault(op, encoding, true)); + raise_guest_page_fault(op, gpaddr, vaddr, tinst_value_for_guest_page_fault(op, encoding, true), effective_mode); } else if (op == MemoryOperation::Write || op == MemoryOperation::ReadModifyWrite) { - raise_guest_page_fault(op, gpaddr, vaddr, tinst_value_for_guest_page_fault(op, encoding, true)); + raise_guest_page_fault(op, gpaddr, vaddr, tinst_value_for_guest_page_fault(op, encoding, true), effective_mode); } else { - assert(op == MemoryOperation::Fetch); - raise_guest_page_fault(op, gpaddr, vaddr, tinst_value_for_guest_page_fault(op, encoding, true)); + assert(op == MemoryOperation::Fetch, "unexpected memory op"); + raise_guest_page_fault(op, gpaddr, vaddr, tinst_value_for_guest_page_fault(op, encoding, true), effective_mode); } } } @@ -1446,7 +1465,7 @@ function tinst_value_for_guest_page_fault { if (TINST_VALUE_ON_FINAL_LOAD_GUEST_PAGE_FAULT == "always zero") { return 0; } else if (TINST_VALUE_ON_FINAL_LOAD_GUEST_PAGE_FAULT == "always pseudoinstruction") { - if ((VSXLEN == 32) || (CSR[hstatus].VSXL == $bits(XRegWidth::XLEN32))) { + if ((VSXLEN == 32) || ((XLEN == 64) && (CSR[hstatus].VSXL == $bits(XRegWidth::XLEN32)))) { return 0x00002000; } else { return 0x00003000; @@ -1460,7 +1479,7 @@ function tinst_value_for_guest_page_fault { if (TINST_VALUE_ON_FINAL_STORE_AMO_GUEST_PAGE_FAULT == "always zero") { return 0; } else if (TINST_VALUE_ON_FINAL_STORE_AMO_GUEST_PAGE_FAULT == "always pseudoinstruction") { - if ((VSXLEN == 32) || (CSR[hstatus].VSXL == $bits(XRegWidth::XLEN32))) { + if ((VSXLEN == 32) || ((XLEN == 64) && (CSR[hstatus].VSXL == $bits(XRegWidth::XLEN32)))) { return 0x00002020; } else { return 0x00003020; @@ -1474,9 +1493,9 @@ function tinst_value_for_guest_page_fault { } else { if (REPORT_GPA_IN_TVAL_ON_INTERMEDIATE_GUEST_PAGE_FAULT) { # spec states hardware must write the pseduo-instruction values to *tinst - if ((VSXLEN == 32) || (CSR[hstatus].VSXL == $bits(XRegWidth::XLEN32))) { + if ((VSXLEN == 32) || ((XLEN == 64) && (CSR[hstatus].VSXL == $bits(XRegWidth::XLEN32)))) { return 0x00002000; - } else if ((VSXLEN == 64) || (CSR[hstatus].VSXL == $bits(XRegWidth::XLEN64))) { + } else if ((VSXLEN == 64) || ((XLEN == 64) && (CSR[hstatus].VSXL == $bits(XRegWidth::XLEN64)))) { return 0x00003000; } } @@ -1515,11 +1534,26 @@ function tinst_transform { } } +function transformed_standard_instruction_for_tinst { + returns + Bits # transformed instruction encoding + arguments + Bits original # original instruction encoding + description { + Transforms an instruction encoding for htinst. + } + body { + assert(false, "TODO"); + return 0; + } +} + function tinst_value { returns XReg # tinst value arguments - ExceptionCode code # expect type + ExceptionCode code, # expect type + Bits encoding # instruction encoding, needed when tinst value might be the encoding description { Returns the value of htinst/mtinst for the given exception code. } @@ -1580,25 +1614,25 @@ function tinst_value { } else { unpredictable("An unpredictable value is written into tinst in response to a StoreAmoAccessFault exception"); } - } else if (code == ExceptionCode::UCall) { + } else if (code == ExceptionCode::Ucall) { if (TINST_VALUE_ON_UCALL == "always zero") { return 0; } else { unpredictable("An unpredictable value is written into tinst in response to a UCall exception"); } - } else if (code == ExceptionCode::SCall) { + } else if (code == ExceptionCode::Scall) { if (TINST_VALUE_ON_SCALL == "always zero") { return 0; } else { unpredictable("An unpredictable value is written into tinst in response to a SCall exception"); } - } else if (code == ExceptionCode::MCall) { + } else if (code == ExceptionCode::Mcall) { if (TINST_VALUE_ON_MCALL == "always zero") { return 0; } else { unpredictable("An unpredictable value is written into tinst in response to a MCall exception"); } - } else if (code == ExceptionCode::VSCall) { + } else if (code == ExceptionCode::VScall) { if (TINST_VALUE_ON_VSCALL == "always zero") { return 0; } else { @@ -1632,7 +1666,7 @@ function gstage_page_walk { template U32 VA_SIZE, # virtual address size (Sv32 = 32, Sv39 = 39, Sv48 = 48, Sv57 = 57) U32 PA_SIZE, # physical address size (Sv32 = 34, Sv39 = 56, Sv48 = 56, Sv57 = 56) - U32 PTESIZE, # length, in bits, of a Page Table Entry (Sv32 = 4, others = 8) + U32 PTESIZE, # length, in bits, of a Page Table Entry (Sv32 = 32, others = 64) U32 LEVELS # levels in the page table (Sv32 = 2, Sv39 = 3, Sv48 = 4, Sv57 = 5) returns TranslationResult # the translated address and attributes @@ -1677,7 +1711,7 @@ function gstage_page_walk { ExceptionCode::InstructionGuestPageFault : ExceptionCode::StoreAmoGuestPageFault ); - Boolean mxr = for_final_vs_pte && (CSR[menvcfg].MXR == 1); + Boolean mxr = for_final_vs_pte && (CSR[mstatus].MXR == 1); Boolean pbmte = CSR[menvcfg].PBMTE == 1; Boolean adue = CSR[menvcfg].ADUE == 1; @@ -1687,7 +1721,7 @@ function gstage_page_walk { U32 max_gpa_width = LEVELS * VPN_SIZE + 2 + 12; if (gpaddr >> max_gpa_width != 0) { # Guest physical address is too large for the page table - raise_guest_page_fault(op, gpaddr, vaddr, tinst); + raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode); } ppn = CSR[hgatp].PPN; @@ -1711,31 +1745,31 @@ function gstage_page_walk { # check if any reserved bits are set # Sv32 has no reserved bits, and Sv39/48/57 all have reserved bits at 60:54 if ((VA_SIZE != 32) && (pte[60:54] != 0)) { - raise_guest_page_fault(op, gpaddr, vaddr, tinst); + raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode); } if (!implemented?(ExtensionName::Svnapot)) { - if (pte[63] != 0) { + if ((PTESIZE >= 64) && pte[63] != 0) { # N is reserved if Svnapot is not supported - raise_guest_page_fault(op, gpaddr, vaddr, tinst); + raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode); } } - if (!pbmte && (pte[62:61] != 0)) { + if ((PTESIZE >= 64) && !pbmte && (pte[62:61] != 0)) { # PBMTE is reserved when Svpbmt is not enabled - raise_guest_page_fault(op, gpaddr, vaddr, tinst); + raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode); } - if (pbmte && (pte[62:61] == 3)) { + if ((PTESIZE >= 64) && pbmte && (pte[62:61] == 3)) { # PBMTE == 3 is reserved - raise_guest_page_fault(op, gpaddr, vaddr, tinst); + raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode); } if (pte_flags.V == 0) { # page table entry is not valid - raise_guest_page_fault(op, gpaddr, vaddr, tinst); + raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode); } if (pte_flags.R == 0 && pte_flags.W == 1) { # Writable pages must also be readable - raise_guest_page_fault(op, gpaddr, vaddr, tinst); + raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode); } if (pte_flags.R == 1 || pte_flags.X == 1) { @@ -1743,28 +1777,28 @@ function gstage_page_walk { if (pte_flags.U == 0) { # all g-stage tables *must* be user mode accessible # since all g-stage accesses appear like U-mode accesses - raise_guest_page_fault(op, gpaddr, vaddr, tinst); + raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode); } if (((op == MemoryOperation::Write) || (op == MemoryOperation::ReadModifyWrite)) && (pte_flags.W == 0)) { # not write permission for store - raise_guest_page_fault(op, gpaddr, vaddr, tinst); + raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode); } else if ((op == MemoryOperation::Fetch) && (pte_flags.X == 0)) { # no execute permission - raise_guest_page_fault(op, gpaddr, vaddr, tinst); + raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode); } else if ((op == MemoryOperation::Read) || (op == MemoryOperation::ReadModifyWrite)) { if (((!mxr) && (pte_flags.R == 0)) || ((mxr) && (pte_flags.X == 0 && pte_flags.R == 0))) { # no read permision - raise_guest_page_fault(op, gpaddr, vaddr, tinst); + raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode); } } # ensure remaining PPN bits are zero, otherwise there is a misaligned super page if ((i > 0) && (pte[(i-1)*VPN_SIZE:10] != 0)) { - raise_guest_page_fault(op, gpaddr, vaddr, tinst); + raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode); } # check access and dirty bits @@ -1812,13 +1846,15 @@ function gstage_page_walk { } else { # successful translation and update result.paddr = pte_paddr; - result.pbmt = pte[62:61]; + if (PTESIZE >= 64) { + result.pbmt = pte[62:61]; + } result.pte_flags = pte_flags; return result; } } else { # A or D bit needs updated - raise_guest_page_fault(op, gpaddr, vaddr, tinst); + raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode); } } @@ -1826,22 +1862,22 @@ function gstage_page_walk { # pointer to next level if (i == 0) { # a pointer can't exist on the last level - raise_guest_page_fault(op, gpaddr, vaddr, tinst); + raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode); } if (pte_flags.D == 1 || pte_flags.A == 1 || pte_flags.U == 1) { # D, A, and U are reserved in non-leaf PTEs - raise_guest_page_fault(op, gpaddr, vaddr, tinst); + raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode); } if ((VA_SIZE != 32) && (pte[62:61] != 0)) { # PBMT must be zero in a pointer PTE - raise_guest_page_fault(op, gpaddr, vaddr, tinst); + raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode); } if ((VA_SIZE != 32) && pte[63] != 0) { # N must be zero in a pointer PTE - raise_guest_page_fault(op, gpaddr, vaddr, tinst); + raise_guest_page_fault(op, gpaddr, vaddr, tinst, effective_mode); } # fall through to next level @@ -1900,19 +1936,19 @@ function stage1_page_walk { ExceptionCode::StoreAmoPageFault ); # shadow stacks enabled? - Boolean sse; - if (CSR[misa].H == 1 && effective_mode == PrivilegeMode::VS) { - sse = CSR[henvcfg].SSE == 1; - } else if (CSR[misa].H == 1 && effective_mode == PrivilegeMode::VU) { - sse = CSR[senvcfg].SSE == 1; - } else if (CSR[misa].U == 1 && effective_mode == PrivilegeMode::U) { - sse = CSR[senvcfg].SSE == 1; - } else if (CSR[misa].S == 1 && effective_mode == PrivilegeMode::S) { - sse = CSR[menvcfg].SSE == 1; - } else { - # M-mode - sse = false; - } + Boolean sse = false; + # if (CSR[misa].H == 1 && effective_mode == PrivilegeMode::VS) { + # sse = CSR[henvcfg].SSE == 1; + # } else if (CSR[misa].H == 1 && effective_mode == PrivilegeMode::VU) { + # sse = CSR[senvcfg].SSE == 1; + # } else if (CSR[misa].U == 1 && effective_mode == PrivilegeMode::U) { + # sse = CSR[senvcfg].SSE == 1; + # } else if (CSR[misa].S == 1 && effective_mode == PrivilegeMode::S) { + # sse = CSR[menvcfg].SSE == 1; + # } else { + # # M-mode + # sse = false; + # } # access/dirty bit hardware update enable? Boolean adue; @@ -1940,9 +1976,9 @@ function stage1_page_walk { if (CSR[misa].H == 1 && (effective_mode == PrivilegeMode::VS || effective_mode == PrivilegeMode::VU)) { # HS-level sstatus.MXR makes execute-only pages readable for both stages of address translation # (VS-stage and G-stage), whereas vsstatus.MXR affects only the first translation stage (VS-stage) - mxr = (CSR[menvcfg].MXR == 1) || (CSR[henvcfg].MXR == 1); + mxr = (CSR[mstatus].MXR == 1) || (CSR[vsstatus].MXR == 1); } else { - mxr = CSR[menvcfg].MXR == 1; + mxr = CSR[mstatus].MXR == 1; } # Supervisor access user page? @@ -1955,7 +1991,7 @@ function stage1_page_walk { ppn = CSR[vsatp].PPN; - if (vaddr[xlen()-1:VA_SIZE] != {xlen()-VA_SIZE{vaddr[VA_SIZE - 1]}}) { + if ((VA_SIZE < xlen()) && (vaddr[xlen()-1:VA_SIZE] != {xlen()-VA_SIZE{vaddr[VA_SIZE - 1]}})) { # non-canonical virtual address raises a page fault # note that if pointer masking is enabled, # vaddr has already been transformed before reaching here @@ -2015,13 +2051,13 @@ function stage1_page_walk { } } else { # PBMT is reserved if Svpbmt is not supported) - if ((pte[62:61] != 0)) { + if ((PTESIZE >= 64) && (pte[62:61] != 0)) { raise (page_fault_code, effective_mode, vaddr); } } if (!implemented?(ExtensionName::Svnapot)) { - if (pte[63] != 0) { + if ((PTESIZE >= 64) && (pte[63] != 0)) { # N is reserved if Svnapot is not supported raise (page_fault_code, effective_mode, vaddr); } @@ -2150,7 +2186,9 @@ function stage1_page_walk { encoding ); result.paddr = pte_phys.paddr; - result.pbmt = pte_phys.pbmt == 0 ? pte[62:61] : pte_phys.pbmt; + if (PTESIZE >= 64) { + result.pbmt = pte_phys.pbmt == Pbmt::PMA ? $enum(Pbmt, pte[62:61]) : pte_phys.pbmt; + } result.pte_flags = pte_flags; return result; } else { @@ -2238,7 +2276,7 @@ function translate { } else if (op == MemoryOperation::Write || op == MemoryOperation::ReadModifyWrite) { raise (ExceptionCode::StoreAmoPageFault, effective_mode, vaddr); } else { - assert(op == MemoryOperation::Fetch); + assert(op == MemoryOperation::Fetch, "Unexpected memory operation"); raise (ExceptionCode::InstructionPageFault, effective_mode, vaddr); } } @@ -2321,11 +2359,11 @@ function canonical_gpaddr? { } else if (satp_mode == SatpMode::Sv32) { # Sv32 uses all 32 bits of the VA return true; - } else if (satp_mode == SatpMode::Sv39) { + } else if ((XLEN > 32) && (satp_mode == SatpMode::Sv39)) { return gpaddr[63:39] == {25{gpaddr[38]}}; - } else if (satp_mode == SatpMode::Sv48) { + } else if ((XLEN > 32) && (satp_mode == SatpMode::Sv48)) { return gpaddr[63:48] == {16{gpaddr[47]}}; - } else if (satp_mode == SatpMode::Sv57) { + } else if ((XLEN > 32) && (satp_mode == SatpMode::Sv57)) { return gpaddr[63:57] == {6{gpaddr[56]}}; } } @@ -2414,10 +2452,10 @@ function read_memory { if (MAX_MISALIGNED_ATOMICITY_GRANULE_SIZE > 0) { # sanity check that the implementation isn't expecting a Misaligned exception # before an access/page fault exception (that would be an invalid config) - assert(MISALIGNED_LDST_EXCEPTION_PRIORITY == "low"); + assert(MISALIGNED_LDST_EXCEPTION_PRIORITY == "low", "Invalid config: can't mix low-priority misaligned exceptions with large atomicity granule"); physical_address = (CSR[misa].S == 1) - ? translate(virtual_address, MemoryOperation::Read, effective_ldst_mode(), encoding) + ? translate(virtual_address, MemoryOperation::Read, effective_ldst_mode(), encoding).paddr : virtual_address; if (misaligned_is_atomic?(physical_address)) { @@ -2433,7 +2471,7 @@ function read_memory { if (MISALIGNED_LDST_EXCEPTION_PRIORITY == "low") { # do translation to trigger any access/page faults before raising misaligned physical_address = (CSR[misa].S == 1) - ? translate(virtual_address, MemoryOperation::Read, effective_ldst_mode(), encoding) + ? translate(virtual_address, MemoryOperation::Read, effective_ldst_mode(), encoding).paddr : virtual_address; access_check(physical_address, LEN, virtual_address, MemoryOperation::Read, ExceptionCode::LoadAccessFault, effective_ldst_mode()); } @@ -2530,7 +2568,7 @@ function load_reserved { body { Bits physical_address = (CSR[misa].S == 1) - ? translate(virtual_address, MemoryOperation::Read, effective_ldst_mode(), encoding) + ? translate(virtual_address, MemoryOperation::Read, effective_ldst_mode(), encoding).paddr : virtual_address; if (pma_applies?(PmaAttribute::RsrvNone, physical_address, N)) { @@ -2577,7 +2615,7 @@ function store_conditional { body { Bits physical_address = (CSR[misa].S == 1) - ? translate(virtual_address, MemoryOperation::Write, effective_ldst_mode(), encoding) + ? translate(virtual_address, MemoryOperation::Write, effective_ldst_mode(), encoding).paddr : virtual_address; if (pma_applies?(PmaAttribute::RsrvNone, physical_address, N)) { @@ -2655,7 +2693,7 @@ function amo { Bits physical_address = (CSR[misa].S == 1) - ? translate(virtual_address, MemoryOperation::ReadModifyWrite, effective_ldst_mode(), encoding) + ? translate(virtual_address, MemoryOperation::ReadModifyWrite, effective_ldst_mode(), encoding).paddr : virtual_address; # PMA Atomicity checks @@ -2670,7 +2708,8 @@ function amo { } else { assert( pma_applies?(PmaAttribute::AmoSwap, physical_address, N) && - op == AmoOperation::Swap + op == AmoOperation::Swap, + "Bad AMO operation" ); } @@ -2704,7 +2743,7 @@ function write_memory_aligned { XReg physical_address; physical_address = (CSR[misa].S == 1) - ? translate(virtual_address, MemoryOperation::Write, effective_ldst_mode(), encoding) + ? translate(virtual_address, MemoryOperation::Write, effective_ldst_mode(), encoding).paddr : virtual_address; # may raise an exception @@ -2737,10 +2776,10 @@ function write_memory { if (MAX_MISALIGNED_ATOMICITY_GRANULE_SIZE > 0) { # sanity check that the implementation isn't expecting a Misaligned exception # before an access/page fault exception (that would be an invalid config) - assert(MISALIGNED_LDST_EXCEPTION_PRIORITY == "low"); + assert(MISALIGNED_LDST_EXCEPTION_PRIORITY == "low", "Invalid config: can't mix low-priority misaligned exceptions with large atomicity granule"); physical_address = (CSR[misa].S == 1) - ? translate(virtual_address, MemoryOperation::Write, effective_ldst_mode(), encoding) + ? translate(virtual_address, MemoryOperation::Write, effective_ldst_mode(), encoding).paddr : virtual_address; if (misaligned_is_atomic?(physical_address)) { @@ -2756,7 +2795,7 @@ function write_memory { if (MISALIGNED_LDST_EXCEPTION_PRIORITY == "low") { # do translation to trigger any access/page faults before raising misaligned physical_address = (CSR[misa].S == 1) - ? translate(virtual_address, MemoryOperation::Write, effective_ldst_mode(), encoding) + ? translate(virtual_address, MemoryOperation::Write, effective_ldst_mode(), encoding).paddr : virtual_address; access_check(physical_address, LEN, virtual_address, MemoryOperation::Write, ExceptionCode::StoreAmoAccessFault, effective_ldst_mode()); } diff --git a/arch/isa/util.idl b/arch/isa/util.idl index ba031a180d..3b8370c89f 100644 --- a/arch/isa/util.idl +++ b/arch/isa/util.idl @@ -82,6 +82,28 @@ function lowest_set_bit { } } +function count_leading_zeros { + template U32 N + returns + Bits # Number of leading zeros in +vlaue+ + arguments + Bits value # value to count zero in + description { + Returns the number of leading 0 bits before the most-significant 1 bit of +value+, + or N if value is zero. + } + body { + for (U32 i=0; i < N; i++) { + if (value[N - 1 - i] == 1) { + return i; + } + } + + # fall-through; value must be zero + return N; + } +} + function sext { returns XReg arguments XReg value, XReg first_extended_bit diff --git a/arch/manual/isa/20240411/contents.yaml b/arch/manual/isa/20240411/contents.yaml index 7a6a7e6c37..41819afbce 100644 --- a/arch/manual/isa/20240411/contents.yaml +++ b/arch/manual/isa/20240411/contents.yaml @@ -203,10 +203,13 @@ volumes: - [Smrnmi, "0.5.0"] - [Smcdeleg, "1.0.0"] - [S, "1.12.0"] - - [Sv32, "1.13.0"] - - [Sv39, "1.13.0"] - - [Sv48, "1.13.0"] - - [Sv57, "1.13.0"] + - [Sm, "1.12.0"] + - [Smhpm, "1.12.0"] + - [Smpmp, "1.12.0"] + - [Sv32, "1.12.0"] + - [Sv39, "1.12.0"] + - [Sv48, "1.12.0"] + - [Sv57, "1.12.0"] - [Svnapot, "1.0.0"] - [Svpbmt, "1.0.0"] - [Svinval, "1.0.0"] diff --git a/arch/profile/rva20s64.yaml b/arch/profile/rva20s64.yaml index bf38cb136b..eab1825c5e 100644 --- a/arch/profile/rva20s64.yaml +++ b/arch/profile/rva20s64.yaml @@ -15,47 +15,56 @@ rva20s64: email: krste@sifive.com company: SiFive extensions: - mandatory: - - name: S - version: "= 1.11" - - name: Zifencei - version: "= 2.0" - note: | - Zifencei is mandated as it is the only standard way to support - instruction-cache coherence in RVA20 application processors. A new - instruction-cache coherence mechanism is under development which might - be added as an option in the future. - - name: Svbare - version: "= 1.0" - note: | - Svbare is a new extension name introduced with RVA20. - - name: Sv39 - version: "= 1.11" - - name: Svade - version: "~> 1.0" - note: | - Svbare is a new extension name introduced with RVA20. + - name: S + presence: mandatory + version: "= 1.11" + - name: Zifencei + presence: mandatory + version: "= 2.0" + note: | + Zifencei is mandated as it is the only standard way to support + instruction-cache coherence in RVA20 application processors. A new + instruction-cache coherence mechanism is under development which might + be added as an option in the future. + - name: Svbare + presence: mandatory + version: "= 1.0" + note: | + Svbare is a new extension name introduced with RVA20. + - name: Sv39 + presence: mandatory + version: "= 1.11" + - name: Svade + presence: mandatory + version: "~> 1.0" + note: | + Svbare is a new extension name introduced with RVA20. - It is subsequently defined in more detail with the ratification of - `Svadu`. - - name: Ssccptr - version: "= 1.0" - note: | - Ssccptr is a new extension name introduced with RVA20. - - name: Sstvecd - version: "= 1.0" - note: | - Sstvecd is a new extension name introduced with RVA20. - - name: Sstvala - version: "= 1.0" - note: | - Sstvala is a new extension name introduced with RVA20. - optional: - - name: Zihpm - version: "= 2.0" - - name: Sv48 - version: "= 1.11" - - name: Ssu64xl - version: "= 1.0" - note: | - Ssu64xl is a new extension name introduced with RVA20. + It is subsequently defined in more detail with the ratification of + `Svadu`. + - name: Ssccptr + presence: mandatory + version: "= 1.0" + note: | + Ssccptr is a new extension name introduced with RVA20. + - name: Sstvecd + presence: mandatory + version: "= 1.0" + note: | + Sstvecd is a new extension name introduced with RVA20. + - name: Sstvala + presence: mandatory + version: "= 1.0" + note: | + Sstvala is a new extension name introduced with RVA20. + - name: Zihpm + presence: optional + version: "= 2.0" + - name: Sv48 + presence: optional + version: "= 1.11" + - name: Ssu64xl + presence: optional + version: "= 1.0" + note: | + Ssu64xl is a new extension name introduced with RVA20. diff --git a/arch/profile/rva20u64.yaml b/arch/profile/rva20u64.yaml index 19b086dfd2..195c29387e 100644 --- a/arch/profile/rva20u64.yaml +++ b/arch/profile/rva20u64.yaml @@ -17,105 +17,118 @@ rva20u64: email: krste@sifive.com company: SiFive extensions: - mandatory: - - name: I - version: "~> 2.1" - note: | - RVI is the mandatory base ISA for RVA, and is little-endian. + - name: I + presence: mandatory + version: "~> 2.1" + note: | + RVI is the mandatory base ISA for RVA, and is little-endian. - As per the unprivileged architecture specification, the `ecall` - instruction causes a requested trap to the execution environment. + As per the unprivileged architecture specification, the `ecall` + instruction causes a requested trap to the execution environment. - The `fence.tso` instruction is mandatory. + The `fence.tso` instruction is mandatory. - NOTE: The `fence.tso` instruction was incorrectly described as - optional in the 2019 ratified specifications. However, `fence.tso` is - encoded within the standard `fence` encoding such that implementations - must treat it as a simple global fence if they do not natively support - TSO-ordering optimizations. As software can always assume without any - penalty that `fence.tso` is being exploited by a hardware - implementation, there is no advantage to making the instruction a - profile option. Later versions of the unprivileged ISA - specifications correctly indicate that `fence.tso` is mandatory. - - name: A - version: "= 2.1" - - name: C - version: "= 2.2" - - name: D - version: "= 2.2" - - name: F - version: "= 2.2" - - name: M - version: "= 2.0" - - name: U - version: "~> 2.0" - param_constraints: - U_MODE_ENDIANESS: - schema: - const: little - - name: Zicntr - version: " = 2.0" - - name: Ziccif - version: "= 1.0" - note: | - Ziccif is a new extension name introduced with RVA20. - The fetch atomicity requirement facilitates runtime patching - of aligned instructions. - - name: Ziccrse - version: "= 1.0" - note: | - Ziccrse is a new extension name introduced with RVA20. - - name: Ziccamoa - version: "= 1.0" - note: | - Ziccamo is a new extension name introduced with RVA20. - - name: Za128rs - version: "= 1.0" - note: | - Za128rs is a new extension name introduced with RVA20. - The minimum reservation set size is effectively determined by the - size of atomic accesses in the `A` extension. - - name: Zicclsm - version: "= 1.0" - note: | - Zicclsm is a new extension name introduced with RVA20. - This requires misaligned support for all regular load and store - instructions (including scalar and vector) but not AMOs or other - specialized forms of memory access. Even though mandated, misaligned - loads and stores might execute extremely slowly. Standard software - distributions should assume their existence only for correctness, not - for performance. - optional: - - name: Zihpm - version: "= 2.0" - note: | - The number of counters is platform-specific. - excluded: - - name: Q - note: | - The rationale to not make Q an optional extension is that - quad-precision floating-point is unlikely to be implemented in - hardware, and so we do not require or expect A-profile software to - expend effort optimizing use of Q instructions in case they are - present. - - name: Zifencei - note: | - Zifencei is not classed as a supported option in the user-mode - profile because it is not sufficient by itself to produce the desired - effect in a multiprogrammed multiprocessor environment without OS - support, and so the instruction cache flush should always be performed - using an OS call rather than using the `fence.i` instruction. - `fence.i` semantics can be expensive to implement for some hardware - memory hierarchy designs, and so alternative non-standard - instruction-cache coherence mechanisms can be used behind the OS - abstraction. A separate extension is being developed for more general - and efficient instruction cache coherence. + NOTE: The `fence.tso` instruction was incorrectly described as + optional in the 2019 ratified specifications. However, `fence.tso` is + encoded within the standard `fence` encoding such that implementations + must treat it as a simple global fence if they do not natively support + TSO-ordering optimizations. As software can always assume without any + penalty that `fence.tso` is being exploited by a hardware + implementation, there is no advantage to making the instruction a + profile option. Later versions of the unprivileged ISA + specifications correctly indicate that `fence.tso` is mandatory. + - name: A + presence: mandatory + version: "= 2.1" + - name: C + presence: mandatory + version: "= 2.2" + - name: D + presence: mandatory + version: "= 2.2" + - name: F + presence: mandatory + version: "= 2.2" + - name: M + presence: mandatory + version: "= 2.0" + - name: U + presence: mandatory + version: "~> 2.0" + param_constraints: + U_MODE_ENDIANESS: + schema: + const: little + - name: Zicntr + presence: mandatory + version: " = 2.0" + - name: Ziccif + presence: mandatory + version: "= 1.0" + note: | + Ziccif is a new extension name introduced with RVA20. + The fetch atomicity requirement facilitates runtime patching + of aligned instructions. + - name: Ziccrse + presence: mandatory + version: "= 1.0" + note: | + Ziccrse is a new extension name introduced with RVA20. + - name: Ziccamoa + presence: mandatory + version: "= 1.0" + note: | + Ziccamo is a new extension name introduced with RVA20. + - name: Za128rs + presence: mandatory + version: "= 1.0" + note: | + Za128rs is a new extension name introduced with RVA20. + The minimum reservation set size is effectively determined by the + size of atomic accesses in the `A` extension. + - name: Zicclsm + presence: mandatory + version: "= 1.0" + note: | + Zicclsm is a new extension name introduced with RVA20. + This requires misaligned support for all regular load and store + instructions (including scalar and vector) but not AMOs or other + specialized forms of memory access. Even though mandated, misaligned + loads and stores might execute extremely slowly. Standard software + distributions should assume their existence only for correctness, not + for performance. + - name: Zihpm + presence: optional + version: "= 2.0" + note: | + The number of counters is platform-specific. + - name: Q + presence: excluded + note: | + The rationale to not make Q an optional extension is that + quad-precision floating-point is unlikely to be implemented in + hardware, and so we do not require or expect A-profile software to + expend effort optimizing use of Q instructions in case they are + present. + - name: Zifencei + presence: excluded + note: | + Zifencei is not classed as a supported option in the user-mode + profile because it is not sufficient by itself to produce the desired + effect in a multiprogrammed multiprocessor environment without OS + support, and so the instruction cache flush should always be performed + using an OS call rather than using the `fence.i` instruction. + `fence.i` semantics can be expensive to implement for some hardware + memory hierarchy designs, and so alternative non-standard + instruction-cache coherence mechanisms can be used behind the OS + abstraction. A separate extension is being developed for more general + and efficient instruction cache coherence. - The execution environment must provide a means to synchronize writes to - instruction memory with instruction fetches, the implementation of which - likely relies on the Zifencei extension. - For example, RISC-V Linux supplies the `__riscv_flush_icache` system call and - a corresponding vDSO call. + The execution environment must provide a means to synchronize writes to + instruction memory with instruction fetches, the implementation of which + likely relies on the Zifencei extension. + For example, RISC-V Linux supplies the `__riscv_flush_icache` system call and + a corresponding vDSO call. recommendations: - Implementations are strongly recommended to raise illegal-instruction exceptions on attempts to execute unimplemented opcodes. diff --git a/arch/profile/rva22s64.yaml b/arch/profile/rva22s64.yaml index 3adc51a380..03078f3f13 100644 --- a/arch/profile/rva22s64.yaml +++ b/arch/profile/rva22s64.yaml @@ -15,80 +15,93 @@ rva22s64: email: krste@sifive.com company: SiFive extensions: - mandatory: - - name: S - version: "= 1.12" - - name: Sscounterenw - version: "= 1.0" - note: | - Sstvala is a new extension name introduced with RVA22. - - name: Svpbmt - version: "~> 1.0" - - name: Svinval - version: "~> 1.0" - - name: Ssstateen - version: "~> 1.0" - when: - implemented: H - note: | - Ssstateen is a new extension name introduced with RVA22. - - name: Shvstvala - version: "~> 1.0" - when: - implemented: H - note: | - Shvstvala is a new extension name introduced with RVA22. - - name: Shtvala - version: "~> 1.0" - when: - implemented: H - note: | - Shtvala is a new extension name introduced with RVA22. - - name: Shvstvecd - version: "~> 1.0" - when: - implemented: H - note: | - Shvstvecd is a new extension name introduced with RVA22. - - name: Shgatpa - version: "~> 1.0" - when: - implemented: H - note: | - Shgatpa is a new extension name introduced with RVA22. - optional: - - name: Sv57 - version: "~> 1.12" - - name: Svnapot - version: "~> 1.0" - note: | - It is expected that Svnapot will be mandatory in the next - profile release. - - name: Sstc - version: "~> 1.0" - note: | - Sstc was not made mandatory in RVA22S64 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. - - name: Sscofpmf - version: "~> 1.0" - note: | - Platforms may choose to mandate the presence of Sscofpmf. - - name: Zkr - version: "~> 1.0" - 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. - - name: H - version: "~> 1.0" - note: | - The following extensions become mandatory when H is implemented: + - name: S + presence: mandatory + version: "= 1.12" + - name: Sscounterenw + presence: mandatory + version: "= 1.0" + note: | + Sstvala is a new extension name introduced with RVA22. + - name: Svpbmt + presence: mandatory + version: "~> 1.0" + - name: Svinval + presence: mandatory + version: "~> 1.0" + - name: Ssstateen + presence: mandatory + version: "~> 1.0" + when: + implemented: H + note: | + Ssstateen is a new extension name introduced with RVA22. + - name: Shvstvala + presence: mandatory + version: "~> 1.0" + when: + implemented: H + note: | + Shvstvala is a new extension name introduced with RVA22. + - name: Shtvala + presence: mandatory + version: "~> 1.0" + when: + implemented: H + note: | + Shtvala is a new extension name introduced with RVA22. + - name: Shvstvecd + presence: mandatory + version: "~> 1.0" + when: + implemented: H + note: | + Shvstvecd is a new extension name introduced with RVA22. + - name: Shgatpa + presence: mandatory + version: "~> 1.0" + when: + implemented: H + note: | + Shgatpa is a new extension name introduced with RVA22. + - name: Sv57 + presence: optional + version: "~> 1.12" + - name: Svnapot + presence: optional + version: "~> 1.0" + note: | + It is expected that Svnapot will be mandatory in the next + profile release. + - name: Sstc + presence: optional + version: "~> 1.0" + note: | + Sstc was not made mandatory in RVA22S64 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. + - name: Sscofpmf + presence: optional + version: "~> 1.0" + note: | + Platforms may choose to mandate the presence of Sscofpmf. + - name: Zkr + presence: optional + version: "~> 1.0" + 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. + - name: H + presence: optional + version: "~> 1.0" + note: | + The following extensions become mandatory when H is implemented: - * Ssstateen - * Shcounterenw - * Shvstvala - * Shtvala - * Shvstvecd - * Shgatpa \ No newline at end of file + * Ssstateen + * Shcounterenw + * Shvstvala + * Shtvala + * Shvstvecd + * Shgatpa \ No newline at end of file diff --git a/arch/profile/rva22u64.yaml b/arch/profile/rva22u64.yaml index 29988b60d4..7fb58cc60e 100644 --- a/arch/profile/rva22u64.yaml +++ b/arch/profile/rva22u64.yaml @@ -14,106 +14,119 @@ rva22u64: email: krste@sifive.com company: SiFive extensions: - mandatory: - - name: Zihpm - version: "= 2.0" - - name: Zihintpause - version: "= 2.0" - note: | - While the `pause` instruction is a HINT can be implemented as a - NOP and hence trivially supported by hardware implementers, its - inclusion in the mandatory extension list signifies that software - should use the instruction whenever it would make sense and that - implementors are expected to exploit this information to optimize - hardware execution. - - name: Zba - version: "~> 1.0" - - name: Zbb - version: "~> 1.0" - - name: Zbs - version: "~> 1.0" - - name: Zic64b - version: "= 1.0" - note: | - This is a new extension name for this feature. While the general - RISC-V specifications are agnostic to cache block size, selecting a - common cache block size simplifies the specification and use of the - following cache-block extensions within the application processor - profile. Software does not have to query a discovery mechanism and/or - provide dynamic dispatch to the appropriate code. We choose 64 bytes - at it is effectively an industry standard. Implementations may use - longer cache blocks to reduce tag cost provided they use 64-byte - sub-blocks to remain compatible. Implementations may use shorter cache - blocks provided they sequence cache operations across the multiple - cache blocks comprising a 64-byte block to remain compatible. - - name: Zicbom - version: "~> 1.0" - - name: Zicbop - version: "~> 1.0" - note: | - As with other HINTS, the inclusion of prefetches in the - mandatory set of extensions indicates that software should generate - these instructions where they are expected to be useful, and hardware - is expected to exploit that information. - - name: Zicboz - version: "~> 1.0" - - name: Zfhmin - 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. - - name: Zkt - version: "~> 1.0" - note: | - Zkt requires a certain subset of integer instructions execute - with data-independent latency. Mandating this feature enables - portable libraries for safe basic cryptographic operations. It is - expected that application processors will naturally have this property - and so implementation cost is low, if not zero, in most systems that - would support RVA22. - optional: - - name: Zfh - version: "~> 1.0" - note: A future profile might mandate V. - - name: V - version: "~> 1.0" - note: | - The smaller vector extensions (Zve32f, Zve32x, Zve64d, Zve64f, - Zve64x) are not provided as separately supported profile options. The - full V extension is specified as the only supported profile option. + - name: Zihpm + presence: mandatory + version: "= 2.0" + - name: Zihintpause + presence: mandatory + version: "= 2.0" + note: | + While the `pause` instruction is a HINT can be implemented as a + NOP and hence trivially supported by hardware implementers, its + inclusion in the mandatory extension list signifies that software + should use the instruction whenever it would make sense and that + implementors are expected to exploit this information to optimize + hardware execution. + - name: Zba + presence: mandatory + version: "~> 1.0" + - name: Zbb + presence: mandatory + version: "~> 1.0" + - name: Zbs + presence: mandatory + version: "~> 1.0" + - name: Zic64b + presence: mandatory + version: "= 1.0" + note: | + This is a new extension name for this feature. While the general + RISC-V specifications are agnostic to cache block size, selecting a + common cache block size simplifies the specification and use of the + following cache-block extensions within the application processor + profile. Software does not have to query a discovery mechanism and/or + provide dynamic dispatch to the appropriate code. We choose 64 bytes + at it is effectively an industry standard. Implementations may use + longer cache blocks to reduce tag cost provided they use 64-byte + sub-blocks to remain compatible. Implementations may use shorter cache + blocks provided they sequence cache operations across the multiple + cache blocks comprising a 64-byte block to remain compatible. + - name: Zicbom + presence: mandatory + version: "~> 1.0" + - name: Zicbop + presence: mandatory + version: "~> 1.0" + note: | + As with other HINTS, the inclusion of prefetches in the + mandatory set of extensions indicates that software should generate + these instructions where they are expected to be useful, and hardware + is expected to exploit that information. + - name: Zicboz + presence: mandatory + version: "~> 1.0" + - name: Zfhmin + presence: mandatory + 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. + - name: Zkt + presence: mandatory + version: "~> 1.0" + note: | + Zkt requires a certain subset of integer instructions execute + with data-independent latency. Mandating this feature enables + portable libraries for safe basic cryptographic operations. It is + expected that application processors will naturally have this property + and so implementation cost is low, if not zero, in most systems that + would support RVA22. + - name: Zfh + presence: optional + version: "~> 1.0" + note: A future profile might mandate V. + - name: V + presence: optional + version: "~> 1.0" + note: | + The smaller vector extensions (Zve32f, Zve32x, Zve64d, Zve64f, + Zve64x) are not provided as separately supported profile options. The + full V extension is specified as the only supported profile option. - A future profile might mandate V. - - name: Zkn - version: "~> 1.0" - note: | - The scalar crypto extensions are expected to be superseded by - vector crypto standards in future profiles, and the scalar extensions - may be removed as supported options once vector crypto is present. + A future profile might mandate V. + - name: Zkn + presence: optional + version: "~> 1.0" + note: | + The scalar crypto extensions are expected to be superseded by + vector crypto standards in future profiles, and the scalar extensions + may be removed as supported options once vector crypto is present. - The smaller component scalar crypto extensions (Zbc, Zbkb, Zbkc, - Zbkx, Zknd, Zkne, Zknh, Zksed, Zksh) are not provided as separate - options in the profile. Profile implementers should provide all of - the instructions in a given algorithm suite as part of the Zkn or Zks - supported options. - - name: Zks - version: "~> 1.0" - note: | - The scalar crypto extensions are expected to be superseded by - vector crypto standards in future profiles, and the scalar extensions - may be removed as supported options once vector crypto is present. + The smaller component scalar crypto extensions (Zbc, Zbkb, Zbkc, + Zbkx, Zknd, Zkne, Zknh, Zksed, Zksh) are not provided as separate + options in the profile. Profile implementers should provide all of + the instructions in a given algorithm suite as part of the Zkn or Zks + supported options. + - name: Zks + presence: optional + version: "~> 1.0" + note: | + The scalar crypto extensions are expected to be superseded by + vector crypto standards in future profiles, and the scalar extensions + may be removed as supported options once vector crypto is present. - The smaller component scalar crypto extensions (Zbc, Zbkb, Zbkc, - Zbkx, Zknd, Zkne, Zknh, Zksed, Zksh) are not provided as separate - options in the profile. Profile implementers should provide all of - the instructions in a given algorithm suite as part of the Zkn or Zks - supported options. - excluded: - - name: Zkr - note: | - Access to the entropy source (Zkr) in a system is usually - carefully controlled. While the design supports unprivileged access - to the entropy source, this is unlikely to be commonly used in an - application processor, and so Zkr was not added as a profile option. - This also means the roll-up Zk was not added as a profile option. \ No newline at end of file + The smaller component scalar crypto extensions (Zbc, Zbkb, Zbkc, + Zbkx, Zknd, Zkne, Zknh, Zksed, Zksh) are not provided as separate + options in the profile. Profile implementers should provide all of + the instructions in a given algorithm suite as part of the Zkn or Zks + supported options. + - name: Zkr + presence: excluded + note: | + Access to the entropy source (Zkr) in a system is usually + carefully controlled. While the design supports unprivileged access + to the entropy source, this is unlikely to be commonly used in an + application processor, and so Zkr was not added as a profile option. + This also means the roll-up Zk was not added as a profile option. \ No newline at end of file diff --git a/backends/arch_gen/lib/arch_gen.rb b/backends/arch_gen/lib/arch_gen.rb index cd574bfb49..7baff6b838 100644 --- a/backends/arch_gen/lib/arch_gen.rb +++ b/backends/arch_gen/lib/arch_gen.rb @@ -42,7 +42,8 @@ def gen_params_schema "type" => "object", "required" => ["NAME"], "properties" => { - "NAME" => { "type" => "string", "enum" => [@name] } + "NAME" => { "type" => "string", "enum" => [@name] }, + "XLEN" => { "type" => "intger", "enum" => [32, 64] } }, "additionalProperties" => false } @@ -90,6 +91,12 @@ def initialize(config_name) @cfg_impl_ext = @validator.validate(cfg_impl_ext_path)["implemented_extensions"] raise "Validation failed" if @cfg_impl_ext.nil? + cfg_opts_path = @cfg_dir / "cfg.yaml" + @cfg_opts = YAML.load_file(cfg_opts_path) + raise "Validation failed" if @cfg_opts.nil? + raise "Validation failed: bad type" unless ["partially configured", "fully configured"].include?(@cfg_opts["type"]) + + @params_schema_path = @gen_dir / "schemas" / "params_schema.json" @ext_gen_complete = false @@ -199,7 +206,7 @@ def check_extension_dependencies requirements = @required_ext_map[[ext["name"], ext["version"]]] satisfied = requirements.satisfied_by? do |req| @implemented_extensions.any? do |ext2| - (ext2["name"] == req[0]) && Gem::Requirement.new(req[1]).satisfied_by?(Gem::Version.new(ext2["version"])) + (ext2["name"] == req.name) && Gem::Requirement.new(req.version_requirement).satisfied_by?(Gem::Version.new(ext2["version"])) end end unless satisfied @@ -276,15 +283,69 @@ def gen_arch_def ext_name = ext_obj.keys[0] [ext_name, ext_obj[ext_name]] end.to_h + profile_family_hash = Dir.glob($root / "arch" / "profile_family" / "**" / "*.yaml").map do |f| + profile_obj = YAML.load_file(f) + profile_name = profile_obj.keys[0] + profile_obj[profile_name]["name"] = profile_name + profile_obj[profile_name]["__source"] = f + [profile_name, profile_obj[profile_name]] + end.to_h + profile_hash = Dir.glob($root / "arch" / "profile" / "**" / "*.yaml").map do |f| + profile_obj = YAML.load_file(f) + profile_name = profile_obj.keys[0] + profile_obj[profile_name]["name"] = profile_name + profile_obj[profile_name]["__source"] = f + [profile_name, profile_obj[profile_name]] + end.to_h + manual_hash = {} + Dir.glob($root / "arch" / "manual" / "**" / "contents.yaml").map do |f| + manual_version = YAML.load_file(f) + manual_id = manual_version["manual"] + unless manual_hash.key?(manual_id) + manual_info_files = Dir.glob($root / "arch" / "manual" / "**" / "#{manual_id}.yaml") + raise "Could not find manual info '#{manual_id}'.yaml, needed by #{f}" if manual_info_files.empty? + raise "Found multiple manual infos '#{manual_id}'.yaml, needed by #{f}" if manual_info_files.size > 1 + + manual_info_file = manual_info_files.first + manual_hash[manual_id] = YAML.load_file(manual_info_file) + manual_hash[manual_id]["__source"] = manual_info_file + # TODO: schema validation + end + + manual_hash[manual_id]["versions"] ||= [] + manual_hash[manual_id]["versions"] << YAML.load_file(f) + # TODO: schema validation + manual_hash[manual_id]["versions"].last["__source"] = f + end + crd_family_hash = Dir.glob($root / "arch" / "crd_family" / "**" / "*.yaml").map do |f| + family_obj = YAML.load_file(f, permitted_classes: [Date]) + family_name = family_obj.keys[0] + family_obj[family_name]["name"] = family_name + family_obj[family_name]["__source"] = f + [family_name, family_obj[family_name]] + end.to_h + crd_hash = Dir.glob($root / "arch" / "crd" / "**" / "*.yaml").map do |f| + crd_obj = YAML.load_file(f, permitted_classes: [Date]) + crd_name = crd_obj.keys[0] + crd_obj[crd_name]["name"] = crd_name + crd_obj[crd_name]["__source"] = f + [crd_name, crd_obj[crd_name]] + end.to_h arch_def = { + "type" => @cfg_opts["type"], "params" => params, "instructions" => inst_hash, "implemented_instructions" => @implemented_instructions, "extensions" => ext_hash, "implemented_extensions" => @implemented_extensions, "csrs" => csr_hash, - "implemented_csrs" => @implemented_csrs + "implemented_csrs" => @implemented_csrs, + "profile_families" => profile_family_hash, + "profiles" => profile_hash, + "manuals" => manual_hash, + "crd_families" => crd_family_hash, + "crds" => crd_hash } yaml = YAML.dump(arch_def) @@ -658,7 +719,7 @@ def maybe_add_csr(csr_name, extra_env = {}) @implemented_csrs ||= [] @implemented_csrs << csr_name if belongs - gen_csr_path = @gen_dir / "arch" / "csr" / csr_obj.defined_by[0].name / "#{csr_name}.yaml" + gen_csr_path = @gen_dir / "arch" / "csr" / csr_obj.primary_defined_by / "#{csr_name}.yaml" FileUtils.mkdir_p gen_csr_path.dirname gen_csr_path.write csr_yaml end @@ -909,8 +970,8 @@ def maybe_add_inst(inst_name, extra_env = {}) @implemented_instructions ||= [] @implemented_instructions << inst_name if belongs - raise "?" if inst_obj.defined_by[0].name.nil? - gen_inst_path = @gen_dir / "arch" / "inst" / inst_obj.defined_by[0].name / "#{inst_name}.yaml" + raise "?" if inst_obj.primary_defined_by.nil? + gen_inst_path = @gen_dir / "arch" / "inst" / inst_obj.primary_defined_by / "#{inst_name}.yaml" FileUtils.mkdir_p gen_inst_path.dirname gen_inst_path.write inst_yaml diff --git a/backends/arch_gen/tasks.rake b/backends/arch_gen/tasks.rake index 84ae47e5f7..4fd8d3a07d 100644 --- a/backends/arch_gen/tasks.rake +++ b/backends/arch_gen/tasks.rake @@ -13,9 +13,13 @@ def arch_def_for(config_name) @arch_defs[config_name] = if config_name == "_" - ArchDef.new + ArchDef.new("_", $root / "gen" / "_" / "arch" / "arch_def.yaml") else - ImplArchDef.new(config_name) + ArchDef.new( + config_name, + $root / "gen" / config_name / "arch" / "arch_def.yaml", + overlay_path: $root / "cfgs" / config_name / "arch_overlay" + ) end end @@ -87,14 +91,14 @@ file "#{$root}/.stamps/arch-gen.stamp" => ( # TODO: schema validation manual_hash[manual_id]["versions"].last["__source"] = f end - csc_crd_family_hash = Dir.glob($root / "arch" / "csc_crd_family" / "**" / "*.yaml").map do |f| + crd_family_hash = Dir.glob($root / "arch" / "crd_family" / "**" / "*.yaml").map do |f| family_obj = YAML.load_file(f, permitted_classes: [Date]) family_name = family_obj.keys[0] family_obj[family_name]["name"] = family_name family_obj[family_name]["__source"] = f [family_name, family_obj[family_name]] end.to_h - csc_crd_hash = Dir.glob($root / "arch" / "csc_crd" / "**" / "*.yaml").map do |f| + crd_hash = Dir.glob($root / "arch" / "crd" / "**" / "*.yaml").map do |f| crd_obj = YAML.load_file(f, permitted_classes: [Date]) crd_name = crd_obj.keys[0] crd_obj[crd_name]["name"] = crd_name @@ -103,14 +107,15 @@ file "#{$root}/.stamps/arch-gen.stamp" => ( end.to_h arch_def = { + "type" => "unconfigured", "instructions" => inst_hash, "extensions" => ext_hash, "csrs" => csr_hash, "profile_families" => profile_family_hash, "profiles" => profile_hash, "manuals" => manual_hash, - "csc_crd_families" => csc_crd_family_hash, - "csc_crds" => csc_crd_hash + "crd_families" => crd_family_hash, + "crds" => crd_hash } dest = "#{$root}/gen/_/arch/arch_def.yaml" diff --git a/backends/cfg_html_doc/adoc_gen.rake b/backends/cfg_html_doc/adoc_gen.rake index 36cbd5d000..2e83a6efa0 100644 --- a/backends/cfg_html_doc/adoc_gen.rake +++ b/backends/cfg_html_doc/adoc_gen.rake @@ -50,7 +50,7 @@ require "ruby-prof" File.write(path, arch_def.find_replace_links(erb.result(binding))) end when "func" - global_symtab = arch_def.sym_table + global_symtab = arch_def.symtab path = dir_path / "funcs.adoc" puts " Generating #{path}" File.write(path, arch_def.find_replace_links(erb.result(binding))) diff --git a/backends/cfg_html_doc/templates/csr.adoc.erb b/backends/cfg_html_doc/templates/csr.adoc.erb index 1586c2982d..671ddb68a7 100644 --- a/backends/cfg_html_doc/templates/csr.adoc.erb +++ b/backends/cfg_html_doc/templates/csr.adoc.erb @@ -14,7 +14,7 @@ h| CSR Address | <%= "0x#{csr.address.to_s(16)}" %> <%- if csr.priv_mode == 'VS' -%> h| Virtual CSR Address | <%= "0x#{csr.virtual_address.to_s(16)}" %> <%- end -%> -h| Defining extension | <%= csr.defined_by.map(&:to_s).join(", ") %> +h| Defining extension a| <%= csr.defined_by.to_asciidoc %> <%- if csr.dynamic_length?(arch_def) -%> h| Length | <%= csr.length_pretty(arch_def) %> <%- else -%> @@ -29,7 +29,7 @@ h| Privilege Mode | <%= csr.priv_mode %> .<%= csr.name %> format [wavedrom, ,svg,subs='attributes',width="100%"] .... -<%= JSON.dump csr.wavedrom_desc(arch_def, arch_def.param_values["XLEN"]) %> +<%= JSON.dump csr.wavedrom_desc(arch_def, arch_def.param_values["XLEN"], exclude_unimplemented: true) %> .... <%- else -%> <%# CSR has a dynamic length, or a field has a dynamic location, @@ -39,13 +39,13 @@ This CSR format changes dynamically. .<%= csr.name %> Format when <%= csr.length_cond32 %> [wavedrom, ,svg,subs='attributes',width="100%"] .... -<%= JSON.dump csr.wavedrom_desc(arch_def, 32) %> +<%= JSON.dump csr.wavedrom_desc(arch_def, 32, exclude_unimplemented: true) %> .... .<%= csr.name %> Format when <%= csr.length_cond64 %> [wavedrom, ,svg,subs='attributes',width="100%"] .... -<%= JSON.dump csr.wavedrom_desc(arch_def, 64) %> +<%= JSON.dump csr.wavedrom_desc(arch_def, 64, exclude_unimplemented: true) %> .... @@ -60,7 +60,7 @@ This CSR format changes dynamically. <%- csr.implemented_fields(arch_def).each do |field| -%> | `xref:<%=csr.name%>-<%=field.name%>-def[<%= field.name %>]` | <%= field.location_pretty(arch_def) %> -| <%= field.type(arch_def) %> +| <%= field.type(arch_def.symtab) %> | <%= field.reset_value(arch_def) %> <%- end -%> @@ -88,14 +88,14 @@ Type:: [%autowidth] |=== -| <%= field.type(arch_def) %> | <%= field.type_desc(arch_def) %> +| <%= field.type(arch_def.symtab) %> | <%= field.type_desc(arch_def) %> |=== Reset value:: <%= field.reset_value(arch_def) %> <%- if field.has_custom_sw_write? -%> -Softare write:: +Software write:: This field has special behavior when written by software (_e.g._, through `csrrw`). + When software tries to write `csr_value`, the field will be written with the return value of the function below. @@ -148,7 +148,7 @@ Original:: + [source,idl,subs="specialchars,macros"] ---- -<%= csr.type_checked_sw_read_ast(arch_def.sym_table).gen_adoc %> +<%= csr.type_checked_sw_read_ast(arch_def.symtab).gen_adoc %> ---- ==== <%- end -%> diff --git a/backends/cfg_html_doc/templates/inst.adoc.erb b/backends/cfg_html_doc/templates/inst.adoc.erb index 6699319742..7159fdced2 100644 --- a/backends/cfg_html_doc/templates/inst.adoc.erb +++ b/backends/cfg_html_doc/templates/inst.adoc.erb @@ -5,20 +5,9 @@ *<%= inst.long_name %>* -This instruction is defined by<%- if inst.defined_by.size > 1 -%> any of the following<%- end -%>: +This instruction is defined by: - <%- inst.defined_by.each do |ext| -%> - * `<%= ext.name %>`, `<%= ext.version_requirement %>` - <%- end -%> - -<%- unless inst.extension_requirements.empty? -%> -Additionally, this instruction is only defined if the following <%- if inst.extension_requirements.size == 1 -%>extension is<%- else -%>extensions are<%- end -%> also present and active: - - <%- inst.extension_requirements.each do |ext| -%> - * `<%= ext.name %>`, `<%= ext.version_requirement %>` - <%- end -%> - -<%- end -%> +<%- inst.defined_by.to_asciidoc -%> == Encoding @@ -119,7 +108,7 @@ Pruned, XLEN == <%= effective_xlen %>:: + [source,idl,subs="specialchars,macros"] ---- -<%= inst.pruned_operation_ast(arch_def.sym_table, effective_xlen).gen_adoc %> +<%= inst.pruned_operation_ast(arch_def.symtab, effective_xlen).gen_adoc %> ---- <%- end -%> @@ -132,7 +121,7 @@ Original:: ==== <%- end -%> -<%- exception_list = inst.reachable_exceptions_str(arch_def.sym_table) -%> +<%- exception_list = inst.reachable_exceptions_str(arch_def.symtab) -%> <%- unless exception_list.empty? -%> == Exceptions diff --git a/backends/csc_crd_doc/tasks.rake b/backends/crd_doc/tasks.rake similarity index 50% rename from backends/csc_crd_doc/tasks.rake rename to backends/crd_doc/tasks.rake index f6f541c064..e2280a44be 100644 --- a/backends/csc_crd_doc/tasks.rake +++ b/backends/crd_doc/tasks.rake @@ -7,39 +7,39 @@ require "asciidoctor-diagram" require_relative "#{$lib}/idl/passes/gen_adoc" -CSC_CRD_DOC_DIR = Pathname.new "#{$root}/backends/csc_crd_doc" +CRD_DOC_DIR = Pathname.new "#{$root}/backends/crd_doc" -Dir.glob("#{$root}/arch/csc_crd/*.yaml") do |f| +Dir.glob("#{$root}/arch/crd/*.yaml") do |f| crd_name = File.basename(f, ".yaml") crd_obj = YAML.load_file(f, permitted_classes: [Date]) - raise "Ill-formed CSC CRD file #{f}: missing 'family' field" if crd_obj.dig(crd_name, 'family').nil? + raise "Ill-formed CRD file #{f}: missing 'family' field" if crd_obj.dig(crd_name, 'family').nil? - file "#{$root}/gen/csc_crd_doc/adoc/#{crd_name}.adoc" => [ - "#{$root}/arch/csc_crd/#{crd_name}.yaml", - "#{$root}/arch/csc_crd_family/#{crd_obj[crd_name]['family']}.yaml", - "#{CSC_CRD_DOC_DIR}/templates/crd.adoc.erb", + file "#{$root}/gen/crd_doc/adoc/#{crd_name}.adoc" => [ + "#{$root}/arch/crd/#{crd_name}.yaml", + "#{$root}/arch/crd_family/#{crd_obj[crd_name]['family']}.yaml", + "#{CRD_DOC_DIR}/templates/crd.adoc.erb", __FILE__, "gen:arch" ] do |t| # TODO: schema validation - arch_def = arch_def_for("_") - crd = arch_def.csc_crd(crd_name) - raise "No CSC CRD defined for #{crd_name}" if crd.nil? + arch_def = arch_def_for("_64") + crd = arch_def.crd(crd_name) + raise "No CRD defined for #{crd_name}" if crd.nil? version = File.basename(t.name, '.adoc').split('-')[1..].join('-') - erb = ERB.new(File.read("#{CSC_CRD_DOC_DIR}/templates/crd.adoc.erb"), trim_mode: "-") - erb.filename = "#{CSC_CRD_DOC_DIR}/templates/crd.adoc.erb" + erb = ERB.new(File.read("#{CRD_DOC_DIR}/templates/crd.adoc.erb"), trim_mode: "-") + erb.filename = "#{CRD_DOC_DIR}/templates/crd.adoc.erb" FileUtils.mkdir_p File.dirname(t.name) File.write t.name, AsciidocUtils.resolve_links(arch_def.find_replace_links(erb.result(binding))) puts "Generated adoc source at #{t.name}" end - file "#{$root}/gen/csc_crd_doc/pdf/#{crd_name}.pdf" => [ - "#{$root}/gen/csc_crd_doc/adoc/#{crd_name}.adoc" + file "#{$root}/gen/crd_doc/pdf/#{crd_name}.pdf" => [ + "#{$root}/gen/crd_doc/adoc/#{crd_name}.adoc" ] do |t| - adoc_file = "#{$root}/gen/csc_crd_doc/adoc/#{crd_name}.adoc" + adoc_file = "#{$root}/gen/crd_doc/adoc/#{crd_name}.adoc" FileUtils.mkdir_p File.dirname(t.name) sh [ "asciidoctor-pdf", @@ -57,10 +57,10 @@ Dir.glob("#{$root}/arch/csc_crd/*.yaml") do |f| ].join(" ") end - file "#{$root}/gen/csc_crd_doc/html/#{crd_name}.html" => [ - "#{$root}/gen/csc_crd_doc/adoc/#{crd_name}.adoc" + file "#{$root}/gen/crd_doc/html/#{crd_name}.html" => [ + "#{$root}/gen/crd_doc/adoc/#{crd_name}.adoc" ] do |t| - adoc_file = "#{$root}/gen/csc_crd_doc/adoc/#{crd_name}.adoc" + adoc_file = "#{$root}/gen/crd_doc/adoc/#{crd_name}.adoc" FileUtils.mkdir_p File.dirname(t.name) sh [ "asciidoctor", @@ -80,36 +80,36 @@ end namespace :gen do desc <<~DESC - Generate CSC CRD documentation for a specific version as a PDF + Generate CRD documentation for a specific version as a PDF Required options: - crd_name - The key of the CSC CRD Family under arch/csc_crd + crd_name - The key of the CRD Family under arch/crd DESC - task :csc_crd_pdf, [:crd_name] do |_t, args| + task :crd_pdf, [:crd_name] do |_t, args| if args[:crd_name].nil? warn "Missing required option: 'crd_family_name'" exit 1 end - unless File.exist?("#{$root}/arch/csc_crd/#{args[:crd_name]}.yaml") - warn "No CRD named '#{args[:crd_name]}' found in arch/csc_crd" + unless File.exist?("#{$root}/arch/crd/#{args[:crd_name]}.yaml") + warn "No CRD named '#{args[:crd_name]}' found in arch/crd" exit 1 end - Rake::Task["#{$root}/gen/csc_crd_doc/pdf/#{args[:crd_name]}.pdf"].invoke + Rake::Task["#{$root}/gen/crd_doc/pdf/#{args[:crd_name]}.pdf"].invoke end - task :csc_crd_html, [:crd_name] do |_t, args| + task :crd_html, [:crd_name] do |_t, args| if args[:crd_name].nil? warn "Missing required option: 'crd_family_name'" exit 1 end - unless File.exist?("#{$root}/arch/csc_crd/#{args[:crd_name]}.yaml") - warn "No CRD named '#{args[:crd_name]}' found in arch/csc_crd" + unless File.exist?("#{$root}/arch/crd/#{args[:crd_name]}.yaml") + warn "No CRD named '#{args[:crd_name]}' found in arch/crd" exit 1 end - Rake::Task["#{$root}/gen/csc_crd_doc/html/#{args[:crd_name]}.html"].invoke + Rake::Task["#{$root}/gen/crd_doc/html/#{args[:crd_name]}.html"].invoke end end \ No newline at end of file diff --git a/backends/csc_crd_doc/templates/crd.adoc.erb b/backends/crd_doc/templates/crd.adoc.erb similarity index 60% rename from backends/csc_crd_doc/templates/crd.adoc.erb rename to backends/crd_doc/templates/crd.adoc.erb index 3cdc5fbc3f..c2fe6cb851 100644 --- a/backends/csc_crd_doc/templates/crd.adoc.erb +++ b/backends/crd_doc/templates/crd.adoc.erb @@ -1,4 +1,3 @@ - // Number heading sections (e.g., 1.0, 1.1, etc.) :sectnums: @@ -74,67 +73,138 @@ a| <%- rev.changes.each do |change| %> |=== -== Extension Requirements +== Extensions + +Any RISC-V extension not listed in this section is OUT-OF-SCOPE so the <%= crd.name %> +certificate doesn't cover its associated behaviors. -=== Summary +<%- ["mandatory","optional"].each do |presence| -%> -The following table lists all extensions that are IN-SCOPE (i.e., MANDATORY or OPTIONAL). -Any extension not listed in the table below is OUT-OF-SCOPE. +=== <%= presence.capitalize %> Extensions +<%- ext_reqs = crd.in_scope_ext_reqs(presence) -%> +<%- if ext_reqs.empty? -%> +None +<%- else -%> [%autowidth] |=== -| Requirement ID | Extension | Version Requirement | Status | Long Name +| Requirement ID | Extension | Version | Long Name | Note -<%- crd.extension_reqs.sort.each do |ext_req| -%> -<%- ext = crd.arch_def.extension(ext_req.name) -%> -| <%= ext_req.req_id %> -| <,<%= ext_req.name %>>> +<%- ext_reqs.sort.each do |ext_req| -%> +<%- ext_db = crd.extension_from_db(ext_req.name) -%> +| <%= ext_req.req_id %> +| <-def,<%= ext_req.name %>>> | <%= ext_req.version_requirement %> -| <%= ext_req.status.upcase %> -| <%= ext.nil? ? "" : ext.long_name %> +| <%= ext_db.nil? ? "" : ext_db.long_name %> +| <%= ext_req.note.nil? ? "" : ext_req.note %> <%- end -%> |=== +<%- end # if table -%> +<%- end # do ext_reqs -%> -<%- crd.extension_reqs.sort.each do |ext_req| -%> -<%- ext = crd.arch_def.extension(ext_req.name) -%> +== Implementation-dependencies -[[anchor-ext-requirement-<%= ext_req.name %>]] -=== Extension <%= ext_req.name %> + -*Requirement ID*: <%= ext_req.req_id %> + -<%= ext.nil? ? "" : "*Long Name*: " + ext.long_name + " +" %> -*Version Requirement*: <%= ext_req.version_requirement %> + -*Status*: <%= ext_req.status.upcase %> + -<%- unless ext_req.note.nil? -%> -[NOTE] --- -<%= ext_req.note %> --- -<%- end -%> +RISC-V standards support many implementation-defined parameters. In many cases, there +are no names associated with these parameters. Names are defined in this section when +not provided in the associated standard. -<%- unless crd.param_constraints(ext_req).empty? -%> -.<%= ext_req.name %> Extension IN-SCOPE Parameters -[cols="3,1,2"] +=== IN-SCOPE Parameters + +These implementation-dependent options defined by MANDATORY or OPTIONAL extensions are IN-SCOPE. +An implementation must abide by the "Allowed Value(s)" to obtain a certificate. +If the "Allowed Value(s)" is "Any" then any value allowed by the type is acceptable. + +<%- if crd.all_in_scope_ext_params.empty? -%> +None +<%- else -%> +[%autowidth] |=== -| Parameter | Constraint | Note -<%- crd.param_constraints(ext_req).sort.each do |constraint| -%> -| <-param-<%= constraint.param_db.name %>,<%= constraint.param_db.name %>>> -| <%= constraint.schema_constraint_pretty %> -a| <%= constraint.note %> -<%- end # do constraint -%> +| Parameter | Type | Allowed Value(s) | Extension(s) | Note + +<%- crd.all_in_scope_ext_params.sort.each do |in_scope_ext_param| -%> +| <%= in_scope_ext_param.name %> +| <%= in_scope_ext_param.param_db.schema_type %> +| <%= in_scope_ext_param.allowed_values %> +| <%- crd.all_in_scope_exts_with_param(in_scope_ext_param.param_db).sort.each do |ext_db| -%><-param-<%= in_scope_ext_param.name %>-def,<%= ext_db.name %>>> <%- end # do ext_db -%> +a| <%= in_scope_ext_param.note %> +<%- end # do -%> |=== -<%- end # unless table -%> +<%- end # if table -%> -<%- unless crd.out_of_scope_params(ext_req.name).empty? -%> -.<%= ext_req.name %> Extension OUT-OF-SCOPE Parameters +=== OUT-OF-SCOPE Parameters + +These implementation-dependent options defined by MANDATORY or OPTIONAL extensions are OUT-OF-SCOPE. +There are no restrictions on their values for certification purposes because the certificate +doesn't cover the behavior of the associated RISC-V standard as a function of these parameters. + +<%- if crd.all_out_of_scope_params.empty? -%> +None +<%- else -%> [%autowidth] |=== -| Parameter -<%- crd.out_of_scope_params(ext_req.name).sort.each do |param_db| -%> -| <-param-<%= param_db.name %>,<%= param_db.name %>>> -<%- end # do constraint -%> +| Parameters | Type | Extension(s) + +<%- crd.all_out_of_scope_params.sort.each do |param_db| -%> +| <%= param_db.name %> +| <%= param_db.schema_type %> +| <%- crd.all_in_scope_exts_without_param(param_db).sort.each do |ext_db| -%><-param-<%= param_db.name %>-def,<%= ext_db.name %>>> <%- end # do ext_db -%> + +<%- end # do -%> +|=== +<%- end # if table -%> + +== Instruction Summary + +<%- + insts = crd.in_scope_extensions.map { |ext_crd| ext_crd.instructions }.flatten.uniq + insts.sort_by!(&:name) +-%> + +[%autowidth] +|=== +| Name | Long Name + +<%- insts.each do |inst| -%> +| <%= link_to_inst(inst.name) %> +| <%= inst.long_name %> +<%- end # do -%> +|=== + +== CSR Summary + +<%- + csrs = crd.in_scope_extensions.map { |ext_crd| ext_crd.csrs }.flatten.uniq +-%> + +=== By Name + +[%autowidth] +|=== +| Name | Long Name | Address | Mode | Primary Extension + +<%- csrs.sort_by!(&:name).each do |csr| -%> +| <-def,<%= csr.name %>>> +| <%= csr.long_name %> +| <%= "0x#{csr.address.to_s(16)}" %> +| <%= csr.priv_mode %> +| <%= csr.primary_defined_by %> +<%- end # do -%> +|=== + +=== By Address + +[%autowidth] +|=== +| Address | Mode | Name | Long Name | Primary Extension + +<%- csrs.sort_by!(&:address).each do |csr| -%> +| <%= "0x#{csr.address.to_s(16)}" %> +| <%= csr.priv_mode %> +| <-def,<%= csr.name %>>> +| <%= csr.long_name %> +| <%= csr.primary_defined_by %> +<%- end # do -%> |=== -<%- end # unless table -%> -<%- end # do extension-%> == Additional Requirements @@ -168,19 +238,24 @@ Requirement <%= req.name %> only apply when <%= req.when_pretty %>. <%- end -%> [appendix] -== Extension Specifications -<%- crd.extension_reqs.sort.each do |ext_req| -%> -<%- ext = crd.arch_def.extension(ext_req.name) -%> +== Extension Details +<%- crd.in_scope_ext_reqs.sort.each do |ext_req| -%> +<%- ext_db = crd.extension_from_db(ext_req.name) -%> +[[ext-<%= ext_req.name %>-def]] === Extension <%= ext_req.name %> + -<%= ext.nil? ? "" : "*Long Name*: " + ext.long_name + " +" %> +<%= ext_db.nil? ? "" : "*Long Name*: " + ext_db.long_name + " +" %> *Version Requirement*: <%= ext_req.version_requirement %> + -<%- ext.versions.each do |v| -%> +<%- ext_db.versions.each do |v| -%> <%= v["version"] %>:: + State::: + <%= v["state"] %> + <%- if v["state"] == "ratified" -%> Ratification date::: <%= v["ratification_date"] %> + <%- end # if %> <%- if v.key?("changes") -%> Changes::: @@ -206,7 +281,7 @@ Requirement <%= req.name %> only apply when <%= req.when_pretty %>. :leveloffset: +3 -<%= ext.description %> +<%= ext_db.description %> :leveloffset: -3 @@ -217,7 +292,8 @@ Requirement <%= req.name %> only apply when <%= req.when_pretty %>. -- <%- end -%> -<%- insts = crd.arch_def.instructions.select { |i| i.definedBy == ext.name || i.definedBy.include?(ext.name) } -%> +// TODO: GitHub issue 92: Use version specified by each profile. +<%- insts = crd.arch_def.instructions.select { |i| i.defined_by?(ext_db.name,ext_db.min_version) } -%> <%- unless insts.empty? -%> ==== Instructions @@ -226,67 +302,57 @@ The following instructions are added by this extension: [cols="1,3"] |=== <%- insts.each do |inst| -%> - | <%= "`#{inst.name}`" %> | *<%= inst.long_name %>* +| <%= link_to_inst(inst.name) %> +| *<%= inst.long_name %>* <%- end -%> |=== <%- end -%> -<%- unless crd.param_constraints(ext_req).empty? -%> +<%- unless crd.in_scope_ext_params(ext_req).empty? -%> ==== IN-SCOPE Parameters -<%- crd.param_constraints(ext_req).sort.each do |constraint| -%> -[[anchor-ext-<%= ext_req.name %>-param-<%= constraint.param_db.name %>]] -<%= constraint.param_db.name %>:: +<%- crd.in_scope_ext_params(ext_req).sort.each do |ext_param| -%> +[[ext-<%= ext_req.name %>-param-<%= ext_param.name %>-def]] +<%= ext_param.name %>:: + -- -<%= constraint.param_db.desc %> +<%= ext_param.param_db.desc %> -- -<%- end # do constraint -%> +<%- end # do ext_param -%> <%- end # unless table -%> <%- unless crd.out_of_scope_params(ext_req.name).empty? -%> ==== OUT-OF-SCOPE Parameters <%- crd.out_of_scope_params(ext_req.name).sort.each do |param_db| -%> -[[anchor-ext-<%= ext_req.name %>-param-<%= param_db.name %>]] +[[ext-<%= ext_req.name %>-param-<%= param_db.name %>-def]] <%= param_db.name %>:: + -- <%= param_db.desc %> -- -<%- end # do constraint -%> +<%- end # do param_db -%> <%- end # unless table -%> <%- end # do ext_req -%> [appendix] -== Instruction Specifications +== Instruction Details <%= - insts = crd.extensions.map { |ext| ext.instructions }.flatten.uniq + insts = crd.in_scope_extensions.map { |ext_crd| ext_crd.instructions }.flatten.uniq insts.sort_by!(&:name) -%> <%- insts.each do |inst| -%> <<< -[[inst-<%=inst.name.gsub('.', '_')%>-def]] +<%= anchor_for_inst(inst.name) %> === <%= inst.name %> *<%= inst.long_name %>* -This instruction is defined by<%- if inst.defined_by.size > 1 -%> any of the following<%- end -%>: +This instruction is defined by: - <%- inst.defined_by.each do |ext| -%> - * `<%= ext.name %>`, `<%= ext.version_requirement %>` - <%- end -%> - -<%- unless inst.extension_requirements.empty? -%> -Additionally, this instruction is only defined if the following <%- if inst.extension_requirements.size == 1 -%>extension is<%- else -%>extensions are<%- end -%> also present and active: - - <%- inst.extension_requirements.each do |ext| -%> - * `<%= ext.name %>`, `<%= ext.version_requirement %>` - <%- end -%> - -<%- end -%> +<%= inst.defined_by.to_asciidoc %> ==== Encoding @@ -294,7 +360,6 @@ Additionally, this instruction is only defined if the following <%- if inst.exte [NOTE] This instruction has different encodings in RV32 and RV64. -[tabs] ==== RV32:: + @@ -322,18 +387,18 @@ RV64:: <%= inst.description %> ==== Access -<%- if crd.extensions.any? { |e| e.name == "H" } -%> +<%- if crd.in_scope_extensions.any? { |e| e.name == "H" } -%> [cols="^,^,^,^,^"] <%- else -%> [cols="^,^,^"] <%- end -%> |=== -| M | <%- if crd.extensions.any? { |e| e.name == "H" } -%>HS<%- else -%>S<%- end -%> | U <%- if crd.extensions.any? { |e| e.name == "H" } -%> | VS | VU <%- end -%> +| M | <%- if crd.in_scope_extensions.any? { |e| e.name == "H" } -%>HS<%- else -%>S<%- end -%> | U <%- if crd.in_scope_extensions.any? { |e| e.name == "H" } -%> | VS | VU <%- end -%> | [.access-always]#Always# | [.access-<%=inst.access['s']%>]#<%= inst.access['s'].capitalize %># | [.access-<%=inst.access['u']%>]#<%= inst.access['u'].capitalize %># -<% if crd.extensions.any? { |e| e.name == "H" } %> +<% if crd.in_scope_extensions.any? { |e| e.name == "H" } %> | [.access-<%=inst.access['vs']%>]#<%= inst.access['vs'].capitalize %># | [.access-<%=inst.access['vu']%>]#<%= inst.access['vu'].capitalize %># <% end %> @@ -346,7 +411,6 @@ RV64:: ==== Decode Variables <%- if inst.multi_encoding? -%> -[tabs] ==== RV32:: + @@ -382,7 +446,7 @@ RV64:: <%- if inst.key?("operation()") -%> [source,idl,subs="specialchars,macros"] ---- -<%= inst.operation_ast(crd.arch_def.idl_compiler).gen_adoc %> +<%= inst.operation_ast(crd.arch_def.symtab).gen_adoc %> ---- <%- end -%> @@ -390,7 +454,7 @@ RV64:: // TODO: add back after sym table update for generic arch def is merged in profiles branch <%# -<%- exception_list = inst.reachable_exceptions_str(crd.arch_def.sym_table) -% > +<%- exception_list = inst.reachable_exceptions_str(crd.arch_def.symtab) -% > <%- if exception_list.empty? -% > This instruction does not generate synchronous exceptions. <%- else -% > @@ -406,10 +470,10 @@ This instruction may result in the following synchronous exceptions: <%- end -%> [appendix] -== CSR Specifications +== CSR Details <%- - csrs = crd.extensions.map { |ext| ext.csrs }.flatten.uniq + csrs = crd.in_scope_extensions.map { |ext_crd| ext_crd.csrs }.flatten.uniq csrs.sort_by!(&:name) -%> @@ -436,7 +500,7 @@ h| CSR Address | <%= "0x#{csr.address.to_s(16)}" %> <%- if csr.priv_mode == 'VS' -%> h| Virtual CSR Address | <%= "0x#{csr.virtual_address.to_s(16)}" %> <%- end -%> -h| Defining extension | <%= csr.defined_by.map(&:to_s).join(", ") %> +h| Defining extension a| <%= csr.defined_by.to_asciidoc %> <%- if csr.dynamic_length?(crd.arch_def) -%> h| Length | <%= csr.length_pretty(crd.arch_def) %> <%- else -%> @@ -472,6 +536,6 @@ This CSR format changes dynamically with XLEN. .... -<%- end -%> +<%- end # unless dynamic length -%> -<%- end -%> \ No newline at end of file +<%- end # do csrs -%> \ No newline at end of file diff --git a/backends/ext_pdf_doc/tasks.rake b/backends/ext_pdf_doc/tasks.rake index e93880a205..b0a4852b11 100644 --- a/backends/ext_pdf_doc/tasks.rake +++ b/backends/ext_pdf_doc/tasks.rake @@ -133,7 +133,7 @@ rule %r{#{$root}/gen/ext_pdf_doc/.*/adoc/.*_extension\.adoc} => proc { |tname| arch_def = if config_name == "_" - arch_def_for(nil) + arch_def_for("_64") else arch_def_for(config_name) end diff --git a/backends/manual/tasks.rake b/backends/manual/tasks.rake index 1e6c0fb0da..8d18cd1b2e 100644 --- a/backends/manual/tasks.rake +++ b/backends/manual/tasks.rake @@ -30,50 +30,63 @@ directory MANUAL_GEN_DIR / "adoc" directory MANUAL_GEN_DIR / "antora" directory MANUAL_GEN_DIR / "html" -["inst", "csr", "ext"].each do |type| - directory MANUAL_GEN_DIR / "antora" / "modules" / "#{type}s" / "pages" - - Dir.glob($root / "arch" / type / "**" / "*.yaml") do |fn| - file MANUAL_GEN_DIR / "adoc" / "#{File.basename(fn, '.yaml')}.adoc" => [ - "gen:arch", - (MANUAL_GEN_DIR / "adoc").to_s, - ($root / "backends" / "manual" / "templates" / "#{type}.adoc.erb").to_s, - __FILE__ - ] do |t| - name = File.basename(t.name, ".adoc") - - arch_def = arch_def_for("_") - erb = case type - when "inst" - inst = arch_def.instruction(name) - raise "Could not find inst '#{name}'" if inst.nil? - - ERB.new(File.read($root / "backends" / "manual" / "templates" / "inst.adoc.erb"), trim_mode: "-") - when "csr" - csr = arch_def.csr(name) - raise "Could not find inst '#{name}'" if csr.nil? - - ERB.new(File.read($root / "backends" / "manual" / "templates" / "csr.adoc.erb"), trim_mode: "-") - when "ext" - ext = arch_def.extension(name) - raise "Could not find ext '#{name}'" if ext.nil? - - ERB.new(File.read($root / "backends" / "manual" / "templates" / "ext.adoc.erb"), trim_mode: "-") - else - raise "Unhandled type '#{type}'" - end - - File.write(t.name, erb.result(binding)) - end - - file MANUAL_GEN_DIR / "antora" / "modules" / "#{type}s" / "pages" => [ - (MANUAL_GEN_DIR / "adoc" / "#{File.basename(fn, '.yaml')}.adoc").to_s, - (MANUAL_GEN_DIR / "antora" / "modules" / "#{type}s" / "pages").to_s - ] do |t| - FileUtils.cp t.prerequisites.first, t.name - end - end -end +# ["inst", "csr", "ext"].each do |type| +# directory MANUAL_GEN_DIR / "antora" / "modules" / "#{type}s" / "pages" + +# Dir.glob($root / "arch" / type / "**" / "*.yaml") do |fn| +# file MANUAL_GEN_DIR / "adoc" / "#{File.basename(fn, '.yaml')}.adoc" => [ +# "gen:arch", +# (MANUAL_GEN_DIR / "adoc").to_s, +# ($root / "backends" / "manual" / "templates" / "#{type}.adoc.erb").to_s, +# __FILE__ +# ] do |t| +# name = File.basename(t.name, ".adoc") + +# arch_def_32 = arch_def_for("_32") +# arch_def_64 = arch_def_for("_64") +# erb = case type +# when "inst" +# inst_32 = arch_def_32.instruction(name) +# raise "Could not find inst '#{name}' in RV32" if inst_32.nil? + +# inst_64 = arch_def_64.instruction(name) +# raise "Could not find inst '#{name}' in RV64" if inst_64.nil? + +# inst = inst_32 || inst_64 + +# ERB.new(File.read($root / "backends" / "manual" / "templates" / "inst.adoc.erb"), trim_mode: "-") +# when "csr" +# csr_32 = arch_def_32.csr(name) +# raise "Could not find csr '#{name}' in RV32" if csr_32.nil? + +# csr_64 = arch_def_64.csr(name) +# raise "Could not find csr '#{name}' in RV32" if csr_64.nil? + +# csr = csr_32 || csr_64 + +# ERB.new(File.read($root / "backends" / "manual" / "templates" / "csr.adoc.erb"), trim_mode: "-") +# when "ext" +# ext = arch_def_64.extension(name) +# raise "Could not find ext '#{name}'" if ext.nil? + +# arch_def = arch_def_64 + +# ERB.new(File.read($root / "backends" / "manual" / "templates" / "ext.adoc.erb"), trim_mode: "-") +# else +# raise "Unhandled type '#{type}'" +# end + +# File.write(t.name, erb.result(binding)) +# end + +# file MANUAL_GEN_DIR / "antora" / "modules" / "#{type}s" / "pages" => [ +# (MANUAL_GEN_DIR / "adoc" / "#{File.basename(fn, '.yaml')}.adoc").to_s, +# (MANUAL_GEN_DIR / "antora" / "modules" / "#{type}s" / "pages").to_s +# ] do |t| +# FileUtils.cp t.prerequisites.first, t.name +# end +# end +# end file MANUAL_GEN_DIR / "antora" / "antora.yml" => (MANUAL_GEN_DIR / "antora").to_s do |t| File.write t.name, <<~ANTORA @@ -88,7 +101,7 @@ end # Rule to create a chapter page in antora hierarchy rule %r{#{MANUAL_GEN_DIR}/.*/.*/antora/modules/chapters/pages/.*\.adoc} do |t| parts = t.name.sub("#{MANUAL_GEN_DIR}/", "").split("/") - manual_version = arch_def_for("_").manual(parts[0]).version(parts[1]) + manual_version = arch_def_for("_64").manual(parts[0]).version(parts[1]) chapter_name = File.basename(t.name, ".adoc") volume = manual_version.volumes.find { |v| !v.chapter(chapter_name).nil? } @@ -119,7 +132,7 @@ rule %r{#{MANUAL_GEN_DIR}/.*/.*/antora/antora.yml} => proc { |tname| ] } do |t| parts = t.name.sub("#{MANUAL_GEN_DIR}/", "").split("/") - manual_version = arch_def_for("_").manual(parts[0])&.version(parts[1]) + manual_version = arch_def_for("_64").manual(parts[0])&.version(parts[1]) raise "Can't find any manual version for '#{parts[0]}' '#{parts[1]}'" if manual_version.nil? @@ -154,7 +167,7 @@ rule %r{#{MANUAL_GEN_DIR}/.*/.*/antora/nav.adoc} => proc { |tname| ] } do |t| parts = t.name.sub("#{MANUAL_GEN_DIR}/", "").split("/") - manual_version = arch_def_for("_").manual(parts[0])&.version(parts[1]) + manual_version = arch_def_for("_64").manual(parts[0])&.version(parts[1]) raise "Can't find any manual version for '#{parts[0]}' '#{parts[1]}'" if manual_version.nil? @@ -193,7 +206,7 @@ rule %r{#{MANUAL_GEN_DIR}/.*/.*/antora/modules/ROOT/pages/index.adoc} => proc { ] } do |t| parts = t.name.sub("#{MANUAL_GEN_DIR}/", "").split("/") - manual_version = arch_def_for("_").manual(parts[0])&.version(parts[1]) + manual_version = arch_def_for("_64").manual(parts[0])&.version(parts[1]) raise "Can't find any manual version for '#{parts[0]}' '#{parts[1]}'" if manual_version.nil? @@ -218,7 +231,7 @@ rule %r{#{MANUAL_GEN_DIR}/.*/.*/antora/modules/insts/pages/.*.adoc} => [ ] do |t| inst_name = File.basename(t.name, ".adoc") - arch_def = arch_def_for("_") + arch_def = arch_def_for("_64") inst = arch_def.instruction(inst_name) raise "Can't find instruction '#{inst_name}'" if inst.nil? @@ -238,7 +251,7 @@ rule %r{#{MANUAL_GEN_DIR}/.*/.*/antora/modules/csrs/pages/.*.adoc} => [ ] do |t| csr_name = File.basename(t.name, ".adoc") - arch_def = arch_def_for("_") + arch_def = arch_def_for("_64") csr = arch_def.csr(csr_name) raise "Can't find csr '#{csr_name}'" if csr.nil? @@ -256,7 +269,7 @@ rule %r{#{MANUAL_GEN_DIR}/.*/.*/antora/modules/funcs/pages/funcs.adoc} => [ "gen:arch", ($root / "backends" / "manual" / "templates" / "func.adoc.erb").to_s ] do |t| - arch_def = arch_def_for("_") + arch_def = arch_def_for("_64") funcs_template_path = $root / "backends" / "manual" / "templates" / "func.adoc.erb" erb = ERB.new(funcs_template_path.read, trim_mode: "-") @@ -272,7 +285,7 @@ rule %r{#{MANUAL_GEN_DIR}/.*/top/.*/antora/landing/antora.yml} => [ parts = t.name.sub("#{MANUAL_GEN_DIR}/", "").split("/") manual_name = parts[0] - arch_def = arch_def_for("_") + arch_def = arch_def_for("_64") manual = arch_def.manual(manual_name) raise "Can't find any manual version for '#{manual_name}'" if manual.nil? @@ -297,7 +310,7 @@ rule %r{#{MANUAL_GEN_DIR}/.*/top/.*/antora/landing/modules/ROOT/pages/index.adoc parts = t.name.sub("#{MANUAL_GEN_DIR}/", "").split("/") manual_name = parts[0] - arch_def = arch_def_for("_") + arch_def = arch_def_for("_64") manual = arch_def.manual(manual_name) raise "Can't find any manual version for '#{manual_name}'" if manual.nil? @@ -325,7 +338,7 @@ rule %r{#{MANUAL_GEN_DIR}/.*/top/.*/antora/playbook/playbook.yml} => proc { |tna parts = t.name.sub("#{MANUAL_GEN_DIR}/", "").split("/") manual_name = parts[0] - arch_def = arch_def_for("_") + arch_def = arch_def_for("_64") manual = arch_def.manual(manual_name) raise "Can't find any manual version for '#{manual_name}'" if manual.nil? @@ -347,9 +360,10 @@ end Dir.glob($root / "arch" / "manual" / "**" / "contents.yaml") do |content_fn| file "#{File.dirname(content_fn)}/riscv-isa-manual/README.md" => ($root / "ext" / "riscv-isa-manual" / "README.md").to_s do |t| content_obj = YAML.load_file(content_fn) + git_dir = `git rev-parse --git-dir`.strip cmd = [ "git", - "--git-dir=#{$root}/.git/modules/ext/riscv-isa-manual", + "--git-dir=#{git_dir}/modules/ext/riscv-isa-manual", "worktree add", File.dirname(t.name), content_obj["isa_manual_tree"], @@ -378,11 +392,11 @@ namespace :gen do A static HTML website will be written into gen/manual/MANUAL_NAME//html DESC desc html_manual_desc - task :html_manual => "gen:arch" do + task :html_manual => "#{$root}/.stamps/arch-gen-_64.stamp" do raise ArgumentError, "Missing required environment variable MANUAL_NAME\n\n#{html_manual_desc}" if ENV["MANUAL_NAME"].nil? raise ArgumentError, "Missing required environment variable VERSIONS\n\n#{html_manual_desc}" if ENV["VERSIONS"].nil? - arch_def = arch_def_for("_") + arch_def = arch_def_for("_64") manual = arch_def.manuals.find { |m| m.name == ENV["MANUAL_NAME"] } raise "No manual '#{ENV['MANUAL_NAME']}'" if manual.nil? @@ -447,7 +461,7 @@ namespace :serve do port = ENV.key?("PORT") ? ENV["PORT"] : 8000 - arch_def = arch_def_for("_") + arch_def = arch_def_for("_64") manual = arch_def.manuals.find { |m| m.name == ENV["MANUAL_NAME"] } raise "No manual '#{ENV['MANUAL_NAME']}'" if manual.nil? diff --git a/backends/manual/templates/csr.adoc.erb b/backends/manual/templates/csr.adoc.erb index 658f65d3da..38fa832479 100644 --- a/backends/manual/templates/csr.adoc.erb +++ b/backends/manual/templates/csr.adoc.erb @@ -10,7 +10,7 @@ == Attributes [%autowidth] |=== -h| Defining Extension | <%= csr.defined_by.map { |er| "`#{er.name}` (version #{er.version_requirement})" }.join(" or ") %> +h| Defining Extension a| <%= csr.defined_by.to_asciidoc %> h| CSR Address | <%= "0x#{csr.address.to_s(16)}" %> <%- if csr.priv_mode == 'VS' -%> h| Virtual CSR Address | <%= "0x#{csr.virtual_address.to_s(16)}" %> @@ -93,7 +93,7 @@ a@ a@ -- -<%= field.type_pretty(arch_def) %> +<%= field.type_pretty(arch_def.symtab) %> -- a@ @@ -127,7 +127,7 @@ Description:: <%= arch_def.render_erb(field.description, "#{csr.name}.#{field.name}.description").gsub("\n", " +\n") %> Type:: -<%= field.type_pretty(arch_def) %> +<%= field.type_pretty(arch_def.symtab) %> Reset value:: <%= field.reset_value_pretty(arch_def) %> @@ -164,7 +164,7 @@ This CSR may return a value that is different from what is stored in hardware. [source,idl,subs="specialchars,macros"] ---- -<%= csr.sw_read_ast(arch_def.idl_compiler).gen_adoc %> +<%= csr.sw_read_ast(arch_def.symtab).gen_adoc %> ---- <%- end -%> diff --git a/backends/manual/templates/instruction.adoc.erb b/backends/manual/templates/instruction.adoc.erb index 51fa72759a..030b1a6005 100644 --- a/backends/manual/templates/instruction.adoc.erb +++ b/backends/manual/templates/instruction.adoc.erb @@ -5,20 +5,9 @@ *<%= inst.long_name %>* -This instruction is defined by<%- if inst.defined_by.size > 1 -%> any of the following<%- end -%>: +This instruction is defined by: - <%- inst.defined_by.each do |ext| -%> - * `<%= ext.name %>` (version `<%= ext.version_requirement %>`) - <%- end -%> - -<%- unless inst.extension_requirements.empty? -%> -Additionally, this instruction is only defined if the following <%- if inst.extension_requirements.size == 1 -%>extension is<%- else -%>extensions are<%- end -%> also present and active: - - <%- inst.extension_requirements.each do |ext| -%> - * `<%= ext.name %>`, `<%= ext.version_requirement %>` - <%- end -%> - -<%- end -%> +<%= inst.defined_by.to_asciidoc %> == Encoding @@ -115,7 +104,7 @@ RV64:: <%- if inst.key?("operation()") -%> [source,idl,subs="specialchars,macros"] ---- -<%= inst.operation_ast(inst.arch_def.idl_compiler).gen_adoc %> +<%= inst.operation_ast(inst.arch_def.symtab).gen_adoc %> ---- <%- end -%> diff --git a/backends/profile_doc/tasks.rake b/backends/profile_doc/tasks.rake index 4b086865cb..b2ad86bca2 100644 --- a/backends/profile_doc/tasks.rake +++ b/backends/profile_doc/tasks.rake @@ -12,14 +12,14 @@ rule %r{#{$root}/gen/profile_doc/adoc/.*\.adoc} => proc { |tname| } do |t| profile_family_name = Pathname.new(t.name).basename(".adoc").to_s - profile_family = arch_def_for("_").profile_family(profile_family_name) + profile_family = arch_def_for("_64").profile_family(profile_family_name) raise ArgumentError, "No profile family named '#{profile_family_name}'" if profile_family.nil? template_path = Pathname.new "#{$root}/backends/profile_doc/templates/profile_pdf.adoc.erb" erb = ERB.new(template_path.read, trim_mode: "-") erb.filename = template_path.to_s - arch_def = arch_def_for("_") + arch_def = arch_def_for("_64") FileUtils.mkdir_p File.dirname(t.name) File.write t.name, AsciidocUtils.resolve_links(arch_def.find_replace_links(erb.result(binding))) @@ -85,7 +85,7 @@ namespace :gen do family_name = args[:profile_family] raise ArgumentError, "Missing required option +profile_family+" if family_name.nil? - family = arch_def_for("_").profile_family(family_name) + family = arch_def_for("_64").profile_family(family_name) raise ArgumentError, "No profile family named '#{family_name}" if family.nil? Rake::Task["#{$root}/gen/profile_doc/pdf/#{family_name}.pdf"].invoke @@ -96,7 +96,7 @@ namespace :gen do family_name = args[:profile_family] raise ArgumentError, "Missing required option +profile_family+" if family_name.nil? - family = arch_def_for("_").profile_family(family_name) + family = arch_def_for("_64").profile_family(family_name) raise ArgumentError, "No profile family named '#{family_name}" if family.nil? Rake::Task["#{$root}/gen/profile_doc/html/#{family_name}.html"].invoke diff --git a/backends/profile_doc/templates/profile_pdf.adoc.erb b/backends/profile_doc/templates/profile_pdf.adoc.erb index 081bd74550..ffe1f31369 100644 --- a/backends/profile_doc/templates/profile_pdf.adoc.erb +++ b/backends/profile_doc/templates/profile_pdf.adoc.erb @@ -341,7 +341,7 @@ The <%= profile_family.marketing_name %> Profile Family references | Extension | <%= profile_family.profiles.map(&:marketing_name).join(" | ") -%> <%- profile_family.referenced_extensions.sort_by(&:name).each do |ext| -%> -| <%= ext.name %> | <%= profile_family.profiles.map { |profile| profile.extension_status(ext.name) }.join(" | ") -%> +| <%= ext.name %> | <%= profile_family.profiles.map { |profile| profile.extension_presence(ext.name) }.join(" | ") -%> <%- end -%> |=== @@ -467,7 +467,8 @@ end.join(" | ") -%> :leveloffset: -3 -<%- insts = arch_def.instructions.select { |i| i.definedBy == ext.name || i.definedBy.include?(ext.name) } -%> +// TODO: GitHub issue 92: Use version specified by each profile and add version info to inst table below. +<%- insts = arch_def.instructions.select { |i| i.defined_by?(ext.name,ext.min_version) } -%> <%- unless insts.empty? -%> ==== Instructions @@ -512,21 +513,9 @@ This extension has the following implementation options: *<%= inst.long_name %>* -This instruction is defined by<%- if inst.defined_by.size > 1 -%> any of the following<%- end -%>: - - <%- inst.defined_by.each do |ext| -%> - * `<%= ext.name %>`, `<%= ext.version_requirement %>` - <%- end -%> - -<%- unless inst.extension_requirements.empty? -%> -Additionally, this instruction is only defined if the following <%- if inst.extension_requirements.size == 1 -%>extension is<%- else -%>extensions are<%- end -%> also present and active: - - <%- inst.extension_requirements.each do |ext| -%> - * `<%= ext.name %>`, `<%= ext.version_requirement %>` - <%- end -%> - -<%- end -%> +This instruction is defined by: +<%= inst.defined_by.to_asciidoc %> ==== Encoding @@ -623,7 +612,7 @@ RV64:: <%- if inst.key?("operation()") -%> [source,idl,subs="specialchars,macros"] ---- -<%= inst.operation_ast(arch_def.idl_compiler).gen_adoc %> +<%= inst.operation_ast(arch_def.symtab).gen_adoc %> ---- <%- end -%> @@ -631,7 +620,7 @@ RV64:: // TODO: add back after sym table update for generic arch def is merged in profiles branch <%# -<%- exception_list = inst.reachable_exceptions_str(arch_def.sym_table) -% > +<%- exception_list = inst.reachable_exceptions_str(arch_def.symtab) -% > <%- if exception_list.empty? -% > This instruction does not generate synchronous exceptions. <%- else -% > @@ -677,7 +666,7 @@ h| CSR Address | <%= "0x#{csr.address.to_s(16)}" %> <%- if csr.priv_mode == 'VS' -%> h| Virtual CSR Address | <%= "0x#{csr.virtual_address.to_s(16)}" %> <%- end -%> -h| Defining extension | <%= csr.defined_by.map(&:to_s).join(", ") %> +h| Defining extension a| <%= csr.defined_by.to_asciidoc %> <%- if csr.dynamic_length?(arch_def) -%> h| Length | <%= csr.length_pretty(arch_def) %> <%- else -%> diff --git a/bin/setup b/bin/setup index 4b63fe45a1..49d7ce1852 100755 --- a/bin/setup +++ b/bin/setup @@ -19,6 +19,12 @@ else SINGULARITY_CACHE= fi +if [ -f $ROOT/.git ]; then + # if this is a worktree, need to add the parent git repo in, too + GIT_PATH=`git rev-parse --git-common-dir | tr -d '\n' | xargs dirname` + HOME_OPT="${HOME_OPT} --bind ${GIT_PATH}:${GIT_PATH}" +fi + if [ ! -d $ROOT/.home ]; then mkdir $ROOT/.home fi diff --git a/cfgs/_32/cfg.yaml b/cfgs/_32/cfg.yaml new file mode 100644 index 0000000000..ca0f2d33df --- /dev/null +++ b/cfgs/_32/cfg.yaml @@ -0,0 +1,2 @@ +--- +type: partially configured diff --git a/cfgs/_32/implemented_exts.yaml b/cfgs/_32/implemented_exts.yaml new file mode 100644 index 0000000000..11151c2451 --- /dev/null +++ b/cfgs/_32/implemented_exts.yaml @@ -0,0 +1 @@ +implemented_extensions: [] \ No newline at end of file diff --git a/cfgs/_32/params.yaml b/cfgs/_32/params.yaml new file mode 100644 index 0000000000..b4f8fb3d48 --- /dev/null +++ b/cfgs/_32/params.yaml @@ -0,0 +1,5 @@ +--- +params: + NAME: _32 + + XLEN: 32 diff --git a/cfgs/_64/cfg.yaml b/cfgs/_64/cfg.yaml new file mode 100644 index 0000000000..ca0f2d33df --- /dev/null +++ b/cfgs/_64/cfg.yaml @@ -0,0 +1,2 @@ +--- +type: partially configured diff --git a/cfgs/_64/implemented_exts.yaml b/cfgs/_64/implemented_exts.yaml new file mode 100644 index 0000000000..11151c2451 --- /dev/null +++ b/cfgs/_64/implemented_exts.yaml @@ -0,0 +1 @@ +implemented_extensions: [] \ No newline at end of file diff --git a/cfgs/_64/params.yaml b/cfgs/_64/params.yaml new file mode 100644 index 0000000000..b4ff65b89f --- /dev/null +++ b/cfgs/_64/params.yaml @@ -0,0 +1,4 @@ +params: + NAME: _64 + + XLEN: 64 diff --git a/cfgs/generic_rv64/cfg.yaml b/cfgs/generic_rv64/cfg.yaml new file mode 100644 index 0000000000..c9fde92191 --- /dev/null +++ b/cfgs/generic_rv64/cfg.yaml @@ -0,0 +1,2 @@ +--- +type: fully configured diff --git a/cfgs/generic_rv64/implemented_exts.yaml b/cfgs/generic_rv64/implemented_exts.yaml index 108cbbc6de..3719f36e96 100644 --- a/cfgs/generic_rv64/implemented_exts.yaml +++ b/cfgs/generic_rv64/implemented_exts.yaml @@ -11,6 +11,8 @@ implemented_extensions: - [M, "2.0.0"] - [S, "1.12.0"] - [Sm, "1.12.0"] + - [Smhpm, "1.12.0"] + - [Smpmp, "1.12.0"] - [U, "1.12.0"] - [Zicntr, "2.0.0"] - [Zicsr, "2.0.0"] diff --git a/cfgs/generic_rv64/params.yaml b/cfgs/generic_rv64/params.yaml index 9ae25389d6..68a209e306 100644 --- a/cfgs/generic_rv64/params.yaml +++ b/cfgs/generic_rv64/params.yaml @@ -505,4 +505,6 @@ params: TINST_VALUE_ON_LOAD_PAGE_FAULT: "always zero" TINST_VALUE_ON_STORE_AMO_PAGE_FAULT: "always zero" MTVEC_MODES: [0, 1] - + MSTATUS_FS_LEGAL_VALUES: [0,1,2,3] + MSTATUS_FS_WRITEABLE: true + MSTATUS_TVM_IMPLEMENTED: true diff --git a/lib/arch_def.rb b/lib/arch_def.rb index 3fb12b7bf5..2346e3fc90 100644 --- a/lib/arch_def.rb +++ b/lib/arch_def.rb @@ -17,71 +17,315 @@ require_relative "arch_obj_models/csr" require_relative "arch_obj_models/instruction" require_relative "arch_obj_models/extension" -require_relative "arch_obj_models/csc_crd" +require_relative "arch_obj_models/crd" +require_relative "template_helpers" + +include TemplateHelpers class ArchDef # @return [Idl::Compiler] The IDL compiler attr_reader :idl_compiler - # @return [Idl::AstNode] Abstract syntax tree of global scope + # @return [Idl::IsaAst] Abstract syntax tree of global scope attr_reader :global_ast - def name = "_" + # @return [String] Name of this definition. Special names are: + # * '_' - The generic architecture, with no configuration settings. + # * '_32' - A generic RV32 architecture, with only one parameter set (XLEN == 32) + # * '_64' - A generic RV64 architecture, with only one parameter set (XLEN == 64) + attr_reader :name + + # @return [Hash] A hash mapping parameter name to value for any parameter that has been configured with a value. May be empty. + attr_reader :param_values + + # @return [Integer] 32 or 64, the XLEN in M-mode + # @return [nil] if the XLEN in M-mode is not configured + attr_reader :mxlen + + # hash for Hash lookup + def hash = @name_sym.hash + + # @return [Idl::SymbolTable] Symbol table with global scope + # @return [nil] if the architecture is not configured (use symtab_32 or symtab_64) + def symtab + raise NotImplementedError, "Un-configured ArchDefs have no symbol table" if @symtab.nil? + + @symtab + end + + def fully_configured? = @arch_def["type"] == "fully configured" + def partially_configured? = @arch_def["type"] == "partially configured" + def unconfigured? = @arch_def["type"] == "unconfigured" + def configured? = @arch_def["type"] != "unconfigured" + def type = @arch_def["type"] - # Initialize a new configured architecture defintiion + # Initialize a new configured architecture definition # # @param config_name [#to_s] The name of a configuration, which must correspond # to a folder under $root/cfgs - def initialize(from_child: false) + def initialize(config_name, arch_def_path, overlay_path: nil) + @name = config_name.to_s.freeze + @name_sym = @name.to_sym.freeze + @idl_compiler = Idl::Compiler.new(self) - unless from_child - arch_def_file = $root / "gen" / "_" / "arch" / "arch_def.yaml" + validator = Validator.instance + begin + validator.validate_str(arch_def_path.read, type: :arch) + rescue Validator::SchemaValidationError => e + warn "While parsing unified architecture definition at #{arch_def_path}" + raise e + end - @arch_def = YAML.load_file(arch_def_file, permitted_classes: [Date]) + @arch_def = YAML.load_file(arch_def_path, permitted_classes: [Date]).freeze + @param_values = (@arch_def.key?("params") ? @arch_def["params"] : {}).freeze + @mxlen = @arch_def.dig("params", "XLEN") # might be nil + unless @mxlen.nil? + # need at least XLEN specified to have a full architecture definition + # to populate the symbol table. + # + # if this is the fully generic config ("_"), then you need to use + # either symtab_32 or symtab_64 + @symtab = Idl::SymbolTable.new(self) + custom_globals_path = overlay_path.nil? ? Pathname.new("/does/not/exist") : overlay_path / "isa" / "globals.isa" + idl_path = File.exist?(custom_globals_path) ? custom_globals_path : $root / "arch" / "isa" / "globals.isa" + @global_ast = @idl_compiler.compile_file( + idl_path + ) + @global_ast.add_global_symbols(@symtab) + @symtab.deep_freeze + @global_ast.freeze_tree(@symtab) + @mxlen.freeze + else # parse globals @global_ast = @idl_compiler.compile_file( - $root / "arch" / "isa" / "globals.isa", - symtab: sym_table_32 + $root / "arch" / "isa" / "globals.isa" ) - sym_table_32.deep_freeze + @global_ast.add_global_symbols(symtab_32) + symtab_32.deep_freeze + @global_ast.freeze_tree(symtab_32) # do it again for rv64, but we don't need the ast this time - @idl_compiler.compile_file( - $root / "arch" / "isa" / "globals.isa", - symtab: sym_table_64 + global_ast_64 = @idl_compiler.compile_file( + $root / "arch" / "isa" / "globals.isa" ) - sym_table_64.deep_freeze + global_ast_64.add_global_symbols(symtab_64) + symtab_64.deep_freeze + global_ast_64.freeze_tree(symtab_64) + end + end + + # type check all IDL, including globals, instruction ops, and CSR functions + # + # @param show_progress [Boolean] whether to show progress bars + # @param io [IO] where to write progress bars + # @return [void] + def type_check(show_progress: true, io: $stdout) + io.puts "Type checking IDL code for #{name}..." + progressbar = + if show_progress + ProgressBar.create(title: "Instructions", total: instructions.size) + end + + instructions.each do |inst| + progressbar.increment if show_progress + if @mxlen == 32 + inst.type_checked_operation_ast(@idl_compiler, @symtab, 32) if inst.rv32? + elsif @mxlen == 64 + inst.type_checked_operation_ast(@idl_compiler, @symtab, 64) if inst.rv64? + inst.type_checked_operation_ast(@idl_compiler, @symtab, 32) if possible_xlens.include?(32) && inst.rv32? + end + end + + progressbar = + if show_progress + ProgressBar.create(title: "CSRs", total: csrs.size) + end + + csrs.each do |csr| + progressbar.increment if show_progress + if csr.has_custom_sw_read? + if (possible_xlens.include?(32) && csr.defined_in_base32?) || (possible_xlens.include?(64) && csr.defined_in_base64?) + csr.type_checked_sw_read_ast(@symtab) + end + end + csr.fields.each do |field| + unless field.type_ast(@symtab).nil? + if ((possible_xlens.include?(32) && csr.defined_in_base32? && field.defined_in_base32?) || + (possible_xlens.include?(64) && csr.defined_in_base64? && field.defined_in_base64?)) + field.type_checked_type_ast(@symtab) + end + end + unless field.reset_value_ast(@symtab).nil? + if ((possible_xlens.include?(32) && csr.defined_in_base32? && field.defined_in_base32?) || + (possible_xlens.include?(64) && csr.defined_in_base64? && field.defined_in_base64?)) + field.type_checked_reset_value_ast(@symtab) if csr.defined_in_base32? && field.defined_in_base32? + end + end + unless field.sw_write_ast(@symtab).nil? + field.type_checked_sw_write_ast(@symtab, 32) if possible_xlens.include?(32) && csr.defined_in_base32? && field.defined_in_base32? + field.type_checked_sw_write_ast(@symtab, 64) if possible_xlens.include?(64) && csr.defined_in_base64? && field.defined_in_base64? + end + end + end + progressbar = + if show_progress + ProgressBar.create(title: "Functions", total: functions.size) + end + functions.each do |func| + progressbar.increment if show_progress + func.type_check(@symtab) end + + puts "done" if show_progress end - # Get a symbol table with globals defined for a generic (config-independent) RV32 architecture defintion - # Being config-independent, parameters in this symbol table will not have values assigned + # Returns whether or not it may be possible to switch XLEN given this definition. + # + # There are three cases when this will return true: + # 1. A mode (e.g., U) is known to be implemented, and the CSR bit that controls XLEN in that mode is known to be writeable. + # 2. A mode is known to be implemented, but the writability of the CSR bit that controls XLEN in that mode is not known. + # 3. It is not known if the mode is implemented. # - # @return [Idl::SymbolTable] Symbol table with config-independent global symbols populated for RV32 - def sym_table_32 - return @sym_table_32 unless @sym_table_32.nil? + # + # @return [Boolean] true if this configuration might execute in multiple xlen environments + # (e.g., that in some mode the effective xlen can be either 32 or 64, depending on CSR values) + def multi_xlen? + return true if @mxlen.nil? - @sym_table_32 = Idl::SymbolTable.new(self, 32) + ["S", "U", "VS", "VU"].any? { |mode| multi_xlen_in_mode?(mode) } end - # Get a symbol table with globals defined for a generic (config-independent) RV64 architecture defintion - # Being config-independent, parameters in this symbol table will not have values assigned + # Returns whether or not it may be possible to switch XLEN in +mode+ given this definition. + # + # There are three cases when this will return true: + # 1. +mode+ (e.g., U) is known to be implemented, and the CSR bit that controls XLEN in +mode+ is known to be writeable. + # 2. +mode+ is known to be implemented, but the writability of the CSR bit that controls XLEN in +mode+ is not known. + # 3. It is not known if +mode+ is implemented. + # + # Will return false if +mode+ is not possible (e.g., because U is a prohibited extension) # - # @return [Idl::SymbolTable] Symbol table with config-independent global symbols populated for RV64 - def sym_table_64 - return @sym_table_64 unless @sym_table_64.nil? + # @param mode [String] mode to check. One of "M", "S", "U", "VS", "VU" + # @return [Boolean] true if this configuration might execute in multiple xlen environments in +mode+ + # (e.g., that in some mode the effective xlen can be either 32 or 64, depending on CSR values) + def multi_xlen_in_mode?(mode) + return false if mxlen == 32 + + case mode + when "M" + mxlen.nil? + when "S" + return true if unconfigured? + + if fully_configured? + ext?(:S) && (@param_values["SXLEN"] == 3264) + elsif partially_configured? + return false if prohibited_ext?(:S) + + return true unless ext?(:S) # if S is not known to be implemented, we can't say anything about it + + return true unless @param_values.key?("SXLEN") + + @param_values["SXLEN"] == 3264 + else + raise "Unexpected configuration state" + end + when "U" + return false if prohibited_ext?(:U) - @sym_table_64 = Idl::SymbolTable.new(self, 64) + return true if unconfigured? + + if fully_configured? + ext?(:U) && (@param_values["UXLEN"] == 3264) + elsif partially_configured? + return true unless ext?(:U) # if U is not known to be implemented, we can't say anything about it + + return true unless @param_values.key?("UXLEN") + + @param_values["UXLEN"] == 3264 + else + raise "Unexpected configuration state" + end + when "VS" + return false if prohibited_ext?(:H) + + return true if unconfigured? + + if fully_configured? + ext?(:H) && (@param_values["VSXLEN"] == 3264) + elsif partially_configured? + return true unless ext?(:H) # if H is not known to be implemented, we can't say anything about it + + return true unless @param_values.key?("VSXLEN") + + @param_values["VSXLEN"] == 3264 + else + raise "Unexpected configuration state" + end + when "VU" + return false if prohibited_ext?(:H) + + return true if unconfigured? + + if fully_configured? + ext?(:H) && (@param_values["VUXLEN"] == 3264) + elsif partially_configured? + return true unless ext?(:H) # if H is not known to be implemented, we can't say anything about it + + return true unless @param_values.key?("VUXLEN") + + @param_values["VUXLEN"] == 3264 + else + raise "Unexpected configuration state" + end + else + raise ArgumentError, "Bad mode" + end + end + + # @return [Array] List of possible XLENs in any mode for this config + def possible_xlens = multi_xlen? ? [32, 64] : [mxlen] + + # @return [Array] List of all available parameters with known values for the config + def params_with_value + return @params_with_value unless @params_with_value.nil? + + @params_with_value = [] + extensions.each do |ext_version| + ext = extension(ext_version.name) + ext.params.each do |ext_param| + if param_values.key?(ext_param.name) + @params_with_value << ExtensionParameterWithValue.new( + ext_param, + param_values[ext_param.name] + ) + end + end + end + @params_with_value end - def possible_xlens = [32, 64] + # @return [Array] List of all available parameters without known values for the config + def params_without_value + return @params_without_value unless @params_without_value.nil? + + @params_without_value = [] + extensions.each do |ext_version| + ext = extension(ext_version.name) + ext.params.each do |ext_param| + unless param_values.key?(ext_param.name) + @params_without_value << ext_param + end + end + end + @params_without_value + end # Returns a string representation of the object, suitable for debugging. # @return [String] A string representation of the object. - def inspect = "ArchDef" + def inspect = "ArchDef##{name}" # @return [Array] List of all extensions, even those that are't implemented def extensions @@ -94,6 +338,41 @@ def extensions @extensions end + # may be overridden by subclass + # @return [Array] List of all extensions known to be implemented in this architecture + def implemented_extensions + return @implemented_extensions unless @implemented_extensions.nil? + + @implemented_extensions = [] + if @arch_def.key?("implemented_extensions") + @arch_def["implemented_extensions"].each do |e| + @implemented_extensions << ExtensionVersion.new(e["name"], e["version"]) + end + end + @implemented_extensions + end + + # @return [Array] List of extensions that are explicitly prohibited by an arch def + def prohibited_extensions + return @prohibited_extensions unless @prohibited_extensions.nil? + + @prohibited_extensions = [] + if @arch_def.key?("prohibited_extensions") + @arch_def["prohibited_extensions"].each do |e| + if e.is_a?(String) + @prohibited_extensions << ExtensionRequirement.new(e, nil) + else + @prohibited_extensions << ExtensionRequirement.new(e["name"], e["requirements"], presence: "prohibited") + end + end + end + @prohibited_extensions + end + + def prohibited_ext?(ext_name) + prohibited_extensions.any? { |ext_req| ext_req.name == ext_name.to_s } + end + # @return [Hash] Hash of all extensions, even those that aren't implemented, indexed by extension name def extension_hash return @extension_hash unless @extension_hash.nil? @@ -112,6 +391,47 @@ def extension(name) extension_hash[name.to_s] end + # @overload ext?(ext_name) + # @param ext_name [#to_s] Extension name (case sensitive) + # @return [Boolean] True if the extension `name` is implemented + # @overload ext?(ext_name, ext_version_requirements) + # @param ext_name [#to_s] Extension name (case sensitive) + # @param ext_version_requirements [Number,String,Array] Extension version requirements, taking the same inputs as Gem::Requirement + # @see https://docs.ruby-lang.org/en/3.0/Gem/Requirement.html#method-c-new Gem::Requirement#new + # @return [Boolean] True if the extension `name` meeting `ext_version_requirements` is implemented + # @example Checking extension presence with a version requirement + # arch_def.ext?(:S, ">= 1.12") + # @example Checking extension presence with multiple version requirements + # arch_def.ext?(:S, ">= 1.12", "< 1.15") + # @example Checking extension precsence with a precise version requirement + # arch_def.ext?(:S, 1.12) + def ext?(ext_name, *ext_version_requirements) + @ext_cache ||= {} + cached_result = @ext_cache[[ext_name, ext_version_requirements]] + return cached_result unless cached_result.nil? + + result = + implemented_extensions.any? do |e| + if ext_version_requirements.empty? + e.name == ext_name.to_s + else + requirement = Gem::Requirement.new(ext_version_requirements) + (e.name == ext_name.to_s) && requirement.satisfied_by?(e.version) + end + end + @ext_cache[[ext_name, ext_version_requirements]] = result + end + + # @return [Array] Array of all extensions that are prohibited because they are excluded by an implemented extension + def conflicting_extensions + extensions.map(&:conflicts).flatten + end + + # @return [Boolean] whether or not ext_name is prohibited because it is excluded by an implemented extension + def conflicting_ext?(ext_name) + prohibited_extensions.include? { |ext_req| ext_req.name == ext_name } + end + # @return [Array] List of all parameters defined in the architecture def params return @params unless @params.nil? @@ -304,51 +624,51 @@ def profiles_hash # @return [nil] if the profile does not exist def profile(name) = profiles_hash[name] - def csc_crd_families - return @csc_crd_families unless @csc_crd_families.nil? + def crd_families + return @crd_families unless @crd_families.nil? - @csc_crd_families = [] - @arch_def["csc_crd_families"].each_value do |family_data| - @csc_crd_families << CscCrdFamily.new(family_data, self) + @crd_families = [] + @arch_def["crd_families"].each_value do |family_data| + @crd_families << CrdFamily.new(family_data, self) end - @csc_crd_families + @crd_families end - def csc_crd_famlies_hash - return @csc_crd_families_hash unless @csc_crd_families_hash.nil? + def crd_famlies_hash + return @crd_families_hash unless @crd_families_hash.nil? - @csc_crd_families_hash = {} - csc_crd_families.each do |family| - @csc_crd_families_hash[family.name] = family + @crd_families_hash = {} + crd_families.each do |family| + @crd_families_hash[family.name] = family end - @csc_crd_families_hash + @crd_families_hash end - def csc_crd_family(name) = csc_crd_famlies_hash[name] + def crd_family(name) = crd_famlies_hash[name] - def csc_crds - return @csc_crds unless @csc_crds.nil? + def crds + return @crds unless @crds.nil? - @csc_crds = [] - @arch_def["csc_crds"].each_value do |csc_crd_data| - @csc_crds << CscCrd.new(csc_crd_data, self) + @crds = [] + @arch_def["crds"].each_value do |crd_data| + @crds << Crd.new(crd_data, self) end - @csc_crds + @crds end - def csc_crds_hash - return @csc_crds_hash unless @csc_crds_hash.nil? + def crds_hash + return @crds_hash unless @crds_hash.nil? - @csc_crds_hash = {} - csc_crds.each do |csc_crd| - @csc_crds_hash[csc_crd.name] = csc_crd + @crds_hash = {} + crds.each do |crd| + @crds_hash[crd.name] = crd end - @csc_crds_hash + @crds_hash end - def csc_crd(name) = csc_crds_hash[name] + def crd(name) = crds_hash[name] - # @return [Array] All exception codes defined by extensions + # @return [Array] All exception codes defined by RISC-V def exception_codes return @exception_codes unless @exception_codes.nil? @@ -367,6 +687,29 @@ def exception_codes end end + # @return [Array] All exception codes known to be implemented + def implemented_exception_codes + return @implemented_exception_codes unless @implemented_exception_codes.nil? + + @implemented_exception_codes = + implemented_extensions.reduce([]) do |list, ext_version| + ecodes = extension(ext_version.name)["exception_codes"] + next list if ecodes.nil? + + ecodes.each do |ecode| + # double check that all the codes are unique + raise "Duplicate exception code" if list.any? { |e| e.num == ecode["num"] || e.name == ecode["name"] || e.var == ecode["var"] } + + unless ecode.dig("when", "version").nil? + # check version + next unless ext?(ext_version.name.to_sym, ecode["when"]["version"]) + end + list << ExceptionCode.new(ecode["name"], ecode["var"], ecode["num"], self) + end + list + end + end + # @return [Array] All interrupt codes defined by extensions def interrupt_codes return @interrupt_codes unless @interrupt_codes.nil? @@ -388,165 +731,137 @@ def interrupt_codes end end - # given an adoc string, find names of CSR/Instruction/Extension enclosed in `monospace` - # and replace them with links to the relevant object page - # - # @param adoc [String] Asciidoc source - # @return [String] Asciidoc source, with link placeholders - def find_replace_links(adoc) - adoc.gsub(/`([\w.]+)`/) do |match| - name = Regexp.last_match(1) - csr_name, field_name = name.split(".") - csr = csr(csr_name) - if !field_name.nil? && !csr.nil? && csr.field?(field_name) - "%%LINK%csr_field;#{csr_name}.#{field_name};#{csr_name}.#{field_name}%%" - elsif !csr.nil? - "%%LINK%csr;#{csr_name};#{csr_name}%%" - elsif inst(name) - "%%LINK%inst;#{name};#{name}%%" - elsif extension(name) - "%%LINK%ext;#{name};#{name}%%" - else - match - end - end - end + # @return [Array] All interrupt codes known to be implemented + def implemented_interrupt_codes + return @implemented_interrupt_codes unless @implemented_interrupt_codes.nil? - # Returns an environment hash suitable for use with ERb templates. - # - # This method returns a hash containing the architecture definition and other - # relevant data that can be used to generate ERb templates. - # - # @return [Hash] An environment hash suitable for use with ERb templates. - def erb_env - return @env unless @env.nil? + @implemented_interupt_codes = + implemented_extensions.reduce([]) do |list, ext_version| + icodes = extension(ext_version.name)["interrupt_codes"] + next list if icodes.nil? - @env = Class.new - @env.instance_variable_set(:@cfg, @cfg) - @env.instance_variable_set(:@params, @params) - @env.instance_variable_set(:@arch_gen, self) + icodes.each do |icode| + # double check that all the codes are unique + raise "Duplicate interrupt code" if list.any? { |i| i.num == icode["num"] || i.name == icode["name"] || i.var == icode["var"] } - @env.instance_exec do - # method to check if a given extension (with an optional version number) is present - # - # @param ext_name [String,#to_s] Name of the extension - # @param ext_requirement [String, #to_s] Version string, as a Gem Requirement (https://guides.rubygems.org/patterns/#pessimistic-version-constraint) - # @return [Boolean] whether or not extension +ext_name+ meeting +ext_requirement+ is implemented in the config - def ext?(ext_name, ext_requirement = ">= 0") - true # ? + unless ecode.dig("when", "version").nil? + # check version + next unless ext?(ext_version.name.to_sym, ecode["when"]["version"]) + end + list << InterruptCode.new(icode["name"], icode["var"], icode["num"], self) + end + list end + end - # @return [Array] List of possible XLENs for any implemented mode - def possible_xlens - [32, 64] - end + # @return [Hash] The raw architecture defintion data structure + def data + @arch_def + end - # insert a hyperlink to an object - # At this point, we insert a placeholder since it will be up - # to the backend to create a specific link - # - # @params type [Symbol] Type (:section, :csr, :inst, :ext) - # @params name [#to_s] Name of the object - def link_to(type, name) - "%%LINK%#{type};#{name}%%" + # @return [Array] List of all implemented CSRs + def implemented_csrs + return @implemented_csrs unless @implemented_csrs.nil? + + @implemented_csrs = + if @arch_def.key?("implemented_csrs") + csrs.select { |c| @arch_def["implemented_csrs"].include?(c.name) } + else + [] end + end - # info on interrupt and exception codes - - # @returns [Hash] architecturally-defined exception codes and their names - def exception_codes - @arch_gen.exception_codes - end + # @return [Hash] Implemented csrs, indexed by CSR name + def implemented_csr_hash + return @implemented_csr_hash unless @implemented_csr_hash.nil? - # returns [Hash] architecturally-defined interrupt codes and their names - def interrupt_codes - @arch_gen.interrupt_codes - end + @implemented_csr_hash = {} + implemented_csrs.each do |csr| + @implemented_csr_hash[csr.name] = csr end - - @env + @implemented_csr_hash end - private :erb_env - # passes _erb_template_ through ERB within the content of this config - # - # @param erb_template [String] ERB source - # @return [String] The rendered text - def render_erb(erb_template, what='') - t = Tempfile.new("template") - t.write erb_template - t.flush - begin - Tilt["erb"].new(t.path, trim: "-").render(erb_env) - rescue - warn "While rendering ERB template: #{what}" - raise - ensure - t.close - t.unlink - end + # @param csr_name [#to_s] CSR name + # @return [Csr,nil] a specific csr, or nil if it doesn't exist or isn't implemented + def implemented_csr(csr_name) + implemented_csr_hash[csr_name] end -end - -# a synchroncous exception code -class ExceptionCode - # @return [String] Long-form display name (can include special characters) - attr_reader :name - # @return [String] Field name for an IDL enum - attr_reader :var - - # @return [Integer] Code, written into *mcause - attr_reader :num - - # @return [Extension] Extension that defines this code - attr_reader :ext + # @return [Array] List of all implemented instructions + def implemented_instructions + return @implemented_instructions unless @implemented_instructions.nil? - def initialize(name, var, number, ext) - @name = name - @var = var - @num = number - @ext = ext + @implemented_instructions = + if @arch_def.key?("implemented_instructions") + @arch_def["implemented_instructions"].map do |inst_name| + instruction_hash[inst_name] + end + else + [] + end end -end -# all the same informatin as ExceptinCode, but for interrupts -InterruptCode = Class.new(ExceptionCode) -# Object model for a configured architecture definition -class ImplArchDef < ArchDef - # @return [String] Name of the architecture configuration - attr_reader :name + # @return [Array] List of all reachable IDL functions for the config + def implemented_functions + return @implemented_functions unless @implemented_functions.nil? - # @return [SymbolTable] The symbol table containing global definitions - attr_reader :sym_table + @implemented_functions = [] - # @return [Hash] The configuration parameter name => value - attr_reader :param_values + puts " Finding all reachable functions from instruction operations" - # @return [Integer] 32 or 64, the XLEN in m-mode - attr_reader :mxlen + implemented_instructions.each do |inst| + @implemented_functions << + if inst.base.nil? + if multi_xlen? + (inst.reachable_functions(symtab, 32) + + inst.reachable_functions(symtab, 64)) + else + inst.reachable_functions(symtab, mxlen) + end + else + inst.reachable_functions(symtab, inst.base) + end + end + raise "?" unless @implemented_functions.is_a?(Array) + @implemented_functions = @implemented_functions.flatten + @implemented_functions.uniq!(&:name) - # hash for Hash lookup - def hash = @name.hash + puts " Finding all reachable functions from CSR operations" - # @return [Array] List of all available parameters for the config - def params_with_value - return @params_with_value unless @params_with_value.nil? + implemented_csrs.each do |csr| + csr_funcs = csr.reachable_functions(self) + csr_funcs.each do |f| + @implemented_functions << f unless @implemented_functions.any? { |i| i.name == f.name } + end + end - @params_with_value = [] - implemented_extensions.each do |ext_version| - ext = extension(ext_version.name) - ext.params.each do |ext_param| - if param_values.key?(ext_param.name) - @params_with_value << ExtensionParameterWithValue.new( - ext_param, - param_values[ext_param.name] - ) - end + @implemented_functions + end + + # given an adoc string, find names of CSR/Instruction/Extension enclosed in `monospace` + # and replace them with links to the relevant object page + # + # @param adoc [String] Asciidoc source + # @return [String] Asciidoc source, with link placeholders + def find_replace_links(adoc) + adoc.gsub(/`([\w.]+)`/) do |match| + name = Regexp.last_match(1) + csr_name, field_name = name.split(".") + csr = csr(csr_name) + if !field_name.nil? && !csr.nil? && csr.field?(field_name) + "%%LINK%csr_field;#{csr_name}.#{field_name};#{csr_name}.#{field_name}%%" + elsif !csr.nil? + "%%LINK%csr;#{csr_name};#{csr_name}%%" + elsif inst(name) + "%%LINK%inst;#{name};#{name}%%" + elsif extension(name) + "%%LINK%ext;#{name};#{name}%%" + else + match end end - @params_with_value end # Returns an environment hash suitable for use with ERb templates. @@ -568,6 +883,10 @@ def erb_env @env.const_set(param.name, param.value) unless @env.const_defined?(param.name) end + params_without_value.each do |param| + @env.const_set(param.name, :unknown) unless @env.const_defined?(param.name) + end + @env.instance_exec do # method to check if a given extension (with an optional version number) is present # @@ -604,236 +923,64 @@ def exception_codes def interrupt_codes @arch_gen.interrupt_codes end - end - - @env - end - private :erb_env - - # Initialize a new configured architecture defintiion - # - # @param config_name [#to_s] The name of a configuration, which must correspond - # to a folder under $root/cfgs - def initialize(config_name) - super(from_child: true) - - @name = config_name.to_s - arch_def_file = $root / "gen" / @name / "arch" / "arch_def.yaml" - - validator = Validator.instance - begin - validator.validate_str(arch_def_file.read, type: :arch) - rescue Validator::SchemaValidationError => e - warn "While parsing unified architecture definition at #{arch_def_file}" - raise e - end - - @arch_def = YAML.load_file(arch_def_file) - - @param_values = @arch_def["params"] - @mxlen = @arch_def["params"]["XLEN"] - - @sym_table = Idl::SymbolTable.new(self) - # load the globals into the symbol table - custom_globals_path = $root / "cfgs" / @name / "arch_overlay" / "isa" / "globals.isa" - idl_path = File.exist?(custom_globals_path) ? custom_globals_path : $root / "arch" / "isa" / "globals.isa" - @global_ast = @idl_compiler.compile_file( - idl_path, - symtab: @sym_table - ) - - @sym_table.deep_freeze - end - - def inspect = "ArchDef##{name}" - - # @return [Boolean] true if this configuration can execute in multiple xlen environments - # (i.e., that in some mode the effective xlen can be either 32 or 64, depending on CSR values) - def multi_xlen? - ["SXLEN", "UXLEN", "VSXLEN", "VUXLEN"].any? { |key| @param_values[key] == 3264 } - end - - # @return [Array] List of possible XLENs in any mode for this config - def possible_xlens - multi_xlen? ? [32, 64] : [mxlen] - end - - # @param mode [String] One of ['M', 'S', 'U', 'VS', 'VU'] - # @return [Boolean] whether or not XLEN can change in the mode - def multi_xlen_in_mode?(mode) - case mode - when "M" - false - when "S" - @param_values["SXLEN"] == 3264 - when "U" - @param_values["UXLEN"] == 3264 - when "VS" - @param_values["VSXLEN"] == 3264 - when "VU" - @param_values["VUXLEN"] == 3264 - else - raise ArgumentError, "Bad mode" - end - end - - # @return [Array] List of all extensions, with specific versions, that are implemented - def implemented_extensions - return @implemented_extensions unless @implemented_extensions.nil? - - @implemented_extensions = [] - @arch_def["implemented_extensions"].each do |e| - @implemented_extensions << ExtensionVersion.new(e["name"], e["version"]) - end - - @implemented_extensions - end - - # @overload ext?(ext_name) - # @param ext_name [#to_s] Extension name (case sensitive) - # @return [Boolean] True if the extension `name` is implemented - # @overload ext?(ext_name, ext_version_requirements) - # @param ext_name [#to_s] Extension name (case sensitive) - # @param ext_version_requirements [Number,String,Array] Extension version requirements, taking the same inputs as Gem::Requirement - # @see https://docs.ruby-lang.org/en/3.0/Gem/Requirement.html#method-c-new Gem::Requirement#new - # @return [Boolean] True if the extension `name` meeting `ext_version_requirements` is implemented - # @example Checking extension presence with a version requirement - # arch_def.ext?(:S, ">= 1.12") - # @example Checking extension presence with multiple version requirements - # arch_def.ext?(:S, ">= 1.12", "< 1.15") - # @example Checking extension precsence with a precise version requirement - # arch_def.ext?(:S, 1.12) - def ext?(ext_name, *ext_version_requirements) - @ext_cache ||= {} - cached_result = @ext_cache[[ext_name, ext_version_requirements]] - return cached_result unless cached_result.nil? - - result = - implemented_extensions.any? do |e| - if ext_version_requirements.empty? - e.name == ext_name.to_s - else - requirement = Gem::Requirement.new(ext_version_requirements) - (e.name == ext_name.to_s) && requirement.satisfied_by?(e.version) - end - end - @ext_cache[[ext_name, ext_version_requirements]] = result - end - - # @return [Array] All exception codes from this implementation - def exception_codes - return @exception_codes unless @exception_codes.nil? - - @exception_codes = - implemented_extensions.reduce([]) do |list, ext_version| - ecodes = extension(ext_version.name)["exception_codes"] - next list if ecodes.nil? - - ecodes.each do |ecode| - # double check that all the codes are unique - raise "Duplicate exception code" if list.any? { |e| e.num == ecode["num"] || e.name == ecode["name"] || e.var == ecode["var"] } - - list << ExceptionCode.new(ecode["name"], ecode["var"], ecode["num"], self) - end - list + # @returns [Hash] architecturally-defined exception codes and their names + def implemented_exception_codes + @arch_gen.implemented_exception_codes end - end - - # @return [Array] All interrupt codes from this implementation - def interrupt_codes - return @interrupt_codes unless @interrupt_codes.nil? - - @interupt_codes = - implemented_extensions.reduce([]) do |list, ext_version| - icodes = extension(ext_version.name)["interrupt_codes"] - next list if icodes.nil? - icodes.each do |icode| - # double check that all the codes are unique - raise "Duplicate interrupt code" if list.any? { |i| i.num == icode["num"] || i.name == icode["name"] || i.var == icode["var"] } - - list << InterruptCode.new(icode["name"], icode["var"], icode["num"], self) - end - list + # returns [Hash] architecturally-defined interrupt codes and their names + def implemented_interrupt_codes + @arch_gen.implemented_interrupt_codes end - end - - # @return [Hash] The raw architecture defintion data structure - def data - @arch_def - end - - # @return [Array] List of all implemented CSRs - def implemented_csrs - return @implemented_csrs unless @implemented_csrs.nil? - - @implemented_csrs = csrs.select { |c| @arch_def["implemented_csrs"].include?(c.name) } - end - - # @return [Hash] Implemented csrs, indexed by CSR name - def implemented_csr_hash - return @implemented_csr_hash unless @implemented_csr_hash.nil? - - @implemented_csr_hash = {} - implemented_csrs.each do |csr| - @implemented_csr_hash[csr.name] = csr end - @implemented_csr_hash - end - - - # @param csr_name [#to_s] CSR name - # @return [Csr,nil] a specific csr, or nil if it doesn't exist or isn't implemented - def implemented_csr(csr_name) - implemented_csr_hash[csr_name] + @env end + private :erb_env - # @return [Array] List of all implemented instructions - def implemented_instructions - return @implemented_instructions unless @implemented_instructions.nil? - - @implemented_instructions = @arch_def["implemented_instructions"].map do |inst_name| - instruction_hash[inst_name] + # passes _erb_template_ through ERB within the content of this config + # + # @param erb_template [String] ERB source + # @return [String] The rendered text + def render_erb(erb_template, what='') + t = Tempfile.new("template") + t.write erb_template + t.flush + begin + Tilt["erb"].new(t.path, trim: "-").render(erb_env) + rescue + warn "While rendering ERB template: #{what}" + raise + ensure + t.close + t.unlink end - - @implemented_instructions end +end - # @return [Array] List of all reachable IDL functions for the config - def implemented_functions - return @implemented_functions unless @implemented_functions.nil? - - @implemented_functions = [] - - puts " Finding all reachable functions from instruction operations" - - implemented_instructions.each do |inst| - @implemented_functions << - if inst.base.nil? - if multi_xlen? - (inst.reachable_functions(sym_table, 32) + - inst.reachable_functions(sym_table, 64)) - else - inst.reachable_functions(sym_table, mxlen) - end - else - inst.reachable_functions(sym_table, inst.base) - end - end - @implemented_functions.flatten!.uniq!(&:name) +# a synchroncous exception code +class ExceptionCode + # @return [String] Long-form display name (can include special characters) + attr_reader :name + # @return [String] Field name for an IDL enum + attr_reader :var - puts " Finding all reachable functions from CSR operations" + # @return [Integer] Code, written into *mcause + attr_reader :num - implemented_csrs.each do |csr| - csr_funcs = csr.reachable_functions(self) - csr_funcs.each do |f| - @implemented_functions << f unless @implemented_functions.any? { |i| i.name == f.name } - end - end + # @return [Extension] Extension that defines this code + attr_reader :ext - @implemented_functions + def initialize(name, var, number, ext) + @name = name + @name.freeze + @var = var + @num = number + @ext = ext end end + +# all the same informatin as ExceptinCode, but for interrupts +InterruptCode = Class.new(ExceptionCode) diff --git a/lib/arch_obj_models/crd.rb b/lib/arch_obj_models/crd.rb new file mode 100644 index 0000000000..d68723fc3a --- /dev/null +++ b/lib/arch_obj_models/crd.rb @@ -0,0 +1,472 @@ +# Classes for CRD (Certification Requirements Documents). +# Each CRD is a member of a CRD family (e.g., Microcontroller). +# +# Many classes inherit from the ArchDefObject class. This provides facilities for accessing the contents of a +# CRD family YAML or CRD YAML file via the "data" member (hash holding releated YAML file contents). +# +# Many classes have an "arch_def" member which is an ArchDef (not ArchDefObject) class. +# The "arch_def" member contains the "database" of RISC-V standards including extensions, instructions, CSRs, Profiles, and CRDs. +# The arch_def 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_families Array of all known profile families +# profile_family(name) ProfileFamily object for "name" and nil if none. +# profiles Array of all known profiles. +# profile(name) Profile object for "name" and nil if none. +# crd_families Array of all known CRD families +# crd_family(name) CrdFamily object for "name" and nil if none. +# crds Array of all known CRDs. +# crd(name) Crd object for "name" and nil if none. +# +# A variable name with a "_crd" suffix indicates it is from the CRD family/member YAML file. +# A variable name with a "_db" suffix indicates it is an object reference from the arch_def database. + +require_relative "schema" + +################### +# CrdFamily Class # +################### + +# Holds information from CRD family YAML file. +# The inherited "data" member is the database of extensions, instructions, CSRs, etc. +class CrdFamily < ArchDefObject + class Revision < ArchDefObject + def initialize(data) + super(data) + end + + def version + @data["version"] + end + + def date + @data["date"] + end + + def changes + @data["changes"] + end + end +end + +class CrdFamily < ArchDefObject + attr_reader :arch_def + + def initialize(data, arch_def) + super(data) + @arch_def = arch_def + end + + def mandatory_priv_modes = @data["mandatory_priv_modes"] + + def revisions + return @revisions unless @revisions.nil? + + @revisions = [] + @data["revision_history"].each do |rev| + @revisions << Revision.new(rev) + end + @revisions + end + + def introduction = @data["introduction"] + def naming_scheme = @data["naming_scheme"] + + def eql?(other) + other.is_a?(CrdFamily) && other.name == name + end + + def crds + return @crds unless @version.nil? + + @crds = [] + arch_def.crds.each do |crd| + @crds << crd if crd.famly == self + end + @crds + end +end + +############# +# Crd Class # +############# + +# Holds information about a CRD YAML file. +# The inherited "data" member is the database of extensions, instructions, CSRs, etc. +class Crd < ArchDefObject + attr_reader :arch_def + + def initialize(data, arch_def) + super(data) + @arch_def = arch_def + end + + def version = @data["version"] + + def family + return @family unless @family.nil? + + fam = @arch_def.crd_family(@data["family"]) + raise "No CRD family named '#{@data["family"]}'" if fam.nil? + + @family = fam + end + + def tsc_profile + return nil if @data["tsc_profile"].nil? + + profile = arch_def.profile(@data["tsc_profile"]) + + raise "No profile '#{@data["tsc_profile"]}'" if profile.nil? + + profile + 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"] + def description = @data["description"] + + # @return [Extension] - # Returns named Extension object from database (nil if not found). + def extension_from_db(name) + @arch_def.extension(name) + end + + # @return [Array] List of all extensions listed as mandatory or optional in CRD. + def in_scope_extensions + in_scope_ext_reqs.map do |er| + obj = arch_def.extension(er.name) + + # @todo: change this to raise once all the profile extensions + # are defined + warn "Extension #{er.name} is not defined" if obj.nil? + + obj + end.reject(&:nil?) + end + + # @return [Array] - # Extensions with their CRD information. + # If desired_presence is provided, only returns extensions with that presence. + def in_scope_ext_reqs(desired_presence = nil) + in_scope_ext_reqs = [] + @data["extensions"]&.each do |ext_crd| + actual_presence = ext_crd["presence"] + raise "Missing extension presence for extension #{ext_crd["name"]}" if actual_presence.nil? + + if (actual_presence != "mandatory") && (actual_presence != "optional") + raise "Unknown extension presence of #{actual_presence} for extension #{ext_crd["name"]}" + end + + add = false + + if desired_presence.nil? + add = true + elsif desired_presence == actual_presence + add = true + end + + if add + in_scope_ext_reqs << + ExtensionRequirement.new(ext_crd["name"], ext_crd["version"], presence: actual_presence, + note: ext_crd["note"], req_id: "REQ-EXT-" + ext_crd["name"]) + end + end + in_scope_ext_reqs + end + + ################################### + # InScopeExtensionParameter Class # + ################################### + + # Holds extension parameter information from the CRD. + class InScopeExtensionParameter + attr_reader :param_db # ExtensionParameter object (from the architecture database) + attr_reader :note + + def initialize(param_db, schema_hash, note) + raise ArgumentError, "Expecting ExtensionParameter" unless param_db.is_a?(ExtensionParameter) + + if schema_hash.nil? + schema_hash = {} + else + raise ArgumentError, "Expecting schema_hash to be a hash" unless schema_hash.is_a?(Hash) + end + + @param_db = param_db + @schema_crd = Schema.new(schema_hash) + @note = note + end + + def single_value? + @schema_crd.single_value? + end + + def name + @param_db.name + end + + def idl_type + @param_db.type + end + + def value + raise "Parameter schema_crd for #{name} is not a single value" unless single_value? + + @schema_crd.value + end + + # @return [String] - # What parameter values are allowed by the CRD. + # + # Old implementation: + # def schema_pretty_crd_merged_with_param_db + # Schema.new(@param_db.schema).merge!(@schema_crd).to_pretty_s + # end + def allowed_values + if (@schema_crd.empty?) + # CRD doesn't add any constraints on parameter's value. + return "Any" + end + + # Create a Schema object just using information in the parameter database. + schema_obj = Schema.new(@param_db.schema) + + # Merge in constraints imposed by the CRD on the parameter. + schema_obj.merge!(@schema_crd) + + # Create string showing allowed values of parameter with CRD constraints added + schema_obj.to_pretty_s + end + + # sorts by name + def <=>(other) + raise ArgumentError, + "InScopeExtensionParameter are only comparable to other parameter constraints" unless other.is_a?(InScopeExtensionParameter) + @param_db.name <=> other.param_db.name + end + end # class InScopeExtensionParameter + + ############################################ + # Routines using InScopeExtensionParameter # + ############################################ + + # @return [Array] List of parameters specified by any extension in CRD. + # These are always IN SCOPE by definition (since they are listed in the CRD). + # Can have multiple array entries with the same parameter name since multiple extensions may define + # the same parameter. + def all_in_scope_ext_params + return @all_in_scope_ext_params unless @all_in_scope_ext_params.nil? + + @all_in_scope_ext_params = [] + + @data["extensions"].each do |ext_crd| + # Find Extension object from database + ext_db = @arch_def.extension(ext_crd["name"]) + raise "Cannot find extension named #{ext_crd["name"]}" if ext_db.nil? + + ext_crd["parameters"]&.each do |param_name, param_data| + param_db = ext_db.params.find { |p| p.name == param_name } + raise "There is no param '#{param_name}' in extension '#{ext_crd["name"]}" if param_db.nil? + + @all_in_scope_ext_params << + InScopeExtensionParameter.new(param_db, param_data["schema"], param_data["note"]) + end + end + @all_in_scope_ext_params + end + + # @return [Array] List of extension parameters from CRD for given extension. + # These are always IN SCOPE by definition (since they are listed in the CRD). + def in_scope_ext_params(ext_req) + raise ArgumentError, "Expecting ExtensionRequirement" unless ext_req.is_a?(ExtensionRequirement) + + ext_params = [] # Local variable, no caching + + # Get extension information from CRD YAML for passed in extension requirement. + ext_crd = @data["extensions"].find {|ext| ext["name"] == ext_req.name} + raise "Cannot find extension named #{ext_req.name}" if ext_crd.nil? + + # Find Extension object from database + ext_db = @arch_def.extension(ext_crd["name"]) + raise "Cannot find extension named #{ext_crd["name"]}" if ext_db.nil? + + # Loop through an extension's parameter constraints (hash) from the CRD. + # Note that "&" is the Ruby safe navigation operator (i.e., skip do loop if nil). + ext_crd["parameters"]&.each do |param_name, param_data| + # Find ExtensionParameter object from database + ext_param_db = ext_db.params.find { |p| p.name == param_name } + raise "There is no param '#{param_name}' in extension '#{ext_crd["name"]}" if ext_param_db.nil? + + ext_params << + InScopeExtensionParameter.new(ext_param_db, param_data["schema"], param_data["note"]) + end + + ext_params + end + + # @return [Array] Parameters out of scope across all in scope extensions (those listed in the CRD). + def all_out_of_scope_params + return @all_out_of_scope_params unless @all_out_of_scope_params.nil? + + @all_out_of_scope_params = [] + in_scope_ext_reqs.each do |ext_req| + @arch_def.extension(ext_req.name).params.each do |param_db| + next if all_in_scope_ext_params.any? { |c| c.param_db.name == param_db.name } + @all_out_of_scope_params << param_db + end + end + @all_out_of_scope_params + end + + # @return [Array] Parameters that are out of scope for named extension. + def out_of_scope_params(ext_name) + all_out_of_scope_params.select{|param_db| param_db.exts.any? {|ext| ext.name == ext_name} } + end + + # @return [Array] + # All the in-scope extensions (those in the CRD) that define this parameter in the database + # and the parameter is in-scope (listed in that extension's list of parameters in the CRD). + def all_in_scope_exts_with_param(param_db) + raise ArgumentError, "Expecting ExtensionParameter" unless param_db.is_a?(ExtensionParameter) + + exts = [] + + # Interate through all the extensions in the architecture database that define this parameter. + param_db.exts.each do |ext_in_db| + found = false + + in_scope_extensions.each do |in_scope_ext| + if ext_in_db.name == in_scope_ext.name + found = true + next + end + end + + if found + # Only add extensions that exist in this CRD. + exts << ext_in_db + end + end + + # Return intersection of extension names + exts + end + + # @return [Array] + # All the in-scope extensions (those in the CRD) that define this parameter in the database + # but the parameter is out-of-scope (not listed in that extension's list of parameters in the CRD). + def all_in_scope_exts_without_param(param_db) + raise ArgumentError, "Expecting ExtensionParameter" unless param_db.is_a?(ExtensionParameter) + + exts = [] # Local variable, no caching + + # Interate through all the extensions in the architecture database that define this parameter. + param_db.exts.each do |ext_in_db| + found = false + + in_scope_extensions.each do |in_scope_ext| + if ext_in_db.name == in_scope_ext.name + found = true + next + end + end + + if found + # Only add extensions that are in-scope (i.e., exist in this CRD). + exts << ext_in_db + end + end + + # Return intersection of extension names + exts + end + + ##################### + # Requirement Class # + ##################### + + # Holds extra requirements not associated with extensions or their parameters. + class Requirement < ArchDefObject + def initialize(data, arch_def) + super(data) + @arch_def = arch_def + end + + def description = @data["description"] + + def when = @data["when"] + + def when_pretty + @data["when"].keys.map do |key| + case key + when "xlen" + "XLEN == #{@data["when"]["xlen"]}" + when "param" + @data["when"]["param"].map do |param_name, param_value| + "Parameter #{param_name} == #{param_value}" + end + else + raise "TODO: when type #{key} not implemented" + end + end.flatten.join(" and ") + end + end + + ########################## + # RequirementGroup Class # + ########################## + + # Holds a group of Requirement objects to provide a one-level group. + # Can't nest RequirementGroup objects to make multi-level group. + class RequirementGroup < ArchDefObject + def initialize(data, arch_def) + super(data) + @arch_def = arch_def + end + + def description = @data["description"] + + def when = @data["when"] + + def when_pretty + @data["when"].keys.map do |key| + case key + when "xlen" + "XLEN == #{@data["when"]["xlen"]}" + when "param" + @data["when"]["param"].map do |param_name, param_value| + "Parameter #{param_name} == #{param_value}" + end + else + raise "TODO: when type #{key} not implemented" + end + end.flatten.join(" and ") + end + + def requirements + return @requirements unless @requirements.nil? + + @requirements = [] + @data["requirements"].each do |req| + @requirements << Requirement.new(req, @arch_def) + end + @requirements + end + end + + def requirement_groups + return @requirement_groups unless @requirement_groups.nil? + + @requirement_groups = [] + @data["requirement_groups"].each do |req_group| + @requirement_groups << RequirementGroup.new(req_group, @arch_def) + end + @requirement_groups + end + +end \ No newline at end of file diff --git a/lib/arch_obj_models/csc_crd.rb b/lib/arch_obj_models/csc_crd.rb deleted file mode 100644 index bcb7317c8a..0000000000 --- a/lib/arch_obj_models/csc_crd.rb +++ /dev/null @@ -1,318 +0,0 @@ -# Classes for CRD (Certification Requirements Documents). -# Each CRD is a member of a CRD family (e.g., Microcontroller). -# -# Some classes inherit from the ArchDefObject class. This provides facilities for accessing -# the contents of a CRD family or CRD YAML definition via the "data" member (hash holding YAML file contents). -# A variable name with a "_crd" suffix indicates it is from the CRD family/member YAML file. -# -# The "archdef" member is an ArchDef class containing the "database" of RISC-V standards -# including extensions, instructions, CSRs, Profiles, and CRDs. -# A variable name with a "_db" suffix indicates it is from the archdef. - -class CscCrdFamily < ArchDefObject - class Revision < ArchDefObject - def initialize(data) - super(data) - end - - def version - @data["version"] - end - - def date - @data["date"] - end - - def changes - @data["changes"] - end - end -end - -class CscCrdFamily < ArchDefObject - attr_reader :arch_def - - def initialize(data, arch_def) - super(data) - @arch_def = arch_def - end - - def mandatory_priv_modes = @data["mandatory_priv_modes"] - - def revisions - return @revisions unless @revisions.nil? - - @revisions = [] - @data["revision_history"].each do |rev| - @revisions << Revision.new(rev) - end - @revisions - end - - def introduction = @data["introduction"] - - def naming_scheme = @data["naming_scheme"] - - def eql?(other) - other.is_a?(CscCrdFamily) && other.name == name - end - - def crds - return @crds unless @version.nil? - - @crds = [] - arch_def.csc_crds.each do |csc_crd| - @crds << csc_crd if csc_crd.famly == self - end - @crds - end -end - -class CscCrd < ArchDefObject - attr_reader :arch_def - - def initialize(data, arch_def) - super(data) - @arch_def = arch_def - end - - def version = @data["version"] - - def family - return @family unless @family.nil? - - fam = @arch_def.csc_crd_family(@data["family"]) - raise "No CSC CRD family named '#{@data["family"]}'" if fam.nil? - - @family = fam - end - - def tsc_profile - return nil if @data["tsc_profile"].nil? - - profile = arch_def.profile(@data["tsc_profile"]) - - raise "No profile '#{@data["tsc_profile"]}'" if profile.nil? - - profile - 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"] - - def description = @data["description"] - - # @return [Array] - # Extensions with their CRD information. - def extension_reqs - return @extension_reqs_crd unless @extension_reqs_crd.nil? - - @extension_reqs_crd = [] - [ "mandatory", "optional"].each do |status| - @data["extensions"][status]&.each do |ext_crd| - @extension_reqs_crd << - ExtensionRequirement.new(ext_crd["name"], ext_crd["version"], - note: ext_crd["note"], req_id: "REQ-EXT-" + ext_crd["name"], status: status) - end - end - @extension_reqs_crd - end - - # @return [Array] List of extensions - def extensions - extension_reqs.map do |er| - obj = arch_def.extension(er.name) - - # @todo: change this to raise once all the profile extensions - # are defined - warn "Extension #{er.name} is not defined" if obj.nil? - - obj - end.reject(&:nil?) - end - - # Holds an extension's parameter schema constraint from the CRD YAML. - class CrdParameterConstraint - attr_reader :param_db # ExtensionParameter object (from the architecture database) - attr_reader :note - - def initialize(param_db, schema_constraint, note) - raise ArgumentError, "Expecting ExtensionParameter" unless param_db.is_a?(ExtensionParameter) - - @param_db = param_db - @schema_constraint = schema_constraint - @note = note - end - - def single_value? - !@schema_constraint.nil? && @schema_constraint.key?("const") - end - - def value - raise "Parameter schema_constraint for #{@param_db.name} is not a single value" unless single_value? - - @schema_constraint["const"] - end - - def schema_constraint_pretty - return "Unconstrained" if (@schema_constraint.nil? or @schema_constraint == "") - if @schema_constraint.key?("const") - "#{@schema_constraint["const"]}" - elsif @schema_constraint.key?("enum") - "One of: [#{@schema_constraint["enum"].join(', ')}]" - else - raise "TODO: Pretty schema for #{@schema_constraint}" - end - end - - # sorts by name - def <=>(other) - raise ArgumentError, - "CrdParameterConstraint are only comparable to other parameter constraints" unless other.is_a?(CrdParameterConstraint) - @param_db.name <=> other.param_db.name - end - end - - # @return [Array] List of parameters constraints from CRD extension information. - # These are always IN SCOPE by definition (since they are listed in the CRD). - def param_constraints(ext_req_crd) - param_constraints = [] # Local variable, no caching - - # Get extension information from CRD YAML for passed in extension requirement. - ext_crd = @data["extensions"][ext_req_crd.status].find {|ext| ext["name"] == ext_req_crd.name} - raise "Cannot find extension named #{ext_req_crd.name}" if ext_crd.nil? - - # Find Extension object from database - ext_db = @arch_def.extension(ext_crd["name"]) - raise "Cannot find extension named #{ext_crd["name"]}" if ext_db.nil? - - # Loop through an extension's parameter constraints (hash) from the CRD. - # Note that "&" is the Ruby safe navigation operator (i.e., skip do loop if nil). - ext_crd["param_constraints"]&.each do |param_name, param_data| - # Find ExtensionParameter object from database - ext_param_db = ext_db.params.find { |p| p.name == param_name } - raise "There is no param '#{param_name}' in extension '#{ext_crd["name"]}" if ext_param_db.nil? - - param_constraints << CrdParameterConstraint.new(ext_param_db, param_data["schema"], param_data["note"]) - end - - param_constraints - end - - # @return [Array] List of parameters constraints specified by any extension in CRD. - # These are always IN SCOPE by definition (since they are listed in the CRD). - def all_parameter_constraints - return @all_parameter_constraints unless @all_parameter_constraints.nil? - - @all_parameter_constraints = [] - - [ "mandatory", "optional"].each do |status| - @data["extensions"][status].each do |ext_crd| - # Find Extension object from database - ext_db = @arch_def.extension(ext_crd["name"]) - raise "Cannot find extension named #{ext_crd["name"]}" if ext_db.nil? - - ext_crd["param_constraints"]&.each do |param_name, param_data| - param_db = ext_db.params.find { |p| p.name == param_name } - raise "There is no param '#{param_name}' in extension '#{ext_crd["name"]}" if param_db.nil? - - @all_parameter_constraints << CrdParameterConstraint.new(param_db, param_data["schema"], param_data["note"]) - end - end - end - @all_parameter_constraints - end - - # @return [Array] List of parameters that are out of scope across all extensions. - def all_out_of_scope_params - return @all_out_of_scope_params unless @all_out_of_scope_params.nil? - - @all_out_of_scope_params = [] - extension_reqs.each do |ext_req_crd| - @arch_def.extension(ext_req_crd.name).params.each do |param_db| - next if all_parameter_constraints.any? { |c| c.param_db.name == param_db.name } - @all_out_of_scope_params << param_db - end - end - @all_out_of_scope_params - end - - # @return [Array] List of parameters that are out of scope for named extension. - def out_of_scope_params(ext_name) - all_out_of_scope_params.select{|param_db| param_db.exts.any? {|ext| ext.name == ext_name} } - end - - class Requirement < ArchDefObject - def initialize(data, arch_def) - super(data) - @arch_def = arch_def - end - - def description = @data["description"] - - def when = @data["when"] - - def when_pretty - @data["when"].keys.map do |key| - case key - when "xlen" - "XLEN == #{@data["when"]["xlen"]}" - when "param" - @data["when"]["param"].map do |param_name, param_value| - "Parameter #{param_name} == #{param_value}" - end - else - raise "TODO: when type #{key} not implemented" - end - end.flatten.join(" and ") - end - end - - class RequirementGroup < ArchDefObject - def initialize(data, arch_def) - super(data) - @arch_def = arch_def - end - - def description = @data["description"] - - def when = @data["when"] - - def when_pretty - @data["when"].keys.map do |key| - case key - when "xlen" - "XLEN == #{@data["when"]["xlen"]}" - when "param" - @data["when"]["param"].map do |param_name, param_value| - "Parameter #{param_name} == #{param_value}" - end - else - raise "TODO: when type #{key} not implemented" - end - end.flatten.join(" and ") - end - - def requirements - return @requirements unless @requirements.nil? - - @requirements = [] - @data["requirements"].each do |req| - @requirements << Requirement.new(req, @arch_def) - end - @requirements - end - end - - def requirement_groups - return @requirement_groups unless @requirement_groups.nil? - - @requirement_groups = [] - @data["requirement_groups"].each do |req_group| - @requirement_groups << RequirementGroup.new(req_group, @arch_def) - end - @requirement_groups - end -end \ No newline at end of file diff --git a/lib/arch_obj_models/csr.rb b/lib/arch_obj_models/csr.rb index 797a3281a6..fb54617010 100644 --- a/lib/arch_obj_models/csr.rb +++ b/lib/arch_obj_models/csr.rb @@ -56,7 +56,7 @@ def format_changes_with_xlen?(arch_def) end end - # @param arch_def [ImplArchDef] A configuration + # @param arch_def [ArchDef] A configuration # @return [Array] List of functions reachable from this CSR's sw_read or a field's sw_wirte function def reachable_functions(arch_def) return @reachable_functions unless @reachable_functions.nil? @@ -65,8 +65,8 @@ def reachable_functions(arch_def) if has_custom_sw_read? ast = pruned_sw_read_ast(arch_def) - symtab = arch_def.sym_table.deep_clone - symtab.push + symtab = arch_def.symtab.deep_clone + symtab.push(ast) fns.concat(ast.reachable_functions(symtab)) end @@ -94,7 +94,7 @@ def reachable_functions_unevaluated(arch_def) fns = [] if has_custom_sw_read? - ast = sw_read_ast(arch_def.idl_compiler) + ast = sw_read_ast(arch_def) fns.concat(ast.reachable_functions_unevaluated(arch_def)) end @@ -111,47 +111,23 @@ def reachable_functions_unevaluated(arch_def) def dynamic_length?(arch_def) return false if @data["length"].is_a?(Integer) + # when a CSR is only defined in one base, its length can't change + return false unless @data["base"].nil? + case @data["length"] when "MXLEN" - if arch_def.is_a?(ImplArchDef) - false # mxlen can never change - else - if @data["base"].nil? - # don't know MXLEN - true - else - # mxlen is always "base" - false - end - end + # mxlen can never change at runtime, so if we have it in the config, the length is not dynamic + # if we don't have it in the config, we don't know what the length is + return arch_def.mxlen.nil? when "SXLEN" - if arch_def.is_a?(ImplArchDef) - arch_def.param_values["SXLEN"] == 3264 - else - if @data["base"].nil? - # don't know SXLEN - true - else - # sxlen is always "base" - false - end - end + # dynamic if either we don't know SXLEN or SXLEN is explicitly mutable + [nil, 3264].include?(arch_def.param_values["SXLEN"]) when "VSXLEN" - if arch_def.is_a?(ImplArchDef) - arch_def.param_values["VSXLEN"] == 3264 - else - if @data["base"].nil? - # don't know VSXLEN - true - else - # vsxlen is always "base" - false - end - end + # dynamic if either we don't know VSXLEN or VSXLEN is explicitly mutable + [nil, 3264].include?(arch_def.param_values["VSXLEN"]) else raise "Unexpected length" end - # !@data["length"].is_a?(Integer) && (@data["length"] != "MXLEN") end # @param arch_def [ArchDef] Architecture definition @@ -183,63 +159,45 @@ def max_length(arch_def) # @param arch_def [ArchDef] A configuration (can be nil if the lenth is not dependent on a config parameter) # @param effective_xlen [Integer] The effective xlen, needed since some fields change location with XLEN. If the field location is not determined by XLEN, then this parameter can be nil # @return [Integer] Length, in bits, of the CSR, given effective_xlen + # @return [nil] if the length cannot be determined from the arch_def (e.g., because SXLEN is unknown and +effective_xlen+ was not provided) def length(arch_def, effective_xlen = nil) case @data["length"] when "MXLEN" - if arch_def.is_a?(ImplArchDef) - arch_def.param_values["XLEN"] - else - if !@data["base"].nil? - @data["base"] - else - # don't know MXLEN - raise ArgumentError, "for CSR #{name}: effective_xlen is required when length is MXLEN and arch_def is generic" if effective_xlen.nil? + return arch_def.mxlen unless arch_def.mxlen.nil? - effective_xlen - end + if !@data["base"].nil? + @data["base"] + else + # don't know MXLEN + effective_xlen end when "SXLEN" - if arch_def.is_a?(ImplArchDef) + if arch_def.param_values.key?("SXLEN") if arch_def.param_values["SXLEN"] == 3264 - raise ArgumentError, "effective_xlen is required when length is dynamic (#{name})" if effective_xlen.nil? - effective_xlen else - raise "CSR #{name} is not implemented" if arch_def.implemented_csrs.none? { |c| c.name == name } - raise "CSR #{name} is not implemented" if arch_def.param_values["SXLEN"].nil? - arch_def.param_values["SXLEN"] end + elsif !@data["base"].nil? + # if this CSR is only available in one base, then we know its length + @data["base"] else - if !@data["base"].nil? - @data["base"] - else - # don't know SXLEN - raise ArgumentError, "effective_xlen is required when length is SXLEN and arch_def is generic" if effective_xlen.nil? - - effective_xlen - end + # don't know SXLEN + effective_xlen end when "VSXLEN" - if arch_def.is_a?(ImplArchDef) + if arch_def.param_values.key?("VSXLEN") if arch_def.param_values["VSXLEN"] == 3264 - raise ArgumentError, "effective_xlen is required when length is dynamic (#{name})" if effective_xlen.nil? - effective_xlen else - raise "CSR #{name} is not implemented" if arch_def.param_values["VSXLEN"].nil? - arch_def.param_values["VSXLEN"] end + elsif !@data["base"].nil? + # if this CSR is only available in one base, then we know its length + @data["base"] else - if !@data["base"].nil? - @data["base"] - else - # don't know VSXLEN - raise ArgumentError, "effective_xlen is required when length is VSXLEN and arch_def is generic" if effective_xlen.nil? - - effective_xlen - end + # don't know VSXLEN + effective_xlen end when Integer @data["length"] @@ -250,37 +208,26 @@ def length(arch_def, effective_xlen = nil) # @return [Integer] The largest length of this CSR in any valid mode/xlen for the config def max_length(arch_def) + return @data["base"] unless @data["base"].nil? + case @data["length"] when "MXLEN" - if arch_def.is_a?(ImplArchDef) - arch_def.param_values["XLEN"] - else - 64 - end + arch_def.mxlen || 64 when "SXLEN" - if arch_def.is_a?(ImplArchDef) + if arch_def.param_values.key?("SXLEN") if arch_def.param_values["SXLEN"] == 3264 - raise ArgumentError, "effective_xlen is required when length is dynamic (#{name})" if effective_xlen.nil? - 64 else - raise "CSR #{name} is not implemented" if arch_def.implemented_csrs.none? { |c| c.name == name } - raise "CSR #{name} is not implemented" if arch_def.param_values["SXLEN"].nil? - arch_def.param_values["SXLEN"] end else 64 end when "VSXLEN" - if arch_def.is_a?(ImplArchDef) + if arch_def.param_values.key?("VSXLEN") if arch_def.param_values["VSXLEN"] == 3264 - raise ArgumentError, "effective_xlen is required when length is dynamic (#{name})" if effective_xlen.nil? - 64 else - raise "CSR #{name} is not implemented" if arch_def.param_values["VSXLEN"].nil? - arch_def.param_values["VSXLEN"] end else @@ -468,8 +415,8 @@ def type_checked_sw_read_ast(symtab) return ast unless ast.nil? symtab_hash = symtab.hash - symtab = symtab.deep_clone - symtab.push + symtab = symtab.global_clone + symtab.push(ast) # all CSR instructions are 32-bit symtab.add( "__instruction_encoding_size", @@ -480,28 +427,33 @@ def type_checked_sw_read_ast(symtab) Idl::Type.new(:bits, width: 128) ) - ast = sw_read_ast(symtab.archdef.idl_compiler) + ast = sw_read_ast(symtab) symtab.archdef.idl_compiler.type_check( ast, symtab, "CSR[#{name}].sw_read()" ) + symtab.pop + symtab.release @type_checked_sw_read_asts[symtab_hash] = ast end # @return [FunctionBodyAst] The abstract syntax tree of the sw_read() function - # @param idl_compiler [Idl::Compiler] A compiler - def sw_read_ast(idl_compiler) + # @param archdef [ArchDef] A configuration + def sw_read_ast(symtab) + raise ArgumentError, "Argument should be a symtab" unless symtab.is_a?(Idl::SymbolTable) + return @sw_read_ast unless @sw_read_ast.nil? return nil if @data["sw_read()"].nil? # now, parse the function - @sw_read_ast = idl_compiler.compile_func_body( + @sw_read_ast = symtab.archdef.idl_compiler.compile_func_body( @data["sw_read()"], return_type: Idl::Type.new(:bits, width: 128), # big int to hold special return values name: "CSR[#{name}].sw_read()", input_file: __source, input_line: source_line("sw_read()"), + symtab:, type_check: false ) @@ -517,10 +469,10 @@ def pruned_sw_read_ast(arch_def) ast = @pruned_sw_read_asts[arch_def.name] return ast unless ast.nil? - ast = type_checked_sw_read_ast(arch_def.sym_table).prune(arch_def.sym_table.deep_clone) + ast = type_checked_sw_read_ast(arch_def.symtab) - symtab = arch_def.sym_table.deep_clone - symtab.push + symtab = arch_def.symtab.global_clone + symtab.push(ast) # all CSR instructions are 32-bit symtab.add( "__instruction_encoding_size", @@ -531,11 +483,18 @@ def pruned_sw_read_ast(arch_def) Idl::Type.new(:bits, width: 128) ) + ast = ast.prune(symtab) + ast.freeze_tree(arch_def.symtab) + arch_def.idl_compiler.type_check( ast, symtab, "CSR[#{name}].sw_read()" ) + + symtab.pop + symtab.release + @pruned_sw_read_asts[arch_def.name] = ast end @@ -551,21 +510,19 @@ def pruned_sw_read_ast(arch_def) # @param arch_def [ArchDef] A configuration # @param effective_xlen [Integer,nil] Effective XLEN to use when CSR length is dynamic # @return [Hash] A representation of the WaveDrom drawing for the CSR (should be turned into JSON for wavedrom) - def wavedrom_desc(arch_def, effective_xlen) + def wavedrom_desc(arch_def, effective_xlen, exclude_unimplemented: false) desc = { "reg" => [] } last_idx = -1 + field_list = - if arch_def.is_a?(ImplArchDef) + if exclude_unimplemented implemented_fields_for(arch_def, effective_xlen) else - fields.select do |f| - effective_xlen.nil? || \ - ((effective_xlen == 32) && f.defined_in_base32?) || \ - ((effective_xlen == 64) && f.defined_in_base64?) - end + fields_for(effective_xlen) end + field_list.sort! { |a, b| a.location(arch_def, effective_xlen).min <=> b.location(arch_def, effective_xlen).min } field_list.each do |field| diff --git a/lib/arch_obj_models/csr_field.rb b/lib/arch_obj_models/csr_field.rb index e8b86179c6..0e6740f979 100644 --- a/lib/arch_obj_models/csr_field.rb +++ b/lib/arch_obj_models/csr_field.rb @@ -39,16 +39,17 @@ def exists_in_cfg?(possible_xlens, extensions) # @return [Idl::FunctionBodyAst] Abstract syntax tree of the type() function # @return [nil] if the type property is not a function - # @param idl_compiler [Idl::Compiler] A compiler - def type_ast(idl_compiler) + # @param symtab [SymbolTable] Symbol table with execution context + def type_ast(symtab) return @type_ast unless @type_ast.nil? return nil if @data["type()"].nil? - @type_ast = idl_compiler.compile_func_body( + @type_ast = symtab.archdef.idl_compiler.compile_func_body( @data["type()"], name: "CSR[#{csr.name}].#{name}.type()", input_file: csr.__source, input_line: csr.source_line("fields", name, "type()"), + symtab:, type_check: false ) @@ -66,20 +67,25 @@ def type_checked_type_ast(symtab) return ast unless ast.nil? symtab_hash = symtab.hash - symtab = symtab.deep_clone - symtab.push + + symtab = symtab.global_clone + + symtab.push(ast) # all CSR instructions are 32-bit symtab.add( "__expected_return_type", Idl::Type.new(:enum_ref, enum_class: symtab.get("CsrFieldType")) ) - ast = type_ast(symtab.archdef.idl_compiler) + ast = type_ast(symtab) symtab.archdef.idl_compiler.type_check( ast, symtab, "CSR[#{name}].type()" ) + symtab.pop + symtab.release + @type_checked_type_asts[symtab_hash] = ast end @@ -94,24 +100,29 @@ def pruned_type_ast(symtab) ast = type_checked_type_ast(symtab).prune(symtab.deep_clone) symtab_hash = symtab.hash - symtab.push + symtab = symtab.global_clone + symtab.push(ast) # all CSR instructions are 32-bit symtab.add( "__expected_return_type", Idl::Type.new(:enum_ref, enum_class: symtab.get("CsrFieldType")) ) + ast.freeze_tree(symtab) + symtab.archdef.idl_compiler.type_check( ast, symtab, "CSR[#{name}].type()" ) + symtab.pop + symtab.release @pruned_type_asts[symtab_hash] = ast end # returns the definitive type for a configuration # - # @param arch_def [ArchDef] A config + # @param symtab [SymbolTable] Symbol table # @return [String] # The type of the field. One of: # 'RO' => Read-only @@ -120,69 +131,75 @@ def pruned_type_ast(symtab) # 'RW-R' => Read-write, with a restricted set of legal values # 'RW-H' => Read-write, with a hardware update # 'RW-RH' => Read-write, with a hardware update and a restricted set of legal values - def type(arch_def) - if !@type_cache.nil? && @type_cache.key?(arch_def) - return @type_cache[arch_def] - end + def type(symtab) + raise ArgumentError, "Argument 1 should be a symtab" unless symtab.is_a?(Idl::SymbolTable) - @type_cache ||= {} + unless @type_cache.nil? + raise "Different archdef for type #{@type_cache.keys}, #{symtab.archdef}" unless @type_cache.key?(symtab.archdef) + + return @type_cache[symtab.archdef] + end type = if @data.key?("type") @data["type"] - elsif arch_def.is_a?(ImplArchDef) + else # the type is config-specific... idl = @data["type()"] raise "type() is nil for #{csr.name}.#{name} #{@data}?" if idl.nil? - # grab global symtab - sym_table = arch_def.sym_table + + # value_result = Idl::AstNode.value_try do + ast = type_checked_type_ast(symtab) begin - case pruned_type_ast(sym_table.deep_clone).return_value(sym_table.deep_clone.push) - when 0 - "RO" - when 1 - "RO-H" - when 2 - "RW" - when 3 - "RW-R" - when 4 - "RW-H" - when 5 - "RW-RH" - else - raise "Unhandled CsrFieldType value" - end - rescue Idl::AstNode::ValueError => e - warn "In parsing #{csr.name}.#{name}::type()" - warn " Return of type() function cannot be evaluated at compile time" - raise e + symtab = symtab.global_clone + + symtab.push(ast) + type = case ast.return_value(symtab) + when 0 + "RO" + when 1 + "RO-H" + when 2 + "RW" + when 3 + "RW-R" + when 4 + "RW-H" + when 5 + "RW-RH" + else + raise "Unhandled CsrFieldType value" + end + ensure + symtab.pop + symtab.release end - else - raise Idl::AstNode::ValueError.new( - type_ast(arch_def.idl_compiler).lineno, - type_ast(arch_def.idl_compiler).input_file, - "arch def is generic, can't know type exactly" - ) + type + # end + # Idl::AstNode.value_else(value_result) do + # warn "In parsing #{csr.name}.#{name}::type()" + # raise " Return of type() function cannot be evaluated at compile time" + # Idl::AstNode.value_error "" + # end end - @type_cache[arch_def] = type + @type_cache ||= {} + @type_cache[symtab.archdef] = type end # @return [String] A pretty-printed type string - def type_pretty(arch_def) - if arch_def.is_a?(ImplArchDef) - type(arch_def) - else - if @data.key?("type") - @data["type"] - else - ast = type_ast(arch_def.idl_compiler) - ast.gen_option_adoc - end + def type_pretty(symtab) + str = nil + value_result = Idl::AstNode.value_try do + str = type(symtab) + end + Idl::AstNode.value_else(value_result) do + ast = type_ast(symtab) + str = ast.gen_option_adoc end + str end # @return [Alias,nil] The aliased field, or nil if there is no alias @@ -213,21 +230,21 @@ def alias end # @return [Array] List of functions called thorugh this field - # @param archdef [ImplArchDef] a configuration + # @param archdef [ArchDef] a configuration # @Param effective_xlen [Integer] 32 or 64; needed because fields can change in different XLENs def reachable_functions(archdef, effective_xlen) return @reachable_functions unless @reachable_functions.nil? symtab = - if (archdef.is_a?(ImplArchDef)) - archdef.sym_table + if (archdef.configured?) + archdef.symtab else raise ArgumentError, "Must supply effective_xlen for generic ArchDef" if effective_xlen.nil? if effective_xlen == 32 - archdef.sym_table_32 + archdef.symtab_32 else - archdef.sym_table_64 + archdef.symtab_64 end end @@ -236,7 +253,7 @@ def reachable_functions(archdef, effective_xlen) ast = pruned_sw_write_ast(archdef, effective_xlen) unless ast.nil? sw_write_symtab = symtab.deep_clone - sw_write_symtab.push + sw_write_symtab.push(ast) sw_write_symtab.add("csr_value", Idl::Var.new("csr_value", csr.bitfield_type(symtab.archdef, effective_xlen))) fns.concat ast.reachable_functions(sw_write_symtab) end @@ -244,13 +261,13 @@ def reachable_functions(archdef, effective_xlen) if @data.key?("type()") ast = pruned_type_ast(symtab.deep_clone) unless ast.nil? - fns.concat ast.reachable_functions(symtab.deep_clone.push) + fns.concat ast.reachable_functions(symtab.deep_clone.push(ast)) end end if @data.key?("reset_value()") ast = pruned_reset_value_ast(symtab.deep_clone) unless ast.nil? - fns.concat ast.reachable_functions(symtab.deep_clone.push) + fns.concat ast.reachable_functions(symtab.deep_clone.push(ast)) end end @@ -258,27 +275,29 @@ def reachable_functions(archdef, effective_xlen) end # @return [Array] List of functions called thorugh this field, irrespective of context - # @param archdef [ArchDef] Architecture definition - def reachable_functions_unevaluated(archdef) + # @param symtab [SymbolTable] + def reachable_functions_unevaluated(symtab) + raise ArgumentError, "Argument should be a symtab" unless symtab.is_a?(Idl::SymbolTable) + return @reachable_functions_unevaluated unless @reachable_functions_unevaluated.nil? fns = [] if has_custom_sw_write? - ast = sw_write_ast(archdef.idl_compiler) + ast = sw_write_ast(symtab) unless ast.nil? - fns.concat ast.reachable_functions_unevaluated(archdef) + fns.concat ast.reachable_functions_unevaluated(symtab) end end if @data.key?("type()") - ast = type_ast(archdef.idl_compiler) + ast = type_ast(symtab) unless ast.nil? - fns.concat ast.reachable_functions_unevaluated(archdef) + fns.concat ast.reachable_functions_unevaluated(symtab) end end if @data.key?("reset_value()") - ast = reset_value_ast(archdef.idl_compiler) + ast = reset_value_ast(symtab) unless ast.nil? - fns.concat ast.reachable_functions_unevalutated(archdef) + fns.concat ast.reachable_functions_unevalutated(symtab) end end @@ -292,31 +311,29 @@ def reachable_functions_unevaluated(archdef) # @return [Boolean] Whether or not the location of the field changes dynamically # (e.g., based on mstatus.SXL) in the configuration def dynamic_location?(arch_def) - if arch_def.is_a?(ImplArchDef) - unless @data["location_rv32"].nil? - csr.modes_with_access.each do |mode| - return true if arch_def.multi_xlen_in_mode?(mode) - end - end - false - else - !@data["location_rv32"].nil? - end + # if there is no location_rv32, the the field never changes + return false unless @data["location"].nil? + + # the field changes *if* some mode with access can change XLEN + csr.modes_with_access.any? { |mode| arch_def.multi_xlen_in_mode?(mode) } end # @param arch_def [IdL::Compiler] A compiler # @return [Idl::FunctionBodyAst] Abstract syntax tree of the reset_value function # @return [nil] If the reset_value is not a function - def reset_value_ast(idl_compiler) + def reset_value_ast(symtab) + raise ArgumentError, "Argument should be a symtab (is a #{symtab.class.name})" unless symtab.is_a?(Idl::SymbolTable) + return @reset_value_ast unless @reset_value_ast.nil? return nil unless @data.key?("reset_value()") - @reset_value_ast = idl_compiler.compile_func_body( + @reset_value_ast = symtab.archdef.idl_compiler.compile_func_body( @data["reset_value()"], return_type: Idl::Type.new(:bits, width: 64), name: "CSR[#{parent.name}].#{name}.reset_value()", input_file: csr.__source, input_line: csr.source_line("fields", name, "reset_value()"), + symtab:, type_check: false ) end @@ -333,11 +350,11 @@ def type_checked_reset_value_ast(symtab) return nil unless @data.key?("reset_value()") - ast = reset_value_ast(symtab.archdef.idl_compiler) + ast = reset_value_ast(symtab) symtab_hash = symtab.hash symtab = symtab.deep_clone - symtab.push + symtab.push(ast) symtab.add("__expected_return_type", Idl::Type.new(:bits, width: 64)) symtab.archdef.idl_compiler.type_check( ast, @@ -361,18 +378,21 @@ def pruned_reset_value_ast(symtab) symtab_hash = symtab.hash symtab = symtab.deep_clone - symtab.push + symtab.push(ast) symtab.add("__expected_return_type", Idl::Type.new(:bits, width: 64)) ast = ast.prune(symtab) symtab.pop - symtab.push + + ast.freeze_tree(symtab) + + symtab.push(ast) symtab.add("__expected_return_type", Idl::Type.new(:bits, width: 64)) symtab.archdef.idl_compiler.type_check( ast, symtab, - "CSR[#{csr.name}].reset_value()" + "CSR[#{csr.name}].#{name}.reset_value()" ) @type_checked_reset_value_asts[symtab_hash] = ast @@ -382,9 +402,8 @@ def pruned_reset_value_ast(symtab) # @return [Integer] The reset value of this field # @return [String] The string 'UNDEFINED_LEGAL' if, for this config, there is no defined reset value def reset_value(arch_def, effective_xlen = nil) - if !@reset_value_cache.nil? && @reset_value_cache.key?(arch_def) - return @reset_value_cache[arch_def] - end + cached_value = @reset_value_cache.nil? ? nil : @reset_value_cache[arch_def] + return cached_value if cached_value @reset_value_cache ||= {} @@ -393,34 +412,56 @@ def reset_value(arch_def, effective_xlen = nil) @data["reset_value"] else symtab = - if arch_def.is_a?(ImplArchDef) - arch_def.sym_table + if !arch_def.mxlen.nil? + arch_def.symtab else raise ArgumentError, "effective_xlen is required when using generic arch_def" if effective_xlen.nil? - effective_xlen == 32 ? arch_def.sym_table_32 : arch_def.sym_table_64 + effective_xlen == 32 ? arch_def.symtab_32 : arch_def.symtab_64 end - val = pruned_reset_value_ast(symtab.deep_clone).return_value(symtab.deep_clone.push) + ast = pruned_reset_value_ast(symtab.deep_clone) + val = ast.return_value(symtab.deep_clone.push(ast)) val = "UNDEFINED_LEGAL" if val == 0x1_0000_0000_0000_0000 val end end - def dynamic_reset_value? - @data["reset_value()"] != nil - end + def dynamic_reset_value?(arch_def) + return false unless @data["reset_value"].nil? - def reset_value_pretty(arch_def) - if arch_def.is_a?(ImplArchDef) - reset_value(arch_def) - else - if @data.key?("reset_value") - @data["reset_value"] + value_result = value_try do + if arch_def.mxlen.nil? + # need to try with generic symtab_32/symtab_64 + reset_value_32 = reset_value(arch_def, 32) + reset_value_64 = reset_value(arch_def, 64) + reset_value_32 != reset_value_64 else - ast = reset_value_ast(arch_def.idl_compiler) - ast.gen_option_adoc + # just call the function, see if we get a value error + reset_value(arch_def) + false end + end || true + end + + def reset_value_pretty(arch_def) + str = nil + value_result = Idl::AstNode.value_try do + str = + if arch_def.mxlen.nil? + if dynamic_reset_value?(arch_def) + Idl::AstNode.value_error "" + else + reset_value(arch_def, 32) # 32 or 64, doesn't matter + end + else + reset_value(arch_def) + end end + Idl::AstNode.value_else(value_result) do + ast = reset_value_ast(arch_def.symtab) + str = ast.gen_option_adoc + end + str end # @return [Boolean] true if the CSR field has a custom sw_write function @@ -439,8 +480,8 @@ def type_checked_sw_write_ast(symtab, effective_xlen) return nil unless @data.key?("sw_write(csr_value)") symtab_hash = symtab.hash - symtab = symtab.deep_clone - symtab.push + symtab = symtab.global_clone + symtab.push(ast) # all CSR instructions are 32-bit symtab.add( "__instruction_encoding_size", @@ -455,42 +496,46 @@ def type_checked_sw_write_ast(symtab, effective_xlen) Idl::Var.new("csr_value", csr.bitfield_type(symtab.archdef, effective_xlen)) ) - ast = sw_write_ast(symtab.archdef.idl_compiler) + ast = sw_write_ast(symtab) symtab.archdef.idl_compiler.type_check( ast, symtab, "CSR[#{csr.name}].#{name}.sw_write()" ) + symtab.pop + symtab.release @type_checked_sw_write_asts[symtab_hash] = ast end # @return [Idl::FunctionBodyAst] The abstract syntax tree of the sw_write() function # @return [nil] If there is no sw_write() function - # @param idl_compiler [Idl::Compiler] A compiler - def sw_write_ast(idl_compiler) + # @param archdef [ArchDef] An architecture definition + def sw_write_ast(symtab) + raise ArgumentError, "Argument should be a symtab" unless symtab.is_a?(Idl::SymbolTable) + return @sw_write_ast unless @sw_write_ast.nil? return nil if @data["sw_write(csr_value)"].nil? # now, parse the function - @sw_write_ast = idl_compiler.compile_func_body( + @sw_write_ast = symtab.archdef.idl_compiler.compile_func_body( @data["sw_write(csr_value)"], return_type: Idl::Type.new(:bits, width: 128), # big int to hold special return values name: "CSR[#{csr.name}].#{name}.sw_write(csr_value)", - input_file: csr.source_line("fields", name, "sw_write(csr_value)"), + input_file: csr.__source, + input_line: csr.source_line("fields", name, "sw_write(csr_value)"), + symtab:, type_check: false ) raise "unexpected #{@sw_write_ast.class}" unless @sw_write_ast.is_a?(Idl::FunctionBodyAst) - @sw_write_ast.set_input_file(csr.__source, csr.source_line("fields", name, "sw_write(csr_value)")) - @sw_write_ast end - # @return [Idl::FunctionBodyAst] The abstract syntax tree of the sw_write() function, type checked + # @return [Idl::FunctionBodyAst] The abstract syntax tree of the sw_write() function, type checked and pruned # @return [nil] if there is no sw_write() function # @param effective_xlen [Integer] effective xlen, needed because fields can change in different bases - # @param arch_def [ImplArchDef] A configuration + # @param arch_def [ArchDef] A configuration def pruned_sw_write_ast(arch_def, effective_xlen) @pruned_sw_write_asts ||= {} ast = @pruned_sw_write_asts[arch_def.name] @@ -498,8 +543,10 @@ def pruned_sw_write_ast(arch_def, effective_xlen) return nil unless @data.key?("sw_write(csr_value)") - symtab = arch_def.sym_table.deep_clone - symtab.push + raise ArgumentError, "arch_def must be configured to prune" if arch_def.unconfigured? + + symtab = arch_def.symtab.global_clone + symtab.push(ast) # all CSR instructions are 32-bit symtab.add( "__instruction_encoding_size", @@ -514,17 +561,26 @@ def pruned_sw_write_ast(arch_def, effective_xlen) Idl::Var.new("csr_value", csr.bitfield_type(arch_def, effective_xlen)) ) - ast = type_checked_sw_write_ast(arch_def.sym_table.deep_clone, effective_xlen).prune(symtab.deep_clone) + ast = type_checked_sw_write_ast(arch_def.symtab, effective_xlen) + ast = ast.prune(symtab) + raise "Symbol table didn't come back at global + 1" unless symtab.levels == 2 + + ast.freeze_tree(arch_def.symtab) + arch_def.idl_compiler.type_check( ast, symtab, "CSR[#{name}].sw_write(csr_value)" ) + + symtab.pop + symtab.release + @pruned_sw_write_asts[arch_def.name] = ast end - # @param arch_def [ArchDef] A config. May be nil if the locaiton is not configturation-dependent + # @param arch_def [ArchDef] A config. May be nil if the location is not configturation-dependent # @param effective_xlen [Integer] The effective xlen, needed since some fields change location with XLEN. If the field location is not determined by XLEN, then this parameter can be nil # @return [Range] the location within the CSR as a range (single bit fields will be a range of size 1) def location(arch_def, effective_xlen = nil) @@ -532,7 +588,7 @@ def location(arch_def, effective_xlen = nil) if @data.key?("location") "location" else - raise ArgumentError, "Expecting 32 or 64" unless [32, 64].include?(effective_xlen) + raise ArgumentError, "The location of #{csr.name}.#{name} changes with XLEN, so effective_xlen must be provided" unless [32, 64].include?(effective_xlen) "location_rv#{effective_xlen}" end @@ -540,14 +596,14 @@ def location(arch_def, effective_xlen = nil) raise "Missing location for #{csr.name}.#{name} (#{key})?" unless @data.key?(key) if @data[key].is_a?(Integer) - if (arch_def.is_a?(ImplArchDef)) - if @data[key] > csr.length(arch_def, effective_xlen || @data["base"]) - raise "Location (#{key} = #{@data[key]}) is past the csr length (#{csr.length(arch_def, effective_xlen)}) in #{csr.name}.#{name}" - end - else + csr_length = csr.length(arch_def, effective_xlen || @data["base"]) + if csr_length.nil? + # we don't know the csr length for sure, so we can only check again max_length if @data[key] > csr.max_length(arch_def) raise "Location (#{key} = #{@data[key]}) is past the max csr length (#{csr.max_length(arch_def)}) in #{csr.name}.#{name}" end + elsif @data[key] > csr_length + raise "Location (#{key} = #{@data[key]}) is past the csr length (#{csr.length(arch_def, effective_xlen)}) in #{csr.name}.#{name}" end @data[key]..@data[key] @@ -555,14 +611,14 @@ def location(arch_def, effective_xlen = nil) e, s = @data[key].split("-").map(&:to_i) raise "Invalid location" if s > e - if (arch_def.is_a?(ImplArchDef)) - if e > csr.length(arch_def, effective_xlen) - raise "Location (#{key} = #{@data[key]}) is past the csr length (#{csr.length(arch_def, effective_xlen)}) in #{csr.name}.#{name}" - end - else + csr_length = csr.length(arch_def, effective_xlen || @data["base"]) + if csr_length.nil? + # we don't know the csr length for sure, so we can only check again max_length if e > csr.max_length(arch_def) raise "Location (#{key} = #{@data[key]}) is past the max csr length (#{csr.max_length(arch_def)}) in #{csr.name}.#{name}" end + elsif e > csr_length + raise "Location (#{key} = #{@data[key]}) is past the csr length (#{csr_length}) in #{csr.name}.#{name}" end s..e @@ -644,11 +700,7 @@ def location_pretty(arch_def, effective_xlen = nil) derangeify.call(location(arch_def, effective_xlen)) end else - if arch_def.is_a?(ImplArchDef) - derangeify.call(location(arch_def, arch_def.param_values["XLEN"])) - else - derangeify.call(location(arch_def, nil)) - end + derangeify.call(location(arch_def, arch_def.mxlen)) end end @@ -703,6 +755,6 @@ def location_pretty(arch_def, effective_xlen = nil) # @return [String] Long description of the field type def type_desc(arch_def) - TYPE_DESC_MAP[type(arch_def)] + TYPE_DESC_MAP[type(arch_def.symtab)] end end \ No newline at end of file diff --git a/lib/arch_obj_models/extension.rb b/lib/arch_obj_models/extension.rb index 61ea17a29b..2b3920e942 100644 --- a/lib/arch_obj_models/extension.rb +++ b/lib/arch_obj_models/extension.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require_relative "obj" +require_relative "schema" # A parameter (AKA option, AKA implementation-defined value) supported by an extension class ExtensionParameter @@ -26,6 +27,11 @@ class ExtensionParameter # @returns [Idl::Type] Type of the parameter attr_reader :type + # Pretty convert extension schema to a string. + def schema_type + Schema.new(@schema).to_pretty_s + end + def initialize(name, desc, schema, extra_validation, exts) @name = name @desc = desc @@ -187,11 +193,17 @@ def implies(version_requirement = ">= 0") implications end + def conflicts + return [] if @data["conflicts"].nil? + + to_extension_requirement_list(@data["conflicts"]) + end + # @return [Array] the list of instructions implemented by this extension (may be empty) def instructions return @instructions unless @instructions.nil? - @instructions = arch_def.instructions.select { |i| i.definedBy == name || (i.definedBy.is_a?(Array) && i.definedBy.include?(name)) } + @instructions = arch_def.instructions.select { |i| @data["versions"].any? { |version| i.defined_by?(name, version["version"]) }} end # @return [Array] the list of CSRs implemented by this extension (may be empty) @@ -308,7 +320,7 @@ class ExtensionRequirement attr_reader :name attr_reader :note # Optional note. Can be nil. attr_reader :req_id # Optional Requirement ID. Can be nil. - attr_reader :status # Optional status (e.g., Mandatory, Optional, etc.). Can be nil. + attr_reader :presence # Optional presence (e.g., Mandatory, Optional, etc.). Can be nil. # @return [Gem::Requirement] Version requirement def version_requirement @@ -321,7 +333,7 @@ def to_s # @param name [#to_s] Extension name # @param requirements (see Gem::Requirement#new) - def initialize(name, *requirements, note: nil, req_id: nil, status: nil) + def initialize(name, *requirements, note: nil, req_id: nil, presence: nil) @name = name.to_s requirements = if requirements.empty? @@ -332,7 +344,7 @@ def initialize(name, *requirements, note: nil, req_id: nil, status: nil) @requirement = Gem::Requirement.new(requirements) @note = note @req_id = req_id - @status = status + @presence = presence end # @overload diff --git a/lib/arch_obj_models/instruction.rb b/lib/arch_obj_models/instruction.rb index df31a7a8f4..9b9fa0070d 100644 --- a/lib/arch_obj_models/instruction.rb +++ b/lib/arch_obj_models/instruction.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require 'ruby-prof-flamegraph' + require_relative "obj" @@ -9,7 +11,17 @@ def ==(other) if other.is_a?(Instruction) name == other.name else - raise ArgumentError, "Instruction is comparable to a #{other.class.name}" + raise ArgumentError, "Instruction is not comparable to a #{other.class.name}" + end + end + + alias eql? == + + def <=>(other) + if other.is_a?(Instruction) + name <=> other.name + else + raise ArgumentError, "Instruction is not comparable to a #{other.class.name}" end end @@ -44,31 +56,9 @@ def assembly @data["assembly"] end - # @return [Array] List of extensions requirements (in addition to one returned by {#defined_by}) that must be met for the instruction to exist - def extension_requirements - return [] unless @data.key?("requires") - - @extension_requirements = [] - if @data["requires"].is_a?(Array) - # could be either a single extension with requirement, or a list of requirements - if extension_requirement?(@data["requires"][0]) - @extension_requirements << to_extension_requirement(@data["requires"][0]) - else - # this is a list - @data["requires"].each do |r| - @extension_requirements << to_extension_requirement(r) - end - end - else - @extension_requirements << to_extension_requirement(@data["requires"]) - end - - @extension_requirements - end - - def fill_symtab(global_symtab, effective_xlen) + def fill_symtab(global_symtab, effective_xlen, ast) symtab = global_symtab.deep_clone - symtab.push + symtab.push(ast) symtab.add( "__instruction_encoding_size", Idl::Var.new("__instruction_encoding_size", Idl::Type.new(:bits, width: encoding_width.bit_length), encoding_width) @@ -103,10 +93,13 @@ def pruned_operation_ast(global_symtab, effective_xlen) return nil unless @data.key?("operation()") type_checked_ast = type_checked_operation_ast(arch_def.idl_compiler, global_symtab, effective_xlen) - pruned_ast = type_checked_ast.prune(fill_symtab(global_symtab, effective_xlen)) + print "Pruning #{name} operation()..." + pruned_ast = type_checked_ast.prune(fill_symtab(global_symtab, effective_xlen, type_checked_ast)) + puts "done" + pruned_ast.freeze_tree(global_symtab) arch_def.idl_compiler.type_check( pruned_ast, - fill_symtab(global_symtab, effective_xlen), + fill_symtab(global_symtab, effective_xlen, pruned_ast), "#{name}.operation() (pruned)" ) @@ -121,24 +114,45 @@ def reachable_functions(symtab, effective_xlen) [] else # RubyProf.start - pruned_operation_ast(symtab, effective_xlen).reachable_functions(fill_symtab(symtab, effective_xlen)) + ast = type_checked_operation_ast(symtab.archdef.idl_compiler, symtab, effective_xlen) + print "Determining reachable funcs from #{name}..." + fns = ast.reachable_functions(fill_symtab(symtab, effective_xlen, ast)) + puts "done" # result = RubyProf.stop # RubyProf::FlatPrinter.new(result).print($stdout) # exit + fns end end # @param symtab [Idl::SymbolTable] Symbol table with global scope populated # @param effective_xlen [Integer] Effective XLEN to evaluate against - # @return [Array] List of all exceptions that can be reached from operation() + # @return [Integer] Mask of all exceptions that can be reached from operation() def reachable_exceptions(symtab, effective_xlen) if @data["operation()"].nil? [] else - pruned_operation_ast(symtab).reachable_exceptions(fill_symtab(symtab, effective_xlen)).uniq + # pruned_ast = pruned_operation_ast(symtab) + # type_checked_operation_ast() + type_checked_ast = type_checked_operation_ast(symtab.arch_def.idl_compiler, symtab, effective_xlen) + symtab = fill_symtab(symtab, effective_xlen, pruned_ast) + type_checked_ast.reachable_exceptions(symtab) end end + def mask_to_array(int) + elems = [] + idx = 0 + while int != 0 + if (int & (1 << idx)) != 0 + elems << idx + end + int &= ~(1 << idx) + idx += 1 + end + elems + end + # @param symtab [Idl::SymbolTable] Symbol table with global scope populated # @param effective_xlen [Integer] Effective XLEN to evaluate against. If nil, evaluate against all valid XLENs # @return [Array] List of all exceptions that can be reached from operation() @@ -152,28 +166,54 @@ def reachable_exceptions_str(symtab, effective_xlen=nil) if symtab.archdef.multi_xlen? if base.nil? ( - pruned_operation_ast(symtab, 32).reachable_exceptions(fill_symtab(symtab, 32)).uniq.map { |code| + pruned_ast = pruned_operation_ast(symtab, 32) + print "Determining reachable exceptions from #{name}#RV32..." + e32 = mask_to_array(pruned_ast.reachable_exceptions(fill_symtab(symtab, 32, pruned_ast))).map { |code| etype.element_name(code) - } + - pruned_operation_ast(symtab, 64).reachable_exceptions(fill_symtab(symtab, 64)).uniq.map { |code| + } + puts "done" + pruned_ast = pruned_operation_ast(symtab, 64) + print "Determining reachable exceptions from #{name}#RV64..." + e64 = mask_to_array(prunted_ast.reachable_exceptions(fill_symtab(symtab, 64, pruned_ast))).map { |code| etype.element_name(code) } + puts done + e32 + e64 ).uniq else - pruned_operation_ast(symtab, base).reachable_exceptions(fill_symtab(symtab, base)).uniq.map { |code| - etype.element_name(code) - } + pruned_ast = pruned_operation_ast(symtab, base) + print "Determining reachable exceptions from #{name}..." + result = RubyProf.profile do + e = mask_to_array(pruned_ast.reachable_exceptions(fill_symtab(symtab, base, pruned_ast))).map { |code| + etype.element_name(code) + } + end + RubyProf::CallStackPrinter.new(result).print(File.open("#{name}-profile.html", "w+"), {}) + puts "done" + e end else effective_xlen = symtab.archdef.mxlen - pruned_operation_ast(symtab, effective_xlen).reachable_exceptions(fill_symtab(symtab, effective_xlen)).uniq.map { |code| - etype.element_name(code) - } + pruned_ast = pruned_operation_ast(symtab, effective_xlen) + print "Determining reachable exceptions from #{name}..." + # result = RubyProf.profile do + e = mask_to_array(pruned_ast.reachable_exceptions(fill_symtab(symtab, effective_xlen, pruned_ast))).map { |code| + etype.element_name(code) + } + # end + # RubyProf::FlameGraphPrinter.new(result).print(File.open("#{name}-profile.html", "w+"), {}) + puts "done" + e end else - pruned_operation_ast(symtab, effective_xlen).reachable_exceptions(fill_symtab(symtab, effective_xlen)).uniq.map { |code| + pruned_ast = pruned_operation_ast(symtab, effective_xlen) + + print "Determining reachable exceptions from #{name}..." + e = mask_to_array(prunted_ast.reachable_exceptions(fill_symtab(symtab, effective_xlen, pruned_ast))).map { |code| etype.element_name(code) } + puts "done" + e end # result = RubyProf.stop # RubyProf::FlatPrinter.new(result).print(STDOUT) @@ -555,21 +595,23 @@ def type_checked_operation_ast(idl_compiler, symtab, effective_xlen) return nil unless @data.key?("operation()") - ast = operation_ast(idl_compiler) + ast = operation_ast(symtab) - idl_compiler.type_check(ast, fill_symtab(symtab, effective_xlen), "#{name}.operation()") + idl_compiler.type_check(ast, fill_symtab(symtab, effective_xlen, ast), "#{name}.operation()") @type_checked_operation_ast[symtab.hash] = ast end + # @param symtab [SymbolTable] Symbol table with compilation context # @return [FunctionBodyAst] The abstract syntax tree of the instruction operation - def operation_ast(idl_compiler) + def operation_ast(symtab) return @operation_ast unless @operation_ast.nil? return nil if @data["operation()"].nil? # now, parse the operation - @operation_ast = idl_compiler.compile_inst_operation( + @operation_ast = symtab.archdef.idl_compiler.compile_inst_operation( self, + symtab:, input_file: @data["__source"], input_line: source_line("operation()") ) @@ -640,7 +682,7 @@ def extension_exclusions if @data.key?("excludedBy") if @data["exludedBy"].is_a?(Array) # could be either a single extension with exclusion, or a list of exclusions - if extension_exclusion?(@data["definedBy"][0]) + if extension_exclusion?(@data["excludedBy"][0]) @extension_exclusions << to_extension_requirement(@data["excludedBy"][0]) else # this is a list diff --git a/lib/arch_obj_models/obj.rb b/lib/arch_obj_models/obj.rb index 13fe3c9f5e..a205a8c28e 100644 --- a/lib/arch_obj_models/obj.rb +++ b/lib/arch_obj_models/obj.rb @@ -27,6 +27,10 @@ class ArchDefObject attr_reader :data, :name, :long_name, :description + def <=>(other) + name <=> other.name + end + # @return [String] Source file that data for this object can be attributed to # @return [nil] if the source isn't known def __source @@ -97,16 +101,18 @@ def defined_by?(*args) if args.size == 1 raise ArgumentError, "Parameter must be an ExtensionVersion" unless args[0].is_a?(ExtensionVersion) - defined_by.any? do |r| - r.satisfied_by?(args[0]) + defined_by.satisfied_by? do |r| + r.name == args[0].name && r.version_requirement.satisfied_by?(args[0].version) end elsif args.size == 2 raise ArgumentError, "First parameter must be an extension name" unless args[0].respond_to?(:to_s) - raise ArgumentError, "Second parameter must be an extension version" unless args[0].respond_to?(:to_s) + version = args[1].is_a?(Gem::Version) ? args[1] : Gem::Version.new(args[1]) - defined_by.any? do |r| - r.satisfied_by?(args[0].to_s, args[1].to_s) + defined_by.satisfied_by? do |r| + r.name == args[0] && r.version_requirement.satisfied_by?(version) end + else + raise ArgumentError, "Unsupported number of arguments of " + args.size end end @@ -119,50 +125,38 @@ def to_extension_requirement(obj) end private :to_extension_requirement + def to_extension_requirement_list(obj) + list = [] + if obj.is_a?(Array) + # could be either a single extension with exclusion, or a list of exclusions + if extension_exclusion?(obj[0]) + list << to_extension_requirement(obj[0]) + else + # this is a list + obj.each do |r| + list << to_extension_exclusion(r) + end + end + else + list << to_extension_requirement(obj) + end + list + end + def extension_requirement?(obj) obj.is_a?(String) && obj =~ /^([A-WY])|([SXZ][a-z]+)$/ || obj.is_a?(Array) && obj[0] =~ /^([A-WY])|([SXZ][a-z]+)$/ end private :extension_requirement? - # @return [Array] Extension(s) that define the instruction. If *any* requirement is met, the instruction is defined. + # @return [SchemaCondition] Extension(s) that define the instruction. If *any* requirement is met, the instruction is defined. def defined_by - return @defined_by unless @defined_by.nil? - - @defined_by = [] - # definedBy can be: - # - # * [String] Extension name - # * [Array] Extension name, version - # * [Array] Array of one of the two above - if @data["definedBy"].is_a?(Array) - if @data["definedBy"].size == 2 - if @data["definedBy"][1].is_a?(String) && @data["definedBy"][1] =~ /^<>=~$/ - @defined_by << to_extension_requirement(@data["definedBy"]) - elsif @data["definedBy"][1].is_a?(String) - # this is an array of extension names - @defined_by << to_extension_requirement(@data["definedBy"][0]) - @defined_by << to_extension_requirement(@data["definedBy"][1]) - else - # this is a list of extension requirements - @data["definedBy"].each do |r| - @defined_by << to_extension_requirement(r) - end - end - else - # this is a list of extension requirements - @data["definedBy"].each do |r| - @defined_by << to_extension_requirement(r) - end - end - else - raise "unexpected" unless @data["definedBy"].is_a?(String) - @defined_by << to_extension_requirement(@data["definedBy"]) - end - - raise "empty requirements" if @defined_by.empty? + SchemaCondition.new(@data["definedBy"]) + end - @defined_by + # @return [String] Name of an extension that "primarily" defines the object (i.e., is the first in a list) + def primary_defined_by + defined_by.first_requirement.name end # @return [Integer] THe source line number of +path+ in the YAML file @@ -251,10 +245,6 @@ def email = @data["email"] # @return [String] Company the person works for # @return [nil] if the company is not known, or if the person is an individual contributor def company = @data["company"] - - def <=>(other) - name <=> other.name - end end # represents a JSON Schema compoisition, e.g.: @@ -268,45 +258,129 @@ def <=>(other) class SchemaCondition # @param composition_hash [Hash] A possibly recursive hash of "allOf", "anyOf", "oneOf" def initialize(composition_hash) - raise ArgumentError, "Expecting a JSON schema composition" unless is_a_condition?(composition_hash) + unless is_a_condition?(composition_hash) + raise ArgumentError, "Expecting a JSON schema comdition (got #{composition_hash})" + end @hsh = composition_hash end + VERSION_REQ_REGEX = /^((>=)|(>)|(~>)|(<)|(<=)|(=))?\s*[0-9]+(\.[0-9]+(\.[0-9]+(-[a-fA-F0-9]+)?)?)?$/ + def is_a_version_requirement(ver) + case ver + when String + ver =~ VERSION_REQ_REGEX + when Array + ver.all? { |v| v =~ VERSION_REQ_REGEX } + else + false + end + end + + def to_asciidoc(cond = @hsh, indent = 0) + case cond + when String + "#{' ' * indent}* #{cond}, version >= 0" + when Hash + if cond.key?("name") + if cond.key?("version") + "#{' ' * indent}* #{cond['name']}, version #{cond['version']}\n" + else + "#{' ' * indent}* #{cond['name']}, version >= 0\n" + end + else + "#{' ' * indent}* #{cond.keys[0]}:\n" + to_asciidoc(cond[cond.keys[0]], indent + 2) + end + when Array + cond.map { |e| to_asciidoc(e, indent) }.join("\n") + else + raise "Unknown condition type: #{cond}" + end + end + def is_a_condition?(hsh) - return false unless hsh.is_a?(Hash) && hsh.keys.size == 1 && hsh[hsh.keys[0]].is_a?(Array) + case hsh + when String + true + when Hash + if hsh.key?("name") + return false if hsh.size > 2 + + if hsh.size > 1 + return false unless hsh.key?("version") + + return false unless is_a_version_requirement(hsh["version"]) + end + + else + return false unless hsh.size == 1 - return false unless ["allOf", "anyOf", "oneOf"].include?(hsh.keys[0]) + return false unless ["allOf", "anyOf", "oneOf"].include?(hsh.keys[0]) - hsh[hsh.keys[0]].each do |element| - if element.is_a?(Hash) - return false unless is_a_condition?(element) + hsh[hsh.keys[0]].each do |element| + return false unless is_a_condition?(element) + end end + else + raise "unexpected #{hsh.class.name} #{hsh}" end - return true + true end private :is_a_condition? + # @return [ExtensionRequirement] First requirement found, without considering any boolean operators + def first_requirement(req = @hsh) + case req + when String + ExtensionRequirement.new(req, ">= 0") + when Hash + if req.key?("name") + ExtensionRequirement.new(req["name"], req["version"] || ">= 0") + else + first_requirement(req[req.keys[0]]) + end + when Array + first_requirement(req[0]) + else + raise "unexpected" + end + end + def to_rb_helper(hsh) if hsh.is_a?(Hash) - key = hsh.keys[0] - - case key - when "allOf" - rb_str = hsh[key].map { |element| to_rb_helper(element) }.join(' && ') - "(#{rb_str})" - when "anyOf" - rb_str = hsh[key].map { |element| to_rb_helper(element) }.join(' || ') - "(#{rb_str})" - when "oneOf" - rb_str = hsh[key].map { |element| to_rb_helper(element) }.join(', ') - "([#{rb_str}].count(true) == 1)" + if hsh.key?("name") + if hsh.key?("version") + if hsh["version"].is_a?(String) + "(yield ExtensionRequirement.new('#{hsh["name"]}', '#{hsh["version"]}'))" + elsif hsh["version"].is_a?(Array) + "(yield ExtensionRequirement.new('#{hsh["name"]}', #{hsh["version"].map { |v| "'#{v}'" }.join(', ')}))" + else + raise "unexpected" + end + else + "(yield ExtensionRequirement.new('#{hsh["name"]}'))" + end else - "(yield #{hsh})" + key = hsh.keys[0] + + case key + when "allOf" + rb_str = hsh[key].map { |element| to_rb_helper(element) }.join(' && ') + "(#{rb_str})" + when "anyOf" + rb_str = hsh[key].map { |element| to_rb_helper(element) }.join(' || ') + "(#{rb_str})" + when "oneOf" + rb_str = hsh[key].map { |element| to_rb_helper(element) }.join(', ') + "([#{rb_str}].count(true) == 1)" + else + raise "Unexpected" + "(yield #{hsh})" + end end else - "(yield #{hsh})" + "(yield ExtensionRequirement.new('#{hsh}'))" end end diff --git a/lib/arch_obj_models/profile.rb b/lib/arch_obj_models/profile.rb index adf78b33c1..0d88e6b76a 100644 --- a/lib/arch_obj_models/profile.rb +++ b/lib/arch_obj_models/profile.rb @@ -14,15 +14,15 @@ def initialize(data, arch_def) def family = arch_def.profile_family(@data["family"]) - # @return [Profile] Profiles this one inherits from + # @return [Profile] Profile that this profile inherits from # @return [nil] if this profile has no parent - def inherits = arch_def.profile(@data["inherits"]) + def inherits_from = arch_def.profile(@data["inherits"]) # @return ["M", "S", "U", "VS", "VU"] Privilege mode for the profile def mode if @data["mode"].nil? - raise "No mode specified an no inheritance for profile '#{name}'" if inherits.empty? - inherits.last.mode + raise "No mode specified and no inheritance for profile '#{name}'" if inherits_from.nil? + inherits_from.mode else @data["mode"] end @@ -31,9 +31,9 @@ def mode # @return [32, 64] The base XLEN for the profile def base if @data["base"].nil? - raise "No base specified an no inheritance for profile '#{name}'" if inherits.empty? + raise "No base specified and no inheritance for profile '#{name}'" if inherits_from.nil? - inherits.last.base + inherits_from.base else @data["base"] end @@ -61,8 +61,8 @@ def contributors @data["contributors"].map { |data| Person.new(data) } end - # @return [String] Given an extension +ext_name+, return the status - def extension_status(ext_name) + # @return [String] Given an extension +ext_name+, return the presence + def extension_presence(ext_name) if mandatory?(ext_name) req = mandatory_extension_requirements.find do |req| req.name == ext_name @@ -81,45 +81,31 @@ def extension_status(ext_name) # @return [String] The note associated with extension +ext_name+ # @return [nil] if there is no note for +ext_name+ def extension_note(ext_name) - unless @data.dig("extensions", "mandatory").nil? - ext = @data["extensions"]["mandatory"].find { |e| e["name"] == ext_name } - return ext["note"] unless ext.nil? - end - - unless @data.dig("extensions", "optional").nil? - ext = @data["extensions"]["optional"].find { |e| e["name"] == ext_name } - return ext["note"] unless ext.nil? - end - - unless @data.dig("extensions", "excluded").nil? - ext = @data["extensions"]["excluded"].find { |e| e["name"] == ext_name } - return ext["note"] unless ext.nil? - end - - nil + ext = @data["extensions"].find { |e| e["name"] == ext_name } + return ext["note"] unless ext.nil? end # @return [Array] List of mandatory extensions for the profile def mandatory_extension_requirements - return @mandatory_extensions unless @mandatory_extensions.nil? + return @mandatory_ext_reqs unless @mandatory_ext_reqs.nil? - @mandatory_extensions = [] - @mandatory_extensions += inherits.mandatory_extension_requirements unless inherits.nil? + @mandatory_ext_reqs = [] + @mandatory_ext_reqs += inherits_from.mandatory_extension_requirements unless inherits_from.nil? # we need to remove anything that was changed from inheritance unless @data["extensions"].nil? - @mandatory_extensions.delete_if { |ext_req| - @data["extensions"]["optional"]&.any? { |opt| opt["name"] == ext_req.name } || - @data["extensions"]["removed"]&.any? { |opt| opt["name"] == ext_req.name } || - @data["extensions"]["mandatory"]&.any? { |opt| opt["name"] == ext_req.name } + @mandatory_ext_reqs.delete_if { |ext_req| + @data["extensions"]&.any? { |opt| opt["name"] == ext_req.name } } - @data["extensions"]["mandatory"]&.each do |ext_ver| - @mandatory_extensions << ExtensionRequirement.new(ext_ver["name"], ext_ver["version"]) + @data["extensions"]&.each do |ext_req| + if ext_req["presence"] == "mandatory" + @mandatory_ext_reqs << ExtensionRequirement.new(ext_req["name"], ext_req["version"], presence: "mandatory") + end end end - @mandatory_extensions + @mandatory_ext_reqs end # @return [Array] List of mandatory extensions @@ -142,25 +128,25 @@ def mandatory?(ext_name) # @return [Array] List of optional extensions for the profile def optional_extension_requirements - return @optional_extensions unless @optional_extensions.nil? + return @optional_ext_reqs unless @optional_ext_reqs.nil? - @optional_extensions = [] - @optional_extensions += inherits.optional_extension_requirements unless inherits.nil? + @optional_ext_reqs = [] + @optional_ext_reqs += inherits_from.optional_extension_requirements unless inherits_from.nil? # we need to remove anything that was changed from inheritance unless @data["extensions"].nil? - @optional_extensions.delete_if { |ext_req| - @data["extensions"]["optional"]&.any? { |opt| opt["name"] == ext_req.name } || - @data["extensions"]["removed"]&.any? { |opt| opt["name"] == ext_req.name } || - @data["extensions"]["mandatory"]&.any? { |opt| opt["name"] == ext_req.name } + @optional_ext_reqs.delete_if { |ext_req| + @data["extensions"]&.any? { |opt| opt["name"] == ext_req.name } } - @data["extensions"]["optional"]&.each do |ext_ver| - @optional_extensions << ExtensionRequirement.new(ext_ver["name"], ext_ver["version"]) + @data["extensions"]&.each do |ext_ver| + if ext_ver["presence"] == "optional" + @optional_ext_reqs << ExtensionRequirement.new(ext_ver["name"], ext_ver["version"], presence: "optional") + end end end - @optional_extensions + @optional_ext_reqs end # @return [Array] List of optional extensions diff --git a/lib/arch_obj_models/schema.rb b/lib/arch_obj_models/schema.rb new file mode 100644 index 0000000000..cebf5eb671 --- /dev/null +++ b/lib/arch_obj_models/schema.rb @@ -0,0 +1,142 @@ +#frozen_string_literal: true + +class Schema + def initialize(schema_hash) + raise ArgumentError, "Expecting hash" unless schema_hash.is_a?(Hash) + + @schema_hash = schema_hash + end + + def to_pretty_s(schema_hash = @schema_hash) + raise ArgumentError, "Expecting hash" unless schema_hash.is_a?(Hash) + raise ArgumentError, "Expecting non-empty hash" if schema_hash.empty? + + if schema_hash.key?("const") + large2hex(schema_hash["const"]) + elsif schema_hash.key?("enum") + "[#{schema_hash["enum"].join(', ')}]" + elsif schema_hash.key?("type") + case schema_hash["type"] + when "integer" + min = schema_hash["minimum"] + minstr = large2hex(min) + max = schema_hash["maximum"] + maxstr = large2hex(max) + if min && max + sz = num_bits(min, max) + (sz > 0) ? "#{sz}-bit integer" : "#{minstr} to #{maxstr}" + elsif min + "≥ #{minstr}" + elsif max + "≤ #{maxstr}" + else + "integer" + end + when "string" + format = schema_hash["format"] + pattern = schema_hash["pattern"] + if format + format + elsif pattern + "string matching #{pattern}" + else + "string" + end + when "boolean" + "boolean" + when "array" + items = schema_hash["items"] + min_items = schema_hash["minItems"] + max_items = schema_hash["maxItems"] + size_str = if min_items && max_items + if min_items == max_items + "#{min_items}-element " + else + "#{min_items}-element to #{max_items}-element " + end + elsif min_items + "at least #{min_items}-element " + elsif max_items + "at most #{max_items}-element " + else + "" + end + + if items.nil? + size_str + "array" + else + if items.is_a?(Hash) + "#{size_str}array of #{to_pretty_s(items)}" + elsif items.is_a?(Array) + str = size_str + "array where: +\n" + items.each_with_index do |item,index| + str = str + "  [#{index}] is #{to_pretty_s(item)} +\n" + end + additional_items = schema_hash["additionalItems"] + if additional_items + str = str + "additional items are: +\n  " + + to_pretty_s(additional_items) + end + str + else + raise "to_pretty_s unknown array items #{items} in #{schema_hash}" + end + end + else + raise "to_pretty_s unknown type #{schema_hash["type"]} in #{schema_hash}" + end + elsif schema_hash.key?("contains") + "Contains : [#{to_pretty_s(schema_hash["contains"])}]" + else + raise "TODO: to_pretty_s schema for #{schema_hash}" + end + end + + # Convert large integers to hex str. + def large2hex(value) + if value.nil? + "" + elsif value.is_a?(Integer) + (value > 999) ? "0x" + value.to_s(16) : value.to_s + else + value.to_s + end + end + + def merge!(other_schema) + raise ArgumentError, "Expecting Schema" unless (other_schema.is_a?(Schema) || other_schema.is_a?(Hash)) + + hash = other_schema.is_a?(Schema) ? other_schema.instance_variable_get(:@schema_hash) : other_schema + + @schema_hash.merge!(hash) + + self + end + + def empty? + @schema_hash.empty? + end + + def single_value? + @schema_hash.key?("const") + end + + def value + raise "Schema is not a single value" unless single_value? + + @schema_hash["const"] + end + + def is_power_of_two?(num) + return false if num < 1 + return (num & (num-1)) == 0 + end + + # If min to max range represents an unsigned number of bits, return the number of bits. + # Otherwise return 0 + def num_bits(min, max) + return 0 unless min == 0 + is_power_of_two?(max+1) ? max.bit_length : 0 + end +end + diff --git a/lib/asciidoc_extensions.js b/lib/asciidoc_extensions.js new file mode 100644 index 0000000000..7da2f377b4 --- /dev/null +++ b/lib/asciidoc_extensions.js @@ -0,0 +1,3 @@ +const asciidoctor = require('asciidoctor')() +const registry = asciidoctor.Extensions.create() +require('./asciidoc_when_extension.js')(registry) \ No newline at end of file diff --git a/lib/idl.rb b/lib/idl.rb index fc094a16fb..47250ddb2e 100644 --- a/lib/idl.rb +++ b/lib/idl.rb @@ -41,7 +41,7 @@ def initialize(arch_def) @arch_def = arch_def end - def compile_file(path, symtab: nil, type_check: true) + def compile_file(path) @parser.set_input_file(path.to_s) m = @parser.parse path.read @@ -91,24 +91,13 @@ def compile_file(path, symtab: nil, type_check: true) MSG end - include_ast = compile_file(include_path, symtab: nil, type_check: false) + include_ast = compile_file(include_path) include_ast.set_input_file_unless_already_set(include_path) ast.replace_include!(child, include_ast) end # we may have already set an input file from an include, so only set it if it's not already set ast.set_input_file_unless_already_set(path.to_s) - if type_check - begin - ast.type_check(symtab) - rescue AstNode::TypeError, AstNode::InternalError, AstNode::ValueError => e - warn "\n" - warn e.what - warn e.bt - exit 1 - end - ast.freeze_tree - end ast end @@ -138,12 +127,13 @@ def compile_func_body(body, return_type: nil, symtab: nil, name: nil, input_file # fix up left recursion ast = m.to_ast ast.set_input_file(input_file, input_line) + ast.freeze_tree(symtab) # type check unless type_check == false cloned_symtab = symtab.deep_clone - cloned_symtab.push + cloned_symtab.push(ast) cloned_symtab.add("__expected_return_type", return_type) unless return_type.nil? extra_syms.each { |k, v| @@ -179,7 +169,6 @@ def compile_func_body(body, return_type: nil, symtab: nil, name: nil, input_file cloned_symtab.pop end - ast.freeze_tree end ast @@ -188,11 +177,11 @@ def compile_func_body(body, return_type: nil, symtab: nil, name: nil, input_file # compile an instruction operation, and return the abstract syntax tree # # @param inst [Instruction] Instruction object - # @param symtab [SymbolTable] Symbol table to use for type checking + # @param symtab [SymbolTable] Symbol table # @param input_file [Pathname] Path to the input file this source comes from # @param input_line [Integer] Starting line in the input file that this source comes from # @return [Ast] The root of the abstract syntax tree - def compile_inst_operation(inst, input_file: nil, input_line: 0) + def compile_inst_operation(inst, symtab:, input_file: nil, input_line: 0) operation = inst["operation()"] @parser.set_input_file(input_file, input_line) @@ -208,7 +197,7 @@ def compile_inst_operation(inst, input_file: nil, input_line: 0) # fix up left recursion ast = m.to_ast ast.set_input_file(input_file, input_line) - ast.freeze_tree + ast.freeze_tree(symtab) ast end @@ -221,13 +210,22 @@ def compile_inst_operation(inst, input_file: nil, input_line: 0) # @raise AstNode::TypeError if a type error is found def type_check(ast, symtab, what) # type check + raise "Tree should be frozen" unless ast.frozen? + begin - ast.type_check(symtab) - rescue AstNode::TypeError, AstNode::ValueError => e - warn "While type checking #{what}:" - warn e.what - warn e.backtrace - exit 1 + value_result = AstNode.value_try do + ast.type_check(symtab) + end + AstNode.value_else(value_result) do + warn "While type checking #{what}, got a value error on:" + warn ast.text_value + warn AstNode.value_error_reason + warn symtab.callstack + unless AstNode.value_error_ast.nil? + warn "At #{AstNode.value_error_ast.input_file}:#{AstNode.value_error_ast.lineno}" + end + exit 1 + end rescue AstNode::InternalError => e warn "While type checking #{what}:" warn e.what @@ -235,8 +233,6 @@ def type_check(ast, symtab, what) exit 1 end - ast.freeze_tree - ast end @@ -252,6 +248,7 @@ def compile_expression(expression, symtab, pass_error: false) ast = m.to_ast ast.set_input_file("[EXPRESSION]", 0) + ast.freeze_tree(symtab) begin ast.type_check(symtab) rescue AstNode::TypeError => e @@ -270,7 +267,6 @@ def compile_expression(expression, symtab, pass_error: false) exit 1 end - ast.freeze_tree ast end diff --git a/lib/idl/ast.rb b/lib/idl/ast.rb index b321c9e5be..c8de487681 100644 --- a/lib/idl/ast.rb +++ b/lib/idl/ast.rb @@ -1,4 +1,4 @@ -# frozen_string_literal: false +# frozen_string_literal: true require 'benchmark' @@ -39,6 +39,8 @@ def space? = false end module Idl + EMPTY_ARRAY = [].freeze + # base class for all nodes considered part of the Ast # @abstract class AstNode @@ -62,6 +64,9 @@ class AstNode # @retrun [Range] Range within the input for this node attr_reader :interval + # @return [String] The IDL source of this node + attr_reader :text_value + # @retrun [AstNode] The parent node # @retrun [nil] if this is the root of the tree attr_reader :parent @@ -142,6 +147,20 @@ def message end end + def self.value_try(&block) + catch(:value_error) do + yield block + end + end + def value_try(&block) = return self.class.value_try(&block) + + def self.value_else(value_result, &block) + return unless value_result == :unknown_value + + yield block + end + def value_else(value_result, &block) = self.class.value_else(value_result, &block) + # @param input [String] The source being compiled # @param interval [Range] The range in the source corresponding to this AstNode # @param children [Array] Children of this node @@ -150,6 +169,7 @@ def initialize(input, interval, children) @input_file = nil @starting_line = 0 @interval = interval + @text_value = input[interval] children.each { |child| raise ArgumentError, "Children of #{self.class.name} must be AstNodes (found a #{child.class.name})" unless child.is_a?(AstNode)} @children = children @parent = nil # will be set later unless this is the root @@ -203,10 +223,6 @@ def find_ancestor(klass) end end - def text_value - input[interval] - end - # @return [String] returns +-2 lines around the current interval def lines_around cnt = 0 @@ -293,13 +309,25 @@ def internal_error(reason) raise AstNode::InternalError, msg end + @value_error_reason = nil + @value_error_ast = nil + class << self + attr_accessor :value_error_reason, :value_error_ast + end + # raise a value error, indicating that the value is not known at compile time # # @param reason [String] Error message # @raise [AstNode::ValueError] always - def value_error(reason) - raise AstNode::ValueError.new(lineno, input_file, reason) + def self.value_error(reason, ast = nil) + AstNode.value_error_reason = reason + AstNode.value_error_ast = ast + # warn reason + # warn "At #{ast.input_file}:#{ast.lineno}" unless ast.nil? + throw(:value_error, :unknown_value) + #raise AstNode::ValueError.new(lineno, input_file, reason), reason, [] end + def value_error(reason) = self.class.value_error(reason, self) # unindent a multiline string, getting rid of all common leading whitespace (like <<~ heredocs) # @@ -323,9 +351,17 @@ def print_ast(indent = 0, indent_size: 2, io: $stdout) end end - # freeze the entire tree from further modification - def freeze_tree - @children.each { |child| child.freeze_tree } + # @!macro [new] freeze_tree + # + # freeze the entire tree from further modification + # This is also an opportunity to pre-calculate anything that only needs global symbols + # + # @param global_symtab [SymbolTable] Symbol table with global scope populated + + + # @!macro freeze_tree + def freeze_tree(global_symtab) + @children.each { |child| child.freeze_tree(global_symtab) } freeze end @@ -514,7 +550,9 @@ class IdAst < AstNode def name = text_value def initialize(input, interval) - super(input, interval, []) + super(input, interval, EMPTY_ARRAY) + @const = (text_value[0] == text_value[0].upcase) + @vars = {} end # @!macro type_check @@ -524,20 +562,41 @@ def type_check(symtab) # @!macro type_no_archdef def type(symtab) + return @type unless @type.nil? + internal_error "Symbol '#{name}' not found" if symtab.get(name).nil? sym = symtab.get(name) - if sym.is_a?(Type) - sym - elsif sym.is_a?(Var) - sym.type - else - internal_error "Unexpected object on the symbol table" - end + # @type = + if sym.is_a?(Type) + sym + elsif sym.is_a?(Var) + sym.type + else + internal_error "Unexpected object on the symbol table" + end end - # @!macro value_no_archdef + # @return [Boolean] whether or not the Id represents a const + def const? = @const + + # @!macro value def value(symtab) + # can't do this.... a const might be in a template function, with different values at call time + # if @const + # # consts never change, so we can look them up by arch_def + # var = @vars[symtab.archdef] + # if var.nil? + # var = symtab.get(name) + # @vars[symtab.archdef] = var + # end + # type_error "Variable '#{name}' was not found" if var.nil? + # value_error "Value of '#{name}' not known" if var.value.nil? + # value_error "Value of #{name} is unknown" if var.value == :unknown + + # return var.value + # end + var = symtab.get(name) type_error "Variable '#{name}' was not found" if var.nil? @@ -570,6 +629,7 @@ def to_ast # 0, 0, 0, 0, 0, 0, 0, 0]; class GlobalWithInitializationAst < AstNode include Executable + include Declaration # @return [VariableDeclationWithInitializationAst] The initializer def var_decl_with_init @@ -596,6 +656,13 @@ def value(symtab) var_decl_with_init.value(symtab) end + def add_symbol(symtab) + raise "Symtab should be at global scope" unless symtab.levels == 1 + + # globals never have a compile-time value + var_decl_with_init.add_symbol(symtab) + end + # @1macro to_idl def to_idl var_decl_with_init.to_idl @@ -630,8 +697,11 @@ def type(symtab) end def add_symbol(symtab) + internal_error "Should be at global scope" unless symtab.levels == 1 + declaration.add_symbol(symtab) end + end # @api private @@ -666,6 +736,19 @@ def structs = definitions.select { |e| e.is_a?(StructDefinitionAst) } # @return {Array] List of all function definitions def functions = definitions.select { |e| e.is_a?(FunctionDefAst) } + # Add all the global symbols to symtab + # + # @param symtab [SymbolTable] symbol table + def add_global_symbols(symtab) + raise "Symtab is not at global scope" unless symtab.levels == 1 + + enums.each { |g| g.add_symbol(symtab) } + bitfields.each { |g| g.add_symbol(symtab) } + globals.each { |g| g.add_symbol(symtab) } + structs.each { |g| g.add_symbol(symtab) } + functions.each { |g| g.add_symbol(symtab) } + end + # replaces an include statement with the ast in that file, making # it a direct child of this IsaAst # @@ -701,11 +784,13 @@ def initialize(input, interval, expression) end def type_check(symtab) - type_error "#{expression.text_value} is not an array" unless expression.type(symtab).kind == :array - if symtab.archdef.is_a?(ImplArchDef) - type_error "#{expression.text_value} must have a known value at compile time" if expression.type(symtab).width == :unknown - else - type_error "#{expression.text_value} must be a constant" unless expression.type(symtab).const? + expression.type_check(symtab) + expression_type = expression.type(symtab) + type_error "#{expression.text_value} is not an array" unless expression_type.kind == :array + type_error "#{expression.text_value} must be a constant" unless expression_type.const? + + if symtab.archdef.fully_configured? && (expression_type.width == :unknown) + type_error "#{expression.text_value} must have a known value at compile time" end end @@ -791,6 +876,53 @@ def value(symtab) def to_idl = "$enum_element_size(#{enum_class.to_idl})" end + class EnumCastSyntaxNode < Treetop::Runtime::SyntaxNode + def to_ast + EnumCastAst.new(input, interval, user_type_name.to_ast, expression.to_ast) + end + end + + class EnumCastAst < AstNode + include Rvalue + + # @return [UserTypeAst] Enum name + def enum_name = @children[0] + + # @return [Rvalue] Value expression + def expression = @children[1] + + def initialize(input, interval, user_type_name, expression) + super(input, interval, [user_type_name, expression]) + end + + def type_check(symtab) + enum_name.type_check(symtab) + expression.type_check(symtab) + + if expression.type(symtab).kind != :bits + type_error "Can only cast from Bits to enum" + end + + enum_def_type = symtab.get(enum_name.text_value) + type_error "No enum named #{enum_name.text_value}" if enum_def_type.nil? + + value_try do + unless enum_def_type.element_values.include?(expression.value(symtab)) + type_error "#{expression.value(symtab)} is not a value in enum #{enum_name.text_value}" + end + end + end + + def type(symtab) + enum_def_type = symtab.get(enum_name.text_value) + Type.new(:enum_ref, enum_class: enum_def_type) + end + + def value(symtab) = expression.value(symtab) + + def to_idl = "$enum(#{enum_name.to_idl}, #{expression.to_idl})" + end + class EnumArrayCastSyntaxNode < Treetop::Runtime::SyntaxNode def to_ast EnumArrayCastAst.new(input, interval, user_type_name.to_ast) @@ -815,7 +947,7 @@ def type(symtab) Type.new( :array, width: enum_class.type(symtab).element_values.size, - sub_type: Type.new(:bits, width: enum_class.type(symtab).width), + sub_type: Type.new(:bits, width: enum_class.type(symtab).width, qualifiers: [:const]), qualifiers: [:const] ) end @@ -861,6 +993,7 @@ def to_ast # VU 0b100 # } class EnumDefinitionAst < AstNode + include Declaration def initialize(input, interval, user_type, element_names, element_values) super(input, interval, [user_type] + element_names + element_values.reject{ |e| e.nil? }) @@ -914,6 +1047,9 @@ def type_check(symtab) # @!macro add_symbol def add_symbol(symtab) + internal_error "All enums should be declared in global scope" unless symtab.levels == 1 + + internal_error "Type is nil?" if type(symtab).nil? symtab.add!(name, type(symtab)) end @@ -951,11 +1087,19 @@ def to_ast # builtin enum ExtensionName # class BuiltinEnumDefinitionAst < AstNode + include Declaration + def initialize(input, interval, user_type) super(input, interval, [user_type]) @user_type = user_type end + def freeze_tree(global_symtab) + # call type to get it set before we freeze the object + type(global_symtab) + freeze + end + # @!macro type_check_no_args def type_check(_symtab) case @user_type.text_value @@ -966,8 +1110,48 @@ def type_check(_symtab) end end + def element_names(symtab) + case name + when "ExtensionName" + symtab.archdef.extensions.map(&:name) + when "ExceptionCode" + symtab.archdef.exception_codes.map(&:var) + when "InterruptCode" + symtab.archdef.interrupt_codes.map(&:var) + else + type_error "Unknown builtin enum type '#{name}'" + end + end + + def element_values(symtab) + case name + when "ExtensionName" + (0...symtab.archdef.extensions.size).to_a + when "ExceptionCode" + symtab.archdef.exception_codes.map(&:num) + when "InterruptCode" + symtab.archdef.interrupt_codes.map(&:num) + else + type_error "Unknown builtin enum type '#{name}'" + end + end + # @!macro type_no_archdef - def type(symtab) = symtab.get(@user_type.text_value) + def type(symtab) + return @type unless @type.nil? + + @type = EnumerationType.new(name, element_names(symtab), element_values(symtab)) + end + + # @!macro add_symbol + def add_symbol(symtab) + internal_error "All enums should be declared in global scope" unless symtab.levels == 1 + + symtab.add!(name, type(symtab)) + end + + # @return [String] name of the enum class + def name = @user_type.text_value # @!macro to_idl def to_idl = "builtin enum #{@user_type.text_value}" @@ -992,18 +1176,22 @@ def initialize(input, interval, name, msb, lsb) # @!macro type_check def type_check(symtab) @msb.type_check(symtab) - begin + + value_result = value_try do @msb.value(symtab) - rescue ValueError + end + value_else(value_result) do @msb.type_error "Bitfield position must be compile-time-known" end - unless @lsb.nil? - @lsb.type_check(symtab) - begin - @lsb.value(symtab) - rescue ValueError - @lsb.type_error "Bitfield position must be compile-time-known" - end + + return if @lsb.nil? + + @lsb.type_check(symtab) + value_result = value_try do + @lsb.value(symtab) + end + value_else(value_result) do + @lsb.type_error "Bitfield position must be compile-time-known" end end @@ -1057,6 +1245,8 @@ def to_ast # V 0 # } class BitfieldDefinitionAst < AstNode + include Declaration + def initialize(input, interval, name, size, fields) super(input, interval, [name, size] + fields) @@ -1065,6 +1255,17 @@ def initialize(input, interval, name, size, fields) @fields = fields end + # @!macro freeze_tree + def freeze_tree(global_symtab) + type(global_symtab) + freeze + end + + # @return [Integer] The number of bits in the Bitfield + def size(symtab) + @size.value(symtab) + end + # @return [Array] Array of all element names, in the same order as those from {#element_ranges} def element_names return @element_names unless @element_names.nil? @@ -1095,12 +1296,25 @@ def type_check(symtab) # @!macro add_symbol def add_symbol(symtab) + internal_error "All Bitfields should be declared at global scope" unless symtab.levels == 1 + t = type(symtab) + internal_error "Type is nil" if t.nil? + symtab.add!(name, t) end # @!macro type_no_args - def type(symtab) = BitfieldType.new(name, @size.value(symtab), element_names, element_ranges(symtab)) + def type(symtab) + return @type unless @type.nil? + + @type = BitfieldType.new( + name, + @size.value(symtab), + element_names, + element_ranges(symtab) + ) + end # @return [String] bitfield name def name = @name.text_value @@ -1172,6 +1386,8 @@ def type_check(symtab) def type(symtab) @type = StructType.new(@name, @member_types.map do |t| member_type = t.type(symtab) + type_error "Type #{t.text_value} is not known" if member_type.nil? + member_type = Type.new(:enum_ref, enum_class: member_type) if member_type.kind == :enum member_type end, @member_names) @@ -1179,6 +1395,8 @@ def type(symtab) # @!macro add_symbol def add_symbol(symtab) + internal_error "Structs should be declared at global scope" unless symtab.levels == 1 + t = type(symtab) symtab.add!(name, t) end @@ -1238,12 +1456,13 @@ class AryAccessSyntaxNode < Treetop::Runtime::SyntaxNode def to_ast var = a.to_ast brackets.elements.each do |bracket| - var = if bracket.msb.empty? - AryElementAccessAst.new(input, interval, var, bracket.lsb.to_ast) - else - AryRangeAccessAst.new(input, interval, var, - bracket.msb.expression.to_ast, bracket.lsb.to_ast) - end + var = + if bracket.msb.empty? + AryElementAccessAst.new(input, interval, var, bracket.lsb.to_ast) + else + AryRangeAccessAst.new(input, interval, var, + bracket.msb.expression.to_ast, bracket.lsb.to_ast) + end end var @@ -1277,23 +1496,19 @@ def type_check(symtab) type_error "Array index must be integral" unless index.type(symtab).integral? if var.type(symtab).kind == :array - begin + value_result = value_try do index_value = index.value(symtab) type_error "Array index out of range" if index_value >= var.type(symtab).width - rescue ValueError - # Ok, doesn't need to be known - end + end # Ok, doesn't need to be known elsif var.type(symtab).integral? if var.type(symtab).kind == :bits - begin + value_result = value_try do index_value = index.value(symtab) if index_value >= var.type(symtab).width type_error "Bits element index (#{index_value}) out of range (max #{var.type(symtab).width - 1}) in access '#{text_value}'" end - rescue ValueError - # OK, doesn need to be known - end + end # OK, doesn need to be known end else @@ -1355,32 +1570,29 @@ def type_check(symtab) type_error "Range MSB must be an integral type" unless msb.type(symtab).integral? type_error "Range LSB must be an integral type" unless lsb.type(symtab).integral? - begin + value_result = value_try do msb_value = msb.value(symtab) lsb_value = lsb.value(symtab) if var.type(symtab).kind == :bits && msb_value >= var.type(symtab).width type_error "Range too large for bits (msb = #{msb_value}, range size = #{var.type(symtab).width})" - end + end range_size = msb_value - lsb_value + 1 type_error "zero/negative range (#{msb_value}:#{lsb_value})" if range_size <= 0 - rescue ValueError - # OK, don't have to know - end + end # OK, don't have to know end # @!macro type def type(symtab) - begin + value_result = value_try do msb_value = msb.value(symtab) lsb_value = lsb.value(symtab) range_size = msb_value - lsb_value + 1 - Type.new(:bits, width: range_size) - rescue ValueError - # don't know the width at compile time....assume the worst - var.type(symtab) + return Type.new(:bits, width: range_size) end + # don't know the width at compile time....assume the worst + value_else(value_result) { var.type(symtab) } end # @!macro value @@ -1449,31 +1661,44 @@ def rhs = @children[1] def initialize(input, interval, lhs_ast, rhs_ast) super(input, interval, [lhs_ast, rhs_ast]) + @vars = {} end # @!macro type_check def type_check(symtab) lhs.type_check(symtab) + type_error "Cannot assign to a const" if lhs.type(symtab).const? + rhs.type_check(symtab) unless rhs.type(symtab).convertable_to?(lhs.type(symtab)) type_error "Incompatible type in assignment (#{lhs.type(symtab)}, #{rhs.type(symtab)})" end end + def var(symtab) + variable = @vars[symtab.archdef] + if variable.nil? + variable = symtab.get(lhs.text_value) + @vars[symtab.archdef] = variable + end + variable + end + # @!macro execute def execute(symtab) if lhs.is_a?(CsrWriteAst) value_error "CSR writes are never compile-time-known" else - variable = symtab.get(lhs.text_value) + variable = var(symtab) internal_error "No variable #{lhs.text_value}" if variable.nil? - begin + value_result = value_try do variable.value = rhs.value(symtab) - rescue ValueError + end + value_else(value_result) do variable.value = nil - raise + value_error "" end end end @@ -1483,7 +1708,7 @@ def execute_unknown(symtab) if lhs.is_a?(CsrWriteAst) value_error "CSR writes are never compile-time-known" else - variable = symtab.get(lhs.text_value) + variable = var(symtab) internal_error "No variable #{lhs.text_value}" if variable.nil? @@ -1528,12 +1753,11 @@ def type_check(symtab) type_error "Index must be integral" unless idx.type(symtab).integral? - begin + value_result = value_try do idx_value = idx.value(symtab) type_error "Array index (#{idx.text_value} = #{idx_value}) out of range (< #{var.type(symtab).width})" if idx_value >= lhs.type(symtab).width - rescue ValueError - # OK, doesn't need to be known end + # OK, doesn't need to be known rhs.type_check(symtab) @@ -1560,18 +1784,20 @@ def execute(symtab) when :array idx_value = idx.value(symtab) lhs_value = lhs.value(symtab) - begin + value_result = value_try do lhs_value[idx_value] = rhs.value(symtab) - rescue ValueError + end + value_else(value_result) do lhs_value[idx_value] = nil - raise + value_error "right-hand side of array element assignment is unknown" end when :bits var = symtab.get(lhs.text_value) - begin + value_result = value_try do v = rhs.value(symtab) var.value = (lhs.value & ~0) | ((v & 1) << idx.value(symtab)) - rescue ValueError + end + value_else(value_result) do var.value = nil end else @@ -1584,24 +1810,27 @@ def execute_unknown(symtab) case lhs.type(symtab).kind when :array lhs_value = lhs.value(symtab) - begin + value_result = value_try do idx_value = idx.value(symtab) - begin + value_result = value_try do lhs_value[idx_value] = rhs.value(symtab) - rescue ValueError + end + value_else(value_result) do lhs_value[idx_value] = nil - raise + value_error "right-hand side of array element assignment is unknown" end - rescue ValueError + end + value_else(value_result) do # the idx isn't known; the entire array must become unknown - lhs_value.map! { |v| nil } + lhs_value.map! { |_v| nil } end when :bits var = symtab.get(lhs.text_value) - begin + value_result = value_try do v = rhs.value(symtab) var.value = (lhs.value & ~0) | ((v & 1) << idx.value(symtab)) - rescue ValueError + end + value_else(value_result) do var.value = nil end else @@ -1647,15 +1876,14 @@ def type_check(symtab) type_error "MSB must be integral" unless msb.type(symtab).integral? type_error "LSB must be integral" unless lsb.type(symtab).integral? - begin + value_result = value_try do msb_value = msb.value(symtab) lsb_value = lsb.value(symtab) type_error "MSB must be > LSB" unless msb_value > lsb_value type_error "MSB is out of range" if msb_value >= variable.type(symtab).width - rescue ValueError - # OK, don't have to know the value end + # OK, don't have to know the value write_value.type_check(symtab) @@ -1672,7 +1900,7 @@ def rhs def execute(symtab) return if variable.type(symtab).global? - begin + value_result = value_try do var_val = variable.value(symtab) msb_val = msb.value(symtab) @@ -1688,9 +1916,11 @@ def execute(symtab) var_val | ((rval_val << lsb_val) & mask) symtab.add(variable.name, Var.new(variable.name, variable.type(symtab), var_val)) - rescue ValueError + :ok + end + value_else(value_result) do symtab.add(variable.name, Var.new(variable.name, variable.type(symtab))) - raise + value_error "Either the range or right-hand side of an array range assignemnt is unknown" end end @@ -1780,7 +2010,11 @@ def initialize(input, interval, csr_field, write_value) def type(symtab) if field(symtab).defined_in_all_bases? - Type.new(:bits, width: [field(symtab).location(symtab.archdef, 32).size, field(symtab).location(symtab.archdef, 64).size].max) + if symtab.archdef.mxlen == 64 && symtab.archdef.multi_xlen? + Type.new(:bits, width: [field(symtab).location(symtab.archdef, 32).size, field(symtab).location(symtab.archdef, 64).size].max) + else + Type.new(:bits, width: field(symtab).location(symtab.archdef, symtab.archdef.mxlen).size) + end elsif field(symtab).base64_only? Type.new(:bits, width: field(symtab).location(symtab.archdef, 64).size) elsif field(symtab).base32_only? @@ -1796,9 +2030,12 @@ def field(symtab) def type_check(symtab) csr_field.type_check(symtab) - if ["RO", "RO-H"].any?(csr_field.field_def(symtab).type(symtab.archdef)) - type_error "Cannot write to read-only CSR field" + value_try do + if ["RO", "RO-H"].any?(csr_field.field_def(symtab).type(symtab)) + type_error "Cannot write to read-only CSR field" + end end + # ok, we don't know the type because the archdef isn't configured write_value.type_check(symtab) type_error "Incompatible type in assignment" unless write_value.type(symtab).convertable_to?(type(symtab)) @@ -1877,7 +2114,7 @@ def type_check(symtab) # @!macro execute def execute(symtab) - begin + value_result = value_try do values = function_call.execute(symtab) i = 0 @@ -1890,11 +2127,12 @@ def execute(symtab) var.value = values[i] i += 1 end - rescue ValueError + end + value_else(value_result) do variables.each do |v| symtab.get(v.text_value).value = nil end - raise + value_error "value of right-hand side of multi-variable assignment is unknown" end end @@ -2015,11 +2253,12 @@ def decl_type(symtab) # dtype = dtype.clone.qualify(q.text_value.to_sym) unless q.empty? unless ary_size.nil? - begin - dtype = Type.new(:array, width: ary_size.value(symtab), sub_type: dtype.clone, qualifiers:) - rescue ValueError - type_error "Array size must be known at compile time" if symtab.archdef.is_a?(ImplArchDef) - dtype = Type.new(:array, width: :unknown, sub_type: dtype.clone, qualifiers:) + value_result = value_try do + dtype = Type.new(:array, width: ary_size.value(symtab), sub_type: dtype, qualifiers:) + end + value_else(value_result) do + type_error "Array size must be known at compile time" if symtab.archdef.fully_configured? + dtype = Type.new(:array, width: :unknown, sub_type: dtype, qualifiers:) end end @@ -2029,7 +2268,7 @@ def decl_type(symtab) def type(symtab) = decl_type(symtab) # @!macro type_check - def type_check(symtab) + def type_check(symtab, add_sym = true) type_name.type_check(symtab) dtype = type_name.type(symtab) @@ -2039,12 +2278,12 @@ def type_check(symtab) unless ary_size.nil? ary_size.type_check(symtab) - begin + value_result = value_try do ary_size.value(symtab) - rescue ValueError - # if this is an ImplArchDef, this is an error because all constants are supposed to be known - if symtab.archdef.is_a?(ImplArchDef) - puts symtab.get(ary_size.text_value) + end + value_else(value_result) do + # if this is a fully configured ArchDef, this is an error because all constants are supposed to be known + if symtab.archdef.fully_configured? type_error "Array size (#{ary_size.text_value}) must be known at compile time" else # otherwise, it's ok that we don't know the value yet, as long as the value is a const @@ -2053,7 +2292,7 @@ def type_check(symtab) end end - add_symbol(symtab) + add_symbol(symtab) if add_sym id.type_check(symtab) end @@ -2062,7 +2301,7 @@ def type_check(symtab) def add_symbol(symtab) if @global # fill global with nil to prevent its use in compile-time evaluation - symtab.add(id.text_value, Var.new(id.text_value, decl_type(symtab), nil)) + symtab.add!(id.text_value, Var.new(id.text_value, decl_type(symtab), nil)) else type_error "No Type '#{type_name.text_value}'" if decl_type(symtab).nil? symtab.add(id.text_value, Var.new(id.text_value, decl_type(symtab), decl_type(symtab).default)) @@ -2131,9 +2370,10 @@ def lhs_type(symtab) end unless ary_size.nil? - begin + value_result = value_try do decl_type = Type.new(:array, sub_type: decl_type, width: ary_size.value(symtab), qualifiers:) - rescue ValueError + end + value_else(value_result) do type_error "Array size must be known at compile time" end end @@ -2154,9 +2394,10 @@ def type_check(symtab) if decl_type.const? # this is a constant; ensure we are assigning a constant value - begin + value_result = value_try do symtab.add(lhs.text_value, Var.new(lhs.text_value, decl_type.clone, rhs.value(symtab))) - rescue ValueError => e + end + value_else(value_result) do unless rhs.type(symtab).const? type_error "Declaring constant with a non-constant value (#{e})" end @@ -2176,18 +2417,41 @@ def type_check(symtab) # @!macro add_symbol def add_symbol(symtab) - symtab.add(lhs.text_value, Var.new(lhs.text_value, lhs_type(symtab))) + if @global + if lhs.text_value[0] == lhs.text_value[0].upcase + # const, add the value if it's known + value_result = value_try do + symtab.add(lhs.text_value, Var.new(lhs.text_value, lhs_type(symtab), rhs.value(symtab))) + end + value_else(value_result) do + symtab.add(lhs.text_value, Var.new(lhs.text_value, lhs_type(symtab))) + end + else + # mutable globals never have a compile-time value + symtab.add!(lhs.text_value, Var.new(lhs.text_value, lhs_type(symtab))) + end + else + value_result = value_try do + symtab.add(lhs.text_value, Var.new(lhs.text_value, lhs_type(symtab), rhs.value(symtab))) + end + value_else(value_result) do + symtab.add(lhs.text_value, Var.new(lhs.text_value, lhs_type(symtab))) + end + end end # @!macro execute def execute(symtab) value_error "TODO: Array declaration" unless ary_size.nil? rhs_value = nil - begin - rhs_value = rhs.value(symtab) unless @global - rescue ValueError + return if @global # never executed at compile time + + value_result = value_try do + rhs_value = rhs.value(symtab) + end + value_else(value_result) do symtab.add(lhs.text_value, Var.new(lhs.text_value, lhs_type(symtab), nil)) - raise + value_error "value of right-hand side of variable initialization is unknown" end symtab.add(lhs.text_value, Var.new(lhs.text_value, lhs_type(symtab), rhs_value)) end @@ -2378,9 +2642,9 @@ def invert(symtab) } if inverted_op_map.key?(op) - BinaryExpressionAst.new(input, interval, lhs, inverted_op_map[op], rhs) + BinaryExpressionAst.new(input, interval, lhs.dup, inverted_op_map[op], rhs.dup) else - UnaryOperatorExpressionAst.new(input, interval, "!", self) + UnaryOperatorExpressionAst.new(input, interval, "!", self.dup) end # else # # harder case of && / || @@ -2401,14 +2665,15 @@ def to_idl def type(symtab) lhs_type = lhs.type(symtab) short_circuit = false - begin + + value_result = value_try do lhs_value = lhs.value(symtab) if (lhs_value == true && op == "||") || (lhs_value == false && op == "&&") short_circuit = true end - rescue ValueError - short_circuit = false end + value_else(value_result) { short_circuit = false } + rhs_type = rhs.type(symtab) unless short_circuit qualifiers = [] @@ -2421,11 +2686,13 @@ def type(symtab) BoolType end elsif op == "<<" - begin + value_result = value_try do # if shift amount is known, then the result width is increased by the shift # otherwise, the result is the width of the left hand side - Type.new(:bits, width: lhs_type.width + rhs.value(symtab), qualifiers:) - rescue ValueError + value_error "lhs width unknown" if lhs_type.width == :unknown + return Type.new(:bits, width: lhs_type.width + rhs.value(symtab), qualifiers:) + end + value_else(value_result) do Type.new(:bits, width: lhs_type.width, qualifiers:) end #elsif ["+", "-", "*", "/", "%"].include?(op) @@ -2476,15 +2743,16 @@ def type_check(symtab) lhs.type_check(symtab) short_circuit = false - # begin - # lhs_value = lhs.value(symtab) - # if (lhs_value == true && op == "||") || (lhs_value == false && op == "&&") - # short_circuit = true - # end - # rescue ValueError - # short_circuit = false - # end - rhs.type_check(symtab) #unless short_circuit + value_result = value_try do + lhs_value = lhs.value(symtab) + if (lhs_value == true && op == "||") || (lhs_value == false && op == "&&") + short_circuit = true + end + end + value_else(value_result) do + short_circuit = false + end + rhs.type_check(symtab) unless short_circuit if ["<=", ">=", "<", ">", "!=", "=="].include?(op) rhs_type = rhs.type(symtab) @@ -2521,19 +2789,19 @@ def type_check(symtab) rhs_type = rhs.type(symtab) lhs_type = lhs.type(symtab) unless lhs_type.integral? && rhs_type.integral? - type_error "Multiplication/division is only defined for integral types" + type_error "Multiplication/division is only defined for integral types. Maybe you forgot a $bits cast?" end elsif ["+", "-"].include?(op) rhs_type = rhs.type(symtab) lhs_type = lhs.type(symtab) unless lhs_type.integral? && rhs_type.integral? - type_error "Addition/subtraction is only defined for integral types" + type_error "Addition/subtraction is only defined for integral types. Maybe you forgot a $bits cast?" end elsif ["&", "|", "^"].include?(op) rhs_type = rhs.type(symtab) lhs_type = lhs.type(symtab) unless lhs_type.integral? && rhs_type.integral? - type_error "Bitwise operations is only defined for integral types" + type_error "Bitwise operation is only defined for integral types. Maybe you forgot a $bits cast?" end else internal_error "Unhandled op '#{op}'" @@ -2574,21 +2842,24 @@ def value(symtab) end end elsif op == "==" - begin - lhs.value(symtab) == rhs.value(symtab) - rescue ValueError + value_result = value_try do + return lhs.value(symtab) == rhs.value(symtab) + end + value_else(value_result) do # even if we don't know the exact value of @lhs and @rhs, we can still # know that == is false if the possible values of each do not overlap - if lhs.values(symtab).intersection(rhs.value(symtab)).empty? + if lhs.values(symtab).intersection(rhs.values(symtab)).empty? false else + value_error "There is overlap in the lhs/rhs return values" end end elsif op == "!=" - begin - lhs.value(symtab) != rhs.value(symtab) - rescue ValueError + value_result = value_try do + return lhs.value(symtab) != rhs.value(symtab) + end + value_else(value_result) do # even if we don't know the exact value of @lhs and @rhs, we can still # know that != is true if the possible values of each do not overlap if lhs.values(symtab).intersection(rhs.values(symtab)).empty? @@ -2598,9 +2869,10 @@ def value(symtab) end end elsif op == "<=" - begin - lhs.value(symtab) <= rhs.value(symtab) - rescue ValueError + value_result = value_try do + return lhs.value(symtab) <= rhs.value(symtab) + end + value_else(value_result) do # even if we don't know the exact value of @lhs and @rhs, we can still # know that != is true if the possible values of lhs are all <= the possible values of rhs rhs_values = rhs.values(symtab) @@ -2611,9 +2883,10 @@ def value(symtab) end end elsif op == ">=" - begin - lhs.value(symtab) >= rhs.value(symtab) - rescue ValueError + value_result = value_try do + return lhs.value(symtab) >= rhs.value(symtab) + end + value_else(value_result) do # even if we don't know the exact value of @lhs and @rhs, we can still # know that != is true if the possible values of lhs are all >= the possible values of rhs rhs_values = rhs.values(symtab) @@ -2624,9 +2897,10 @@ def value(symtab) end end elsif op == "<" - begin - lhs.value(symtab) < rhs.value(symtab) - rescue ValueError + value_result = value_try do + return lhs.value(symtab) < rhs.value(symtab) + end + value_else(value_result) do # even if we don't know the exact value of @lhs and @rhs, we can still # know that != is true if the possible values of lhs are all < the possible values of rhs rhs_values = rhs.values(symtab) @@ -2637,9 +2911,10 @@ def value(symtab) end end elsif op == ">" - begin - lhs.value(symtab) > rhs.value(symtab) - rescue ValueError + value_result = value_try do + return lhs.value(symtab) > rhs.value(symtab) + end + value_else(value_result) do # even if we don't know the exact value of @lhs and @rhs, we can still # know that != is true if the possible values of lhs are all > the possible values of rhs rhs_values = rhs.values(symtab) @@ -2651,11 +2926,10 @@ def value(symtab) end elsif op == "&" # if one side is zero, we don't need to know the other side - begin + value_result = value_try do return 0 if lhs.value(symtab).zero? - rescue ValueError - # ok, trye rhs end + # ok, trye rhs return 0 if rhs.value(symtab).zero? @@ -2663,12 +2937,11 @@ def value(symtab) elsif op == "|" # if one side is all ones, we don't need to know the other side - begin + value_result = value_try do rhs_mask = ((1 << rhs.type(symtab).width) - 1) return rhs_mask if (rhs.value(symtab) == rhs_mask) && (lhs.type(symtab).width <= rhs.type(symtab).width) - rescue ValueError - # ok, trye rhs end + # ok, trye rhs lhs_mask = ((1 << lhs.type(symtab).width) - 1) return lhs_mask if (lhs.value(symtab) == lhs_mask) && (rhs.type(symtab).width <= lhs.type(symtab).width) @@ -2701,6 +2974,7 @@ def value(symtab) else internal_error "Unhandled binary op #{op}" end + v_trunc = if !lhs.type(symtab).const? || !rhs.type(symtab).const? # when both sides are constant, the value is not truncated @@ -2708,6 +2982,7 @@ def value(symtab) else v end + warn "WARNING: The value of '#{text_value}' (#{lhs.type(symtab).const?}, #{rhs.type(symtab).const?}) is truncated from #{v} to #{v_trunc} because the result is only #{type(symtab).width} bits" if v != v_trunc v_trunc end @@ -2863,11 +3138,10 @@ def type_check(symtab) v.type_check(symtab) type_error "value of replication must be a Bits type" unless v.type(symtab).kind == :bits - begin + value_try do type_error "replication amount must be positive (#{n.value(symtab)})" unless n.value(symtab).positive? - rescue ValueError - # type_error "replication amount must be known at compile time" end + # type_error "replication amount must be known at compile time" end # @!macro value @@ -2881,10 +3155,11 @@ def value(symtab) # @!macro type def type(symtab) - begin + value_result = value_try do width = (n.value(symtab) * v.type(symtab).width) - Type.new(:bits, width:) - rescue ValueError + return Type.new(:bits, width:) + end + value_else(value_result) do Type.new(:bits, width: :unknown) end end @@ -2924,15 +3199,16 @@ def type(symtab) # @!macro execute def execute(symtab) var = symtab.get(rval.text_value) - begin + value_result = value_try do internal_error "No symbol #{rval.text_value}" if var.nil? value_error "value of variable '#{rval.text_value}' not know" if var.value.nil? var.value = var.value - 1 - rescue ValueError + end + value_else(value_result) do var.value = nil - raise + value_error "value of variable '#{rval.text_value}' not know" end end @@ -2955,7 +3231,7 @@ class BuiltinVariableAst < AstNode def name = text_value def initialize(input, interval) - super(input, interval, []) + super(input, interval, EMPTY_ARRAY) end def type_check(symtab) @@ -3017,16 +3293,18 @@ def type(symtab) # @!macro execute def execute(symtab) - begin - var = symtab.get(rval.text_value) + var = symtab.get(rval.text_value) + + value_result = value_try do internal_error "No symbol named '#{rval.text_value}'" if var.nil? value_error "#{rval.text_value} is not compile-time-known" if var.value.nil? var.value = var.value + 1 - rescue ValueError + end + value_else(value_result) do var.value = nil - raise + value_error "#{rval.text_value} is not compile-time-known" if var.value.nil? end end @@ -3041,7 +3319,7 @@ def to_idl = "#{rval.to_idl}++" class FieldAccessExpressionSyntaxNode < Treetop::Runtime::SyntaxNode def to_ast - FieldAccessExpressionAst.new(input, interval, rval.to_ast, field_name.text_value) + FieldAccessExpressionAst.new(input, interval, field_access_eligible_expression.to_ast, field_name.text_value) end end @@ -3128,15 +3406,31 @@ def class_name = @enum_class_name def member_name = @member_name def initialize(input, interval, class_name, member_name) - super(input, interval, []) + super(input, interval, EMPTY_ARRAY) @enum_class_name = class_name @member_name = member_name + @enum_def_type = nil + end + + # @!macro freeze_tree + def freeze_tree(global_symtab) + enum_def_ast = global_symtab.archdef.global_ast.enums.find { |e| e.name == @enum_class_name } + + @enum_def_type = + if enum_def_ast.is_a?(BuiltinEnumDefinitionAst) + enum_def_ast&.type(global_symtab) + else + enum_def_ast&.type(nil) + end + + freeze end # @!macro type_check def type_check(symtab) - enum_def_type = symtab.get(@enum_class_name) + enum_def_type = @enum_def_type + type_error "No symbol #{@enum_class_name} has been defined" if enum_def_type.nil? type_error "#{@enum_class_name} is not an enum type" unless enum_def_type.is_a?(EnumerationType) @@ -3145,16 +3439,17 @@ def type_check(symtab) # @!macro type_no_archdef def type(symtab) - internal_error "Must call type_check first" if symtab.get(@enum_class_name).nil? + internal_error "Not frozen?" unless frozen? + type_error "No enum named #{@enum_class_name}" if @enum_def_type.nil? - symtab.get(@enum_class_name).ref_type + @enum_def_type.ref_type end # @!macro value_no_archdef def value(symtab) - internal_error "Must call type_check first" if symtab.get(@enum_class_name).nil? + internal_error "Must call type_check first" if @enum_def_type.nil? - symtab.get(@enum_class_name).value(@member_name) + @enum_def_type.value(@member_name) end # @!macro to_idl @@ -3304,15 +3599,12 @@ def type_check(symtab) condition.type_check(symtab) type_error "ternary selector must be bool" unless condition.type(symtab).kind == :boolean - begin + value_result = value_try do cond = condition.value(symtab) # if the condition is compile-time-known, only check the used field - if (cond) - true_expression.type_check(symtab) - else - false_expression.type_check(symtab) - end - rescue ValueError + cond ? true_expression.type_check(symtab) : false_expression.type_check(symtab) + end + value_else(value_result) do true_expression.type_check(symtab) false_expression.type_check(symtab) @@ -3328,23 +3620,32 @@ def type_check(symtab) # @!macro type def type(symtab) condition.type_check(symtab) - begin + value_result = value_try do cond = condition.value(symtab) # if the condition is compile-time-known, only check the used field - if (cond) - true_expression.type(symtab) + if cond + return true_expression.type(symtab) else - false_expression.type(symtab) + return false_expression.type(symtab) end - rescue ValueError - t = + end + value_else(value_result) do + t = if true_expression.type(symtab).kind == :bits && false_expression.type(symtab).kind == :bits - Type.new(:bits, width: [true_expression.type(symtab).width, false_expression.type(symtab).width].max) + true_width = true_expression.type(symtab).width + false_width = false_expression.type(symtab).width + if true_width == :unknown || false_width == :unknown + Type.new(:bits, width: :unknown) + else + Type.new(:bits, width: [true_width, false_width].max) + end else true_expression.type(symtab).clone end - t.make_const if condition.type(symtab).const? && true_expression.type(symtab).const? && false_expression.type(symtab).const? - t + if condition.type(symtab).const? && true_expression.type(symtab).const? && false_expression.type(symtab).const? + t.make_const + end + return t end end @@ -3355,9 +3656,12 @@ def value(symtab) # @!macro values def values(symtab) - condition.value(symtab) ? true_expression.values(symtab) : false_expression.values(symtab) - rescue ValueError - (true_expression.values(symtab) + false_expression.values(symtab)).uniq + value_result = value_try do + return condition.value(symtab) ? true_expression.values(symtab) : false_expression.values(symtab) + end + value_else(value_result) do + (true_expression.values(symtab) + false_expression.values(symtab)).uniq + end end # @!macro to_idl @@ -3372,7 +3676,7 @@ def to_ast class NoopAst < AstNode def initialize - super("", 0...0, []) + super("", 0...0, EMPTY_ARRAY) end # @!macro type_check @@ -3459,16 +3763,17 @@ def type_check(symtab) # @!macro execute def execute(symtab) - begin + value_result = value_try do cond = condition.value(symtab) if (cond) action.execute(symtab) end - rescue ValueError + end + value_else(value_result) do # force action to set any values to nil action.execute_unknown(symtab) - raise + value_error "" end end @@ -3497,7 +3802,7 @@ class DontCareReturnAst < AstNode include Rvalue def initialize(input, interval) - super(input, interval, []) + super(input, interval, EMPTY_ARRAY) end # @!macro type_check_no_args @@ -3538,7 +3843,7 @@ def to_ast = DontCareLvalueAst.new(input, interval) class DontCareLvalueAst < AstNode include Rvalue - def initialize(input, interval) = super(input, interval, []) + def initialize(input, interval) = super(input, interval, EMPTY_ARRAY) # @!macro type_check_no_args def type_check(_symtab) @@ -3629,6 +3934,11 @@ def to_ast class ReturnExpressionAst < AstNode def return_value_nodes = @children + def initialize(input, interval, return_nodes) + super(input, interval, return_nodes) + @func_type_cache = {} + end + # @return [Array] List of actual return types def return_types(symtab) if return_value_nodes[0].type(symtab).kind == :tuple @@ -3659,6 +3969,9 @@ def expected_return_type(symtab) symtab.get("__expected_return_type") else # need to find the type to get the right symbol table + func_type = @func_type_cache[symtab.archdef] + return func_type.return_type(EMPTY_ARRAY, self) unless func_type.nil? + func_type = symtab.get_global(func_def.name) internal_error "Couldn't find function type for '#{func_def.name}' #{symtab.keys} " if func_type.nil? @@ -3666,13 +3979,18 @@ def expected_return_type(symtab) # a templated function definition # # that information should be up the stack in the symbol table - template_values = symtab.find_all(single_scope: true) do |o| - o.is_a?(Var) && o.template_value_for?(func_def.name) - end - unless template_values.size == func_type.template_names.size - internal_error "Did not find correct number of template arguments (found #{template_values.size}, need #{func_type.template_names.size}) #{symtab.keys_pretty}" + if func_type.templated? + template_values = symtab.find_all(single_scope: true) do |o| + o.is_a?(Var) && o.template_value_for?(func_def.name) + end + unless template_values.size == func_type.template_names.size + internal_error "Did not find correct number of template arguments (found #{template_values.size}, need #{func_type.template_names.size}) #{symtab.keys_pretty}" + end + func_type.return_type(template_values.sort { |a, b| a.template_index <=> b.template_index }.map(&:value), self) + else + @func_type_cache[symtab.archdef]= func_type + func_type.return_type(EMPTY_ARRAY, self) end - func_type.return_type(template_values.sort { |a, b| a.template_index <=> b.template_index }.map(&:value)) end end @@ -3764,13 +4082,16 @@ def return_value(symtab) # @!macro return_values def return_values(symtab) - cond = condition.value(symtab) + value_result = value_try do + cond = condition.value(symtab) - cond ? return_expression.return_values(symtab) : [] + return cond ? return_expression.return_values(symtab) : EMPTY_ARRAY - rescue ValueError - # condition isn't known, so the return value is always possible - return_expression.return_values(symtab) + end + value_else(value_result) do + # condition isn't known, so the return value is always possible + return_expression.return_values(symtab) + end end def to_idl = "#{return_expression.to_idl} if (#{condition.to_idl});" @@ -3784,7 +4105,7 @@ def to_ast = CommentAst(input, interval) # represents a comment class CommentAst < AstNode def initialize(input, interval) - super(input, interval, []) + super(input, interval, EMPTY_ARRAY) end # @!macro type_check @@ -3824,7 +4145,7 @@ def bits_expression = @children[0] def initialize(input, interval, type_name, bits_expression) if bits_expression.nil? - super(input, interval, []) + super(input, interval, EMPTY_ARRAY) else super(input, interval, [bits_expression]) end @@ -3835,10 +4156,13 @@ def initialize(input, interval, type_name, bits_expression) def type_check(symtab) if @type_name == "Bits" bits_expression.type_check(symtab) - begin - type_error "Bits width (#{bits_expression.value(symtab)}) must be positive" unless bits_expression.value(symtab).positive? - rescue ValueError - type_error "Bit width must be known at compile time" if symtab.is_a?(ImplArchDef) + value_result = value_try do + unless bits_expression.value(symtab).positive? + type_error "Bits width (#{bits_expression.value(symtab)}) must be positive" + end + end + value_else(value_result) do + type_error "Bit width must be known at compile time" if symtab.archdef.fully_configured? end end unless ["Bits", "String", "XReg", "Boolean", "U32", "U64"].include?(@type_name) @@ -3846,6 +4170,21 @@ def type_check(symtab) end end + def freeze_tree(symtab) + if @type_name == "Bits" + # precalculate size if possible + begin + value_try do + @bits_type = Type.new(:bits, width: bits_expression.value(symtab)) + end + rescue TypeError + # ok, probably in a function template + end + bits_expression.freeze_tree(symtab) + end + freeze + end + # @!macro type def type(symtab) case @type_name @@ -3864,10 +4203,13 @@ def type(symtab) when "String" StringType when "Bits" - begin - Type.new(:bits, width: bits_expression.value(symtab)) - rescue ValueError - Type.new(:bits, width: :unknown) + return @bits_type unless @bits_type.nil? + + value_result = value_try do + return Type.new(:bits, width: bits_expression.value(symtab)) + end + value_else(value_result) do + return Type.new(:bits, width: :unknown) end else internal_error "TODO: #{text_value}" @@ -3899,7 +4241,7 @@ class StringLiteralAst < AstNode include Rvalue def initialize(input, interval) - super(input, interval, []) + super(input, interval, EMPTY_ARRAY) @type = Type.new(:string, width: value(nil).length, qualifiers: [:const]) end @@ -3929,7 +4271,7 @@ class IntLiteralAst < AstNode include Rvalue def initialize(input, interval) - super(input, interval, []) + super(input, interval, EMPTY_ARRAY) @types = [nil, nil] end @@ -4118,7 +4460,7 @@ def to_idl = text_value class FunctionCallExpressionSyntaxNode < Treetop::Runtime::SyntaxNode def to_ast - targs = t.empty? ? [] : [t.targs.first.to_ast] + t.targs.rest.elements.map { |e| e.arg.to_ast } + targs = t.empty? ? EMPTY_ARRAY : [t.targs.first.to_ast] + t.targs.rest.elements.map { |e| e.arg.to_ast } args = [] args << function_arg_list.first.to_ast unless function_arg_list.first.empty? args += function_arg_list.rest.elements.map { |e| e.expression.to_ast } @@ -4142,6 +4484,8 @@ def initialize(input, interval, function_name, targs, args) @num_targs = targs.size @name = function_name + @reachable_exceptions_func_call_cache = {} + @func_def_type_cache = {} end # @return [Boolean] whether or not the function call has a template argument @@ -4154,10 +4498,23 @@ def template_arg_nodes targs end - def template_values(symtab) - return [] unless template? + def template_values(symtab, unknown_ok: false) + return EMPTY_ARRAY unless template? - template_arg_nodes.map { |e| e.value(symtab) } + if unknown_ok + template_arg_nodes.map do |e| + val = nil + value_result = value_try do + val = e.value(symtab) + end + value_else(value_result) do + val = :unknown + end + val + end + else + template_arg_nodes.map { |e| e.value(symtab) } + end end # @return [Array] Function argument nodes @@ -4166,6 +4523,9 @@ def arg_nodes end def func_type(symtab) + func_def_type = @func_def_type_cache[symtab.archdef] + return func_def_type unless func_def_type.nil? + func_def_type = symtab.get(@name) type_error "No symbol #{@name}" if func_def_type.nil? @@ -4173,13 +4533,16 @@ def func_type(symtab) type_error "#{@name} is not a function (it's a #{func_def_type.class.name})" end - func_def_type + @func_def_type_cache[symtab.archdef] = func_def_type end # @!macro type_check def type_check(symtab) level = symtab.levels + unknown_ok = symtab.archdef.partially_configured? + tvals = template_values(symtab, unknown_ok:) + func_def_type = func_type(symtab) type_error "Missing template arguments in call to #{@name}" if template? && func_def_type.template_names.empty? @@ -4199,9 +4562,10 @@ def type_check(symtab) end end - func_def_type.type_check_call(template_values(symtab), self) + func_def_type.type_check_call(tvals, arg_nodes, symtab, self) else - func_def_type.type_check_call([], self) + # no need to type check this function; it will be done on its own + # func_def_type.type_check_call([], arg_nodes, symtab, self) end num_args = arg_nodes.size @@ -4212,12 +4576,12 @@ def type_check(symtab) a.type_check(symtab) end arg_nodes.each_with_index do |a, idx| - unless a.type(symtab).convertable_to?(func_def_type.argument_type(idx, template_values(symtab), arg_nodes, symtab, self)) - type_error "Wrong type for argument number #{idx + 1}. Expecting #{func_def_type.argument_type(idx, template_values(symtab), self)}, got #{a.type(symtab)}" + unless a.type(symtab).convertable_to?(func_def_type.argument_type(idx, tvals, arg_nodes, symtab, self)) + type_error "Wrong type for argument number #{idx + 1}. Expecting #{func_def_type.argument_type(idx, tvals, arg_nodes, symtab, self)}, got #{a.type(symtab)}" end end - if func_def_type.return_type(template_values(symtab), self).nil? + if func_def_type.return_type(tvals, self).nil? internal_error "No type determined for function" end @@ -4228,8 +4592,7 @@ def type_check(symtab) def type(symtab) return ConstBoolType if name == "implemented?" - func_def_type = symtab.get(name) - func_def_type.return_type(template_values(symtab), self) + func_type(symtab).return_type(template_values(symtab, unknown_ok: symtab.archdef.partially_configured?), self) end # @!macro value @@ -4239,25 +4602,33 @@ def value(symtab) return symtab.get("__effective_xlen").value end - func_def_type = symtab.get(name) + func_def_type = func_type(symtab) type_error "#{name} is not a function" unless func_def_type.is_a?(FunctionType) if func_def_type.builtin? if name == "implemented?" extname_ref = arg_nodes[0] type_error "First argument should be a ExtensionName" unless extname_ref.type(symtab).kind == :enum_ref && extname_ref.class_name == "ExtensionName" - return symtab.archdef.ext?(arg_nodes[0].member_name) if symtab.archdef.is_a?(ImplArchDef) + return symtab.archdef.ext?(arg_nodes[0].member_name) if symtab.archdef.fully_configured? - value_error "implemented? is only known when evaluating in the context of a configuration" + if symtab.archdef.ext?(arg_nodes[0].member_name) + # we can know if it is implemented, but not if it's not implemented for a partially configured + return true + end + value_error "implemented? is only known when evaluating in the context of a fully-configured arch def" else value_error "value of builtin function cannot be known" end end - template_values = [] - template_arg_nodes.each do |targ| - template_values << targ.value(symtab) - end + template_values = + if !template? + EMPTY_ARRAY + else + template_arg_nodes.map do |targ| + targ.value(symtab) + end + end func_def_type.return_value(template_values, arg_nodes, symtab, self) end @@ -4290,19 +4661,23 @@ def to_ast class UserTypeNameAst < AstNode def initialize(input, interval) - super(input, interval, []) + super(input, interval, EMPTY_ARRAY) + @type_cache = {} end # @!macro type_check def type_check(symtab) - type = symtab.get(text_value) + type = type(symtab) type_error "#{text_value} is not a type" unless type.is_a?(Type) end # @!macro type_no_archdef def type(symtab) - symtab.get(text_value) + typ = @type_cache[symtab.archdef] + return typ unless typ.nil? + + @type_cache[symtab.archdef] = symtab.get(text_value) end # @!macro to_idl @@ -4311,7 +4686,7 @@ def to_idl = text_value class InstructionOperationSyntaxNode < Treetop::Runtime::SyntaxNode def to_ast - FunctionBodyAst.new(input, interval, op_stmt_list.elements.map(&:choice).map(&:to_ast) ) + FunctionBodyAst.new(input, interval, op_stmt_list.elements.map(&:choice).map(&:to_ast)) end end @@ -4383,18 +4758,20 @@ def return_values(symtab) internal_error "Function bodies should be at global + 1 scope" unless symtab.levels == 2 values = [] - begin + value_result = value_try do # if there is a definate return value, then just return that return [return_value(symtab)] - rescue ValueError + end + value_else(value_result) do # go through the statements, and collect return values # we can stop if we encounter a statement with a known return value stmts.each do |s| if s.is_a?(Returns) - begin + value_result = value_try do v = s.return_value(symtab) return values.push(v).uniq unless v.nil? - rescue ValueError + end + value_else(value_result) do values += s.return_values(symtab) end else @@ -4432,6 +4809,16 @@ def to_ast end class FunctionDefAst < AstNode + include Declaration + + # @param input [String] The source code + # @param interval [Range] The range in the source code for this function definition + # @param name [String] The name of the function + # @param targs [Array] Template arguments + # @params return_types [Array] Return types + # @param arguments [Array] Arguments + # @param desc [String] Description + # @param body [AstNode,nil] Body, unless the function is builtin def initialize(input, interval, name, targs, return_types, arguments, desc, body) if body.nil? super(input, interval, targs + return_types + arguments) @@ -4446,33 +4833,50 @@ def initialize(input, interval, name, targs, return_types, arguments, desc, body @desc = desc @body = body + @cached_return_type = {} @reachable_functions_cache ||= {} end attr_reader :reachable_functions_cache + # @!macro freeze_tree + def freeze_tree(global_symtab) + unless templated? + arguments(global_symtab) + end + + @children.each { |child| child.freeze_tree(global_symtab) } + freeze + end + + # @return [String] Asciidoc formatted function description def description unindent(@desc) end + # @return [Boolean] whether or not the function is templated def templated? !@targs.empty? end + # @return [Integer] The number of arguments to the function def num_args @argument_nodes.size end - # @return [Array] containing the argument types, in order + # @return [Array] containing the argument types and names, in order def arguments(symtab) + return @arglist unless @arglist.nil? + if templated? template_names.each do |tname| - internal_error "Template values missing" unless symtab.get(tname) + internal_error "Template values missing in symtab" unless symtab.get(tname) end end + return EMPTY_ARRAY if @argument_nodes.empty? + arglist = [] - return arglist if @argument_nodes.empty? @argument_nodes.each do |a| atype = a.type(symtab) @@ -4481,6 +4885,10 @@ def arguments(symtab) arglist << [atype, a.name] end + arglist.freeze + unless templated? + @arglist = arglist + end arglist end @@ -4492,19 +4900,47 @@ def arguments_list_str # return the return type, which may be a tuple of multiple types def return_type(symtab) + cached = @cached_return_type[symtab.archdef] + return cached unless cached.nil? + unless symtab.levels == 2 internal_error "Function bodies should be at global + 1 scope (at global + #{symtab.levels - 1})" end + if @return_type_nodes.empty? + @cached_return_type[symtab.archdef] = VoidType + return VoidType + end + + unless templated? + # with no templates, the return type does not change for a given arch_def + rtype = + if @return_type_nodes.size == 1 + rtype = @return_type_nodes[0].type(symtab) + rtype = rtype.ref_type if rtype.kind == :enum + rtype + else + tuple_types = @return_type_nodes.map do |r| + rtype = r.type(symtab) + rtype = rtype.ref_type if rtype.kind == :enum + rtype + end + + Type.new(:tuple, tuple_types:) + end + + raise "??????" if rtype.nil? + + return @cached_return_type[symtab.archdef] = rtype + end + if templated? template_names.each do |tname| internal_error "Template values missing" unless symtab.get(tname) end end - if @return_type_nodes.empty? - return VoidType - end + if @return_type_nodes.size == 1 rtype = @return_type_nodes[0].type(symtab) @@ -4548,10 +4984,8 @@ def type_check_template_instance(symtab) type_check_return(symtab) type_check_args(symtab) - symtab.push @argument_nodes.each { |a| symtab.add(a.name, Var.new(a.name, a.type(symtab))) } type_check_body(symtab) - symtab.pop end # we do lazy type checking of the function body so that we never check @@ -4562,10 +4996,15 @@ def type_check_from_call(symtab) type_check_return(symtab) type_check_args(symtab) - symtab.push # push function scope - @argument_nodes.each { |a| symtab.add(a.name, Var.new(a.name, a.type(symtab))) } + # @argument_nodes.each do |a| + # value_result = value_try do + # symtab.add(a.name, Var.new(a.name, a.type(symtab), a.value(symtab))) + # end + # value_else(value_result) do + # symtab.add(a.name, Var.new(a.name, a.type(symtab))) + # end + # end type_check_body(symtab) - symtab.pop end # @!macro type_check @@ -4574,12 +5013,31 @@ def type_check(symtab) type_check_targs(symtab) - # recursion isn't supported (doesn't map well to hardware), so we can add the function after type checking the body - add_symbol(symtab) + symtab = symtab.deep_clone + symtab.push(self) + template_names.each_with_index do |tname, index| + symtab.add(tname, Var.new(tname, template_types(symtab)[index])) + end + + type_check_return(symtab) + + arguments(symtab).each do |arg_type, arg_name| + symtab.add(arg_name, Var.new(arg_name, arg_type)) + end + type_check_args(symtab) + + + # template functions are checked as they are called + unless templated? + type_check_body(symtab) + end + symtab.pop end # @!macro add_symbol def add_symbol(symtab) + internal_error "Functions should be declared at global scope" unless symtab.levels == 1 + # now add the function in global scope def_type = FunctionType.new( name, @@ -4598,7 +5056,7 @@ def template_names # @param symtab [SymbolTable] The context for evaluation # @return [Array] Template argument types, in order def template_types(symtab) - return [] unless templated? + return EMPTY_ARRAY unless templated? ttypes = [] @targs.each do |a| @@ -4619,13 +5077,13 @@ def type_check_return(symtab) end def type_check_args(symtab) - @argument_nodes.each { |a| a.type_check(symtab) } + @argument_nodes.each { |a| a.type_check(symtab, false) } end def type_check_body(symtab) - if respond_to?(:body_block) - @body.type_check(symtab) - end + return if @body.nil? + + @body.type_check(symtab) end def body @@ -4666,7 +5124,7 @@ def initialize(input, interval, init, condition, update, stmts) # @!macro type_check def type_check(symtab) - symtab.push + symtab.push(self) init.type_check(symtab) condition.type_check(symtab) update.type_check(symtab) @@ -4679,66 +5137,76 @@ def type_check(symtab) # @!macro return_value def return_value(symtab) - symtab.push + symtab.push(self) begin - init.execute(symtab) + value_result = value_try do + init.execute(symtab) - while condition.value(symtab) - stmts.each do |s| - if s.is_a?(Returns) - v = s.return_value(symtab) - unless v.nil? - symtab.pop - return v + while condition.value(symtab) + stmts.each do |s| + if s.is_a?(Returns) + v = s.return_value(symtab) + unless v.nil? + return v + end + else + s.execute(symtab) end - else - s.execute(symtab) end + update.execute(symtab) end - update.execute(symtab) end - rescue ValueError => e + value_else(value_result) do + value_error "" + end + ensure symtab.pop - raise e end - - symtab.pop nil end # @!macro return_values def return_values(symtab) - # if there is a known return value, then we are done - [return_value(symtab)] - rescue ValueError - # see if we can collect a list - values = [] - symtab.push - - begin - init.execute(symtab) + value_result = value_try do + # if there is a known return value, then we are done + return [return_value(symtab)] + end + value_else(value_result) do + # see if we can collect a list + values = [] + symtab.push(self) - while condition.value(symtab) - stmts.each do |s| - if s.is_a?(Returns) - begin - v = s.return_value(symtab) - return values.push(v).uniq unless v.nil? - rescue ValueError - values += s.return_values(symtab) + begin + value_result = value_try do + init.execute(symtab) + + while condition.value(symtab) + stmts.each do |s| + if s.is_a?(Returns) + value_result = value_try do + v = s.return_value(symtab) + unless v.nil? + return values.push(v).uniq + end + end + value_else(value_result) do + values += s.return_values(symtab) + end + else + s.execute(symtab) + end end - else - s.execute(symtab) + update.execute(symtab) end + :ok end - update.execute(symtab) + ensure + symtab.pop end - ensure - symtab.pop - end - values.uniq + values.uniq + end end # @!macro execute @@ -4763,7 +5231,7 @@ def stmts = @children def initialize(input, interval, body_stmts) if body_stmts.empty? - super("", 0...0, []) + super("", 0...0, EMPTY_ARRAY) else super(input, interval, body_stmts) end @@ -4771,18 +5239,20 @@ def initialize(input, interval, body_stmts) # @!macro type_check def type_check(symtab) - symtab.push + symtab.push(self) - stmts.each do |s| - s.type_check(symtab) + begin + stmts.each do |s| + s.type_check(symtab) + end + ensure + symtab.pop end - - symtab.pop end # @!macro return_value def return_value(symtab) - symtab.push + symtab.push(self) begin stmts.each do |s| if s.is_a?(Returns) @@ -4804,18 +5274,23 @@ def return_value(symtab) # @!macro return_values def return_values(symtab) values = [] - symtab.push + symtab.push(self) begin - stmts.each do |s| - if s.is_a?(Returns) - begin - v = s.return_value(symtab) - return values.push(v).uniq unless v.nil? - rescue ValueError - values += s.return_values(symtab) + value_result = value_try do + stmts.each do |s| + if s.is_a?(Returns) + value_result = value_try do + v = s.return_value(symtab) + unless v.nil? + return values.push(v).uniq + end + end + value_else(value_result) do + values += s.return_values(symtab) + end + else + s.execute(symtab) end - else - s.execute(symtab) end end ensure @@ -4829,24 +5304,27 @@ def return_values(symtab) def execute(symtab) err = nil stmts.each do |s| - begin + value_result = value_try do if s.is_a?(Returns) - begin + value_result = value_try do v = s.return_value(symtab) break unless v.nil? # nil means this is a conditional return and the condition is false - rescue ValueError => e + + end + value_else(value_result) do # not known, keep going - err = e if err.nil? + err = :value_error end else s.execute(symtab) end - rescue ValueError => e + end + value_else(value_result) do # keep going so that we invalidate everything - err = e if err.nil? # remember the first error + err = :value_error end end - raise err unless err.nil? + throw err unless err.nil? end # @!macro execute_unknown @@ -4876,23 +5354,28 @@ def initialize(input, interval, body_interval, cond, body_stmts) def type_check(symtab) cond.type_check(symtab) + + cond_value = nil + value_try do + cond_value = cond.value(symtab) + end + unless cond.type(symtab).convertable_to?(:boolean) type_error "'#{cond.text_value}' is not boolean" end - body.type_check(symtab) + body.type_check(symtab) unless cond_value == false end # @!macro return_values def return_values(symtab) - if cond.value(symtab) + value_result = value_try do + return cond.value(symtab) ? body.return_values(symtab) : EMPTY_ARRAY + end + value_else(value_result) do + # might be taken, so add the possible return values body.return_values(symtab) - else - [] end - rescue ValueError - # might be taken, so add the possible return values - body.return_values(symtab) end # @!macro to_idl @@ -4959,11 +5442,17 @@ def type_check(symtab) type_error "'#{if_cond.text_value}' is not boolean" unless if_cond.type(symtab).convertable_to?(:boolean) - if_body.type_check(symtab) + if_cond_value = nil + value_try do + if_cond_value = if_cond.value(symtab) + end + + # short-circuit the if body if we can + if_body.type_check(symtab) unless if_cond_value == false internal_error "not at same level #{level} #{symtab.levels}" unless level == symtab.levels - unless elseifs.empty? + unless (if_cond_value == true) || elseifs.empty? elseifs.each do |eif| eif.type_check(symtab) end @@ -4971,7 +5460,7 @@ def type_check(symtab) internal_error "not at same level #{level} #{symtab.levels}" unless level == symtab.levels - final_else_body.type_check(symtab) + final_else_body.type_check(symtab) unless if_cond_value == true internal_error "not at same level #{level} #{symtab.levels}" unless level == symtab.levels end @@ -5007,15 +5496,16 @@ def return_values_after_if(symtab) unless elseifs.empty? elseifs.each do |eif| values += eif.return_values(symtab) - begin + value_result = value_try do elseif_cond_value = eif.value(symtab) if elseif_cond_value # this else if is defintately taken, so we are done return (values + eif.return_values(symtab)).uniq else - next # we know the else if isn't taken, so we can just go to the next + next :ok # we know the else if isn't taken, so we can just go to the next end - rescue ValueError + end + value_else(value_result) do # else if path not known; body return paths are possible values += eif.return_values(symtab) end @@ -5033,17 +5523,20 @@ def return_values_after_if(symtab) # @return [Array] List of all possible return values # @raise ValueError if it is not possible to determine all return values at compile time def return_values(symtab) - if_cond_value = if_cond.value(symtab) - if if_cond_value - # if is taken, so the only possible return values are those in the if body - if_body.return_values(symtab) - else - # if cond not taken; check else ifs and possibly final else - return_values_after_if(symtab) + value_result = value_try do + if_cond_value = if_cond.value(symtab) + if if_cond_value + # if is taken, so the only possible return values are those in the if body + return if_body.return_values(symtab) + else + # if cond not taken; check else ifs and possibly final else + return return_values_after_if(symtab) + end + end + value_else(value_result) do + # if condition not known; both paths are possible + (if_body.return_values(symtab) + return_values_after_if(symtab)).uniq end - rescue ValueError - # if condition not known; both paths are possible - (if_body.return_values(symtab) + return_values_after_if(symtab)).uniq end # return values starting at the first else if @@ -5051,66 +5544,75 @@ def execute_after_if(symtab) err = nil unless elseifs.empty? elseifs.each do |eif| - begin + value_result = value_try do elseif_cond_value = eif.cond.value(symtab) if elseif_cond_value # this else if is defintately taken, so we are done eif.body.execute(symtab) return else - next # we know the else if isn't taken, so we can just go to the next + next :ok # we know the else if isn't taken, so we can just go to the next end - rescue ValueError + end + value_else(value_result) do # else if path not known; body return paths are possible - begin + value_result = value_try do eif.body.execute(symtab) - rescue ValueError => e - err = e if err.nil? + end + value_else(value_result) do + err = :value_error if err.nil? end end end end # now do the final else - begin + value_result = value_try do final_else_body.execute(symtab) unless final_else_body.nil? - rescue ValueError => e - err = e if err.nil? + end + value_else(value_result) do + err = :value_error if err.nil? end - raise err unless err.nil? + value_error "" unless err.nil? end private :execute_after_if # @!macro execute def execute(symtab) err = nil - if_cond_value = if_cond.value(symtab) - if if_cond_value - # if is taken, so only the taken body is executable - begin + value_result = value_try do + if_cond_value = if_cond.value(symtab) + if if_cond_value + # if is taken, so only the taken body is executable + value_result = value_try do + if_body.execute(symtab) + end + value_else(value_result) do + err = :value_error if err.nil? + end + else + execute_after_if(symtab) + end + end + value_else(value_result) do + # condition not known; both paths can execute + value_result = value_try do if_body.execute(symtab) - rescue ValueError => e + end + value_else(value_result) do + err = :value_error if err.nil? + end + + value_result = value_try do + execute_after_if(symtab) + end + value_else(value_result) do err = e if err.nil? end - else - execute_after_if(symtab) - end - rescue ValueError - # condition not known; both paths can execute - begin - if_body.execute(symtab) - rescue ValueError => e - err = e if err.nil? end - begin - execute_after_if(symtab) - rescue ValueError => e - err = e if err.nil? - end - ensure - raise err unless err.nil? + value_error "" unless err.nil? end # return values starting at the first else if @@ -5152,13 +5654,24 @@ def initialize(input, interval, idx, field_name) if idx.is_a?(AstNode) super(input, interval, [idx]) else - super(input, interval, []) + super(input, interval, EMPTY_ARRAY) end @idx = idx @field_name = field_name end + def freeze_tree(symtab) + value_result = value_try do + @value = calc_value(symtab) + end + value_else(value_result) do + @value = nil + end + @type = calc_type(symtab) + freeze + end + # @!macro type_check def type_check(symtab) if @idx.is_a?(IntLiteralAst) @@ -5169,6 +5682,8 @@ def type_check(symtab) type_error "No CSR named #{csr_name}" if csr_def(symtab).nil? end type_error "CSR[#{csr_name(symtab)}] has no field named #{@field_name}" if field_def(symtab).nil? + type_error "CSR[#{csr_name(symtab)}].#{@field_name} is not defined in RV32" if symtab.archdef.mxlen == 32 && !field_def(symtab).defined_in_base32? + type_error "CSR[#{csr_name(symtab)}].#{@field_name} is not defined in RV64" if symtab.archdef.mxlen == 64 && !field_def(symtab).defined_in_base64? end def csr_def(symtab) @@ -5204,6 +5719,10 @@ def to_idl # @!macro type def type(symtab) + @type + end + + def calc_type(symtab) fd = field_def(symtab) if fd.nil? if @idx.is_a?(IntLiteralAst) @@ -5215,9 +5734,13 @@ def type(symtab) if fd.defined_in_all_bases? Type.new(:bits, width: symtab.archdef.possible_xlens.map{ |xlen| fd.width(symtab.archdef, xlen) }.max) elsif fd.base64_only? - Type.new(:bits, width: fd.width(symtab.archdef, 64)) + if symtab.archdef.possible_xlens.include?(64) + Type.new(:bits, width: fd.width(symtab.archdef, 64)) + end elsif fd.base32_only? - Type.new(:bits, width: fd.width(symtab.archdef, 32)) + if symtab.archdef.possible_xlens.include?(32) + Type.new(:bits, width: fd.width(symtab.archdef, 32)) + end else internal_error "unexpected field base" end @@ -5225,10 +5748,18 @@ def type(symtab) # @!macro value def value(symtab) + if @value.nil? + value_error "'#{csr_name(symtab)}.#{field_name(symtab)}' is not RO" + else + @value + end + end + + def calc_value(symtab) # field isn't implemented, so it must be zero return 0 if field_def(symtab).nil? - unless field_def(symtab).type(symtab.archdef) == "RO" + unless field_def(symtab).type(symtab) == "RO" value_error "'#{csr_name(symtab)}.#{field_name(symtab)}' is not RO" end @@ -5263,7 +5794,7 @@ def initialize(input, interval, idx) if idx.is_a?(AstNode) super(input, interval, [idx]) else - super(input, interval, []) + super(input, interval, EMPTY_ARRAY) end @idx = idx @@ -5301,13 +5832,13 @@ def type_check(symtab) @idx.type_check(symtab) type_error "Csr index must be integral" unless @idx.type(symtab).integral? - begin + value_result = value_try do idx_value = @idx.value(symtab) csr_index = archdef.csrs.index { |csr| csr.address == idx_value } type_error "No csr number '#{idx_value}' was found" if csr_index.nil? - rescue ValueError - # OK, index doesn't have to be known + :ok end + # OK, index doesn't have to be known end end @@ -5320,13 +5851,12 @@ def csr_def(symtab) csr else # this is an expression - begin + value_result = value_try do idx_value = @idx.value(symtab) - csr_index = archdef.csrs.find { |csr| csr.address == idx_value } - rescue ValueError - # we don't know at compile time which CSR this is... - nil + return archdef.csrs.find { |csr| csr.address == idx_value } end + # || we don't know at compile time which CSR this is... + nil end end @@ -5344,12 +5874,12 @@ def csr_name(symtab) def value(symtab) cd = csr_def(symtab) value_error "CSR number not knowable" if cd.nil? - if symtab.archdef.is_a?(ImplArchDef) + if symtab.archdef.fully_configured? value_error "CSR is not implemented" unless symtab.archdef.implemented_csrs.any? { |icsr| icsr.name == cd.name } else value_error "CSR is not defined" unless symtab.archdef.csrs.any? { |icsr| icsr.name == cd.name } end - cd.fields.each { |f| value_error "#{csr_name(symtab)}.#{f.name} not RO" unless f.type(symtab.archdef) == "RO" } + cd.fields.each { |f| value_error "#{csr_name(symtab)}.#{f.name} not RO" unless f.type(symtab) == "RO" } csr_def(symtab).fields.reduce(0) { |val, f| val | (f.value << f.location.begin) } end @@ -5447,7 +5977,7 @@ def type(symtab) case function_name when "sw_read" if csr_known?(symtab) - Type.new(:bits, width: archdef.csr(csr.csr_name(symtab)).length) + Type.new(:bits, width: archdef.csr(csr.csr_name(symtab)).length(archdef)) else Type.new(:bits, width: symtab.mxlen) end diff --git a/lib/idl/idl.treetop b/lib/idl/idl.treetop index ceae364d82..a054cb2d56 100644 --- a/lib/idl/idl.treetop +++ b/lib/idl/idl.treetop @@ -279,8 +279,16 @@ grammar Idl 'CSR' space* '[' space* idx:expression space* ']' end + rule field_access_eligible_expression + paren_expression + / + function_call # Ast is assigned in function_call rule + / + rval # must come last! + end + rule field_access_expression - rval space* '.' space* field_name + field_access_eligible_expression space* '.' space* field_name end rule ary_eligible_expression @@ -290,14 +298,14 @@ grammar Idl / concatenation_expression / + field_access_expression + / function_call # Ast is assigned in function_call rule / csr_field_access_expression / csr_register_access_expression / - field_access_expression - / bits_cast / rval # must come last! @@ -334,6 +342,8 @@ grammar Idl / '$enum_to_a' space* '(' space* user_type_name ')' / + '$enum' space* '(' space* user_type_name space* ',' space* expression space* ')' + / '$array_size' space* '(' space* expression ')' / paren_expression @@ -348,14 +358,14 @@ grammar Idl / concatenation_expression / + field_access_expression + / function_call # Ast is assigned in function_call rule / csr_field_access_expression / csr_register_access_expression / - field_access_expression - / enum_ref / rval # must come last diff --git a/lib/idl/passes/gen_adoc.rb b/lib/idl/passes/gen_adoc.rb index a4bc52fed4..fbaa8172ea 100644 --- a/lib/idl/passes/gen_adoc.rb +++ b/lib/idl/passes/gen_adoc.rb @@ -96,6 +96,11 @@ def gen_adoc(indent, indent_spaces: 2) "#{' '*indent}$bits(#{expression.gen_adoc(0, indent_spaces: )})" end end + class EnumCastAst + def gen_adoc(indent, indent_spaces: 2) + "#{' '*indent}$enum(#{enum_name.gen_adoc(0, indent_spaces:)}, #{expression.gen_adoc(0, indent_spaces: )})" + end + end class CsrFieldAssignmentAst def gen_adoc(indent, indent_spaces: 2) "#{' '*indent}#{csr_field.gen_adoc(indent, indent_spaces:)} = #{write_value.gen_adoc(0, indent_spaces:)}" diff --git a/lib/idl/passes/prune.rb b/lib/idl/passes/prune.rb index 768d073fc4..3cd76e6a72 100644 --- a/lib/idl/passes/prune.rb +++ b/lib/idl/passes/prune.rb @@ -21,7 +21,7 @@ def create_literal(value) elsif value.is_a?(TrueClass) || value.is_a?(FalseClass) create_bool_literal(value) else - raise "TODO" + raise "TODO: #{value.class.name}" end end @@ -35,9 +35,10 @@ def prune(symtab) new_node.instance_variable_set(:@children, new_children) if is_a?(Executable) - begin + value_result = value_try do execute(symtab) - rescue ValueError + end + value_else(value_result) do execute_unknown(symtab) end end @@ -48,10 +49,11 @@ def prune(symtab) end class FunctionCallExpressionAst def prune(symtab) - begin + value_result = value_try do v = value(symtab) - create_literal(v) - rescue ValueError + return create_literal(v) + end + value_else(value_result) do FunctionCallExpressionAst.new(input, interval, name, targs.map { |t| t.prune(symtab) }, args.map { |a| a.prune(symtab)} ) end end @@ -69,79 +71,92 @@ def prune(symtab) end class ForLoopAst def prune(symtab) - symtab.push + symtab.push(self) symtab.add(init.lhs.name, Var.new(init.lhs.name, init.lhs_type(symtab))) - new_loop = - ForLoopAst.new( - input, interval, - init.prune(symtab), - condition.prune(symtab), - update.prune(symtab), - stmts.map { |s| s.prune(symtab) } - ) - symtab.pop + begin + new_loop = + ForLoopAst.new( + input, interval, + init.prune(symtab), + condition.prune(symtab), + update.prune(symtab), + stmts.map { |s| s.prune(symtab) } + ) + ensure + symtab.pop + end new_loop end end class FunctionBodyAst def prune(symtab, args_already_applied: false) - symtab.push + symtab.push(self) - func_def = find_ancestor(FunctionDefAst) - unless args_already_applied || func_def.nil? - if func_def.templated? # can't prune a template because we don't have all types - return dup - end + begin + func_def = find_ancestor(FunctionDefAst) + unless args_already_applied || func_def.nil? + if func_def.templated? # can't prune a template because we don't have all types + return dup + end - # push template values - func_def.template_names.each_with_index do |tname, idx| - symtab.add(tname, Var.new(tname, func_def.template_types(symtab)[idx])) - end + # push template values + func_def.template_names.each_with_index do |tname, idx| + symtab.add(tname, Var.new(tname, func_def.template_types(symtab)[idx])) + end - # push args - func_def.arguments(symtab).each do |arg_type, arg_name| - symtab.add(arg_name, Var.new(arg_name, arg_type)) + # push args + func_def.arguments(symtab).each do |arg_type, arg_name| + symtab.add(arg_name, Var.new(arg_name, arg_type)) + end end - end - begin - # go through the statements, and stop if we find one that retuns or raises an exception - statements.each_with_index do |s, idx| - if s.is_a?(ReturnStatementAst) - return FunctionBodyAst.new(input, interval, statements[0..idx].map { |s| s.prune(symtab) }) - elsif s.is_a?(ConditionalReturnStatementAst) - begin - v = s.return_value(symtab) + pruned_body = nil - # conditional return, condition not taken if v.nil? - return FunctionBodyAst.new(input, interval, statements[0..idx].map { |s| s.prune(symtab) }) unless v.nil? - rescue ValueError - # conditional return, condition not known; keep going + value_result = value_try do + # go through the statements, and stop if we find one that retuns or raises an exception + statements.each_with_index do |s, idx| + if s.is_a?(ReturnStatementAst) + pruned_body = FunctionBodyAst.new(input, interval, statements[0..idx].map { |s| s.prune(symtab) }) + return pruned_body + elsif s.is_a?(ConditionalReturnStatementAst) + value_try do + v = s.return_value(symtab) + + # conditional return, condition not taken if v.nil? + unless v.nil? + pruned_body = FunctionBodyAst.new(input, interval, statements[0..idx].map { |s| s.prune(symtab) }) + return pruned_body + end + end + # || conditional return, condition not known; keep going + elsif s.is_a?(StatementAst) && s.action.is_a?(FunctionCallExpressionAst) && s.action.name == "raise" + pruned_body = FunctionBodyAst.new(input, interval, statements[0..idx].map { |s| s.prune(symtab) }) + return pruned_body + else + s.execute(symtab) end - elsif s.is_a?(StatementAst) && s.action.is_a?(FunctionCallExpressionAst) && s.action.name == "raise" - return FunctionBodyAst.new(input, interval, statements[0..idx].map { |s| s.prune(symtab) }) - else - s.execute(symtab) end - end - FunctionBodyAst.new(input, interval, statements.map { |s| s.prune(symtab) }) - rescue ValueError - FunctionBodyAst.new(input, interval, statements.map { |s| s.prune(symtab) }) + pruned_body = FunctionBodyAst.new(input, interval, statements.map { |s| s.prune(symtab) }) + end + value_else(value_result) do + pruned_body = FunctionBodyAst.new(input, interval, statements.map { |s| s.prune(symtab) }) + end ensure symtab.pop end + + pruned_body end end class StatementAst def prune(symtab) pruned_action = action.prune(symtab) pruned_action.add_symbol(symtab) if pruned_action.is_a?(Declaration) - begin + value_try do pruned_action.execute(symtab) if pruned_action.is_a?(Executable) - rescue ValueError - # ok end + # || ok StatementAst.new(input, interval, pruned_action) end @@ -149,22 +164,21 @@ def prune(symtab) class BinaryExpressionAst # @!macro prune def prune(symtab) - begin + value_try do val = value(symtab) return create_literal(val) - rescue ValueError - # fall through end + # fall through - begin + lhs_value = nil + rhs_value = nil + + value_try do lhs_value = lhs.value(symtab) - rescue ValueError - lhs_value = nil end - begin + + value_try do rhs_value = rhs.value(symtab) - rescue ValueError - rhs_value = nil end if op == "&&" @@ -245,67 +259,72 @@ def prune(symtab) class IfAst # @!macro prune def prune(symtab) - if if_cond.value(symtab) - if_body.prune(symtab) - elsif !elseifs.empty? - # we know that the if condition is false, so now we treat the else if - # as the starting point and try again - IfAst.new( - input, interval, - elseifs[0].cond.dup, - elseifs[0].body.dup, - elseifs[1..].map(&:dup), - final_else_body.dup).prune(symtab) - elsif !final_else_body.stmts.empty? - # the if is false, and there are no else ifs, so the result of the prune is just the pruned else body - final_else_body.prune(symtab) - else - # the if is false, and there are no else ifs or elses. This is just a no-op - NoopAst.new + value_result = value_try do + if if_cond.value(symtab) + return if_body.prune(symtab) + elsif !elseifs.empty? + # we know that the if condition is false, so now we treat the else if + # as the starting point and try again + return IfAst.new( + input, interval, + elseifs[0].cond.dup, + elseifs[0].body.dup, + elseifs[1..].map(&:dup), + final_else_body.dup).prune(symtab) + elsif !final_else_body.stmts.empty? + # the if is false, and there are no else ifs, so the result of the prune is just the pruned else body + return final_else_body.prune(symtab) + else + # the if is false, and there are no else ifs or elses. This is just a no-op + return NoopAst.new + end end - rescue ValueError - # we don't know the value of the if condition - # we still might know the value of an else if - unknown_elsifs = [] - elseifs.each do |eif| - begin - if eif.cond.value(symtab) - # this elseif is true, so turn it into an else and then we are done - return IfAst.new( - input, interval, - if_cond.dup, - if_body.dup, - unknown_elsifs.map(&:dup), - eif.body.dup - ).prune(symtab) - else - # this elseif is false, so we can remove it - next + value_else(value_result) do + # we don't know the value of the if condition + # we still might know the value of an else if + unknown_elsifs = [] + elseifs.each do |eif| + value_result = value_try do + if eif.cond.value(symtab) + # this elseif is true, so turn it into an else and then we are done + return IfAst.new( + input, interval, + if_cond.dup, + if_body.dup, + unknown_elsifs.map(&:dup), + eif.body.dup + ).prune(symtab) + else + # this elseif is false, so we can remove it + next :ok + end + end + value_else(value_result) do + unknown_elsifs << eif end - rescue ValueError - unknown_elsifs << eif end + # we get here, then we don't know the value of anything. just return this if with everything pruned + IfAst.new( + input, interval, + if_cond.prune(symtab), + if_body.prune(symtab), + unknown_elsifs.map { |eif| eif.prune(symtab) }, + final_else_body.prune(symtab) + ) end - # we get here, then we don't know the value of anything. just return this if with everything pruned - IfAst.new( - input, interval, - if_cond.prune(symtab), - if_body.prune(symtab), - elseifs.map { |eif| eif.prune(symtab) }, - final_else_body.prune(symtab) - ) end end class ConditionalReturnStatementAst def prune(symtab) - begin + value_result = value_try do if condition.value(symtab) return return_expression.prune(symtab) else return NoopAst.new end - rescue ValueError + end + value_else(value_result) do ConditionalReturnStatementAst.new(input, interval, return_expression.prune(symtab), condition.prune(symtab)) end end @@ -313,40 +332,42 @@ def prune(symtab) class ConditionalStatementAst def prune(symtab) - if condition.value(symtab) + value_result = value_try do + if condition.value(symtab) + pruned_action = action.prune(symtab) + pruned_action.add_symbol(symtab) if pruned_action.is_a?(Declaration) + value_result = value_try do + pruned_action.execute(symtab) if pruned_action.is_a?(Executable) + end + + return StatementAst.new(input, interval, pruned_action) + else + return NoopAst.new + end + end + value_else(value_result) do + # condition not known pruned_action = action.prune(symtab) pruned_action.add_symbol(symtab) if pruned_action.is_a?(Declaration) - begin + value_result = value_try do pruned_action.execute(symtab) if pruned_action.is_a?(Executable) - rescue ValueError - # ok end - StatementAst.new(input, interval, pruned_action) - else - NoopAst.new() - end - rescue ValueError - # condition not known - pruned_action = action.prune(symtab) - pruned_action.add_symbol(symtab) if pruned_action.is_a?(Declaration) - begin - pruned_action.execute(symtab) if pruned_action.is_a?(Executable) - rescue ValueError - # ok + # ok + ConditionalStatementAst.new(input, interval, pruned_action, condition.prune(symtab)) end - ConditionalStatementAst.new(input, interval, pruned_action, condition.prune(symtab)) end end class TernaryOperatorExpressionAst def prune(symtab) - begin + value_result = value_try do if condition.value(symtab) - true_expression.prune(symtab) + return true_expression.prune(symtab) else - false_expression.prune(symtab) + return false_expression.prune(symtab) end - rescue ValueError + end + value_else(value_result) do TernaryOperatorExpressionAst.new( input, interval, condition.prune(symtab), diff --git a/lib/idl/passes/reachable_exceptions.rb b/lib/idl/passes/reachable_exceptions.rb index 528ada8d2b..72f8dc5a86 100644 --- a/lib/idl/passes/reachable_exceptions.rb +++ b/lib/idl/passes/reachable_exceptions.rb @@ -8,9 +8,13 @@ module Idl class AstNode # @return [Array] List of all functions that can be reached (via function calls) from this node def reachable_exceptions(symtab) - children.reduce([]) do |list, e| - list.concat e.reachable_exceptions(symtab) - end.uniq + return 0 if @children.empty? + + mask = 0 + @children.size.times do |i| + mask |= @children[i].reachable_exceptions(symtab) + end + mask end end @@ -19,108 +23,178 @@ def reachable_exceptions(symtab) if name == "raise" # first argument is the exception code_ast = arg_nodes[0] - begin + value_result = value_try do code = code_ast.value(symtab) internal_error "Code should be an integer" unless code.is_a?(Integer) - return [code] - rescue ValueError + return 1 << code + end + value_else(value_result) do value_error "Cannot determine value of exception code" end end + # return @reachable_exceptions_func_call_cache[symtab] unless @reachable_exceptions_func_call_cache[symtab].nil? + func_def_type = func_type(symtab) - fns = [] + mask = 0 if template? template_arg_nodes.each do |t| - fns.concat(t.reachable_exceptions(symtab)) + mask |= t.reachable_exceptions(symtab) if t.is_a?(FunctionCallExpressionAst) end end arg_nodes.each do |a| - fns.concat(a.reachable_exceptions(symtab)) + mask |= a.reachable_exceptions(symtab) if a.is_a?(FunctionCallExpressionAst) end unless func_def_type.builtin? body_symtab = func_def_type.apply_template_values(template_values(symtab), self) func_def_type.apply_arguments(body_symtab, arg_nodes, symtab, self) - fns.concat(func_def_type.body.prune(body_symtab, args_already_applied: true).reachable_exceptions(body_symtab)) + begin + mask |= func_def_type.body.reachable_exceptions(body_symtab) + ensure + body_symtab.pop + body_symtab.release + end end - fns + # @reachable_exceptions_func_call_cache[symtab] = mask + mask end end class StatementAst def reachable_exceptions(symtab) - fns = action.reachable_exceptions(symtab) + mask = + # if action.is_a?(FunctionCallExpressionAst) + action.reachable_exceptions(symtab) + # else + # 0 + # end action.add_symbol(symtab) if action.is_a?(Declaration) - begin - action.execute(symtab) if action.is_a?(Executable) - rescue ValueError + if action.is_a?(Executable) + value_try do + action.execute(symtab) + end + end # ok + mask + end + end + + class IfAst + def reachable_exceptions(symtab) + mask = 0 + value_try do + mask = if_cond.reachable_exceptions(symtab) if if_cond.is_a?(FunctionCallExpressionAst) + value_result = value_try do + if (if_cond.value(symtab)) + mask |= if_body.reachable_exceptions(symtab) + return mask # no need to continue + else + elseifs.each do |eif| + mask |= eif.cond.reachable_exceptions(symtab) if eif.cond.is_a?(FunctionCallExpressionAst) + value_result = value_try do + if (eif.cond.value(symtab)) + mask |= eif.body.reachable_exceptions(symtab) + return mask # no need to keep going + end + end + value_else(value_result) do + # condition isn't known; body is potentially reachable + mask |= eif.body.reachable_exceptions(symtab) + end + end + mask |= final_else_body.reachable_exceptions(symtab) + end + end + value_else(value_result) do + mask |= if_body.reachable_exceptions(symtab) + + elseifs.each do |eif| + mask |= eif.cond.reachable_exceptions(symtab) if eif.cond.is_a?(FunctionCallExpressionAst) + value_result = value_try do + if (eif.cond.value(symtab)) + mask |= eif.body.reachable_exceptions(symtab) + return mask # no need to keep going + end + end + value_else(value_result) do + # condition isn't known; body is potentially reachable + mask |= eif.body.reachable_exceptions(symtab) + end + end + mask |= final_else_body.reachable_exceptions(symtab) + end end - fns + return mask end end class ConditionalReturnStatementAst - def reachable_functions(symtab) - fns = condition.reachable_exceptions(symtab) - if condition.value(symtab) - fns.concat return_expression.reachable_exceptions(symtab) - begin - return_expression.execute(symtab) - rescue ValueError - # ok + def reachable_exceptions(symtab) + mask = condition.is_a?(FunctionCallExpressionAst) ? condition.reachable_exceptions(symtab) : 0 + value_result = value_try do + if condition.value(symtab) + mask |= return_expression.is_a?(FunctionCallExpressionAst) ? return_expression.reachable_exceptions(symtab) : 0 + # ok end - fns - else - [] end + value_else(value_result) do + mask |= return_expression.is_a?(FunctionCallExpressionAst) ? return_expression.reachable_exceptions(symtab) : 0 + end + mask end end class ConditionalStatementAst def reachable_exceptions(symtab) - if condition.value(symtab) - fns = action.reachable_exceptions(symtab) - action.add_symbol(symtab) if action.is_a?(Declaration) - begin - action.execute(symtab) if action.is_a?(Executable) - rescue ValueError - # ok + mask = 0 + value_result = value_try do + mask |= condition.reachable_exceptions(symtab) + if condition.value(symtab) + mask |= action.reachable_exceptions(symtab) + action.add_symbol(symtab) if action.is_a?(Declaration) + if action.is_a?(Executable) + value_result = value_try do + action.execute(symtab) + end + end end - fns - else - [] end - rescue ValueError - # condition not known - fns = action.reachable_exceptions(symtab) - action.add_symbol(symtab) if action.is_a?(Declaration) - begin - action.execute(symtab) if action.is_a?(Executable) - rescue ValueError - # ok + value_else(value_result) do + mask = 0 + # condition not known + mask |= condition.reachable_exceptions(symtab) + mask |= action.reachable_exceptions(symtab) + action.add_symbol(symtab) if action.is_a?(Declaration) + if action.is_a?(Executable) + value_result = value_try do + action.execute(symtab) + end + end end - fns + mask end end class ForLoopAst def reachable_exceptions(symtab) - symtab.push - symtab.add(init.lhs.name, Var.new(init.lhs.name, init.lhs_type(symtab))) - fns = init.reachable_exceptions(symtab) - fns.concat(condition.reachable_exceptions(symtab)) - fns.concat(update.reachable_exceptions(symtab)) - stmts.each do |stmt| - fns.concat(stmt.reachable_exceptions(symtab)) + symtab.push(self) + begin + symtab.add(init.lhs.name, Var.new(init.lhs.name, init.lhs_type(symtab))) + mask = init.is_a?(FunctionCallExpressionAst) ? init.reachable_exceptions(symtab) : 0 + mask |= condition.reachable_exceptions(symtab) if condition.is_a?(FunctionCallExpressionAst) + mask |= update.reachable_exceptions(symtab) if update.is_a?(FunctionCallExpressionAst) + stmts.each do |stmt| + mask |= stmt.reachable_exceptions(symtab) + end + ensure + symtab.pop end - symtab.pop - fns.uniq + mask end end end diff --git a/lib/idl/passes/reachable_functions.rb b/lib/idl/passes/reachable_functions.rb index e7574e1871..2c9472babe 100644 --- a/lib/idl/passes/reachable_functions.rb +++ b/lib/idl/passes/reachable_functions.rb @@ -7,7 +7,8 @@ class AstNode # @return [Array] List of all functions that can be reached (via function calls) from this node def reachable_functions(symtab) children.reduce([]) do |list, e| - list.concat e.reachable_functions(symtab) + fns = e.reachable_functions(symtab) + list.concat fns end.uniq(&:name) end end @@ -20,40 +21,31 @@ def reachable_functions(symtab) body_symtab = func_def_type.apply_template_values(tvals, self) - # have we seen this exact same call already?? - key = nil + fns = [] + begin - key = [ - name, - tvals, - func_def_type.argument_values(body_symtab, arg_nodes, symtab, self) - ].hash - fns = func_def_type.func_def_ast.reachable_functions_cache[key] - return fns unless fns.nil? - rescue ValueError - # fall through, we need to evaluate - end + if template? + template_arg_nodes.each do |t| + fns.concat(t.reachable_functions(symtab)) if t.is_a?(FunctionCallExpressionAst) + end + end - fns = [] - if template? - template_arg_nodes.each do |t| - fns.concat(t.reachable_functions(symtab)) + arg_nodes.each do |a| + fns.concat(a.reachable_functions(symtab)) if a.is_a?(FunctionCallExpressionAst) end - end - arg_nodes.each do |a| - fns.concat(a.reachable_functions(symtab)) - end + func_def_type.apply_arguments(body_symtab, arg_nodes, symtab, self) - func_def_type.apply_arguments(body_symtab, arg_nodes, symtab, self) + unless func_def_type.builtin? + fns.concat(func_def_type.body.reachable_functions(body_symtab)) + end - unless func_def_type.builtin? - prune_symtab = body_symtab #.deep_clone - fns.concat(func_def_type.body.prune(prune_symtab, args_already_applied: true).reachable_functions(body_symtab)) + fns = fns.push(func_def_type.func_def_ast).uniq(&:name) + ensure + body_symtab.pop + body_symtab.release end - fns = fns.push(func_def_type.func_def_ast).uniq(&:name) - func_def_type.func_def_ast.reachable_functions_cache[key] = fns unless key.nil? fns end end @@ -61,75 +53,119 @@ def reachable_functions(symtab) class StatementAst def reachable_functions(symtab) fns = action.reachable_functions(symtab) + action.add_symbol(symtab) if action.is_a?(Declaration) - begin + value_try do action.execute(symtab) if action.is_a?(Executable) - rescue ValueError - # ok end + # ok + fns end end + + class IfAst + def reachable_functions(symtab) + fns = [] + value_try do + fns.concat if_cond.reachable_functions(symtab) if if_cond.is_a?(FunctionCallExpressionAst) + value_result = value_try do + if (if_cond.value(symtab)) + fns.concat if_body.reachable_functions(symtab) + return fns # no need to continue + else + elseifs.each do |eif| + fns.concat eif.cond.reachable_functions(symtab) if eif.cond.is_a?(FunctionCallExpressionAst) + value_result = value_try do + if (eif.cond.value(symtab)) + fns.concat eif.body.reachable_functions(symtab) + return fns # no need to keep going + end + end + value_else(value_result) do + # condition isn't known; body is potentially reachable + fns.concat eif.body.reachable_functions(symtab) + end + end + fns.concat final_else_body.reachable_functions(symtab) + end + end + value_else(value_result) do + fns.concat if_body.reachable_functions(symtab) + + elseifs.each do |eif| + fns.concat eif.cond.reachable_functions(symtab) if eif.cond.is_a?(FunctionCallExpressionAst) + value_result = value_try do + if (eif.cond.value(symtab)) + fns.concat eif.body.reachable_functions(symtab) + return fns # no need to keep going + end + end + value_else(value_result) do + # condition isn't known; body is potentially reachable + fns.concat eif.body.reachable_functions(symtab) + end + end + fns.concat final_else_body.reachable_functions(symtab) + end + end + return fns + end + end + class ConditionalReturnStatementAst def reachable_functions(symtab) - fns = condition.reachable_functions(symtab) - if condition.value(symtab) - fns.concat return_expression.reachable_functions(symtab) - begin - return_expression.execute(symtab) - rescue ValueError - # ok + fns = condition.is_a?(FunctionCallExpressionAst) ? condition.reachable_functions(symtab) : [] + value_result = value_try do + cv = condition.value(symtab) + if cv + fns.concat return_expression.reachable_functions(symtab) if return_expression.is_a?(FunctionCallExpressionAst) end - fns - else - [] end + value_else(value_result) do + fns.concat return_expression.reachable_functions(symtab) if return_expression.is_a?(FunctionCallExpressionAst) + end + + fns end end class ConditionalStatementAst def reachable_functions(symtab) - fns = condition.reachable_functions(symtab) - if condition.value(symtab) - fns.concat action.reachable_functions(symtab) - action.add_symbol(symtab) if action.is_a?(Declaration) - begin - action.execute(symtab) if action.is_a?(Executable) - rescue ValueError - # ok + + fns = condition.is_a?(FunctionCallExpressionAst) ? condition.reachable_functions(symtab) : [] + + value_result = value_try do + if condition.value(symtab) + fns.concat action.reachable_functions(symtab) if action.is_a?(FunctionCallExpressionAst) + # no need to execute action (return) end - fns - else - [] end - rescue ValueError - # condition not known - fns = action.reachable_functions(symtab) - action.add_symbol(symtab) if action.is_a?(Declaration) - begin - action.execute(symtab) if action.is_a?(Executable) - rescue ValueError - # ok + value_else(value_result) do + # condition not known + fns = fns.concat action.reachable_functions(symtab) if action.is_a?(FunctionCallExpressionAst) end + fns end end class ForLoopAst def reachable_functions(symtab) - # puts path - # puts to_idl - symtab.push - symtab.add(init.lhs.name, Var.new(init.lhs.name, init.lhs_type(symtab))) - fns = init.reachable_functions(symtab) - fns.concat(condition.reachable_functions(symtab)) - fns.concat(update.reachable_functions(symtab)) - stmts.each do |stmt| - fns.concat(stmt.reachable_functions(symtab)) + symtab.push(self) + begin + symtab.add(init.lhs.name, Var.new(init.lhs.name, init.lhs_type(symtab))) + fns = init.is_a?(FunctionCallExpressionAst) ? init.reachable_functions(symtab) : [] + fns.concat(condition.reachable_functions(symtab)) if condition.is_a?(FunctionCallExpressionAst) + fns.concat(update.reachable_functions(symtab)) if update.is_a?(FunctionCallExpressionAst) + stmts.each do |stmt| + fns.concat(stmt.reachable_functions(symtab)) + end + ensure + symtab.pop end - symtab.pop - fns.uniq + fns end end end diff --git a/lib/idl/symbol_table.rb b/lib/idl/symbol_table.rb index f1097520d8..ca97b1dc2a 100644 --- a/lib/idl/symbol_table.rb +++ b/lib/idl/symbol_table.rb @@ -91,12 +91,13 @@ def hash def initialize(arch_def, effective_xlen = nil) @archdef = arch_def - if arch_def.is_a?(ImplArchDef) - raise "effective_xlen should not be set when symbol table is given an ImplArchDef" unless effective_xlen.nil? + if arch_def.fully_configured? + raise "effective_xlen should not be set when symbol table is given a fully-configured ArchDef" unless effective_xlen.nil? else - raise "effective_xlen should be set when symbol table is given an ArchDef" if effective_xlen.nil? + raise "effective_xlen should be set when symbol table is given an ArchDef" if effective_xlen.nil? && arch_def.mxlen.nil? end @mxlen = effective_xlen.nil? ? arch_def.mxlen : effective_xlen + @callstack = [nil] @scopes = [{ "X" => Var.new( "X", @@ -116,28 +117,24 @@ def initialize(arch_def, effective_xlen = nil) ) }] - if arch_def.is_a?(ImplArchDef) - arch_def.params_with_value.each do |param_with_value| - type = Type.from_json_schema(param_with_value.schema).make_const - if type.kind == :array && type.width == :unknown - type = Type.new(:array, width: param_with_value.value.length, sub_type: type.sub_type) - end + arch_def.params_with_value.each do |param_with_value| + type = Type.from_json_schema(param_with_value.schema).make_const + if type.kind == :array && type.width == :unknown + type = Type.new(:array, width: param_with_value.value.length, sub_type: type.sub_type, qualifiers: [:const]) + end - # could already be present... - existing_sym = get(param_with_value.name) - if existing_sym.nil? - add!(param_with_value.name, Var.new(param_with_value.name, type, param_with_value.value)) - else - unless existing_sym.type.equal_to?(type) && existing_sym.value == param_with_value.value - raise DuplicateSymError, "Definition error: Param #{param.name} is defined by multiple extensions and is not the same definition in each" - end + # could already be present... + existing_sym = get(param_with_value.name) + if existing_sym.nil? + add!(param_with_value.name, Var.new(param_with_value.name, type, param_with_value.value)) + else + unless existing_sym.type.equal_to?(type) && existing_sym.value == param_with_value.value + raise DuplicateSymError, "Definition error: Param #{param.name} is defined by multiple extensions and is not the same definition in each" end end end # now add all parameters, even those not implemented - arch_def.params.each do |param| - next if arch_def.is_a?(ImplArchDef) && arch_def.params_with_value.any? { |p| p.name == param.name } - + arch_def.params_without_value.each do |param| if param.exts.size == 1 if param.name == "XLEN" # special case: we actually do know XLEN @@ -159,30 +156,30 @@ def initialize(arch_def, effective_xlen = nil) end # add the builtin extensions - add!( - "ExtensionName", - EnumerationType.new( - "ExtensionName", - arch_def.extensions.map(&:name), - Array.new(arch_def.extensions.size) { |i| i + 1 } - ) - ) - add!( - "ExceptionCode", - EnumerationType.new( - "ExceptionCode", - arch_def.exception_codes.map(&:var), - arch_def.exception_codes.map(&:num) - ) - ) - add!( - "InterruptCode", - EnumerationType.new( - "InterruptCode", - arch_def.interrupt_codes.map(&:var), - arch_def.interrupt_codes.map(&:num) - ) - ) + # add!( + # "ExtensionName", + # EnumerationType.new( + # "ExtensionName", + # arch_def.extensions.map(&:name), + # Array.new(arch_def.extensions.size) { |i| i + 1 } + # ) + # ) + # add!( + # "ExceptionCode", + # EnumerationType.new( + # "ExceptionCode", + # arch_def.exception_codes.map(&:var), + # arch_def.exception_codes.map(&:num) + # ) + # ) + # add!( + # "InterruptCode", + # EnumerationType.new( + # "InterruptCode", + # arch_def.interrupt_codes.map(&:var), + # arch_def.interrupt_codes.map(&:num) + # ) + # ) end # do a deep freeze to protect the sym table and all its entries from modification @@ -196,17 +193,39 @@ def deep_freeze # set frozen_hash so that we can quickly compare symtabs @frozen_hash = [@scopes.hash, @archdef.hash].hash + # set up the global clone that be used as a mutable table + @global_clone_pool = [] + + 5.times do + copy = SymbolTable.allocate + copy.instance_variable_set(:@scopes, [@scopes[0]]) + copy.instance_variable_set(:@callstack, [@callstack[0]]) + copy.instance_variable_set(:@archdef, @archdef) + copy.instance_variable_set(:@mxlen, @mxlen) + copy.instance_variable_set(:@global_clone_pool, @global_clone_pool) + copy.instance_variable_set(:@in_use, false) + @global_clone_pool << copy + end + freeze self end + # @return [String] inspection string + def inspect + "SymbolTable[#{@archdef.name}]#{frozen? ? ' (frozen)' : ''}" + end + # pushes a new scope # @return [SymbolTable] self - def push + def push(ast) # puts "push #{caller[0]}" # @scope_caller ||= [] # @scope_caller.push caller[0] + raise "#{@scopes.size} #{@callstack.size}" unless @scopes.size == @callstack.size @scopes << {} + @callstack << ast + @frozen_hash = nil self end @@ -216,7 +235,13 @@ def pop # puts " from #{@scope_caller.pop}" raise "Error: popping the symbol table would remove global scope" if @scopes.size == 1 + raise "?" unless @scopes.size == @callstack.size @scopes.pop + @callstack.pop + end + + def callstack + @callstack.reverse.map { |ast| ast.nil? ? "" : "#{ast.input_file}:#{ast.lineno}" }.join("\n") end # @return [Boolean] whether or not any symbol 'name' is defined at any level in the symbol table @@ -233,7 +258,8 @@ def keys_pretty # @return [Object] A symbol named 'name', or nil if not found def get(name) @scopes.reverse_each do |s| - return s[name] if s.key?(name) + result = s.fetch(name, nil) + return result unless result.nil? end nil end @@ -327,6 +353,51 @@ def print end end + # @return [Boolean] true if the symbol table is at the global scope + def at_global_scope? + @scopes.size == 1 + end + + # @return [SymbolTable] a mutable clone of the global scope of this SymbolTable + def global_clone + # raise "symtab isn't frozen" if @global_clone.nil? + # raise "global clone isn't at global scope" unless @global_clone.at_global_scope? + + @global_clone_pool.each do |symtab| + unless symtab.in_use? + symtab.instance_variable_set(:@in_use, true) + return symtab + end + end + + # need more! + warn "Allocating more SymbolTables" + 5.times do + copy = SymbolTable.allocate + copy.instance_variable_set(:@scopes, [@scopes[0]]) + copy.instance_variable_set(:@callstack, [@callstack[0]]) + copy.instance_variable_set(:@archdef, @archdef) + copy.instance_variable_set(:@mxlen, @mxlen) + copy.instance_variable_set(:@global_clone_pool, @global_clone_pool) + copy.instance_variable_set(:@in_use, false) + @global_clone_pool << copy + end + + global_clone + end + + def release + pop while levels > 1 + raise "Clone isn't back in global scope" unless at_global_scope? + raise "You are calling release on the frozen SymbolTable" if frozen? + raise "??" if @in_use.nil? + raise "Double release detected" unless @in_use + + @in_use = false + end + + def in_use? = @in_use + # @return [SymbolTable] a deep clone of this SymbolTable def deep_clone(clone_values: false, freeze_global: true) raise "don't do this" unless freeze_global @@ -336,11 +407,13 @@ def deep_clone(clone_values: false, freeze_global: true) if levels == 1 copy = dup copy.instance_variable_set(:@scopes, copy.instance_variable_get(:@scopes).dup) + copy.instance_variable_set(:@callstack, copy.instance_variable_get(:@callstack).dup) return copy end copy = dup # back up the table to global scope + copy.instance_variable_set(:@callstack, @callstack.dup) copy.instance_variable_set(:@scopes, []) c_scopes = copy.instance_variable_get(:@scopes) c_scopes.push(@scopes[0]) diff --git a/lib/idl/tests/helpers.rb b/lib/idl/tests/helpers.rb index e69ee73cde..ca26eb4ab3 100644 --- a/lib/idl/tests/helpers.rb +++ b/lib/idl/tests/helpers.rb @@ -11,18 +11,26 @@ def initialize(name) end MockExtensionParameter = Struct.new(:name, :desc, :schema, :extra_validation, :exts, :type) +MockExtensionParameterWithValue = Struct.new(:name, :desc, :schema, :extra_validation, :exts, :value) # ArchDef mock that knows about XLEN and extensions class MockArchDef def param_values = { "XLEN" => 32 } + def params_with_value = [MockExtensionParameterWithValue.new("XLEN", "mxlen", {"type" => "integer", "enum" => [32, 64]}, nil, nil, 32)] + def params_without_value = [] def params = [] def extensions = [MockExtension.new("I")] def mxlen = 64 def exception_codes = [OpenStruct.new(var: "ACode", num: 0), OpenStruct.new(var: "BCode", num: 1)] def interrupt_codes = [OpenStruct.new(var: "CoolInterrupt", num: 1)] -end -class ImplArchDef + def fully_configured? = false + def partially_configured? = true + def unconfigured? = false + + def name = "mock" + + attr_accessor :global_ast end module TestMixin diff --git a/lib/idl/tests/test_functions.rb b/lib/idl/tests/test_functions.rb index 922ba4031a..70917a73d2 100644 --- a/lib/idl/tests/test_functions.rb +++ b/lib/idl/tests/test_functions.rb @@ -18,6 +18,11 @@ def test_that_reachable_raise_analysis_respects_transitive_known_values B 1 } + enum ExceptionCode { + ACode 0 + BCode 1 + } + builtin function raise { arguments ExceptionCode code description { raise an exception} @@ -64,10 +69,16 @@ def test_that_reachable_raise_analysis_respects_transitive_known_values path = Pathname.new(t.path) - ast = @compiler.compile_file(path, symtab: @symtab) + ast = @compiler.compile_file(path) + ast.add_global_symbols(@symtab) + @symtab.deep_freeze + @archdef.global_ast = ast + ast.freeze_tree(@symtab) test_ast = ast.functions.select { |f| f.name == "test" }[0] - assert_equal [1], test_ast.body.prune(@symtab).reachable_exceptions(@symtab) + + # should return (1 << BCode), also known as 2 + assert_equal (1 << 1), test_ast.body.prune(@symtab.deep_clone).reachable_exceptions(@symtab.deep_clone) end def test_that_reachable_raise_analysis_respects_known_paths_down_an_unknown_path @@ -78,6 +89,11 @@ def test_that_reachable_raise_analysis_respects_known_paths_down_an_unknown_path B 1 } + enum ExceptionCode { + ACode 0 + BCode 1 + } + Bits<64> unknown; builtin function raise { @@ -118,10 +134,14 @@ def test_that_reachable_raise_analysis_respects_known_paths_down_an_unknown_path path = Pathname.new(t.path) - ast = @compiler.compile_file(path, symtab: @symtab) + ast = @compiler.compile_file(path) + ast.add_global_symbols(@symtab) + @symtab.deep_freeze + @archdef.global_ast = ast + ast.freeze_tree(@symtab) test_ast = ast.functions.select { |f| f.name == "test" }[0] - pruned_test_ast = test_ast.body.prune(@symtab) - assert_equal [1], pruned_test_ast.reachable_exceptions(@symtab) + pruned_test_ast = test_ast.body.prune(@symtab.deep_clone) + assert_equal (1 << 1), pruned_test_ast.reachable_exceptions(@symtab.deep_clone) end end diff --git a/lib/idl/type.rb b/lib/idl/type.rb index 46c2dafd39..bb0a58ef7f 100644 --- a/lib/idl/type.rb +++ b/lib/idl/type.rb @@ -113,6 +113,7 @@ def initialize(kind, qualifiers: [], width: nil, sub_type: nil, name: nil, tuple @width = width end end + TYPE_FROM_KIND = [:boolean, :void, :dontcare].map { |k| [k, Type.new(k)] }.to_h.freeze def clone Type.new( @@ -167,20 +168,24 @@ def equal_to?(type) if type.is_a?(Symbol) raise "#{type} is not a kind" unless KINDS.include?(type) - type = Type.new(type) + type = TYPE_FROM_KIND[type] end case @kind when :boolean - return type.kind == :boolean + type.kind == :boolean when :enum_ref - return type.kind == :enum_ref && type.name == @enum_class.name + type.kind == :enum_ref && type.name == @enum_class.name when :dontcare - return true + true when :bits - return type.kind == :bits && type.width == @width + type.kind == :bits && type.width == @width when :string - return type.kind == :string && type.width == @width + type.kind == :string && type.width == @width + when :array + type.kind == :array && type.sub_type.equal_to?(@sub_type) + when :struct + type.kind == :struct && (type.type_name == type_name) else raise "unimplemented type '#{@kind}'" end @@ -201,7 +206,7 @@ def convertable_to?(type) if type.is_a?(Symbol) raise "#{type} is not a kind" unless KINDS.include?(type) - type = Type.new(type) + type = TYPE_FROM_KIND[type] end case @kind @@ -519,24 +524,32 @@ def member_type(member_name) end class EnumerationType < Type - attr_reader :element_names, :element_values, :width, :ref_type + # @return [Integer] The bit width of the enumeration elements + attr_reader :width + + # @return [Array] The names of the enumeration elements, in the same order as element_values + attr_reader :element_names + + # @return [Array] The values of the enumeration elements, in the same order as element_names + attr_reader :element_values + # @return [Type] The type of an reference to this Enumeration class + attr_reader :ref_type + + # @param type_name [String] The name of the enum class + # @param element_names [Array] The names of the elements, in the same order as +element_values+ + # @param element_values [Array] The values of the elements, in the same order as +element_names+ def initialize(type_name, element_names, element_values) width = element_values.max.bit_length width = 1 if width.zero? # can happen if only enum member has value 0 - super(:enum, width: width) + super(:enum, width:) @name = type_name @element_names = element_names @element_values = element_values raise "unexpected" unless element_names.is_a?(Array) - # now add the constant values at the same scope - # ...or, enum values are only usable in specific contexts? - # element_names.each_index do |idx| - # syms.add!(element_names[idx], Var.new(element_names[idx], self, element_values[idx])) - # end - @ref_type = Type.new(:enum_ref, enum_class: self) + @ref_type = Type.new(:enum_ref, enum_class: self) end def clone @@ -623,20 +636,27 @@ def builtin? = @func_def_ast.builtin? def num_args = @func_def_ast.num_args - def type_check_call(template_values, func_call_ast) + def type_check_call(template_values, argument_nodes, call_site_symtab, func_call_ast) raise "Missing template values" if templated? && template_values.empty? if templated? symtab = apply_template_values(template_values, func_call_ast) + apply_arguments(symtab, argument_nodes, call_site_symtab, func_call_ast) @func_def_ast.type_check_template_instance(symtab) + + symtab.pop + symtab.release else - symtab = @symtab.deep_clone - symtab.pop while symtab.levels != 1 + symtab = @symtab.global_clone - symtab.push # to keep things consistent with template functions, push a scope + symtab.push(func_call_ast) # to keep things consistent with template functions, push a scope + + apply_arguments(symtab, argument_nodes, call_site_symtab, func_call_ast) @func_def_ast.type_check_from_call(symtab) + symtab.pop + symtab.release end end @@ -646,17 +666,16 @@ def template_types(symtab) = @func_def_ast.template_types(symtab) def templated? = @func_def_ast.templated? - def apply_template_values(template_values = [], func_call_ast) + def apply_template_values(template_values, func_call_ast) func_call_ast.type_error "Missing template values" if templated? && template_values.empty? func_call_ast.type_error "wrong number of template values in call to #{name}" unless template_names.size == template_values.size - symtab = @symtab.deep_clone - symtab.pop while symtab.levels != 1 + symtab = @symtab.global_clone func_call_ast.type_error "Symbol table should be at global scope" unless symtab.levels == 1 - symtab.push + symtab.push(func_call_ast) template_values.each_with_index do |value, idx| func_call_ast.type_error "template value should be an Integer (found #{value.class.name})" unless value == :unknown || value.is_a?(Integer) @@ -672,9 +691,10 @@ def apply_arguments(symtab, argument_nodes, call_site_symtab, func_call_ast) idx = 0 @func_def_ast.arguments(symtab).each do |atype, aname| func_call_ast.type_error "Missing argument #{idx}" if idx >= argument_nodes.size - begin + value_result = Idl::AstNode.value_try do symtab.add(aname, Var.new(aname, atype, argument_nodes[idx].value(call_site_symtab))) - rescue AstNode::ValueError => e + end + Idl::AstNode.value_else(value_result) do symtab.add(aname, Var.new(aname, atype)) end idx += 1 @@ -688,9 +708,10 @@ def argument_values(symtab, argument_nodes, call_site_symtab, func_call_ast) values = [] @func_def_ast.arguments(symtab).each do |atype, aname| func_call_ast.type_error "Missing argument #{idx}" if idx >= argument_nodes.size - begin + value_result = Idl::AstNode.value_try do values << argument_nodes[idx].value(call_site_symtab) - rescue AstNode::ValueError => e + end + Idl::AstNode.value_else(value_result) do return nil end idx += 1 @@ -705,14 +726,26 @@ def return_type(template_values, func_call_ast) symtab = apply_template_values(template_values, func_call_ast) # apply_arguments(symtab, argument_nodes, call_site_symtab) - @func_def_ast.return_type(symtab).clone + begin + type = @func_def_ast.return_type(symtab) + ensure + symtab.pop + symtab.release + end + type end def return_value(template_values, argument_nodes, call_site_symtab, func_call_ast) symtab = apply_template_values(template_values, func_call_ast) apply_arguments(symtab, argument_nodes, call_site_symtab, func_call_ast) - @func_def_ast.body.return_value(symtab) + begin + value = @func_def_ast.body.return_value(symtab) + ensure + symtab.pop + symtab.release + end + value end # @param template_values [Array] Template values to apply, required if {#templated?} @@ -721,17 +754,28 @@ def return_types(template_values, argument_nodes, call_site_symtab, func_call_as symtab = apply_template_values(template_values, func_call_ast) apply_arguments(symtab, argument_nodes, call_site_symtab, func_call_ast) - @func_def_ast.return_types(symtab).map(&:clone) + begin + types = @func_def_ast.return_types(symtab) + ensure + symtab.pop + symtab.release + end + types end def argument_type(index, template_values, argument_nodes, call_site_symtab, func_call_ast) return nil if index >= @func_def_ast.num_args symtab = apply_template_values(template_values, func_call_ast) - apply_arguments(symtab, argument_nodes, call_site_symtab, func_call_ast) + # apply_arguments(symtab, argument_nodes, call_site_symtab, func_call_ast) - arguments = @func_def_ast.arguments(symtab) - arguments[index][0].clone + begin + arguments = @func_def_ast.arguments(symtab) + ensure + symtab.pop + symtab.release + end + arguments[index][0] end def argument_name(index, template_values = [], func_call_ast) @@ -740,7 +784,12 @@ def argument_name(index, template_values = [], func_call_ast) symtab = apply_template_values(template_values, func_call_ast) # apply_arguments(symtab, argument_nodes, call_site_symtab) - arguments = @func_def_ast.arguments(symtab) + begin + arguments = @func_def_ast.arguments(symtab) + ensure + symtab.pop + symtab.relase + end arguments[index][1] end diff --git a/lib/template_helpers.rb b/lib/template_helpers.rb new file mode 100644 index 0000000000..d1d05750a5 --- /dev/null +++ b/lib/template_helpers.rb @@ -0,0 +1,83 @@ +module TemplateHelpers + # Insert a hyperlink to an extension. + # + # At this point, we insert a placeholder since it will be up + # to the backend to create a specific link. + # + # @param name [#to_s] Name of the extension + def link_to_ext(name) + "%%LINK%ext;#{name};#{name}%%" + end + + # Insert a hyperlink to an instruction. + # + # At this point, we insert a placeholder since it will be up + # to the backend to create a specific link. + # + # @param name [#to_s] Name of the instruction + def link_to_inst(name) + "%%LINK%inst;#{name};#{name}%%" + end + + # Insert a hyperlink to a CSR. + # + # At this point, we insert a placeholder since it will be up + # to the backend to create a specific link. + # + # @param name [#to_s] Name of the CSR + def link_to_csr(name) + "%%LINK%csr;#{name};#{name}%%" + end + + # Insert a hyperlink to a CSR field. + # + # At this point, we insert a placeholder since it will be up + # to the backend to create a specific link. + # + # @param csr_name [#to_s] Name of the CSR + # @param field_name [#to_s] Name of the CSR field + def link_to_csr_field(csr_name, field_name) + "%%LINK%csr_field;#{csr_name}.#{field_name};#{csr_name}.#{field_name}%%" + end + + # Insert anchor to an extension. + # + # At this point, we insert a placeholder since it will be up + # to the backend to create a specific link. + # + # @param name [#to_s] Name of the extension + def anchor_for_ext(name) + "[[ext-#{name.gsub(".", "_")}-def]]" + end + + # Insert anchor to an instruction. + # + # At this point, we insert a placeholder since it will be up + # to the backend to create a specific link. + # + # @param name [#to_s] Name of the instruction + def anchor_for_inst(name) + "[[inst-#{name.gsub(".", "_")}-def]]" + end + + # Insert anchor to a CSR. + # + # At this point, we insert a placeholder since it will be up + # to the backend to create a specific link. + # + # @param name [#to_s] Name of the CSR + def anchor_for_csr(name) + "[[csr-#{name.gsub(".", "_")}-def]]" + end + + # Insert anchor to a CSR field. + # + # At this point, we insert a placeholder since it will be up + # to the backend to create a specific link. + # + # @param csr_name [#to_s] Name of the CSR + # @param field_name [#to_s] Name of the CSR field + def anchor_for_csr_field(csr_name, field_name) + "[[csr_field-#{csr_name.gsub(".", "_")}-#{field_name.gsub(".", "_")}-def]]" + end +end \ No newline at end of file diff --git a/lib/validate.rb b/lib/validate.rb index 421935d2b3..406b817c9a 100644 --- a/lib/validate.rb +++ b/lib/validate.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true +require "date" require "json" require "json_schemer" require "pathname" @@ -95,7 +96,7 @@ def initialize(result) end end - # iniailize a new Validator + # initialize a new Validator # # @raise [SchemaError] if a schema is ill-formed def initialize @@ -132,7 +133,7 @@ def validate_str(str, type: nil, schema_path: nil) raise "Invalid type #{type}" unless TYPES.any?(type) || !schema_path.nil? begin - obj = YAML.safe_load(str, permitted_classes: [Symbol]) + obj = YAML.safe_load(str, permitted_classes: [Symbol, Date]) rescue Psych::SyntaxError => e warn "While parsing: #{str}\n\n" raise e @@ -198,7 +199,13 @@ def validate(path, type: nil) end end begin - validate_str(File.read(path.to_s), type:, schema_path:) + obj = validate_str(File.read(path.to_s), type:, schema_path:) + + # check that the top key matches the filename + if [:inst, :ext, :csr].include?(type) && obj.keys.first != File.basename(path, ".yaml").to_s + raise ValidationError, "In #{path}, top key '#{obj.keys.first}' does not match filename '#{File.basename(path)}'" + end + obj rescue Psych::SyntaxError => e warn "While parsing #{path}" raise e diff --git a/schemas/arch_schema.json b/schemas/arch_schema.json index 63de02d596..bfed75d58d 100644 --- a/schemas/arch_schema.json +++ b/schemas/arch_schema.json @@ -4,15 +4,34 @@ "type": "object", "title": "Unified Architecture Specification", "required": [ + "type", "extensions", - "implemented_extensions", "csrs", - "implemented_csrs", - "params", - "instructions", - "implemented_instructions" + "instructions" + ], + "allOf": [ + { + "if": { + "properties": { + "type": { "enum": ["partially configured", "fully configured"]} + } + }, + "then": { + "required": [ + "implemented_instructions", + "implemented_extensions", + "implemented_csrs", + "params" + ] + } + } ], "properties": { + "type": { + "type": "string", + "description": "Type of the arch", + "enum": ["unconfigured", "partially configured", "fully configured"] + }, "params": { "type": "object" }, @@ -85,6 +104,21 @@ "pattern": "^[a-z][a-zA-Z0-9.]+$", "description": "Instruction name" } + }, + "profile_families": { + "type": "object" + }, + "profiles": { + "type": "object" + }, + "manuals": { + "type": "object" + }, + "crd_families": { + "type": "object" + }, + "crds": { + "type": "object" } }, "additionalProperties": false diff --git a/schemas/csr_schema.json b/schemas/csr_schema.json index 74c61fb859..95998c6a04 100644 --- a/schemas/csr_schema.json +++ b/schemas/csr_schema.json @@ -15,25 +15,16 @@ "description": "Name of the field. Optional because it is implied by the object key of the CSR object holding the field" }, "location": { - "oneOf": [ - {"type": "number", "description": "Location of a single bit"}, - {"type": "string", "pattern": "^[0-9]+-[0-9]+$", "description": "Location range of a multibit field"} - ], + "$ref": "schema_defs.json#/$defs/field_location", "description": "Location of the field within the CSR register" }, "location_rv32": { - "description": "Location of the field within the CSR register when the effective XLEN of the current mode is 32", - "oneOf": [ - {"type": "number", "description": "Location of a single bit"}, - {"type": "string", "pattern": "^[0-9]+-[0-9]+$", "description": "Location range of a multibit field"} - ] + "$ref": "schema_defs.json#/$defs/field_location", + "description": "Location of the field within the CSR register when the effective XLEN of the current mode is 32" }, "location_rv64": { - "description": "Location of the field within the CSR register when the effective XLEN of the current mode is 64", - "oneOf": [ - {"type": "number", "description": "Location of a single bit"}, - {"type": "string", "pattern": "^[0-9]+-[0-9]+$", "description": "Location range of a multibit field"} - ] + "$ref": "schema_defs.json#/$defs/field_location", + "description": "Location of the field within the CSR register when the effective XLEN of the current mode is 64" }, "reset_value": { "description": "Value of the state after reset. Can be UNDEFINED_LEGAL for the generic architecture spec, but must have an integer value for the implementation spec", @@ -95,17 +86,7 @@ "description": "When specified, indicates that this field aliases (a portion of) another CSR field" }, "definedBy": { - "oneOf": [ - { - "$ref": "schema_defs.json#/$defs/extension_requirement" - }, - { - "type": "array", - "items": { - "$ref": "schema_defs.json#/$defs/extension_requirement" - } - } - ], + "$ref": "schema_defs.json#/$defs/requires_entry", "description": "Where this field is defined: indicates that the field is only present if the extension(s) are implemented. If definedBy is not given, defaults to the definedBy field of the parent CSR" }, "affectedBy": { @@ -203,17 +184,7 @@ "description": "A full Asciidoc description of the CSR, indended to be used as documentation." }, "definedBy": { - "oneOf": [ - { - "$ref": "schema_defs.json#/$defs/extension_requirement" - }, - { - "type": "array", - "items": { - "$ref": "schema_defs.json#/$defs/extension_requirement" - } - } - ], + "$ref": "schema_defs.json#/$defs/requires_entry", "description": "Extension(s) that define the CSR" }, "address": { diff --git a/schemas/ext_schema.json b/schemas/ext_schema.json index d1071745e7..9ae365f400 100644 --- a/schemas/ext_schema.json +++ b/schemas/ext_schema.json @@ -34,29 +34,6 @@ }, "additionalProperties": false }, - "requires_entry": { - "oneOf": [ - { "$ref": "schema_defs.json#/$defs/extension_requirement" }, - { - "type": "object", - "properties": { - "anyOf": { - "type": "array", - "items": { - "$ref": "#/$defs/requires_entry" - } - }, - "allOf": { - "type": "array", - "items": { - "$ref": "#/$defs/requires_entry" - } - }, - "additionalProperties": false - } - } - ] - }, "ext_data": { "type": "object", "required": ["description", "long_name", "versions"], @@ -106,6 +83,13 @@ "additionalProperties": false }, "type": { "enum": ["unprivileged", "privileged"] }, + "conflicts": { + "description": "Extension(s) that conflict with this extension; both cannot be implemented at the same time", + "oneOf": [ + { "$ref": "schema_defs.json#/$defs/extension_requirement" }, + { "type": "array", "items": { "$ref": "schema_defs.json#/$defs/extension_requirement" }} + ] + }, "versions": { "type": "array", "items": { @@ -161,14 +145,7 @@ }, "requires": { "description": "Extension(s) required by this extension", - "$ref": "#/$defs/requires_entry" - }, - "conflicts": { - "description": "Extension(s) that conflict with this extension; both cannot be implemented at the same time", - "oneOf": [ - { "$ref": "schema_defs.json#/$defs/extension_requirement" }, - { "type": "array", "items": { "$ref": "schema_defs.json#/$defs/extension_requirement" }} - ] + "$ref": "schema_defs.json#/$defs/requires_entry" }, "contributors": { "description": "List of contributors to this version of the extension", @@ -276,6 +253,10 @@ } }, "additionalProperties": false + }, + "__source": { + "type": "string", + "description": "Source file where this extension was defined" } }, "additionalProperties": false diff --git a/schemas/inst_schema.json b/schemas/inst_schema.json index 1e44df8ea9..ce7fa67ce1 100644 --- a/schemas/inst_schema.json +++ b/schemas/inst_schema.json @@ -103,33 +103,9 @@ "description": "Detailed description of the instruction" }, "definedBy": { - "oneOf": [ - { - "$ref": "schema_defs.json#/$defs/extension_requirement" - }, - { - "type": "array", - "items": { - "$ref": "schema_defs.json#/$defs/extension_requirement" - } - } - ], + "$ref": "schema_defs.json#/$defs/requires_entry", "description": "Extension(s) that defines the instruction" }, - "requires": { - "oneOf": [ - { - "$ref": "schema_defs.json#/$defs/extension_requirement" - }, - { - "type": "array", - "items": { - "$ref": "schema_defs.json#/$defs/extension_requirement" - } - } - ], - "description": "Extension(s) that must also be present (in addition to definedBy) for the instruction to exist" - }, "excludedBy": { "oneOf": [ { diff --git a/schemas/schema_defs.json b/schemas/schema_defs.json index 40221c8ab6..cd74503f4d 100644 --- a/schemas/schema_defs.json +++ b/schemas/schema_defs.json @@ -8,6 +8,13 @@ "type": "string", "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$" }, + "field_location": { + "oneOf": [ + {"type": "number", "description": "Location of a single bit"}, + {"type": "string", "pattern": "^[0-9]+-[0-9]+$", "description": "Location range of a multibit field"} + ], + "description": "Location of a field in a register" + }, "spec_state": { "type": "string", "enum": [ @@ -64,24 +71,52 @@ "extension_requirement": { "description": "A requirement on an extension. Can either specify just an extension name, in which case version '>= 0' is implied, or both a name and a requirement", "oneOf": [ + { "$ref": "#/$defs/extension_name" }, { - "$ref": "#/$defs/extension_name" - }, - { - "type": "array", - "items": [ - { + "type": "object", + "properties": { + "name": { "$ref": "#/$defs/extension_name" }, - { + "version": { "$ref": "#/$defs/version_requirements" } - ], - "additionalItems": false + }, + "required": ["name"], + "additionalProperties": false } ] }, + "requires_entry": { + "oneOf": [ + { "$ref": "#/$defs/extension_requirement" }, + { + "type": "object", + "properties": { + "anyOf": { + "type": "array", + "items": { + "$ref": "#/$defs/requires_entry" + } + }, + "allOf": { + "type": "array", + "items": { + "$ref": "#/$defs/requires_entry" + } + }, + "oneOf": { + "type": "array", + "items": { + "$ref": "#/$defs/requires_entry" + } + } + }, + "additionalProperties": false + } + ] + }, "author": { "type": "object", "required": ["name"],