Class: HDLRuby::Low::Behavior

Inherits:
Base::Behavior
  • Object
show all
Includes:
Hdecorator, Hparent, Low2Symbol
Defined in:
lib/HDLRuby/hruby_db.rb,
lib/HDLRuby/hruby_low.rb,
lib/HDLRuby/hruby_low2c.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_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 Hdecorator

#hdr_id

Attributes included from Hparent

#parent

Instance Method Summary collapse

Methods included from Low2Symbol

#to_sym

Methods included from Hdecorator

decorate_parent_id, dump, each, each_with_property, get, included, load, #properties

Methods included from Hparent

#scope

Constructor Details

#initialize(block) ⇒ Behavior

Creates a new behavior executing +block+.



2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
# File 'lib/HDLRuby/hruby_low.rb', line 2082

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.



2079
2080
2081
# File 'lib/HDLRuby/hruby_low.rb', line 2079

def block
  @block
end

Instance Method Details

#add_event(event) ⇒ Object

Adds an +event+ to the sensitivity list.



2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
# File 'lib/HDLRuby/hruby_low.rb', line 2143

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.



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

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.



2183
2184
2185
2186
2187
2188
2189
# File 'lib/HDLRuby/hruby_low.rb', line 2183

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.



2193
2194
2195
2196
2197
2198
2199
# File 'lib/HDLRuby/hruby_low.rb', line 2193

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.



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

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.



2157
2158
2159
2160
2161
2162
# File 'lib/HDLRuby/hruby_low.rb', line 2157

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.



2203
2204
2205
2206
2207
2208
2209
# File 'lib/HDLRuby/hruby_low.rb', line 2203

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.



2216
2217
2218
# File 'lib/HDLRuby/hruby_low.rb', line 2216

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

#eql?(obj) ⇒ Boolean

Comparison for hash: structural comparison.

Returns:

  • (Boolean)


2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
# File 'lib/HDLRuby/hruby_low.rb', line 2123

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!



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

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

#has_event?Boolean

Tells if there is any event.

Returns:

  • (Boolean)


2165
2166
2167
# File 'lib/HDLRuby/hruby_low.rb', line 2165

def has_event?
    return !@events.empty?
end

#hashObject

Hash function.



2136
2137
2138
# File 'lib/HDLRuby/hruby_low.rb', line 2136

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

#last_statementObject

Returns the last statement.



2244
2245
2246
# File 'lib/HDLRuby/hruby_low.rb', line 2244

def last_statement
    @block.last_statement
end

#map_events!(&ruby_block) ⇒ Object

Maps on the events.



379
380
381
382
383
384
385
# File 'lib/HDLRuby/hruby_low_mutable.rb', line 379

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)


2175
2176
2177
2178
2179
2180
# File 'lib/HDLRuby/hruby_low.rb', line 2175

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)


2170
2171
2172
# File 'lib/HDLRuby/hruby_low.rb', line 2170

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.



2254
2255
2256
# File 'lib/HDLRuby/hruby_low.rb', line 2254

def parent_system
    return self.top_scope.parent
end

#replace_names!(former, nname) ⇒ Object

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



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

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.



2223
2224
2225
# File 'lib/HDLRuby/hruby_low.rb', line 2223

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

#set_block!(block) ⇒ Object

Sets the block.



374
375
376
# File 'lib/HDLRuby/hruby_low_mutable.rb', line 374

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

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

Generates the text of the equivalent HDLRuby::High code. +level+ is the hierachical level of the object and +time+ is a flag telling if the behavior is timed or not.



579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
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
# File 'lib/HDLRuby/hruby_low2c.rb', line 579

def to_c(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)" + 
               "#{Low2C.obj_name(self.parent)};\n"
    else
        res << "behavior->owner = NULL;\n"
    end

    # 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 }
        # 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)," +
           "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"
        
        # 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
        # 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}," +
               "#{sigad}->num_#{field}*sizeof(Object));\n"
        res << "#{sigad}->#{field}[#{sigad}->num_#{field}-1] = " +
               "(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_chObject

Generates the content of the h file.



694
695
696
697
698
699
700
701
702
703
704
705
706
# File 'lib/HDLRuby/hruby_low2c.rb', line 694

def to_ch
    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

    return res;
end

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

Generates the text of the equivalent HDLRuby::High code. +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_low2high.rb', line 251

def to_high(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_high(level)
        end.join(", ")
        res << " )"
    end
    res << " do\n"
    # Generate the content.
    res << self.block.to_high(level+1,false)
    # Close the behavior.
    res << " " * (level*3) << "end\n"
    # Return the result.
    return res
end

#to_upper_space!Object

Moves the declarations to the upper namespace.



430
431
432
433
# File 'lib/HDLRuby/hruby_low_without_namespace.rb', line 430

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.



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

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.



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

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