diff --git a/backends/common_templates/adoc/README.adoc b/backends/common_templates/adoc/README.adoc new file mode 100644 index 000000000..a17bf4ffe --- /dev/null +++ b/backends/common_templates/adoc/README.adoc @@ -0,0 +1 @@ +This directory contains partial templates (e.g., a CSR description) to be used by document generators. diff --git a/backends/common_templates/adoc/csr.adoc.erb b/backends/common_templates/adoc/csr.adoc.erb new file mode 100644 index 000000000..01f208f84 --- /dev/null +++ b/backends/common_templates/adoc/csr.adoc.erb @@ -0,0 +1,123 @@ +<%= anchor_for_csr(csr.name) %> += <%= csr.name %> + +*<%= csr.long_name %>* + +<%= 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 -%> +<%- if csr.dynamic_length?(arch_def) -%> +h| Length | <%= csr.length_pretty(arch_def) %> +<%- else -%> +h| Length | <%= csr.length_pretty(arch_def) %>-bit +<%- end -%> +h| Privilege Mode | <%= csr.priv_mode %> +|=== + +== Format +<%- unless csr.dynamic_length?(arch_def) || csr.fields.any? { |f| f.dynamic_location?(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(arch_def, 64) %> +.... +<%- 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. + +.<%= csr.name %> Format when <%= csr.length_cond32 %> +[wavedrom, ,svg,subs='attributes',width="100%"] +.... +<%= JSON.dump csr.wavedrom_desc(arch_def, 32) %> +.... + +.<%= csr.name %> Format when <%= csr.length_cond64 %> +[wavedrom, ,svg,subs='attributes',width="100%"] +.... +<%= JSON.dump csr.wavedrom_desc(arch_def, 64) %> +.... +<%- end -%> + +== Field Summary + +[%autowidth,float="center",align="center",cols="^,<,<,<",options="header",role="stretch"] +|=== +|Name | Location | Type | Reset Value + +<%- csr.fields.each do |field| -%> +| xref:<%=csr.name%>-<%=field.name%>-def[`<%= field.name %>`] +| <%= field.location_pretty(arch_def) %> +| <%= field.type_pretty(arch_def.symtab) %> +| <%= field.reset_value_pretty(arch_def) %> + +<%- end -%> +|=== + + +== Fields + +<%- if csr.fields.empty? -%> +This CSR has no fields. However, it must still exist (not cause an `Illegal Instruction` trap) and always return zero on a read. +<%- else -%> + +<%- csr.fields.each do |field| -%> +[[<%=csr.name%>-<%=field.name%>-def]] +===== `<%= field.name %>` + +[example] +**** +Location:: +<%= field.location_pretty(arch_def) %> + +Description:: +<%= field.description %> + +Type:: +<%= field.type_pretty(arch_def.symtab) %> + +Reset value:: +<%= field.reset_value_pretty(arch_def) %> + +**** + +<%- end -%> +<%- end -%> + +<%- if csr.fields.map(&:has_custom_sw_write?).any? -%> +== Software write + +This CSR may store a value that is different from what software attempts to write. + +When a software write occurs (_e.g._, through `csrrw`), the following determines the +written value: + +[idl] +---- +<%- csr.fields.each do |field| -%> +<%- if field.has_custom_sw_write? -%> +<%= field.name %> = <%= field["sw_write(csr_value)"] %> +<%- else -%> +<%= field.name %> = csr_value.<%= field.name %> +<%- end -%> +<%- end -%> +---- +<%- end -%> + +<%- if csr.has_custom_sw_read? -%> +== Software read + +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.symtab).gen_adoc %> +---- +<%- end -%> diff --git a/backends/common_templates/adoc/inst.adoc.erb b/backends/common_templates/adoc/inst.adoc.erb new file mode 100644 index 000000000..8d9422e47 --- /dev/null +++ b/backends/common_templates/adoc/inst.adoc.erb @@ -0,0 +1,84 @@ +<%= anchor_for_inst(inst.name) %> += <%= inst.name %> + +Synopsis:: +<%= inst.long_name %> + +Mnemonic:: +---- +<%= inst.name %> <%= inst.assembly.gsub('x', 'r') %> +---- + +Encoding:: +<%- if inst.multi_encoding? -%> +[NOTE] +This instruction has different encodings in RV32 and RV64 + +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? ? 64 : inst.base) %> +.... +<%- end -%> + +Description:: +<%= inst.description %> + + +Decode Variables:: + +<%- if inst.multi_encoding? ? (inst.decode_variables(32).empty? && inst.decode_variables(64).empty?) : inst.decode_variables(inst.base.nil? ? 64 : inst.base).empty? -%> + +<%= inst.name %> has no decode variables. + +<%- else -%> +<%- if inst.multi_encoding? -%> +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,subs="specialchars,macros"] +---- +<%- inst.decode_variables(inst.base.nil? ? 64 : inst.base).each do |d| -%> +<%= d.sext? ? 'signed ' : '' %>Bits<<%= d.size %>> <%= d.name %> = <%= d.extract %>; +<%- end -%> +---- +<%- end # if multi_encoding? -%> +<%- end # if no decode variables-%> + +Operation:: +<%- unless inst.data["operation()"].nil? -%> +[source,idl,subs="specialchars,macros"] +---- +<%= inst.operation_ast(arch_def.symtab).gen_adoc %> +---- +<%- end -%> + +Included in:: + +<%= inst.defined_by.to_asciidoc %> diff --git a/backends/ext_pdf_doc/templates/ext_pdf.adoc.erb b/backends/ext_pdf_doc/templates/ext_pdf.adoc.erb index 46db5142b..44501d85b 100644 --- a/backends/ext_pdf_doc/templates/ext_pdf.adoc.erb +++ b/backends/ext_pdf_doc/templates/ext_pdf.adoc.erb @@ -186,10 +186,12 @@ Requires:: <<< == Extension description +:leveloffset: +2 <%= ext.description %> +:leveloffset: -2 <%- implications = versions.map { |v| v.implications }.flatten.uniq -%> -<%- unless implications.nil? -%> +<%- unless implications.empty? -%> === Sub-extensions <%- if implications.size > 1 -%> <%= ext.name %> defines the following #{implications.size} sub-extensions: @@ -284,134 +286,12 @@ The following <%= ext.csrs.size %> are added by this extension. <%- ext.csrs.each do |csr| -%> <<< -[#csrs-<%= csr.name.gsub('.', '_') %>,reftext=<%= csr.name %>] -=== <%= csr.name %> - -*<%= csr.long_name %>* - -<%= arch_def.render_erb(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 -%> -<%- if csr.dynamic_length?(arch_def) -%> -h| Length | <%= csr.length_pretty(arch_def) %> -<%- else -%> -h| Length | <%= csr.length_pretty(arch_def) %>-bit -<%- end -%> -h| Privilege Mode | <%= csr.priv_mode %> -|=== - -==== Format -<%- unless csr.dynamic_length?(arch_def) || csr.fields.any? { |f| f.dynamic_location?(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(arch_def, 64) %> -.... -<%- 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. - -.<%= csr.name %> Format when <%= csr.length_cond32 %> -[wavedrom, ,svg,subs='attributes',width="100%"] -.... -<%= JSON.dump csr.wavedrom_desc(arch_def, 32) %> -.... - -.<%= csr.name %> Format when <%= csr.length_cond64 %> -[wavedrom, ,svg,subs='attributes',width="100%"] -.... -<%= JSON.dump csr.wavedrom_desc(arch_def, 64) %> -.... -<%- end -%> - -==== Field Summary - -[%autowidth,float="center",align="center",cols="^,<,<,<",options="header",role="stretch"] -|=== -|Name | Location | Type | Reset Value - -<%- csr.fields.each do |field| -%> -| xref:<%=csr.name%>-<%=field.name%>-def[`<%= field.name %>`] -| <%= field.location_pretty(arch_def) %> -| <%= field.type_pretty(arch_def.symtab) %> -| <%= field.reset_value_pretty(arch_def) %> - -<%- end -%> -|=== - - -==== Fields - -<%- if csr.fields.empty? -%> -This CSR has no fields. However, it must still exist (not cause an `Illegal Instruction` trap) and always return zero on a read. -<%- else -%> - -<%- csr.fields.each do |field| -%> -[[<%=csr.name%>-<%=field.name%>-def]] -===== `<%= field.name %>` - -[example] -**** -Location:: -<%= field.location_pretty(arch_def) %> - -Description:: -<%= field.description %> - -Type:: -<%= field.type_pretty(arch_def.symtab) %> - -Reset value:: -<%= field.reset_value_pretty(arch_def) %> - -**** - -<%- end -%> -<%- end -%> - -<%- if csr.fields.map(&:has_custom_sw_write?).any? -%> -==== Software write - -This CSR may store a value that is different from what software attempts to write. - -When a software write occurs (_e.g._, through `csrrw`), the following determines the -written value: - -[idl] ----- -<%- csr.fields.each do |field| -%> -<%- if field.has_custom_sw_write? -%> -<%= field.name %> = <%= field["sw_write(csr_value)"] %> -<%- else -%> -<%= field.name %> = csr_value.<%= field.name %> -<%- end -%> -<%- end -%> ----- +:leveloffset: +2 +<%= partial "adoc/csr.adoc.erb", { csr: csr, arch_def: arch_def } %> +:leveloffset: -2 <%- end -%> -<%- if csr.has_custom_sw_read? -%> -==== Software read - -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.symtab).gen_adoc %> ----- -<%- end -%> - - -<%- end -%> - -<%- end -%> +<%- end # unless csrs.empty? -%> <%- unless ext.instructions.empty? -%> <<< @@ -419,91 +299,9 @@ This CSR may return a value that is different from what is stored in hardware. == Instructions (in alphabetical order) <%- ext.instructions.each do |i| -%> -[#insns-<%= i.name.gsub('.', '_') %>,reftext=<%= i.long_name %>] -=== <%= i.name %> - -Synopsis:: -<%= i.long_name %> - -Mnemonic:: ----- -<%= i.name %> <%= i.assembly.gsub('x', 'r') %> ----- - -Encoding:: -<%- if i.multi_encoding? -%> -[NOTE] -This instruction has different encodings in RV32 and RV64 - -RV32:: -[wavedrom, ,svg,subs='attributes',width="100%"] -.... -<%= JSON.dump i.wavedrom_desc(32) %> -.... - -RV64:: -[wavedrom, ,svg,subs='attributes',width="100%"] -.... -<%= JSON.dump i.wavedrom_desc(64) %> -.... -<%- else -%> -[wavedrom, ,svg,subs='attributes',width="100%"] -.... -<%= JSON.dump i.wavedrom_desc(i.base.nil? ? 64 : i.base) %> -.... -<%- end -%> - -Description:: -<%= i.description %> - - -Decode Variables:: - -<%- if i.multi_encoding? ? (i.decode_variables(32).empty? && i.decode_variables(64).empty?) : i.decode_variables(i.base.nil? ? 64 : i.base).empty? -%> - -<%= i.name %> has no decode variables. - -<%- else -%> -<%- if i.multi_encoding? -%> -RV32:: -+ -[source,idl] ----- -<%- i.decode_variables(32).each do |d| -%> -<%= d.sext? ? 'signed ' : '' %>Bits<<%= d.size %>> <%= d.name %> = <%= d.extract %>; -<%- end -%> ----- - -RV64:: -+ -[source,idl] ----- -<%- i.decode_variables(64).each do |d| -%> -<%= d.sext? ? 'signed ' : '' %>Bits<<%= d.size %>> <%= d.name %> = <%= d.extract %>; -<%- end -%> ----- -<%- else -%> -[source,idl,subs="specialchars,macros"] ----- -<%- i.decode_variables(i.base.nil? ? 64 : i.base).each do |d| -%> -<%= d.sext? ? 'signed ' : '' %>Bits<<%= d.size %>> <%= d.name %> = <%= d.extract %>; -<%- end -%> ----- -<%- end # if multi_encoding? -%> -<%- end # if no decode variables-%> - -Operation:: -<%- unless i.data["operation()"].nil? -%> -[source,idl,subs="specialchars,macros"] ----- -<%= i.operation_ast(arch_def.symtab).gen_adoc %> ----- -<%- end -%> - -Included in:: - -<%= i.defined_by.to_asciidoc %> - +:leveloffset: +2 +<%= partial "adoc/inst.adoc.erb", { inst: i, arch_def: arch_def } %> +:leveloffset: -2 <<< <%- end -%> diff --git a/lib/arch_obj_models/extension.rb b/lib/arch_obj_models/extension.rb index aea15fb7b..b40aff3c5 100644 --- a/lib/arch_obj_models/extension.rb +++ b/lib/arch_obj_models/extension.rb @@ -320,9 +320,10 @@ def contributors return @contributors unless @contributors.nil? @contributors = [] - @data["contributors"].each do |c| + @data["contributors"]&.each do |c| @contributors << Person.new(c) end + @contributors end # @return [Array] The list of parameters for this extension version diff --git a/lib/template_helpers.rb b/lib/template_helpers.rb index be11d0dee..f42ef9603 100644 --- a/lib/template_helpers.rb +++ b/lib/template_helpers.rb @@ -72,10 +72,12 @@ def anchor_for_csr_field(csr_name, field_name) "[[csr_field-#{csr_name.gsub(".", "_")}-#{field_name.gsub(".", "_")}-def]]" end - def render(template_path, locals = {}) - template_path = Pathname.new(template_path) - erb = ERB.new(template) - erb.filename = template_path.realpath + def partial(template_path, locals = {}) + template_path = Pathname.new($root / "backends" / "common_templates" / template_path) + raise ArgumentError, "Template '#{template_path} not found" unless template_path.exist? + + erb = ERB.new(template_path.read, trim_mode: "-") + erb.filename = template_path.realpath.to_s erb.result(OpenStruct.new(locals).instance_eval { binding }) end diff --git a/views/html/README.md b/views/html/README.md deleted file mode 100644 index 769c5ad29..000000000 --- a/views/html/README.md +++ /dev/null @@ -1 +0,0 @@ -This directory contains templates for constructing HTML documentation using Antora. \ No newline at end of file