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

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



4789
4790
4791
4792
4793
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
# File 'lib/HDLRuby/hruby_low.rb', line 4789

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.



4781
4782
4783
# File 'lib/HDLRuby/hruby_low.rb', line 4781

def left
  @left
end

#rightObject (readonly)

The right child.



4784
4785
4786
# File 'lib/HDLRuby/hruby_low.rb', line 4784

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



4885
4886
4887
4888
# File 'lib/HDLRuby/hruby_low.rb', line 4885

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.



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

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.



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

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.



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

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.



4868
4869
4870
4871
4872
4873
4874
4875
4876
# File 'lib/HDLRuby/hruby_low.rb', line 4868

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)


4828
4829
4830
4831
4832
4833
4834
4835
4836
# File 'lib/HDLRuby/hruby_low.rb', line 4828

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.



4839
4840
4841
# File 'lib/HDLRuby/hruby_low.rb', line 4839

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

#immutable?Boolean

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

Returns:

  • (Boolean)


4806
4807
4808
4809
# File 'lib/HDLRuby/hruby_low.rb', line 4806

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)



2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
# File 'lib/HDLRuby/hruby_low2c.rb', line 2257

def to_c(res, level = 0)
    # Save the value pool state.
    res << (" " * (level*3)) << "SV;\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.



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)


4879
4880
4881
4882
# File 'lib/HDLRuby/hruby_low.rb', line 4879

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