Class: HDLRuby::BitString

Inherits:
Object
  • Object
show all
Defined in:
lib/HDLRuby/hruby_bstr.rb,
lib/HDLRuby/hruby_verilog.rb

Overview

Used to output bitstring. Enhance HDLRuby with generation of verilog code.

Constant Summary collapse

TRUE =

A few common bit strings.

BitString.new("01")
FALSE =
BitString.new("00")
UNKNOWN =
BitString.new("xx")
ZERO =
BitString.new("00")
ONE =
BitString.new("01")
TWO =
BitString.new("010")
THREE =
BitString.new("011")
MINUS_ONE =
BitString.new("11")
MINUS_TWO =
BitString.new("10")
MINUS_THREE =
BitString.new("101")
NOT_T =

Not truth table

{ "0" => "1", "1" => "0", "z" => "x", "x" => "x" }
AND_T =

And truth table: 0, 1, 2=z, 3=x

{ "0" => {"0"=>"0", "1"=>"0", "z"=>"0", "x"=>"0"},  # 0 line
"1" => {"0"=>"0", "1"=>"1", "z"=>"x", "x"=>"x"},  # 1 line
"z" => {"0"=>"0", "1"=>"x", "z"=>"x", "x"=>"x"},  # z line
"x" => {"0"=>"0", "1"=>"x", "z"=>"x", "x"=>"x"} }
OR_T =

Or truth table: 0, 1, 2=z, 3=x

{ "0" => {"0"=>"0", "1"=>"1", "z"=>"x", "x"=>"x"},  # 0 line
"1" => {"0"=>"1", "1"=>"1", "z"=>"1", "x"=>"1"},  # 1 line
"z" => {"0"=>"x", "1"=>"1", "z"=>"x", "x"=>"x"},  # z line
"x" => {"0"=>"x", "1"=>"1", "z"=>"x", "x"=>"x"} }
XOR_T =

Xor truth table: 0, 1, 2=z, 3=x

{ "0" => {"0"=>"0", "1"=>"1", "z"=>"x", "x"=>"x"},  # 0 line
"1" => {"0"=>"1", "1"=>"0", "z"=>"x", "x"=>"x"},  # 1 line
"z" => {"0"=>"x", "1"=>"x", "z"=>"x", "x"=>"x"},  # z line
"x" => {"0"=>"x", "1"=>"x", "z"=>"x", "x"=>"x"} }
XOR3_T =

Double xor truth table: 0, 1, 2=z, 3=x

{ "0" => {
"0" => {"0"=>"0", "1"=>"1", "z"=>"x", "x"=>"x"}, 
"1" => {"0"=>"1", "1"=>"0", "z"=>"x", "x"=>"x"}, 
"z" => {"0"=>"x", "1"=>"x", "z"=>"x", "x"=>"x"},
"x" => {"0"=>"x", "1"=>"x", "z"=>"x", "x"=>"x"} }, # 0 line
                 "1" => {
"0" => {"0"=>"1", "1"=>"0", "z"=>"x", "x"=>"x"},
"1" => {"0"=>"0", "1"=>"1", "z"=>"x", "x"=>"x"}, 
"z" => {"0"=>"x", "1"=>"x", "z"=>"x", "x"=>"x"},
"x" => {"0"=>"x", "1"=>"x", "z"=>"x", "x"=>"x"} }, # 1 line
                 "z" => {
"0" => {"0"=>"x", "1"=>"x", "z"=>"x", "x"=>"x"},
"1" => {"0"=>"x", "1"=>"x", "z"=>"x", "x"=>"x"}, 
"z" => {"0"=>"x", "1"=>"x", "z"=>"x", "x"=>"x"},
"x" => {"0"=>"x", "1"=>"x", "z"=>"x", "x"=>"x"} }, # z line
                 "x" => {
"0" => {"0"=>"x", "1"=>"x", "z"=>"x", "x"=>"x"},
"1" => {"0"=>"x", "1"=>"x", "z"=>"x", "x"=>"x"},
"z" => {"0"=>"x", "1"=>"x", "z"=>"x", "x"=>"x"},
"x" => {"0"=>"x", "1"=>"x", "z"=>"x", "x"=>"x"} } }
MAJ_T =

Majority truth table: 0, 1, 2=z, 3=x

