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

B2S_T =

String conversion table.

[ "0", "1", "z", "x" ]
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 NOT_T = { "0" => "1", "1" => "0", "z" => "x", "x" => "x" }

[ 1, 0, 3, 3 ]
AND_T =

And truth table: 0, 1, 2=z, 3=x AND_T = { "0" => "1"=>"0", "z"=>"0", "x"=>"0", # 0 line "1" => "1"=>"1", "z"=>"x", "x"=>"x", # 1 line "z" => "1"=>"x", "z"=>"x", "x"=>"x", # z line "x" => "1"=>"x", "z"=>"x", "x"=>"x" } # x line

[ [ 0, 0, 0, 0 ],   # 0 line
[ 0, 1, 3, 3 ],   # 1 line
[ 0, 3, 3, 3 ],   # z line
[ 0, 3, 3, 3 ] ]
OR_T =

Or truth table: 0, 1, 2=z, 3=x OR_T = { "0" => "1"=>"1", "z"=>"x", "x"=>"x", # 0 line "1" => "1"=>"1", "z"=>"1", "x"=>"1", # 1 line "z" => "1"=>"1", "z"=>"x", "x"=>"x", # z line "x" => "1"=>"1", "z"=>"x", "x"=>"x" } # x line

[ [ 0, 1, 3, 3 ],   # 0 line
[ 1, 1, 1, 1 ],   # 1 line
[ 3, 1, 3, 3 ],   # z line
[ 3, 1, 3, 3 ] ]
XOR_T =

Xor truth table: 0, 1, 2=z, 3=x XOR_T = { "0" => "1"=>"1", "z"=>"x", "x"=>"x", # 0 line "1" => "1"=>"0", "z"=>"x", "x"=>"x", # 1 line "z" => "1"=>"x", "z"=>"x", "x"=>"x", # z line "x" => "1"=>"x", "z"=>"x", "x"=>"x" } # x line

[ [ 0, 1, 3, 3 ],   # 0 line
[ 1, 0, 3, 3 ],   # 1 line
[ 3, 3, 3, 3 ],   # z line
[ 3, 3, 3, 3 ] ]
LOGIC_T =
[ AND_T, OR_T, XOR_T ]

Instance Method Summary collapse

Constructor Details

#initialize(val, opt = false) ⇒ BitString

Creates a new bit string from +val+. NOTE:* +val+ can be a Numeric or a String. * when +opt+ is :raw, val is considered to be the raw content.



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
83
84
85
86
87
88
89
# File 'lib/HDLRuby/hruby_bstr.rb', line 47

def initialize(val, opt = false)
    # puts "val=#{val} val.class=#{val.class} opt=#{opt}"
    if opt == :raw then
        @content = [*val]
    elsif val.is_a?(Numeric) then
        # Content is a numeric.
        @content = []
        if val == 0 then
            @content << 0
        elsif val > 0 then
            while val > 0 do
                @content << (val & 1)
                val /= 2
            end
            @content << 0
        else
            while val < -1 do
                @content << (val & 1)
                val /= 2
            end
            @content << 1
        end
    else
        # Content is not a numeric nor a BitString.
        @content = []
        # Ensure it is a string.
        val = val.to_s.downcase
        val.each_byte.reverse_each do |c|
            case c
            when 48  # "0"
                @content << 0
            when 49  # "1"
                @content << 1
            when 120 # "x"
                @content << 3
            when 122 # "z"
                @content << 2
            else
                raise "Invalid bit: #{b.chr}"
            end
        end
    end
end

Instance Method Details

#[](index) ⇒ Object

Gets a bit by +index+. If +index+ is a range it is a range access.

NOTE: * Assumes index is a numeric or a range of numerics. * Access is compatible with Ruby array access and not with hardware access, e.g., 0..4 is not reversed. This is compatible with sub access of Numeric. * If the index is larger than the bit string width, returns the bit sign.



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/HDLRuby/hruby_bstr.rb', line 172

def [](index)
    if index.is_a?(Range) then
        # Process the left index.
        left = index.first
        left = left.to_i
        # Adjust left to @content size.
        left += @content.size if left < 0
        left = left >= @content.size ? @content.size-1 : left
        # Process the right index.
        right = index.last
        right = right.to_i
        # Adjust right to @content size.
        right += @content.size if right < 0
        right = right >= @content.size ? @content.size-1 : right
        # Do the access.
        if right >= left then
            # puts "left=#{left} right=#{right}"
            # Get the corresponding bits as a BitString
            # return BitString.new(@content[left..right],:raw)
            # set to positive.
            return BitString.new(@content[left..right]+[0],:raw)
        else
            # Get the corresponding bits as a BitString
            # return BitString.new(@content[right..left].reverse,:raw)
            # set to positive.
            return BitString.new(@content[right..left].reverse+[0],:raw)
        end
    else
        # Process the index.
        index = index.to_i
        # Handle the negative index case.
        if index < 0 then
            return self[self.width+index]
        end
        # Process the index.
        index = index >= @content.size ? @content.size-1 : index
        b = @content[index]
        if b < 2 then
            # b is specified return it as an Numeric.
            return b
        else
            # b is not specified, create a new BitString.
            return BitString.new(b,:raw)
        end
    end
end

#[]=(index, value) ⇒ Object

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

NOTE: * Assumes index is a numeric or a range of numerics. * Access is compatible with Ruby array access and not with hardware access, e.g., 0..4 is not reversed. This is compatible with sub access of Numeric. * when index is larger than the bit width, the bit string is X extended accordingly.



227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
# File 'lib/HDLRuby/hruby_bstr.rb', line 227

def []=(index,value)
    # puts "first @content=#{@content}"
    # Change inside the bit string, it is not know any longer if it
    # is specified or not
    @specified = nil
    # Process according to the kind of index.
    if index.is_a?(Range) then
        # Process the left index.
        left = index.first
        left = left.to_i
        # Adjust left and @content size.
        left += @content.size if left < 0
        if left >= @content.size then
            # Overflow, sign extend the content.
            sign = @content[-1]
            @content.concat([sign] * (left-@content.size+1))
        end
        # Process the right index.
        right = index.last
        right = right.to_i
        # Adjust right and @content size.
        right += @content.size if right < 0
        if right >= @content.size then
            # Overflow, sign extend the bit string.
            sign = @content[-1]
            @content.concat([sign] * (right-@content.size+1))
        end
        # puts "left=#{left} right=#{right} sign=#{sign} @content=#{@content}"
        if right >= left then
            # Sets the value to a copy of the bit string.
            @content[left..right] = value.is_a?(BitString) ?
                value.raw_content[0..right-left] : 
                (right-left+1).times.map do |i|
                    value[i]
                end
        else
            # Sets the value to a copy of the bit string.
            @content[right..left] = value.is_a?(BitString) ?
                value.raw_content[left-right..0] : 
                (left-right).down_to(0).map do |i|
                    value[i]
                end
        end
        # puts "now @content=#{@content}"
    else
        # Process the index.
        index = index.to_i
        # Handle the negative index case.
        if index < 0 then
            return self[@content.size+index] = value
        end
        # Process the index.
        if index >= @content.size then
            # Overflow, sign extend the bit string.
            sign = @content[-1]
            @content.concat([sign] * (index-@content.size+1))
        end
        # Sets the value to the bit string.
        @content[index] = value[0]
    end
    return value
end

#cloneObject

Clone the bit string.



92
93
94
# File 'lib/HDLRuby/hruby_bstr.rb', line 92

def clone
    return BitString.new(@content,:raw)
end

#coerce(other) ⇒ Object

Coerces.



417
418
419
420
421
422
423
# File 'lib/HDLRuby/hruby_bstr.rb', line 417

def coerce(other)
    if other.is_a?(Numeric) && self.specified? then
        return [other,self.to_i]
    else
        return [BitString.new(other),self]
    end
end

#each(&ruby_block) ⇒ Object

Iterates over the bits.

NOTE: the sign bit in comprised.

Returns an enumerator if no ruby block is given.



355
356
357
358
359
360
# File 'lib/HDLRuby/hruby_bstr.rb', line 355

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

#eql?(bstr) ⇒ Boolean

Hash comparison.

Returns:

  • (Boolean)


116
117
118
# File 'lib/HDLRuby/hruby_bstr.rb', line 116

def eql?(bstr)
    return @content.eql?(bstr.raw_content)
end

#maybe_zero?Boolean

Tells if the bit string could be zero.

Returns:

  • (Boolean)


154
155
156
# File 'lib/HDLRuby/hruby_bstr.rb', line 154

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)


137
138
139
# File 'lib/HDLRuby/hruby_bstr.rb', line 137

def negative?
    return (@content[-1] == 1)
end

#nonzero?Boolean

Tells if the bit string is not zero.

Returns:

  • (Boolean)


149
150
151
# File 'lib/HDLRuby/hruby_bstr.rb', line 149

def nonzero?
    return @content.any? {|b| b == 1 }
end

#positive!Object

Force the BitSting to be positive by appending a 0 is required.



129
130
131
132
# File 'lib/HDLRuby/hruby_bstr.rb', line 129

def positive!
    @content << 0 if @content[-1] != 0
    return self
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)


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

def positive?
    return (@content[-1] == 0)
end

#raw_contentObject

Give access to the raw content. NOTE: the content is not copied, so there is a risk of side effect.



111
112
113
# File 'lib/HDLRuby/hruby_bstr.rb', line 111

def raw_content
    return @content
end

#reverse!(width) ⇒ Object

Reverse the content of the bit string assuming a bit width of +width+.



98
99
100
101
102
103
104
105
106
# File 'lib/HDLRuby/hruby_bstr.rb', line 98

def reverse!(width)
    # Ensure content is large enough.
    if @content.size < width then
        @content.concat(content[-1]*(width-@content.size))
    else
        @content.trunc!(width)
    end
    @content.reverse!
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.



367
368
369
370
371
372
# File 'lib/HDLRuby/hruby_bstr.rb', line 367

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.
    @content.reverse_each(&ruby_block)
end

#specified?Boolean

Tell if the bit string is fully specified

Returns:

  • (Boolean)


411
412
413
414
# File 'lib/HDLRuby/hruby_bstr.rb', line 411

def specified?
    @specified = ! @content.any? {|b| b > 1 } if @specified == nil
    return @specified
end

#to_iObject

Convert the bit string to a Ruby Numeric.

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



401
402
403
404
405
406
407
408
# File 'lib/HDLRuby/hruby_bstr.rb', line 401

def to_i
    # Compute the 2-complement's value.
    res = 0
    @content.reverse_each { |b| res = res * 2 | b }
    # Fix the sign.
    res = -((1 << @content.size) - res) if @content[-1] == 1
    return res
end

#to_sObject Also known as: str

Converts to a string (sign bit is comprised).



159
160
161
# File 'lib/HDLRuby/hruby_bstr.rb', line 159

def to_s
    return @content.reverse_each.map { |b| B2S_T[b] }.join
end

#to_verilogObject

Converts the system to Verilog code.



1516
1517
1518
# File 'lib/HDLRuby/hruby_verilog.rb', line 1516

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

#trunc!(width) ⇒ Object

Truncs to +width+.

NOTE:

  • trunc remove the end of the bit string.
  • if the width is already smaller or equal than +width+, do nothing.


295
296
297
298
# File 'lib/HDLRuby/hruby_bstr.rb', line 295

def trunc!(width)
    return self if width >= @content.size
    @content.pop(width-@content.size)
end

#zero?Boolean

Tells if the bit string is zero.

NOTE: return false if the bit string is undefined.

Returns:

  • (Boolean)


144
145
146
# File 'lib/HDLRuby/hruby_bstr.rb', line 144

def zero?
    return ! @content.any? {|b| b != 0 }
end