class HDLRuby::BitString
Describes a bit string.
NOTE:
-
a bit string is immutable.
-
bit strings are always signed.
-
the upper bit of a bit string is the sign.
Used to output bitstring. Enhance HDLRuby
with generation of verilog code.
Constants
- AND_T
And truth table: 0, 1, 2=z, 3=x
- BITWISE
Table of bitwise operations
- FALSE
- GT_T
Greater than truth table: 0, 1, 2=z, 3=x
- LT_T
Lower than truth table: 0, 1, 2=z, 3=x
- MAJ_T
Majority truth table: 0, 1, 2=z, 3=x
- MINUS_ONE
- MINUS_THREE
- MINUS_TWO
- NOT_T
Not truth table
- ONE
- OR_T
Or truth table: 0, 1, 2=z, 3=x
- THREE
- TRUE
A few common bit strings.
- TWO
- UNKNOWN
- XOR3_T
Double xor truth table: 0, 1, 2=z, 3=x
- XOR_T
Xor truth table: 0, 1, 2=z, 3=x
- ZERO
Public Class Methods
Bitwise addition
# 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 addition without processing of the x and z states.
# File lib/HDLRuby/hruby_bstr.rb, line 471 def self.bitwise_add0(s0,s1) return BitString.new("x"*(s0.width+1)) end
Bitwise and
# 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.
# 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 cp without processing of the x and z states.
# File lib/HDLRuby/hruby_bstr.rb, line 739 def self.bitwise_cp0(s0,s1) return UNKNOWN end
Bitwise div.
# 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 div without processing of the x and z states.
# File lib/HDLRuby/hruby_bstr.rb, line 800 def self.bitwise_div0(s0,s1) return BitString.new("x"*(s0.width)) end
Bitwise eq.
# 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 eq without processing of the x and z states.
# File lib/HDLRuby/hruby_bstr.rb, line 589 def self.bitwise_eq0(s0,s1) return UNKNOWN end
Bitwise ge.
# 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 ge without processing of the x and z states.
# File lib/HDLRuby/hruby_bstr.rb, line 721 def self.bitwise_ge0(s0,s1) return UNKNOWN end
Bitwise gt.
# File lib/HDLRuby/hruby_bstr.rb, line 697 def self.bitwise_gt(s0,s1) return self.bitwise_lt(s1,s0) end
Bitwise gt without processing of the x and z states.
# File lib/HDLRuby/hruby_bstr.rb, line 692 def self.bitwise_gt0(s0,s1) return UNKNOWN end
Bitwise le.
# 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 le without processing of the x and z states.
# File lib/HDLRuby/hruby_bstr.rb, line 703 def self.bitwise_le0(s0,s1) return UNKNOWN end
Bitwise lt.
# 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 lt without processing of the x and z states.
# File lib/HDLRuby/hruby_bstr.rb, line 601 def self.bitwise_lt0(s0,s1) return UNKNOWN end
Bitwise mod without processing of the x and z states.
# File lib/HDLRuby/hruby_bstr.rb, line 906 def self.bitwise_mod0(s0,s1) return BitString.new("x"*(s1.width)) end
Bitwise mul.
# 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 mul without processing of the x and z states.
# File lib/HDLRuby/hruby_bstr.rb, line 765 def self.bitwise_mul0(s0,s1) return BitString.new("x"*(s0.width+s1.width)) end
Bitwise negation
# 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 negation without processing of the x and z states.
# File lib/HDLRuby/hruby_bstr.rb, line 521 def self.bitwise_neg0(s) return BitString.new("x"*(s.width+1)) end
Bitwise not
# 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
# 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 positive sign: does nothing.
# File lib/HDLRuby/hruby_bstr.rb, line 516 def self.bitwise_pos(s) return s end
Bitwise shift left.
# 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 shift right.
# 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 subtraction
# 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 subtraction without processing of the x and z states.
# File lib/HDLRuby/hruby_bstr.rb, line 490 def self.bitwise_sub0(s0,s1) return BitString.new("x"*(s0.width+1)) end
Bitwise xor
# 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
Adds l1
to l0
.
NOTE:
-
l0 is contains the result.
-
The result has the same size as
l0
(no sign extension). -
Assumes
l0
andl1
have the same size.
# 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
Adds 1 to l0
.
NOTE:
-
l0 is contains the result.
-
The result has the same size as
l0
(no sign extension).
# 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
Compute the and between l
and an unknown value.
# 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
Compute the not of l
# 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
Left shifts l
x
times.
NOTE:
-
l contains the result.
-
The result has the same size as
l
(no sign extension).
# File lib/HDLRuby/hruby_bstr.rb, line 1083 def self.list_shl!(l,x) l.pop(x) l.unshift(*([0]*x)) end
Left shifts l
once.
NOTE:
-
l contains the result.
-
The result has the same size as
l
(no sign extension).
# File lib/HDLRuby/hruby_bstr.rb, line 1060 def self.list_shl_1!(l) l.pop l.unshift(0) return l end
Right shifts l
once.
NOTE:
-
l contains the result.
-
The result has the same size as
l
(no sign extension).
# File lib/HDLRuby/hruby_bstr.rb, line 1071 def self.list_shr_1!(l) l.shift l.push(0) return l end
Subtracts l1
from l0
.
NOTE:
-
l0 is contains the result.
-
The result has the same size as
l0
(no sign extension). -
Assumes
l0
andl1
have the same size.
# 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
Converts list of bits l
to a bit string.
# 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
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.
# 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
Creates a new uniq unknown bit.
# File lib/HDLRuby/hruby_bstr.rb, line 924 def self.new_unknown @@unknown += 1 return @@unknown end
Public Instance Methods
Gets a bit by index
.
NOTE: If the index is larger than the bit string width, returns the
bit sign.
# 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
Sets the bit at index
to value
.
NOTE: when index is larger than the bit width, the bit string is sign extended accordingly.
# 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
Coerces.
# File lib/HDLRuby/hruby_bstr.rb, line 252 def coerce(other) return [BitString.new(other),self] end
Iterates over the bits.
NOTE: the sign bit in comprised.
Returns an enumerator if no ruby block is given.
# 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 to width
.
NOTE:
-
if the width is already larger than
width
, do nothing. -
preserves the sign.
# 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
Tells if the bit string could be zero.
# File lib/HDLRuby/hruby_bstr.rb, line 118 def maybe_zero? return ! self.nonzero? end
Tells if the bit string is strictly negative.
NOTE: return false if the sign is undefined
# File lib/HDLRuby/hruby_bstr.rb, line 101 def negative? return @str[0] == "1" end
Tells if the bit string is not zero.
# File lib/HDLRuby/hruby_bstr.rb, line 113 def nonzero? return @str.each_char.any? {|b| b == "1" } end
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.
# File lib/HDLRuby/hruby_bstr.rb, line 94 def positive? return (@str[0] == "0" and self.nonzero?) end
Reverse iterates over the bits.
NOTE: the sign bit in comprised.
Returns an enumerator if no ruby block is given.
# 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
Gets the sign of the bit string.
# File lib/HDLRuby/hruby_bstr.rb, line 224 def sign return @str[0] end
Tell if the sign is specified.
# File lib/HDLRuby/hruby_bstr.rb, line 229 def sign? return (@str[0] == "0" or @str[0] == "1") end
Tell if the bit string is fully specified
# File lib/HDLRuby/hruby_bstr.rb, line 247 def specified? return ! @str.match(/[xz]/) end
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.
# 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
Convert the bit string to a Ruby Numeric
.
NOTE: the result will be wrong is the bit string is unspecified.
# 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
Converts to a string (sign bit is comprised).
# File lib/HDLRuby/hruby_bstr.rb, line 123 def to_s return @str.clone end
Converts the system to Verilog
code.
# File lib/HDLRuby/hruby_verilog.rb, line 1442 def to_verilog return "#{self.to_s}" end
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.
# 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
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.
# 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
Gets the bitwidth.
# File lib/HDLRuby/hruby_bstr.rb, line 85 def width return @str.size end
Tells if the bit string is zero.
NOTE: return false if the bit string is undefined.
# File lib/HDLRuby/hruby_bstr.rb, line 108 def zero? return ! @str.each_char.any? {|b| b != "0" } end