Class: ArchDef

Inherits:
Object
  • Object
show all
Defined in:
lib/arch_def.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config_name, arch_def_path, overlay_path: nil) ⇒ ArchDef

Initialize a new configured architecture definition

Parameters:

  • config_name (#to_s)

    The name of a configuration, which must correspond to a folder under $root/cfgs



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/arch_def.rb', line 91

def initialize(config_name, arch_def_path, overlay_path: nil)
  @name = config_name.to_s.freeze
  @name_sym = @name.to_sym.freeze

  @idl_compiler = Idl::Compiler.new(self)

  validator = Validator.instance
  begin
    validator.validate_str(arch_def_path.read, type: :arch)
  rescue Validator::SchemaValidationError => e
    warn "While parsing unified architecture definition at #{arch_def_path}"
    raise e
  end

  @arch_def = YAML.load_file(arch_def_path, permitted_classes: [Date]).freeze
  @param_values = (@arch_def.key?("params") ? @arch_def["params"] : {}).freeze
  @mxlen = @arch_def.dig("params", "XLEN") # might be nil

  unless @mxlen.nil?
    # need at least XLEN specified to have a full architecture definition
    # to populate the symbol table.
    #
    # if this is the fully generic config ("_"), then you need to use
    # either symtab_32 or symtab_64
    @symtab = Idl::SymbolTable.new(self)
    custom_globals_path = overlay_path.nil? ? Pathname.new("/does/not/exist") : overlay_path / "isa" / "globals.isa"
    idl_path = File.exist?(custom_globals_path) ? custom_globals_path : $root / "arch" / "isa" / "globals.isa"
    @global_ast = @idl_compiler.compile_file(
      idl_path
    )
    @global_ast.add_global_symbols(@symtab)
    @symtab.deep_freeze
    @global_ast.freeze_tree(@symtab)
    @mxlen.freeze
  else
    # parse globals
    @global_ast = @idl_compiler.compile_file(
      $root / "arch" / "isa" / "globals.isa"
    )
    @global_ast.add_global_symbols(symtab_32)
    symtab_32.deep_freeze
    @global_ast.freeze_tree(symtab_32)

    # do it again for rv64, but we don't need the ast this time
    global_ast_64 = @idl_compiler.compile_file(
      $root / "arch" / "isa" / "globals.isa"
    )
    global_ast_64.add_global_symbols(symtab_64)
    symtab_64.deep_freeze
    global_ast_64.freeze_tree(symtab_64)
  end
end

Instance Attribute Details

#global_astIdl::IsaAst (readonly)

Returns Abstract syntax tree of global scope.

Returns:

  • (Idl::IsaAst)

    Abstract syntax tree of global scope



55
56
57
# File 'lib/arch_def.rb', line 55

def global_ast
  @global_ast
end

#idl_compilerIdl::Compiler (readonly)

Returns The IDL compiler.

Returns:

  • (Idl::Compiler)

    The IDL compiler



52
53
54
# File 'lib/arch_def.rb', line 52

def idl_compiler
  @idl_compiler
end

#mxlenInteger? (readonly)

Returns:

  • (Integer)

    32 or 64, the XLEN in M-mode

  • (nil)

    if the XLEN in M-mode is not configured



68
69
70
# File 'lib/arch_def.rb', line 68

def mxlen
  @mxlen
end

#nameString (readonly)

Returns Name of this definition. Special names are:

  • ‘_’ - The generic architecture, with no configuration settings.

  • ‘_32’ - A generic RV32 architecture, with only one parameter set (XLEN == 32)

  • ‘_64’ - A generic RV64 architecture, with only one parameter set (XLEN == 64).

Returns:

  • (String)

    Name of this definition. Special names are:

    • ‘_’ - The generic architecture, with no configuration settings.

    • ‘_32’ - A generic RV32 architecture, with only one parameter set (XLEN == 32)

    • ‘_64’ - A generic RV64 architecture, with only one parameter set (XLEN == 64)



61
62
63
# File 'lib/arch_def.rb', line 61

def name
  @name
end

#param_valuesHash<String, Object> (readonly)

Returns A hash mapping parameter name to value for any parameter that has been configured with a value. May be empty.

Returns:

  • (Hash<String, Object>)

    A hash mapping parameter name to value for any parameter that has been configured with a value. May be empty.



64
65
66
# File 'lib/arch_def.rb', line 64

def param_values
  @param_values
end

Instance Method Details

#all_known_csr_namesArray<String>

Returns List of all known CSRs, even those not implemented by this config.

Returns:

  • (Array<String>)

    List of all known CSRs, even those not implemented by this config



527
528
529
# File 'lib/arch_def.rb', line 527

def all_known_csr_names
  @arch_def["csrs"].map { |csr| csr[0] }
end

#cert_class(name) ⇒ CertClass?

Returns:

  • (CertClass)

    The certificate class named name

  • (nil)

    if the certificate class does not exist



741
# File 'lib/arch_def.rb', line 741

def cert_class(name) = cert_classes_hash[name]

#cert_classesObject



719
720
721
722
723
724
725
726
727
# File 'lib/arch_def.rb', line 719

def cert_classes
  return @cert_classes unless @cert_classes.nil?

  @cert_classes = []
  @arch_def["certificate_classes"].each do |cc_data|
    @cert_classes << CertClass.new(cc_data, self)
  end
  @cert_classes
end

#cert_classes_hashObject



729
730
731
732
733
734
735
736
737
# File 'lib/arch_def.rb', line 729

def cert_classes_hash
  return @cert_classes_hash unless @cert_classes_hash.nil?

  @cert_classes_hash = {}
  cert_classes.each do |cc|
    @cert_classes_hash[cc.name] = cc
  end
  @cert_classes_hash
end

#cert_model(name) ⇒ CertModel?

Returns:

  • (CertModel)

    The CertModel named name

  • (nil)

    if the CertModel does not exist



766
# File 'lib/arch_def.rb', line 766

def cert_model(name) = cert_models_hash[name]

#cert_modelsCertModel

Returns List of all defined certificate models across all certificate classes.

Returns:

  • (CertModel)

    List of all defined certificate models across all certificate classes



744
745
746
747
748
749
750
751
752
# File 'lib/arch_def.rb', line 744

def cert_models
  return @cert_models unless @cert_models.nil?

  @cert_models = []
  @arch_def["certificate_models"].each do |cm_data|
    @cert_models << CertModel.new(cm_data, self)
  end
  @cert_models
end

#cert_models_hashObject



754
755
756
757
758
759
760
761
762
# File 'lib/arch_def.rb', line 754

def cert_models_hash
  return @cert_models_hash unless @cert_models_hash.nil?

  @cert_models_hash = {}
  cert_models.each do |cert_model|
    @cert_models_hash[cert_model.name] = cert_model
  end
  @cert_models_hash
end

#configured?Boolean

Returns:

  • (Boolean)


84
# File 'lib/arch_def.rb', line 84

def configured? = @arch_def["type"] != "unconfigured"

#conflicting_ext?(ext_name) ⇒ Boolean

Returns whether or not ext_name is prohibited because it is excluded by an implemented extension.

Returns:

  • (Boolean)

    whether or not ext_name is prohibited because it is excluded by an implemented extension



488
489
490
# File 'lib/arch_def.rb', line 488

def conflicting_ext?(ext_name)
  prohibited_extensions.include? { |ext_req| ext_req.name == ext_name }
end

#conflicting_extensionsArray<ExtensionRequirement>

Returns Array of all extensions that are prohibited because they are excluded by an implemented extension.

Returns:

  • (Array<ExtensionRequirement>)

    Array of all extensions that are prohibited because they are excluded by an implemented extension



483
484
485
# File 'lib/arch_def.rb', line 483

def conflicting_extensions
  extensions.map(&:conflicts).flatten
end

#csr(csr_name) ⇒ Csr?

Returns a specific csr, or nil if it doesn’t exist.

Parameters:

  • csr_name (#to_s)

    CSR name

Returns:

  • (Csr, nil)

    a specific csr, or nil if it doesn’t exist



544
545
546
# File 'lib/arch_def.rb', line 544

def csr(csr_name)
  csr_hash[csr_name]
end

#csr_hashHash<String, Csr>

Returns All csrs, even unimplemented ones, indexed by CSR name.

Returns:

  • (Hash<String, Csr>)

    All csrs, even unimplemented ones, indexed by CSR name



532
533
534
535
536
537
538
539
540
# File 'lib/arch_def.rb', line 532

def csr_hash
  return @csr_hash unless @csr_hash.nil?

  @csr_hash = {}
  csrs.each do |csr|
    @csr_hash[csr.name] = csr
  end
  @csr_hash
end

#csrsArray<Csr>

Returns List of all CSRs defined by RISC-V, whether or not they are implemented.

Returns:

  • (Array<Csr>)

    List of all CSRs defined by RISC-V, whether or not they are implemented



517
518
519
520
521
522
523
# File 'lib/arch_def.rb', line 517

def csrs
  return @csrs unless @csrs.nil?

  @csrs = @arch_def["csrs"].map do |csr_data|
    Csr.new(csr_data)
  end
end

#dataHash

Returns The raw architecture defintion data structure.

Returns:

  • (Hash)

    The raw architecture defintion data structure



855
856
857
# File 'lib/arch_def.rb', line 855

def data
  @arch_def
end

#exception_codesArray<ExceptionCode>

Returns All exception codes defined by RISC-V.

Returns:

  • (Array<ExceptionCode>)

    All exception codes defined by RISC-V



769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
# File 'lib/arch_def.rb', line 769

def exception_codes
  return @exception_codes unless @exception_codes.nil?

  @exception_codes =
    extensions.reduce([]) do |list, ext_version|
      ecodes = extension(ext_version.name)["exception_codes"]
      next list if ecodes.nil?

      ecodes.each do |ecode|
        # double check that all the codes are unique
        raise "Duplicate exception code" if list.any? { |e| e.num == ecode["num"] || e.name == ecode["name"] || e.var == ecode["var"] }

        list << ExceptionCode.new(ecode["name"], ecode["var"], ecode["num"], self)
      end
      list
    end
end

#ext?(ext_name) ⇒ Boolean #ext?(ext_name, ext_version_requirements) ⇒ Boolean

Overloads:

  • #ext?(ext_name) ⇒ Boolean

    Returns True if the extension ‘name` is implemented.

    Parameters:

    • ext_name (#to_s)

      Extension name (case sensitive)

    Returns:

    • (Boolean)

      True if the extension ‘name` is implemented

  • #ext?(ext_name, ext_version_requirements) ⇒ Boolean

    Returns True if the extension ‘name` meeting `ext_version_requirements` is implemented.

    Examples:

    Checking extension presence with a version requirement

    arch_def.ext?(:S, ">= 1.12")

    Checking extension presence with multiple version requirements

    arch_def.ext?(:S, ">= 1.12", "< 1.15")

    Checking extension precsence with a precise version requirement

    arch_def.ext?(:S, 1.12)

    Parameters:

    • ext_name (#to_s)

      Extension name (case sensitive)

    • ext_version_requirements (Number, String, Array)

      Extension version requirements, taking the same inputs as Gem::Requirement

    Returns:

    • (Boolean)

      True if the extension ‘name` meeting `ext_version_requirements` is implemented

    See Also:



450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
# File 'lib/arch_def.rb', line 450

def ext?(ext_name, *ext_version_requirements)
  @ext_cache ||= {}
  cached_result = @ext_cache[[ext_name, ext_version_requirements]]
  return cached_result unless cached_result.nil?

  result =
    if fully_configured?
      implemented_extensions.any? do |e|
        if ext_version_requirements.empty?
          e.name == ext_name.to_s
        else
          requirement = Gem::Requirement.new(ext_version_requirements)
          (e.name == ext_name.to_s) && requirement.satisfied_by?(e.version)
        end
      end
    else
      raise "unexpected type" unless partially_configured?

      mandatory_extensions.any? do |e|
        if ext_version_requirements.empty?
          e.name == ext_name.to_s
        else
          requirement = Gem::Requirement.new(ext_version_requirements)
          e.satisfying_versions.all? do |ext_ver|
            (e.name == ext_name.to_s) && requirement.satisfied_by?(exrt_ver.version)
          end
        end
      end
    end
  @ext_cache[[ext_name, ext_version_requirements]] = result
end

#extension(name) ⇒ Extension?

Parameters:

  • name (#to_s)

    Extension name

Returns:

  • (Extension)

    Extension named ‘name`

  • (nil)

    if no extension ‘name` exists



432
433
434
# File 'lib/arch_def.rb', line 432

def extension(name)
  extension_hash[name.to_s]
end

#extension_hashHash<String, Extension>

Returns Hash of all extensions, even those that aren’t implemented, indexed by extension name.

Returns:

  • (Hash<String, Extension>)

    Hash of all extensions, even those that aren’t implemented, indexed by extension name



419
420
421
422
423
424
425
426
427
# File 'lib/arch_def.rb', line 419

def extension_hash
  return @extension_hash unless @extension_hash.nil?

  @extension_hash = {}
  extensions.each do |ext|
    @extension_hash[ext.name] = ext
  end
  @extension_hash
end

#extensionsArray<Extension>

Returns List of all extensions, even those that are’t implemented.

Returns:

  • (Array<Extension>)

    List of all extensions, even those that are’t implemented



356
357
358
359
360
361
362
363
364
# File 'lib/arch_def.rb', line 356

def extensions
  return @extensions unless @extensions.nil?

  @extensions = []
  @arch_def["extensions"].each do |ext_data|
    @extensions << Extension.new(ext_data, self)
  end
  @extensions
end

given an adoc string, find names of CSR/Instruction/Extension enclosed in ‘monospace` and replace them with links to the relevant object page

Parameters:

  • adoc (String)

    Asciidoc source

Returns:

  • (String)

    Asciidoc source, with link placeholders



996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
# File 'lib/arch_def.rb', line 996

def find_replace_links(adoc)
  adoc.gsub(/`([\w.]+)`/) do |match|
    name = Regexp.last_match(1)
    csr_name, field_name = name.split(".")
    csr = csr(csr_name)
    if !field_name.nil? && !csr.nil? && csr.field?(field_name)
      "%%LINK%csr_field;#{csr_name}.#{field_name};#{csr_name}.#{field_name}%%"
    elsif !csr.nil?
      "%%LINK%csr;#{csr_name};#{csr_name}%%"
    elsif inst(name)
      "%%LINK%inst;#{name};#{name}%%"
    elsif extension(name)
      "%%LINK%ext;#{name};#{name}%%"
    else
      match
    end
  end
end

#fully_configured?Boolean

Returns:

  • (Boolean)


81
# File 'lib/arch_def.rb', line 81

def fully_configured? = @arch_def["type"] == "fully configured"

#function(name) ⇒ Idl::FunctionBodyAst?

Parameters:

  • name (String)

    A function name

Returns:

  • (Idl::FunctionBodyAst)

    A function named name

  • (nil)

    if no function named name is found



599
600
601
# File 'lib/arch_def.rb', line 599

def function(name)
  function_hash[name]
end

#function_hashHash<String,FunctionBodyAst>

Returns Function hash of name => FunctionBodyAst.

Returns:

  • (Hash<String,FunctionBodyAst>)

    Function hash of name => FunctionBodyAst



585
586
587
588
589
590
591
592
593
594
# File 'lib/arch_def.rb', line 585

def function_hash
  return @function_hash unless @function_hash.nil?

  @function_hash = {}
  functions.each do |func|
    @function_hash[func.name] = func
  end

  @function_hash
end

#functionsArray<Idl::FunctionBodyAst>

Returns List of all functions defined by the architecture.

Returns:

  • (Array<Idl::FunctionBodyAst>)

    List of all functions defined by the architecture



578
579
580
581
582
# File 'lib/arch_def.rb', line 578

def functions
  return @functions unless @functions.nil?

  @functions = @global_ast.functions
end

#hashObject

hash for Hash lookup



71
# File 'lib/arch_def.rb', line 71

def hash = @name_sym.hash

#implemented_csr(csr_name) ⇒ Csr?

Returns a specific csr, or nil if it doesn’t exist or isn’t implemented.

Parameters:

  • csr_name (#to_s)

    CSR name

Returns:

  • (Csr, nil)

    a specific csr, or nil if it doesn’t exist or isn’t implemented



935
936
937
# File 'lib/arch_def.rb', line 935

def implemented_csr(csr_name)
  implemented_csr_hash[csr_name]
end

#implemented_csr_hashHash<String, Csr>

Returns Implemented csrs, indexed by CSR name.

Returns:

  • (Hash<String, Csr>)

    Implemented csrs, indexed by CSR name



923
924
925
926
927
928
929
930
931
# File 'lib/arch_def.rb', line 923

def implemented_csr_hash
  return @implemented_csr_hash unless @implemented_csr_hash.nil?

  @implemented_csr_hash = {}
  implemented_csrs.each do |csr|
    @implemented_csr_hash[csr.name] = csr
  end
  @implemented_csr_hash
end

#implemented_csrsArray<Csr>

Returns List of all implemented CSRs.

Returns:

  • (Array<Csr>)

    List of all implemented CSRs



911
912
913
914
915
916
917
918
919
920
# File 'lib/arch_def.rb', line 911

def implemented_csrs
  return @implemented_csrs unless @implemented_csrs.nil?

  @implemented_csrs =
    if @arch_def.key?("implemented_csrs")
      csrs.select { |c| @arch_def["implemented_csrs"].include?(c.name) }
    else
      []
    end
end

#implemented_exception_codesArray<ExceptionCode>

Returns All exception codes known to be implemented.

Returns:

  • (Array<ExceptionCode>)

    All exception codes known to be implemented



788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
# File 'lib/arch_def.rb', line 788

def implemented_exception_codes
  return @implemented_exception_codes unless @implemented_exception_codes.nil?

  @implemented_exception_codes =
    implemented_extensions.reduce([]) do |list, ext_version|
      ecodes = extension(ext_version.name)["exception_codes"]
      next list if ecodes.nil?

      ecodes.each do |ecode|
        # double check that all the codes are unique
        raise "Duplicate exception code" if list.any? { |e| e.num == ecode["num"] || e.name == ecode["name"] || e.var == ecode["var"] }

        unless ecode.dig("when", "version").nil?
          # check version
          next unless ext?(ext_version.name.to_sym, ecode["when"]["version"])
        end
        list << ExceptionCode.new(ecode["name"], ecode["var"], ecode["num"], self)
      end
      list
    end
end

#implemented_extensionsArray<ExtensionVersion>

may be overridden by subclass

Returns:

  • (Array<ExtensionVersion>)

    List of all extensions known to be implemented in this architecture



368
369
370
371
372
373
374
375
376
377
378
379
380
# File 'lib/arch_def.rb', line 368

def implemented_extensions
  raise "implemented_extensions is only valid for a fully configured defintion" unless fully_configured?

  return @implemented_extensions unless @implemented_extensions.nil?

  @implemented_extensions = []
  if @arch_def.key?("implemented_extensions")
    @arch_def["implemented_extensions"].each do |e|
      @implemented_extensions << ExtensionVersion.new(e["name"], e["version"], self)
    end
  end
  @implemented_extensions
end

#implemented_functionsArray<FuncDefAst>

Returns List of all reachable IDL functions for the config.

Returns:

  • (Array<FuncDefAst>)

    List of all reachable IDL functions for the config



955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
# File 'lib/arch_def.rb', line 955

def implemented_functions
  return @implemented_functions unless @implemented_functions.nil?

  @implemented_functions = []

  puts "  Finding all reachable functions from instruction operations"

  implemented_instructions.each do |inst|
    @implemented_functions <<
      if inst.base.nil?
        if multi_xlen?
          (inst.reachable_functions(symtab, 32) +
           inst.reachable_functions(symtab, 64))
        else
          inst.reachable_functions(symtab, mxlen)
        end
      else
        inst.reachable_functions(symtab, inst.base)
      end
  end
  raise "?" unless @implemented_functions.is_a?(Array)
  @implemented_functions = @implemented_functions.flatten
  @implemented_functions.uniq!(&:name)

  puts "  Finding all reachable functions from CSR operations"

  implemented_csrs.each do |csr|
    csr_funcs = csr.reachable_functions(self)
    csr_funcs.each do |f|
      @implemented_functions << f unless @implemented_functions.any? { |i| i.name == f.name }
    end
  end

  @implemented_functions
end

#implemented_instructionsArray<Instruction>

Returns List of all implemented instructions.

Returns:

  • (Array<Instruction>)

    List of all implemented instructions



940
941
942
943
944
945
946
947
948
949
950
951
# File 'lib/arch_def.rb', line 940

def implemented_instructions
  return @implemented_instructions unless @implemented_instructions.nil?

  @implemented_instructions =
    if @arch_def.key?("implemented_instructions")
      @arch_def["implemented_instructions"].map do |inst_name|
        instruction_hash[inst_name]
      end
    else
      []
    end
end

#implemented_interrupt_codesArray<InteruptCode>

Returns All interrupt codes known to be implemented.

Returns:

  • (Array<InteruptCode>)

    All interrupt codes known to be implemented



832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
# File 'lib/arch_def.rb', line 832

def implemented_interrupt_codes
  return @implemented_interrupt_codes unless @implemented_interrupt_codes.nil?

  @implemented_interupt_codes =
    implemented_extensions.reduce([]) do |list, ext_version|
      icodes = extension(ext_version.name)["interrupt_codes"]
      next list if icodes.nil?

      icodes.each do |icode|
        # double check that all the codes are unique
        raise "Duplicate interrupt code" if list.any? { |i| i.num == icode["num"] || i.name == icode["name"] || i.var == icode["var"] }

        unless ecode.dig("when", "version").nil?
          # check version
          next unless ext?(ext_version.name.to_sym, ecode["when"]["version"])
        end
        list << InterruptCode.new(icode["name"], icode["var"], icode["num"], self)
      end
      list
    end
end

#inspectString

Returns a string representation of the object, suitable for debugging.

Returns:

  • (String)

    A string representation of the object.



353
# File 'lib/arch_def.rb', line 353

def inspect = "ArchDef##{name}"

#inst(inst_name) ⇒ Instruction? Also known as: instruction

Returns An instruction named ‘inst_name’, or nil if it doesn’t exist.

Parameters:

  • inst_name (#to_s)

    Instruction name

Returns:

  • (Instruction, nil)

    An instruction named ‘inst_name’, or nil if it doesn’t exist



572
573
574
# File 'lib/arch_def.rb', line 572

def inst(inst_name)
  instruction_hash[inst_name.to_s]
end

#instruction_hashHash<String, Instruction>

Returns All instructions, indexed by name.

Returns:

  • (Hash<String, Instruction>)

    All instructions, indexed by name



560
561
562
563
564
565
566
567
568
# File 'lib/arch_def.rb', line 560

def instruction_hash
  return @instruction_hash unless @instruction_hash.nil?

  @instruction_hash = {}
  instructions.each do |inst|
    @instruction_hash[inst.name] = inst
  end
  @instruction_hash
end

#instructionsArray<Instruction>

Returns List of all instructions, whether or not they are implemented.

Returns:

  • (Array<Instruction>)

    List of all instructions, whether or not they are implemented



549
550
551
552
553
554
555
556
557
# File 'lib/arch_def.rb', line 549

def instructions
  return @instructions unless @instructions.nil?

  @instructions = @arch_def["instructions"].map do |inst_data|
    Instruction.new(inst_data, self)
  end

  @instructions
end

#interrupt_codesArray<InteruptCode>

Returns All interrupt codes defined by extensions.

Returns:

  • (Array<InteruptCode>)

    All interrupt codes defined by extensions



811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
# File 'lib/arch_def.rb', line 811

def interrupt_codes
  return @interrupt_codes unless @interrupt_codes.nil?

  @interupt_codes =
    extensions.reduce([]) do |list, ext_version|
      icodes = extension(ext_version.name)["interrupt_codes"]
      next list if icodes.nil?

      icodes.each do |icode|
        # double check that all the codes are unique
        if list.any? { |i| i.num == icode["num"] || i.name == icode["name"] || i.var == icode["var"] }
          raise "Duplicate interrupt code"
        end

        list << InterruptCode.new(icode["name"], icode["var"], icode["num"], self)
      end
      list
    end
end

#mandatory_extensionsArray<ExtensionRequirement>

Returns List of extensions that are explicitly required by an arch def.

Returns:



383
384
385
386
387
388
389
390
391
392
393
394
395
# File 'lib/arch_def.rb', line 383

def mandatory_extensions
  raise "mandatory_extensions is only valid for a partially configured defintion" unless partially_configured?

  return @mandatory_extensions unless @mandatory_extensions.nil?

  @mandatory_extensions = []
  if @arch_def.key?("mandatory_extensions")
    @arch_def["mandatory_extensions"].each do |e|
      @mandatory_extensions << ExtensionRequirement.new(e["name"], e["version"], presence: "mandatory")
    end
  end
  @mandatory_extensions
end

#manual(name) ⇒ Manual?

Returns A manual named name, or nil if it doesn’t exist.

Returns:

  • (Manual, nil)

    A manual named name, or nil if it doesn’t exist



626
# File 'lib/arch_def.rb', line 626

def manual(name) = manuals_hash[name]

#manualsArray<Manual>

Returns List of all manuals defined by the architecture.

Returns:

  • (Array<Manual>)

    List of all manuals defined by the architecture



604
605
606
607
608
609
610
611
612
# File 'lib/arch_def.rb', line 604

def manuals
  return @manuals unless @manuals.nil?

  @manuals = []
  @arch_def["manuals"].each_value do |manual_data|
    @manuals << Manual.new(manual_data, self)
  end
  @manuals
end

#manuals_hashHash<String, Manual>

Returns All manuals, indexed by name.

Returns:

  • (Hash<String, Manual>)

    All manuals, indexed by name



615
616
617
618
619
620
621
622
623
# File 'lib/arch_def.rb', line 615

def manuals_hash
  return @manuals_hash unless @manuals_hash.nil?

  @manuals_hash = {}
  manuals.each do |manual|
    @manuals_hash[manual.name] = manual
  end
  @manuals_hash
end

#multi_xlen?Boolean

Returns whether or not it may be possible to switch XLEN given this definition.

There are three cases when this will return true:

1. A mode (e.g., U) is known to be implemented, and the CSR bit that controls XLEN in that mode is known to be writeable.
2. A mode is known to be implemented, but the writability of the CSR bit that controls XLEN in that mode is not known.
3. It is not known if the mode is implemented.

Returns:

  • (Boolean)

    true if this configuration might execute in multiple xlen environments (e.g., that in some mode the effective xlen can be either 32 or 64, depending on CSR values)



220
221
222
223
224
# File 'lib/arch_def.rb', line 220

def multi_xlen?
  return true if @mxlen.nil?

  ["S", "U", "VS", "VU"].any? { |mode| multi_xlen_in_mode?(mode) }
end

#multi_xlen_in_mode?(mode) ⇒ Boolean

Returns whether or not it may be possible to switch XLEN in mode given this definition.

There are three cases when this will return true:

1. +mode+ (e.g., U) is known to be implemented, and the CSR bit that controls XLEN in +mode+ is known to be writeable.
2. +mode+ is known to be implemented, but the writability of the CSR bit that controls XLEN in +mode+ is not known.
3. It is not known if +mode+ is implemented.

Will return false if mode is not possible (e.g., because U is a prohibited extension)

Parameters:

  • mode (String)

    mode to check. One of “M”, “S”, “U”, “VS”, “VU”

Returns:

  • (Boolean)

    true if this configuration might execute in multiple xlen environments in mode (e.g., that in some mode the effective xlen can be either 32 or 64, depending on CSR values)



238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
# File 'lib/arch_def.rb', line 238

def multi_xlen_in_mode?(mode)
  return false if mxlen == 32

  case mode
  when "M"
    mxlen.nil?
  when "S"
    return true if unconfigured?

    if fully_configured?
      ext?(:S) && (@param_values["SXLEN"] == 3264)
    elsif partially_configured?
      return false if prohibited_ext?(:S)

      return true unless ext?(:S) # if S is not known to be implemented, we can't say anything about it

      return true unless @param_values.key?("SXLEN")

      @param_values["SXLEN"] == 3264
    else
      raise "Unexpected configuration state"
    end
  when "U"
    return false if prohibited_ext?(:U)

    return true if unconfigured?

    if fully_configured?
      ext?(:U) && (@param_values["UXLEN"] == 3264)
    elsif partially_configured?
      return true unless ext?(:U) # if U is not known to be implemented, we can't say anything about it

      return true unless @param_values.key?("UXLEN")

      @param_values["UXLEN"] == 3264
    else
      raise "Unexpected configuration state"
    end
  when "VS"
    return false if prohibited_ext?(:H)

    return true if unconfigured?

    if fully_configured?
      ext?(:H) && (@param_values["VSXLEN"] == 3264)
    elsif partially_configured?
      return true unless ext?(:H) # if H is not known to be implemented, we can't say anything about it

      return true unless @param_values.key?("VSXLEN")

      @param_values["VSXLEN"] == 3264
    else
      raise "Unexpected configuration state"
    end
  when "VU"
    return false if prohibited_ext?(:H)

    return true if unconfigured?

    if fully_configured?
      ext?(:H) && (@param_values["VUXLEN"] == 3264)
    elsif partially_configured?
      return true unless ext?(:H) # if H is not known to be implemented, we can't say anything about it

      return true unless @param_values.key?("VUXLEN")

      @param_values["VUXLEN"] == 3264
    else
      raise "Unexpected configuration state"
    end
  else
    raise ArgumentError, "Bad mode"
  end
end

#param(name) ⇒ ExtensionParameter?

Returns:

  • (ExtensionParameter)

    Parameter named name

  • (nil)

    if there is no parameter named name



512
513
514
# File 'lib/arch_def.rb', line 512

def param(name)
  params_hash[name]
end

#paramsArray<ExtensionParameter>

Returns Alphabetical list of all parameters defined in the architecture.

Returns:

  • (Array<ExtensionParameter>)

    Alphabetical list of all parameters defined in the architecture



493
494
495
496
497
# File 'lib/arch_def.rb', line 493

def params
  return @params unless @params.nil?

  @params = extensions.map(&:params).flatten.uniq(&:name).sort_by!(&:name)
end

#params_hashHash<String, ExtensionParameter>

Returns Hash of all extension parameters defined in the architecture.

Returns:

  • (Hash<String, ExtensionParameter>)

    Hash of all extension parameters defined in the architecture



500
501
502
503
504
505
506
507
508
# File 'lib/arch_def.rb', line 500

def params_hash
  return @params_hash unless @params_hash.nil?

  @params_hash = {}
  params.each do |param|
    @params_hash[param.name] = param
  end
  @param_hash
end

#params_with_valueArray<ExtensionParameterWithValue>

Returns List of all available parameters with known values for the config.

Returns:



317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
# File 'lib/arch_def.rb', line 317

def params_with_value
  return @params_with_value unless @params_with_value.nil?

  @params_with_value = []
  extensions.each do |ext_version|
    ext = extension(ext_version.name)
    ext.params.each do |ext_param|
      if param_values.key?(ext_param.name)
        @params_with_value << ExtensionParameterWithValue.new(
          ext_param,
          param_values[ext_param.name]
        )
      end
    end
  end
  @params_with_value
end

#params_without_valueArray<ExtensionParameter>

Returns List of all available parameters without known values for the config.

Returns:

  • (Array<ExtensionParameter>)

    List of all available parameters without known values for the config



336
337
338
339
340
341
342
343
344
345
346
347
348
349
# File 'lib/arch_def.rb', line 336

def params_without_value
  return @params_without_value unless @params_without_value.nil?

  @params_without_value = []
  extensions.each do |ext_version|
    ext = extension(ext_version.name)
    ext.params.each do |ext_param|
      unless param_values.key?(ext_param.name)
        @params_without_value << ext_param
      end
    end
  end
  @params_without_value
end

#partially_configured?Boolean

Returns:

  • (Boolean)


82
# File 'lib/arch_def.rb', line 82

def partially_configured? = @arch_def["type"] == "partially configured"

#possible_xlensArray<Integer>

Returns List of possible XLENs in any mode for this config.

Returns:

  • (Array<Integer>)

    List of possible XLENs in any mode for this config



314
# File 'lib/arch_def.rb', line 314

def possible_xlens = multi_xlen? ? [32, 64] : [mxlen]

#profile(name) ⇒ Profile?

Returns:

  • (Profile)

    The profile named name

  • (nil)

    if the profile does not exist



717
# File 'lib/arch_def.rb', line 717

def profile(name) = profiles_hash[name]

#profile_class(profile_class_name) ⇒ ProfileClass?

Returns:

  • (ProfileClass)

    The profile class named name

  • (nil)

    if the profile class does not exist



652
# File 'lib/arch_def.rb', line 652

def profile_class(profile_class_name) = profile_classes_hash[profile_class_name]

#profile_classesArray<ProfileClass>

Returns All known profile classes (e.g. RVA).

Returns:

  • (Array<ProfileClass>)

    All known profile classes (e.g. RVA)



629
630
631
632
633
634
635
636
637
# File 'lib/arch_def.rb', line 629

def profile_classes
  return @profile_classes unless @profile_classes.nil?

  @profile_classes = []
  @arch_def["profile_classes"].each_value do |pc_data|
    @profile_classes << ProfileClass.new(pc_data, self)
  end
  @profile_classes
end

#profile_classes_hashHash<String, ProfileClass>

Returns Profile classes, indexed by profile class name.

Returns:

  • (Hash<String, ProfileClass>)

    Profile classes, indexed by profile class name



640
641
642
643
644
645
646
647
648
# File 'lib/arch_def.rb', line 640

def profile_classes_hash
  return @profile_classes_hash unless @profile_classes_hash.nil?

  @profile_classes_hash = {}
  profile_classes.each do |pc|
    @profile_classes_hash[pc.name] = pc
  end
  @profile_classes_hash
end

#profile_release(profile_release_name) ⇒ ProfileRelease?

Returns:

  • (ProfileRelease)

    The profile release named profile_release_name

  • (nil)

    if the profile release does not exist



683
# File 'lib/arch_def.rb', line 683

def profile_release(profile_release_name) = profile_releases_hash[profile_release_name]

#profile_releasesProfileRelease

Returns List of all profile releases (e.g. RVA20, RVA22) for all profile classes.

Returns:

  • (ProfileRelease)

    List of all profile releases (e.g. RVA20, RVA22) for all profile classes.



655
656
657
658
659
660
661
662
663
664
665
666
667
668
# File 'lib/arch_def.rb', line 655

def profile_releases
  return @profile_releases unless @profile_releases.nil?

  @profile_releases = []
  @arch_def["profile_releases"].each_value do |pr_data|
    raise ArgumentError, "Expecting pr_data to be a hash" unless pr_data.is_a?(Hash)

    profile_release = ProfileRelease.new(pr_data, self)
    raise ArgumentError, "ProfileRelease constructor returned nil" if profile_release.nil?

    @profile_releases << profile_release
  end
  @profile_releases
end

#profile_releases_hashHash<String, ProfileRelease>

Returns , indexed by profile release name.

Returns:

  • (Hash<String, ProfileRelease>)

    , indexed by profile release name



671
672
673
674
675
676
677
678
679
# File 'lib/arch_def.rb', line 671

def profile_releases_hash
  return @profile_releases_hash unless @profile_releases_hash.nil?

  @profile_releases_hash = {}
  profile_releases.each do |profile_release|
    @profile_releases_hash[profile_release.name] = profile_release
  end
  @profile_releases_hash
end

#profilesProfile

Returns List of all defined profiles in all releases in all classes.

Returns:

  • (Profile)

    List of all defined profiles in all releases in all classes



686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
# File 'lib/arch_def.rb', line 686

def profiles
  return @profiles unless @profiles.nil?

  @profiles = []
  @arch_def["profile_releases"].each_value do |pr_data|
    raise ArgumentError, "Expecting pr_data to be a hash" unless pr_data.is_a?(Hash)

    pr_data["profiles"].each do |profile_name, profile_data|
      profile_data["name"] = profile_name
      profile = Profile.new(profile_data, self)
      raise ArgumentError, "Profile constructor returned nil" if profile.nil?

      @profiles << profile
    end
  end
  @profiles
end

#profiles_hashHash<String, Profile>

Returns Profiles, indexed by profile name.

Returns:

  • (Hash<String, Profile>)

    Profiles, indexed by profile name



705
706
707
708
709
710
711
712
713
# File 'lib/arch_def.rb', line 705

def profiles_hash
  return @profiles_hash unless @profiles_hash.nil?

  @profiles_hash = {}
  profiles.each do |profile|
    @profiles_hash[profile.name] = profile
  end
  @profiles_hash
end

#prohibited_ext?(ext_name) ⇒ Boolean

Returns:

  • (Boolean)


414
415
416
# File 'lib/arch_def.rb', line 414

def prohibited_ext?(ext_name)
  prohibited_extensions.any? { |ext_req| ext_req.name == ext_name.to_s }
end

#prohibited_extensionsArray<ExtensionRequirement>

Returns List of extensions that are explicitly prohibited by an arch def.

Returns:

  • (Array<ExtensionRequirement>)

    List of extensions that are explicitly prohibited by an arch def



398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
# File 'lib/arch_def.rb', line 398

def prohibited_extensions
  return @prohibited_extensions unless @prohibited_extensions.nil?

  @prohibited_extensions = []
  if @arch_def.key?("prohibited_extensions")
    @arch_def["prohibited_extensions"].each do |e|
      if e.is_a?(String)
        @prohibited_extensions << ExtensionRequirement.new(e, nil)
      else
        @prohibited_extensions << ExtensionRequirement.new(e["name"], e["requirements"], presence: "prohibited")
      end
    end
  end
  @prohibited_extensions
end

#ref(uri) ⇒ Object

given a ‘$ref` target, return the Ruby object

Returns:

  • (Object)

    The pointed-to object

Raises:

  • (ArgumentError)


863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
# File 'lib/arch_def.rb', line 863

def ref(uri)
  raise ArgumentError, "JSON Reference must contain one '#'" unless uri.count("#") == 1

  file_path, obj_path = uri.split("#")
  obj =
    case file_path
    when /^certificate_class.*/
      cert_class_name = File.basename(file_path, ".yaml")
      cert_class(cert_class_name)
    when /^certificate_model.*/
      cert_mode_name = File.basename(file_path, ".yaml")
      cert_model(cert_model_name)
    when /^csr.*/
      csr_name = File.basename(file_path, ".yaml")
      csr(csr_name)
    when /^ext.*/
      ext_name = File.basename(file_path, ".yaml")
      extension(ext_name)
    when /^inst.*/
      inst_name = File.basename(file_path, ".yaml")
      instruction(inst_name)
    when /^manual.*/
      manual_name = File.basename(file_path, ".yaml")
      manual(manual_name)
    when /^profile_class.*/
      profile_class_name = File.basename(file_path, ".yaml")
      profile_class(profile_class_name)
    when /^profile_release.*/
      profile_release_name = File.basename(file_path, ".yaml")
      profile_release(profile_release_name)
    else
      raise "Unhandled ref object: #{file_path}"
    end

    if obj_path.nil?
      obj
    else
      parts = obj_path.split("/")
      parts.each do |part|
        raise "Error in $ref. There is no method '#{part}' for a #{obj.class.name}" unless obj.respond_to?(part.to_sym)

        obj = obj.send(part)
      end
      obj
    end
end

#render_erb(erb_template, what = '') ⇒ String

passes erb_template through ERB within the content of this config

Parameters:

  • erb_template (String)

    ERB source

Returns:

  • (String)

    The rendered text



1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
# File 'lib/arch_def.rb', line 1115

def render_erb(erb_template, what='')
  t = Tempfile.new("template")
  t.write erb_template
  t.flush
  begin
    Tilt["erb"].new(t.path, trim: "-").render(erb_env)
  rescue
    warn "While rendering ERB template: #{what}"
    raise
  ensure
    t.close
    t.unlink
  end
end

#symtabIdl::SymbolTable?

Returns:

  • (Idl::SymbolTable)

    Symbol table with global scope

  • (nil)

    if the architecture is not configured (use symtab_32 or symtab_64)

Raises:

  • (NotImplementedError)


75
76
77
78
79
# File 'lib/arch_def.rb', line 75

def symtab
  raise NotImplementedError, "Un-configured ArchDefs have no symbol table" if @symtab.nil?

  @symtab
end

#typeObject



85
# File 'lib/arch_def.rb', line 85

def type = @arch_def["type"]

#type_check(show_progress: true, io: $stdout) ⇒ void

This method returns an undefined value.

type check all IDL, including globals, instruction ops, and CSR functions

Parameters:

  • show_progress (Boolean) (defaults to: true)

    whether to show progress bars

  • io (IO) (defaults to: $stdout)

    where to write progress bars



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/arch_def.rb', line 149

def type_check(show_progress: true, io: $stdout)
  io.puts "Type checking IDL code for #{name}..."
  progressbar =
    if show_progress
      ProgressBar.create(title: "Instructions", total: instructions.size)
    end

  instructions.each do |inst|
    progressbar.increment if show_progress
    if @mxlen == 32
      inst.type_checked_operation_ast(@idl_compiler, @symtab, 32) if inst.rv32?
    elsif @mxlen == 64
      inst.type_checked_operation_ast(@idl_compiler, @symtab, 64) if inst.rv64?
      inst.type_checked_operation_ast(@idl_compiler, @symtab, 32) if possible_xlens.include?(32) && inst.rv32?
    end
  end

  progressbar =
    if show_progress
      ProgressBar.create(title: "CSRs", total: csrs.size)
    end

  csrs.each do |csr|
    progressbar.increment if show_progress
    if csr.has_custom_sw_read?
      if (possible_xlens.include?(32) && csr.defined_in_base32?) || (possible_xlens.include?(64) && csr.defined_in_base64?)
        csr.type_checked_sw_read_ast(@symtab)
      end
    end
    csr.fields.each do |field|
      unless field.type_ast(@symtab).nil?
        if ((possible_xlens.include?(32) && csr.defined_in_base32? && field.defined_in_base32?) ||
            (possible_xlens.include?(64) && csr.defined_in_base64? && field.defined_in_base64?))
          field.type_checked_type_ast(@symtab)
        end
      end
      unless field.reset_value_ast(@symtab).nil?
        if ((possible_xlens.include?(32) && csr.defined_in_base32? && field.defined_in_base32?) ||
            (possible_xlens.include?(64) && csr.defined_in_base64? && field.defined_in_base64?))
          field.type_checked_reset_value_ast(@symtab) if csr.defined_in_base32? && field.defined_in_base32?
        end
      end
      unless field.sw_write_ast(@symtab).nil?
        field.type_checked_sw_write_ast(@symtab, 32) if possible_xlens.include?(32) && csr.defined_in_base32? && field.defined_in_base32?
        field.type_checked_sw_write_ast(@symtab, 64) if possible_xlens.include?(64) &&  csr.defined_in_base64? && field.defined_in_base64?
      end
    end
  end

  progressbar =
    if show_progress
      ProgressBar.create(title: "Functions", total: functions.size)
    end
  functions.each do |func|
    progressbar.increment if show_progress
    func.type_check(@symtab)
  end

  puts "done" if show_progress
end

#unconfigured?Boolean

Returns:

  • (Boolean)


83
# File 'lib/arch_def.rb', line 83

def unconfigured? = @arch_def["type"] == "unconfigured"

#unconfigured_dataHash

create a new raw unconfigured architecture defintion data structure

The data will not include anything configuration-dependent such as implemented_/mandatory_/etc.

This function can be used to create a new arch_def for a different configuration

Returns:

  • (Hash)

    A unconfigured architecture definition



1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
# File 'lib/arch_def.rb', line 1097

def unconfigured_data
  {
    "type" => "partially configured",
    "instructions" => instructions.map(&:data),
    "extensions" => extensions.map.map(&:data),
    "csrs" => csrs.map(&:data),
    "profile_classes" => profile_classes.map { |f| [f.name, f.data] }.to_h,
    "profile_releases" => profile_releases.map { |p| [p.name, p.data] }.to_h,
    "manuals" => manuals.map { |m| [m.name, m.data] }.to_h,
    "certificate_classes" => cert_classes.map(&:data),
    "certificate_models" => cert_models.map(&:data)
  }
end