Class: HDLRuby::Low::Binary

Inherits:
Operation show all
Defined in:
lib/HDLRuby/hruby_low.rb,
lib/HDLRuby/hruby_low2c.rb,
lib/HDLRuby/hruby_low2hdr.rb,
lib/HDLRuby/hruby_low2vhd.rb,
lib/HDLRuby/hruby_verilog.rb,
lib/HDLRuby/hruby_low2high.rb,
lib/HDLRuby/hruby_low_mutable.rb,
lib/HDLRuby/hruby_low_skeleton.rb,
lib/HDLRuby/hruby_low_fix_types.rb,
lib/HDLRuby/hruby_low_with_bool.rb,
lib/HDLRuby/hruby_low_bool2select.rb,
lib/HDLRuby/hruby_low_casts_without_expression.rb

Overview

Describes an binary operation.

Direct Known Subclasses

High::Binary

Constant Summary

Constants included from Low2Symbol

Low2Symbol::Low2SymbolPrefix, Low2Symbol::Low2SymbolTable, Low2Symbol::Symbol2LowTable

Instance Attribute Summary collapse

Attributes inherited from Operation

#operator

Attributes inherited from Expression

#type

Attributes included from Hparent

#parent

Instance Method Summary collapse

Methods inherited from Operation

#set_operator!, #to_viz_node

Methods inherited from Expression

#break_types!, #extract_selects_to!, #fix_scope_refnames!, #leftvalue?, #replace_names!, #rightvalue?, #set_type!, #signal2subs!, #statement, #to_c_expr, #to_viz_names

Methods included from Low2Symbol

#to_sym

Methods included from Hparent

#absolute_ref, #hierarchy, #no_parent!, #scope

Constructor Details

#initialize(type, operator, left, right) ⇒ Binary

Creates a new binary expression with +type+ applying +operator+ on +left+ and +right+ children expressions. def initialize(operator,left,right)



5394
5395
5396
5397
5398
5399
5400
5401
5402
5403
5404
5405
5406
5407
5408
# File 'lib/HDLRuby/hruby_low.rb', line 5394

def initialize(type,operator,left,right)
    # Initialize as a general operation.
    super(type,operator)
    # Check and set the children.
    unless left.is_a?(Expression)
        raise AnyError, "Invalid class for an expression: #{left.class}"
    end
    unless right.is_a?(Expression)
        raise AnyError,"Invalid class for an expression: #{right.class}"
    end
    @left = left
    @right = right
    # And set their parents.
    left.parent = right.parent = self
end

Instance Attribute Details

#leftObject (readonly)

The left child.



5386
5387
5388
# File 'lib/HDLRuby/hruby_low.rb', line 5386

def left
  @left
end

#rightObject (readonly)

The right child.



5389
5390
5391
# File 'lib/HDLRuby/hruby_low.rb', line 5389

def right
  @right
end

Instance Method Details

#boolean?Boolean

Tells if the expression is boolean.

Returns:

  • (Boolean)


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

def boolean?
    case(self.operator)
    when :==,:!=,:>,:<,:>=,:<= then
        # Comparison, it is a boolean.
        return true
    when :&,:|,:^ then
        # AND, OR or XOR, boolean if both subs are boolean.
        return self.left.boolean? && self.right.boolean?
    else
        # Other cases: not boolean.
        return false
    end
end

#boolean_in_assign2selectObject

Converts booleans in assignments to select operators.



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