{ "0" => {
"0" => {"0"=>"0", "1"=>"0", "z"=>"0", "x"=>"0"},
"1" => {"0"=>"0", "1"=>"1", "z"=>"x", "x"=>"x"}, 
"z" => {"0"=>"0", "1"=>"x", "z"=>"x", "x"=>"x"},
"x" => {"0"=>"0", "1"=>"x", "z"=>"x", "x"=>"x"} }, # "0" line
                 "1" => { 
"0" => {"0"=>"0", "1"=>"1", "z"=>"x", "x"=>"x"},
"1" => {"0"=>"1", "1"=>"1", "z"=>"1", "x"=>"1"}, 
"z" => {"0"=>"x", "1"=>"1", "z"=>"x", "x"=>"x"},
"x" => {"0"=>"x", "1"=>"1", "z"=>"x", "x"=>"x"} }, # "1" line
                 "z" => {
"0" => {"0"=>"0", "1"=>"x", "z"=>"x", "x"=>"x"},
"1" => {"0"=>"x", "1"=>"1", "z"=>"x", "x"=>"x"}, 
"z" => {"0"=>"x", "1"=>"x", "z"=>"x", "x"=>"x"},
"x" => {"0"=>"x", "1"=>"x", "z"=>"x", "x"=>"x"} }, # z line
                 "x" => {
"0" => {"0"=>"0", "1"=>"x", "z"=>"x", "x"=>"x"},
"1" => {"0"=>"x", "1"=>"1", "z"=>"x", "x"=>"x"}, 
"z" => {"0"=>"x", "1"=>"x", "z"=>"x", "x"=>"x"},
"x" => {"0"=>"x", "1"=>"x", "z"=>"x", "x"=>"x"} } }
LT_T =

Lower than truth table: 0, 1, 2=z, 3=x

{ "0" => {"0"=>"0", "1"=>"1", "z"=>"x", "x"=>"x"},  # 0 line
"1" => {"0"=>"0", "1"=>"0", "z"=>"x", "x"=>"x"},  # 1 line
"z" => {"0"=>"x", "1"=>"x", "z"=>"x", "x"=>"x"},  # z line
"x" => {"0"=>"x", "1"=>"x", "z"=>"x", "x"=>"x"} }
GT_T =

Greater than truth table: 0, 1, 2=z, 3=x

{ "0" => {"0"=>"0", "1"=>"0", "z"=>"x", "x"=>"x"},  # 0 line
"1" => {"0"=>"1", "1"=>"0", "z"=>"x", "x"=>"x"},  # 1 line
"z" => {"0"=>"x", "1"=>"x", "z"=>"x", "x"=>"x"},  # z line
"x" => {"0"=>"x", "1"=>"x", "z"=>"x", "x"=>"x"} }
BITWISE =

Table of bitwise operations

{ :+  => :bitwise_add0,
            :-  => :bitwise_sub0,
            :-@ => :bitwise_neg0,
            :+@ => :bitwise_pos,
            :*  => :bitwise_mul0,
            :/  => :bitwise_div0,
            :%  => :bitwise_mod0,
            :** => :bitwise_pow0,
            :&  => :bitwise_and,
            :|  => :bitwise_or,
            :^  => :bitwise_xor,
            :~  => :bitwise_not,
            :<< => :bitwise_shl,
            :>> => :bitwise_shr,
            :== => :bitwise_eq0,
            :<  => :bitwise_lt0,
            :>  => :bitwise_gt0,
            :<= => :bitwise_le0,
            :>= => :bitwise_ge0,
            :<=>=> :bitwise_cp0
}
@@unknown =

The counter of unknown bits.

1

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(str, sign = nil) ⇒ BitString

Creates a new bit string from +str+ with +sign+.

NOTE:

  • +sign+ can be "0", "1", "z" and "x", is positive when "0" and negative when "1".
  • when not present it is assumed to be within str.


34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/HDLRuby/hruby_bstr.rb', line 34

def initialize(str,sign = nil)
    # puts "str=#{str}"
    # Maybe str is an numeric.
    if str.is_a?(Numeric) then
        # Yes, convert it to a binary string.
        num = str
        str = num.to_s(2)
        # And fix the sign.
        if str[0] == "-" then
            # str = str[1..-1]
            str = (2**str.size+num).to_s(2)
            puts "str=#{str}"
            sign = "-"
        else
            sign = "+"
        end
        # puts "str=#{str} sign=#{sign}"
    end
    # Process the sign
    sign = sign.to_s unless sign.is_a?(Integer)
    case sign
    when 0, "0","+" then @str = "0"
    when 1, "1","-" then @str = "1"
    when 2, "z","Z" then @str = "z"
    when 3, "x","X" then @str = "x"
    when nil, ""    then @str = "" # The sign is in str
    else
        raise "Invalid bit string sign: #{sign}"
    end
    # Check and set the value of the bit string.
    if str.respond_to?(:to_a) then
        # Str is a bit list: convert it to a string.
        str = str.to_a.map do |e|
            case e
            when 0 then "0"
            when 1 then "1"
            when 2 then "z"
            when 3 then "x"
            else
                e
            end
        end.reverse.join
    end
    @str += str.to_s.downcase
    # puts "@str=#{@str}"
    unless @str.match(/^[0-1zx]+$/) then
        raise "Invalid value for creating a bit string: #{str}"
    end
end

Class Method Details

.bitwise_add(s0, s1) ⇒ Object

Bitwise addition



476
477
478
479
480
481
482
483
484
485
486
487
# File 'lib/HDLRuby/hruby_bstr.rb', line 476

