diff --git a/arch/crd/MockCRD-1.yaml b/arch/crd/MockCRD-1.yaml index 16ad4c58e7..7df55f61eb 100644 --- a/arch/crd/MockCRD-1.yaml +++ b/arch/crd/MockCRD-1.yaml @@ -198,4 +198,18 @@ MockCRD-1: 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 + description: Can avoid adding extra CSRs with `h` suffix + extra_notes: + - presence: optional + text: Here's the first extra note for the optional extensions section. + - presence: mandatory + text: | + Here's the first extra note for the mandatory extensions section. + This note is multiple lines. + - presence: optional + text: Here's the second extra note for the optional extensions section. + recommendations: + - text: | + Implementations are strongly recommended to raise illegal-instruction + exceptions on attempts to execute unimplemented opcodes. + - text: Micky should give Pluto an extra treat \ No newline at end of file diff --git a/arch/profile/MockProfile-1.yaml b/arch/profile/MockProfile-1.yaml index 417542d3fa..9f818d7599 100644 --- a/arch/profile/MockProfile-1.yaml +++ b/arch/profile/MockProfile-1.yaml @@ -5,9 +5,9 @@ MockProfile-1: mode: S version: "1.0" contributors: - - name: Krste Asanovic - email: krste@sifive.com - company: SiFive + - name: Micky Mouse + email: micky@disney.com + company: Disneyk extensions: - name: S presence: mandatory @@ -25,4 +25,18 @@ MockProfile-1: version: "= 2.0" - name: Sv48 presence: optional - version: "= 1.11" \ No newline at end of file + version: "= 1.11" + extra_notes: + - presence: optional + text: Here's the first extra note for the optional extensions section. + - presence: mandatory + text: | + Here's the first extra note for the mandatory extensions section. + This note is multiple lines. + - presence: optional + text: Here's the second extra note for the optional extensions section. + recommendations: + - text: | + Implementations are strongly recommended to raise illegal-instruction + exceptions on attempts to execute unimplemented opcodes. + - text: Micky should give Pluto an extra treat \ No newline at end of file diff --git a/arch/profile/rva20u64.yaml b/arch/profile/rva20u64.yaml index 6e0e07c03d..afbbdef321 100644 --- a/arch/profile/rva20u64.yaml +++ b/arch/profile/rva20u64.yaml @@ -103,15 +103,15 @@ rva20u64: note: | The number of counters is platform-specific. extra_notes: - - location: optional - note: | + - presence: optional + text: | 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. - - location: optional - note: | + - presence: optional + text: | 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 @@ -122,13 +122,14 @@ rva20u64: 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. - - location: optional - note: | + - presence: optional + text: | 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. + - text: | + Implementations are strongly recommended to raise illegal-instruction + exceptions on attempts to execute unimplemented opcodes. \ No newline at end of file diff --git a/arch/profile/rva22u64.yaml b/arch/profile/rva22u64.yaml index feab845599..eebd04ba05 100644 --- a/arch/profile/rva22u64.yaml +++ b/arch/profile/rva22u64.yaml @@ -103,26 +103,26 @@ rva22u64: presence: optional version: "~> 1.0" extra_notes: - - location: optional - note: | + - presence: optional + text: | 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. - - location: optional - note: | + - presence: optional + text: | 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. - - location: optional - note: | + - presence: optional + text: | 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. - - location: optional - note: | + - presence: optional + text: | The Zfinx, Zdinx, Zhinx, Zhinxmin extensions are incompatible with the profile mandates to support the F and D extensions. \ No newline at end of file diff --git a/backends/crd_doc/templates/crd.adoc.erb b/backends/crd_doc/templates/crd.adoc.erb index c490ee96e0..c9616aaeb5 100644 --- a/backends/crd_doc/templates/crd.adoc.erb +++ b/backends/crd_doc/templates/crd.adoc.erb @@ -125,10 +125,26 @@ None | <%= ext_req.version_requirement %> | <%= ext_db.nil? ? "" : ext_db.long_name %> | <%= ext_req.note.nil? ? "" : ext_req.note %> -<% end -%> +<% end # each ext_req -%> |=== -<% end # if table -%> -<% end # do ext_reqs -%> +<% end # if empty ext_reqs -%> + +<% crd.extra_notes_for_presence(presence)&.each do |extra_note| -%> +NOTE: <%= extra_note.text %> + +<% end # each extra_note -%> + +<% end # each presence -%> + +<% unless crd.recommendations.empty? -%> +=== Recommendations + +Recommendations are not strictly mandated but are included to guide implementers making design choices. + +<% crd.recommendations.each do |recommendation| -%> +<%= recommendation.text %> +<% end # each recommendation -%> +<% end # unless recommendations empty -%> <<< == Implementation-dependencies diff --git a/backends/manual/templates/instruction.adoc.erb b/backends/manual/templates/instruction.adoc.erb index 5debd937aa..fd58fde37d 100644 --- a/backends/manual/templates/instruction.adoc.erb +++ b/backends/manual/templates/instruction.adoc.erb @@ -13,11 +13,11 @@ This instruction is included in the following profiles: <%- arch_def.profiles.each do |profile| -%> <%- - in_profile_mandatory = profile.mandatory_extension_requirements.any? do |ext_req| + in_profile_mandatory = profile.in_scope_ext_reqs("mandatory").any? do |ext_req| ext_versions = ext_req.satisfying_versions(arch_def) ext_versions.any? { |ext_ver| inst.defined_by?(ext_ver) } end - in_profile_optional = profile.optional_extension_requirements.any? do |ext_req| + in_profile_optional = profile.in_scope_ext_reqs("optional").any? do |ext_req| ext_versions = ext_req.satisfying_versions(arch_def) ext_versions.any? { |ext_ver| inst.defined_by?(ext_ver) } end diff --git a/backends/profile_doc/templates/profile.adoc.erb b/backends/profile_doc/templates/profile.adoc.erb index 4e11d099aa..f8a1f8f00a 100644 --- a/backends/profile_doc/templates/profile.adoc.erb +++ b/backends/profile_doc/templates/profile.adoc.erb @@ -62,31 +62,31 @@ endif::[] [preface] == Copyright and license information This document is released under the -<%- if profile_family.doc_license.url.nil? -%> +<% if profile_family.doc_license.url.nil? -%> <%= profile_family.doc_license.name %>. -<%- else -%> +<% else -%> <%= profile_family.doc_license.url %>[<%= profile_family.doc_license.name %>]. -<%- end -%> +<% end -%> -<%- if profile_family.ratification_date.nil? -%> +<% if profile_family.ratification_date.nil? -%> Copyright <%= Date.today.year %> -<%- else -%> +<% else -%> Copyright <%= profile_family.ratification_date.year %> -<%- end -%> +<% end -%> by <%= profile_family.company.name %>. [preface] == Acknowledgements -<%- profile_family.profiles.each do |profile| -%> +<% profile_family.profiles.each do |profile| -%> Contributors to the <%= profile.marketing_name %> Profile (in alphabetical order) include: + -<%- profile.contributors.sort.each do |c| -%> +<% profile.contributors.sort.each do |c| -%> * <%= c.name %> <<%= c.email %>> (<%= c.company %>) -<%- end -%> +<% end -%> -<%- end -%> +<% end -%> We express our gratitude to everyone that contributed to, reviewed or improved this specification through their comments and questions. @@ -329,15 +329,15 @@ non-profile extensions on an earlier profile. The following profiles are defined in this family: -<%- profile_family.profiles.each do |profile| -%> +<% profile_family.profiles.each do |profile| -%> -- Name:: <%= profile.marketing_name %> State:: <%= profile.state %> -<%- unless profile.ratification_date.nil? -%> +<% unless profile.ratification_date.nil? -%> Ratification date:: <%= profile.ratification_date %> -<%- end -%> +<% end -%> -- -<%- end -%> +<% end -%> === Extensions in the <%= profile_family.name %> Family @@ -348,77 +348,80 @@ 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| -%> +<% profile_family.referenced_extensions.sort_by(&:name).each do |ext| -%> | <%= ext.name %> | <%= profile_family.profiles.map { |profile| profile.extension_presence(ext.name) }.join(" | ") -%> -<%- end -%> +<% end -%> |=== -<%- profile_family.profiles.each do |profile| -%> +<% profile_family.profiles.each do |profile| -%> <<< == <%= profile.marketing_name %> Profile <%= profile.description %> -=== Extensions +<% ["mandatory","optional"].each do |presence| -%> -The <%= profile.marketing_name %> Profile has -<%= profile.mandatory_extension_requirements.size %> mandatory extensions -and <%= profile.optional_extension_requirements.size %> optional extensions. +=== <%= presence.capitalize %> Extensions -==== Mandatory Extensions +<% ext_reqs = profile.in_scope_ext_reqs(presence) -%> -<%- profile.mandatory_extension_requirements.each do |ext_req| -%> -<%- ext = profile.arch_def.extension(ext_req.name) -%> +The <%= profile.marketing_name %> Profile has <%= ext_reqs.size %> <%= presence %> extensions. + +<% unless ext_reqs.empty? -%> +<% ext_reqs.each do |ext_req| -%> +<% ext = profile.arch_def.extension(ext_req.name) -%> * *<%= ext_req.name %>* <%= ext.nil? ? "" : ext.long_name %> + Version <%= ext_req.version_requirement %> -<%- unless profile.extension_note(ext_req.name).nil? -%> +<% unless profile.extension_note(ext_req.name).nil? -%> + [NOTE] -- <%= profile.extension_note(ext_req.name) %> -- -<%- end -%> -<%- end -%> +<% end # unless note -%> +<% end # each ext_req -%> +<% end # no ext_reqs -%> -==== Optional Extensions +<% profile.extra_notes_for_presence(presence)&.each do |extra_note| -%> +NOTE: <%= extra_note.text %> -<%- profile.optional_extension_requirements.each do |ext_req| -%> -<%- ext = profile.arch_def.extension(ext_req.name) -%> -* *<%= ext_req.name %>* <%= ext.nil? ? "" : ext.long_name %> -+ -Version<%= ext_req.version_requirement %> -<%- unless profile.extension_note(ext_req.name).nil? -%> -+ -[NOTE] --- -<%= profile.extension_note(ext_req.name) %> --- -<%- end -%> -<%- end -%> +<% end # each extra_note -%> + +<% end # presence -%> + +<% puts("CCC profile #{profile.name}") -%> +<% unless profile.recommendations.empty? -%> +=== Recommendations + +Recommendations are not strictly mandated but are included to guide implementers making design choices. -<%- end -%> +<% profile.recommendations.each do |recommendation| -%> +<%= recommendation.text %> +<% end # each recommendation %> +<% end # unless recommendations empty %> +<% end # each profile -%> == Profile Parameters <%= profile_family.marketing_name %> has <%= profile_family.referenced_extensions.reduce(0) { |sum, ext| sum + ext.params.size } %> associated paramters. -<%- profile_family.referenced_extensions.each do |ext| -%> -<%- ext.params.sort_by { |p| p.name }.each do |param| -%> +<% profile_family.referenced_extensions.each do |ext| -%> +<% ext.params.sort_by { |p| p.name }.each do |param| -%> <%= param.name %>:: + -- <%= param.desc %> -- -<%- end -%> -<%- end -%> +<% end -%> +<% end -%> <<< [appendix] == Extension Specifications -<%- profile_family.referenced_extensions.each do |ext| -%> +<% profile_family.referenced_extensions.each do |ext| -%> <<< === <%= ext.name %> Extension <%= ext.long_name %> @@ -427,10 +430,10 @@ Version<%= ext_req.version_requirement %> |=== | Profile | v<%= ext.versions.map { |v| v["version"] }.join(" | v") %> -<%- profile_family.profiles.each do |profile| -%> +<% profile_family.profiles.each do |profile| -%> | <%= profile.marketing_name %> | <%= ext.versions.map do |v| - mandatory = profile.mandatory_extension_requirements.any? { |req| req.satisfied_by?(ext.name, v["version"]) } - optional = profile.optional_extension_requirements.any? { |req| req.satisfied_by?(ext.name, v["version"]) } + mandatory = profile.in_scope_ext_reqs("mandatory").any? { |req| req.satisfied_by?(ext.name, v["version"]) } + optional = profile.in_scope_ext_reqs("optional").any? { |req| req.satisfied_by?(ext.name, v["version"]) } if mandatory "mandatory" elsif optional @@ -439,34 +442,34 @@ Version<%= ext_req.version_requirement %> "-" end end.join(" | ") -%> -<%- end -%> +<% end -%> |=== -<%- ext.versions.each do |v| -%> +<% ext.versions.each do |v| -%> <%= v["version"] %>:: Ratification date::: <%= v["ratification_date"] %> - <%- if v.key?("changes") -%> + <% if v.key?("changes") -%> Changes::: - <%- v["changes"].each do |c| -%> + <% v["changes"].each do |c| -%> * <%= c %> - <%- end -%> + <% end -%> - <%- end -%> - <%- if v.key?("url") -%> + <% end -%> + <% if v.key?("url") -%> Ratification document::: <%= v["url"] %> - <%- end -%> - <%- if v.key?("implies") -%> + <% end -%> + <% if v.key?("implies") -%> Implies::: - <%- implications = v["implies"][0].is_a?(Array) ? v["implies"] : [v["implies"]] -%> - <%- implications.each do |i| -%> + <% implications = v["implies"][0].is_a?(Array) ? v["implies"] : [v["implies"]] -%> + <% implications.each do |i| -%> * `<%= i[0] %>` version <%= i[1] %> - <%- end -%> - <%- end -%> -<%- end -%> + <% end -%> + <% end -%> +<% end -%> ==== Synopsis @@ -477,35 +480,35 @@ 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) } -%> -<%- unless insts.empty? -%> +<% insts = arch_def.instructions.select { |i| i.defined_by?(ext.name,ext.min_version) } -%> +<% unless insts.empty? -%> ==== Instructions The following instructions are added by this extension: [cols="1,3"] |=== -<%- insts.each do |inst| -%> +<% insts.each do |inst| -%> | <%= "`#{inst.name}`" %> | *<%= inst.long_name %>* -<%- end -%> +<% end -%> |=== -<%- end -%> +<% end -%> -<%- unless ext.params.empty? -%> +<% unless ext.params.empty? -%> ==== Parameters This extension has the following implementation options: -<%- ext.params.sort_by { |p| p.name }.each do |param| -%> +<% ext.params.sort_by { |p| p.name }.each do |param| -%> <%= param.name %>:: + -- <%= param.desc %> -- -<%- end -%> +<% end -%> -<%- end -%> -<%- end -%> +<% end -%> +<% end -%> <<< [appendix] @@ -516,7 +519,7 @@ This extension has the following implementation options: insts.sort_by!(&:name) -%> -<%- insts.each do |inst| -%> +<% insts.each do |inst| -%> <<< [[inst-<%=inst.name.gsub('.', '_')%>-def]] === <%= inst.name %> @@ -529,7 +532,7 @@ This instruction is defined by: ==== Encoding -<%- if inst.multi_encoding? -%> +<% if inst.multi_encoding? -%> [NOTE] This instruction has different encodings in RV32 and RV64. @@ -549,25 +552,25 @@ RV64:: <%= JSON.dump inst.wavedrom_desc(64) %> .... ==== -<%- else -%> +<% else -%> [wavedrom, ,svg,subs='attributes',width="100%"] .... <%= JSON.dump inst.wavedrom_desc(inst.base.nil? ? 32 : inst.base) %> .... -<%- end -%> +<% end -%> ==== Synopsis <%= inst.description %> ==== Access -<%- if profile_family.referenced_extensions.any? { |e| e.name == "H" } -%> +<% if profile_family.referenced_extensions.any? { |e| e.name == "H" } -%> [cols="^,^,^,^,^"] -<%- else -%> +<% else -%> [cols="^,^,^"] -<%- end -%> +<% end -%> |=== -| M | <%- if profile_family.referenced_extensions.any? { |e| e.name == "H" } -%>HS<%- else -%>S<%- end -%> | U <%- if profile_family.referenced_extensions.any? { |e| e.name == "H" } -%> | VS | VU <%- end -%> +| M | <% if profile_family.referenced_extensions.any? { |e| e.name == "H" } -%>HS<% else -%>S<% end -%> | U <% if profile_family.referenced_extensions.any? { |e| e.name == "H" } -%> | VS | VU <% end -%> | [.access-always]#Always# | [.access-<%=inst.access['s']%>]#<%= inst.access['s'].capitalize %># @@ -578,92 +581,92 @@ RV64:: <% end %> |=== -<%- if inst.access_detail? -%> +<% if inst.access_detail? -%> <%= inst.access_detail %> -<%- end -%> +<% end -%> ==== Decode Variables -<%- if inst.multi_encoding? -%> +<% if inst.multi_encoding? -%> [tabs] ==== RV32:: + [source.idl] ---- -<%- inst.decode_variables(32).each do |d| -%> +<% inst.decode_variables(32).each do |d| -%> <%= d.sext? ? 'signed ' : '' %>Bits<<%= d.size %>> <%= d.name %> = <%= d.extract %>; -<%- end -%> +<% end -%> ---- RV64:: + [source,idl] ---- -<%- inst.decode_variables(64).each do |d| -%> +<% inst.decode_variables(64).each do |d| -%> <%= d.sext? ? 'signed ' : '' %>Bits<<%= d.size %>> <%= d.name %> = <%= d.extract %>; -<%- end -%> +<% end -%> ---- ==== -<%- else -%> +<% else -%> [source,idl] ---- -<%- inst.decode_variables(inst.base.nil? ? 32 : inst.base).each do |d| -%> +<% inst.decode_variables(inst.base.nil? ? 32 : inst.base).each do |d| -%> <%= d.sext? ? 'signed ' : '' %>Bits<<%= d.size %>> <%= d.name %> = <%= d.extract %>; -<%- end -%> +<% end -%> ---- -<%- end -%> +<% end -%> ==== Execution -<%- xlens = inst.base.nil? ? [32, 64] : [inst.base] -%> +<% xlens = inst.base.nil? ? [32, 64] : [inst.base] -%> -<%- if inst.key?("operation()") -%> +<% if inst.key?("operation()") -%> [source,idl,subs="specialchars,macros"] ---- <%= inst.operation_ast(arch_def.symtab).gen_adoc %> ---- -<%- end -%> +<% end -%> ==== Exceptions -<%- exception_list = inst.reachable_exceptions_str(arch_def.symtab) -%> -<%- if exception_list.empty? -%> +<% exception_list = inst.reachable_exceptions_str(arch_def.symtab) -%> +<% if exception_list.empty? -%> This instruction does not generate synchronous exceptions. -<%- else -%> +<% else -%> This instruction may result in the following synchronous exceptions: - <%- exception_list.sort.each do |etype| -%> + <% exception_list.sort.each do |etype| -%> * <%= etype %> - <%- end -%> + <% end -%> -<%- end -%> +<% end -%> -<%- end -%> +<% end -%> <<< [appendix] == CSR Specifications -<%- +<% csrs = profile_family.referenced_extensions.map { |ext| ext.csrs }.flatten.uniq csrs.sort_by!(&:name) -%> -<%- csrs.each do |csr| -%> +<% csrs.each do |csr| -%> <<< [[csr-<%= csr.name %>-def]] === <%= csr.name %> *<%= csr.long_name %>* -<%- unless csr.base.nil? -%> +<% unless csr.base.nil? -%> [NOTE] -- `<%= csr.name %>` is only defined in RV<%= csr.base %>. -- -<%- end -%> +<% end -%> <%= csr.description %> @@ -671,28 +674,28 @@ This instruction may result in the following synchronous exceptions: [%autowidth] |=== h| CSR Address | <%= "0x#{csr.address.to_s(16)}" %> -<%- if csr.priv_mode == 'VS' -%> +<% if csr.priv_mode == 'VS' -%> h| Virtual CSR Address | <%= "0x#{csr.virtual_address.to_s(16)}" %> -<%- end -%> +<% end -%> h| Defining extension a| <%= csr.defined_by.to_asciidoc %> -<%- if csr.dynamic_length?(arch_def) -%> +<% if csr.dynamic_length?(arch_def) -%> h| Length | <%= csr.length_pretty(arch_def) %> -<%- else -%> +<% else -%> h| Length | <%= csr.length_pretty(arch_def) %> -<%- end -%> +<% end -%> h| Privilege Mode | <%= csr.priv_mode %> |=== ==== Format -<%- unless csr.dynamic_length?(arch_def) || csr.fields.any? { |f| f.dynamic_location?(arch_def) } -%> +<% 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, csr.base.nil? ? 32 : csr.base) %> .... -<%- else -%> +<% 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. @@ -710,6 +713,6 @@ This CSR format changes dynamically with XLEN. .... -<%- end -%> +<% end -%> -<%- end -%> \ No newline at end of file +<% end -%> \ No newline at end of file diff --git a/lib/arch_obj_models/portfolio.rb b/lib/arch_obj_models/portfolio.rb index 082f8fd51a..965d5f4c29 100644 --- a/lib/arch_obj_models/portfolio.rb +++ b/lib/arch_obj_models/portfolio.rb @@ -157,56 +157,6 @@ def in_scope_extensions @in_scope_extensions end - # @return [Array] List of mandatory extensions listed in the portfolio. - def mandatory_extension_requirements - return @mandatory_ext_reqs unless @mandatory_ext_reqs.nil? - - @mandatory_ext_reqs = in_scope_ext_reqs("mandatory") - end - - # @return [Array] List of mandatory extensions listed in the portfolio. - def mandatory_extensions - mandatory_extension_requirements.map do |e| - obj = arch_def.extension(e.name) - - # @todo: change this to raise once all the profile extensions - # are defined - warn "Extension #{e.name} is not defined" if obj.nil? - - obj - end.reject(&:nil?) - end - - # @return [Boolean] whether or not +ext_name+ is mandatory in the portfolio. - def mandatory?(ext_name) - mandatory_extension_requirements.any? { |ext| ext.name == ext_name } - end - - # @return [Array] List of optional extensions listed in the portfolio. - def optional_extension_requirements - return @optional_ext_reqs unless @optional_ext_reqs.nil? - - @optional_ext_reqs = in_scope_ext_reqs("optional") - end - - # @return [Array] List of optional extensions listed in the portfolio. - def optional_extensions - optional_extension_requirements.map do |e| - obj = arch_def.extension(e.name) - - # @todo: change this to raise once all the profile extensions - # are defined - warn "Extension #{e.name} is not defined" if obj.nil? - - obj - end.reject(&:nil?) - end - - # @return [Boolean] whether or not +ext_name+ is optional in the prfoile - def optional?(ext_name) - optional_extension_requirements.any? { |ext| ext.name == ext_name } - end - ################################### # InScopeExtensionParameter Class # ################################### @@ -457,4 +407,61 @@ def revision_history end @revision_history end + + ###################### + # ExtraNote Subclass # + ###################### + + class ExtraNote < ArchDefObject + def initialize(data) + super(data) + end + + def presence + @data["presence"] + end + + def text + @data["text"] + end + end + + def extra_notes + return @extra_notes unless @extra_notes.nil? + + @extra_notes = [] + @data["extra_notes"]&.each do |extra_note| + @extra_notes << ExtraNote.new(extra_note) + end + @extra_notes + end + + def extra_notes_for_presence(desired_presence) + extra_notes.select {|extra_note| extra_note.presence == desired_presence} + end + + ########################### + # Recommendation Subclass # + ########################### + + class Recommendation < ArchDefObject + def initialize(data) + puts "CCC: data = #{data}" + super(data) + end + + def text + @data["text"] + end + end + + def recommendations + return @recommendations unless @recommendations.nil? + + @recommendations = [] + @data["recommendations"]&.each do |recommendation| + @recommendations << Recommendation.new(recommendation) + end + @recommendations + end end \ No newline at end of file