Class: HDLRuby::Low::Behavior

Inherits:
Base::Behavior
  • Object
show all
Includes:
Hparent, Low2Symbol
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_low2seq.rb,
lib/HDLRuby/hruby_low2sym.rb,
lib/HDLRuby/hruby_low2vhd.rb,
lib/HDLRuby/hruby_low2high.rb,
lib/HDLRuby/hruby_low_mutable.rb,
lib/HDLRuby/hruby_low_resolve.rb,
lib/HDLRuby/hruby_low_skeleton.rb,
lib/HDLRuby/hruby_low_with_var.rb,
lib/HDLRuby/hruby_low_fix_types.rb,
lib/HDLRuby/hruby_low_with_bool.rb,
lib/HDLRuby/hruby_low_without_namespace.rb

Overview

Extends the Behavior class with functionality for moving the declarations to the upper namespace.

Direct Known Subclasses

High::Behavior, TimeBehavior

Constant Summary

Constants included from Low2Symbol

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

Instance Attribute Summary collapse

Attributes included from Hparent

#parent

Instance Method Summary collapse

Methods included from Low2Symbol

#to_sym

Methods included from Hparent

#hierarchy, #no_parent!, #scope

Constructor Details

#initialize(block) ⇒ Behavior

Creates a new behavior executing +block+.



2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
# File 'lib/HDLRuby/hruby_low.rb', line 2192

def initialize(block)
    # Initialize the sensitivity list.
    @events = []
    # Check and set the block.
    return unless block # No block case
    # There is a block
    self.block = block
    # unless block.is_a?(Block)
    #     raise AnyError, "Invalid class for a block: #{block.class}."
    # end
    # # Time blocks are only supported in Time Behaviors.
    # if block.is_a?(TimeBlock)
    #     raise AnyError, "Timed blocks are not supported in common behaviors."
    # end
    # # Set the block's parent.
    # block.parent = self
    # # And set the block
    # @block = block
end

Instance Attribute Details

#blockObject

The block executed by the behavior.



2189
2190
2191
# File 'lib/HDLRuby/hruby_low.rb', line 2189

def block
  @block
end

Instance Method Details

#add_event(event) ⇒ Object

Adds an +event+ to the sensitivity list.



2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
# File 'lib/HDLRuby/hruby_low.rb', line 2253

def add_event(event)
    unless event.is_a?(Event)
        raise AnyError, "Invalid class for a event: #{event.class}"
    end
    # Set the event's parent.
    event.parent = self
    # And add the event.
    @events << event
    event
end

#blocks2seq!Object

Converts the par sub blocks to seq.



62
63
64
65
66
# File 'lib/HDLRuby/hruby_low2seq.rb', line 62

def blocks2seq!
    # Converts the block to seq.
    self.block.to_seq!
    return self
end

#delete_event!(event) ⇒ Object

Deletes a event.



400
401
402
403
404
405
406
407
408
# File 'lib/HDLRuby/hruby_low_mutable.rb', line 400

def delete_event!(event)
    if @events.include?(event) then
        # The event is present, delete it.
        @events.delete(event)
        # And remove its parent.
        event.parent = nil
    end
    event
end

#each_block(&ruby_block) ⇒ Object

Iterates over the blocks.



2293
2294
2295
2296
2297
2298
2299
# File 'lib/HDLRuby/hruby_low.rb', line 2293

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

#each_block_deep(&ruby_block) ⇒ Object

Iterates over all the blocks of the system type and its system instances.



2303
2304
2305
2306
2307
2308
2309
# File 'lib/HDLRuby/hruby_low.rb', line 2303

def each_block_deep(&ruby_block)
    # No ruby block? Return an enumerator.
    return to_enum(:each_block_deep) unless ruby_block
    # A ruby block?
    # Recurse.
    @block.each_block_deep(&ruby_block)
end

#each_deep(&ruby_block) ⇒ Object

Iterates over each object deeply.

Returns an enumerator if no ruby block is given.



2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
# File 'lib/HDLRuby/hruby_low.rb', line 2340

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 each event.
    self.each_event do |event|
        event.each_deep(&ruby_block)
    end
    # Then apply on the block.
    self.block.each_deep(&ruby_block)
