diff --git a/Rakefile b/Rakefile index b1b3feb28..51a15e183 100644 --- a/Rakefile +++ b/Rakefile @@ -302,42 +302,56 @@ task :regress do end desc <<~DESC - Generate all certificates and profile PDFs. + Generate all portfolio-based PDFs (certificates and profiles). DESC -task :cert_profile_pdfs do +task :portfolio_pdfs do + puts "" puts "===================================" - puts "cert_profile_pdfs: Generating MC100" - puts " 1st target" + puts "Generating MC100" puts "===================================" + puts "" Rake::Task["#{$root}/gen/certificate_doc/pdf/MC100.pdf"].invoke + puts "" puts "==================================================" - puts "cert_profile_pdfs: Generating MockCertificateModel" - puts " 2nd target" + puts "Generating MockCertificateModel" puts "==================================================" + puts "" Rake::Task["#{$root}/gen/certificate_doc/pdf/MockCertificateModel.pdf"].invoke + puts "" puts "===================================" - puts "cert_profile_pdfs: Generating RVA20" - puts " 3rd target" + puts "Generating RVA20" puts "===================================" + puts "" Rake::Task["#{$root}/gen/profile_doc/pdf/RVA20.pdf"].invoke + puts "" puts "===================================" - puts "cert_profile_pdfs: Generating RVA22" - puts " 4th target" + puts "Generating RVA22" puts "===================================" + puts "" Rake::Task["#{$root}/gen/profile_doc/pdf/RVA22.pdf"].invoke + puts "" puts "===================================" - puts "cert_profile_pdfs: Generating RVI20" - puts " 5th target" + puts "Generating RVI20" puts "===================================" + puts "" Rake::Task["#{$root}/gen/profile_doc/pdf/RVI20.pdf"].invoke + puts "" puts "===================================" - puts "cert_profile_pdfs: Generating MockProfileRelease" - puts " 6th target" + puts "Generating MockProfileRelease" puts "===================================" + puts "" Rake::Task["#{$root}/gen/profile_doc/pdf/MockProfileRelease.pdf"].invoke -end \ No newline at end of file +end + +# Shortcut targets for building profiles and certificates. +task MC100: "#{$root}/gen/certificate_doc/pdf/MC100.pdf" +task MockCertificateModel: "#{$root}/gen/certificate_doc/pdf/MockCertificateModel.pdf" +task RVI20: "#{$root}/gen/profile_doc/pdf/RVI20.pdf" +task RVA20: "#{$root}/gen/profile_doc/pdf/RVA20.pdf" +task RVA22: "#{$root}/gen/profile_doc/pdf/RVA22.pdf" +task MockProfileRelease: "#{$root}/gen/profile_doc/pdf/MockProfileRelease.pdf" \ No newline at end of file diff --git a/arch/profile_release/MockProfileRelease.yaml b/arch/profile_release/MockProfileRelease.yaml index 45104cdec..ca4a0f10c 100644 --- a/arch/profile_release/MockProfileRelease.yaml +++ b/arch/profile_release/MockProfileRelease.yaml @@ -68,6 +68,9 @@ MockProfileRelease: optional: transitory version: "~> 1.11" note: Made this a transitory option + MockExt: + presence: mandatory + version: "~> 0.9.9" extra_notes: - presence: mandatory text: | diff --git a/backends/profile_doc/tasks.rake b/backends/profile_doc/tasks.rake index 167ba087e..489cfd9aa 100644 --- a/backends/profile_doc/tasks.rake +++ b/backends/profile_doc/tasks.rake @@ -4,7 +4,7 @@ rule %r{#{$root}/gen/profile_doc/adoc/.*\.adoc} => proc { |tname| profile_release_name = Pathname.new(tname).basename(".adoc") [ - "#{$root}/.stamps/arch-gen.stamp", + "#{$root}/.stamps/arch-gen-_64.stamp", __FILE__, "#{$root}/lib/arch_obj_models/profile.rb", "#{$root}/backends/profile_doc/templates/profile.adoc.erb" diff --git a/backends/profile_doc/templates/profile.adoc.erb b/backends/profile_doc/templates/profile.adoc.erb index 166ec08b7..cee0ec4b2 100644 --- a/backends/profile_doc/templates/profile.adoc.erb +++ b/backends/profile_doc/templates/profile.adoc.erb @@ -2,7 +2,7 @@ :description: <%= profile_release.marketing_name %> Profile :revdate: <%= profile_release.ratification_date.nil? ? Date.today : profile_release.ratification_date %> -// XXX - Figure out what we really want here - Change percent hash to percent equals. +// TODO - Figure out what we really want here - Change percent hash to percent equals. // :revnumber: <%# profile_release.map(&:version).sort.last %> :revmark: "TODO: revmark" @@ -311,6 +311,7 @@ optional profile extensions for a new profile might be prototyped as non-profile extensions on an earlier profile. // XXX - Need to create render() Ruby function. +// See https://github.com/riscv-software-src/riscv-unified-db/issues/59 // <%# render("#{$root}/backends/portfolio_doc/templates/family_intro.erb", portfolio_class: profile_class) %> == <%= profile_class.name %> Profile Class @@ -344,21 +345,6 @@ Ratification date:: <%= profile_release.ratification_date %> -- <% end # each profile_release -%> -=== Extension Presence - -The <%= profile_class.marketing_name %> Profile Class references -<%= profile_class.referenced_extensions.size %> extensions. - -.Status -|=== -| Extension | <%= profile_class.profiles.map(&:marketing_name).join(" | ") -%> - -<% profile_class.referenced_extensions.sort_by(&:name).each do |ext| -%> -| <%= ext.name %> | <%= profile_class.profiles.map { |profile| profile.extension_presence(ext.name) }.join(" | ") -%> -<% end -%> - -|=== - == <%= profile_release.name %> Profile Release <%= profile_release.introduction %> @@ -370,8 +356,8 @@ associated implementation-defined parameters across all its defined profiles. === <%= profile_release.name %> Description <%= profile_release.description %> - <% end # unless -%> + <% profile_release.profiles.each do |profile| -%> === <%= profile.marketing_name %> Profile @@ -411,6 +397,41 @@ associated implementation-defined parameters. <% end # each profile -%> +<<< +[appendix] +== Profile Comparisons + +=== Release Comparison + +The <%= profile_class.marketing_name %> Profile Class has <%= profile_class.profile_releases.size %> releases that +reference a total of <%= profile_class.referenced_extensions.size %> extensions. + +.Extension Presence +|=== +| Extension | <%= profile_class.profile_releases.map(&:marketing_name).join(" | ") %> + +<% profile_class.referenced_extensions.sort_by(&:name).each do |ext| -%> +| <%= ext.name %> | <%= profile_class.profile_releases.map { |profile_release| profile_release.extension_presence(ext.name) }.join(" | ") %> +<% end -%> +|=== + +=== Profile Comparison + +The <%= profile_release.marketing_name %> Profile Release has <%= profile_release.profiles.size %> profiles that +reference a total of <%= profile_release.referenced_extensions.size %> extensions. + +[NOTE] +Extensions present in a profile are also present in higher-privileged profiles in the same profile release. + +.Extension Presence +|=== +| Extension | <%= profile_release.profiles.map(&:marketing_name).join(" | ") %> + +<% profile_release.referenced_extensions.sort_by(&:name).each do |ext| -%> +| <%= ext.name %> | <%= profile_release.profiles.map { |profile| profile.extension_presence(ext.name) }.join(" | ") %> +<% end -%> +|=== + <<< [appendix] == Extension Details @@ -420,12 +441,12 @@ associated implementation-defined parameters. === <%= ext.name %> Extension <%= ext.long_name %> -.Status +.Presence |=== | Profile | v<%= ext.versions.map { |v| v.version }.join(" | v") %> <% profile_release.profiles.each do |profile| -%> -| <%= profile.marketing_name %> | <%= profile.version_strongest_presence(ext.name, ext.versions).join(" | ") -%> +| <%= profile.marketing_name %> | <%= profile.version_greatest_presence(ext.name, ext.versions).join(" | ") -%> <% end -%> |=== diff --git a/lib/arch_obj_models/extension.rb b/lib/arch_obj_models/extension.rb index b40aff3c5..97671b44a 100644 --- a/lib/arch_obj_models/extension.rb +++ b/lib/arch_obj_models/extension.rb @@ -476,8 +476,8 @@ def initialize(data) end end - def mandatory? = (@presence == mandatory) - def optional? = (@presence == optional) + def mandatory? = (@presence == "mandatory") + def optional? = (@presence == "optional") # Class methods def self.mandatory = "mandatory" @@ -522,6 +522,17 @@ def to_s @optional_type.nil? ? "#{presence}" : "#{presence} (#{optional_type})" end + def to_s_concise + "#{presence}" + end + + # + # Overloaded comparison operators following these rules: + # - "mandatory" is greater than "optional" + # - optional_types all have same rank + # - equals compares presence and then optional_type + # + # @overload ==(other) # @param other [String] A presence string # @return [Boolean] whether or not this ExtensionPresence has the same presence (ignores optional_type) @@ -539,6 +550,26 @@ def ==(other) end end + # @overload >(other) + # @param other [ExtensionPresence] An extension presence object + # @return [Boolean] Whether or not this ExtensionPresence is greater-than the other + def >(other) = (self.mandatory? && other.optional?) + + # @overload >=(other) + # @param other [ExtensionPresence] An extension presence object + # @return [Boolean] Whether or not this ExtensionPresence is greater-than or equal to the other + def >=(other) = (self > other) || (self == other) + + # @overload <(other) + # @param other [ExtensionPresence] An extension presence object + # @return [Boolean] Whether or not this ExtensionPresence is less-than the other + def <(other) = (self.optional? && other.mandatory?) + + # @overload <=(other) + # @param other [ExtensionPresence] An extension presence object + # @return [Boolean] Whether or not this ExtensionPresence is less-than or equal to the other + def <=(other) = (self < other) || (self == other) + # Sorts by presence, then by optional_type def <=>(other) raise ArgumentError, "ExtensionPresence is only comparable to other ExtensionPresence classes" unless other.is_a?(ExtensionPresence) diff --git a/lib/arch_obj_models/portfolio.rb b/lib/arch_obj_models/portfolio.rb index e378cdc01..7a2ad3a8b 100644 --- a/lib/arch_obj_models/portfolio.rb +++ b/lib/arch_obj_models/portfolio.rb @@ -61,35 +61,48 @@ def description = @data["description"] # @return [Gem::Version] Semantic version of the PortfolioInstance def version = Gem::Version.new(@data["version"]) + # @return [ExtensionPresence] Given an extension +ext_name+, return the presence. + # If the extension name isn't found in the portfolio, return nil. + def extension_presence_obj(ext_name) + # Get extension information from YAML for passed in extension name. + ext_data = @data["extensions"][ext_name] + + ext_data.nil? ? nil : ExtensionPresence.new(ext_data["presence"]) + end + # @return [String] Given an extension +ext_name+, return the presence as a string. # If the extension name isn't found in the portfolio, return "-". def extension_presence(ext_name) - # Get extension information from YAML for passed in extension name. - ext_data = @data["extensions"][ext_name] + ext_presence_obj = extension_presence_obj(ext_name) - ext_data.nil? ? "-" : ExtensionPresence.new(ext_data["presence"]).to_s + ext_presence_obj.nil? ? "-" : ext_presence_obj.to_s end - # Returns the strongest presence string for each of the specified versions. + # Returns the greatest presence string for each of the specified versions. # @param ext_name [String] # @param ext_versions [Array] # @return [Array] - def version_strongest_presence(ext_name, ext_versions) + def version_greatest_presence(ext_name, ext_versions) presences = [] - # See if any extension requirement in this profile lists this version as either mandatory or optional. ext_versions.map do |v| - mandatory = mandatory_ext_reqs.any? { |ext_req| ext_req.satisfied_by?(ext_name, v.version) } - optional = optional_ext_reqs.any? { |ext_req| ext_req.satisfied_by?(ext_name, v.version) } - - # Just show strongest presence (mandatory stronger than optional). - if mandatory - presences << ExtensionPresence.mandatory - elsif optional - presences << ExtensionPresence.optional - else - presences << "-" + greatest_presence = nil + + in_scope_ext_reqs.each do |ext_req| + if ext_req.satisfied_by?(ext_name, v.version) + presence = extension_presence_obj(ext_name) + + unless presence.nil? + if greatest_presence.nil? + greatest_presence = presence + elsif presence > greatest_presence + greatest_presence = presence + end + end + end end + + presences << (greatest_presence.nil? ? "-" : greatest_presence.to_s_concise) end presences @@ -194,7 +207,7 @@ def to_arch_def end arch_def_data["params"] = all_in_scope_ext_params.select(&:single_value?).map { |p| [p.name, p.value] }.to_h - # XXX Add list of prohibited_extensions + # TODO: Add list of prohibited_extensions file = Tempfile.new("archdef") file.write(YAML.safe_dump(arch_def_data, permitted_classes: [Date])) diff --git a/lib/arch_obj_models/profile.rb b/lib/arch_obj_models/profile.rb index 44d63f3b4..497a62317 100644 --- a/lib/arch_obj_models/profile.rb +++ b/lib/arch_obj_models/profile.rb @@ -126,6 +126,27 @@ def referenced_extensions @referenced_extensions end + + # @return [String] Given an extension +ext_name+, return the presence as a string. + # Returns the greatest presence string across all profiles in the release. + # If the extension name isn't found in the release, return "-". + def extension_presence(ext_name) + greatest_presence = nil + + profiles.each do |profile| + presence = profile.extension_presence_obj(ext_name) + + unless presence.nil? + if greatest_presence.nil? + greatest_presence = presence + elsif presence > greatest_presence + greatest_presence = presence + end + end + end + + greatest_presence.nil? ? "-" : greatest_presence.to_s_concise + end end # Representation of a specific profile in a profile release.