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.



758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
# File 'lib/udb/obj/instruction.rb', line 758

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)



621
622
623
# File 'lib/udb/obj/instruction.rb', line 621

def alias
  @alias
end

#encoding_fieldsObject (readonly)

Returns the value of attribute encoding_fields.



631
632
633
# File 'lib/udb/obj/instruction.rb', line 631

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



629
630
631
# File 'lib/udb/obj/instruction.rb', line 629

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



626
627
628
# File 'lib/udb/obj/instruction.rb', line 626

def left_shift
  @left_shift
end

#locationString (readonly)

Returns:

  • (String)


634
635
636
# File 'lib/udb/obj/instruction.rb', line 634

def location
  @location
end

#nameObject (readonly)

the name of the field



616
617
618
# File 'lib/udb/obj/instruction.rb', line 616

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)


802
803
804
805
806
# File 'lib/udb/obj/instruction.rb', line 802

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)


699
700
701
702
703
704
705
706
707
708
709
710
711
# File 'lib/udb/obj/instruction.rb', line 699

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)


783
784
785
# File 'lib/udb/obj/instruction.rb', line 783

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

#extractObject

return code to extract the field



833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
# File 'lib/udb/obj/instruction.rb', line 833

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})" if sext?
  ops
end

#extract_location(location) ⇒ Object



656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
# File 'lib/udb/obj/instruction.rb', line 656

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



734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
# File 'lib/udb/obj/instruction.rb', line 734

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



787
788
789
# File 'lib/udb/obj/instruction.rb', line 787

def hash
  @name.hash
end

#inst_pos_to_var_posObject



682
683
684
685
686
687
688
689
690
691
692
693
694
# File 'lib/udb/obj/instruction.rb', line 682

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_bitsArray<Integer>

Returns Any array containing every encoding index covered by this variable.

Returns:

  • (Array<Integer>)

    Any array containing every encoding index covered by this variable



638
639
640
# File 'lib/udb/obj/instruction.rb', line 638

def location_bits
  Instruction.ary_from_location(@location)
end

#overlaps?(other) ⇒ Boolean

Parameters:

Returns:

  • (Boolean)


824
825
826
827
828
829
830
# File 'lib/udb/obj/instruction.rb', line 824

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,



646
647
648
649
650
651
652
653
654
# File 'lib/udb/obj/instruction.rb', line 646

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)


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

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_



809
810
811
# File 'lib/udb/obj/instruction.rb', line 809

def size
  size_in_encoding + @left_shift
end

#size_in_encodingObject

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



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

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)


792
793
794
# File 'lib/udb/obj/instruction.rb', line 792

def split?
  @encoding_fields.size > 1
end