def self.bitwise_add(s0,s1)
    res = ""  # The result list of bits
    c   = "0" # The current carry
    s0.each.zip(s1.each) do |b0,b1|
        res << XOR3_T[b0][b1][c]
        c = MAJ_T[b0][b1][c]
    end
    # Compute the sign extension (the sign bit of s0 and s1 is used
    # again)
    res << XOR3_T[s0.sign][s1.sign][c]
    return BitString.new(res.reverse)
end

.bitwise_add0(s0, s1) ⇒ Object

Bitwise addition without processing of the x and z states.



471
472
473
# File 'lib/HDLRuby/hruby_bstr.rb', line 471

def self.bitwise_add0(s0,s1)
    return BitString.new("x"*(s0.width+1))
end

.bitwise_and(s0, s1) ⇒ Object

Bitwise and



536
537
538
539
540
# File 'lib/HDLRuby/hruby_bstr.rb', line 536

def self.bitwise_and(s0,s1)
    res = s0.each.zip(s1.each).map { |b0,b1| AND_T[b0][b1] }.join
    # puts "s0=#{s0}, s1=#{s1}, res=#{res}"
    return BitString.new(res.reverse)
end

.bitwise_cp(s0, s1) ⇒ Object

Bitwise cp.



744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
# File 'lib/HDLRuby/hruby_bstr.rb', line 744

def self.bitwise_cp(s0,s1)
    # Compare the signs.
    if s0.sign == "0" and s1.sign == "1" then
        return ONE
    elsif s0.sign == 0 and s1.sign == "1" then
        return MINUS_ONE
    end
    # Compare the other bits.
    sub = self.bitwise_sub(s0,s1)
    if sub.negative? then
        return MINUS_ONE
    elsif sub.zero? then
        return ZERO
    elsif sub.positive? then
        return ONE
    else
        return UNKNOWN
    end
end

.bitwise_cp0(s0, s1) ⇒ Object

Bitwise cp without processing of the x and z states.



739
740
741
# File 'lib/HDLRuby/hruby_bstr.rb', line 739

def self.bitwise_cp0(s0,s1)
    return UNKNOWN
end

.bitwise_div(s0, s1) ⇒ Object

Bitwise mod.



805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
# File 'lib/HDLRuby/hruby_bstr.rb', line 805

def self.bitwise_div(s0,s1)
    width = s0.width
    # The zero cases.
    if s0.zero? then
        return res
    elsif s1.maybe_zero? then
        return UNKNOWN.extend(width)
    end
    # Handle the sign: the division is only performed on positive
    # numbers.
    # NOTE: we are sure that s0 and s1 are not zero since these
    # cases have been handled before.
    sign = nil
    if s0.sign == "0" then
        if s1.sign == "0" then
            sign = "0"
        elsif s1.sign == "1" then
            sign = "1"
            s1 = -s1
        else
            # Unknown sign, unkown result.
            return UNKNOWN.extend(width)
        end
    elsif s0.sign == "1" then
        s0 = -s0
        if s1.sign == "0" then
            sign = "1"
        elsif s1.sign == "1" then
            sign = "0"
            s1 = -s1
        else
            # Unknwown sign, unknown result.
            return UNKNOWN.extend(width)
        end
    else
        # Unknown sign, unknown result.
        return UNKNOWN.extend(width)
    end
    # Convert s0 and s1 to list of bits of widths of s0 and s1 -1
    # (the largest possible value).
    # s0 will serve as current remainder.
    s0 = BitString.new(s0) if s0.is_a?(Numeric)
    s1 = BitString.new(s1) if s1.is_a?(Numeric)
    s0 = s0.extend(s0.width+s1.width-1)
    s1 = s1.extend(s0.width)
    s0 = s0.to_list
    s1 = s1.to_list
    puts "first s1=#{s1}"
    # Adujst s1 to the end of s0 and the corresponding 0s in front of q
    msb = s0.reverse.index {|b| b != 0}
    steps = s0.size-msb
    self.list_shl!(s1,steps-1)
    q = [ 0 ] * (width-steps)
    # Apply the non-restoring division algorithm.
    sub = true
    puts "steps= #{steps} s0=#{s0} s1=#{s1} q=#{q}"
    (steps).times do |i|
        if sub then
            self.list_sub!(s0,s1)
        else
            self.list_add!(s0,s1)
        end
        puts "s0=#{s0}"
        # Is the result positive?
        if s0[-1] == 0 then
            # Yes, the next step is a subtraction and the current
            # result bit is one.
            sub = true
            q.unshift(1)
        elsif s0[-1] == 1 then
            # No, it is negative the next step is an addition and the
            # current result bit is zero.
            sub = false
            q.unshift(0)
        else
            # Unknown sign, the remaining of q is unknown.
            (steps-i).times { q.unshift(self.new_unknown) }
            # Still, can add the positive sign bit.
            q.push(0)
            break
        end
        self.list_shr_1!(s1)
    end
    # Generate the resulting bit string.
    puts "q=#{q}"
    q = self.list_to_bstr(q)
    puts "q=#{q}"
    # Set the sign.
    if sign == "1" then
        q = (-q).trunc(width)
    elsif q.zero? then
        q = 0
    else
        q = q.extend(width)
    end
    # Return the result.
    return q
