Skip to content

Commit ce98d6d

Browse files
authored
Add $mref to inst variables (#228)
* Add $mref to inst variables Also enhances arch_gen to expand references. Supports $ref (JSON Reference) and $mref (merged ref, doesn't ignore other keys in the object) Difference: (in something.yaml) key: ref_extra: Hello! obj: $ref: path/to/something.yaml#/key extra: Hi! => obj = { ref_extra: "Hello!" } obj: $mref: path/to/something.yaml#/key extra: Hi! => obj = { extra: "Hi!", ref_extra: "Hello!" } * Adjust ArchGen to account for json references * bug fix * Add YamlLoader test, support for multiple
1 parent c79a3a5 commit ce98d6d

File tree

10 files changed

+453
-140
lines changed

10 files changed

+453
-140
lines changed

Rakefile

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,20 @@ namespace :serve do
5555
end
5656
end
5757

58-
Minitest::TestTask.create :idl_test do |t|
58+
desc "Run the IDL compiler test suite"
59+
task :idl_test do
60+
t = Minitest::TestTask.new(:lib_test)
5961
t.test_globs = ["#{$root}/lib/idl/tests/test_*.rb"]
62+
t.process_env
63+
ruby t.make_test_cmd
64+
end
65+
66+
desc "Run the Ruby library test suite"
67+
task :lib_test do
68+
t = Minitest::TestTask.new(:lib_test)
69+
t.test_globs = ["#{$root}/lib/test/test_*.rb"]
70+
t.process_env
71+
ruby t.make_test_cmd
6072
end
6173

6274
desc "Clean up all generated files"
@@ -269,6 +281,7 @@ desc <<~DESC
269281
DESC
270282
task :regress do
271283
Rake::Task["idl_test"].invoke
284+
Rake::Task["lib_test"].invoke
272285
Rake::Task["validate"].invoke
273286
ENV["MANUAL_NAME"] = "isa"
274287
ENV["VERSIONS"] = "all"
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# yaml-language-server: $schema=../../schemas/inst_variable_metadatas.json
2+
---
3+
4+
itype_imm:
5+
location: 31-20

arch/inst/I/addi.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ addi:
99
match: -----------------000-----0010011
1010
variables:
1111
- name: imm
12-
location: 31-20
12+
$mref: ../../common/inst_variable_types.yaml#/itype_imm
1313
- name: rs1
1414
location: 19-15
1515
- name: rd

backends/arch_gen/lib/arch_gen.rb

Lines changed: 27 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
require "rake/application"
77
require "rubygems/requirement"
88
require "tilt"
9-
require "yaml"
109

1110
require_relative "#{$lib}/validate"
1211
require_relative "#{$lib}/arch_def"
@@ -53,7 +52,7 @@ def gen_params_schema
5352
@implemented_extensions.each do |ext|
5453
ext_name = ext["name"]
5554
gen_ext_path = @gen_dir / "arch" / "ext" / "#{ext_name}.yaml"
56-
ext_yaml = YAML.safe_load gen_ext_path.read
55+
ext_yaml = YAML.load_file gen_ext_path.to_s
5756
unless ext_yaml[ext_name]["params"].nil?
5857
ext_yaml[ext_name]["params"].each do |param_name, param_data|
5958
schema["properties"]["params"]["required"] << param_name
@@ -92,7 +91,7 @@ def initialize(config_name)
9291
raise "Validation failed" if @cfg_impl_ext.nil?
9392

9493
cfg_opts_path = @cfg_dir / "cfg.yaml"
95-
@cfg_opts = YAML.load_file(cfg_opts_path)
94+
@cfg_opts = YamlLoader.load(cfg_opts_path)
9695
raise "Validation failed" if @cfg_opts.nil?
9796
raise "Validation failed: bad type" unless ["partially configured", "fully configured"].include?(@cfg_opts["type"])
9897

@@ -147,7 +146,7 @@ def params_extra_validation
147146
@implemented_extensions.each do |ext|
148147
ext_name = ext["name"]
149148
gen_ext_path = @gen_dir / "arch" / "ext" / "#{ext_name}.yaml"
150-
ext_yaml = YAML.safe_load gen_ext_path.read
149+
ext_yaml = YAML.load_file gen_ext_path.to_s
151150
unless ext_yaml[ext_name]["params"].nil?
152151
ext_yaml[ext_name]["params"].each do |param_name, param_data|
153152
next unless param_data.key?("extra_validation")
@@ -275,63 +274,63 @@ def implemented_extensions
275274
#
276275
def gen_arch_def
277276
csr_hash = Dir.glob(@gen_dir / "arch" / "csr" / "**" / "*.yaml").map do |f|
278-
csr_obj = YAML.load_file(f)
277+
csr_obj = YamlLoader.load(f)
279278
csr_name = csr_obj.keys[0]
280279
[csr_name, csr_obj[csr_name]]
281280
end.to_h
282281
inst_hash = Dir.glob(@gen_dir / "arch" / "inst" / "**" / "*.yaml").map do |f|
283-
inst_obj = YAML.load_file(f)
282+
inst_obj = YamlLoader.load(f)
284283
inst_name = inst_obj.keys[0]
285284
[inst_name, inst_obj[inst_name]]
286285
end.to_h
287286
ext_hash = Dir.glob(@gen_dir / "arch" / "ext" / "**" / "*.yaml").map do |f|
288-
ext_obj = YAML.load_file(f)
287+
ext_obj = YamlLoader.load(f)
289288
ext_name = ext_obj.keys[0]
290289
[ext_name, ext_obj[ext_name]]
291290
end.to_h
292291
profile_family_hash = Dir.glob($root / "arch" / "profile_family" / "**" / "*.yaml").map do |f|
293-
profile_obj = YAML.load_file(f)
292+
profile_obj = YamlLoader.load(f)
294293
profile_name = profile_obj.keys[0]
295294
profile_obj[profile_name]["name"] = profile_name
296295
profile_obj[profile_name]["__source"] = f
297296
[profile_name, profile_obj[profile_name]]
298297
end.to_h
299298
profile_hash = Dir.glob($root / "arch" / "profile" / "**" / "*.yaml").map do |f|
300-
profile_obj = YAML.load_file(f)
299+
profile_obj = YamlLoader.load(f)
301300
profile_name = profile_obj.keys[0]
302301
profile_obj[profile_name]["name"] = profile_name
303302
profile_obj[profile_name]["__source"] = f
304303
[profile_name, profile_obj[profile_name]]
305304
end.to_h
306305
manual_hash = {}
307306
Dir.glob($root / "arch" / "manual" / "**" / "contents.yaml").map do |f|
308-
manual_version = YAML.load_file(f)
307+
manual_version = YamlLoader.load(f)
309308
manual_id = manual_version["manual"]
310309
unless manual_hash.key?(manual_id)
311310
manual_info_files = Dir.glob($root / "arch" / "manual" / "**" / "#{manual_id}.yaml")
312311
raise "Could not find manual info '#{manual_id}'.yaml, needed by #{f}" if manual_info_files.empty?
313312
raise "Found multiple manual infos '#{manual_id}'.yaml, needed by #{f}" if manual_info_files.size > 1
314313

315314
manual_info_file = manual_info_files.first
316-
manual_hash[manual_id] = YAML.load_file(manual_info_file)
315+
manual_hash[manual_id] = YamlLoader.load(manual_info_file)
317316
manual_hash[manual_id]["__source"] = manual_info_file
318317
# TODO: schema validation
319318
end
320319

321320
manual_hash[manual_id]["versions"] ||= []
322-
manual_hash[manual_id]["versions"] << YAML.load_file(f)
321+
manual_hash[manual_id]["versions"] << YamlLoader.load(f)
323322
# TODO: schema validation
324323
manual_hash[manual_id]["versions"].last["__source"] = f
325324
end
326325
crd_family_hash = Dir.glob($root / "arch" / "crd_family" / "**" / "*.yaml").map do |f|
327-
family_obj = YAML.load_file(f, permitted_classes: [Date])
326+
family_obj = YamlLoader.load(f, permitted_classes: [Date])
328327
family_name = family_obj.keys[0]
329328
family_obj[family_name]["name"] = family_name
330329
family_obj[family_name]["__source"] = f
331330
[family_name, family_obj[family_name]]
332331
end.to_h
333332
crd_hash = Dir.glob($root / "arch" / "crd" / "**" / "*.yaml").map do |f|
334-
crd_obj = YAML.load_file(f, permitted_classes: [Date])
333+
crd_obj = YamlLoader.load(f, permitted_classes: [Date])
335334
crd_name = crd_obj.keys[0]
336335
crd_obj[crd_name]["name"] = crd_name
337336
crd_obj[crd_name]["__source"] = f
@@ -546,99 +545,6 @@ def arch_overlay_path_for(type, name)
546545
def schema_path_for(type) = Validator::SCHEMA_PATHS[type]
547546
private :schema_path_for
548547

549-
# Render a architecture definition file and save it to gen_dir / .rendered_arch
550-
#
551-
# Will not re-render if rendered file already exists and sources have not changed
552-
#
553-
# @param type [Symbol] Type of the object (@see Validator::SCHEMA_PATHS)
554-
# @param name [#to_s] Name of the object
555-
# @param extra_env [Hash,NilObject] Optional hash with extra enviornment variables for the render
556-
# @return [Pathname,nil] Path to generated file, or nil if there is no (valid) definition for type,name
557-
def gen_rendered_arch_def(type, name, extra_env = {})
558-
gen_path = @gen_dir / ".rendered_arch" / type.to_s / "#{name}.yaml"
559-
560-
source_path = arch_path_for(type, name)
561-
return nil if source_path.nil?
562-
563-
schema_path = schema_path_for(type)
564-
565-
if gen_path.exist?
566-
# this already exists...see if we need to regenerate it
567-
dep_mtime = [File.mtime(__FILE__), source_path.mtime, schema_path.mtime].max
568-
return gen_path if gen_path.mtime >= dep_mtime # no update needed
569-
end
570-
571-
trace "Rendering architecture file for #{type}:#{name}"
572-
573-
# render the source template
574-
current_env = env.clone
575-
extra_env&.each { |k, v| current_env.define_singleton_method(k) { v } }
576-
rendered_def = Tilt["erb"].new(source_path, trim: "-").render(current_env)
577-
578-
# see if the rendering was empty, meaning that the def isn't valid in this config
579-
return nil if rendered_def.nil?
580-
581-
# write the object
582-
FileUtils.mkdir_p gen_path.dirname
583-
File.write(gen_path, rendered_def)
584-
585-
# verify
586-
begin
587-
@validator.validate_str(rendered_def, type:)
588-
rescue Validator::SchemaValidationError => e
589-
warn "#{type} definition in #{source_path} did not validate"
590-
raise e
591-
end
592-
593-
def_obj = YAML.safe_load(rendered_def)
594-
595-
raise "#{type} name ('#{name}') must match key in defintion ('#{def_obj.keys[0]}')" if name.to_s != def_obj.keys[0]
596-
597-
# return path to generated file
598-
gen_path
599-
end
600-
private :gen_rendered_arch_def
601-
602-
# Render a architecture overlay definition file and save it to gen_dir / .rendered_overlay_arch
603-
#
604-
# Will not re-render if rendered file already exists and sources have not changed
605-
#
606-
# @param type [Symbol] Type of the object (@see Validator::SCHEMA_PATHS)
607-
# @param name [#to_s] Name of the object
608-
# @param extra_env [Hash,NilObject] Optional hash with extra enviornment variables for the render
609-
# @return [Pathname] Path to generated file
610-
def gen_rendered_arch_overlay_def(type, name, extra_env = {})
611-
gen_path = @gen_dir / ".rendered_overlay_arch" / type.to_s / "#{name}.yaml"
612-
613-
source_path = arch_overlay_path_for(type, name)
614-
return nil if source_path.nil?
615-
616-
if gen_path.exist?
617-
# this already exists...see if we need to regenerate it
618-
dep_mtime = [File.mtime(__FILE__), source_path.mtime].max
619-
return gen_path if gen_path.mtime >= dep_mtime # no update needed
620-
end
621-
622-
trace "Rendering overlay file for #{type}:#{name}"
623-
624-
# render the source template
625-
current_env = env.clone
626-
extra_env&.each { |k, v| current_env.define_singleton_method(k) { v } }
627-
rendered_def = Tilt["erb"].new(source_path, trim: "-").render(current_env)
628-
629-
def_obj = YAML.safe_load(rendered_def)
630-
631-
raise "#{type} name (#{name}) must match key in defintion (#{def_obj.keys[0]})" if name.to_s != def_obj.keys[0]
632-
633-
# write the object
634-
FileUtils.mkdir_p gen_path.dirname
635-
File.write(gen_path, YAML.dump(def_obj))
636-
637-
# return path to generated file
638-
gen_path
639-
end
640-
private :gen_rendered_arch_overlay_def
641-
642548
# generate a merged definition from rendered arch and overlay, and write it to gen / .merged_arch
643549
#
644550
# Skips if gen file already exists and sources are older
@@ -666,14 +572,16 @@ def gen_merged_def(type, arch_path, overlay_path)
666572
FileUtils.mkdir_p merged_path.dirname
667573
if overlay_path.nil?
668574
# no overlay, just copy arch
669-
FileUtils.cp arch_path, merged_path
575+
merged_path.write YAML.dump(YamlLoader.load(arch_path))
576+
# FileUtils.cp arch_path, merged_path
670577
elsif arch_path.nil?
671578
# no arch, overlay is arch
672-
FileUtils.cp overlay_path, merged_path
579+
merged_path.write YAML.dump(YamlLoader.load(overlay_path))
580+
# FileUtils.cp overlay_path, merged_path
673581
else
674582
# arch and overlay, do the merge
675-
arch_obj = YAML.load_file(arch_path)
676-
overlay_obj = YAML.load_file(overlay_path)
583+
arch_obj = YamlLoader.load(arch_path)
584+
overlay_obj = YamlLoader.load(overlay_path)
677585

678586
merge(arch_obj, overlay_obj)
679587
merged_path.write YAML.dump(arch_obj)
@@ -696,8 +604,8 @@ def gen_merged_def(type, arch_path, overlay_path)
696604
# @param csr_name [#to_s] CSR name
697605
# @param extra_env [Hash] Extra enviornment variables to be used when parsing the CSR definition template
698606
def maybe_add_csr(csr_name, extra_env = {})
699-
arch_path = arch_path_for(:csr, csr_name) # gen_rendered_arch_def(:csr, csr_name, extra_env)
700-
arch_overlay_path = arch_overlay_path_for(:csr, csr_name) # gen_rendered_arch_overlay_def(:csr, csr_name, extra_env)
607+
arch_path = arch_path_for(:csr, csr_name)
608+
arch_overlay_path = arch_overlay_path_for(:csr, csr_name)
701609

702610
# return immediately if this CSR isn't defined in this config
703611
raise "No arch or overlay for sr #{csr_name}" if arch_path.nil? && arch_overlay_path.nil?
@@ -797,8 +705,8 @@ def all_known_exts
797705
end
798706

799707
def maybe_add_ext(ext_name)
800-
arch_path = arch_path_for(:ext, ext_name) # gen_rendered_arch_def(:ext, ext_name)
801-
arch_overlay_path = arch_overlay_path_for(:ext, ext_name) # gen_rendered_arch_overlay_def(:ext, ext_name)
708+
arch_path = arch_path_for(:ext, ext_name)
709+
arch_overlay_path = arch_overlay_path_for(:ext, ext_name)
802710

803711
# return immediately if this ext isn't defined
804712
return if arch_path.nil? && arch_overlay_path.nil?
@@ -884,7 +792,7 @@ def exception_codes
884792

885793
@exception_codes = {}
886794
Dir.glob(@gen_dir / "arch" / "ext" / "*.yaml") do |ext_path|
887-
ext_obj = YAML.load_file(ext_path)
795+
ext_obj = YamlLoader.load(ext_path)
888796
ext_obj = ext_obj[ext_obj.keys[0]]
889797
if ext_obj.key?("exception_codes")
890798
ext_obj["exception_codes"].each do |exception_code|
@@ -905,7 +813,7 @@ def interrupt_codes
905813

906814
@interrupt_codes = {}
907815
Dir.glob(@gen_dir / "arch" / "ext" / "*.yaml") do |ext_path|
908-
ext_obj = YAML.load_file(ext_path)
816+
ext_obj = YamlLoader.load(ext_path)
909817
ext_obj = ext_obj[ext_obj.keys[0]]
910818
if ext_obj.key?("interrupt_codes")
911819
ext_obj["interrupt_codes"].each do |interrupt_code|
@@ -941,8 +849,8 @@ def possible_xlens
941849
# @param inst_name [#to_s] instruction name
942850
# @param extra_env [Hash] Extra options to add into the rendering enviornment
943851
def maybe_add_inst(inst_name, extra_env = {})
944-
arch_path = arch_path_for(:inst, inst_name) # gen_rendered_arch_def(:inst, inst_name, extra_env)
945-
arch_overlay_path = arch_overlay_path_for(:inst, inst_name) # gen_rendered_arch_overlay_def(:inst, inst_name, extra_env)
852+
arch_path = arch_path_for(:inst, inst_name)
853+
arch_overlay_path = arch_overlay_path_for(:inst, inst_name)
946854

947855
# return immediately if inst isn't defined in this config
948856
raise "No arch or overlay for instruction #{inst_name}" if arch_path.nil? && arch_overlay_path.nil?

0 commit comments

Comments
 (0)