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.



738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
# File 'lib/udb/obj/instruction.rb', line 738

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)



601
602
603
# File 'lib/udb/obj/instruction.rb', line 601

def alias
  @alias
end

#encoding_fieldsObject (readonly)

Returns the value of attribute encoding_fields.



611
612
613
# File 'lib/udb/obj/instruction.rb', line 611

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



609
610
611
# File 'lib/udb/obj/instruction.rb', line 609

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



606
607
608
# File 'lib/udb/obj/instruction.rb', line 606

def left_shift
  @left_shift
end

#locationString (readonly)

Returns:

  • (String)


614
615
616
# File 'lib/udb/obj/instruction.rb', line 614

def location
  @location
end

#nameObject (readonly)

the name of the field



596
597
598
# File 'lib/udb/obj/instruction.rb', line 596

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)


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

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)


679
680
681
682
683
684
685
686
687
688
689
690
691
# File 'lib/udb/obj/instruction.rb', line 679

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)


763
764
765
# File 'lib/udb/obj/instruction.rb', line 763

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

#extractObject

return code to extract the field



813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
# File 'lib/udb/obj/instruction.rb', line 813

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



636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
# File 'lib/udb/obj/instruction.rb', line 636

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



714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
# File 'lib/udb/obj/instruction.rb', line 714

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



767
768
769
# File 'lib/udb/obj/instruction.rb', line 767

def hash
  @name.hash
end

#inst_pos_to_var_posObject



662
663
664
665
666
667
668
669
670
671
672
673
674
# File 'lib/udb/obj/instruction.rb', line 662

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



618
619
620
# File 'lib/udb/obj/instruction.rb', line 618

def location_bits
  Instruction.ary_from_location(@location)
end

#overlaps?(other) ⇒ Boolean

Parameters:

Returns:

  • (Boolean)


804
805
806
807
808
809
810
# File 'lib/udb/obj/instruction.rb', line 804

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,



626
627
628
629
630
631
632
633
634
# File 'lib/udb/obj/instruction.rb', line 626

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)


799
800
801
# File 'lib/udb/obj/instruction.rb', line 799

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_



789
790
791
# File 'lib/udb/obj/instruction.rb', line 789

def size
  size_in_encoding + @left_shift
end

#size_in_encodingObject

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



794
795
796
# File 'lib/udb/obj/instruction.rb', line 794

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)


772
773
774
# File 'lib/udb/obj/instruction.rb', line 772

def split?
  @encoding_fields.size > 1
end