diff --git a/backends/crd_doc/templates/crd.adoc.erb b/backends/crd_doc/templates/crd.adoc.erb index a3906d2ab..a00554108 100644 --- a/backends/crd_doc/templates/crd.adoc.erb +++ b/backends/crd_doc/templates/crd.adoc.erb @@ -320,7 +320,7 @@ Requirement <%= req.name %> only apply when <%= req.when_pretty %>. <% end -%> // TODO: GitHub issue 92: Use version specified by each profile. -<% insts = arch_def.instructions.select { |i| i.defined_by?(ext_db.name,ext_db.min_version) } -%> +<% insts = arch_def.instructions.select { |i| i.defined_by?(ext_db.min_version) } -%> <% unless insts.empty? -%> ==== Instructions diff --git a/backends/ext_pdf_doc/tasks.rake b/backends/ext_pdf_doc/tasks.rake index a7546f5c4..b33f81242 100644 --- a/backends/ext_pdf_doc/tasks.rake +++ b/backends/ext_pdf_doc/tasks.rake @@ -145,13 +145,18 @@ rule %r{#{$root}/gen/ext_pdf_doc/.*/adoc/.*_extension\.adoc} => proc { |tname| erb.filename = template_path.to_s ext = arch_def.extension(ext_name) - version_num = - if ENV.key?("EXT_VERSION") - ENV["EXT_VERSION"] + version_strs = ENV["VERSION"].split(",") + versions = + if version_strs.include?("all") + ext.versions else - ext.versions.max { |a, b| a.version <=> b.version }.version + vs = ext.versions.select do |ext_ver| + version_strs.include?(ext_ver.version.to_s) + end + vs << ext.max_version if version_strs.include?("latest") + vs.uniq end - ext_version = ext.versions.find { |v| v.version == version_num } + max_version = versions.max { |a, b| a.version <=> b.version } FileUtils.mkdir_p File.dirname(t.name) File.write t.name, AsciidocUtils.resolve_links(arch_def.find_replace_links(erb.result(binding))) end @@ -161,25 +166,36 @@ namespace :gen do Generate PDF documentation for :extension If the extension is custom (from an arch_overlay), also give the config name - DESC - task :ext_pdf, [:extension] do |_t, args| - extension = args[:extension] - Rake::Task[$root / "gen" / "ext_pdf_doc" / "_" / "pdf" / "#{extension}_extension.pdf"].invoke - end + Options: - desc <<~DESC - Generate PDF documentation for :extension that is defined or overlayed in :cfg + * EXT - The extension name + * CFG - The config name, required only when an overlay is required + * VERSION - A list of versions to include. May also be "all" or "latest". + + Examples: + + ./do gen:ext_pdf EXT=Xqci CFG=qc_iu VERSION=latest + ./do gen:ext_pdf EXT=B VERSION=all + ./do gen:ext_pdf EXT=B VERSION=1.0.0 + ./do gen:ext_pdf EXT=B VERSION=1.0.0,1.1.0 - The latest version will be used, but can be overloaded by setting the EXT_VERSION environment variable. DESC - task :cfg_ext_pdf, [:extension, :cfg] do |_t, args| - raise ArgumentError, "Missing required argument :extension" if args[:extension].nil? - raise ArgumentError, "Missing required argument :cfg" if args[:cfg].nil? + task :ext_pdf, [:extension] do |_t, args| + raise ArgumentError, "Missing required argument EXT" if ENV["EXT"].nil? - extension = args[:extension] + extension = ENV["EXT"] + cfg = ENV["CFG"] + version = ENV["VERSION"] + + versions = version.split(",") + raise ArgumentError, "Nothing else should be specified with 'all'" if versions.include?("all") && versions.size > 1 - Rake::Task[$root / "gen" / "ext_pdf_doc" / args[:cfg] / "pdf" / "#{extension}_extension.pdf"].invoke(args) + if cfg.nil? + Rake::Task[$root / "gen" / "ext_pdf_doc" / "_" / "pdf" / "#{extension}_extension.pdf"].invoke + else + Rake::Task[$root / "gen" / "ext_pdf_doc" / cfg / "pdf" / "#{extension}_extension.pdf"].invoke(args) + end end desc <<~DESC diff --git a/backends/ext_pdf_doc/templates/ext_pdf.adoc.erb b/backends/ext_pdf_doc/templates/ext_pdf.adoc.erb index ee5eb803a..ff662b2f2 100644 --- a/backends/ext_pdf_doc/templates/ext_pdf.adoc.erb +++ b/backends/ext_pdf_doc/templates/ext_pdf.adoc.erb @@ -1,9 +1,9 @@ [[header]] :description: <%= ext.long_name %> (<%= ext.name %>) -:revdate: <%= ext_version.ratification_date.nil? ? Date.today : ext_version.ratification_date %> -:revnumber: <%= ext_version.version %> +:revdate: <%= max_version.ratification_date.nil? ? Date.today : max_version.ratification_date %> +:revnumber: <%= max_version.version %> :revmark: <%= - case ext_version.state + case max_version.state when "ratified" <<~STATE This document is in the http://riscv.org/spec-state[Ratified state] + \\ @@ -28,7 +28,7 @@ Change should be expected + \\ DEV_STATE else - raise "TODO: #{ext_version.state} description" + raise "TODO: #{max_version.state} description" end %> :company: <%= ext.company.nil? ? "unknown" : ext.company["name"] %> @@ -41,7 +41,7 @@ :title-logo-image: image:risc-v_logo.png["RISC-V International Logo",pdfwidth=3.25in,align=center] :back-cover-image: image:riscv-horizontal-color.svg[opacity=25%] <%- end -%> -<%- if ext_version.state == "development" -%> +<%- if max_version.state == "development" -%> :page-background-image: image:draft.png[opacity=20%] <%- end -%> // Settings @@ -85,7 +85,7 @@ endif::[] // Preamble <%= - case ext_version.state + case max_version.state when "ratified" <<~RATIFIED_STATE [WARNING] @@ -115,7 +115,7 @@ endif::[] ==== DEV_STATE else - raise "TODO: #{ext_version.state} description" + raise "TODO: #{max_version.state} description" end %> @@ -123,12 +123,12 @@ endif::[] == Copyright and license information This document is released under the <%= ext.doc_license.nil? ? "unknown" : ext.doc_license["url"] %>[<%= ext.doc_license.nil? ? "unknown" : ext.doc_license["name"] %>]. -Copyright <%= ext_version.ratification_date.nil? ? Date.today.year : ext_version.ratification_date.split("-")[0] %> by <%= ext.company.nil? ? "unknown" : ext.company["name"] %>. +Copyright <%= max_version.ratification_date.nil? ? Date.today.year : max_version.ratification_date.split("-")[0] %> by <%= ext.company.nil? ? "unknown" : ext.company["name"] %>. [preface] == Acknowledgements -<%- ext.versions.each do |version| -%> +<%- versions.each do |version| -%> Contributors to version <%= version.version %> of the specification (in alphabetical order) include: + <%- unless version.contributors.empty? -%> @@ -145,7 +145,13 @@ improved this specification through their comments and questions. [preface] == Versions -The following versions have been defined: +<%- if versions.size > 1 -%> +This specification documents versions <%= versions.map { |v| v.version }.join(', ') %> of <%= ext.name %>: +<%- else -%> +This specification documents version <%= max_version.version %> of <%= ext.name %>. +<%- end -%> + +=== Version History <%- ext.versions.each do |version| -%> -- @@ -182,22 +188,31 @@ Requires:: <%= ext.description %> -<%- unless ext.implies.nil? -%> +<%- implications = versions.map { |v| v.implications }.flatten.uniq -%> +<%- unless implications.nil? -%> === Sub-extensions -<%- if ext.implies.size > 1 -%> -<%= ext.name %> defines the following #{ext.implies.size} sub-extensions: +<%- if implications.size > 1 -%> +<%= ext.name %> defines the following #{implications.size} sub-extensions: <%- else -%> <%= ext.name %> defines a single sub-extension: <%- end -%> -<%- ext.implies.each do |sub_ext| -%> -==== <%= sub_ext.name %> +<%- implications.each do |sub_ext| -%> +==== <%= sub_ext.name %> (<%= sub_ext.version %>) + +<%- if versions.size > 1 -%> +<%= sub_ext.name %> (<%= sub_ext.version %>) is implied by +version <%= versions.select { |v| v.implications.include?(sub_ext)}.map(&:version).join(", ") %> +of <%= ext.name %>. +<%- end -%> <%= arch_def.extension(sub_ext.name).description %> <%- unless sub_ext.requirements.empty? -%> <%= sub_ext.name %> requires: + <%= sub_ext.requirements.to_asciidoc %> + <%- end -%> <%- end -%> @@ -211,27 +226,29 @@ The following <%= ext.instructions.size %> instructions are added by this extens [%autowidth] |=== -| RV32 | RV64 | Mnemonic | Instruction | <%= ext.versions.map { |v| "v#{v.version}" }.join(" | ") %> +| RV32 | RV64 | Mnemonic | Instruction <%- if versions.size > 1 -%>| <%= versions.map { |v| "v#{v.version}" }.join(" | ") %><%- end -%> <%- ext.instructions.each do |i| -%> | <%= i.rv32? ? "✓" : "" %> | <%= i.rv64? ? "✓" : "" %> | `<%= i.name %> <%= i.assembly.gsub("x", "r").strip %>` | xref:insns-<%= i.name.gsub('.', '_') %>[<%= i.long_name %>] +<%- if versions.size > 1 -%> | <%= ext.versions.map { |v| i.defined_by?(ext.name, v.version) ? "✓" : "" }.join(" | ") %> <%- end -%> +<%- end -%> |=== -<%- unless ext.implies.empty? -%> +<%- unless implications.empty? -%> === Instructions by sub-extension +[%autowidth] |=== -| Mnemonic | `<%= ext.name %>` | <%= ext.implies.map { |e| "`#{e.name}`" }.join(" | ") %> +| Mnemonic | <%= implications.map { |e| "`#{e.name}`" }.join(" | ") %> <%- ext.instructions.each do |i| -%> | `<%= i.name %>` -| ✓ -| <%= ext.implies.map { |e| i.defined_by?(e.name, arch_def.extension(e.name).max_version) ? "✓" : "" }.join(" | ") %> +| <%= implications.map { |e| i.defined_by?(e) ? "✓" : "" }.join(" | ") %> <%- end -%> |=== @@ -247,15 +264,17 @@ The following <%= ext.csrs.size %> are added by this extension. [%autowidth] |=== -| RV32 | RV64 | CSR | Name | <%= ext.versions.map { |v| "v#{v.version}" }.join(" | ") %> +| RV32 | RV64 | CSR | Name <%- if versions.size > 1 -%>| <%= versions.map { |v| "v#{v.version}" }.join(" | ") %><%- end -%> <%- ext.csrs.each do |csr| -%> | <%= csr.defined_in_base32? ? "✓" : "" %> | <%= csr.defined_in_base64? ? "✓" : "" %> | xref:csrs-<%= csr.name.gsub('.', '_') %>[<%= csr.name %>] | <%= csr.long_name %> +<%- if versions.size > 1 -%> | <%= ext.versions.map { |v| csr.defined_by?(ext.name, v.version) ? "✓" : "" }.join(" | ") %> <%- end -%> +<%- end -%> |=== diff --git a/backends/profile_doc/templates/profile_pdf.adoc.erb b/backends/profile_doc/templates/profile_pdf.adoc.erb index 2e7674a95..78f769663 100644 --- a/backends/profile_doc/templates/profile_pdf.adoc.erb +++ b/backends/profile_doc/templates/profile_pdf.adoc.erb @@ -467,7 +467,7 @@ end.join(" | ") -%> :leveloffset: -3 // 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) } -%> +<%- insts = arch_def.instructions.select { |i| i.defined_by?(ext.min_version) } -%> <%- unless insts.empty? -%> ==== Instructions diff --git a/lib/arch_obj_models/extension.rb b/lib/arch_obj_models/extension.rb index 1396767c0..c3dd5d98c 100644 --- a/lib/arch_obj_models/extension.rb +++ b/lib/arch_obj_models/extension.rb @@ -145,27 +145,27 @@ def versions end end - # @return [Array] Ratified versions hash from config + # @return [Array] Ratified versions hash from config def ratified_versions - @data["versions"].select { |v| v["state"] == "ratified" } + versions.select { |v| v.state == "ratified" } end - # @return [Gem::Version] Mimumum defined version of this extension + # @return [ExtensionVersion] Mimumum defined version of this extension def min_version - versions.map { |v| v.version }.min + versions.min { |a, b| a.version <=> b.version } end - # @return [Gem::Version] Maximum defined version of this extension + # @return [ExtensionVersion] Maximum defined version of this extension def max_version - versions.map { |v| v.version }.max + versions.max { |a, b| a.version <=> b.version } end - # @return [Gem::Version] Mimumum defined ratified version of this extension + # @return [ExtensionVersion] Mimumum defined ratified version of this extension # @return [nil] if there is no ratified version def min_ratified_version return nil if ratified_versions.empty? - ratified_versions.map { |v| v.version }.min + ratified_versions.min { |a, b| a.version <=> b.version } end # @return [Array] List of parameters added by this extension @@ -191,22 +191,9 @@ def initialize(ext_data, arch_def) # @param version_requirement [String] Version requirement # @return [Array] Array of extensions implied by any version of this extension meeting version_requirement def implies(version_requirement = ">= 0") - implications = [] - @data["versions"].each do |v| - next unless Gem::Requirement.new(version_requirement).satisfied_by?(Gem::Version.new(v["version"])) - - case v["implies"] - when nil - next - when Array - if v["implies"][0].is_a?(Array) - implications += v["implies"].map { |e| ExtensionVersion.new(e[0], e[1], @arch_def)} - else - implications << ExtensionVersion.new(v["implies"][0], v["implies"][1], @arch_def) - end - end - end - implications + return [] unless Gem::Requirement.new(version_requirement).satisfied_by?(max_version.version) + + max_version.implications end def conflicts @@ -215,18 +202,18 @@ def conflicts to_extension_requirement_list(@data["conflicts"]) end - # @return [Array] the list of instructions implemented by this extension (may be empty) + # @return [Array] the list of instructions implemented by *any version* of this extension (may be empty) def instructions return @instructions unless @instructions.nil? - @instructions = arch_def.instructions.select { |i| @data["versions"].any? { |version| i.defined_by?(name, version["version"]) }} + @instructions = arch_def.instructions.select { |i| versions.any? { |v| i.defined_by?(v) }} end - # @return [Array] the list of CSRs implemented by this extension (may be empty) + # @return [Array] the list of CSRs implemented by *any version* of this extension (may be empty) def csrs return @csrs unless @csrs.nil? - @csrs = arch_def.csrs.select { |csr| csr.defined_by?(ExtensionVersion.new(name, max_version, @arch_def)) } + @csrs = arch_def.csrs.select { |csr| versions.any? { |v| csr.defined_by?(v) } } end # @return [Array] the list of CSRs implemented by this extension (may be empty) @@ -364,6 +351,14 @@ def ==(other) end end + # @param other [ExtensionVersion] Comparison + # @return [Boolean] Whether or not +other+ is an ExtensionVersion with the same name and version + def eql?(other) + return false unless other.is_a?(ExtensionVersion) + + @name == other.name && @version == other.version + end + def requirements r = case @data["requires"] when nil @@ -392,11 +387,12 @@ def implications return @implications when Array if @data["implies"][0].is_a?(Array) - @implications += @data["implies"].map { |e| ExtensionVersion.new(e[0], e[1], @arch_def)} + @implications += @data["implies"].map { |e| ExtensionVersion.new(e[0], e[1], @arch_def) } else @implications << ExtensionVersion.new(@data["implies"][0], @data["implies"][1], @arch_def) end end + @implications.uniq! @implications end