end

.bitwise_div0(s0, s1) ⇒ Object

Bitwise div without processing of the x and z states.



800
801
802
# File 'lib/HDLRuby/hruby_bstr.rb', line 800

def self.bitwise_div0(s0,s1)
    return BitString.new("x"*(s0.width))
end

.bitwise_eq(s0, s1) ⇒ Object

Bitwise eq.



594
595
596
597
# File 'lib/HDLRuby/hruby_bstr.rb', line 594

def self.bitwise_eq(s0,s1)
    return UNKNOWN unless (s0.specified? and s1.specified?)
    return s0.str == s1.str ? TRUE : FALSE
end

.bitwise_eq0(s0, s1) ⇒ Object

Bitwise eq without processing of the x and z states.



589
590
591
# File 'lib/HDLRuby/hruby_bstr.rb', line 589

def self.bitwise_eq0(s0,s1)
    return UNKNOWN
end

.bitwise_ge(s0, s1) ⇒ Object

Bitwise ge.



726
727
728
729
730
731
732
733
734
735
# File 'lib/HDLRuby/hruby_bstr.rb', line 726

def self.bitwise_ge(s0,s1)
    lt = self.bitwise_lt(s0,s1)
    if lt.eql?(TRUE) then
        return FALSE
    elsif lt.eql?(FALSE) then
        return TRUE
    else
        return UNKNOWN
    end
end

.bitwise_ge0(s0, s1) ⇒ Object

Bitwise ge without processing of the x and z states.



721
722
723
# File 'lib/HDLRuby/hruby_bstr.rb', line 721

def self.bitwise_ge0(s0,s1)
    return UNKNOWN
end

.bitwise_gt(s0, s1) ⇒ Object

Bitwise gt.



697
698
699
# File 'lib/HDLRuby/hruby_bstr.rb', line 697

def self.bitwise_gt(s0,s1)
    return self.bitwise_lt(s1,s0)
end

.bitwise_gt0(s0, s1) ⇒ Object

Bitwise gt without processing of the x and z states.



692
693
694
# File 'lib/HDLRuby/hruby_bstr.rb', line 692

def self.bitwise_gt0(s0,s1)
    return UNKNOWN
end

.bitwise_le(s0, s1) ⇒ Object

Bitwise le.



708
709
710
711
712
713
714
715
716
717
# File 'lib/HDLRuby/hruby_bstr.rb', line 708

def self.bitwise_le(s0,s1)
    gt = self.bitwise_gt(s0,s1)
    if gt.eql?(TRUE) then
        return FALSE
    elsif gt.eql?(FALSE) then
        return TRUE
    else
        return UNKNOWN
    end
end

.bitwise_le0(s0, s1) ⇒ Object

Bitwise le without processing of the x and z states.



703
704
705
# File 'lib/HDLRuby/hruby_bstr.rb', line 703

def self.bitwise_le0(s0,s1)
    return UNKNOWN
end

.bitwise_lt(s0, s1) ⇒ Object

Bitwise lt.



606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
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
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
# File 'lib/HDLRuby/hruby_bstr.rb', line 606

def self.bitwise_lt(s0,s1)
    # # Handle the zero cases.
    # if s0.zero? then
    #     return TRUE if s1.positive?
    #     return FALSE if s1.negative? or s1.zero?
    #     return UNKNOWN
    # elsif s1.zero? then
    #     return TRUE if s0.negative?
    #     return FALSE if s0.positive? or s0.zero?
    #     return UNKNOWN
    # end
    # # Handle the unspecified sign cases.
    # unless s0.sign? then
    #     # Check both sign cases.
    #     lt_pos = self.bitwise_lt(s0[-1] = "1",s1) 
    #     lt_neg = self.bitwise_lt(s0[-1] = "0",s1) 
    #     # At least one of the results is unspecified.
    #     return UNKNOWN unless (lt_pos.specified? and lt_neg.specified?)
    #     # Both results are specified and identical.
    #     return lt_pos if lt_pos == lt_neg
    #     # Results are different.
    #     return UNKNOWN
    # end
    # unless s1.sign? then
    #     # Check both sign cases.
    #     lt_pos = self.bitwise_lt(s0,s1[-1] = "1") 
    #     lt_neg = self.bitwise_lt(s0,s1[-1] = "0") 
    #     # At least one of the results is unspecified.
    #     return UNKNOWN unless (lt_pos.specified? and lt_neg.specified?)
    #     # Both results are specified and identical.
    #     return lt_pos if lt_pos == lt_neg
    #     # Results are different.
    #     return UNKNOWN
    # end
    # # Signs are specificied.
    # # Depending on the signs
    # if s0.positive? then
    #     if s1.positive? then
    #         # s0 and s1 are positive, need to compare each bit.
    #         s0.reverse_each.zip(s1.reverse_each) do |b0,b1|
    #             # puts "b0=#{b0} b1=#{b1}, LT_T[b0][b1]=#{LT_T[b0][b1]}"
    #             case LT_T[b0][b1]
    #             when "x" then return UNKNOWN
    #             when "1" then return TRUE
    #             when "0" then
    #                 return FALSE if GT_T[b0][b1] == "1"
    #             end
    #         end
    #     elsif s1.negative? then
    #         # s0 is positive and s1 is negative.
    #         return FALSE
    #     else
    #         # The sign of s1 is undefined, comparison is undefined too.
    #         return UNKNOWN
    #     end
    # elsif s0.negative? then
    #     if s1.positive? then
    #         # s0 is negative and s1 is positive
    #         return TRUE
    #     elsif s1.negative? then
    #         # s0 and s1 are negative, need to compare each bit.
    #         s0.reverse_each.zip(s1.reverse_each) do |b0,b1|
    #             case GT_T[b0][b1]
    #             when "x" then return UNKNOWN
    #             when "1" then return FALSE
    #             when "0" then
    #                 return TRUE if LT_T[b0][b1] == "1"
    #             end
    #         end
    #     end
    # else
    #     # The sign of s0 is undefined, comparison is undefined too.
    #     return UNKNOWN
    # end

    # Check the sign of the subtraction between s0 and s1.
    case (s0-s1).sign
    when "0" then return FALSE
    when "1" then return TRUE
    else 
        return UNKNOWN
    end
