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



165
166
167
168
169
170
171
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
# File 'lib/HDLRuby/hruby_bstr.rb', line 165

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)
        else
            # Get the corresponding bits as a BitString
            return BitString.new(@content[right..left].reverse,: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.



216
217
218
219
220
221
222
223
224
225
226
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
# File 'lib/HDLRuby/hruby_bstr.rb', line 216

def []=(index,value)
    # 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
        if right >= left then
            # puts "left=#{left} right=#{right} value=#{value} (#{value.class})"
            # 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.



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

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

#each(&ruby_block) ⇒ Object

Iterates over the bits.

NOTE: the sign bit in comprised.

Returns an enumerator if no ruby block is given.



343
344
345
346
347
348
# File 'lib/HDLRuby/hruby_bstr.rb', line 343

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

#maybe_zero?Boolean

Tells if the bit string could be zero.

Returns:

  • (Boolean)


147
148
149
# File 'lib/HDLRuby/hruby_bstr.rb', line 147

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)


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

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

#nonzero?Boolean

Tells if the bit string is not zero.

Returns:

  • (Boolean)


142
143
144
# File 'lib/HDLRuby/hruby_bstr.rb', line 142

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

#positive!Object

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



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

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)


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

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.



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

def raw_content
    return @content
end

#reverse!(width) ⇒ Object

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



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

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.



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

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)


399
400
401
402
# File 'lib/HDLRuby/hruby_bstr.rb', line 399

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



389
390
391
392
393
394
395
396
# File 'lib/HDLRuby/hruby_bstr.rb', line 389

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



152
153
154
# File 'lib/HDLRuby/hruby_bstr.rb', line 152

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

#to_verilogObject

Converts the system to Verilog code.



1514
1515
1516
# File 'lib/HDLRuby/hruby_verilog.rb', line 1514

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.


283
284
285
286
# File 'lib/HDLRuby/hruby_bstr.rb', line 283

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)


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

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