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.



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

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)



598
599
600
# File 'lib/udb/obj/instruction.rb', line 598

def alias
  @alias
end

#encoding_fieldsObject (readonly)

Returns the value of attribute encoding_fields.



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

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



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

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



603
604
605
# File 'lib/udb/obj/instruction.rb', line 603

def left_shift
  @left_shift
end

#locationString (readonly)

Returns:

  • (String)


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

def location
  @location
end

#nameObject (readonly)

the name of the field



593
594
595
# File 'lib/udb/obj/instruction.rb', line 593

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)


779
780
781
782
783
# File 'lib/udb/obj/instruction.rb', line 779

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)


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

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)


760
761
762
# File 'lib/udb/obj/instruction.rb', line 760

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

#extractObject

return code to extract the field



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

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



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

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



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

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



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

def hash
  @name.hash
end

#inst_pos_to_var_posObject



659
660
661
662
663
664
665
666
667
668
669
670
671
# File 'lib/udb/obj/instruction.rb', line 659

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



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

def location_bits
  Instruction.ary_from_location(@location)
end

#overlaps?(other) ⇒ Boolean

Parameters:

Returns:

  • (Boolean)


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

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,



623
624
625
626
627
628
629
630
631
# File 'lib/udb/obj/instruction.rb', line 623

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)


796
797
798
# File 'lib/udb/obj/instruction.rb', line 796

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_



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

def size
  size_in_encoding + @left_shift
end

#size_in_encodingObject

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



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

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)


769
770
771
# File 'lib/udb/obj/instruction.rb', line 769

def split?
  @encoding_fields.size > 1
end