end

.bitwise_lt0(s0, s1) ⇒ Object

Bitwise lt without processing of the x and z states.



601
602
603
# File 'lib/HDLRuby/hruby_bstr.rb', line 601

def self.bitwise_lt0(s0,s1)
    return UNKNOWN
end

.bitwise_mod0(s0, s1) ⇒ Object

Bitwise mod without processing of the x and z states.



906
907
908
# File 'lib/HDLRuby/hruby_bstr.rb', line 906

def self.bitwise_mod0(s0,s1)
    return BitString.new("x"*(s1.width))
end

.bitwise_mul(s0, s1) ⇒ Object

Bitwise mul.



770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
# File 'lib/HDLRuby/hruby_bstr.rb', line 770

def self.bitwise_mul(s0,s1)
    # Initialize the result to ZERO of combined s0 and s1 widths
    res = ZERO.extend(s0.width + s1.width)
    # The zero cases.
    if s0.zero? or s1.zero? then
        return res
    end
    # Convert s1 and res to lists of bits which support computation
    # between unknown bits of same values.
    s1 = s1.extend(res.width).to_list
    res = res.to_list
    # The other cases: perform a multiplication with shifts and adds.
    s0.each.lazy.take(s0.width).each do |b|
        case b
        when "1" then self.list_add!(res,s1)
        when "x","z" then self.list_add!(res,self.list_and_unknown(s1))
        end
        # puts "res=#{res} s1=#{s1}"
        self.list_shl_1!(s1)
    end
    # Add the sign row.
    case s0.sign
    when "1" then self.list_sub!(res,s1)
    when "x","z" then self.list_sub!(res,list_and_unknown(s1))
    end
    # Return the result.
    return self.list_to_bstr(res)
end

.bitwise_mul0(s0, s1) ⇒ Object

Bitwise mul without processing of the x and z states.



765
766
767
# File 'lib/HDLRuby/hruby_bstr.rb', line 765

def self.bitwise_mul0(s0,s1)
    return BitString.new("x"*(s0.width+s1.width))
end

.bitwise_neg(s) ⇒ Object

Bitwise negation



526
527
528
529
530
531
532
533
# File 'lib/HDLRuby/hruby_bstr.rb', line 526

def self.bitwise_neg(s)
    # -s = ~s + 1
    # # Not s.
    # s = BitString.bitwise_not(s)
    # # Add 1.
    # return BitString.bitwise_add(s,ONE.extend(s.width))
    return ~s + 1
end

.bitwise_neg0(s) ⇒ Object

Bitwise negation without processing of the x and z states.



521
522
523
# File 'lib/HDLRuby/hruby_bstr.rb', line 521

def self.bitwise_neg0(s)
    return BitString.new("x"*(s.width+1))
end

.bitwise_not(s) ⇒ Object

Bitwise not



555
556
557
# File 'lib/HDLRuby/hruby_bstr.rb', line 555

def self.bitwise_not(s)
    return BitString.new(s.each.map { |b| NOT_T[b] }.join.reverse)
end

.bitwise_or(s0, s1) ⇒ Object

Bitwise or



543
544
545
546
# File 'lib/HDLRuby/hruby_bstr.rb', line 543

def self.bitwise_or(s0,s1)
    res = s0.each.zip(s1.each). map { |b0,b1| OR_T[b0][b1] }.join
    return BitString.new(res.reverse)
end

.bitwise_pos(s) ⇒ Object

Bitwise positive sign: does nothing.



516
517
518
# File 'lib/HDLRuby/hruby_bstr.rb', line 516

def self.bitwise_pos(s)
    return s
end

.bitwise_shl(s0, s1) ⇒ Object

Bitwise shift left.



560
561
562
563
564
565
566
567
568
569
570
571
# File 'lib/HDLRuby/hruby_bstr.rb', line 560

