From dfc6c6d92c457ac1ed966a4d0d09835264a4a169 Mon Sep 17 00:00:00 2001 From: James Ball Date: Tue, 1 Oct 2024 18:52:30 -0700 Subject: [PATCH] Added instruction and CSR appendixes to CRD --- arch/csc_crd/MC-1.yaml | 8 +- arch/csr/mstatus.yaml | 1 + arch/ext/Sm.yaml | 10 +- arch/ext/pmpaddr3.yaml | 76 ----- backends/csc_crd_doc/templates/crd.adoc.erb | 310 ++++++++++++++++-- .../templates/profile_pdf.adoc.erb | 8 +- lib/arch_obj_models/csc_crd.rb | 23 +- 7 files changed, 318 insertions(+), 118 deletions(-) delete mode 100644 arch/ext/pmpaddr3.yaml diff --git a/arch/csc_crd/MC-1.yaml b/arch/csc_crd/MC-1.yaml index d002b98a9..a3f6f7901 100644 --- a/arch/csc_crd/MC-1.yaml +++ b/arch/csc_crd/MC-1.yaml @@ -92,12 +92,8 @@ MC-1: const: 0 #XXX optional: {} # None optional: - - name: B - note: "This is just for testing. B isn't really optional for MC-1." - param_constraints: - MUTABLE_MISA_B: - schema: - const: false + - name: Zifencei + note: "This is just for testing. Zifencei extension isn't really optional for MC-1." requirement_groups: - name: MC-Unpriv diff --git a/arch/csr/mstatus.yaml b/arch/csr/mstatus.yaml index 9cae3c900..98701bec1 100644 --- a/arch/csr/mstatus.yaml +++ b/arch/csr/mstatus.yaml @@ -485,4 +485,5 @@ mstatus: * When 1, (H)S-mode interrupts that are not otherwise disabled with a field in `sie` are enabled. type: RW-H + definedBy: S reset_value: UNDEFINED_LEGAL diff --git a/arch/ext/Sm.yaml b/arch/ext/Sm.yaml index 05c9869b5..635e5a10f 100644 --- a/arch/ext/Sm.yaml +++ b/arch/ext/Sm.yaml @@ -95,7 +95,15 @@ Sm: interrupt-pending registers is not immediate. - Clarified that MXR affects only explicit memory accesses. description: | - TODO + This chapter describes the machine-level operations available in machine-mode (M-mode), which is + the highest privilege mode in a RISC-V hart. M-mode is used for low-level access to a hardware + platform and is the first mode entered at reset. M-mode can also be used to implement features that + are too difficult or expensive to implement in hardware directly. The RISC-V machine-level ISA + contains a common core that is extended depending on which other privilege levels are supported and + other details of the hardware implementation. + This chapter describes the RISC-V machine-level architecture, which + contains a common core that is used with various supervisor-level + address translation and protection schemes. interrupt_codes: - num: 1 name: Supervisor software interrupt diff --git a/arch/ext/pmpaddr3.yaml b/arch/ext/pmpaddr3.yaml deleted file mode 100644 index d1ca6017f..000000000 --- a/arch/ext/pmpaddr3.yaml +++ /dev/null @@ -1,76 +0,0 @@ -# yaml-language-server: $schema=../../../schemas/csr_schema.json - -# WARNING: This file is auto-generated from arch/csr/I/pmpaddrN.layout - - - -pmpaddr3: - long_name: PMP Address 3 - address: 0x3B3 - priv_mode: M - length: MXLEN - description: PMP entry address - definedBy: Sm - fields: - ADDR: - location_rv32: 31-0 - location_rv64: 63-0 - description: | - Bits PHYS_ADDR_WIDTH-1:2 of the address specifier for PMP entry 3 - (or, if `pmp4cfg.A` == TOR, for PMP entry 4). - type(): | - if (NUM_PMP_ENTRIES > 3) { - return CsrFieldType::RW; - } else { - return CsrFieldType::RO; - } - reset_value(): | - if (NUM_PMP_ENTRIES > 3) { - return UNDEFINED_LEGAL; - } else { - return 0; - } - sw_write(csr_value): | - if (csr_value.ADDR >= (PHYS_ADDR_WIDTH >> 2)) { - return UNDEFINED_LEGAL_DETERMINISTIC; - } else if (NUM_PMP_ENTRIES > 3) { - return UNDEFINED_LEGAL_DETERMINISTIC; - } else { - return csr_value.ADDR; - } - sw_read(): | - # when the mode is NAPOT and PMP_GRANULARITY >= 16, - # bits (PMP_GRANULARITY-4):0 must read as ones - if (XLEN == 32) { - if ((PMP_GRANULARITY >= 16) && - (CSR[pmpcfg0].pmp3cfg[4] == 1)) { - return CSR[pmpaddr3].ADDR | {PMP_GRANULARITY-3{1'b1}}; - - # when the mode is OFF or TOR and PMP_GRANULARITY >= 8, - # bits (PMP_GRANULARITY-3):0 must read as zeros - } else if ((PMP_GRANULARITY >= 8) && - (CSR[pmpcfg0].pmp3cfg[4] == 0)) { - Bits mask = {PMP_GRANULARITY-2{1'b1}}; - return CSR[pmpaddr3].ADDR & ~mask; - - # no modifications needed - } else { - return CSR[pmpaddr3].ADDR; - } - } else { - if ((PMP_GRANULARITY >= 16) && - (CSR[pmpcfg0].pmp3cfg[4] == 1)) { - return CSR[pmpaddr3].ADDR | {PMP_GRANULARITY-3{1'b1}}; - - # when the mode is OFF or TOR and PMP_GRANULARITY >= 8, - # bits (PMP_GRANULARITY-3):0 must read as zeros - } else if ((PMP_GRANULARITY >= 8) && - (CSR[pmpcfg0].pmp3cfg[4] == 0)) { - Bits mask = {PMP_GRANULARITY-2{1'b1}}; - return CSR[pmpaddr3].ADDR & ~mask; - - # no modifications needed - } else { - return CSR[pmpaddr3].ADDR; - } - } diff --git a/backends/csc_crd_doc/templates/crd.adoc.erb b/backends/csc_crd_doc/templates/crd.adoc.erb index 636f87ee5..251dcb7dd 100644 --- a/backends/csc_crd_doc/templates/crd.adoc.erb +++ b/backends/csc_crd_doc/templates/crd.adoc.erb @@ -1,9 +1,21 @@ + // Number heading sections (e.g., 1.0, 1.1, etc.) :sectnums: // Add a table of contents for HTML (and VSCode adoc preview) :toc: left +// Include headings up to 3 levels deep (don't know why 5 gives you this). +:toclevels: 5 + +// +// Stuff to generate nice wavedrom drawings of instruction and CSR fields +// +:wavedrom: <%= $root %>/node_modules/.bin/wavedrom-cli + +// TODO: needs to be changed +:imagesoutdir: images + = <%= crd.name %> Certification Requirements Document [Preface] @@ -54,11 +66,11 @@ a| <%- rev.changes.each do |change| %> |=== | M | S | U | VS | VU -| <%- if crd.family.mandatory_priv_modes.include?('M') -%> MANDATORY <%- else -%> OUT OF SCOPE <%- end -%> -| <%- if crd.family.mandatory_priv_modes.include?('S') -%> MANDATORY <%- else -%> OUT OF SCOPE <%- end -%> -| <%- if crd.family.mandatory_priv_modes.include?('U') -%> MANDATORY <%- else -%> OUT OF SCOPE <%- end -%> -| <%- if crd.family.mandatory_priv_modes.include?('VS') -%> MANDATORY <%- else -%> OUT OF SCOPE <%- end -%> -| <%- if crd.family.mandatory_priv_modes.include?('VU') -%> MANDATORY <%- else -%> OUT OF SCOPE <%- end -%> +| <%- if crd.family.mandatory_priv_modes.include?('M') -%> MANDATORY <%- else -%> OUT-OF-SCOPE <%- end -%> +| <%- if crd.family.mandatory_priv_modes.include?('S') -%> MANDATORY <%- else -%> OUT-OF-SCOPE <%- end -%> +| <%- if crd.family.mandatory_priv_modes.include?('U') -%> MANDATORY <%- else -%> OUT-OF-SCOPE <%- end -%> +| <%- if crd.family.mandatory_priv_modes.include?('VS') -%> MANDATORY <%- else -%> OUT-OF-SCOPE <%- end -%> +| <%- if crd.family.mandatory_priv_modes.include?('VU') -%> MANDATORY <%- else -%> OUT-OF-SCOPE <%- end -%> |=== @@ -66,8 +78,8 @@ a| <%- rev.changes.each do |change| %> === Summary -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. +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. [%autowidth] |=== @@ -76,7 +88,7 @@ Any extension not listed in the table below is OUT OF SCOPE. <%- crd.extension_reqs.sort.each do |ext_req| -%> <%- ext = crd.arch_def.extension(ext_req.name) -%> | <%= ext_req.req_id %> -| <%= ext_req.name %> +| <,<%= ext_req.name %>>> | <%= ext_req.version_requirement %> | <%= ext_req.status.upcase %> | <%= ext.nil? ? "" : ext.long_name %> @@ -86,6 +98,7 @@ Any extension not listed in the table below is OUT OF SCOPE. <%- crd.extension_reqs.sort.each do |ext_req| -%> <%- ext = crd.arch_def.extension(ext_req.name) -%> +[[anchor-ext-requirement-<%= ext_req.name %>]] === Extension <%= ext_req.name %> + *Requirement ID*: <%= ext_req.req_id %> + <%= ext.nil? ? "" : "*Long Name*: " + ext.long_name + " +" %> @@ -99,10 +112,7 @@ Any extension not listed in the table below is OUT OF SCOPE. <%- end -%> <%- unless crd.param_constraints(ext_req).empty? -%> -==== IN SCOPE Parameters - -These parameters are covered by an <%= crd.name %> certificate. - +.<%= ext_req.name %> Extension IN-SCOPE Parameters [cols="3,1,2"] |=== | Parameter | Constraint | Note @@ -115,10 +125,7 @@ a| <%= constraint.note %> <%- end # unless table -%> <%- unless crd.out_of_scope_params(ext_req.name).empty? -%> -==== OUT OF SCOPE Parameters - -These parameters are *NOT* covered by an <%= crd.name %> certificate. - +.<%= ext_req.name %> Extension OUT-OF-SCOPE Parameters <%- crd.out_of_scope_params(ext_req.name).sort.each do |param_db| -%> * <-param-<%= param_db.name %>,<%= param_db.name %>>> <%- end # do constraint -%> @@ -157,7 +164,7 @@ Requirement <%= req.name %> only apply when <%= req.when_pretty %>. <%- end -%> [appendix] -== Extension Descriptions +== Extension Specifications <%- crd.extension_reqs.sort.each do |ext_req| -%> <%- ext = crd.arch_def.extension(ext_req.name) -%> @@ -166,6 +173,31 @@ Requirement <%= req.name %> only apply when <%= req.when_pretty %>. *Version Requirement*: <%= ext_req.version_requirement %> + +<%- ext.versions.each do |v| -%> +<%= v["version"] %>:: + Ratification date::: + <%= v["ratification_date"] %> + <%- if v.key?("changes") -%> + Changes::: + + <%- v["changes"].each do |c| -%> + * <%= c %> + <%- end -%> + + <%- end -%> + <%- if v.key?("url") -%> + Ratification document::: + <%= v["url"] %> + <%- end -%> + <%- if v.key?("implies") -%> + Implies::: + <%- implications = v["implies"][0].is_a?(Array) ? v["implies"] : [v["implies"]] -%> + <%- implications.each do |i| -%> + * `<%= i[0] %>` version <%= i[1] %> + <%- end -%> + <%- end -%> +<%- end -%> + ==== Synopsis :leveloffset: +3 @@ -180,19 +212,23 @@ Requirement <%= req.name %> only apply when <%= req.when_pretty %>. <%= ext_req.note %> -- <%- end -%> -<%- end -%> -[appendix] -== Extension Parameters -<%- crd.extension_reqs.sort.each do |ext_req| -%> -<%- ext = crd.arch_def.extension(ext_req.name) -%> +<%- insts = crd.arch_def.instructions.select { |i| i.definedBy == ext.name || i.definedBy.include?(ext.name) } -%> +<%- unless insts.empty? -%> +==== Instructions + +The following instructions are added by this extension: + +[cols="1,3"] +|=== +<%- insts.each do |inst| -%> + | <%= "`#{inst.name}`" %> | *<%= inst.long_name %>* +<%- end -%> +|=== +<%- end -%> -=== Extension <%= ext_req.name %> + -<%- if crd.arch_def.extension(ext_req.name).params.empty? -%> -None -<%- end %> <%- unless crd.param_constraints(ext_req).empty? -%> -==== IN SCOPE Parameters +==== IN-SCOPE Parameters <%- crd.param_constraints(ext_req).sort.each do |constraint| -%> [[anchor-ext-<%= ext_req.name %>-param-<%= constraint.param_db.name %>]] @@ -205,7 +241,7 @@ None <%- end # unless table -%> <%- unless crd.out_of_scope_params(ext_req.name).empty? -%> -==== OUT OF SCOPE Parameters +==== 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 %>]] @@ -216,4 +252,222 @@ None -- <%- end # do constraint -%> <%- end # unless table -%> +<%- end # do ext_req -%> + +[appendix] +== Instruction Specifications + +<%= + insts = crd.extensions.map { |ext| ext.instructions }.flatten.uniq + insts.sort_by!(&:name) +-%> + +<%- insts.each do |inst| -%> +<<< +[[inst-<%=inst.name.gsub('.', '_')%>-def]] +=== <%= inst.name %> + +*<%= 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 -%> + +==== Encoding + +<%- if inst.multi_encoding? -%> +[NOTE] +This instruction has different encodings in RV32 and RV64. + +[tabs] +==== +RV32:: ++ +[wavedrom, ,svg,subs='attributes',width="100%"] +.... +<%= JSON.dump inst.wavedrom_desc(32) %> +.... + +RV64:: ++ +[wavedrom, ,svg,subs='attributes',width="100%"] +.... +<%= JSON.dump inst.wavedrom_desc(64) %> +.... +==== +<%- else -%> +[wavedrom, ,svg,subs='attributes',width="100%"] +.... +<%= JSON.dump inst.wavedrom_desc(inst.base.nil? ? 32 : inst.base) %> +.... +<%- end -%> + +==== Synopsis + +<%= inst.description %> + +==== Access +<%- if crd.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 -%> + +| [.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" } %> +| [.access-<%=inst.access['vs']%>]#<%= inst.access['vs'].capitalize %># +| [.access-<%=inst.access['vu']%>]#<%= inst.access['vu'].capitalize %># +<% end %> +|=== + +<%- if inst.access_detail? -%> +<%= inst.access_detail %> +<%- end -%> + +==== Decode Variables + +<%- if inst.multi_encoding? -%> +[tabs] +==== +RV32:: ++ +[source.idl] +---- +<%- inst.decode_variables(32).each do |d| -%> +<%= d.sext? ? 'signed ' : '' %>Bits<<%= d.size %>> <%= d.name %> = <%= d.extract %>; +<%- end -%> +---- + +RV64:: ++ +[source,idl] +---- +<%- inst.decode_variables(64).each do |d| -%> +<%= d.sext? ? 'signed ' : '' %>Bits<<%= d.size %>> <%= d.name %> = <%= d.extract %>; +<%- end -%> +---- +==== +<%- else -%> +[source,idl] +---- +<%- inst.decode_variables(inst.base.nil? ? 32 : inst.base).each do |d| -%> +<%= d.sext? ? 'signed ' : '' %>Bits<<%= d.size %>> <%= d.name %> = <%= d.extract %>; +<%- end -%> +---- +<%- end -%> + +==== Execution + +<%- xlens = inst.base.nil? ? [32, 64] : [inst.base] -%> + +<%- if inst.key?("operation()") -%> +[source,idl,subs="specialchars,macros"] +---- +<%= inst.operation_ast(crd.arch_def.idl_compiler).gen_adoc %> +---- +<%- end -%> + +==== Exceptions + +// 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) -% > +<%- if exception_list.empty? -% > +This instruction does not generate synchronous exceptions. +<%- else -% > +This instruction may result in the following synchronous exceptions: + + <%- exception_list.sort.each do |etype| -% > + * <%= etype % > + <%- end -% > + +<%- end -% > +%> + +<%- end -%> + +[appendix] +== CSR Specifications + +<%- + csrs = crd.extensions.map { |ext| ext.csrs }.flatten.uniq + csrs.sort_by!(&:name) +-%> + +<%- csrs.each do |csr| -%> +<<< +[[csr-<%= csr.name %>-def]] +=== <%= csr.name %> + +*<%= csr.long_name %>* + +<%- unless csr.base.nil? -%> +[NOTE] +-- +`<%= csr.name %>` is only defined in RV<%= csr.base %>. +-- +<%- end -%> + +<%= csr.description %> + +==== Attributes +[%autowidth] +|=== +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(", ") %> +<%- if csr.dynamic_length?(crd.arch_def) -%> +h| Length | <%= csr.length_pretty(crd.arch_def) %> +<%- else -%> +h| Length | <%= csr.length_pretty(crd.arch_def) %> +<%- end -%> +h| Privilege Mode | <%= csr.priv_mode %> +|=== + + +==== Format +<%- unless csr.dynamic_length?(crd.arch_def) || csr.fields.any? { |f| f.dynamic_location?(crd.arch_def) } -%> +<%# CSR has a known static length, so there is only one format to display -%> +.<%= csr.name %> format +[wavedrom, ,svg,subs='attributes',width="100%"] +.... +<%= JSON.dump csr.wavedrom_desc(crd.arch_def, csr.base.nil? ? 32 : csr.base) %> +.... +<%- else -%> +<%# CSR has a dynamic length, or a field has a dynamic location, + so there is more than one format to display -%> +This CSR format changes dynamically with XLEN. + +.<%= csr.name %> Format when <%= csr.length_cond32 %> +[wavedrom, ,svg,subs='attributes',width="100%"] +.... +<%= JSON.dump csr.wavedrom_desc(crd.arch_def, 32) %> +.... + +.<%= csr.name %> Format when <%= csr.length_cond64 %> +[wavedrom, ,svg,subs='attributes',width="100%"] +.... +<%= JSON.dump csr.wavedrom_desc(crd.arch_def, 64) %> +.... + + +<%- end -%> + <%- end -%> \ No newline at end of file diff --git a/backends/profile_doc/templates/profile_pdf.adoc.erb b/backends/profile_doc/templates/profile_pdf.adoc.erb index d0dad6a5e..081bd7455 100644 --- a/backends/profile_doc/templates/profile_pdf.adoc.erb +++ b/backends/profile_doc/templates/profile_pdf.adoc.erb @@ -18,7 +18,7 @@ :experimental: :reproducible: :wavedrom: <%= $root %>/node_modules/.bin/wavedrom-cli -// needs to be changed +// TODO: needs to be changed :imagesoutdir: images :icons: font :lang: en @@ -440,7 +440,11 @@ end.join(" | ") -%> <%= v["ratification_date"] %> <%- if v.key?("changes") -%> Changes::: - <%= v["changes"] %> + + <%- v["changes"].each do |c| -%> + * <%= c %> + <%- end -%> + <%- end -%> <%- if v.key?("url") -%> Ratification document::: diff --git a/lib/arch_obj_models/csc_crd.rb b/lib/arch_obj_models/csc_crd.rb index 4415c383a..bcb7317c8 100644 --- a/lib/arch_obj_models/csc_crd.rb +++ b/lib/arch_obj_models/csc_crd.rb @@ -58,13 +58,13 @@ def eql?(other) end def crds - return @versions unless @version.nil? + return @crds unless @version.nil? - @versions = [] + @crds = [] arch_def.csc_crds.each do |csc_crd| - @versions << csc_crd if csc_crd.famly == self + @crds << csc_crd if csc_crd.famly == self end - @versions + @crds end end @@ -105,7 +105,7 @@ def debug_manual_revision = @data["debug_manual_revision"] def description = @data["description"] - # @return [Array] - # An extension with its CRD information. + # @return [Array] - # Extensions with their CRD information. def extension_reqs return @extension_reqs_crd unless @extension_reqs_crd.nil? @@ -120,6 +120,19 @@ def extension_reqs @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)