Skip to content

Commit c09d447

Browse files
authored
Enhance wavedrom display to a number-per-cell format. (#613)
* fix: make string to hexa conversion methods be available for all templates, instead of just instruction_appendix Signed-off-by: Afonso Oliveira <Afonso.Oliveira@synopsys.com> * feat: make all outputs use the new number-per-cell format in wavedroms. Signed-off-by: Afonso Oliveira <Afonso.Oliveira@synopsys.com> --------- Signed-off-by: Afonso Oliveira <Afonso.Oliveira@synopsys.com>
1 parent 2974f27 commit c09d447

File tree

5 files changed

+98
-92
lines changed

5 files changed

+98
-92
lines changed

backends/common_templates/adoc/inst.adoc.erb

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,23 +30,23 @@ This instruction has different encodings in RV32 and RV64
3030
RV32::
3131
[wavedrom, ,svg,subs='attributes',width="100%"]
3232
....
33-
<%= JSON.dump inst.wavedrom_desc(32) %>
33+
<%= inst.processed_wavedrom_desc(32) %>
3434
....
3535

3636
RV64::
3737
[wavedrom, ,svg,subs='attributes',width="100%"]
3838
....
39-
<%= JSON.dump inst.wavedrom_desc(64) %>
39+
<%= inst.processed_wavedrom_desc(64) %>
4040
....
4141
<%- else -%>
4242
[wavedrom, ,svg,subs='attributes',width="100%"]
4343
....
44-
<%= JSON.dump inst.wavedrom_desc(inst.base.nil? ? 64 : inst.base) %>
44+
<%= inst.processed_wavedrom_desc(inst.base.nil? ? 64 : inst.base) %>
4545
....
4646
<%- end -%>
4747

4848
Description::
49-
<%= inst.description %>
49+
<%= inst.fix_entities(inst.description) %>
5050

5151

5252
Decode Variables::
@@ -89,7 +89,7 @@ RV64::
8989
Operation::
9090
[source,idl,subs="specialchars,macros"]
9191
----
92-
<%= inst.operation_ast.gen_adoc %>
92+
<%= inst.fix_entities(inst.operation_ast.gen_adoc) %>
9393
----
9494
<% end %>
9595
<% end %>
@@ -99,7 +99,7 @@ Operation::
9999
Sail::
100100
[source,sail]
101101
----
102-
<%= inst.data["sail()"] %>
102+
<%= inst.fix_entities(inst.data["sail()"]) %>
103103
----
104104
<% end %>
105105
<% end %>
@@ -111,9 +111,9 @@ Included in::
111111
| Extension | Version
112112
113113
<%- inst.defined_by_condition.flat_versions.each do |r| -%>
114-
| *<%= r.name %>* | <%= r.requirement_specs_to_s %>
114+
| *<%= r.name %>* | <%= inst.fix_entities(r.requirement_specs_to_s) %>
115115
<%- end -%>
116116
|===
117117
<%- else -%>
118-
<%= inst.defined_by_condition.to_asciidoc %>
118+
<%= inst.fix_entities(inst.defined_by_condition.to_asciidoc) %>
119119
<%- end -%>
Lines changed: 7 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,3 @@
1-
<%
2-
# Helper to substitute problematic entity strings with proper Unicode characters.
3-
def fix_entities(text)
4-
text.to_s.gsub("&ne;", "≠")
5-
.gsub("&pm;", "±")
6-
.gsub("-&infin;", "−∞")
7-
.gsub("+&infin;", "+∞")
8-
end
9-
10-
# Custom JSON converter for wavedrom that handles hexadecimal literals
11-
def json_dump_with_hex_literals(data)
12-
# First convert to standard JSON
13-
json_string = JSON.dump(data)
14-
15-
# Replace string hex values with actual hex literals
16-
json_string.gsub(/"0x([0-9a-fA-F]+)"/) do |match|
17-
# Remove the quotes, leaving just the hex literal
18-
"0x#{$1}"
19-
end.gsub(/"name":/, '"name": ') # Add space after colon for name field
20-
end
21-
22-
# Helper to process wavedrom data
23-
def process_wavedrom(json_data)
24-
result = json_data.dup
25-
26-
# Process reg array if it exists
27-
if result["reg"].is_a?(Array)
28-
result["reg"].each do |item|
29-
# For fields that are likely opcodes or immediates (type 2)
30-
if item["type"] == 2
31-
# Convert to number first (if it's a string)
32-
if item["name"].is_a?(String)
33-
if item["name"].start_with?("0x")
34-
# Already hexadecimal
35-
numeric_value = item["name"].to_i(16)
36-
elsif item["name"] =~ /^[01]+$/
37-
# Binary string without prefix
38-
numeric_value = item["name"].to_i(2)
39-
elsif item["name"] =~ /^\d+$/
40-
# Decimal
41-
numeric_value = item["name"].to_i
42-
else
43-
# Not a number, leave it alone
44-
next
45-
end
46-
else
47-
# Already a number
48-
numeric_value = item["name"]
49-
end
50-
51-
# Convert to hexadecimal string
52-
hex_str = numeric_value.to_s(16).downcase
53-
54-
# Set the name to a specially formatted string that will be converted
55-
# to a hex literal in our custom JSON converter
56-
item["name"] = "0x" + hex_str
57-
end
58-
59-
# Ensure bits is a number
60-
if item["bits"].is_a?(String) && item["bits"] =~ /^\d+$/
61-
item["bits"] = item["bits"].to_i
62-
end
63-
end
64-
end
65-
66-
result
67-
end
68-
%>
691
= Instruction Appendix
702
:doctype: book
713
:wavedrom: <%= $root %>/node_modules/.bin/wavedrom-cli
@@ -86,23 +18,23 @@ This instruction has different encodings in RV32 and RV64
8618
RV32::
8719
[wavedrom, ,svg,subs='attributes',width="100%"]
8820
....
89-
<%= fix_entities(json_dump_with_hex_literals(process_wavedrom(inst.wavedrom_desc(32)))) %>
21+
<%= inst.processed_wavedrom_desc(32) %>
9022
....
9123

9224
RV64::
9325
[wavedrom, ,svg,subs='attributes',width="100%"]
9426
....
95-
<%= fix_entities(json_dump_with_hex_literals(process_wavedrom(inst.wavedrom_desc(64)))) %>
27+
<%= inst.processed_wavedrom_desc(64) %>
9628
....
9729
<%- else -%>
9830
[wavedrom, ,svg,subs='attributes',width="100%"]
9931
....
100-
<%= fix_entities(json_dump_with_hex_literals(process_wavedrom(inst.wavedrom_desc(inst.base.nil? ? 64 : inst.base)))) %>
32+
<%= inst.processed_wavedrom_desc(inst.base.nil? ? 64 : inst.base) %>
10133
....
10234
<%- end -%>
10335

10436
Description::
105-
<%= fix_entities(inst.description) %>
37+
<%= inst.fix_entities(inst.description) %>
10638

10739
Decode Variables::
10840
<%- if inst.multi_encoding? ? (inst.decode_variables(32).empty? && inst.decode_variables(64).empty?) : inst.decode_variables(inst.base.nil? ? 64 : inst.base).empty? -%>
@@ -149,12 +81,12 @@ Included in::
14981
|===
15082
| Extension | Version
15183
<% inst.defined_by_condition.flat_versions.each do |r| %>
152-
| *<%= r.name %>* | <%= fix_entities(r.requirement_specs_to_s) %>
84+
| *<%= r.name %>* | <%= inst.fix_entities(r.requirement_specs_to_s) %>
15385
<% end %>
15486
|===
15587
<%- else -%>
156-
<%= fix_entities(inst.defined_by_condition.to_asciidoc) %>
88+
<%= inst.fix_entities(inst.defined_by_condition.to_asciidoc) %>
15789
<%- end -%>
15890

159-
<<<
91+
<
16092
<% end %>

backends/manual/templates/instruction.adoc.erb

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
This instruction is defined by:
99

10-
<%= inst.defined_by_condition.to_asciidoc %>
10+
<%= inst.fix_entities(inst.defined_by_condition.to_asciidoc) %>
1111

1212
This instruction is included in the following profiles:
1313

@@ -41,20 +41,20 @@ RV32::
4141
+
4242
[wavedrom, ,svg,subs='attributes',width="100%"]
4343
....
44-
<%= JSON.dump inst.wavedrom_desc(32) %>
44+
<%= inst.processed_wavedrom_desc(32) %>
4545
....
4646

4747
RV64::
4848
+
4949
[wavedrom, ,svg,subs='attributes',width="100%"]
5050
....
51-
<%= JSON.dump inst.wavedrom_desc(64) %>
51+
<%= inst.processed_wavedrom_desc(64) %>
5252
....
5353
====
5454
<%- else -%>
5555
[wavedrom, ,svg,subs='attributes',width="100%"]
5656
....
57-
<%= JSON.dump inst.wavedrom_desc(inst.base.nil? ? 32 : inst.base) %>
57+
<%= inst.processed_wavedrom_desc(inst.base.nil? ? 32 : inst.base) %>
5858
....
5959
<%- end -%>
6060

@@ -69,7 +69,7 @@ RV64::
6969
This instruction must have data-independent timing when extension `Zkt` is enabled.
7070
<%- end -%>
7171

72-
<%= inst.description %>
72+
<%= inst.fix_entities(inst.description) %>
7373

7474
== Access
7575
[cols="^,^,^,^,^"]
@@ -84,7 +84,7 @@ This instruction must have data-independent timing when extension `Zkt` is enabl
8484
|===
8585

8686
<%- if inst.access_detail? -%>
87-
<%= inst.access_detail %>
87+
<%= inst.fix_entities(inst.access_detail) %>
8888
<%- end -%>
8989

9090
== Decode Variables
@@ -128,7 +128,7 @@ IDL::
128128
+
129129
[source,idl,subs="specialchars,macros"]
130130
----
131-
<%= inst.operation_ast.gen_adoc %>
131+
<%= inst.fix_entities(inst.operation_ast.gen_adoc) %>
132132
----
133133
<%- end -%>
134134

@@ -137,7 +137,7 @@ Sail::
137137
+
138138
[source,sail]
139139
----
140-
<%= inst["sail()"] %>
140+
<%= inst.fix_entities(inst["sail()"]) %>
141141
----
142142
<%- end -%>
143143
====
@@ -149,7 +149,7 @@ Sail::
149149
This instruction may result in the following synchronous exceptions:
150150

151151
<%- exception_list.sort.each do |etype| -%>
152-
* <%= etype %>
152+
* <%= inst.fix_entities(etype) %>
153153
<%- end -%>
154154

155155
<%- end -%>

lib/arch_obj_models/instruction.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@
77

88
# model of a specific instruction in a specific base (RV32/RV64)
99
class Instruction < DatabaseObject
10+
def processed_wavedrom_desc(base)
11+
data = wavedrom_desc(base)
12+
processed_data = process_wavedrom(data)
13+
TemplateHelpers.fix_entities(json_dump_with_hex_literals(processed_data))
14+
end
15+
16+
1017
def self.ary_from_location(location_str_or_int)
1118
return [location_str_or_int] if location_str_or_int.is_a?(Integer)
1219

lib/template_helpers.rb

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,73 @@
99

1010
# collection of functions that can be used inside ERB templates
1111
module TemplateHelpers
12+
13+
def fix_entities(text)
14+
text.to_s.gsub("&ne;", "≠")
15+
.gsub("&pm;", "±")
16+
.gsub("-&infin;", "−∞")
17+
.gsub("+&infin;", "+∞")
18+
end
19+
20+
# Custom JSON converter for wavedrom that handles hexadecimal literals
21+
def json_dump_with_hex_literals(data)
22+
# First convert to standard JSON
23+
json_string = JSON.dump(data)
24+
25+
# Replace string hex values with actual hex literals
26+
json_string.gsub(/"0x([0-9a-fA-F]+)"/) do |match|
27+
# Remove the quotes, leaving just the hex literal
28+
"0x#{$1}"
29+
end.gsub(/"name":/, '"name": ') # Add space after colon for name field
30+
end
31+
32+
# Helper to process wavedrom data
33+
def process_wavedrom(json_data)
34+
result = json_data.dup
35+
36+
# Process reg array if it exists
37+
if result["reg"].is_a?(Array)
38+
result["reg"].each do |item|
39+
# For fields that are likely opcodes or immediates (type 2)
40+
if item["type"] == 2
41+
# Convert to number first (if it's a string)
42+
if item["name"].is_a?(String)
43+
if item["name"].start_with?("0x")
44+
# Already hexadecimal
45+
numeric_value = item["name"].to_i(16)
46+
elsif item["name"] =~ /^[01]+$/
47+
# Binary string without prefix
48+
numeric_value = item["name"].to_i(2)
49+
elsif item["name"] =~ /^\d+$/
50+
# Decimal
51+
numeric_value = item["name"].to_i
52+
else
53+
# Not a number, leave it alone
54+
next
55+
end
56+
else
57+
# Already a number
58+
numeric_value = item["name"]
59+
end
60+
61+
# Convert to hexadecimal string
62+
hex_str = numeric_value.to_s(16).downcase
63+
64+
# Set the name to a specially formatted string that will be converted
65+
# to a hex literal in our custom JSON converter
66+
item["name"] = "0x" + hex_str
67+
end
68+
69+
# Ensure bits is a number
70+
if item["bits"].is_a?(String) && item["bits"] =~ /^\d+$/
71+
item["bits"] = item["bits"].to_i
72+
end
73+
end
74+
end
75+
76+
result
77+
end
78+
1279
# Insert a hyperlink to an extension.
1380
# @param name [#to_s] Name of the extension
1481
def link_to_ext(name)

0 commit comments

Comments
 (0)