def self.bitwise_shl(s0,s1)
    # puts "s0=#{s0} s1=#{s1}"
    return BitString.new("x" * s0.width) unless s1.specified?
    s1 = s1.to_numeric
    if s1 >= 0 then
        return BitString.new(s0.str + "0" * s1)
    elsif -s1 > s0.width then
        return ZERO
    else
        return s0.trim(s0.width+s1)
    end
end

.bitwise_shr(s0, s1) ⇒ Object

Bitwise shift right.



574
575
576
577
578
579
580
581
582
583
584
585
# File 'lib/HDLRuby/hruby_bstr.rb', line 574

def self.bitwise_shr(s0,s1)
    # puts "s0=#{s0} s1=#{s1}"
    return BitString.new("x" * s0.width) unless s1.specified?
    s1 = s1.to_numeric
    if s1 <= 0 then
        return BitString.new(s0.str + "0" * -s1)
    elsif s1 > s0.width then
        return ZERO
    else
        return s0.trim(s0.width-s1)
    end
end

.bitwise_sub(s0, s1) ⇒ Object

Bitwise subtraction



495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
# File 'lib/HDLRuby/hruby_bstr.rb', line 495

def self.bitwise_sub(s0,s1)
    # # Negate s1.
    # s1 = BitString.bitwise_neg(s1).trunc(s0.width)
    # # puts "s1.width = #{s1.width} s0.width = #{s0.width}"
    # # Add it to s0: but no need to add a bit since neg already added
    # # one.
    # return BitString.bitwise_add(s0,s1)
    # Perform the computation is a way to limit the propagation of
    # unspecified bits.
    # Is s1 specified?
    if s1.specified? then
        # Yes, perform -s1+s0
        return (-s1 + s0)
    else
        # No, perform s0+1+NOT(s1).
        # puts "s0=#{s0} s0+1=#{s0+1} not s1=#{bitwise_not(s1)}"
        return (s0 + 1 + bitwise_not(s1)).trunc(s0.width+1)
    end
end

.bitwise_sub0(s0, s1) ⇒ Object

Bitwise subtraction without processing of the x and z states.



490
491
492
# File 'lib/HDLRuby/hruby_bstr.rb', line 490

def self.bitwise_sub0(s0,s1)
    return BitString.new("x"*(s0.width+1))
end

.bitwise_xor(s0, s1) ⇒ Object

Bitwise xor



549
550
551
552
# File 'lib/HDLRuby/hruby_bstr.rb', line 549

def self.bitwise_xor(s0,s1)
    res = s0.each.zip(s1.each). map { |b0,b1| XOR_T[b0][b1] }.join
    return BitString.new(res.reverse)
end

.list_add!(l0, l1) ⇒ Object

Adds +l1+ to +l0+.

NOTE:

  • l0 is contains the result.
  • The result has the same size as +l0+ (no sign extension).
  • Assumes +l0+ and +l1+ have the same size.


978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
# File 'lib/HDLRuby/hruby_bstr.rb', line 978

def self.list_add!(l0,l1)
    # puts "add l0=#{l0} l1=#{l1}"
    c = 0 # Current carry.
    l0.each_with_index do |b0,i|
        b1 = l1[i]
        # puts "i=#{i} b0=#{b0} b1=#{b1} c=#{c}"
        if b0 == b1 then
            # The sum is c.
            l0[i] = c
            # The carry is b0.
            c = b0
        elsif b0 == c then
            # The sum is b1.
            l0[i] = b1
            # The carry is b0.
            c = b0
        elsif b1 == c then
            # The sum is b0.
            l0[i] = b0
            # The carry is b1.
            c = b1
        else
            l0[i] = self.new_unknown
            c = self.new_unknown
        end
    end
    return l0
end

.list_add_1!(l0) ⇒ Object

Adds 1 to +l0+.

NOTE:

  • l0 is contains the result.
  • The result has the same size as +l0+ (no sign extension).


1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
# File 'lib/HDLRuby/hruby_bstr.rb', line 1012

def self.list_add_1!(l0)
    c = 1 # Current carry.
    l0.each_with_index do |b0,i|
        if c == 0 then
            # The sum is b0.
            l0[i] = b0
            # The carry is unchanged.
        elsif b0 == 0 then
            # The sum is c.
            l0[i] = c
            # The carry is 0.
            c = 0
        elsif b0 == c then
            # The sum is 0.
            l0[i] = 0
            # The carry is b0.
            c = b0
        else
            # Both sum and carry are unknown
            l0[i] = BitString.new_unknown
            c = BitString.new_unknown
        end
    end
    return l0
end

.list_and_unknown(l) ⇒ Object

Compute the and between +l+ and an unknown value.



954
955
956
957
958
# File 'lib/HDLRuby/hruby_bstr.rb', line 954

def self.list_and_unknown(l)
    return l.map do |b|
        b == 0 ? 0 : BitString.new_unknown
    end
end

.list_not(l) ⇒ Object

Compute the not of +l+



