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

#parent

Instance Method Summary collapse

Methods included from Low2Symbol

#to_sym

Methods included from Hparent

#scope

Constructor Details

#initialize(block) ⇒ Behavior

Creates a new behavior executing +block+.



1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
# File 'lib/HDLRuby/hruby_low.rb', line 1985

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.



1982
1983
1984
# File 'lib/HDLRuby/hruby_low.rb', line 1982

def block
  @block
end

Instance Method Details

#add_event(event) ⇒ Object

Adds an +event+ to the sensitivity list.



2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
# File 'lib/HDLRuby/hruby_low.rb', line 2043

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.



2083
2084
2085
2086
2087
2088
2089
# File 'lib/HDLRuby/hruby_low.rb', line 2083

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.



2093
2094
2095
2096
2097
2098
2099
# File 'lib/HDLRuby/hruby_low.rb', line 2093

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_event(&ruby_block) ⇒ Object

Iterates over the events of the sensitivity list.

Returns an enumerator if no ruby block is given.



2057
2058
2059
2060
2061
2062
# File 'lib/HDLRuby/hruby_low.rb', line 2057

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.



2103
2104
2105
2106
2107
2108
2109
# File 'lib/HDLRuby/hruby_low.rb', line 2103

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.



2116
2117
2118
# File 'lib/HDLRuby/hruby_low.rb', line 2116

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

#eql?(obj) ⇒ Boolean

Comparison for hash: structural comparison.

Returns:

  • (Boolean)


2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
# File 'lib/HDLRuby/hruby_low.rb', line 2023

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)


2065
2066
2067
# File 'lib/HDLRuby/hruby_low.rb', line 2065

def has_event?
    return !@events.empty?
end

#hashObject

Hash function.



2036
2037
2038
# File 'lib/HDLRuby/hruby_low.rb', line 2036

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

#last_statementObject

Returns the last statement.



2128
2129
2130
# File 'lib/HDLRuby/hruby_low.rb', line 2128

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)


2075
2076
2077
2078
2079
2080
# File 'lib/HDLRuby/hruby_low.rb', line 2075

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)


2070
2071
2072
# File 'lib/HDLRuby/hruby_low.rb', line 2070

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.



2138
2139
2140
# File 'lib/HDLRuby/hruby_low.rb', line 2138

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.



2123
2124
2125
# File 'lib/HDLRuby/hruby_low.rb', line 2123

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.



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

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.



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

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.



2133
2134
2135
# File 'lib/HDLRuby/hruby_low.rb', line 2133

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