Class: Udb::Instruction::DecodeVariable

Inherits:
Object
  • Object
show all
Extended by:
T::Sig
Defined in:
lib/udb/obj/instruction.rb

Overview

decode field constructions from YAML file, rather than riscv-opcodes eventually, we will move so that all instructions use the YAML file,

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, field_data) ⇒ DecodeVariable

Returns a new instance of DecodeVariable.



789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
# File 'lib/udb/obj/instruction.rb', line 789

def initialize(name, field_data)
  @name = name
  @left_shift = field_data["left_shift"].nil? ? 0 : field_data["left_shift"]
  @sext = field_data["sign_extend"].nil? ? false : field_data["sign_extend"]
  @alias = field_data["alias"].nil? ? nil : field_data["alias"]
  @location = field_data["location"]
  extract_location(field_data["location"])
  @excludes =
    if field_data.key?("not")
      if field_data["not"].is_a?(Array)
        field_data["not"]
      else
        [field_data["not"]]
      end
    else
      []
    end
  @decode_variable =
    if @alias.nil?
      name
    else
      @decode_variable = [name, @alias]
    end
end

Instance Attribute Details

#aliasObject (readonly)

alias of this field, or nil if none

used, e.g., when a field represents more than one variable (like rs1/rd for destructive instructions)



652
653
654
# File 'lib/udb/obj/instruction.rb', line 652

def alias
  @alias
end

#encoding_fieldsObject (readonly)

Returns the value of attribute encoding_fields.



662
663
664
# File 'lib/udb/obj/instruction.rb', line 662

def encoding_fields
  @encoding_fields
end

#excludesArray<Integer> (readonly)

Returns Specific values that are prohibited for this variable.

Returns:

  • (Array<Integer>)

    Specific values that are prohibited for this variable



660
661
662
# File 'lib/udb/obj/instruction.rb', line 660

def excludes
  @excludes
end

#left_shiftObject (readonly)

amount the field is left shifted before use, or nil is there is no left shift

For example, if the field is offset, left_shift is 3



657
658
659
# File 'lib/udb/obj/instruction.rb', line 657

def left_shift
  @left_shift
end

#locationObject (readonly)

Returns the value of attribute location.



665
666
667
# File 'lib/udb/obj/instruction.rb', line 665

def location
  @location
end

#nameObject (readonly)

the name of the field



647
648
649
# File 'lib/udb/obj/instruction.rb', line 647

def name
  @name
end

Instance Method Details

#bitsObject

returns bits of the encoding that make up the field, as an array

 Each item of the array is either:
   - A number, to represent a single bit
   - A range, to represent a continugous range of bits

The array is ordered from encoding MSB (at index 0) to LSB (at index n-1)


833
834
835
836
837
# File 'lib/udb/obj/instruction.rb', line 833

def bits
  @encoding_fields.map do |ef|
    ef.range.size == 1 ? ef.range.first : ef.range
  end
end

#encoding_repl(encoding, value) ⇒ String

Returns encoding, with the decode variable replaced with value.

Parameters:

  • encoding (String)

    Encoding, as a string of 1, 0, and - with MSB at index 0

  • value (Integer)

    Value of the decode variable

Returns:

  • (String)

    encoding, with the decode variable replaced with value

Raises:

  • (ArgumentError)


730
731
732
733
734
735
736
737
738
739
740
741
742
# File 'lib/udb/obj/instruction.rb', line 730

def encoding_repl(encoding, value)
  raise ArgumentError, "Expecting string" unless encoding.is_a?(String)
  raise ArgumentError, "Expecting Integer" unless value.is_a?(Integer)

  new_encoding = encoding.dup
  inst_pos_to_var_pos.each_with_index do |pos, idx|
    next if pos.nil?
    raise "Bad encoding" if idx >= encoding.size

    new_encoding[encoding.size - idx - 1] = ((value >> pos) & 1).to_s
  end
  new_encoding
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


814
815
816
# File 'lib/udb/obj/instruction.rb', line 814

def eql?(other)
  @name.eql?(other.name)
end

#extractObject

return code to extract the field



864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
# File 'lib/udb/obj/instruction.rb', line 864

def extract
  ops = []
  so_far = 0
  bits.each do |b|
    if b.is_a?(Integer)
      op = "$encoding[#{b}]"
      ops << op
      so_far += 1
    elsif b.is_a?(Range)
      op = "$encoding[#{b.end}:#{b.begin}]"
      ops << op
      so_far += T.must(b.size)
    end
  end
  ops << "#{@left_shift}'d0" unless @left_shift.zero?
  ops =
    if ops.size > 1
      "{#{ops.join(', ')}}"
    else
      ops[0]
    end
  ops = "sext(#{ops}, #{size})" if sext?
  ops