end

#each_event(&ruby_block) ⇒ Object

Iterates over the events of the sensitivity list.

Returns an enumerator if no ruby block is given.



2267
2268
2269
2270
2271
2272
# File 'lib/HDLRuby/hruby_low.rb', line 2267

def each_event(&ruby_block)
    # No ruby block? Return an enumerator.
    return to_enum(:each_event) unless ruby_block
    # A ruby block? Apply it on each event.
    @events.each(&ruby_block)
end

#each_node_deep(&ruby_block) ⇒ Object

Iterates over all the nodes of the system type and its system instances.



2313
2314
2315
2316
2317
2318
2319
# File 'lib/HDLRuby/hruby_low.rb', line 2313

def each_node_deep(&ruby_block)
    # No ruby block? Return an enumerator.
    return to_enum(:each_node_deep) unless ruby_block
    # A ruby block?
    # Recurse on the block.
    @block.each_node_deep(&ruby_block)
end

#each_statement(&ruby_block) ⇒ Object

Iterates over the statements.

Returns an enumerator if no ruby block is given.



2326
2327
2328
# File 'lib/HDLRuby/hruby_low.rb', line 2326

def each_statement(&ruby_block)
    @block.each_statement(&ruby_block)
end

#eql?(obj) ⇒ Boolean

Comparison for hash: structural comparison.

Returns:

  • (Boolean)


2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
# File 'lib/HDLRuby/hruby_low.rb', line 2233

def eql?(obj)
    return false unless obj.is_a?(Behavior)
    idx = 0
    obj.each_event do |event|
        return false unless @events[idx].eql?(event)
        idx += 1
    end
    return false unless idx == @events.size
    return false unless @block.eql?(obj.block)
    return true
end

#explicit_types!Object

Explicit the types conversions in the scope.



46
47
48
49
50
# File 'lib/HDLRuby/hruby_low_fix_types.rb', line 46

def explicit_types!
    # Fix the types of the block.
    self.block.explicit_types!
    return self
end

#extract_declares!Object

Extract the declares from the scope and returns them into an array.

NOTE: do not recurse into the sub scopes or behaviors!



445
446
447
448
# File 'lib/HDLRuby/hruby_low_without_namespace.rb', line 445

def extract_declares!
    # Recurse on the block.
    return self.block.extract_declares!
end

#get_by_name(name) ⇒ Object

Find an inner object by +name+. NOTE: return nil if not found.



65
66
67
68
69
70
# File 'lib/HDLRuby/hruby_low_resolve.rb', line 65

def get_by_name(name)
    if (self.block.name == name.to_sym) then
        return self.block
    end
    return self.block.get_by_name(name)
end

#has_event?Boolean

Tells if there is any event.

Returns:

  • (Boolean)


2275
2276
2277
# File 'lib/HDLRuby/hruby_low.rb', line 2275

def has_event?
    return !@events.empty?
end

#hashObject

Hash function.



2246
2247
2248
# File 'lib/HDLRuby/hruby_low.rb', line 2246

def hash
    return [@events,@block].hash
end

#last_statementObject

Returns the last statement.



2354
2355
2356
# File 'lib/HDLRuby/hruby_low.rb', line 2354

def last_statement
    @block.last_statement
end

#map_events!(&ruby_block) ⇒ Object

Maps on the events.



391
392
393
394
395
396
397
# File 'lib/HDLRuby/hruby_low_mutable.rb', line 391

def map_events!(&ruby_block)
    @events.map! do |event|
        event = ruby_block.call(event)
        event.parent = self unless event.parent
        event
    end
end

#mixblocks2seq!Object

Converts the par sub blocks to seq if they are not full par.



69
70
71
72
73
74
75
# File 'lib/HDLRuby/hruby_low2seq.rb', line 69

def mixblocks2seq!
    # Is the block mix?
    return unless block.mix?
    # Mixed, do convert.
    # Converts the block to seq.
    self.block.to_seq!
end

#on_edge?Boolean

Tells if there is a positive or negative edge event.

Returns:

  • (Boolean)


