Class: Udb::Instruction

Inherits:
TopLevelDatabaseObject show all
Includes:
Helpers::WavedromUtil, CertifiableObject
Defined in:
lib/udb/obj/instruction.rb

Overview

model of a specific instruction in a specific base (RV32/RV64)

Defined Under Namespace

Classes: DecodeVariable, Encoding, EncodingField, Opcode

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

This class inherits a constructor from Udb::TopLevelDatabaseObject

Class Method Details

.ary_from_location(location_str_or_int) ⇒ Object



248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'lib/udb/obj/instruction.rb', line 248

def self.ary_from_location(location_str_or_int)
  return [location_str_or_int] if location_str_or_int.is_a?(Integer)

  bits = []
  parts = location_str_or_int.split("|")
  parts.each do |part|
    if part.include?("-")
      msb, lsb = part.split("-").map(&:to_i)
      (lsb..msb).each { |i| bits << i }
    else
      bits << part.to_i
    end
  end
  bits
end

.deprecated_validate_encoding(encoding, inst_name) ⇒ Object



285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
# File 'lib/udb/obj/instruction.rb', line 285

def self.deprecated_validate_encoding(encoding, inst_name)
  match = encoding["match"]
  raise "No match for instruction #{inst_name}?" if match.nil?

  variables = encoding.key?("variables") ? encoding["variables"] : []
  match.size.times do |i|
    if match[match.size - 1 - i] == "-"
      # make sure exactly one variable covers this bit
      vars_match = variables.count { |variable| ary_from_location(variable["location"]).include?(i) }
      if vars_match.zero?
        raise ValidationError, "In instruction #{inst_name}, no variable or encoding bit covers bit #{i}"
      elsif vars_match != 1
        raise ValidationError, "In instruction, #{inst_name}, bit #{i} is covered by more than one variable"
      end
    else
      # make sure no variable covers this bit
      unless variables.nil?
        unless variables.none? { |variable| ary_from_location(variable["location"]).include?(i) }
          raise ValidationError, "In instruction, #{inst_name}, bit #{i} is covered by both a variable and the match string"
        end
      end
    end
  end
end

.validate_encoding(inst, base)

This method returns an undefined value.

Parameters:



265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
# File 'lib/udb/obj/instruction.rb', line 265

def self.validate_encoding(inst, base)
  # make sure there is no overlap between variables/opcodes
  (inst.opcodes(base) + inst.decode_variables(base)).combination(2) do |field1, field2|
    raise "In instruction #{inst.name}, #{field1.name} and #{field2.name} overlap" if field1.overlaps?(field2)
  end

  # makes sure every bit is accounted for
  inst.type(base).length.times do |i|
    covered =
      inst.opcodes(base).any? { |opcode| opcode.range.cover?(i) } || \
      inst.decode_variables(base).any? { |var| var.location_bits.include?(i) }
    raise "In instruction #{inst.name}, there is no opcode or variable at bit #{i}" unless covered
  end

  # make sure opcode values fit
  inst.opcodes(base).each do |opcode|
    raise "In instruction #{inst.name}, opcode #{opcode.name}, value #{opcode.value} does not fit in #{opcode.range}" unless T.must(opcode.range.size) >= opcode.value.bit_length
  end
end

Instance Method Details

#<=>(other) ⇒ Object



359
360
361
362
363
364
365
# File 'lib/udb/obj/instruction.rb', line 359

def <=>(other)
  if other.is_a?(Instruction)
    name <=> other.name
  else
    raise ArgumentError, "Instruction is not comparable to a #{other.class.name}"
  end
end

#==(other) ⇒ Object Also known as: eql?



349
350
351
352
353
354
355
# File 'lib/udb/obj/instruction.rb', line 349

def ==(other)
  if other.is_a?(Instruction)
    name == other.name
  else
    raise ArgumentError, "Instruction is not comparable to a #{other.class.name}"
  end
end

#accessHash<String, String>

Returns Hash of access permissions for each mode. The key is the lowercase name of a privilege mode, and the value is one of [‘never’, ‘sometimes’, ‘always’].

