class HDLRuby::Low::Behavior

Describes a behavior.

Describes a behavior.

Extends the Behavior class with generation of C text.

Extends the Behavior class with generation of hdr text.

Add the conversion to high.

Extends the Behavior class with functionality for converting par block to seq.

Extends the Behavior class with conversion to symbol.

Extends the Behavior class with generation of HDLRuby::High text.

Extends the Behavior class with fixing of types and constants.

Describes a behavior.

Extends the Behaviour class for converting types of comparison and operations on it to boolean type.

Extends the Behavior class with separation between signals and variables.

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

Attributes

block[R]

The block executed by the behavior.

Public Class Methods

new(block) click to toggle source

Creates a new behavior executing block.

# File lib/HDLRuby/hruby_low.rb, line 2107
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

Public Instance Methods

add_event(event) click to toggle source

Adds an event to the sensitivity list.

# File lib/HDLRuby/hruby_low.rb, line 2168
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!() click to toggle source

Converts the par sub blocks to seq.

# 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) click to toggle source

Deletes a event.

# 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) click to toggle source

Iterates over the blocks.

# File lib/HDLRuby/hruby_low.rb, line 2208
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) click to toggle source

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

# File lib/HDLRuby/hruby_low.rb, line 2218
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) click to toggle source

Iterates over each object deeply.

Returns an enumerator if no ruby block is given.

# File lib/HDLRuby/hruby_low.rb, line 2255
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) click to toggle source

Iterates over the events of the sensitivity list.

Returns an enumerator if no ruby block is given.

# File lib/HDLRuby/hruby_low.rb, line 2182
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) click to toggle source

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

# File lib/HDLRuby/hruby_low.rb, line 2228
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) click to toggle source

Iterates over the statements.

Returns an enumerator if no ruby block is given.

# File lib/HDLRuby/hruby_low.rb, line 2241
def each_statement(&ruby_block)
    @block.each_statement(&ruby_block)
end
eql?(obj) click to toggle source

Comparison for hash: structural comparison.

# File lib/HDLRuby/hruby_low.rb, line 2148
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!() click to toggle source

Explicit the types conversions in the scope.

# 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!() click to toggle source

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

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

# 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?() click to toggle source

Tells if there is any event.

# File lib/HDLRuby/hruby_low.rb, line 2190
def has_event?
    return !@events.empty?
end
hash() click to toggle source

Hash function.

# File lib/HDLRuby/hruby_low.rb, line 2161
def hash
    return [@events,@block].hash
end
last_statement() click to toggle source

Returns the last statement.

# File lib/HDLRuby/hruby_low.rb, line 2269
def last_statement
    @block.last_statement
end
map_events!(&ruby_block) click to toggle source

Maps on the events.

# 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!() click to toggle source

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

# 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?() click to toggle source

Tells if there is a positive or negative edge event.

# File lib/HDLRuby/hruby_low.rb, line 2200
def on_edge?
    @events.each do |event|
        return true if event.on_edge?
    end
    return false
end
on_event?(*events) click to toggle source

Tells if it is activated on one of events.

# File lib/HDLRuby/hruby_low.rb, line 2195
def on_event?(*events)
    @events.any? { |ev0| events.any? { |ev1| ev0.eql?(ev1) } }
end
parent_system() click to toggle source

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

# File lib/HDLRuby/hruby_low.rb, line 2279
def parent_system
    return self.top_scope.parent
end
replace_names!(former,nname) click to toggle source

Replaces recursively former name by nname until it is redeclared.

# 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) click to toggle source

Reverse iterates over the statements.

Returns an enumerator if no ruby block is given.

# File lib/HDLRuby/hruby_low.rb, line 2248
def reverse_each_statement(&ruby_block)
    @block.reverse_each_statement(&ruby_block)
end
set_block!(block) click to toggle source

Sets the block.

# File lib/HDLRuby/hruby_low_mutable.rb, line 374
def set_block!(block)
    self.block = block
end
to_c(level = 0, time = false) click to toggle source

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.

# File lib/HDLRuby/hruby_low2c.rb, line 586
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_ch() click to toggle source

Generates the content of the h file.

# File lib/HDLRuby/hruby_low2c.rb, line 701
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_hdr(level = 0,timed = false) click to toggle source

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.

# 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_high() click to toggle source

Creates a new high behavior.

# 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!() click to toggle source

Moves the declarations to the upper namespace.

# 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) click to toggle source

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

# 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_scope() click to toggle source

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

# File lib/HDLRuby/hruby_low.rb, line 2274
def top_scope
    return parent.top_scope
end
with_boolean!() click to toggle source

Converts to a variable-compatible system.

NOTE: the result is the same Behaviour.

# 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) click to toggle source

Converts to a variable-compatible behavior.

NOTE: the result is the same systemT.

# 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

Private Instance Methods

block=(block) click to toggle source

Sets the block if not already set.

# File lib/HDLRuby/hruby_low.rb, line 2131
def block=(block)
    # Check the 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