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, #to_c_expr

Methods included from Low2Symbol

#to_sym

Methods included from Hparent

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



5034
5035
5036
5037
5038
5039
5040
5041
5042
5043
5044
5045
5046
5047
5048
# File 'lib/HDLRuby/hruby_low.rb', line 5034

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.



5026
5027
5028
# File 'lib/HDLRuby/hruby_low.rb', line 5026

def left
  @left
end

#rightObject (readonly)

The right child.



5029
5030
5031
# File 'lib/HDLRuby/hruby_low.rb', line 5029

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.



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

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.



241
242
243
244
245
246
247
248
249
# File 'lib/HDLRuby/hruby_low_casts_without_expression.rb', line 241

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)



5130
5131
5132
5133
# File 'lib/HDLRuby/hruby_low.rb', line 5130

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.



5059
5060
5061
5062
5063
5064
5065
5066
5067
5068
5069
5070
# File 'lib/HDLRuby/hruby_low.rb', line 5059

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.



5089
5090
5091
5092
5093
5094
5095
# File 'lib/HDLRuby/hruby_low.rb', line 5089

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.



5100
5101
5102
5103
5104
5105
5106
5107
5108
# File 'lib/HDLRuby/hruby_low.rb', line 5100

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.



5113
5114
5115
5116
5117
5118
5119
5120
5121
# File 'lib/HDLRuby/hruby_low.rb', line 5113

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)


5073
5074
5075
5076
5077
5078
5079
5080
5081
# File 'lib/HDLRuby/hruby_low.rb', line 5073

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.



288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
# File 'lib/HDLRuby/hruby_low_fix_types.rb', line 288

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.



5084
5085
5086
# File 'lib/HDLRuby/hruby_low.rb', line 5084

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

#immutable?Boolean

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

Returns:

  • (Boolean)


5051
5052
5053
5054
# File 'lib/HDLRuby/hruby_low.rb', line 5051

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

#map_nodes!(&ruby_block) ⇒ Object

Maps on the child.



1503
1504
1505
1506
1507
1508
# File 'lib/HDLRuby/hruby_low_mutable.rb', line 1503

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.



1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
# File 'lib/HDLRuby/hruby_low_mutable.rb', line 1516

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.



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

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.



1492
1493
1494
1495
1496
1497
1498
1499
1500
# File 'lib/HDLRuby/hruby_low_mutable.rb', line 1492

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)



2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
# File 'lib/HDLRuby/hruby_low2c.rb', line 2365

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.



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/HDLRuby/hruby_verilog.rb', line 128

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.



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.



121
122
123
# File 'lib/HDLRuby/hruby_verilog.rb', line 121

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.



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
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
# File 'lib/HDLRuby/hruby_low2vhd.rb', line 1285

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)


5124
5125
5126
5127
# File 'lib/HDLRuby/hruby_low.rb', line 5124

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