2285
2286
2287
2288
2289
2290
# File 'lib/HDLRuby/hruby_low.rb', line 2285

def on_edge?
    @events.each do |event|
        return true if event.on_edge?
    end
    return false
end

#on_event?(*events) ⇒ Boolean

Tells if it is activated on one of +events+.

Returns:

  • (Boolean)


2280
2281
2282
# File 'lib/HDLRuby/hruby_low.rb', line 2280

def on_event?(*events)
    @events.any? { |ev0| events.any? { |ev1| ev0.eql?(ev1) } }
end

#parent_systemObject

Gets the parent system, i.e., the parent of the top scope.



2364
2365
2366
# File 'lib/HDLRuby/hruby_low.rb', line 2364

def parent_system
    return self.top_scope.parent
end

#replace_names!(former, nname) ⇒ Object

Replaces recursively +former+ name by +nname+ until it is redeclared.



451
452
453
454
# File 'lib/HDLRuby/hruby_low_without_namespace.rb', line 451

def replace_names!(former,nname)
    # Recurse on the block.
    self.block.replace_names!(former,nname)
end

#reverse_each_statement(&ruby_block) ⇒ Object

Reverse iterates over the statements.

Returns an enumerator if no ruby block is given.



2333
2334
2335
# File 'lib/HDLRuby/hruby_low.rb', line 2333

def reverse_each_statement(&ruby_block)
    @block.reverse_each_statement(&ruby_block)
end

#set_block!(block) ⇒ Object

Sets the block.



386
387
388
# File 'lib/HDLRuby/hruby_low_mutable.rb', line 386

def set_block!(block)
    self.block = block
end

#to_c(res, level = 0, time = false) ⇒ Object

Generates the text of the equivalent HDLRuby code. +level+ is the hierachical level of the object and +time+ is a flag telling if the behavior is timed or not. def to_c(level = 0, time = false)



661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
# File 'lib/HDLRuby/hruby_low2c.rb', line 661

def to_c(res, level = 0, time = false)
    # puts "For behavior: #{self}"
    # # The resulting string.
    # res = ""

    # Declare the global variable holding the behavior.
    res << "Behavior " << Low2C.obj_name(self) << ";\n\n"

    # Generate the code of the behavior.
    
    # The header of the behavior.
    res << " " * level*3
    res << "Behavior " << Low2C.make_name(self) << "() {\n"
    res << " " * (level+1)*3

    # Allocate the behavior.
    res << "Behavior behavior = malloc(sizeof(BehaviorS));\n"
    res << " " * (level+1)*3
    res << "behavior->kind = BEHAVIOR;\n";

    # Sets the global variable of the behavior.
    res << "\n"
    res << " " * (level+1)*3
    res << Low2C.obj_name(self) << " = behavior;\n"

    # Register it as a time behavior if it is one of them. */
    if time then
        res << " " * (level+1)*3
        res << "register_timed_behavior(behavior);\n"
    end

    # Set the owner if any.
    if self.parent then
        res << " " * (level+1)*3
        res << "behavior->owner = (Object)"
        res << Low2C.obj_name(self.parent) << ";\n"
    else
        res << "behavior->owner = NULL;\n"
    end

    # Set the behavior as not enabled. */
    res << " " * (level+1)*3
    res << "behavior->enabled = 0;\n"

    # Set the behavior as inactive. */
    res << " " * (level+1)*3
    res << "behavior->activated = 0;\n"

    # Tells if the behavior is timed or not.
    res << " " * (level+1)*3
    res << "behavior->timed = #{time ? 1 : 0};\n"
    
    # Set the active time to 0.
    res << " " * (level+1)*3
    res << "behavior->active_time = 0;\n"

    # Is it a clocked behavior?
    events = self.each_event.to_a
    if events.empty? && !self.is_a?(TimeBehavior) then
        # No events, this is not a clock behavior.
        # And it is not a time behavior neigther.
        # Generate the events list from the right values.
        # First get the references.
        refs = self.block.each_node_deep.select do |node|
            node.is_a?(RefName) && !node.leftvalue? && 
                !node.parent.is_a?(RefName) 
        end.to_a
        # Keep only one ref per signal.
        refs.uniq! { |node| node.full_name }
        # Remove the inner signals from the list.
        self.block.each_inner do |inner|
            refs.delete_if {|r| r.name == inner.name }
        end
        # Generate the event.
        events = refs.map {|ref| Event.new(:anyedge,ref.clone) }
        # Add them to the behavior for further processing.
        events.each {|event| self.add_event(event) }
    end
    # Add the events and register the behavior as activable
    # on them.
    # First allocates the array containing the events.
    res << " " * (level+1)*3
    res << "behavior->num_events = #{events.size};\n"
    res << " " * (level+1)*3
    res << "behavior->events = calloc(sizeof(Event),"
    res << "behavior->num_events);\n"
    # Then, create and add them.
    events.each_with_index do |event,i|
        # puts "for event=#{event}"
        # Add the event.
        res << " " * (level+1)*3
        # res << "behavior->events[#{i}] = #{event.to_c};\n"
        res << "behavior->events[#{i}] = "
        event.to_c(res)
        res << ";\n"
        
        # Register the behavior as activable on this event.
        # Select the active field.
        field = "any"
        field = "pos" if event.type == :posedge
        field = "neg" if event.type == :negedge
        # puts "Adding #{field} event: #{event}\n"
        # Get the target signal access
        # sigad = event.ref.resolve.to_c_signal
        sigad = ""
        event.ref.resolve.to_c_signal(sigad)
        # Add the behavior to the relevant field.
        res << " " * (level+1)*3
        res << "#{sigad}->num_#{field} += 1;\n"
        res << " " * (level+1)*3
        res << "#{sigad}->#{field} = realloc(#{sigad}->#{field},"
        res << "#{sigad}->num_#{field}*sizeof(Object));\n"
        res << "#{sigad}->#{field}[#{sigad}->num_#{field}-1] = "
        res << "(Object)behavior;\n"
    end

    # Adds the block.
    res << " " * (level+1)*3
    res << "behavior->block = " << Low2C.make_name(self.block) << "();\n"

    # Generate the Returns of the result.
    res << "\n"
    res << " " * (level+1)*3
    res << "return behavior;\n"

    # Close the behavior makeing.
    res << " " * level*3
    res << "}\n\n"
    return res
