Class: HDLRuby::Low::Binary

Inherits:
Operation show all
Defined in:
lib/HDLRuby/hruby_db.rb,
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

Extends the Binary class with functionality for extracting expressions from cast.

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!

Methods inherited from Expression

#break_types!, #extract_selects_to!, #leftvalue?, #replace_names!, #rightvalue?, #set_type!, #statement

Methods included from Low2Symbol

#to_sym

Methods included from Hparent

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



4778
4779
4780
4781
4782
4783
4784
4785
4786
4787
4788
4789
4790
4791
4792
# File 'lib/HDLRuby/hruby_low.rb', line 4778

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.



4770
4771
4772
# File 'lib/HDLRuby/hruby_low.rb', line 4770

def left
  @left
end

#rightObject (readonly)

The right child.



4773
4774
4775
# File 'lib/HDLRuby/hruby_low.rb', line 4773

def right
  @right
end

Instance Method Details

#boolean?Boolean

Tells if the expression is boolean.

Returns:

  • (Boolean)


116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/HDLRuby/hruby_low_with_bool.rb', line 116

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.



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/HDLRuby/hruby_low_bool2select.rb', line 211

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_expressionObject

Extracts the expressions from the casts.



238
239
240
241
242
243
# File 'lib/HDLRuby/hruby_low_casts_without_expression.rb', line 238

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

#cloneObject

Clones the binary operator (deeply)



4874
4875
4876
4877
# File 'lib/HDLRuby/hruby_low.rb', line 4874

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.



4803
4804
4805
4806
4807
4808
4809
4810
4811
4812
4813
4814
# File 'lib/HDLRuby/hruby_low.rb', line 4803

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.



4833
4834
4835
4836
4837
4838
4839
# File 'lib/HDLRuby/hruby_low.rb', line 4833

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.



4844
4845
4846
4847
4848
4849
4850
4851
4852
# File 'lib/HDLRuby/hruby_low.rb', line 4844

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.



4857
4858
4859
4860
4861
4862
4863
4864
4865
# File 'lib/HDLRuby/hruby_low.rb', line 4857

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)


4817
4818
4819
4820
4821
4822
4823
4824
4825
# File 'lib/HDLRuby/hruby_low.rb', line 4817

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.



269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
# File 'lib/HDLRuby/hruby_low_fix_types.rb', line 269

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.



4828
4829
4830
# File 'lib/HDLRuby/hruby_low.rb', line 4828

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

#immutable?Boolean

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

Returns:

  • (Boolean)


4795
4796
4797
4798
# File 'lib/HDLRuby/hruby_low.rb', line 4795

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

#map_nodes!(&ruby_block) ⇒ Object

Maps on the child.



1491
1492
1493
1494
1495
1496
# File 'lib/HDLRuby/hruby_low_mutable.rb', line 1491

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.



1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
# File 'lib/HDLRuby/hruby_low_mutable.rb', line 1504

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.



1469
1470
1471
1472
1473
1474
1475
1476
1477
# File 'lib/HDLRuby/hruby_low_mutable.rb', line 1469

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.



1480
1481
1482
1483
1484
1485
1486
1487
1488
# File 'lib/HDLRuby/hruby_low_mutable.rb', line 1480

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(level = 0) ⇒ Object

Generates the C text of the equivalent HDLRuby code. +level+ is the hierachical level of the object.



1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
# File 'lib/HDLRuby/hruby_low2c.rb', line 1699

def to_c(level = 0)
    # res = " " * (level*3)
    res = "({\n"
    # Overrides the upper src0, src1 and dst...
    # And allocates a new value for dst.
    res << (" " * ((level+1)*3))
    res << "Value src0,src1,dst = get_value();\n"
    # Save the state of the value pool.
    res << (" " * ((level+1)*3))
    res << "unsigned int pool_state = get_value_pos();\n"
    # Compute the left.
    res << (" " * ((level+1)*3))
    res << "src0 = #{self.left.to_c(level+2)};\n"
    # Compute the right.
    res << (" " * ((level+1)*3))
    res << "src1 = #{self.right.to_c(level+2)};\n"
    res << (" " * ((level+1)*3))

    # Compute the current binary operation.
    case self.operator
    when :+ then
        res += "dst = add_value(src0,src1,dst);\n"
    when :- then
        res += "dst = sub_value(src0,src1,dst);\n"
    when :* then
        res += "dst = mul_value(src0,src1,dst);\n"
    when :/ then
        res += "dst = div_value(src0,src1,dst);\n"
    when :% then
        res += "dst = mod_value(src0,src1,dst);\n"
    when :** then
        res += "dst = pow_value(src0,src1,dst);\n"
    when :& then
        res += "dst = and_value(src0,src1,dst);\n"
    when :| then
        res += "dst = or_value(src0,src1,dst);\n"
    when :^ then
        res += "dst = xor_value(src0,src1,dst);\n"
    when :<<,:ls then
        res += "dst = shift_left_value(src0,src1,dst);\n"
    when :>>,:rs then
        res += "dst = shift_right_value(src0,src1,dst);\n"
    when :lr then
        res += "dst = rotate_left_value(src0,src1,dst);\n"
    when :rr then
        res += "dst = rotate_right_value(src0,src1,dst);\n"
    when :== then
        res += "dst = equal_value(src0,src1,dst);\n" +
               "dst = reduce_or_value(dst,dst);"
    when :!= then
        # res += "dst = not_equal_value(src0,src1,dst);\n"
        res += "dst = xor_value(src0,src1,dst);\n" +
               "dst = reduce_or_value(dst,dst);"
    when :> then
        res += "dst = greater_value(src0,src1,dst);\n"
    when :< then
        res += "dst = lesser_value(src0,src1,dst);\n"
    when :>= then
        res += "dst = greater_equal_value(src0,src1,dst);\n"
    when :<= then
        res += "dst = lesser_equal_value(src0,src1,dst);\n"
    else
        raise "Invalid binary operator: #{self.operator}."
    end
    # Restore the state of the value pool.
    res << (" " * ((level+1)*3))
    res << "set_value_pos(pool_state);\n"
    # Close the computation.
    res << (" " * (level*3))
    res << "dst; })"

    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.



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/HDLRuby/hruby_verilog.rb', line 71

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 $fm.fm_par.has_key?(self.left.to_verilog) && mode == :par then
            left = $fm.fm_par["#{self.left.to_verilog}"]
        elsif $fm.fm_seq.has_key?(self.left.to_verilog) && mode == :seq then
            left = $fm.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 $fm.fm_par.has_key?(self.right.to_verilog) && mode == :par then
            right = $fm.fm_par["#{self.right.to_verilog}"]
        elsif $fm.fm_seq.has_key?(self.right.to_verilog) && mode == :seq then
            right = $fm.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.



599
600
601
602
# File 'lib/HDLRuby/hruby_low2hdr.rb', line 599

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.



426
427
428
429
430
# File 'lib/HDLRuby/hruby_low2high.rb', line 426

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.



64
65
66
# File 'lib/HDLRuby/hruby_verilog.rb', line 64

def to_verilog
    return "(#{self.left.to_verilog} #{self.operator} #{self.right.to_verilog})"
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.



1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
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
# File 'lib/HDLRuby/hruby_low2vhd.rb', line 1273

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)


4868
4869
4870
4871
# File 'lib/HDLRuby/hruby_low.rb', line 4868

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