def boolean_in_assign2select
    # Recurse on the sub nodes.
    nleft = self.left.boolean_in_assign2select
    nright = self.right.boolean_in_assign2select
    # Is it a comparison but the parent is not a boolean?
    # or a transmit to a boolean.
    if [:==,:>,:<,:>=,:<=].include?(self.operator) &&
      ( (self.parent.is_a?(Expression) && !self.parent.type.boolean?) ||
        (self.parent.is_a?(Transmit) && !self.parent.left.type.boolean?)) then
        # Yes, create a select.
        nself = Binary.new(self.type,self.operator,nleft,nright)
        # return Select.new(self.type, "?", nself,
        return Select.new(HDLRuby::Low::Bit, "?", nself,
                # Value.new(self.type,1), Value.new(self.type,0) )
                Value.new(HDLRuby::Low::Bit,0), 
                Value.new(HDLRuby::Low::Bit,1) )
                # Value.new(HDLRuby::Low::Boolean,0),
                # Value.new(HDLRuby::Low::Boolean,1) )
    else
        # No return it as is.
        # self.set_left!(nleft)
        # self.set_right!(nright)
        # return self
        return Binary.new(self.type,self.operator,nleft,nright)
    end
end

#casts_without_expression!Object

Extracts the expressions from the casts.



247
248
249
250
251
252
253
254
255
# File 'lib/HDLRuby/hruby_low_casts_without_expression.rb', line 247

def casts_without_expression!
    # # Recurse on the sub nodes.
    # return Binary.new(self.type,self.operator,
    #                   self.left.casts_without_expression,
    #                   self.right.casts_without_expression)
    self.set_left!(self.left.casts_without_expression!)
    self.set_right!(self.right.casts_without_expression!)
    return self
end

#cloneObject

Clones the binary operator (deeply)



5490
5491
5492
5493
# File 'lib/HDLRuby/hruby_low.rb', line 5490

def clone
    return Binary.new(@type, self.operator,
                      @left.clone, @right.clone)
end

#each_deep(&ruby_block) ⇒ Object

Iterates over each object deeply.

Returns an enumerator if no ruby block is given.



5419
5420
5421
5422
5423
5424
5425
5426
5427
5428
5429
5430
# File 'lib/HDLRuby/hruby_low.rb', line 5419

def each_deep(&ruby_block)
    # No ruby block? Return an enumerator.
    return to_enum(:each_deep) unless ruby_block
    # A ruby block? First apply it to current.
    ruby_block.call(self)
    # Then apply on the type.
    self.type.each_deep(&ruby_block)
    # Then apply on the left.
    self.left.each_deep(&ruby_block)
    # Then apply on the right.
    self.right.each_deep(&ruby_block)
end

#each_node(&ruby_block) ⇒ Object Also known as: each_expression

Iterates over the expression children if any.



5449
5450
5451
5452
5453
5454
5455
# File 'lib/HDLRuby/hruby_low.rb', line 5449

def each_node(&ruby_block)
    # No ruby block? Return an enumerator.
    return to_enum(:each_node) unless ruby_block
    # A ruby block? Apply it on the children.
    ruby_block.call(@left)
    ruby_block.call(@right)
end

#each_node_deep(&ruby_block) ⇒ Object

Iterates over the nodes deeply if any.



5460
5461
5462
5463
5464
5465
5466
5467
5468
# File 'lib/HDLRuby/hruby_low.rb', line 5460

def each_node_deep(&ruby_block)
    # No ruby block? Return an enumerator.
    return to_enum(:each_node_deep) unless ruby_block
    # A ruby block? First apply it to current.
    ruby_block.call(self)
    # And recurse on the children.
    @left.each_node_deep(&ruby_block)
    @right.each_node_deep(&ruby_block)
end

#each_ref_deep(&ruby_block) ⇒ Object

Iterates over all the references encountered in the expression.

NOTE: do not iterate inside the references.



5473
5474
5475
5476
5477
5478
5479
5480
5481
# File 'lib/HDLRuby/hruby_low.rb', line 5473

def each_ref_deep(&ruby_block)
    # No ruby block? Return an enumerator.
    return to_enum(:each_ref_deep) unless ruby_block
    # puts "each_ref_deep for Binary"
    # A ruby block?
    # Recurse on the children.
    @left.each_ref_deep(&ruby_block)
    @right.each_ref_deep(&ruby_block)
end

#eql?(obj) ⇒ Boolean

Comparison for hash: structural comparison.

Returns:

  • (Boolean)


