Class: Instruction
- Inherits:
-
ArchDefObject
- Object
- ArchDefObject
- Instruction
- Defined in:
- lib/arch_obj_models/instruction.rb
Overview
model of a specific instruction in a specific base (RV32/RV64)
Defined Under Namespace
Classes: DecodeVariable, Encoding, EncodingField
Instance Attribute Summary collapse
-
#arch_def ⇒ ArchDef
readonly
The architecture definition.
Instance Method Summary collapse
- #<=>(other) ⇒ Object
- #==(other) ⇒ Object (also: #eql?)
-
#access ⇒ Hash<String, String>
Hash of access permissions for each mode.
- #access_detail ⇒ String?
-
#access_detail? ⇒ Boolean
True if the instruction has an ‘access_detail’ field.
-
#assembly ⇒ String
Assembly format.
- #base ⇒ Integer?
-
#data_independent_timing? ⇒ Boolean
Whether or not the instruction must have data-independent timing when Zkt is enabled.
-
#decode_variables(base) ⇒ Array<DecodeVariable>
The decode variables.
-
#defined_in_base?(xlen) ⇒ Boolean
Whethen or not instruction is defined in base
xlen
. -
#encoding(base) ⇒ Encoding
The encoding.
-
#encoding_width ⇒ Integer
The width of the encoding.
- #excluded_by?(*args) ⇒ Object
-
#exists_in_cfg?(arch_def) ⇒ Boolean
Whether or not the instruction is implemented given the supplies config options.
-
#initialize(data, arch_def) ⇒ Instruction
constructor
A new instance of Instruction.
- #mask_to_array(int) ⇒ Object
-
#multi_encoding? ⇒ Boolean
Whether or not this instruction has different encodings depending on XLEN.
-
#operation_ast(symtab) ⇒ FunctionBodyAst
The abstract syntax tree of the instruction operation.
-
#pruned_operation_ast(global_symtab, effective_xlen) ⇒ Idl::FunctionBodyAst
A pruned abstract syntax tree.
-
#reachable_exceptions(symtab, effective_xlen) ⇒ Integer
Mask of all exceptions that can be reached from operation().
-
#reachable_exceptions_str(symtab, effective_xlen = nil) ⇒ Array<Integer>
List of all exceptions that can be reached from operation().
-
#reachable_functions(symtab, effective_xlen) ⇒ Array<Idl::FunctionBodyAst>
List of all functions that can be reached from operation().
-
#rv32? ⇒ Boolean
Whether or not this instruction is defined for RV32.
-
#rv64? ⇒ Boolean
Whether or not this instruction is defined for RV64.
-
#type_checked_operation_ast(idl_compiler, symtab, effective_xlen) ⇒ FunctionBodyAst
A type-checked abstract syntax tree of the operation.
-
#wavedrom_desc(base) ⇒ String
Generates a wavedrom description of the instruction encoding.
Constructor Details
#initialize(data, arch_def) ⇒ Instruction
Returns a new instance of Instruction.
217 218 219 220 |
# File 'lib/arch_obj_models/instruction.rb', line 217 def initialize(data, arch_def) super(data) @arch_def = arch_def end |
Instance Attribute Details
#arch_def ⇒ ArchDef (readonly)
Returns The architecture definition.
215 216 217 |
# File 'lib/arch_obj_models/instruction.rb', line 215 def arch_def @arch_def end |
Instance Method Details
#<=>(other) ⇒ Object
20 21 22 23 24 25 26 |
# File 'lib/arch_obj_models/instruction.rb', line 20 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?
10 11 12 13 14 15 16 |
# File 'lib/arch_obj_models/instruction.rb', line 10 def ==(other) if other.is_a?(Instruction) name == other.name else raise ArgumentError, "Instruction is not comparable to a #{other.class.name}" end end |
#access ⇒ Hash<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’].
29 30 31 |
# File 'lib/arch_obj_models/instruction.rb', line 29 def access @data["access"] end |
#access_detail ⇒ String?
35 36 37 |
# File 'lib/arch_obj_models/instruction.rb', line 35 def access_detail @data["access_detail"] end |
#access_detail? ⇒ Boolean
Returns true if the instruction has an ‘access_detail’ field.
636 637 638 |
# File 'lib/arch_obj_models/instruction.rb', line 636 def access_detail? @data.key?("access_detail") end |
#assembly ⇒ String
Returns Assembly format.
55 56 57 |
# File 'lib/arch_obj_models/instruction.rb', line 55 def assembly @data["assembly"] end |
#base ⇒ Integer?
41 42 43 |
# File 'lib/arch_obj_models/instruction.rb', line 41 def base @data["base"] end |
#data_independent_timing? ⇒ Boolean
Returns Whether or not the instruction must have data-independent timing when Zkt is enabled.
46 |
# File 'lib/arch_obj_models/instruction.rb', line 46 def data_independent_timing? = @data["data_independent_timing"] |
#decode_variables(base) ⇒ Array<DecodeVariable>
Returns The decode variables.
631 632 633 |
# File 'lib/arch_obj_models/instruction.rb', line 631 def decode_variables(base) encoding(base).decode_variables end |
#defined_in_base?(xlen) ⇒ Boolean
Returns whethen or not instruction is defined in base xlen
.
50 51 52 |
# File 'lib/arch_obj_models/instruction.rb', line 50 def defined_in_base?(xlen) base == xlen end |
#encoding(base) ⇒ Encoding
Returns the encoding.
617 618 619 620 621 |
# File 'lib/arch_obj_models/instruction.rb', line 617 def encoding(base) load_encoding if @encodings.nil? @encodings[base] end |
#encoding_width ⇒ Integer
Returns the width of the encoding.
624 625 626 627 628 |
# File 'lib/arch_obj_models/instruction.rb', line 624 def encoding_width raise "unexpected: encodings are different sizes" unless encoding(32).size == encoding(64).size encoding(64).size end |
#excluded_by?(ext_name, ext_version) ⇒ Boolean #excluded_by?(ext_version) ⇒ Boolean
675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 |
# File 'lib/arch_obj_models/instruction.rb', line 675 def excluded_by?(*args) return false if @data["excludedBy"].nil? excluded_by = SchemaCondition.new(@data["excludedBy"]) if args.size == 1 raise ArgumentError, "Parameter must be an ExtensionVersion" unless args[0].is_a?(ExtensionVersion) excluded_by.satisfied_by? do |r| r.name == args[0].name && r.version_requirement.satisfied_by?(args[0].version) end elsif args.size == 2 raise ArgumentError, "First parameter must be an extension name" unless args[0].respond_to?(:to_s) raise ArgumentError, "Second parameter must be an extension version" unless args[0].respond_to?(:to_s) version = args[1].is_a?(Gem::Version) ? args[1] : Gem::Version.new(args[1]) excluded_by.satisfied_by? do |r| r.name == args[0] && r.version_requirement.satisfied_by?(version) end end end |
#exists_in_cfg?(arch_def) ⇒ Boolean
Returns whether or not the instruction is implemented given the supplies config options.
700 701 702 703 704 705 706 707 708 709 710 711 712 |
# File 'lib/arch_obj_models/instruction.rb', line 700 def exists_in_cfg?(arch_def) if arch_def.fully_configured? (@data["base"].nil? || (arch_def.possible_xlens.include? @data["base"])) && arch_def.implemented_extensions.any? { |e| defined_by?(e) } && arch_def.implemented_extensions.none? { |e| excluded_by?(e) } else raise "unexpected arch_def type" unless arch_def.partially_configured? (@data["base"].nil? || (arch_def.possible_xlens.include? @data["base"])) && arch_def.prohibited_extensions.none? { |e| defined_by?(e) } && arch_def.mandatory_extensions.none? { |e| excluded_by?(e) } end end |
#mask_to_array(int) ⇒ Object
143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/arch_obj_models/instruction.rb', line 143 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 |
#multi_encoding? ⇒ Boolean
Returns whether or not this instruction has different encodings depending on XLEN.
574 575 576 |
# File 'lib/arch_obj_models/instruction.rb', line 574 def multi_encoding? @data.key?("encoding") && @data["encoding"].key?("RV32") end |
#operation_ast(symtab) ⇒ FunctionBodyAst
Returns The abstract syntax tree of the instruction operation.
598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 |
# File 'lib/arch_obj_models/instruction.rb', line 598 def operation_ast(symtab) return @operation_ast unless @operation_ast.nil? return nil if @data["operation()"].nil? # now, parse the operation @operation_ast = symtab.archdef.idl_compiler.compile_inst_operation( self, symtab:, input_file: @data["__source"], input_line: source_line("operation()") ) raise "unexpected #{@operation_ast.class}" unless @operation_ast.is_a?(Idl::FunctionBodyAst) @operation_ast end |
#pruned_operation_ast(global_symtab, effective_xlen) ⇒ Idl::FunctionBodyAst
Returns A pruned abstract syntax tree.
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/arch_obj_models/instruction.rb', line 85 def pruned_operation_ast(global_symtab, effective_xlen) @pruned_asts ||= {} arch_def = global_symtab.archdef pruned_ast = @pruned_asts[arch_def.name] return pruned_ast unless pruned_ast.nil? return nil unless @data.key?("operation()") type_checked_ast = type_checked_operation_ast(arch_def.idl_compiler, global_symtab, effective_xlen) print "Pruning #{name} operation()..." pruned_ast = type_checked_ast.prune(fill_symtab(global_symtab, effective_xlen, type_checked_ast)) puts "done" pruned_ast.freeze_tree(global_symtab) arch_def.idl_compiler.type_check( pruned_ast, fill_symtab(global_symtab, effective_xlen, pruned_ast), "#{name}.operation() (pruned)" ) @pruned_asts[arch_def.name] = pruned_ast end |
#reachable_exceptions(symtab, effective_xlen) ⇒ Integer
Returns Mask of all exceptions that can be reached from operation().
131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/arch_obj_models/instruction.rb', line 131 def reachable_exceptions(symtab, effective_xlen) if @data["operation()"].nil? [] else # pruned_ast = pruned_operation_ast(symtab) # type_checked_operation_ast() type_checked_ast = type_checked_operation_ast(symtab.arch_def.idl_compiler, symtab, effective_xlen) symtab = fill_symtab(symtab, effective_xlen, pruned_ast) type_checked_ast.reachable_exceptions(symtab) end end |
#reachable_exceptions_str(symtab, effective_xlen = nil) ⇒ Array<Integer>
Returns List of all exceptions that can be reached from operation().
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 209 210 211 212 |
# File 'lib/arch_obj_models/instruction.rb', line 159 def reachable_exceptions_str(symtab, effective_xlen=nil) if @data["operation()"].nil? [] else etype = symtab.get("ExceptionCode") if effective_xlen.nil? if symtab.archdef.multi_xlen? if base.nil? ( pruned_ast = pruned_operation_ast(symtab, 32) print "Determining reachable exceptions from #{name}#RV32..." e32 = mask_to_array(pruned_ast.reachable_exceptions(fill_symtab(symtab, 32, pruned_ast))).map { |code| etype.element_name(code) } puts "done" pruned_ast = pruned_operation_ast(symtab, 64) print "Determining reachable exceptions from #{name}#RV64..." e64 = mask_to_array(pruned_ast.reachable_exceptions(fill_symtab(symtab, 64, pruned_ast))).map { |code| etype.element_name(code) } puts "done" e32 + e64 ).uniq else pruned_ast = pruned_operation_ast(symtab, base) print "Determining reachable exceptions from #{name}..." e = mask_to_array(pruned_ast.reachable_exceptions(fill_symtab(symtab, base, pruned_ast))).map { |code| etype.element_name(code) } puts "done" e end else effective_xlen = symtab.archdef.mxlen pruned_ast = pruned_operation_ast(symtab, effective_xlen) print "Determining reachable exceptions from #{name}..." e = mask_to_array(pruned_ast.reachable_exceptions(fill_symtab(symtab, effective_xlen, pruned_ast))).map { |code| etype.element_name(code) } puts "done" e end else pruned_ast = pruned_operation_ast(symtab, effective_xlen) print "Determining reachable exceptions from #{name}..." e = mask_to_array(pruned_ast.reachable_exceptions(fill_symtab(symtab, effective_xlen, pruned_ast))).map { |code| etype.element_name(code) } puts "done" e end end end |
#reachable_functions(symtab, effective_xlen) ⇒ Array<Idl::FunctionBodyAst>
Returns List of all functions that can be reached from operation().
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/arch_obj_models/instruction.rb', line 112 def reachable_functions(symtab, effective_xlen) if @data["operation()"].nil? [] else # RubyProf.start ast = type_checked_operation_ast(symtab.archdef.idl_compiler, symtab, effective_xlen) print "Determining reachable funcs from #{name}..." fns = ast.reachable_functions(fill_symtab(symtab, effective_xlen, ast)) puts "done" # result = RubyProf.stop # RubyProf::FlatPrinter.new(result).print($stdout) # exit fns end end |
#rv32? ⇒ Boolean
Returns whether or not this instruction is defined for RV32.
659 660 661 |
# File 'lib/arch_obj_models/instruction.rb', line 659 def rv32? !@data.key?("base") || base == 32 end |
#rv64? ⇒ Boolean
Returns whether or not this instruction is defined for RV64.
664 665 666 |
# File 'lib/arch_obj_models/instruction.rb', line 664 def rv64? !@data.key?("base") || base == 64 end |
#type_checked_operation_ast(idl_compiler, symtab, effective_xlen) ⇒ FunctionBodyAst
Returns A type-checked abstract syntax tree of the operation.
582 583 584 585 586 587 588 589 590 591 592 593 594 |
# File 'lib/arch_obj_models/instruction.rb', line 582 def type_checked_operation_ast(idl_compiler, symtab, effective_xlen) @type_checked_operation_ast ||= {} ast = @type_checked_operation_ast[symtab.hash] return ast unless ast.nil? return nil unless @data.key?("operation()") ast = operation_ast(symtab) idl_compiler.type_check(ast, fill_symtab(symtab, effective_xlen, ast), "#{name}.operation()") @type_checked_operation_ast[symtab.hash] = ast end |
#wavedrom_desc(base) ⇒ String
Generates a wavedrom description of the instruction encoding
644 645 646 647 648 649 650 651 652 653 654 655 656 |
# File 'lib/arch_obj_models/instruction.rb', line 644 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 |