Skip to content

Commit 95cfa7c

Browse files
authored
Merge pull request #205 from riscv-software-src/ext_pdf
More robust ext_pdf generator
2 parents 86ff955 + d462e6f commit 95cfa7c

File tree

10 files changed

+135
-54
lines changed

10 files changed

+135
-54
lines changed

arch/inst/A/lr.w.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ lr.w:
4545
Software should not set the _rl_ bit on an LR instruction unless the _aq_ bit is also set.
4646
LR.rl and SC.aq instructions are not guaranteed to provide any stronger ordering than those
4747
with both bits clear, but may result in lower performance.
48-
definedBy: A
48+
definedBy:
49+
anyOf: [A, Zalrsc]
4950
assembly: xd, xs1
5051
encoding:
5152
match: 00010--00000-----010-----0101111

arch/inst/A/sc.d.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,8 @@ sc.d:
9696
Software should not set the _rl_ bit on an LR instruction unless the _aq_ bit is also set.
9797
LR.rl and SC.aq instructions are not guaranteed to provide any stronger ordering than those
9898
with both bits clear, but may result in lower performance.
99-
definedBy: A
99+
definedBy:
100+
anyOf: [A, Zalrsc]
100101
assembly: xd, xs2, xs1
101102
encoding:
102103
match: 00011------------011-----0101111

arch/inst/A/sc.w.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@ sc.w:
102102
Software should not set the _rl_ bit on an LR instruction unless the _aq_ bit is also set.
103103
LR.rl and SC.aq instructions are not guaranteed to provide any stronger ordering than those
104104
with both bits clear, but may result in lower performance.
105-
definedBy: A
105+
definedBy:
106+
anyOf: [A, Zalrsc]
106107
assembly: xd, xs2, xs1
107108
encoding:
108109
match: 00011------------010-----0101111

backends/arch_gen/lib/arch_gen.rb

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -470,31 +470,51 @@ def interrupt_codes
470470
end
471471
private :env
472472

473-
def merge_helper(base_obj, updates, path_so_far)
474-
obj = path_so_far.empty? ? updates : updates.dig(*path_so_far)
475-
obj.each do |key, value|
476-
if value.is_a?(Hash)
477-
merge_helper(base_obj, updates, (path_so_far + [key]))
473+
# merges patch into base_obj based on JSON Merge Patch (RFC 7386)
474+
#
475+
# @param base_obj [Hash] base object to merge into
476+
# @param patch [Hash] patch to merge into base_obj
477+
# @param path_so_far [Array<String>] path into the current object. Shouldn't be set by user (used during recursion)
478+
# @return [Hash] merged object
479+
def merge_patch(base, patch, path_so_far = [])
480+
patch_obj = path_so_far.empty? ? patch : patch.dig(*path_so_far)
481+
patch_obj.each do |key, patch_value|
482+
if patch_value.is_a?(Hash)
483+
# continue to dig
484+
merge_patch(base, patch, (path_so_far + [key]))
478485
else
479-
(path_so_far + [key]).each_with_index do |k, idx|
480-
base_obj[k] ||= {}
481-
if idx != path_so_far.size
482-
base_obj = base_obj[k]
483-
else
484-
base_obj[k] = value
486+
base_ptr = base.dig(*path_so_far)
487+
base_value = base_ptr&.dig(key)
488+
case patch_value
489+
when nil
490+
# remove from base, if it exists
491+
unless base_value.nil?
492+
base_ptr[key] = nil
493+
end
494+
else
495+
# add or overwrite value in base
496+
if base_ptr.nil?
497+
# need to create intermediate nodes, too
498+
base_ptr = base
499+
path_so_far.each do |k|
500+
base_ptr[k] = {} unless base_ptr.key?(k)
501+
base_ptr = base_ptr[k]
502+
end
503+
base_ptr = base.dig(*path_so_far)
485504
end
505+
base_ptr[key] = patch_value
486506
end
487507
end
488508
end
489509
end
490-
private :merge_helper
510+
private :merge_patch
491511

492512
# overwrites base_obj with any data in update
493513
#
494514
# @param base_obj [Hash] Base object
495515
# @param updates [Hash] Object with overlays
496516
# @return [Hash] Updated object
497-
def merge(base_obj, updates) = merge_helper(base_obj, updates, [])
517+
def merge(base_obj, updates) = merge_patch(base_obj, updates, [])
498518
private :merge
499519

