From 82b404e59f1db3aa5933da21ea5f0daa21d8ac89 Mon Sep 17 00:00:00 2001 From: Derek Hower Date: Tue, 29 Oct 2024 06:55:12 -0700 Subject: [PATCH 1/3] Correct definedBy for a some Zalrsc instructions --- arch/inst/A/lr.w.yaml | 3 ++- arch/inst/A/sc.d.yaml | 3 ++- arch/inst/A/sc.w.yaml | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/inst/A/lr.w.yaml b/arch/inst/A/lr.w.yaml index 9df0a62c..46442c6b 100644 --- a/arch/inst/A/lr.w.yaml +++ b/arch/inst/A/lr.w.yaml @@ -45,7 +45,8 @@ lr.w: Software should not set the _rl_ bit on an LR instruction unless the _aq_ bit is also set. LR.rl and SC.aq instructions are not guaranteed to provide any stronger ordering than those with both bits clear, but may result in lower performance. - definedBy: A + definedBy: + anyOf: [A, Zalrsc] assembly: xd, xs1 encoding: match: 00010--00000-----010-----0101111 diff --git a/arch/inst/A/sc.d.yaml b/arch/inst/A/sc.d.yaml index 2a692b82..c50aaa02 100644 --- a/arch/inst/A/sc.d.yaml +++ b/arch/inst/A/sc.d.yaml @@ -96,7 +96,8 @@ sc.d: Software should not set the _rl_ bit on an LR instruction unless the _aq_ bit is also set. LR.rl and SC.aq instructions are not guaranteed to provide any stronger ordering than those with both bits clear, but may result in lower performance. - definedBy: A + definedBy: + anyOf: [A, Zalrsc] assembly: xd, xs2, xs1 encoding: match: 00011------------011-----0101111 diff --git a/arch/inst/A/sc.w.yaml b/arch/inst/A/sc.w.yaml index 94fd254d..efd798c9 100644 --- a/arch/inst/A/sc.w.yaml +++ b/arch/inst/A/sc.w.yaml @@ -102,7 +102,8 @@ sc.w: Software should not set the _rl_ bit on an LR instruction unless the _aq_ bit is also set. LR.rl and SC.aq instructions are not guaranteed to provide any stronger ordering than those with both bits clear, but may result in lower performance. - definedBy: A + definedBy: + anyOf: [A, Zalrsc] assembly: xd, xs2, xs1 encoding: match: 00011------------010-----0101111 From 101043eceb8b5e2d2f49bacf8a8bd6e83ca69811 Mon Sep 17 00:00:00 2001 From: Derek Hower Date: Tue, 29 Oct 2024 06:55:35 -0700 Subject: [PATCH 2/3] Fix incorrect build dep on ext_pdf --- backends/ext_pdf_doc/tasks.rake | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/backends/ext_pdf_doc/tasks.rake b/backends/ext_pdf_doc/tasks.rake index b0a4852b..c4112ff0 100644 --- a/backends/ext_pdf_doc/tasks.rake +++ b/backends/ext_pdf_doc/tasks.rake @@ -120,7 +120,7 @@ rule %r{#{$root}/gen/ext_pdf_doc/.*/adoc/.*_extension\.adoc} => proc { |tname| end raise "Can't find extension '#{ext_name}'" if arch_yaml_paths.empty? - stamp = config_name == "_" ? "#{$root}/.stamps/arch-gen.stamp" : "#{$root}/.stamps/arch-gen-#{config_name}.stamp" + stamp = config_name == "_" ? "#{$root}/.stamps/arch-gen-_64.stamp" : "#{$root}/.stamps/arch-gen-#{config_name}.stamp" [ stamp, @@ -145,7 +145,12 @@ 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 = ENV.key?("EXT_VERSION") ? ENV["EXT_VERSION"] : ext.versions.sort { |v| Gem::Version.new(v["version"]) }.last["version"] + version_num = + if ENV.key?("EXT_VERSION") + ENV["EXT_VERSION"] + else + ext.versions.max { |a, b| Gem::Version.new(a["version"]) <=> Gem::Version.new(b["version"]) }["version"] + end ext_version = ext.versions.find { |v| v["version"] == version_num } FileUtils.mkdir_p File.dirname(t.name) File.write t.name, AsciidocUtils.resolve_links(arch_def.find_replace_links(erb.result(binding))) From d462e6f0bcdebf14a30a6862191e33dab017a948 Mon Sep 17 00:00:00 2001 From: Derek Hower Date: Tue, 29 Oct 2024 06:56:38 -0700 Subject: [PATCH 3/3] More robust ext_pdf --- backends/arch_gen/lib/arch_gen.rb | 52 +++++++--- .../ext_pdf_doc/templates/ext_pdf.adoc.erb | 96 +++++++++++++------ lib/idl/ast.rb | 12 ++- schemas/arch_schema.json | 2 +- schemas/csr_schema.json | 2 +- schemas/inst_schema.json | 7 +- 6 files changed, 122 insertions(+), 49 deletions(-) diff --git a/backends/arch_gen/lib/arch_gen.rb b/backends/arch_gen/lib/arch_gen.rb index 29d9f78e..1c03e9b3 100644 --- a/backends/arch_gen/lib/arch_gen.rb +++ b/backends/arch_gen/lib/arch_gen.rb @@ -470,31 +470,51 @@ def interrupt_codes end private :env - def merge_helper(base_obj, updates, path_so_far) - obj = path_so_far.empty? ? updates : updates.dig(*path_so_far) - obj.each do |key, value| - if value.is_a?(Hash) - merge_helper(base_obj, updates, (path_so_far + [key])) + # merges patch into base_obj based on JSON Merge Patch (RFC 7386) + # + # @param base_obj [Hash] base object to merge into + # @param patch [Hash] patch to merge into base_obj + # @param path_so_far [Array] path into the current object. Shouldn't be set by user (used during recursion) + # @return [Hash] merged object + def merge_patch(base, patch, path_so_far = []) + patch_obj = path_so_far.empty? ? patch : patch.dig(*path_so_far) + patch_obj.each do |key, patch_value| + if patch_value.is_a?(Hash) + # continue to dig + merge_patch(base, patch, (path_so_far + [key])) else - (path_so_far + [key]).each_with_index do |k, idx| - base_obj[k] ||= {} - if idx != path_so_far.size - base_obj = base_obj[k] - else - base_obj[k] = value + base_ptr = base.dig(*path_so_far) + base_value = base_ptr&.dig(key) + case patch_value + when nil + # remove from base, if it exists + unless base_value.nil? + base_ptr[key] = nil + end + else + # add or overwrite value in base + if base_ptr.nil? + # need to create intermediate nodes, too + base_ptr = base + path_so_far.each do |k| + base_ptr[k] = {} unless base_ptr.key?(k) + base_ptr = base_ptr[k] + end + base_ptr = base.dig(*path_so_far) end + base_ptr[key] = patch_value end end end end - private :merge_helper + private :merge_patch # overwrites base_obj with any data in update # # @param base_obj [Hash] Base object # @param updates [Hash] Object with overlays # @return [Hash] Updated object - def merge(base_obj, updates) = merge_helper(base_obj, updates, []) + def merge(base_obj, updates) = merge_patch(base_obj, updates, []) private :merge # @param type [Symbol] Type of the object (@see Validator::SCHEMA_PATHS) @@ -728,6 +748,7 @@ def maybe_add_csr(csr_name, extra_env = {}) end belongs = csr_obj.exists_in_cfg?(arch_def_mock) + @implemented_csrs ||= [] @implemented_csrs << csr_name if belongs @@ -784,7 +805,10 @@ def maybe_add_ext(ext_name) merged_path = gen_merged_def(:ext, arch_path, arch_overlay_path) - ext_obj = YAML.load_file(merged_path)[ext_name] + yaml_contents = YAML.load_file(merged_path) + raise "In #{merged_path}, key does not match file name" unless yaml_contents.key?(ext_name) + + ext_obj = yaml_contents[ext_name] ext_obj["name"] = ext_name @implied_ext_map ||= {} diff --git a/backends/ext_pdf_doc/templates/ext_pdf.adoc.erb b/backends/ext_pdf_doc/templates/ext_pdf.adoc.erb index bcc0b938..bce3131e 100644 --- a/backends/ext_pdf_doc/templates/ext_pdf.adoc.erb +++ b/backends/ext_pdf_doc/templates/ext_pdf.adoc.erb @@ -23,9 +23,9 @@ FROZEN_STATE when "development" <<~DEV_STATE - This document is in the http://riscv.org/spec-state[Development state]. - - Change should be expected + This document is in the http://riscv.org/spec-state[Development state]. + \\ + + \\ + Change should be expected + \\ DEV_STATE else raise "TODO: #{ext_version["state"]} description" @@ -37,11 +37,13 @@ :preface-title: Licensing and Acknowledgements :colophon: :appendix-caption: Appendix +<%- if !ext.company.nil? && (ext.company["name"] =~ /RISCV/) -%> :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 -%> <%- unless ext_version["state"] == "ratified" -%> :page-background-image: image:draft.png[opacity=20%] <%- end -%> -:back-cover-image: image:riscv-horizontal-color.svg[opacity=25%] // Settings :experimental: :reproducible: @@ -121,7 +123,7 @@ 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"].split("-")[0] %> by <%= ext.company.nil? ? "unknown" : ext.company["name"] %>. +Copyright <%= ext_version["ratification_date"].nil? ? Date.today.year : ext_version["ratification_date"].split("-")[0] %> by <%= ext.company.nil? ? "unknown" : ext.company["name"] %>. [preface] == Acknowledgements @@ -131,7 +133,8 @@ Contributors to version <%= version["version"] %> of the specification (in alpha <%- unless version["contributors"].nil? -%> <%- version["contributors"].sort { |a, b| a["name"].split(" ").last <=> b["name"].split(" ").last }.each do |c| -%> - * <%= c["name"] %> <<%= c["email"] %>> (<%= c["company"] %>) + * <%= c["name"] %> <<%= c["email"] %>> (<%= c["company"] %>) + <%- end -%> <%- end -%> <%- end -%> @@ -154,21 +157,69 @@ Ratification Date:: <%= version["ratification_date"] %> <%- if version.key?("url") -%> Design document:: <%= version["url"] %> <%- end -%> -<%- if version.key?("change") -%> +<%- if version.key?("changes") -%> Changes:: <%= version["changes"] %> <%- end -%> +<%- unless version["implies"].nil? || version["implies"].empty? -%> +Implies:: +* <%= version["implies"].map { |name, version| "#{name} (#{version})" }.join("\n* ") %> +<%- end -%> -- <%- end -%> + <<< == Extension description <%= ext.description %> <%- unless ext.implies.nil? -%> -<%- ext.implies.each do |e| -%> +=== Sub-extensions +The following sub-extensions are defined: + +<%- ext.implies.each do |sub_ext| -%> +==== <%= sub_ext.name %> + +<%= arch_def.extension(sub_ext.name).description %> + +<%- end -%> +<%- end -%> + +<%- unless ext.instructions.empty? -%> +<<< +== Instruction summary + +The following <%= ext.instructions.size %> instructions are added by this extension: + +[%autowidth] +|=== +| RV32 | RV64 | Mnemonic | Instruction | <%= ext.versions.map { |v| "v#{v["version"]}" }.join(" | ") %> + +<%- 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 %>] +| <%= ext.versions.map { |v| i.defined_by?(ext.name, v["version"]) ? "✓" : "" }.join(" | ") %> +<%- end -%> +|=== + +<%- unless ext.implies.empty? -%> +=== Instructions by sub-extension + +|=== +| Mnemonic | `<%= ext.name %>` | <%= ext.implies.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(" | ") %> +<%- end -%> +|=== + <%- end -%> + <%- end -%> <%- unless ext.csrs.empty? -%> @@ -327,24 +378,6 @@ This CSR may return a value that is different from what is stored in hardware. <%- end -%> <%- unless ext.instructions.empty? -%> -<<< -== Instruction summary - -The following <%= ext.instructions.size %> instructions are added by this extension: - -[%autowidth] -|=== -| RV32 | RV64 | Mnemonic | Instruction | <%= ext.versions.map { |v| "v#{v["version"]}" }.join(" | ") %> - -<%- ext.instructions.each do |i| -%> -| <%= i.rv32? ? "✓" : "" %> -| <%= i.rv64? ? "✓" : "" %> -| `<%= i.name %> <%= i.assembly.gsub("x", "r") %>` -| xref:insns-<%= i.name.gsub('.', '_') %>[<%= i.long_name %>] -| <%= ext.versions.map { |v| i.defined_by?(ext.name, v["version"]) ? "✓" : "" }.join(" | ") %> -<%- end -%> -|=== - <<< [#insns,reftext="Instructions (in alphabetical order)"] == Instructions (in alphabetical order) @@ -387,8 +420,14 @@ RV64:: 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:: + @@ -414,7 +453,8 @@ RV64:: <%= d.sext? ? 'signed ' : '' %>Bits<<%= d.size %>> <%= d.name %> = <%= d.extract %>; <%- end -%> ---- -<%- end -%> +<%- end # if multi_encoding? -%> +<%- end # if no decode variables-%> Operation:: <%- unless i.data["operation()"].nil? -%> @@ -455,4 +495,4 @@ h| Arguments l| <%= f.arguments_list_str.join (', ') %> ---- <%- end -%> -<%- end -%> \ No newline at end of file +<%- end -%> diff --git a/lib/idl/ast.rb b/lib/idl/ast.rb index acd5609f..159e819f 100644 --- a/lib/idl/ast.rb +++ b/lib/idl/ast.rb @@ -3601,7 +3601,11 @@ def initialize(input, interval, condition, true_expression, false_expression) # @!macro type_check def type_check(symtab) condition.type_check(symtab) - type_error "ternary selector must be bool" unless condition.type(symtab).kind == :boolean + if condition.type(symtab).kind == :bits + type_error "ternary selector must be bool (maybe you meant '#{condition.text_value} != 0'?)" + else + type_error "ternary selector must be bool" unless condition.type(symtab).kind == :boolean + end value_result = value_try do cond = condition.value(symtab) @@ -5740,9 +5744,9 @@ def calc_type(symtab) fd = field_def(symtab) if fd.nil? if @idx.is_a?(IntLiteralAst) - internal_error "Could not find CSR[#{@idx.to_idl}]" + internal_error "Could not find CSR[#{@idx.to_idl}].#{@field_name}" else - internal_error "Could not find CSR[#{@idx}]" + internal_error "Could not find CSR[#{@idx}].#{@field_name}" end end if fd.defined_in_all_bases? @@ -6026,7 +6030,7 @@ def value(symtab) when "sw_read" value_error "CSR not knowable" unless csr_known?(symtab) cd = csr_def(symtab) - cd.fields.each { |f| value_error "#{csr_name}.#{f.name} not RO" unless f.type == "RO" } + cd.fields.each { |f| value_error "#{csr_name(symtab)}.#{f.name} not RO" unless f.type(symtab) == "RO" } value_error "TODO: CSRs with sw_read function" when "address" diff --git a/schemas/arch_schema.json b/schemas/arch_schema.json index 4633d0a1..6cdedf4a 100644 --- a/schemas/arch_schema.json +++ b/schemas/arch_schema.json @@ -90,7 +90,7 @@ "type": "array", "items": { "type": "string", - "pattern": "^[a-z][a-zA-Z0-9]+$", + "pattern": "^[a-z][a-zA-Z0-9_]+$", "description": "CSR name" } }, diff --git a/schemas/csr_schema.json b/schemas/csr_schema.json index c522f360..daf3aac4 100644 --- a/schemas/csr_schema.json +++ b/schemas/csr_schema.json @@ -278,7 +278,7 @@ "misa:\\n long_name: Machine ISA Control\\n address: 0x301\\n priv_mode: M\\n length: 64\\n description: Reports the XLEN and 'major' extensions supported by the ISA.\\n definedBy: I\\n fields:\\n MXL:\\n location: 63-62\\n description: XLEN in M-mode.\\n type: RO\\n value: 2\\n Extensions: location: 25-0\\n description: |\\n Indicates support for major (single letter) ISA extensions.\\n\\n Value corresponds to A, D, F, H, I, M, S, U\\n type: RO\\n value: 0x1411A9" ], "patternProperties": { - "^[a-z][a-z0-9A-Z]+$": { + "^[a-z][a-z0-9A-Z_]+$": { "description": "CSR name", "$ref": "#/$defs/csr_register" } diff --git a/schemas/inst_schema.json b/schemas/inst_schema.json index f12507bf..2fad5777 100644 --- a/schemas/inst_schema.json +++ b/schemas/inst_schema.json @@ -62,6 +62,11 @@ "properties": { "match": { "oneOf": [ + { + "type": "string", + "pattern": "^[01-]{43}11111$", + "description": "48-bit encoding" + }, { "type": "string", "pattern": "^[01-]{30}11$", @@ -217,4 +222,4 @@ }, "additionalProperties": false, "maxProperties": 1 -} \ No newline at end of file +}