Skip to content

Commit 55134c0

Browse files
authored
Merge pull request #140 from riscv-software-src/crd_arch_def
2 parents 2fa5eba + 0b5eed2 commit 55134c0

File tree

12 files changed

+228
-110
lines changed

12 files changed

+228
-110
lines changed

backends/arch_gen/lib/arch_gen.rb

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -716,11 +716,18 @@ def maybe_add_csr(csr_name, extra_env = {})
716716
end
717717

718718
csr_obj = Csr.new(csr_data[csr_name])
719+
arch_def_mock = Object.new
720+
arch_def_mock.define_singleton_method(:fully_configured?) { true }
721+
pos_xlen_local = possible_xlens
722+
arch_def_mock.define_singleton_method(:possible_xlens) do
723+
pos_xlen_local
724+
end
725+
impl_ext = @cfg_impl_ext.map { |e| ExtensionVersion.new(e[0], e[1]) }
726+
arch_def_mock.define_singleton_method(:implemented_extensions) do
727+
impl_ext
728+
end
719729
belongs =
720-
csr_obj.exists_in_cfg?(
721-
possible_xlens,
722-
@cfg_impl_ext.map { |e| ExtensionVersion.new(e[0], e[1]) }
723-
)
730+
csr_obj.exists_in_cfg?(arch_def_mock)
724731

725732
@implemented_csrs ||= []
726733
@implemented_csrs << csr_name if belongs
@@ -967,11 +974,15 @@ def maybe_add_inst(inst_name, extra_env = {})
967974
possible_xlens << 64 if [64, 3264].include?(params["VSXLEN"])
968975
possible_xlens << 64 if [64, 3264].include?(params["VUXLEN"])
969976
end
977+
arch_def_mock = Object.new
978+
arch_def_mock.define_singleton_method(:fully_configured?) { true }
979+
arch_def_mock.define_singleton_method(:possible_xlens) { possible_xlens }
980+
impl_ext = @cfg_impl_ext.map { |e| ExtensionVersion.new(e[0], e[1]) }
981+
arch_def_mock.define_singleton_method(:implemented_extensions) do
982+
impl_ext
983+
end
970984
belongs =
971-
inst_obj.exists_in_cfg?(
972-
possible_xlens.uniq,
973-
@cfg_impl_ext.map { |e| ExtensionVersion.new(e[0], e[1]) }
974-
)
985+
inst_obj.exists_in_cfg?(arch_def_mock)
975986

976987
@implemented_instructions ||= []
977988
@implemented_instructions << inst_name if belongs

backends/crd_doc/tasks.rake

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ Dir.glob("#{$root}/arch/crd/*.yaml") do |f|
2929
crd = arch_def.crd(crd_name)
3030
raise "No CRD defined for #{crd_name}" if crd.nil?
3131

32+
# switch to the generated CRD arch def
33+
arch_def = crd.to_arch_def
34+
crd = arch_def.crd(crd_name)
35+
3236
version = File.basename(t.name, '.adoc').split('-')[1..].join('-')
3337

3438
erb = ERB.new(File.read("#{CRD_DOC_DIR}/templates/crd.adoc.erb"), trim_mode: "-")

backends/crd_doc/templates/crd.adoc.erb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,7 @@ h| Privilege Mode | <%= csr.priv_mode %>
519519
.<%= csr.name %> format
520520
[wavedrom, ,svg,subs='attributes',width="100%"]
521521
....
522-
<%= JSON.dump csr.wavedrom_desc(crd.arch_def, csr.base.nil? ? 32 : csr.base) %>
522+
<%= JSON.dump csr.wavedrom_desc(crd.arch_def, csr.base.nil? ? 32 : csr.base, optional_type: 3) %>
523523
....
524524
<% else -%>
525525
<%# CSR has a dynamic length, or a field has a dynamic location,
@@ -529,13 +529,13 @@ This CSR format changes dynamically with XLEN.
529529
.<%= csr.name %> Format when <%= csr.length_cond32 %>
530530
[wavedrom, ,svg,subs='attributes',width="100%"]
531531
....
532-
<%= JSON.dump csr.wavedrom_desc(crd.arch_def, 32) %>
532+
<%= JSON.dump csr.wavedrom_desc(crd.arch_def, 32, optional_type: 3) %>
533533
....
534534

