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
# File 'lib/HDLRuby/hruby_bstr.rb', line 34

def initialize(str,sign = nil)
    # Maybe str is an numeric.
    if str.is_a?(Numeric) then
        # Yes, convert it to a binary string.
        str = str.to_s(2)
        # And fix the sign.
        if str[0] == "-" then
            str = str[1..-1]
            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
    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



471
472
473
474
475
476
477
478
479
480
481
482
# File 'lib/HDLRuby/hruby_bstr.rb', line 471

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.



466
467
468
# File 'lib/HDLRuby/hruby_bstr.rb', line 466

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

.bitwise_and(s0, s1) ⇒ Object

Bitwise and



531
532
533
534
535
# File 'lib/HDLRuby/hruby_bstr.rb', line 531

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.



739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
# File 'lib/HDLRuby/hruby_bstr.rb', line 739

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.



734
735
736
# File 'lib/HDLRuby/hruby_bstr.rb', line 734

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

.bitwise_div(s0, s1) ⇒ Object

Bitwise mod.



800
801
802
803
804
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
# File 'lib/HDLRuby/hruby_bstr.rb', line 800

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.



795
796
797
# File 'lib/HDLRuby/hruby_bstr.rb', line 795

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

.bitwise_eq(s0, s1) ⇒ Object

Bitwise eq.



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

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.



584
585
586
# File 'lib/HDLRuby/hruby_bstr.rb', line 584

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

.bitwise_ge(s0, s1) ⇒ Object

Bitwise ge.



721
722
723
724
725
726
727
728
729
730
# File 'lib/HDLRuby/hruby_bstr.rb', line 721

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.



716
717
718
# File 'lib/HDLRuby/hruby_bstr.rb', line 716

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

.bitwise_gt(s0, s1) ⇒ Object

Bitwise gt.



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

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.



687
688
689
# File 'lib/HDLRuby/hruby_bstr.rb', line 687

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

.bitwise_le(s0, s1) ⇒ Object

Bitwise le.



703
704
705
706
707
708
709
710
711
712
# File 'lib/HDLRuby/hruby_bstr.rb', line 703

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.



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

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

.bitwise_lt(s0, s1) ⇒ Object

Bitwise lt.



601
602
603
604
605
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
# File 'lib/HDLRuby/hruby_bstr.rb', line 601

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.



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

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

.bitwise_mod0(s0, s1) ⇒ Object

Bitwise mod without processing of the x and z states.



901
902
903
# File 'lib/HDLRuby/hruby_bstr.rb', line 901

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

.bitwise_mul(s0, s1) ⇒ Object

Bitwise mul.



765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
# File 'lib/HDLRuby/hruby_bstr.rb', line 765

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.



760
761
762
# File 'lib/HDLRuby/hruby_bstr.rb', line 760

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

.bitwise_neg(s) ⇒ Object

Bitwise negation



521
522
523
524
525
526
527
528
# File 'lib/HDLRuby/hruby_bstr.rb', line 521

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.



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

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

.bitwise_not(s) ⇒ Object

Bitwise not



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

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



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

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.



511
512
513
# File 'lib/HDLRuby/hruby_bstr.rb', line 511

def self.bitwise_pos(s)
    return s
end

.bitwise_shl(s0, s1) ⇒ Object

Bitwise shift left.



555
556
557
558
559
560
561
562
563
564
565
566
# File 'lib/HDLRuby/hruby_bstr.rb', line 555

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.



569
570
571
572
573
574
575
576
577
578
579
580
# File 'lib/HDLRuby/hruby_bstr.rb', line 569

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



490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
# File 'lib/HDLRuby/hruby_bstr.rb', line 490

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.



485
486
487
# File 'lib/HDLRuby/hruby_bstr.rb', line 485

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

.bitwise_xor(s0, s1) ⇒ Object

Bitwise xor



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

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.


973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# File 'lib/HDLRuby/hruby_bstr.rb', line 973

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).


1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
# File 'lib/HDLRuby/hruby_bstr.rb', line 1007

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.



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

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+



956
957
958
959
960
961
962
963
964
965
# File 'lib/HDLRuby/hruby_bstr.rb', line 956

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).


1078
1079
1080
1081
# File 'lib/HDLRuby/hruby_bstr.rb', line 1078

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).


1055
1056
1057
1058
1059
# File 'lib/HDLRuby/hruby_bstr.rb', line 1055

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).


1066
1067
1068
1069
1070
# File 'lib/HDLRuby/hruby_bstr.rb', line 1066

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.


1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
# File 'lib/HDLRuby/hruby_bstr.rb', line 1039

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.



943
944
945
946
# File 'lib/HDLRuby/hruby_bstr.rb', line 943

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.



919
920
921
922
# File 'lib/HDLRuby/hruby_bstr.rb', line 919

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.



127
128
129
130
131
132
133
134
135
136
# File 'lib/HDLRuby/hruby_bstr.rb', line 127

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.



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/HDLRuby/hruby_bstr.rb', line 142

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.



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

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.



199
200
201
202
203
204
# File 'lib/HDLRuby/hruby_bstr.rb', line 199

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.


189
190
191
192
# File 'lib/HDLRuby/hruby_bstr.rb', line 189

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)


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

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)


96
97
98
# File 'lib/HDLRuby/hruby_bstr.rb', line 96

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

#nonzero?Boolean

Tells if the bit string is not zero.

Returns:

  • (Boolean)


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

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)


89
90
91
# File 'lib/HDLRuby/hruby_bstr.rb', line 89

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.



211
212
213
214
215
216
# File 'lib/HDLRuby/hruby_bstr.rb', line 211

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.



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

def sign
    return @str[0]
end

#sign?Boolean

Tell if the sign is specified.

Returns:

  • (Boolean)


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

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

#specified?Boolean

Tell if the bit string is fully specified

Returns:

  • (Boolean)


242
243
244
# File 'lib/HDLRuby/hruby_bstr.rb', line 242

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.


930
931
932
933
934
935
936
937
938
939
940
# File 'lib/HDLRuby/hruby_bstr.rb', line 930

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.



231
232
233
234
235
236
237
238
239
# File 'lib/HDLRuby/hruby_bstr.rb', line 231

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).



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

def to_s
    return @str.clone
end

#to_verilogObject

Converts the system to Verilog code.



1303
1304
1305
# File 'lib/HDLRuby/hruby_verilog.rb', line 1303

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.


179
180
181
182
# File 'lib/HDLRuby/hruby_bstr.rb', line 179

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.


168
169
170
171
# File 'lib/HDLRuby/hruby_bstr.rb', line 168

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.



80
81
82
# File 'lib/HDLRuby/hruby_bstr.rb', line 80

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)


103
104
105
# File 'lib/HDLRuby/hruby_bstr.rb', line 103

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