end

#extract_location(location) ⇒ Object



687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
# File 'lib/udb/obj/instruction.rb', line 687

def extract_location(location)
  @encoding_fields = []

  if location.is_a?(Integer)
    @encoding_fields << EncodingField.new("", location..location)
    return
  end

  location_string = location
  parts = location_string.split("|")
  parts.each do |part|
    if part =~ /^([0-9]+)$/
      bit = ::Regexp.last_match(1)
      @encoding_fields << EncodingField.new("", bit.to_i..bit.to_i)
    elsif part =~ /^([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

      @encoding_fields << EncodingField.new("", lsb.to_i..msb.to_i)
    else
      raise "location format error"
    end
  end
end

#grouped_encoding_fieldsObject

array of constituent encoding fields



765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
# File 'lib/udb/obj/instruction.rb', line 765

def grouped_encoding_fields
  sorted_encoding_fields = @encoding_fields.sort { |a, b| b.range.last <=> a.range.last }
  # need to group encoding_fields if they are consecutive
  grouped_fields = [sorted_encoding_fields[0].range]
  sorted_encoding_fields[1..].each do |ef|
    if (ef.range.last + 1) == grouped_fields.last.first
      grouped_fields[-1] = (ef.range.first..grouped_fields.last.last)
    else
      grouped_fields << ef.range
    end
  end
  if grouped_fields.size == 1
    if grouped_fields.last.size == size
      [EncodingField.new(pretty_name, grouped_fields[0])]
    else
      [EncodingField.new("#{pretty_name}[#{inst_range_to_var_range(grouped_fields[0])}]", grouped_fields[0])]
    end
  else
    grouped_fields.map do |f|
      EncodingField.new("#{pretty_name}[#{inst_range_to_var_range(f)}]", f)
    end
  end
end

#hashObject



818
819
820
# File 'lib/udb/obj/instruction.rb', line 818

def hash
  @name.hash
end

#inst_pos_to_var_posObject



713
714
715
716
717
718
719
720
721
722
723
724
725
# File 'lib/udb/obj/instruction.rb', line 713

def inst_pos_to_var_pos
  s = size
  map = Array.new(32, nil)
  @encoding_fields.each do |ef|
    ef.range.to_a.reverse_each do |ef_i|
      raise "unexpected" if s <= 0

      map[ef_i] = s - 1
      s -= 1
    end
  end
  map
end

#location_bitsObject



669
670
671
# File 'lib/udb/obj/instruction.rb', line 669

def location_bits
  Instruction.ary_from_location(@location)
end

#overlaps?(other) ⇒ Boolean

Returns:

  • (Boolean)


855
856
857
858
859
860
861
# File 'lib/udb/obj/instruction.rb', line 855

def overlaps?(other)
  if other.is_a?(Instruction::Opcode)
    location_bits.any? { |i| other.range.cover?(i) }
  else
    location_bits.intersect?(other.location_bits)
  end
end

#pretty_nameString

Returns Name, along with any != constraints,.

Examples:

pretty_name #=> "rd != 0"
pretty_name #=> "rd != {0,2}"

Returns:

  • (String)

    Name, along with any != constraints,



677
678
679
680
681
682
683
684
685
# File 'lib/udb/obj/instruction.rb', line 677

def pretty_name
  if excludes.empty?
    name
  elsif excludes.size == 1
    "#{name} != #{excludes[0]}"
  else
    "#{name} != {#{excludes.join(',')}}"
  end
end

#sext?Boolean

true if the field should be sign extended

Returns:

  • (Boolean)


850
851
852
# File 'lib/udb/obj/instruction.rb', line 850

def sext?
  @sext
end

#sizeInteger

Returns the number of bits in the field, _including any implicit bits_.

Returns:

  • (Integer)

    the number of bits in the field, _including any implicit bits_



840
841
842
# File 'lib/udb/obj/instruction.rb', line 840

def size
  size_in_encoding + @left_shift
end

#size_in_encodingObject

the number of bits in the field, _not including any implicit zeros_



845
846
847
# File 'lib/udb/obj/instruction.rb', line 845

def size_in_encoding
  bits.reduce(0) { |sum, f| sum + (f.is_a?(Integer) ? 1 : f.size) }
end

#split?Boolean

returns true if the field is encoded across more than one groups of bits

Returns:

  • (Boolean)


823
824
825
# File 'lib/udb/obj/instruction.rb', line 823

def split?
  @encoding_fields.size > 1
end