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+.



1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
# File 'lib/HDLRuby/hruby_low.rb', line 1974

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.



1971
1972
1973
# File 'lib/HDLRuby/hruby_low.rb', line 1971

def block
  @block
end

Instance Method Details

#add_event(event) ⇒ Object

Adds an +event+ to the sensitivity list.



2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
# File 'lib/HDLRuby/hruby_low.rb', line 2032

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.



361
362
363
364
365
366
367
368
369
# File 'lib/HDLRuby/hruby_low_mutable.rb', line 361

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.



2067
2068
2069
2070
2071
2072
2073
# File 'lib/HDLRuby/hruby_low.rb', line 2067

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.



2077
2078
2079
2080
2081
2082
2083
# File 'lib/HDLRuby/hruby_low.rb', line 2077

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.



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

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.



2087
2088
2089
2090
2091
2092
2093
# File 'lib/HDLRuby/hruby_low.rb', line 2087

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.



2100
2101
2102
# File 'lib/HDLRuby/hruby_low.rb', line 2100

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

#eql?(obj) ⇒ Boolean

Comparison for hash: structural comparison.

Returns:

  • (Boolean)


2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
# File 'lib/HDLRuby/hruby_low.rb', line 2012

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)


2054
2055
2056
# File 'lib/HDLRuby/hruby_low.rb', line 2054

def has_event?
    return !@events.empty?
end

#hashObject

Hash function.



2025
2026
2027
# File 'lib/HDLRuby/hruby_low.rb', line 2025

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

#last_statementObject

Returns the last statement.



2112
2113
2114
# File 'lib/HDLRuby/hruby_low.rb', line 2112

def last_statement
    @block.last_statement
end

#map_events!(&ruby_block) ⇒ Object

Maps on the events.



352
353
354
355
356
357
358
# File 'lib/HDLRuby/hruby_low_mutable.rb', line 352

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)


2059
2060
2061
2062
2063
2064
# File 'lib/HDLRuby/hruby_low.rb', line 2059

def on_edge?
    @events.each do |event|
        return true if event.on_edge?
    end
    return false
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.



2107
2108
2109
# File 'lib/HDLRuby/hruby_low.rb', line 2107

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

#set_block!(block) ⇒ Object

Sets the block.



347
348
349
# File 'lib/HDLRuby/hruby_low_mutable.rb', line 347

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.



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

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.



690
691
692
693
694
695
696
697
698
699
700
701
702
# File 'lib/HDLRuby/hruby_low2c.rb', line 690

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.



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

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 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
    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.



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

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