Returns:

  • (Hash<String, String>)

    Hash of access permissions for each mode. The key is the lowercase name of a privilege mode, and the value is one of [‘never’, ‘sometimes’, ‘always’]



368
369
370
# File 'lib/udb/obj/instruction.rb', line 368

def access
  @data["access"]
end

#access_detailString?

Returns:

  • (String)

    Details of the access restrictions

  • (nil)

    if no details are available



374
375
376
# File 'lib/udb/obj/instruction.rb', line 374

def access_detail
  @data["access_detail"]
end

#access_detail?Boolean

Returns true if the instruction has an ‘access_detail’ field.

Returns:

  • (Boolean)

    true if the instruction has an ‘access_detail’ field



1123
1124
1125
# File 'lib/udb/obj/instruction.rb', line 1123

def access_detail?
  @data.key?("access_detail")
end

#assemblyString

Returns Assembly format.

Returns:

  • (String)

    Assembly format



394
395
396
# File 'lib/udb/obj/instruction.rb', line 394

def assembly
  @data["assembly"]
end

#bad_encoding_conflict?(xlen, other_inst) ⇒ Boolean

Returns true if self and other_inst have indistinguishable encodings and can be simultaneously implemented in some design.

Returns:

  • (Boolean)

    true if self and other_inst have indistinguishable encodings and can be simultaneously implemented in some design



1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
# File 'lib/udb/obj/instruction.rb', line 1007

def bad_encoding_conflict?(xlen, other_inst)
  return false if !defined_in_base?(xlen) || !other_inst.defined_in_base?(xlen)
  return false unless encoding(xlen).indistinguishable?(other_inst.encoding(xlen))

  # ok, so they have the same encoding. can they be present at the same time?
  return false if !defined_by_condition.compatible?(other_inst.defined_by_condition)

  # is this a hint?
  !(hints.include?(other_inst) || other_inst.hints.include?(self))
end

#baseInteger?

Returns:

  • (Integer)

    XLEN that must be effective for instruction to exist

  • (nil)

    if instruction exists in all XLENs



380
381
382
# File 'lib/udb/obj/instruction.rb', line 380

def base
  @data["base"]
end

#cert_coverage_point(id) ⇒ CertNormativeRule? Originally defined in module CertifiableObject

Parameters:

  • id (String)

    Unique ID for the normative rule

Returns:

  • (CertNormativeRule)
  • (nil)

    if there is no certification normative ruleed with ID of id

#cert_coverage_point_hashHash<String, CertNormativeRule> Originally defined in module CertifiableObject

Returns Hash with ID as key of all normative rules defined by database object.

Returns:

  • (Hash<String, CertNormativeRule>)

    Hash with ID as key of all normative rules defined by database object

#cert_normative_rulesArray<CertNormativeRule> Originally defined in module CertifiableObject

Returns:

#cert_test_procedure(id) ⇒ CertTestProcedure? Originally defined in module CertifiableObject

Parameters:

  • id (String)

    Unique ID for test procedure

Returns:

  • (CertTestProcedure)
  • (nil)

    if there is no certification test procedure with ID id

#cert_test_procedure_hashHash<String, CertTestProcedure> Originally defined in module CertifiableObject

Returns Hash of all normative rules defined by database object.

Returns:

  • (Hash<String, CertTestProcedure>)

    Hash of all normative rules defined by database object

#cert_test_proceduresArray<CertTestProcedure> Originally defined in module CertifiableObject

Returns:

#conflicting_instructions(xlen) ⇒ Array<Instruction>

Returns List of instructions that reuse this instruction’s encoding, but can’t be present in the same system because their defining extensions conflict.

Returns:

  • (Array<Instruction>)

    List of instructions that reuse this instruction’s encoding, but can’t be present in the same system because their defining extensions conflict



1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
# File 'lib/udb/obj/instruction.rb', line 1021