535535
.<%= csr.name %> Format when <%= csr.length_cond64 %>
536536
[wavedrom, ,svg,subs='attributes',width="100%"]
537537
....
538-
<%= JSON.dump csr.wavedrom_desc(crd.arch_def, 64) %>
538+
<%= JSON.dump csr.wavedrom_desc(crd.arch_def, 64, optional_type: 3) %>
539539
....
540540

541541

backends/manual/templates/ext.adoc.erb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
== Versions
66

77
<%- ext.versions.each do |v| -%>
8-
<%- implemented = arch_def.implemented_extensions.include?(ExtensionVersion.new(ext.name, v["version"])) -%>
98
<%= v["version"] %>::
109
State:::
1110
<%= v["state"] %>

lib/arch_def.rb

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,8 @@ def extensions
341341
# may be overridden by subclass
342342
# @return [Array<ExtensionVersion>] List of all extensions known to be implemented in this architecture
343343
def implemented_extensions
344+
raise "implemented_extensions is only valid for a fully configured defintion" unless fully_configured?
345+
344346
return @implemented_extensions unless @implemented_extensions.nil?
345347

346348
@implemented_extensions = []
@@ -352,6 +354,21 @@ def implemented_extensions
352354
@implemented_extensions
353355
end
354356

357+
# @return [Array<ExtensionRequirement>] List of extensions that are explicitly required by an arch def
358+
def mandatory_extensions
359+
raise "mandatory_extensions is only valid for a partially configured defintion" unless partially_configured?
360+
361+
return @mandatory_extensions unless @mandatory_extensions.nil?
362+
363+
@mandatory_extensions = []
364+
if @arch_def.key?("mandatory_extensions")
365+
@arch_def["mandatory_extensions"].each do |e|
366+
@mandatory_extensions << ExtensionRequirement.new(e["name"], e["version"])
367+
end
368+
end
369+
@mandatory_extensions
370+
end
371+
355372
# @return [Array<ExtensionRequirement>] List of extensions that are explicitly prohibited by an arch def
356373
def prohibited_extensions
357374
return @prohibited_extensions unless @prohibited_extensions.nil?
@@ -411,12 +428,27 @@ def ext?(ext_name, *ext_version_requirements)
411428
return cached_result unless cached_result.nil?
412429

413430
result =
414-
implemented_extensions.any? do |e|
415-
if ext_version_requirements.empty?
416-
e.name == ext_name.to_s
417-
else
418-
requirement = Gem::Requirement.new(ext_version_requirements)
419-
(e.name == ext_name.to_s) && requirement.satisfied_by?(e.version)
431+
if fully_configured?
432+
implemented_extensions.any? do |e|
433+
if ext_version_requirements.empty?
434+
e.name == ext_name.to_s
435+
else
436+
requirement = Gem::Requirement.new(ext_version_requirements)
437+
(e.name == ext_name.to_s) && requirement.satisfied_by?(e.version)
438+
end
439+
end
440+
else
441+
raise "unexpected type" unless partially_configured?
442+
443+
mandatory_extensions.any? do |e|
444+
if ext_version_requirements.empty?
445+
e.name == ext_name.to_s
446+
else
447+
requirement = Gem::Requirement.new(ext_version_requirements)
448+
e.satisfying_versions.all? do |ext_ver|
449+
(e.name == ext_name.to_s) && requirement.satisfied_by?(exrt_ver.version)
450+
end
451+
end
420452
end
421453
end
422454
@ext_cache[[ext_name, ext_version_requirements]] = result
@@ -935,6 +967,27 @@ def implemented_interrupt_codes
935967
end
936968
private :erb_env
937969

