udb-gen 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +26 -0
- data/bin/udb-gen +57 -0
- data/lib/udb-gen/adoc_helpers.rb +83 -0
- data/lib/udb-gen/common_opts.rb +51 -0
- data/lib/udb-gen/defines.rb +14 -0
- data/lib/udb-gen/generators/ext_doc/generator.rb +228 -0
- data/lib/udb-gen/generators/ext_doc/helpers.rb +63 -0
- data/lib/udb-gen/generators/isa_explorer/generator.rb +247 -0
- data/lib/udb-gen/generators/isa_explorer/js_xlsx_writer.rb +140 -0
- data/lib/udb-gen/generators/isa_explorer/table_builder.rb +244 -0
- data/lib/udb-gen/generators/manual/generator.rb +124 -0
- data/lib/udb-gen/generators/manual/tasks.rake +472 -0
- data/lib/udb-gen/subcommand.rb +33 -0
- data/lib/udb-gen/template_helpers.rb +153 -0
- data/lib/udb-gen/version.rb +9 -0
- data/lib/udb-gen.rb +9 -0
- data/templates/common/csr.adoc.erb +133 -0
- data/templates/common/inst.adoc.erb +130 -0
- data/templates/common/mmr.adoc.erb +71 -0
- data/templates/ext_doc/_csr_list.adoc.erb +49 -0
- data/templates/ext_doc/_header.adoc.erb +57 -0
- data/templates/ext_doc/_idl_functions.adoc.erb +47 -0
- data/templates/ext_doc/_instruction_list.adoc.erb +85 -0
- data/templates/ext_doc/_preamble.adoc.erb +89 -0
- data/templates/ext_doc/ext_pdf.adoc.erb +144 -0
- data/templates/isa_explorer/csr-browser.html.erb +21 -0
- data/templates/isa_explorer/ext-browser.html.erb +21 -0
- data/templates/isa_explorer/inst-browser.html.erb +21 -0
- data/templates/isa_explorer/load_table.js +39 -0
- data/templates/manual/csr.adoc.erb +172 -0
- data/templates/manual/ext.adoc.erb +85 -0
- data/templates/manual/func.adoc.erb +45 -0
- data/templates/manual/highlight.js +3580 -0
- data/templates/manual/index.adoc.erb +16 -0
- data/templates/manual/instruction.adoc.erb +180 -0
- data/templates/manual/isa_nav.adoc.erb +29 -0
- data/templates/manual/isa_version_index.adoc.erb +12 -0
- data/templates/manual/param_list.adoc.erb +22 -0
- data/templates/manual/playbook.yml.erb +130 -0
- metadata +270 -0
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
|
2
|
+
# SPDX-License-Identifier: BSD-3-Clause-Clear
|
|
3
|
+
|
|
4
|
+
# typed: true
|
|
5
|
+
# frozen_string_literal: true
|
|
6
|
+
|
|
7
|
+
require "sorbet-runtime"
|
|
8
|
+
require "tty-exit"
|
|
9
|
+
require "tty-progressbar"
|
|
10
|
+
require "write_xlsx"
|
|
11
|
+
|
|
12
|
+
require_relative "../../common_opts"
|
|
13
|
+
require_relative "../../defines"
|
|
14
|
+
require_relative "../../template_helpers"
|
|
15
|
+
require_relative "table_builder"
|
|
16
|
+
require_relative "js_xlsx_writer"
|
|
17
|
+
|
|
18
|
+
require "udb/obj/extension"
|
|
19
|
+
|
|
20
|
+
module UdbGen
|
|
21
|
+
class GenIsaExplorerOptions < SubcommandWithCommonOptions
|
|
22
|
+
include TTY::Exit
|
|
23
|
+
include TemplateHelpers
|
|
24
|
+
|
|
25
|
+
NAME = "isa-explorer"
|
|
26
|
+
|
|
27
|
+
sig { void }
|
|
28
|
+
def initialize
|
|
29
|
+
super(name: NAME, desc: "Create ISA explorer tables / sites")
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
usage \
|
|
33
|
+
command: NAME,
|
|
34
|
+
desc: "Create static websites and/or spreadsheets populated with helpful ISA information",
|
|
35
|
+
example: <<~EXAMPLE
|
|
36
|
+
Generate a static HTML page with extension information
|
|
37
|
+
$ #{File.basename($PROGRAM_NAME)} #{NAME} -t ext-browser -o gen/isa_explorer
|
|
38
|
+
|
|
39
|
+
Generate a static HTML page with instruciton information
|
|
40
|
+
$ #{File.basename($PROGRAM_NAME)} #{NAME} -t inst-browser -o gen/isa_explorer
|
|
41
|
+
|
|
42
|
+
Generate a static HTML page with csr information
|
|
43
|
+
$ #{File.basename($PROGRAM_NAME)} #{NAME} -t csr-browser -o gen/isa_explorer
|
|
44
|
+
|
|
45
|
+
Generate an Excel spreadsheet with all info
|
|
46
|
+
$ #{File.basename($PROGRAM_NAME)} #{NAME} -t xlsx -o gen/isa_explorer
|
|
47
|
+
EXAMPLE
|
|
48
|
+
|
|
49
|
+
option :type do
|
|
50
|
+
T.bind(self, TTY::Option::Parameter::Option)
|
|
51
|
+
short "-t"
|
|
52
|
+
long "--type=type"
|
|
53
|
+
desc "The type of artifact to build"
|
|
54
|
+
permit ["ext-browser", "inst-browser", "csr-browser", "xlsx"]
|
|
55
|
+
required
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
option :skip do
|
|
59
|
+
T.bind(self, TTY::Option::Parameter::Option)
|
|
60
|
+
long "--skip=N"
|
|
61
|
+
desc "Only consider every Nth ext/inst/etc. (for testing)"
|
|
62
|
+
convert :integer
|
|
63
|
+
default 0
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
option :output_dir do
|
|
67
|
+
T.bind(self, TTY::Option::Parameter::Option)
|
|
68
|
+
required
|
|
69
|
+
short "-o"
|
|
70
|
+
long "--out=directory"
|
|
71
|
+
desc "Output directory"
|
|
72
|
+
convert :path
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
option :debug do
|
|
76
|
+
T.bind(self, TTY::Option::Parameter::Option)
|
|
77
|
+
desc "Set debug level"
|
|
78
|
+
long "--debug=level"
|
|
79
|
+
short "-d"
|
|
80
|
+
default "info"
|
|
81
|
+
permit ["debug", "info", "warn", "error", "fatal"]
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
sig { void }
|
|
85
|
+
def gen_ext_browser
|
|
86
|
+
FileUtils.mkdir_p params[:output_dir]
|
|
87
|
+
|
|
88
|
+
target_html_fn = params[:output_dir] / "ext-explorer.html"
|
|
89
|
+
|
|
90
|
+
# Delete target file if already present.
|
|
91
|
+
if target_html_fn.exist?
|
|
92
|
+
begin
|
|
93
|
+
File.delete(target_html_fn)
|
|
94
|
+
rescue StandardError => e
|
|
95
|
+
raise "Can't delete '#{target_html_fn}': #{e.message}"
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
builder = IsaExplorer::TableBuilder.new(cfg_arch, params[:skip])
|
|
100
|
+
writer = IsaExplorer::JsXlsxWriter.new
|
|
101
|
+
js_table = writer.js_table(builder.ext_table, "ext_table")
|
|
102
|
+
|
|
103
|
+
template_path = Pathname.new(Gem.loaded_specs["udb-gen"].full_gem_path) / "templates" / "isa_explorer" / "ext-browser.html.erb"
|
|
104
|
+
|
|
105
|
+
erb = ERB.new(template_path.read, trim_mode: "-")
|
|
106
|
+
erb.filename = template_path.to_s
|
|
107
|
+
|
|
108
|
+
Udb.logger.info "SUCCESS: Writing result to #{target_html_fn}"
|
|
109
|
+
target_html_fn.write erb.result(binding)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
sig { void }
|
|
113
|
+
def gen_inst_browser
|
|
114
|
+
FileUtils.mkdir_p params[:output_dir]
|
|
115
|
+
|
|
116
|
+
target_html_fn = params[:output_dir] / "inst-explorer.html"
|
|
117
|
+
|
|
118
|
+
# Delete target file if already present.
|
|
119
|
+
if target_html_fn.exist?
|
|
120
|
+
begin
|
|
121
|
+
File.delete(target_html_fn)
|
|
122
|
+
rescue StandardError => e
|
|
123
|
+
raise "Can't delete '#{target_html_fn}': #{e.message}"
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
builder = IsaExplorer::TableBuilder.new(cfg_arch, params[:skip])
|
|
128
|
+
writer = IsaExplorer::JsXlsxWriter.new
|
|
129
|
+
js_table = writer.js_table(builder.inst_table, "inst_table")
|
|
130
|
+
|
|
131
|
+
template_path = Pathname.new(Gem.loaded_specs["udb-gen"].full_gem_path) / "templates" / "isa_explorer" / "inst-browser.html.erb"
|
|
132
|
+
|
|
133
|
+
erb = ERB.new(template_path.read, trim_mode: "-")
|
|
134
|
+
erb.filename = template_path.to_s
|
|
135
|
+
|
|
136
|
+
Udb.logger.info "SUCCESS: Writing result to #{target_html_fn}"
|
|
137
|
+
target_html_fn.write erb.result(binding)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
sig { void }
|
|
141
|
+
def gen_csr_browser
|
|
142
|
+
FileUtils.mkdir_p params[:output_dir]
|
|
143
|
+
|
|
144
|
+
target_html_fn = params[:output_dir] / "csr-explorer.html"
|
|
145
|
+
|
|
146
|
+
# Delete target file if already present.
|
|
147
|
+
if target_html_fn.exist?
|
|
148
|
+
begin
|
|
149
|
+
File.delete(target_html_fn)
|
|
150
|
+
rescue StandardError => e
|
|
151
|
+
raise "Can't delete '#{target_html_fn}': #{e.message}"
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
builder = IsaExplorer::TableBuilder.new(cfg_arch, params[:skip])
|
|
156
|
+
writer = IsaExplorer::JsXlsxWriter.new
|
|
157
|
+
js_table = writer.js_table(builder.csr_table, "csr_table")
|
|
158
|
+
|
|
159
|
+
template_path = Pathname.new(Gem.loaded_specs["udb-gen"].full_gem_path) / "templates" / "isa_explorer" / "csr-browser.html.erb"
|
|
160
|
+
|
|
161
|
+
erb = ERB.new(template_path.read, trim_mode: "-")
|
|
162
|
+
erb.filename = template_path.to_s
|
|
163
|
+
|
|
164
|
+
Udb.logger.info "SUCCESS: Writing result to #{target_html_fn}"
|
|
165
|
+
target_html_fn.write erb.result(binding)
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
sig { void }
|
|
169
|
+
def gen_xlsx
|
|
170
|
+
FileUtils.mkdir_p params[:output_dir]
|
|
171
|
+
|
|
172
|
+
target_xlsx_fn = params[:output_dir] / "isa_explorer.xlsx"
|
|
173
|
+
|
|
174
|
+
# Delete target file if already present.
|
|
175
|
+
if target_xlsx_fn.exist?
|
|
176
|
+
begin
|
|
177
|
+
File.delete(target_xlsx_fn)
|
|
178
|
+
rescue StandardError => e
|
|
179
|
+
raise "Can't delete '#{target_xlsx_fn}': #{e.message}"
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
builder = IsaExplorer::TableBuilder.new(cfg_arch, params[:skip])
|
|
184
|
+
writer = IsaExplorer::JsXlsxWriter.new
|
|
185
|
+
|
|
186
|
+
# Create a new Excel workbook
|
|
187
|
+
Udb.logger.info "Creating Excel workboook #{target_xlsx_fn}"
|
|
188
|
+
workbook = WriteXLSX.new(target_xlsx_fn)
|
|
189
|
+
|
|
190
|
+
# Extension worksheet
|
|
191
|
+
Udb.logger.info "Creating extension table data structure"
|
|
192
|
+
ext_worksheet = workbook.add_worksheet("Extensions")
|
|
193
|
+
Udb.logger.info "Adding extension table to worksheet #{ext_worksheet.name}"
|
|
194
|
+
writer.xlsx_table(builder.ext_table, workbook, ext_worksheet)
|
|
195
|
+
|
|
196
|
+
# Instruction worksheet
|
|
197
|
+
Udb.logger.info "Creating instruction table data structure"
|
|
198
|
+
inst_worksheet = workbook.add_worksheet("Instructions")
|
|
199
|
+
Udb.logger.info "Adding instruction table to worksheet #{inst_worksheet.name}"
|
|
200
|
+
writer.xlsx_table(builder.inst_table, workbook, inst_worksheet)
|
|
201
|
+
|
|
202
|
+
# CSR worksheet
|
|
203
|
+
Udb.logger.info "Creating CSR table data structure"
|
|
204
|
+
csr_worksheet = workbook.add_worksheet("CSRs")
|
|
205
|
+
Udb.logger.info "Adding CSR table to worksheet #{csr_worksheet.name}"
|
|
206
|
+
writer.xlsx_table(builder.csr_table, workbook, csr_worksheet)
|
|
207
|
+
|
|
208
|
+
workbook.close
|
|
209
|
+
|
|
210
|
+
Udb.logger.info "SUCCESS: Wrote result to #{target_xlsx_fn}"
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
sig { override.params(argv: T::Array[String]).returns(T.noreturn) }
|
|
214
|
+
def run(argv)
|
|
215
|
+
parse(argv)
|
|
216
|
+
|
|
217
|
+
if params[:help]
|
|
218
|
+
print help
|
|
219
|
+
exit_with(:success)
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
if params.errors.any?
|
|
223
|
+
exit_with(:usage_error, "#{params.errors.summary}\n\n#{help}")
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
unless params.remaining.empty?
|
|
227
|
+
exit_with(:usage_error, "Unknown arguments: #{params.remaining}\n")
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
case params[:type]
|
|
231
|
+
when "ext-browser"
|
|
232
|
+
gen_ext_browser
|
|
233
|
+
when "inst-browser"
|
|
234
|
+
gen_inst_browser
|
|
235
|
+
when "csr-browser"
|
|
236
|
+
gen_csr_browser
|
|
237
|
+
when "xlsx"
|
|
238
|
+
gen_xlsx
|
|
239
|
+
else
|
|
240
|
+
Udb.logger.error "Unknown target type: #{params[:type]}"
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
exit_with(:success)
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
end
|
|
247
|
+
end
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
|
2
|
+
# SPDX-License-Identifier: BSD-3-Clause-Clear
|
|
3
|
+
|
|
4
|
+
# typed: true
|
|
5
|
+
# frozen_string_literal: true
|
|
6
|
+
|
|
7
|
+
require "sorbet-runtime"
|
|
8
|
+
require "write_xlsx"
|
|
9
|
+
|
|
10
|
+
module UdbGen
|
|
11
|
+
module IsaExplorer
|
|
12
|
+
class JsXlsxWriter
|
|
13
|
+
extend T::Sig
|
|
14
|
+
|
|
15
|
+
# Create ISA Explorer table as JavaScript file.
|
|
16
|
+
#
|
|
17
|
+
# @param table Table data
|
|
18
|
+
# @param div_name Name of div element in HTML
|
|
19
|
+
sig { params(table: T::Hash[String, T::Array[T.untyped]], div_name: String).returns(String) }
|
|
20
|
+
def js_table(table, div_name)
|
|
21
|
+
columns = table.fetch("columns")
|
|
22
|
+
rows = table.fetch("rows")
|
|
23
|
+
|
|
24
|
+
fp = StringIO.new
|
|
25
|
+
fp.write "// Define data array\n"
|
|
26
|
+
fp.write "\n"
|
|
27
|
+
fp.write "var tabledata = [\n"
|
|
28
|
+
|
|
29
|
+
rows.each do |row|
|
|
30
|
+
items = []
|
|
31
|
+
columns.each_index do |i|
|
|
32
|
+
column = columns.fetch(i)
|
|
33
|
+
column_name = column.fetch(:name).gsub("\n", " ")
|
|
34
|
+
cell = row.fetch(i)
|
|
35
|
+
if cell.is_a?(String)
|
|
36
|
+
cell_fmt = '"' + row.fetch(i).gsub("\n", "\\n") + '"'
|
|
37
|
+
elsif cell.is_a?(TrueClass) || cell.is_a?(FalseClass) || cell.is_a?(Integer)
|
|
38
|
+
cell_fmt = "#{cell}"
|
|
39
|
+
elsif cell.is_a?(Array)
|
|
40
|
+
cell_fmt = '"' + cell.join("\\n") + '"'
|
|
41
|
+
else
|
|
42
|
+
raise ArgumentError, "Unknown cell class of #{cell.class} for '#{cell}'"
|
|
43
|
+
end
|
|
44
|
+
items.append('"' + column_name + '":' + cell_fmt)
|
|
45
|
+
end
|
|
46
|
+
fp.write " {" + items.join(", ") + "},\n"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
fp.write "];\n"
|
|
50
|
+
fp.write "\n"
|
|
51
|
+
fp.write "// Initialize table\n"
|
|
52
|
+
fp.write "var table = new Tabulator(\"##{div_name}\", {\n"
|
|
53
|
+
fp.write " height: window.innerHeight-25, // Set height to window less 25 pixels for horz scrollbar\n"
|
|
54
|
+
fp.write " data: tabledata, // Assign data to table\n"
|
|
55
|
+
fp.write " columns:[\n"
|
|
56
|
+
columns.each do |column|
|
|
57
|
+
column_name = column.fetch(:name).gsub("\n", " ")
|
|
58
|
+
sorter = column.fetch(:sorter)
|
|
59
|
+
formatter = column.fetch(:formatter)
|
|
60
|
+
fp.write " {title: \"#{column_name}\", field: \"#{column_name}\", sorter: \"#{sorter}\", formatter: \"#{formatter}\""
|
|
61
|
+
|
|
62
|
+
if column[:headerFilter] == true
|
|
63
|
+
fp.write ", headerFilter: true"
|
|
64
|
+
end
|
|
65
|
+
if column[:headerVertical] == true
|
|
66
|
+
fp.write ", headerVertical: true"
|
|
67
|
+
end
|
|
68
|
+
if column[:frozen] == true
|
|
69
|
+
fp.write ", frozen: true"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
if formatter == "link"
|
|
73
|
+
formatterParams = column.fetch(:formatterParams)
|
|
74
|
+
urlPrefix = formatterParams.fetch(:urlPrefix)
|
|
75
|
+
fp.write ", formatterParams:{\n"
|
|
76
|
+
fp.write " labelField:\"#{column_name}\",\n"
|
|
77
|
+
fp.write " urlPrefix:\"#{urlPrefix}\"\n"
|
|
78
|
+
fp.write " }\n"
|
|
79
|
+
end
|
|
80
|
+
fp.write " },\n"
|
|
81
|
+
end
|
|
82
|
+
fp.write " ]\n"
|
|
83
|
+
fp.write "});\n"
|
|
84
|
+
fp.write "\n"
|
|
85
|
+
|
|
86
|
+
fp.write "// Load data in chunks after table is built\n"
|
|
87
|
+
fp.write "table.on(\"tableBuilt\", function() {\n"
|
|
88
|
+
fp.write " loadDataInChunks(tabledata);\n"
|
|
89
|
+
fp.write "});\n"
|
|
90
|
+
fp.write "\n"
|
|
91
|
+
fp.rewind
|
|
92
|
+
T.must(fp.read)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Create ISA Explorer table as XLSX worksheet.
|
|
96
|
+
#
|
|
97
|
+
# @param table [Hash<String,Array<String>] Table data
|
|
98
|
+
# @param workbook
|
|
99
|
+
# @param worksheet
|
|
100
|
+
sig { params(table: T::Hash[String, T::Array[T.untyped]], workbook: WriteXLSX, worksheet: Writexlsx::Worksheet).void }
|
|
101
|
+
def xlsx_table(table, workbook, worksheet)
|
|
102
|
+
# Add and define a header format
|
|
103
|
+
header_format = workbook.add_format
|
|
104
|
+
header_format.set_bold
|
|
105
|
+
header_format.set_align("center")
|
|
106
|
+
|
|
107
|
+
# Add column names in 1st row (row 0).
|
|
108
|
+
col_num = 0
|
|
109
|
+
table.fetch("columns").each do |column|
|
|
110
|
+
worksheet.write(0, col_num, column.fetch(:name), header_format)
|
|
111
|
+
col_num += 1
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Add table information in rows
|
|
115
|
+
row_num = 1
|
|
116
|
+
table.fetch("rows").each do |row_cells|
|
|
117
|
+
col_num = 0
|
|
118
|
+
row_cells.each do |cell|
|
|
119
|
+
if cell.is_a?(String) || cell.is_a?(Integer)
|
|
120
|
+
cell_fmt = cell.to_s
|
|
121
|
+
elsif cell.is_a?(TrueClass) || cell.is_a?(FalseClass)
|
|
122
|
+
cell_fmt = cell ? "Y" : "N"
|
|
123
|
+
elsif cell.is_a?(Array)
|
|
124
|
+
cell_fmt = cell.join(", ")
|
|
125
|
+
else
|
|
126
|
+
raise ArgumentError, "Unknown cell class of #{cell.class} for '#{cell}'"
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
worksheet.write(row_num, col_num, cell_fmt)
|
|
130
|
+
col_num += 1
|
|
131
|
+
end
|
|
132
|
+
row_num += 1
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Set column widths to hold data width.
|
|
136
|
+
worksheet.autofit
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
|
2
|
+
# SPDX-License-Identifier: BSD-3-Clause-Clear
|
|
3
|
+
|
|
4
|
+
# typed: true
|
|
5
|
+
# frozen_string_literal: true
|
|
6
|
+
|
|
7
|
+
require "sorbet-runtime"
|
|
8
|
+
require "tty-progressbar"
|
|
9
|
+
|
|
10
|
+
module UdbGen
|
|
11
|
+
module IsaExplorer
|
|
12
|
+
class TableBuilder
|
|
13
|
+
extend T::Sig
|
|
14
|
+
|
|
15
|
+
sig { params(arch: Udb::ConfiguredArchitecture, skip: Integer).void }
|
|
16
|
+
def initialize(arch, skip)
|
|
17
|
+
@arch = arch
|
|
18
|
+
@skip = skip
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @return Extension table data
|
|
22
|
+
sig { returns(T::Hash[String, T::Array[T.untyped]]) }
|
|
23
|
+
def ext_table
|
|
24
|
+
sorted_releases = sorted_profile_releases
|
|
25
|
+
|
|
26
|
+
table = {
|
|
27
|
+
# Array of hashes
|
|
28
|
+
"columns" => [
|
|
29
|
+
{ name: "Extension Name", formatter: "link", sorter: "alphanum", headerFilter: true, frozen: true, formatterParams:
|
|
30
|
+
{
|
|
31
|
+
labelField: "Extension Name",
|
|
32
|
+
urlPrefix: "https://riscv.github.io/riscv-unified-db/manual/html/isa/isa_20240411/exts/"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
{ name: "Description", formatter: "textarea", sorter: "alphanum", headerFilter: true },
|
|
36
|
+
{ name: "IC", formatter: "textarea", sorter: "alphanum", headerFilter: true },
|
|
37
|
+
{ name: "Requires\n(Exts)", formatter: "textarea", sorter: "alphanum" },
|
|
38
|
+
{ name: "Transitive Requires\n(Ext)", formatter: "textarea", sorter: "alphanum" },
|
|
39
|
+
{ name: "Incompatible\n(Ext Reqs)", formatter: "textarea", sorter: "alphanum" },
|
|
40
|
+
{ name: "Ratified", formatter: "textarea", sorter: "boolean", headerFilter: true },
|
|
41
|
+
{ name: "Ratification\nDate", formatter: "textarea", sorter: "alphanum", headerFilter: true },
|
|
42
|
+
sorted_releases.map do |pr|
|
|
43
|
+
{ name: "#{pr.name}", formatter: "textarea", sorter: "alphanum", headerFilter: true }
|
|
44
|
+
end
|
|
45
|
+
].flatten,
|
|
46
|
+
|
|
47
|
+
# Will eventually be an array containing arrays.
|
|
48
|
+
"rows" => []
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
pb = Udb.create_progressbar(
|
|
52
|
+
"Analyzing extensions [:bar] :current/:total",
|
|
53
|
+
total: @arch.extensions.size,
|
|
54
|
+
clear: true
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
@arch.extensions.sort_by!(&:name).each_with_index do |ext, idx|
|
|
58
|
+
pb.advance
|
|
59
|
+
|
|
60
|
+
if @skip != 0
|
|
61
|
+
next unless (idx % @skip) == 0
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
row = [
|
|
65
|
+
ext.name, # Name
|
|
66
|
+
ext.long_name, # Description
|
|
67
|
+
ext.compact_priv_type, # IC
|
|
68
|
+
ext.max_version.ext_requirements(expand: false).map do |cond_ext_req|
|
|
69
|
+
if cond_ext_req.cond.empty?
|
|
70
|
+
cond_ext_req.ext_req.name
|
|
71
|
+
else
|
|
72
|
+
"#{cond_ext_req.ext_req.name} if #{cond_ext_req.cond}"
|
|
73
|
+
end
|
|
74
|
+
end.uniq, # Requires
|
|
75
|
+
ext.max_version.ext_requirements(expand: true).map do |cond_ext_req|
|
|
76
|
+
if cond_ext_req.cond.empty?
|
|
77
|
+
cond_ext_req.ext_req.name
|
|
78
|
+
else
|
|
79
|
+
"#{cond_ext_req.ext_req.name} if #{cond_ext_req.cond}"
|
|
80
|
+
end
|
|
81
|
+
end.uniq, # Transitive Requires
|
|
82
|
+
ext.conflicting_extensions.map(&:name),
|
|
83
|
+
ext.ratified,
|
|
84
|
+
if ext.ratified
|
|
85
|
+
if ext.min_ratified_version.ratification_date.nil? || ext.min_ratified_version.ratification_date.empty?
|
|
86
|
+
"UDB MISSING"
|
|
87
|
+
else
|
|
88
|
+
ext.min_ratified_version.ratification_date
|
|
89
|
+
end
|
|
90
|
+
else
|
|
91
|
+
""
|
|
92
|
+
end
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
sorted_releases.each do |pr|
|
|
96
|
+
row.append(presence2char(pr.extension_presence(ext.name)))
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
table["rows"].append(row)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
table
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# @return Instruction table data
|
|
106
|
+
sig { returns(T::Hash[String, T::Array[T.untyped]]) }
|
|
107
|
+
def inst_table
|
|
108
|
+
sorted_releases = sorted_profile_releases
|
|
109
|
+
|
|
110
|
+
table = {
|
|
111
|
+
# Array of hashes
|
|
112
|
+
"columns" => [
|
|
113
|
+
{ name: "Instruction Name", formatter: "link", sorter: "alphanum", headerFilter: true, frozen: true, formatterParams:
|
|
114
|
+
{
|
|
115
|
+
labelField: "Instruction Name",
|
|
116
|
+
urlPrefix: "https://riscv.github.io/riscv-unified-db/manual/html/isa/isa_20240411/insts/"
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
{ name: "Description", formatter: "textarea", sorter: "alphanum", headerFilter: true },
|
|
120
|
+
{ name: "Assembly", formatter: "textarea", sorter: "alphanum", headerFilter: true },
|
|
121
|
+
sorted_releases.map do |pr|
|
|
122
|
+
{ name: "#{pr.name}", formatter: "textarea", sorter: "alphanum", headerFilter: true }
|
|
123
|
+
end
|
|
124
|
+
].flatten,
|
|
125
|
+
|
|
126
|
+
# Will eventually be an array containing arrays.
|
|
127
|
+
"rows" => []
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
insts = @arch.instructions.sort_by!(&:name)
|
|
131
|
+
progressbar = TTY::ProgressBar.new("Instruction Table [:bar] :current/:total", total: insts.size, output: $stdout)
|
|
132
|
+
|
|
133
|
+
insts.each_with_index do |inst, idx|
|
|
134
|
+
progressbar.advance
|
|
135
|
+
if @skip != 0
|
|
136
|
+
next unless (idx % @skip) == 0
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
row = [
|
|
140
|
+
inst.name,
|
|
141
|
+
inst.long_name,
|
|
142
|
+
inst.name + " " + inst.assembly.gsub("x", "r")
|
|
143
|
+
]
|
|
144
|
+
|
|
145
|
+
sorted_releases.each do |pr|
|
|
146
|
+
row.append(presence2char(pr.instruction_presence(inst.name)))
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
table["rows"].append(row)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
table
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# @return CSR table data
|
|
156
|
+
sig { returns(T::Hash[String, T::Array[T.untyped]]) }
|
|
157
|
+
def csr_table
|
|
158
|
+
sorted_releases = sorted_profile_releases
|
|
159
|
+
|
|
160
|
+
table = {
|
|
161
|
+
# Array of hashes
|
|
162
|
+
"columns" => [
|
|
163
|
+
{ name: "CSR Name", formatter: "link", sorter: "alphanum", headerFilter: true, frozen: true, formatterParams:
|
|
164
|
+
{
|
|
165
|
+
labelField: "CSR Name",
|
|
166
|
+
urlPrefix: "https://riscv.github.io/riscv-unified-db/manual/html/isa/isa_20240411/csrs/"
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
{ name: "Address", formatter: "textarea", sorter: "number", headerFilter: true },
|
|
170
|
+
{ name: "Description", formatter: "textarea", sorter: "alphanum", headerFilter: true },
|
|
171
|
+
sorted_releases.map do |pr|
|
|
172
|
+
{ name: "#{pr.name}", formatter: "textarea", sorter: "alphanum", headerFilter: true }
|
|
173
|
+
end
|
|
174
|
+
].flatten,
|
|
175
|
+
|
|
176
|
+
# Will eventually be an array containing arrays.
|
|
177
|
+
"rows" => []
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
csrs = @arch.csrs.sort_by!(&:name)
|
|
181
|
+
progressbar = TTY::ProgressBar.new("CSR Table [:bar]", total: csrs.size, output: $stdout)
|
|
182
|
+
|
|
183
|
+
csrs.each_with_index do |csr, idx|
|
|
184
|
+
progressbar.advance
|
|
185
|
+
|
|
186
|
+
if @skip != 0
|
|
187
|
+
next unless (idx % @skip) == 0
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
raise "Indirect CSRs not yet supported for CSR #{csr.name}" if csr.address.nil?
|
|
191
|
+
|
|
192
|
+
row = [
|
|
193
|
+
csr.name,
|
|
194
|
+
csr.address,
|
|
195
|
+
csr.long_name,
|
|
196
|
+
]
|
|
197
|
+
|
|
198
|
+
sorted_releases.each do |pr|
|
|
199
|
+
row.append(presence2char(pr.csr_presence(csr.name)))
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
table["rows"].append(row)
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
table
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
private
|
|
209
|
+
|
|
210
|
+
# return Nice list of profile release to use in a nice order
|
|
211
|
+
sig { returns(T::Array[Udb::ProfileRelease]) }
|
|
212
|
+
def sorted_profile_releases
|
|
213
|
+
# Get array of profile releases and sort by name
|
|
214
|
+
sorted = @arch.profile_releases.sort_by(&:name)
|
|
215
|
+
|
|
216
|
+
# Remove Mock profile release if present.
|
|
217
|
+
sorted.delete_if { |pr| pr.name == "Mock" }
|
|
218
|
+
|
|
219
|
+
# Move RVI20 to the beginning of the array if it exists.
|
|
220
|
+
if sorted.any? { |pr| pr.name == "RVI20" }
|
|
221
|
+
sorted.delete_if { |pr| pr.name == "RVI20" }
|
|
222
|
+
sorted.unshift(T.must(@arch.profile_release("RVI20")))
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
sorted
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# @param presence [String] Can be nil
|
|
229
|
+
# @return [String] m=mandatory, o=optional, n=not present
|
|
230
|
+
sig { params(presence: String).returns(String) }
|
|
231
|
+
def presence2char(presence)
|
|
232
|
+
if presence == "mandatory"
|
|
233
|
+
"m"
|
|
234
|
+
elsif presence == "optional"
|
|
235
|
+
"o"
|
|
236
|
+
elsif presence == "-"
|
|
237
|
+
"n"
|
|
238
|
+
else
|
|
239
|
+
raise ArgumentError, "Unknown presence of #{presence}"
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
end
|