500520
# @param type [Symbol] Type of the object (@see Validator::SCHEMA_PATHS)
@@ -728,6 +748,7 @@ def maybe_add_csr(csr_name, extra_env = {})
728748
end
729749
belongs =
730750
csr_obj.exists_in_cfg?(arch_def_mock)
751+
731752

732753
@implemented_csrs ||= []
733754
@implemented_csrs << csr_name if belongs
@@ -784,7 +805,10 @@ def maybe_add_ext(ext_name)
784805

785806
merged_path = gen_merged_def(:ext, arch_path, arch_overlay_path)
786807

787-
ext_obj = YAML.load_file(merged_path)[ext_name]
808+
yaml_contents = YAML.load_file(merged_path)
809+
raise "In #{merged_path}, key does not match file name" unless yaml_contents.key?(ext_name)
810+
811+
ext_obj = yaml_contents[ext_name]
788812
ext_obj["name"] = ext_name
789813

790814
@implied_ext_map ||= {}

backends/ext_pdf_doc/tasks.rake

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ rule %r{#{$root}/gen/ext_pdf_doc/.*/adoc/.*_extension\.adoc} => proc { |tname|
120120
end
121121
raise "Can't find extension '#{ext_name}'" if arch_yaml_paths.empty?
122122

123-
stamp = config_name == "_" ? "#{$root}/.stamps/arch-gen.stamp" : "#{$root}/.stamps/arch-gen-#{config_name}.stamp"
123+
stamp = config_name == "_" ? "#{$root}/.stamps/arch-gen-_64.stamp" : "#{$root}/.stamps/arch-gen-#{config_name}.stamp"
124124

125125
[
126126
stamp,
@@ -145,7 +145,12 @@ rule %r{#{$root}/gen/ext_pdf_doc/.*/adoc/.*_extension\.adoc} => proc { |tname|
145145
erb.filename = template_path.to_s
146146

147147
ext = arch_def.extension(ext_name)
148-
version_num = ENV.key?("EXT_VERSION") ? ENV["EXT_VERSION"] : ext.versions.sort { |v| Gem::Version.new(v["version"]) }.last["version"]
148+
version_num =
149+
if ENV.key?("EXT_VERSION")
150+
ENV["EXT_VERSION"]
151+
else
152+
ext.versions.max { |a, b| Gem::Version.new(a["version"]) <=> Gem::Version.new(b["version"]) }["version"]
153+
end
149154
ext_version = ext.versions.find { |v| v["version"] == version_num }
150155
FileUtils.mkdir_p File.dirname(t.name)
151156
File.write t.name, AsciidocUtils.resolve_links(arch_def.find_replace_links(erb.result(binding)))

backends/ext_pdf_doc/templates/ext_pdf.adoc.erb

Lines changed: 68 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@
2323
FROZEN_STATE
2424
when "development"
2525
<<~DEV_STATE
26-
This document is in the http://riscv.org/spec-state[Development state].
27-
28-
Change should be expected
26+
This document is in the http://riscv.org/spec-state[Development state]. + \\
27+
+ \\
28+
Change should be expected + \\
2929
DEV_STATE
3030
else
3131
raise "TODO: #{ext_version["state"]} description"
@@ -37,11 +37,13 @@
3737
:preface-title: Licensing and Acknowledgements
3838
:colophon:
3939
:appendix-caption: Appendix
40+
<%- if !ext.company.nil? && (ext.company["name"] =~ /RISCV/) -%>
4041
:title-logo-image: image:risc-v_logo.png["RISC-V International Logo",pdfwidth=3.25in,align=center]
42+
:back-cover-image: image:riscv-horizontal-color.svg[opacity=25%]
43+
<%- end -%>
4144
<%- unless ext_version["state"] == "ratified" -%>
4245
:page-background-image: image:draft.png[opacity=20%]
4346
<%- end -%>
44-
:back-cover-image: image:riscv-horizontal-color.svg[opacity=25%]
4547
// Settings
4648
:experimental:
4749
:reproducible:
@@ -121,7 +123,7 @@ endif::[]
121123
== Copyright and license information
122124
This document is released under the <%= ext.doc_license.nil? ? "unknown" : ext.doc_license["url"] %>[<%= ext.doc_license.nil? ? "unknown" : ext.doc_license["name"] %>].
123125

124-
Copyright <%= ext_version["ratification_date"].split("-")[0] %> by <%= ext.company.nil? ? "unknown" : ext.company["name"] %>.
126+
Copyright <%= ext_version["ratification_date"].nil? ? Date.today.year : ext_version["ratification_date"].split("-")[0] %> by <%= ext.company.nil? ? "unknown" : ext.company["name"] %>.
125127

126128
[preface]
127129
== Acknowledgements
@@ -131,7 +133,8 @@ Contributors to version <%= version["version"] %> of the specification (in alpha
131133

132134
<%- unless version["contributors"].nil? -%>
133135
<%- version["contributors"].sort { |a, b| a["name"].split(" ").last <=> b["name"].split(" ").last }.each do |c| -%>
134-
* <%= c["name"] %> <<%= c["email"] %>> (<%= c["company"] %>)
136+
* <%= c["name"] %> <<%= c["email"] %>> (<%= c["company"] %>)
137+
135138
<%- end -%>
136139
<%- end -%>
137140
<%- end -%>
@@ -154,21 +157,69 @@ Ratification Date:: <%= version["ratification_date"] %>
154157
<%- if version.key?("url") -%>
155158
Design document:: <%= version["url"] %>
156159
<%- end -%>
157-
<%- if version.key?("change") -%>
160+
<%- if version.key?("changes") -%>
158161
Changes::
159162
<%= version["changes"] %>
160163
<%- end -%>
164+
<%- unless version["implies"].nil? || version["implies"].empty? -%>
165+
Implies::
166+
* <%= version["implies"].map { |name, version| "#{name} (#{version})" }.join("\n* ") %>
167+
<%- end -%>
161168
--
162169
<%- end -%>
163170

171+
164172
<<<
165173
== Extension description
166174

167175
<%= ext.description %>
168176

169177
<%- unless ext.implies.nil? -%>
170-
<%- ext.implies.each do |e| -%>
178+
=== Sub-extensions
179+
The following sub-extensions are defined:
180+
181+
<%- ext.implies.each do |sub_ext| -%>
182+
==== <%= sub_ext.name %>
183+
184+
<%= arch_def.extension(sub_ext.name).description %>
185+
186+
<%- end -%>
187+
<%- end -%>
188+
189+
<%- unless ext.instructions.empty? -%>
190+
<<<
191+
== Instruction summary
192+
193+
The following <%= ext.instructions.size %> instructions are added by this extension:
194+
195+
[%autowidth]
196+
|===
197+
| RV32 | RV64 | Mnemonic | Instruction | <%= ext.versions.map { |v| "v#{v["version"]}" }.join(" | ") %>
198+
199+
<%- ext.instructions.each do |i| -%>
200+
| <%= i.rv32? ? "&#x2713;" : "" %>
201+
| <%= i.rv64? ? "&#x2713;" : "" %>
202+
| `<%= i.name %> <%= i.assembly.gsub("x", "r").strip %>`
203+
| xref:insns-<%= i.name.gsub('.', '_') %>[<%= i.long_name %>]
204+
| <%= ext.versions.map { |v| i.defined_by?(ext.name, v["version"]) ? "&#x2713;" : "" }.join(" | ") %>
205+
<%- end -%>
206+
|===
207+
208+
<%- unless ext.implies.empty? -%>
209+
=== Instructions by sub-extension
210+
211+
|===
212+
| Mnemonic | `<%= ext.name %>` | <%= ext.implies.map { |e| "`#{e.name}`" }.join(" | ") %>
213+
214+
<%- ext.instructions.each do |i| -%>
215+
| `<%= i.name %>`
216+
| &#x2713;
217+
| <%= ext.implies.map { |e| i.defined_by?(e.name, arch_def.extension(e.name).max_version) ? "&#x2713;" : "" }.join(" | ") %>
218+
<%- end -%>
219+
|===
220+
171221
<%- end -%>
222+
172223
<%- end -%>
173224

174225
<%- unless ext.csrs.empty? -%>
@@ -327,24 +378,6 @@ This CSR may return a value that is different from what is stored in hardware.
327378
<%- end -%>
328379

329380
<%- unless ext.instructions.empty? -%>
330-
<<<
331-
== Instruction summary
332-
333-
The following <%= ext.instructions.size %> instructions are added by this extension:
334-
335-
[%autowidth]
336-
|===
337-
| RV32 | RV64 | Mnemonic | Instruction | <%= ext.versions.map { |v| "v#{v["version"]}" }.join(" | ") %>
338-
339-
<%- ext.instructions.each do |i| -%>
340-
| <%= i.rv32? ? "&#x2713;" : "" %>
341-
| <%= i.rv64? ? "&#x2713;" : "" %>
342-
| `<%= i.name %> <%= i.assembly.gsub("x", "r") %>`
343-
| xref:insns-<%= i.name.gsub('.', '_') %>[<%= i.long_name %>]
344-
| <%= ext.versions.map { |v| i.defined_by?(ext.name, v["version"]) ? "&#x2713;" : "" }.join(" | ") %>
345-
<%- end -%>
346-
|===
347-
348381
<<<
349382
[#insns,reftext="Instructions (in alphabetical order)"]
350383
== Instructions (in alphabetical order)
@@ -387,8 +420,14 @@ RV64::
387420
Description::
388421
<%= i.description %>
389422

423+
390424
Decode Variables::
391425

426+
<%- if i.multi_encoding? ? (i.decode_variables(32).empty? && i.decode_variables(64).empty?) : i.decode_variables(i.base.nil? ? 64 : i.base).empty? -%>
427+
428+
<%= i.name %> has no decode variables.
429+
430+
<%- else -%>
392431
<%- if i.multi_encoding? -%>
393432
RV32::
394433
+
@@ -414,7 +453,8 @@ RV64::
414453
<%= d.sext? ? 'signed ' : '' %>Bits<<%= d.size %>> <%= d.name %> = <%= d.extract %>;
415454
<%- end -%>
416455
----
417-
<%- end -%>
456+
<%- end # if multi_encoding? -%>
457+
<%- end # if no decode variables-%>
418458
419459
Operation::
420460
<%- unless i.data["operation()"].nil? -%>
@@ -455,4 +495,4 @@ h| Arguments l| <%= f.arguments_list_str.join (', ') %>
455495
----
456496
<%- end -%>
457497
458-
<%- end -%>
498+
<%- end -%>

lib/idl/ast.rb

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3601,7 +3601,11 @@ def initialize(input, interval, condition, true_expression, false_expression)
36013601
# @!macro type_check
36023602
def type_check(symtab)
36033603
condition.type_check(symtab)
3604-
type_error "ternary selector must be bool" unless condition.type(symtab).kind == :boolean
3604+
if condition.type(symtab).kind == :bits
3605+
type_error "ternary selector must be bool (maybe you meant '#{condition.text_value} != 0'?)"
3606+
else
3607+
type_error "ternary selector must be bool" unless condition.type(symtab).kind == :boolean
3608+
end
36053609
36063610
value_result = value_try do
36073611
cond = condition.value(symtab)
@@ -5740,9 +5744,9 @@ def calc_type(symtab)
57405744
fd = field_def(symtab)
57415745
if fd.nil?
57425746
if @idx.is_a?(IntLiteralAst)
5743-
internal_error "Could not find CSR[#{@idx.to_idl}]"
5747+
internal_error "Could not find CSR[#{@idx.to_idl}].#{@field_name}"
57445748
else
5745-
internal_error "Could not find CSR[#{@idx}]"
5749+
internal_error "Could not find CSR[#{@idx}].#{@field_name}"
57465750
end
57475751
end
57485752
if fd.defined_in_all_bases?
@@ -6026,7 +6030,7 @@ def value(symtab)
60266030
when "sw_read"
60276031
value_error "CSR not knowable" unless csr_known?(symtab)
60286032
cd = csr_def(symtab)
6029-
cd.fields.each { |f| value_error "#{csr_name}.#{f.name} not RO" unless f.type == "RO" }
6033+
cd.fields.each { |f| value_error "#{csr_name(symtab)}.#{f.name} not RO" unless f.type(symtab) == "RO" }
60306034
60316035
value_error "TODO: CSRs with sw_read function"
60326036
when "address"

schemas/arch_schema.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@
9090
"type": "array",
9191
"items": {
9292
"type": "string",
93-
"pattern": "^[a-z][a-zA-Z0-9]+$",
93+
"pattern": "^[a-z][a-zA-Z0-9_]+$",
9494
"description": "CSR name"
9595
}
9696
},

schemas/csr_schema.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@
278278
"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"
279279
],
280280
"patternProperties": {
281-
"^[a-z][a-z0-9A-Z]+$": {
281+
"^[a-z][a-z0-9A-Z_]+$": {
282282
"description": "CSR name",
283283
"$ref": "#/$defs/csr_register"
284284
}

schemas/inst_schema.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@
6262
"properties": {
6363
"match": {
6464
"oneOf": [
65+
{
66+
"type": "string",
67+
"pattern": "^[01-]{43}11111$",
68+
"description": "48-bit encoding"
69+
},
6570
{
6671
"type": "string",
6772
"pattern": "^[01-]{30}11$",
@@ -217,4 +222,4 @@
217222
},
218223
"additionalProperties": false,
219224
"maxProperties": 1
220-
}
225+
}

0 commit comments

Comments
 (0)