970+
# create a new raw *unconfigured* architecture defintion data structure
971+
#
972+
# The data will not include anything configuration-dependent such as implemented_*/mandatory_*/etc.
973+
#
974+
# This function can be used to create a new arch_def for a different configuration
975+
#
976+
# @return [Hash] A unconfigured architecture definition
977+
def unconfigured_data
978+
{
979+
"type" => "partially configured",
980+
"instructions" => instructions.map { |i| [i.name, i.data] }.to_h,
981+
"extensions" => extensions.map.map { |e| [e.name, e.data] }.to_h,
982+
"csrs" => csrs.map { |c| [c.name, c.data] }.to_h,
983+
"profile_families" => profile_families.map { |f| [f.name, f.data] }.to_h,
984+
"profiles" => profiles.map { |p| [p.name, p.data] }.to_h,
985+
"manuals" => manuals.map { |m| [m.name, m.data] }.to_h,
986+
"crd_families" => crd_families.map { |f| [f.name, f.data] }.to_h,
987+
"crds" => crds.map { |c| [c.name, c.data] }.to_h
988+
}
989+
end
990+
938991
# passes _erb_template_ through ERB within the content of this config
939992
#
940993
# @param erb_template [String] ERB source

lib/arch_obj_models/crd.rb

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ def in_scope_ext_params(ext_req)
305305
ext_param_db.defined_in_extension_version?(ver["version"])
306306
end
307307

308-
ext_params <<
308+
ext_params <<
309309
InScopeExtensionParameter.new(ext_param_db, param_data["schema"], param_data["note"])
310310
end
311311

@@ -479,4 +479,25 @@ def requirement_groups
479479
@requirement_groups
480480
end
481481

482+
# @return [ArchDef] A partially-configued architecture definition corresponding to this CRD
483+
def to_arch_def
484+
return @generated_arch_def unless @generated_arch_def.nil?
485+
486+
arch_def_data = arch_def.unconfigured_data
487+
488+
arch_def_data["mandatory_extensions"] = in_scope_ext_reqs("mandatory").map do |ext_req|
489+
{
490+
"name" => ext_req.name,
491+
"version" => ext_req.version_requirement.requirements.map { |r| "#{r[0]} #{r[1]}" }
492+
}
493+
end
494+
arch_def_data["params"] = all_in_scope_ext_params.select(&:single_value?).map { |p| [p.name, p.value] }.to_h
495+
496+
file = Tempfile.new("archdef")
497+
file.write(YAML.safe_dump(arch_def_data, permitted_classes: [Date]))
498+
file.flush
499+
file.close
500+
@generated_arch_def = ArchDef.new(name, Pathname.new(file.path))
501+
end
502+
482503
end

lib/arch_obj_models/csr.rb

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ def implemented_fields(arch_def)
352352
end
353353

354354
@implemented_fields = fields.select do |f|
355-
f.exists_in_cfg?(implemented_bases, arch_def.implemented_extensions)
355+
f.exists_in_cfg?(arch_def)
356356
end
357357
end
358358

@@ -509,8 +509,10 @@ def pruned_sw_read_ast(arch_def)
509509
#
510510
# @param arch_def [ArchDef] A configuration
511511
# @param effective_xlen [Integer,nil] Effective XLEN to use when CSR length is dynamic
512+
# @param exclude_unimplemented [Boolean] If true, do not create include unimplemented fields in the figure
513+
# @param optional_type [Integer] Wavedrom type (Fill color) for fields that are optional (not mandatory) in a partially-specified arch_def
512514
# @return [Hash] A representation of the WaveDrom drawing for the CSR (should be turned into JSON for wavedrom)
513-
def wavedrom_desc(arch_def, effective_xlen, exclude_unimplemented: false)
515+
def wavedrom_desc(arch_def, effective_xlen, exclude_unimplemented: false, optional_type: 2)
514516
desc = {
515517
"reg" => []
516518
}
@@ -533,7 +535,11 @@ def wavedrom_desc(arch_def, effective_xlen, exclude_unimplemented: false)
533535

534536
desc["reg"] << { "bits" => n, type: 1 }
535537
end
536-
desc["reg"] << { "bits" => field.location(arch_def, effective_xlen).size, "name" => field.name, type: 2 }
538+
if arch_def.partially_configured? && field.optional_in_cfg?(arch_def)
539+
desc["reg"] << { "bits" => field.location(arch_def, effective_xlen).size, "name" => field.name, type: optional_type }
540+
else
541+
desc["reg"] << { "bits" => field.location(arch_def, effective_xlen).size, "name" => field.name, type: 2 }
542+
end
537543
last_idx = field.location(arch_def, effective_xlen).max
538544
end
539545
if !field_list.empty? && (field_list.last.location(arch_def, effective_xlen).max != (length(arch_def, effective_xlen) - 1))
@@ -546,11 +552,26 @@ def wavedrom_desc(arch_def, effective_xlen, exclude_unimplemented: false)
546552
desc
547553
end
548554