5433
5434
5435
5436
5437
5438
5439
5440
5441
# File 'lib/HDLRuby/hruby_low.rb', line 5433

def eql?(obj)
    # General comparison.
    return false unless super(obj)
    # Specific comparison.
    return false unless obj.is_a?(Binary)
    return false unless @left.eql?(obj.left)
    return false unless @right.eql?(obj.right)
    return true
end

#explicit_types(type = nil) ⇒ Object

Explicit the types conversions in the binary operation where +type+ is the expected type of the condition if any.



311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
# File 'lib/HDLRuby/hruby_low_fix_types.rb', line 311

def explicit_types(type = nil)
    # Find the larger child type.
    ctype = self.left.type.width > self.right.type.width ?
        self.left.type : self.right.type
    # Recurse on the children: match the larger type.
    op = Binary.new(self.type,self.operator,
                    self.left.explicit_types(ctype),
                    self.right.explicit_types(ctype))
    # Does the type match the operation?
    if type && !self.type.eql?(type) then
        # No create a cast.
        return Cast.new(type,op)
    else
        # Yes, return the operation as is.
        return op
    end
end

#hashObject

Hash function.



5444
5445
5446
# File 'lib/HDLRuby/hruby_low.rb', line 5444

def hash
    return [super,@left,@right].hash
end

#immutable?Boolean

Tells if the expression is immutable (cannot be written.)

Returns:

  • (Boolean)


5411
5412
5413
5414
# File 'lib/HDLRuby/hruby_low.rb', line 5411

def immutable?
    # Immutable if both children are immutable.
    return left.immutable? && right.immutable?
end

#map_nodes!(&ruby_block) ⇒ Object Also known as: map_expressions!

Maps on the child.



1465
1466
1467
1468
1469
1470
# File 'lib/HDLRuby/hruby_low_mutable.rb', line 1465

def map_nodes!(&ruby_block)
    @left  = ruby_block.call(@left)
    @left.parent = self unless @left.parent
    @right = ruby_block.call(@right)
    @right.parent = self unless @right.parent
end

#replace_expressions!(node2rep) ⇒ Object

Replaces sub expressions using +node2rep+ table indicating the node to replace and the corresponding replacement. Returns the actually replaced nodes and their corresponding replacement.

NOTE: the replacement is duplicated.



1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
# File 'lib/HDLRuby/hruby_low_mutable.rb', line 1480

def replace_expressions!(node2rep)
    # First recurse on the children.
    res = self.left.replace_expressions!(node2rep)
    res.merge!(self.right.replace_expressions!(node2rep))
    # Is there a replacement to do on the left?
    rep = node2rep[self.left]
    if rep then
        # Yes, do it.
        rep = rep.clone
        node = self.left
        # node.set_parent!(nil)
        self.set_left!(rep)
        # And register the replacement.
        res[node] = rep
    end
    # Is there a replacement to do on the right?
    rep = node2rep[self.right]
    if rep then
        # Yes, do it.
        rep = rep.clone
        node = self.right
        # node.set_parent!(nil)
        self.set_right!(rep)
        # And register the replacement.
        res[node] = rep
    end

    return res
end

#set_left!(left) ⇒ Object

Sets the left.



1443
1444
1445
1446
1447
1448
1449
1450
1451
# File 'lib/HDLRuby/hruby_low_mutable.rb', line 1443

def set_left!(left)
    # Check and set the left.
    unless left.is_a?(Expression)
        raise AnyError,"Invalid class for an expression: #{left.class}"
    end
    @left = left
    # And set its parent.
    left.parent = self
end

#set_right!(right) ⇒ Object

Sets the right.



1454
1455
1456
1457
1458
1459
1460
1461
1462
# File 'lib/HDLRuby/hruby_low_mutable.rb', line 1454

def set_right!(right)
    # Check and set the right.
    unless right.is_a?(Expression)
        raise AnyError,"Invalid class for an expression: #{right.class}"
    end
    @right = right
    # And set its parent.
    right.parent = self
end

