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_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

Overview

Extends the Binary class with functionality for converting booleans in assignments to select operators.

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)



4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
# File 'lib/HDLRuby/hruby_low.rb', line 4175

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.



4167
4168
4169
# File 'lib/HDLRuby/hruby_low.rb', line 4167

def left
  @left
end

#rightObject (readonly)

The right child.



4170
4171
4172
# File 'lib/HDLRuby/hruby_low.rb', line 4170

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.



197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/HDLRuby/hruby_low_bool2select.rb', line 197

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

#cloneObject

Clones the binary operator (deeply)



4249
4250
4251
4252
# File 'lib/HDLRuby/hruby_low.rb', line 4249

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

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

Iterates over the expression children if any.



4208
4209
4210
4211
4212
4213
4214
# File 'lib/HDLRuby/hruby_low.rb', line 4208

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.



4219
4220
4221
4222
4223
4224
4225
4226
4227
# File 'lib/HDLRuby/hruby_low.rb', line 4219

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.



4232
4233
4234
4235
4236
4237
4238
4239
4240
# File 'lib/HDLRuby/hruby_low.rb', line 4232

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)


4192
4193
4194
4195
4196
4197
4198
4199
4200
# File 'lib/HDLRuby/hruby_low.rb', line 4192

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.



255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# File 'lib/HDLRuby/hruby_low_fix_types.rb', line 255

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.



4203
4204
4205
# File 'lib/HDLRuby/hruby_low.rb', line 4203

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

#map_nodes!(&ruby_block) ⇒ Object

Maps on the child.



1421
1422
1423
1424
1425
1426
# File 'lib/HDLRuby/hruby_low_mutable.rb', line 1421

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.



1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
# File 'lib/HDLRuby/hruby_low_mutable.rb', line 1434

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.



1399
1400
1401
1402
1403
1404
1405
1406
1407
# File 'lib/HDLRuby/hruby_low_mutable.rb', line 1399

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.



1410
1411
1412
1413
1414
1415
1416
1417
1418
# File 'lib/HDLRuby/hruby_low_mutable.rb', line 1410

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::High code. +level+ is the hierachical level of the object.



1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
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
# File 'lib/HDLRuby/hruby_low2c.rb', line 1656

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.



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
90
91
92
93
# File 'lib/HDLRuby/hruby_verilog.rb', line 63

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

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



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

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

#to_verilogObject

Converts the system to Verilog code.



56
57
58
# File 'lib/HDLRuby/hruby_verilog.rb', line 56

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.



1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
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
# File 'lib/HDLRuby/hruby_low2vhd.rb', line 1249

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)


4243
4244
4245
4246
# File 'lib/HDLRuby/hruby_low.rb', line 4243

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