549-
# @param possible_xlens [Array<Integer>] List of xlens that be used in any implemented mode
550-
# @param extensions [Array<ExtensionVersion>] List of extensions implemented
551-
# @return [Boolean] whether or not the instruction is implemented given the supplies config options
552-
def exists_in_cfg?(possible_xlens, extensions)
553-
(@data["base"].nil? || (possible_xlens.include? @data["base"])) &&
554-
extensions.any? { |e| defined_by?(e) }
555+
# @param arch_def [ArchDef] Architecture def
556+
# @return [Boolean] whether or not the CSR is possibly implemented given the supplies config options
557+
def exists_in_cfg?(arch_def)
558+
if arch_def.fully_configured?
559+
(@data["base"].nil? || (arch_def.possible_xlens.include? @data["base"])) &&
560+
arch_def.implemented_extensions.any? { |e| defined_by?(e) }
561+
else
562+
(@data["base"].nil? || (arch_def.possible_xlens.include? @data["base"])) &&
563+
arch_def.prohibited_extensions.none? { |e| defined_by?(e) }
564+
end
565+
end
566+
567+
# @param arch_def [ArchDef] Architecture def
568+
# @return [Boolean] whether or not the CSR is optional in the config
569+
def optional_in_cfg?(arch_def)
570+
raise "optional_in_cfg? should only be used by a partially-specified arch def" unless arch_def.partially_configured?
571+
572+
exists_in_cfg?(arch_def) &&
573+
arch_def.mandatory_extensions.none? do |ext_req|
574+
ext_req.satisfying_versions(arch_def).none? { |ext_ver| defined_by?(ext_ver) }
575+
end
555576
end
556577
end

lib/arch_obj_models/csr_field.rb

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,31 @@ def initialize(parent_csr, field_data)
3131
# @param possible_xlens [Array<Integer>] List of xlens that be used in any implemented mode
3232
# @param extensions [Array<ExtensionVersion>] List of extensions implemented
3333
# @return [Boolean] whether or not the instruction is implemented given the supplies config options
34-
def exists_in_cfg?(possible_xlens, extensions)
35-
parent.exists_in_cfg?(possible_xlens, extensions) &&
36-
(@data["base"].nil? || possible_xlens.include?(@data["base"])) &&
37-
(@data["definedBy"].nil? || extensions.any? { |e| defined_by?(e) } )
34+
def exists_in_cfg?(arch_def)
35+
if arch_def.fully_configured?
36+
parent.exists_in_cfg?(arch_def) &&
37+
(@data["base"].nil? || arch_def.possible_xlens.include?(@data["base"])) &&
38+
(@data["definedBy"].nil? || arch_def.implemented_extensions.any? { |ext_ver| defined_by?(ext_ver) })
39+
else
40+
raise "unexpected type" unless arch_def.partially_configured?
41+
42+
parent.exists_in_cfg?(arch_def) &&
43+
(@data["base"].nil? || arch_def.possible_xlens.include?(@data["base"])) &&
44+
(@data["definedBy"].nil? || arch_def.prohibited_extensions.none? { |ext_ver| defined_by?(ext_ver) })
45+
end
46+
end
47+
48+
# @return [Boolean] For a partially configured arch_def, whether or not the field is optional (not mandatory or prohibited)
49+
def optional_in_cfg?(arch_def)
50+
raise "optional_in_cfg? should only be called on a partially configured arch_def" unless arch_def.partially_configured?
51+
52+
exists_in_cfg?(arch_def) &&
53+
(
54+
parent.optional_in_cfg?(arch_def) ||
55+
(data["definedBy"].nil? || arch_def.mandatory_extensions.none? do |ext_req|
56+
ext_req.satisfying_versions(arch_def).none? { |ext_ver| defined_by?(ext_ver) }
57+
end)
58+
)
3859
end
3960

4061
# @return [Idl::FunctionBodyAst] Abstract syntax tree of the type() function

0 commit comments

Comments
 (0)