#to_c(res, level = 0) ⇒ Object

return res end Generates the C text of the equivalent HDLRuby code. +level+ is the hierachical level of the object. def to_c(level = 0)



2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
# File 'lib/HDLRuby/hruby_low2c.rb', line 2545

def to_c(res, level = 0)
    # Save the value pool state.
    res << (" " * (level*3)) << "PV;\n"
    # Generate the left computation.
    self.left.to_c(res,level)
    # Generate the right computation.
    self.right.to_c(res,level)
    # Generate the binary.
    res << (" " * (level*3))
    res << "binary("
    # Set the operation.
    case self.operator
    when :+ then
        res << "&add_value"
    when :- then
        res << "&sub_value"
    when :* then
        res << "&mul_value"
    when :/ then
        res << "&div_value"
    when :% then
        res << "&mod_value"
    when :** then
        res << "&pow_value"
    when :& then
        res << "&and_value"
    when :| then
        res << "&or_value"
    when :^ then
        res << "&xor_value"
    when :<<,:ls then
        res << "&shift_left_value"
    when :>>,:rs then
        res << "&shift_right_value"
    when :lr then
        res << "&rotate_left_value"
    when :rr then
        res << "&rotate_right_value"
    when :== then
        res << "&equal_value_c"
    when :!= then
        res << "&not_equal_value_c"
    when :> then
        res << "&greater_value"
    when :< then
        res << "&lesser_value"
    when :>= then
        res << "&greater_equal_value"
    when :<= then
        res << "&lesser_equal_value"
    else
        raise "Invalid binary operator: #{self.operator}."
    end
    # Close the computation.
    res << ");\n"
    # Restore the value pool state.
    res << (" " * (level*3)) << "RV;\n"

    return res
end

#to_change(mode) ⇒ Object

Method called when two or more expression terms are present. When translating par into seq mode = seq, when translating seq to par mode = par. Search recursively and replace if hash matches identifier.



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
218
# File 'lib/HDLRuby/hruby_verilog.rb', line 188

def to_change(mode)
    # Recursively search the left side and the right side, check the identifier and replace it.
    if self.left.is_a? (Binary) then
        # If there is an expression on the left side of the right side, to_chang is executed again.
        left = self.left.to_change(mode)
    else
        # If you need to replace the variable, replace it. Otherwise we will get a clone.
        if FmI.fm_par.has_key?(self.left.to_verilog) && mode == :par then
            left = FmI.fm_par["#{self.left.to_verilog}"]
        elsif FmI.fm_seq.has_key?(self.left.to_verilog) && mode == :seq then
            left = FmI.fm_seq["#{self.left.to_verilog}"]
        else
            left = self.left.clone
        end
    end
    if self.right.is_a? (Binary) then
        # Recursively search the right side and the right side, check the identifier and replace it.
        right = self.right.to_change(mode)
    else
        # If you need to replace the variable, replace it. Otherwise we will get a clone.
        if FmI.fm_par.has_key?(self.right.to_verilog) && mode == :par then
            right = FmI.fm_par["#{self.right.to_verilog}"]
        elsif FmI.fm_seq.has_key?(self.right.to_verilog) && mode == :seq then
            right = FmI.fm_seq["#{self.right.to_verilog}"]
        else
            right = self.right.clone
        end
    end
    # After confirmation, we create and return an expression.
    return Binary.new(self.type,self.operator,left.clone,right.clone)
end

#to_hdr(level = 0) ⇒ Object

Generates the text of the equivalent hdr text. +level+ is the hierachical level of the object.



617
618
619
620
# File 'lib/HDLRuby/hruby_low2hdr.rb', line 617

def to_hdr(level = 0)
    return "(" + self.left.to_hdr(level) + self.operator.to_s + 
                 self.right.to_hdr(level) + ")"
end

#to_highObject

Creates a new high binary expression.



460
461
462
463
464
# File 'lib/HDLRuby/hruby_low2high.rb', line 460