end

#to_ch(res) ⇒ Object

Generates the content of the h file. def to_ch



794
795
796
797
798
799
800
801
802
803
804
805
806
807
# File 'lib/HDLRuby/hruby_low2c.rb', line 794

def to_ch(res)
    # res = ""
    # Declare the global variable holding the signal.
    res << "extern Behavior " << Low2C.obj_name(self) << ";\n\n"

    # Generate the access to the function making the behavior.
    res << "extern Behavior " << Low2C.make_name(self) << "();\n\n"

    # Generate the accesses to the block of the behavior.
    # res << self.block.to_ch
    self.block.to_ch(res)

    return res;
end

#to_hdr(level = 0, timed = false) ⇒ Object

Generates the text of the equivalent hdr text. +level+ is the hierachical level of the object and +timed+ tells if the behavior is a time behavior or not.



251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
# File 'lib/HDLRuby/hruby_low2hdr.rb', line 251

def to_hdr(level = 0,timed = false)
    # The resulting string.
    res = " " * (level*3)
    # Generate the header.
    if timed then
        res << "timed"
    else
        res << self.block.mode.to_s
    end
    if self.each_event.any? then
        res << "( "
        res << self.each_event.map do |event|
            event.to_hdr(level)
        end.join(", ")
        res << " )"
    end
    res << " do\n"
    # Generate the content.
    res << self.block.to_hdr(level+1,false)
    # Close the behavior.
    res << " " * (level*3) << "end\n"
    # Return the result.
    return res
end

#to_highObject

Creates a new high behavior.



130
131
132
133
134
135
136
# File 'lib/HDLRuby/hruby_low2high.rb', line 130

def to_high
    # Create the resulting behavior.
    res = HDLRuby::High::Behavior.new(self.block.to_high)
    # Adds the events.
    self.each_event { |ev| res.add_event(ev.to_high) }
    return res
end

#to_upper_space!Object

Moves the declarations to the upper namespace.



