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

Constructor Details

#initialize(block) ⇒ Behavior

Creates a new behavior executing +block+.



2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
# File 'lib/HDLRuby/hruby_low.rb', line 2154

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.



2151
2152
2153
# File 'lib/HDLRuby/hruby_low.rb', line 2151

def block
  @block
end

Instance Method Details

#add_event(event) ⇒ Object

Adds an +event+ to the sensitivity list.



2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
# File 'lib/HDLRuby/hruby_low.rb', line 2215

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.



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

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.



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

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.



2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
# File 'lib/HDLRuby/hruby_low.rb', line 2302

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.



2229
2230
2231
2232
2233
2234
# File 'lib/HDLRuby/hruby_low.rb', line 2229

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.



2275
2276
2277
2278
2279
2280
2281
# File 'lib/HDLRuby/hruby_low.rb', line 2275

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.



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

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

#eql?(obj) ⇒ Boolean

Comparison for hash: structural comparison.

Returns:

  • (Boolean)


2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
# File 'lib/HDLRuby/hruby_low.rb', line 2195

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!



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

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)


2237
2238
2239
# File 'lib/HDLRuby/hruby_low.rb', line 2237

def has_event?
    return !@events.empty?
end

#hashObject

Hash function.



2208
2209
2210
# File 'lib/HDLRuby/hruby_low.rb', line 2208

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

#last_statementObject

Returns the last statement.



2316
2317
2318
# File 'lib/HDLRuby/hruby_low.rb', line 2316

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)


2247
2248
2249
2250
2251
2252
# File 'lib/HDLRuby/hruby_low.rb', line 2247

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)


2242
2243
2244
# File 'lib/HDLRuby/hruby_low.rb', line 2242

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.



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

def parent_system
    return self.top_scope.parent
end

#replace_names!(former, nname) ⇒ Object

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



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

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.



2295
2296
2297
# File 'lib/HDLRuby/hruby_low.rb', line 2295

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

    # 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



790
791
792
793
794
795
796
797
798
799
800
801
802
803
# File 'lib/HDLRuby/hruby_low2c.rb', line 790

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.



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

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.



2321
2322
2323
# File 'lib/HDLRuby/hruby_low.rb', line 2321

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