def to_high
    return HDLRuby::High::Binary.new(self.type.to_high,self.operator,
                                     self.left.to_high,
                                     self.right.to_high)
end

#to_verilogObject

Converts the system to Verilog code.



171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/HDLRuby/hruby_verilog.rb', line 171

def to_verilog
    # In HDLRuby if on term is signed and the other is not, the
    # computation is signed.
    if self.left.type.signed? and self.right.type.unsigned? then
        return "(#{self.left.to_verilog} #{self.operator} " +
            "$signed({1'b0,#{self.right.to_verilog}}))"
    elsif self.left.type.unsigned? and right.type.signed? then
        return "($signed({1'b0,#{self.left.to_verilog}})" +
            " #{self.operator} #{self.right.to_verilog})"
    else
        return "(#{self.left.to_verilog} #{self.operator} #{self.right.to_verilog})"
    end
end

#to_vhdl(level = 0, std_logic = false) ⇒ Object

Generates the text of the equivalent HDLRuby::High code. +level+ is the hierachical level of the object. +std_logic+ tells if std_logic computation is to be done.



1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
# File 'lib/HDLRuby/hruby_low2vhd.rb', line 1313

def to_vhdl(level = 0, std_logic = false)
    # Shifts/rotate require function call.
    if [:<<, :>>, :ls, :rs, :lr, :rr].include?(self.operator) then
        # Generate the function name.
        case self.operator
        when :<<, :ls
            func = "shift_left"
        when :>>, :rs
            func = "shift_right"
        when :lr
            func = "rotate_left"
        when :rr
            function = "rotate_right"
        else
            raise AnyError, "Internal unexpected error."
        end
        res =  Low2VHDL.unarith_cast(self) + "(#{func}(" + 
               Low2VHDL.to_arith(self.left) + "," + 
               Low2VHDL.to_arith(self.right) + "))"
        res += "(0)" if std_logic # Force std_logic if required.
        return res
    end
    # Usual operators.
    # Generate the operator string.
    case self.operator
    when :&
        # puts "self.left.to_vhdl=#{self.left.to_vhdl}"
        # puts "self.right.to_vhdl=#{self.right.to_vhdl}"
        # puts "self.left.type=#{self.left.type.to_vhdl}"
        # puts "self.right.type=#{self.right.type.to_vhdl}"
        # puts "self.type=#{self.type.to_vhdl}"
        opr = " and "
    when :|
        opr = " or "
    when :^
        opr = " xor "
    when :==
        opr = " = "
    when :!=
        opr = " /= "
    else
        opr = self.operator.to_s
    end
    # Is the operator arithmetic?
    if [:+, :-, :*, :/, :%].include?(self.operator) then
        # Yes, type conversion my be required by VHDL standard.
        res = "#{Low2VHDL.unarith_cast(self)}(" +
            Low2VHDL.to_arith(self.left) + opr +
            Low2VHDL.to_arith(self.right) + ")"
        res += "(0)" if std_logic # Force std_logic if required.
        return res
    # Is it a comparison ?
    elsif [:>, :<, :>=, :<=, :==, :!=].include?(self.operator) then
        # Generate comparison operation
        return "(" + self.left.to_vhdl(level) + opr +
            Low2VHDL.to_type(self.left.type,self.right) + ")"
    else
        # No, simply generate the binary operation
        if std_logic then
            return "(" + self.left.to_vhdl(level,std_logic) + opr + 
                self.right.to_vhdl(level,std_logic) + ")"
        else
            return "(" + self.left.to_vhdl(level) + opr + 
                Low2VHDL.to_type(self.left.type,self.right) + ")"
        end
    end
end

#use_name?(*names) ⇒ Boolean

Tell if the expression includes a signal whose name is one of +names+.

Returns:

  • (Boolean)


5484
5485
5486
5487
# File 'lib/HDLRuby/hruby_low.rb', line 5484

def use_name?(*names)
    # Recurse on the left and the right.
    return @left.use_name?(*names) || @right.use_name?(*names)
end