def conflicting_instructions(xlen)
  raise "Bad xlen (#{xlen}) for instruction #{name}" unless defined_in_base?(xlen)

  @conflicting_instructions ||= {}
  return @conflicting_instructions[xlen] unless @conflicting_instructions[xlen].nil?

  @conflicting_instructions[xlen] = []

  @arch.instructions.each do |other_inst|
    next unless other_inst.defined_in_base?(xlen)
    next if other_inst == self

    next unless encoding(xlen).indistinguishable?(other_inst.encoding(xlen))

    # is this a hint?
    next if hints.include?(other_inst) || other_inst.hints.include?(self)

    if defined_by_condition.compatible?(other_inst.defined_by_condition)
      raise "bad encoding conflict found between #{name} and #{other_inst.name}"
    end

    @conflicting_instructions[xlen] << other_inst
  end
  @conflicting_instructions[xlen]
end

#data_independent_timing?Boolean

Returns Whether or not the instruction must have data-independent timing when Zkt is enabled.

Returns:

  • (Boolean)

    Whether or not the instruction must have data-independent timing when Zkt is enabled.



385
# File 'lib/udb/obj/instruction.rb', line 385

def data_independent_timing? = @data["data_independent_timing"]

#decode_variables(base) ⇒ Array<DecodeVariable>

Returns The decode variables.

Returns:



1118
1119
1120
# File 'lib/udb/obj/instruction.rb', line 1118

def decode_variables(base)
  encoding(base).decode_variables
end

#defined_in_base?(xlen) ⇒ Boolean

Returns whethen or not instruction is defined in base xlen.

Parameters:

  • xlen (Integer)

    32 or 64, the target xlen

Returns:

  • (Boolean)

    whethen or not instruction is defined in base xlen



389
390
391
# File 'lib/udb/obj/instruction.rb', line 389

def defined_in_base?(xlen)
  base.nil? || (base == xlen)
end

#encoding(base) ⇒ Encoding

Returns the encoding.

Parameters:

  • base (Integer)

    32 or 64

Returns:



1086
1087
1088
1089
1090
1091
1092
# File 'lib/udb/obj/instruction.rb', line 1086

def encoding(base)
  raise "#{name} is not defined in #{base}" unless defined_in_base?(base)

  load_encoding if @encodings.nil?

  @encodings[base]
end

#encoding_format(base) ⇒ String

Returns format, as a string of 0,1 and -,.

Examples:

Format of ‘sd`

sd.format #=> '-----------------011-----0100011'

Parameters:

  • base (Integer)

Returns:

  • (String)

    format, as a string of 0,1 and -,

Raises:

  • (ArgumentError)


214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# File 'lib/udb/obj/instruction.rb', line 214

def encoding_format(base)
  raise ArgumentError, "base must be 32 or 64" unless [32, 64].include?(base)

  if has_type?
    mask = "-" * type(base).length

    opcodes(base).each do |opcode|
      mask[type(base).length - opcode.range.end - 1, opcode.range.size] = opcode.value.to_s(2).rjust(T.must(opcode.range.size), "0")
    end

    mask
  else
    @encoding_format ||=
      if @data["encoding"].key?("RV32")
        {
          32 => @data["encoding"]["RV32"]["match"],
          64 => @data["encoding"]["RV64"]["match"]
        }
      else
        {
          32 => @data["encoding"]["match"],
          64 => @data["encoding"]["match"]
        }
      end
    @encoding_format[base]
  end
end

#encoding_widthInteger

Returns the width of the encoding.

Returns:

  • (Integer)

    the width of the encoding



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

def encoding_width
  if defined_in_base?(32) && defined_in_base?(64)
    raise "unexpected: encodings are different sizes" unless encoding(32).size == encoding(64).size

    encoding(64).size
  elsif defined_in_base?(32)
    encoding(32).size
  else
    raise "unexpected" unless defined_in_base?(64)

    encoding(64).size
  end

end

#exists_in_cfg?(cfg_arch) ⇒ Boolean

Returns whether or not the instruction is implemented given the supplied config options.

Parameters:

Returns:

  • (Boolean)

    whether or not the instruction is implemented given the supplied config options



1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
# File 'lib/udb/obj/instruction.rb', line 1162

def exists_in_cfg?(cfg_arch)
  if cfg_arch.fully_configured?
    (@data["base"].nil? || (cfg_arch.possible_xlens.include? @data["base"])) &&
      cfg_arch.implemented_extension_versions.any? { |ext_ver| defined_by_condition.possibly_satisfied_by?(ext_ver) }
  else
    raise "unexpected cfg_arch type" unless cfg_arch.partially_configured?

    (@data["base"].nil? || (cfg_arch.possible_xlens.include? @data["base"])) &&
      cfg_arch.prohibited_extension_versions.none? { |ext_ver| defined_by_condition.possibly_satisfied_by?(ext_ver) }
  end
end

#fill_symtab(effective_xlen, ast) ⇒ Object



398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
# File 'lib/udb/obj/instruction.rb', line 398

def fill_symtab(effective_xlen, ast)
  symtab = cfg_arch.symtab.global_clone
  symtab.push(ast)
  symtab.add(
    "__instruction_encoding_size",
    Idl::Var.new("__instruction_encoding_size", Idl::Type.new(:bits, width: encoding_width.bit_length), encoding_width)
  )
  symtab.add(
    "__effective_xlen",
    Idl::Var.new("__effective_xlen", Idl::Type.new(:bits, width: 7), effective_xlen)
  )
  encoding(effective_xlen).decode_variables.each do |d|
    qualifiers = [:const]
    qualifiers << :signed if d.sext?
    width = d.size

    var = Idl::Var.new(d.name, Idl::Type.new(:bits, qualifiers:, width:), decode_var: true)
    symtab.add(d.name, var)
  end

  symtab
end

#has_type?Boolean

Returns:

  • (Boolean)


120
# File 'lib/udb/obj/instruction.rb', line 120

def has_type? = @data.key?("format")

#hintsArray<Instruction>

Returns List of HINTs based on this instruction encoding.

Returns:

  • (Array<Instruction>)

    List of HINTs based on this instruction encoding



1156
1157
1158
# File 'lib/udb/obj/instruction.rb', line 1156

def hints
  @hints ||= @data.key?("hints") ? @data["hints"].map { |ref| @cfg_arch.ref(ref["$ref"]) } : []
end

#mask_to_array(int) ⇒ Object



472
473
474
475
476
477
478
479
480
481
482
483
# File 'lib/udb/obj/instruction.rb', line 472

def mask_to_array(int)
  elems = []
  idx = 0
  while int != 0
    if (int & (1 << idx)) != 0
      elems << idx
    end
    int &= ~(1 << idx)
    idx += 1
  end
  elems
end

#max_encoding_widthInteger

Returns the largest encoding width of the instruction, in any XLEN for which this instruction is valid.

Returns:

  • (Integer)

    the largest encoding width of the instruction, in any XLEN for which this instruction is valid



1113
1114
1115
# File 'lib/udb/obj/instruction.rb', line 1113

def max_encoding_width
  [(rv32? ? encoding(32).size : 0), (rv64? ? encoding(64).size : 0)].max
end

#multi_encoding?Boolean

Returns whether or not this instruction has different encodings depending on XLEN.

Returns:

  • (Boolean)

    whether or not this instruction has different encodings depending on XLEN



998
999
1000
1001
1002
1003
1004
# File 'lib/udb/obj/instruction.rb', line 998

def multi_encoding?
  if has_type?
    @data["format"].key?("RV32")
  else
    @data.key?("encoding") && @data["encoding"].key?("RV32")
  end
end

#opcodes(base) ⇒ Array<Opcode>

Parameters:

  • base (Integer)

Returns:



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/udb/obj/instruction.rb', line 180

def opcodes(base)
  raise "Instruction #{name} is not defined in base RV#{base}" unless defined_in_base?(base)

  @opcodes ||= {}

  return @opcodes[base] unless @opcodes[base].nil?

  @opcodes[base] = @data["format"]["opcodes"].map do |opcode_name, opcode_data|
      next if opcode_name[0] == "$"

      raise "unexpected: opcode field is not contiguous" if opcode_data["location"].include?("|")

      loc = opcode_data["location"]
      range =
        if loc =~ /^([0-9]+)$/
          bit = ::Regexp.last_match(1)
          bit.to_i..bit.to_i
        elsif loc =~ /^([0-9]+)-([0-9]+)$/
          msb = ::Regexp.last_match(1)
          lsb = ::Regexp.last_match(2)
          raise "range must be specified 'msb-lsb'" unless msb.to_i >= lsb.to_i

          lsb.to_i..msb.to_i
        else
          raise "location format error"
        end
      Opcode.new(opcode_name, range, opcode_data["value"])
    end.reject(&:nil?)
end

#operation_astFunctionBodyAst

Returns The abstract syntax tree of the instruction operation.

Returns:

  • (FunctionBodyAst)

    The abstract syntax tree of the instruction operation



1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
# File 'lib/udb/obj/instruction.rb', line 1065

def operation_ast
  defer :operation_ast do
    return nil if @data["operation()"].nil?

    # now, parse the operation
    ast = cfg_arch.idl_compiler.compile_inst_operation(
      self,
      symtab: cfg_arch.symtab,
      input_file: @data["$source"],
      input_line: source_line(["operation()"])
    )

    raise "unexpected #{ast.class}" unless ast.is_a?(Idl::FunctionBodyAst)

    ast
  end
end

#processed_wavedrom_desc(base) ⇒ Object



242
243
244
245
246
# File 'lib/udb/obj/instruction.rb', line 242

def processed_wavedrom_desc(base)
  data = wavedrom_desc(base)
  processed_data = process_wavedrom(data)
  fix_entities(json_dump_with_hex_literals(processed_data))
end

#pruned_operation_ast(effective_xlen) ⇒ Idl::FunctionBodyAst

Returns A pruned abstract syntax tree.

Parameters:

  • global_symtab (Idl::SymbolTable)

    Symbol table with global scope populated and a configuration loaded

Returns:

  • (Idl::FunctionBodyAst)

    A pruned abstract syntax tree



423
424
425
426
427
428
429
430
431
432
433
434
435
# File 'lib/udb/obj/instruction.rb', line 423

def pruned_operation_ast(effective_xlen)
  defer :pruned_operation_ast do
    return nil unless @data.key?("operation()")

    type_checked_ast = type_checked_operation_ast(effective_xlen)
    symtab = fill_symtab(effective_xlen, type_checked_ast)
    pruned_ast = type_checked_ast.prune(symtab)
    pruned_ast.freeze_tree(symtab)

    symtab.release
    pruned_ast
  end
end

#reachable_exceptions(effective_xlen) ⇒ Integer

Returns Mask of all exceptions that can be reached from operation().

Parameters:

  • symtab (Idl::SymbolTable)

    Symbol table with global scope populated

  • effective_xlen (Integer)

    Effective XLEN to evaluate against

Returns:

  • (Integer)

    Mask of all exceptions that can be reached from operation()



459
460
461
462
463
464
465
466
467
468
469
470
# File 'lib/udb/obj/instruction.rb', line 459

def reachable_exceptions(effective_xlen)
  if @data["operation()"].nil?
    []
  else
    # pruned_ast =  pruned_operation_ast(symtab)
    # type_checked_operation_ast()
    type_checked_ast = type_checked_operation_ast( effective_xlen)
    symtab = fill_symtab(effective_xlen, type_checked_ast)
    type_checked_ast.reachable_exceptions(symtab)
    symtab.release
  end
end

#reachable_exceptions_str(effective_xlen = nil) ⇒ Array<Integer>

Returns List of all exceptions that can be reached from operation().

Parameters:

  • effective_xlen (Integer) (defaults to: nil)

    Effective XLEN to evaluate against. If nil, evaluate against all valid XLENs

Returns:

  • (Array<Integer>)

    List of all exceptions that can be reached from operation()

Raises:

  • (ArgumentError)


487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
# File 'lib/udb/obj/instruction.rb', line 487

def reachable_exceptions_str(effective_xlen=nil)
  raise ArgumentError, "effective_xlen is a #{effective_xlen.class} but must be an Integer or nil" unless effective_xlen.nil? || effective_xlen.is_a?(Integer)

  if @data["operation()"].nil?
    []
  else
    symtab = cfg_arch.symtab
    etype = symtab.get("ExceptionCode")
    if effective_xlen.nil?
      if cfg_arch.multi_xlen?
        if base.nil?
          (
            pruned_ast = pruned_operation_ast(32)
            symtab = fill_symtab(32, pruned_ast)
            e32 = mask_to_array(pruned_ast.reachable_exceptions(symtab)).map { |code|
              etype.element_name(code)
            }
            symtab.release
            pruned_ast = pruned_operation_ast(64)
            symtab = fill_symtab(64, pruned_ast)
            e64 = mask_to_array(pruned_ast.reachable_exceptions(symtab)).map { |code|
              etype.element_name(code)
            }
            symtab.release
            e32 + e64
          ).uniq
        else
          pruned_ast = pruned_operation_ast(base)
          symtab = fill_symtab(base, pruned_ast)
          e = mask_to_array(pruned_ast.reachable_exceptions(symtab)).map { |code|
            etype.element_name(code)
          }
          symtab.release
          e
        end
      else
        effective_xlen = cfg_arch.mxlen
        pruned_ast = pruned_operation_ast(effective_xlen)
        puts " #{name}..."
        symtab = fill_symtab(effective_xlen, pruned_ast)
        e = mask_to_array(pruned_ast.reachable_exceptions(symtab)).map { |code|
          etype.element_name(code)
        }
        symtab.release
        e
      end
    else
      pruned_ast = pruned_operation_ast(effective_xlen)

      symtab = fill_symtab(effective_xlen, pruned_ast)
      e = mask_to_array(pruned_ast.reachable_exceptions(symtab)).map { |code|
        etype.element_name(code)
      }
      symtab.release
      e
    end
  end
end

#reachable_functions(effective_xlen) ⇒ Array<Idl::FunctionBodyAst>

Returns List of all functions that can be reached from operation().

Parameters:

  • symtab (Idl::SymbolTable)

    Symbol table with global scope populated

  • effective_xlen (Integer)

    The effective XLEN to evaluate against

Returns:

  • (Array<Idl::FunctionBodyAst>)

    List of all functions that can be reached from operation()



440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
# File 'lib/udb/obj/instruction.rb', line 440

def reachable_functions(effective_xlen)
  if @data["operation()"].nil?
    []
  else
    # RubyProf.start
    ast = type_checked_operation_ast(effective_xlen)
    symtab = fill_symtab(effective_xlen, ast)
    fns = ast.reachable_functions(symtab)
    # result = RubyProf.stop
    # RubyProf::FlatPrinter.new(result).print($stdout)
    # exit
    symtab.release
    fns
  end
end

#rv32?Boolean

Returns whether or not this instruction is defined for RV32.

Returns:

  • (Boolean)

    whether or not this instruction is defined for RV32



1146
1147
1148
# File 'lib/udb/obj/instruction.rb', line 1146

def rv32?
  !@data.key?("base") || base == 32
end

#rv64?Boolean

Returns whether or not this instruction is defined for RV64.

Returns:

  • (Boolean)

    whether or not this instruction is defined for RV64



1151
1152
1153
# File 'lib/udb/obj/instruction.rb', line 1151

def rv64?
  !@data.key?("base") || base == 64
end

#subtype(base) ⇒ InstructionSubtype

Parameters:

  • base (Integer)

Returns:



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/udb/obj/instruction.rb', line 142

def subtype(base)
  @subtype ||= {
    32 =>
      if @data["format"].key?("RV32")
        @arch.ref(@data["format"]["RV32"]["subtype"]["$ref"])
      else
        @arch.ref(@data["format"]["subtype"]["$ref"])
      end,
    64 =>
      if @data["format"].key?("RV64")
        @arch.ref(@data["format"]["RV64"]["subtype"]["$ref"])
      else
        @arch.ref(@data["format"]["subtype"]["$ref"])
      end
  }
  @subtype[base]
end

#type(base) ⇒ InstructionType

Parameters:

  • base (Integer)

Returns:



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/udb/obj/instruction.rb', line 123

def type(base)
  @type ||= {
    32 =>
      if @data["format"].key?("RV32")
        @arch.ref(@data["format"]["RV32"]["type"]["$ref"])
      else
        @arch.ref(@data["format"]["type"]["$ref"])
      end,
    64 =>
      if @data["format"].key?("RV64")
        @arch.ref(@data["format"]["RV64"]["type"]["$ref"])
      else
        @arch.ref(@data["format"]["type"]["$ref"])
      end
  }
  @type[base]
end

#type_checked_operation_ast(effective_xlen) ⇒ FunctionBodyAst

Returns A type-checked abstract syntax tree of the operation.

Parameters:

  • effective_xlen (Integer)

    32 or 64, the effective xlen to type check against

Returns:

  • (FunctionBodyAst)

    A type-checked abstract syntax tree of the operation



1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
# File 'lib/udb/obj/instruction.rb', line 1049

def type_checked_operation_ast(effective_xlen)
  defer :type_checked_operation_ast do
    return nil unless @data.key?("operation()")

    ast = operation_ast

    symtab = fill_symtab(effective_xlen, ast)
    ast.freeze_tree(symtab)
    cfg_arch.idl_compiler.type_check(ast, symtab, "#{name}.operation()")
    symtab.release

    ast
  end
end

#validate(resolver)

This method returns an undefined value.

Parameters:



311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
# File 'lib/udb/obj/instruction.rb', line 311

def validate(resolver)
  super(resolver)

  if has_type?
    if @data["format"]["RV32"].nil?
      b = @data["base"].nil? ? 64 : T.cast(@data["base"], Integer)
      Instruction.validate_encoding(self, b)
    else
      Instruction.validate_encoding(self, 32)
      Instruction.validate_encoding(self, 64)
    end
  else
    if @data["encoding"]["RV32"].nil?
      Instruction.deprecated_validate_encoding(@data["encoding"], name)
    else
      Instruction.deprecated_validate_encoding(@data["encoding"]["RV32"], name)
      Instruction.deprecated_validate_encoding(@data["encoding"]["RV64"], name)
    end
  end

  # Validate hint references
  if @data.key?("hints")
    @data["hints"].each_with_index do |hint, index|
      if hint.key?("$ref")
        begin
          # Try to dereference the hint to validate it exists
          hint_inst = @cfg_arch.ref(hint["$ref"])
          if hint_inst.nil?
            raise "Invalid hint reference in instruction '#{name}' at hints[#{index}]: '#{hint["$ref"]}' - reference not found"
          end
        rescue => e
          raise "Invalid hint reference in instruction '#{name}' at hints[#{index}]: '#{hint["$ref"]}' - #{e.message}"
        end
      end
    end
  end
end

#wavedrom_desc(base) ⇒ String

Generates a wavedrom description of the instruction encoding

Parameters:

  • base (Integer)

    The XLEN (32 or 64), needed if the instruction is #multi_encoding?

Returns:

  • (String)

    The wavedrom JSON description



1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
# File 'lib/udb/obj/instruction.rb', line 1131

def wavedrom_desc(base)
  desc = {
    "reg" => []
  }
  display_fields = encoding(base).opcode_fields
  display_fields += encoding(base).decode_variables.map(&:grouped_encoding_fields).flatten

  display_fields.sort { |a, b| b.range.last <=> a.range.last }.reverse.each do |e|
    desc["reg"] << { "bits" => e.range.size, "name" => e.name, "type" => (e.opcode? ? 2 : 4) }
  end

  desc
end