961
962
963
964
965
966
967
968
969
970
# File 'lib/HDLRuby/hruby_bstr.rb', line 961

def self.list_not(l)
    return l.map do |b|
        case b
        when 0 then 1
        when 1 then 0
        else
            BitString.new_unknown
        end
    end
end

.list_shl!(l, x) ⇒ Object

Left shifts +l+ +x+ times.

NOTE:

  • l contains the result.
  • The result has the same size as +l+ (no sign extension).


1083
1084
1085
1086
# File 'lib/HDLRuby/hruby_bstr.rb', line 1083

def self.list_shl!(l,x)
    l.pop(x)
    l.unshift(*([0]*x))
end

.list_shl_1!(l) ⇒ Object

Left shifts +l+ once.

NOTE:

  • l contains the result.
  • The result has the same size as +l+ (no sign extension).


1060
1061
1062
1063
1064
# File 'lib/HDLRuby/hruby_bstr.rb', line 1060

def self.list_shl_1!(l)
    l.pop
    l.unshift(0)
    return l
end

.list_shr_1!(l) ⇒ Object

Right shifts +l+ once.

NOTE:

  • l contains the result.
  • The result has the same size as +l+ (no sign extension).


1071
1072
1073
1074
1075
# File 'lib/HDLRuby/hruby_bstr.rb', line 1071

def self.list_shr_1!(l)
    l.shift
    l.push(0)
    return l
end

.list_sub!(l0, l1) ⇒ Object

Subtracts +l1+ from +l0+.

NOTE:

  • l0 is contains the result.
  • The result has the same size as +l0+ (no sign extension).
  • Assumes +l0+ and +l1+ have the same size.


1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
# File 'lib/HDLRuby/hruby_bstr.rb', line 1044

def self.list_sub!(l0,l1)
    # Adds 1 to l0.
    BitString.list_add_1!(l0)
    # Adds ~l1 to l0.
    # puts "l0=#{l0} l1=#{l1} ~l1=#{self.list_not(l1)}}"
    self.list_add!(l0,self.list_not(l1))
    # puts "l0=#{l0}"
    # puts "now l0=#{l0}"
    return l0
end

.list_to_bstr(l) ⇒ Object

Converts list of bits +l+ to a bit string.



948
949
950
951
# File 'lib/HDLRuby/hruby_bstr.rb', line 948

def self.list_to_bstr(l)
    str = l.reverse_each.map { |b| b > 1 ? "x" : b }.join
    return BitString.new(str)
end

.new_unknownObject

Creates a new uniq unknown bit.



924
925
926
927
# File 'lib/HDLRuby/hruby_bstr.rb', line 924

def self.new_unknown
    @@unknown += 1
    return @@unknown
end

Instance Method Details

#[](index) ⇒ Object

Gets a bit by +index+.

NOTE: If the index is larger than the bit string width, returns the bit sign.



132
133
134
135
136
137
138
139
140
141
# File 'lib/HDLRuby/hruby_bstr.rb', line 132

def [](index)
    # Handle the negative index case.
    if index < 0 then
        return self[self.width+index]
    end
    # Process the index.
    index = index > @str.size ? @str.size : index
    # Get the corresponding bit.
    return @str[-index-1]
end

#[]=(index, value) ⇒ Object

Sets the bit at +index+ to +value+.

NOTE: when index is larger than the bit width, the bit string is sign extended accordingly.



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/HDLRuby/hruby_bstr.rb', line 147

def []=(index,value)
    # Handle the negative index case.
    if index < 0 then
        return self[self.width+index] = value
    end
    # Duplicate the bit string content to ensure immutability.
    str = @str.clone
    # Process the index.
    if index >= str.size then
        # Overflow, sign extend the bit string.
        str += str[-1] * (index-str.size+1)
    end
    # Checks and convert the value
    value = make_bit(value)
    # Sets the value to a copy of the bit string.
    str[-index-1] = value
    # Return the result as a new bit string.
    return BitString.new(str)
end

#coerce(other) ⇒ Object

Coerces.



252
253
254
# File 'lib/HDLRuby/hruby_bstr.rb', line 252

def coerce(other)
    return [BitString.new(other),self]
end

#each(&ruby_block) ⇒ Object

Iterates over the bits.

NOTE: the sign bit in comprised.

Returns an enumerator if no ruby block is given.



204
205
206
207
208
209
# File 'lib/HDLRuby/hruby_bstr.rb', line 204

def each(&ruby_block)
    # No ruby block? Return an enumerator.
    return to_enum(:each) unless ruby_block
    # A block? Apply it on each bit.
    @str.each_char.reverse_each(&ruby_block)
end

#extend(width) ⇒ Object

Extend to +width+.

NOTE:

  • if the width is already larger than +width+, do nothing.
  • preserves the sign.


194
195
196
197
# File 'lib/HDLRuby/hruby_bstr.rb', line 194

def extend(width)
   return self if width <= @str.size - 1
   return BitString.new(@str[0] * (width-@str.size+1) + @str)
end

#maybe_zero?Boolean

Tells if the bit string could be zero.