437
438
439
440
# File 'lib/HDLRuby/hruby_low_without_namespace.rb', line 437

def to_upper_space!
    # Recurse on the block.
    self.block.to_upper_space!
end

#to_vhdl(level = 0) ⇒ Object

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



748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
# File 'lib/HDLRuby/hruby_low2vhd.rb', line 748

def to_vhdl(level = 0)
    # Gather the variables.
    # It is assumed that the inners are all in declared in the
    # direct sub block and that they represent variables, i.e.,
    # Low::to_upper_space! and Low::with_var! has been called.
    vars = self.block.each_inner.to_a

    # The resulting string.
    res = ""

    # Generate the TimeRepeat as different processes if any.
    self.block.each_statement_deep do |stmnt|
        if stmnt.is_a?(TimeRepeat) then
            res << stmnt.process_to_vhdl(vars,level)
        end
    end

    # Generate the header.
    res << " " * (level*3)
    unless  self.block.name.empty? then
        res << Low2VHDL.vhdl_name(self.block.name) << ": "
    end
    res << "process "
    # Generate the senitivity list if not a timed block.
    unless self.block.is_a?(TimeBlock) then
        if self.each_event.any? then
            # If there is a clock.
            res << "("
            res << self.each_event.map do |event|
                event.ref.to_vhdl(level)
            end.join(", ")
            res << ")"
        else
            # If no clock, generate the sensitivity list from the right
            # values.
            list = self.block.each_node_deep.select do |node|
                node.is_a?(RefName) && !node.leftvalue? && 
                    !node.parent.is_a?(RefName) &&
                    # Also skip the variables
                    !vars.find {|var| var.name == node.name }
            end.to_a
            # Keep only one ref per signal.
            list.uniq! { |node| node.name }
            # Generate the sensitivity list from it.
            res << "("
            res << list.map {|node| node.to_vhdl(level) }.join(", ")
            res << ")"
        end
    end
    res << "\n"
    # Generate the variables.
    vars.each do |var|
        res << " " * ((level+1)*3)
        res << "variable "
        res << Low2VHDL.vhdl_name(var.name) << ": " 
        res << var.type.to_vhdl << ";\n"
    end

    # Generate the content.
    res << " " * (level*3)
    res << "begin\n"
    # Generate the edges if any.
    if self.each_event.find {|event| event.type != :change} then
        # Generate the edge test.
        level = level + 1
        res << " " * (level*3)
        res << "if ("
        res << self.each_event.map do |event|
            if event.type == :posedge then
                "rising_edge(" << event.ref.to_vhdl(level) << ")"
            else
                "falling_edge(" << event.ref.to_vhdl(level)<< ")"
            end
            # The change mode is not an edge!
        end.join(" and ")
        res << ") then\n"
        # Generate the body.
        res << self.block.to_vhdl(vars,level+2)
        # Close the edge test.
        res << " " * (level*3)
        res << "end if;\n"
        level = level - 1
    else
        # Generate the body directly.
        res << self.block.to_vhdl(vars,level+1)
    end
    # Insert an infinite wait is the top block is a timed block.
    if self.block.is_a?(TimeBlock) then
        res << " " * ((level+1)*3)
        res << "wait;\n"
    end
    # Close the process.
    res << " " * (level*3)
    res << "end process;\n\n"
    # Return the result.
    return res
end

#top_scopeObject

Gets the top scope, i.e. the first scope of the current system.



2359
2360
2361
# File 'lib/HDLRuby/hruby_low.rb', line 2359

def top_scope
    return parent.top_scope
end

#with_boolean!Object

Converts to a variable-compatible system.

NOTE: the result is the same Behaviour.



74
75
76
# File 'lib/HDLRuby/hruby_low_with_bool.rb', line 74

def with_boolean!
    self.each_statement  { |statement| statement.with_boolean! }
end

#with_var!(upper = nil) ⇒ Object

Converts to a variable-compatible behavior.

NOTE: the result is the same systemT.



45
46
47
48
49
# File 'lib/HDLRuby/hruby_low_with_var.rb', line 45

def with_var!(upper = nil)
    @block = @block.with_var
    @block.parent = self
    return self
end