Returns:

  • (Boolean)


118
119
120
# File 'lib/HDLRuby/hruby_bstr.rb', line 118

def maybe_zero?
    return ! self.nonzero?
end

#negative?Boolean

Tells if the bit string is strictly negative.

NOTE: return false if the sign is undefined

Returns:

  • (Boolean)


101
102
103
# File 'lib/HDLRuby/hruby_bstr.rb', line 101

def negative?
    return @str[0] == "1"
end

#nonzero?Boolean

Tells if the bit string is not zero.

Returns:

  • (Boolean)


113
114
115
# File 'lib/HDLRuby/hruby_bstr.rb', line 113

def nonzero?
    return @str.each_char.any? {|b| b == "1" }
end

#positive?Boolean

Tells if the bit string is strictly.

NOTE: return false if the sign is undefined of if it is unknown if the result is zero or not.

Returns:

  • (Boolean)


94
95
96
# File 'lib/HDLRuby/hruby_bstr.rb', line 94

def positive?
    return (@str[0] == "0" and self.nonzero?)
end

#reverse_each(&ruby_block) ⇒ Object

Reverse iterates over the bits.

NOTE: the sign bit in comprised.

Returns an enumerator if no ruby block is given.



216
217
218
219
220
221
# File 'lib/HDLRuby/hruby_bstr.rb', line 216

def reverse_each(&ruby_block)
    # No ruby block? Return an enumerator.
    return to_enum(:reverse_each) unless ruby_block
    # A block? Apply it on each bit.
    @str.each_char(&ruby_block)
end

#signObject

Gets the sign of the bit string.



224
225
226
# File 'lib/HDLRuby/hruby_bstr.rb', line 224

def sign
    return @str[0]
end

#sign?Boolean

Tell if the sign is specified.

Returns:

  • (Boolean)


229
230
231
# File 'lib/HDLRuby/hruby_bstr.rb', line 229

def sign?
    return (@str[0] == "0" or @str[0] == "1")
end

#specified?Boolean

Tell if the bit string is fully specified

Returns:

  • (Boolean)


247
248
249
# File 'lib/HDLRuby/hruby_bstr.rb', line 247

def specified?
    return ! @str.match(/[xz]/)
end

#to_listObject

Converts to a list of bits where unknown or high z bits are differentiate from each other.

NOTE:

  • the sign bit is also added to the list.
  • the distinction between z and x is lost.


935
936
937
938
939
940
941
942
943
944
945
# File 'lib/HDLRuby/hruby_bstr.rb', line 935

def to_list
    return @str.each_char.reverse_each.map.with_index do |b,i|
        case b
        when "0"     then 0
        when "1"     then 1
        when "z","x" then BitString.new_unknown
        else
            raise "Internal error: invalid bit in bitstring: #{b}"
        end
    end
end

#to_numericObject

Convert the bit string to a Ruby Numeric.

NOTE: the result will be wrong is the bit string is unspecified.



236
237
238
239
240
241
242
243
244
# File 'lib/HDLRuby/hruby_bstr.rb', line 236

def to_numeric
    res = 0
    # Process the bits.
    @str[1..-1].each_char { |b| res = res << 1 | b.to_i }
    # Process the sign.
    res = res - (2**(@str.size-1)) if @str[0] == "1"
    # Return the result.
    return res
end

#to_sObject Also known as: str

Converts to a string (sign bit is comprised).



123
124
125
# File 'lib/HDLRuby/hruby_bstr.rb', line 123

def to_s
    return @str.clone
end

#to_verilogObject

Converts the system to Verilog code.



1507
1508
1509
# File 'lib/HDLRuby/hruby_verilog.rb', line 1507

def to_verilog
    return "#{self.to_s}"
end

#trim(width) ⇒ Object

Trims to +width+.

NOTE:

  • trim remove the begining of the bit string.
  • if the width is already smaller than +width+, do nothing.
  • do not preserve the sign, but keep the last bit as sign bit.


184
185
186
187
# File 'lib/HDLRuby/hruby_bstr.rb', line 184

def trim(width)
    return self if width >= @str.size-1
    return BitString.new(@str[0..width])
end

#trunc(width) ⇒ Object

Truncs to +width+.

NOTE:

  • trunc remove the end of the bit string.
  • if the width is already smaller than +width+, do nothing.
  • do not preserve the sign, but keep the last bit as sign bit.


173
174
175
176
# File 'lib/HDLRuby/hruby_bstr.rb', line 173

def trunc(width)
    return self if width >= @str.size-1
    return BitString.new(@str[(@str.size-width-1)..-1])
end

#widthObject Also known as: size

Gets the bitwidth.



85
86
87
# File 'lib/HDLRuby/hruby_bstr.rb', line 85

def width
    return @str.size
end

#zero?Boolean

Tells if the bit string is zero.

NOTE: return false if the bit string is undefined.

Returns:

  • (Boolean)


108
109
110
# File 'lib/HDLRuby/hruby_bstr.rb', line 108

def zero?
    return ! @str.each_char.any? {|b| b != "0" }
end