module HDLRuby::High::Std

Standard HDLRuby::High library: universal generic function generator based on the work of Ryota Sakai from NN4H

Public Class Methods

_included_fixpoint(base)
Alias for: included
channel(name,&ruby_block) click to toggle source

Creates a new channel type named name whose instances are creating executing ruby_block.

# File lib/HDLRuby/std/channel.rb, line 62
def self.channel(name,&ruby_block)
    return ChannelT.new(name,&ruby_block)
end
channel_instance(name,*args,&ruby_block) click to toggle source

Creates directly an instance of channel named name using ruby_block built with args.

# File lib/HDLRuby/std/channel.rb, line 74
def self.channel_instance(name,*args,&ruby_block)
    # return ChannelT.new(:"",&ruby_block).instantiate(name,*args)
    return self.channel(:"",&ruby_block).instantiate(name,*args)
end
channel_port(obj) click to toggle source

Wrap object obj to act like a channel port.

# File lib/HDLRuby/std/channel.rb, line 1412
def self.channel_port(obj)
    return obj if obj.is_a?(ChannelPort) # No need to wrap.
    return ChannelPortObject.new(obj)
end
included(base) click to toggle source

Redefines the include to add fixed point generation through the Type class.

# File lib/HDLRuby/std/fixpoint.rb, line 15
def self.included(base)
    # Performs the previous included
    res = self.send(:_included_fixpoint,base)
    # Now modify the Type class if not already modified.
    unless ::HDLRuby::High::Type.instance_methods.include?(:"_[]_fixpoint") then
        ::HDLRuby::High::Type.class_eval do
            # Saves the former type generation method.
            alias_method :"_[]_fixpoint", :[]

            # Redefine the type generation method for supporting fixed point
            # type generation.
            def [](*args)
                if args.size == 1 then
                    return self.send(:"_[]_fixpoint",*args)
                else
                    # Handle the arguments and compute the fix point sizes.
                    arg0,arg1 = *args
                    if arg0.respond_to?(:to_i) then
                        isize = arg0
                    else
                        isize = (arg0.first-arg0.last).abs+1
                    end
                    if arg1.respond_to?(:to_i) then
                        fsize = arg1
                    else
                        fsize = (arg1.first-arg1.last).abs+1
                    end
                    # Build the type.
                    case(self.name)
                    when :bit
                        typ = bit[isize+fsize].typedef(::HDLRuby.uniq_name)
                    when :unsigned
                        typ = unsigned[isize+fsize].typedef(::HDLRuby.uniq_name)
                    when :signed
                        typ = signed[isize+fsize].typedef(::HDLRuby.uniq_name)
                    else
                        raise "Invalid type for generating a fixed point type: #{self.name}"
                    end
                    # Redefine the multiplication and division for fixed point.
                    typ.define_operator(:*) do |left,right|
                        if (typ.signed?) then
                            (left.as(signed[isize+fsize*2])*right) >> fsize
                        else
                            (left.as([isize+fsize*2])*right) >> fsize
                        end
                    end
                    typ.define_operator(:/) do |left,right|
                        if (typ.signed?) then
                            (left.as(signed[isize+fsize*2]) << fsize) / right
                        else
                            (left.as([isize+fsize*2]) << fsize) / right
                        end
                    end
                    # Define the removal of the point.
                    typ.define_singleton_method(:no_point) do
                        if (typ.signed?) then
                            signed[typ.width]
                        else
                            bit[typ.width]
                        end
                    end
                    # Return the resulting typ.
                    typ
                end
            end
            return res
        end
    end
end
Also aliased as: _included_fixpoint
task(name,&ruby_block) click to toggle source

Creates a new task type named name whose instances are creating executing ruby_block.

# File lib/HDLRuby/std/task.rb, line 60
def self.task(name,&ruby_block)
    return TaskT.new(name,&ruby_block)
end
task_instance(name,*args,&ruby_block) click to toggle source

Creates directly an instance of task named name using ruby_block built with args.

# File lib/HDLRuby/std/task.rb, line 72
def self.task_instance(name,*args,&ruby_block)
    # return TaskT.new(:"",&ruby_block).instantiate(name,*args)
    return self.task(:"",&ruby_block).instantiate(name,*args)
end

Public Instance Methods

[](*args) click to toggle source

Redefine the type generation method for supporting fixed point type generation.

# File lib/HDLRuby/std/fixpoint.rb, line 26
def [](*args)
    if args.size == 1 then
        return self.send(:"_[]_fixpoint",*args)
    else
        # Handle the arguments and compute the fix point sizes.
        arg0,arg1 = *args
        if arg0.respond_to?(:to_i) then
            isize = arg0
        else
            isize = (arg0.first-arg0.last).abs+1
        end
        if arg1.respond_to?(:to_i) then
            fsize = arg1
        else
            fsize = (arg1.first-arg1.last).abs+1
        end
        # Build the type.
        case(self.name)
        when :bit
            typ = bit[isize+fsize].typedef(::HDLRuby.uniq_name)
        when :unsigned
            typ = unsigned[isize+fsize].typedef(::HDLRuby.uniq_name)
        when :signed
            typ = signed[isize+fsize].typedef(::HDLRuby.uniq_name)
        else
            raise "Invalid type for generating a fixed point type: #{self.name}"
        end
        # Redefine the multiplication and division for fixed point.
        typ.define_operator(:*) do |left,right|
            if (typ.signed?) then
                (left.as(signed[isize+fsize*2])*right) >> fsize
            else
                (left.as([isize+fsize*2])*right) >> fsize
            end
        end
        typ.define_operator(:/) do |left,right|
            if (typ.signed?) then
                (left.as(signed[isize+fsize*2]) << fsize) / right
            else
                (left.as([isize+fsize*2]) << fsize) / right
            end
        end
        # Define the removal of the point.
        typ.define_singleton_method(:no_point) do
            if (typ.signed?) then
                signed[typ.width]
            else
                bit[typ.width]
            end
        end
        # Return the resulting typ.
        typ
    end
end
after(init, rst = $rst, clk = $clk, &code) click to toggle source

Sets a counter to init when rst is 1 that is decreased according to clk. When this counter reaches 0, code is executed. When not within a block, a behavior will be created which is activated on the rising edge of clk.

# File lib/HDLRuby/std/counters.rb, line 65
def after(init, rst = $rst, clk = $clk, &code)
    with_counter(init,rst,clk) do |counter|
        seq do
            hif(rst.to_expr == 1) do
                counter.to_ref <= init.to_expr
            end
            helsif(counter.to_expr == 0) do
                # code.call
                instance_eval(&code)
            end
            helse do
                counter.to_ref <= counter.to_expr - 1
            end
        end
    end
end
before(init, rst = $rst, clk = $clk, &code) click to toggle source

Sets a counter to init when rst is 1 that is decreased according to clk. As long as this counter does not reach 0, code is executed. When not within a block, a behavior will be created which is activated on the rising edge of clk.

# File lib/HDLRuby/std/counters.rb, line 45
def before(init, rst = $rst, clk = $clk, &code)
    with_counter(init,rst,clk) do |counter|
        seq do
            hif(rst.to_expr == 1) do
                counter.to_ref <= init.to_expr
            end
            helsif(counter.to_expr != 0) do
                counter.to_ref <= counter.to_expr - 1
                # code.call
                instance_eval(&code)
            end
        end
    end
end
channel(name,&ruby_block) click to toggle source

Creates a new channel type named name whose instances are creating executing ruby_block.

# File lib/HDLRuby/std/channel.rb, line 68
def channel(name,&ruby_block)
    HDLRuby::High::Std.channel(name,&ruby_block)
end
channel_instance(name,*args,&ruby_block) click to toggle source

Creates directly an instance of channel named name using ruby_block built with args.

# File lib/HDLRuby/std/channel.rb, line 81
def channel_instance(name,*args,&ruby_block)
    HDLRuby::High::Std.channel_instance(name,*args,&ruby_block)
end
channel_port(obj) click to toggle source
# File lib/HDLRuby/std/channel.rb, line 1416
def channel_port(obj)
    return HDLRuby::High::Std.channel_port(obj)
end
configure_clocks(rst = $rst) click to toggle source

Initialize the clock generator with rst as reset signal.

# File lib/HDLRuby/std/clocks.rb, line 10
def configure_clocks(rst = $rst)
    @@__clocks_rst = rst
end
decoder(*args, &ruby_block) click to toggle source

Declare a new decoder. The arguments can be any of (but in this order):

  • name

    name.

  • expr

    the expression to decode.

If provided, ruby_block the fsm is directly instantiated with it.

# File lib/HDLRuby/std/decoder.rb, line 194
def decoder(*args, &ruby_block)
    # Sets the name if any
    unless args[0].respond_to?(:to_expr) then
        name = args.shift.to_sym
    else
        name = :""
    end
    # Create the decoder.
    decoderI = DecoderT.new(name)

    # Is there a ruby block?
    if ruby_block then
        # Yes, generate the decoder.
        decoderI.build(*args,&ruby_block)
    else
        # No return the decoder structure for later generation.
        return decoderI
    end
end
fsm(*args, &ruby_block) click to toggle source

Declare a new fsm. The arguments can be any of (but in this order):

  • name

    name.

  • clk

    clock.

  • event

    clock event.

  • rst

    reset. (must be declared AFTER clock or clock event).

If provided, ruby_block the fsm is directly instantiated with it.

# File lib/HDLRuby/std/fsm.rb, line 486
def fsm(*args, &ruby_block)
    # Sets the name if any
    unless args[0].respond_to?(:to_event) then
        name = args.shift.to_sym
    else
        name = :""
    end
    # Get the options from the arguments.
    options, args = args.partition {|arg| arg.is_a?(Symbol) }
    # Create the fsm.
    fsmI = FsmT.new(name,*options)
    
    # Process the clock event if any.
    unless args.empty? then
        fsmI.for_event(args.shift)
    end
    # Process the reset if any.
    unless args.empty? then
        fsmI.for_reset(args.shift)
    end
    # Is there a ruby block?
    if ruby_block then
        # Yes, generate the fsm.
        fsmI.build(&ruby_block)
    else
        # No return the fsm structure for later generation.
        return fsmI
    end
end
initialize_lut(func, otyp, awidth, xrange, yrange) click to toggle source

Make an array consists of a point of any activation function. @param [Integer] lut_size the lut_size of LUT @return [Array] table an array consists of a point of tanh

# File lib/HDLRuby/std/function_generator.rb, line 123
def initialize_lut(func, otyp, awidth, xrange, yrange)
    # Compute the x step between discret values.
    xstep = (xrange.last-xrange.first)/(2 ** awidth)

    # Generate the discrete set of x values.
    x_values = xrange.step(xstep)
    # Generate the table.
    table = x_values.map do |x_value|
        ((func.call(x_value)-yrange.first)/(yrange.last-yrange.first)*
         2**otyp.width).to_i.to_expr.as(otyp)
    end

    return table
end
make_2edge_clock(event,times) click to toggle source

Creates a clock inverted every times occurence of an event and its everted.

# File lib/HDLRuby/std/clocks.rb, line 84
def make_2edge_clock(event,times)
    clock = nil # The resulting clock

    # Enters the current system
    HDLRuby::High.cur_system.open do
        # Ensure times is a value.
        times = times.to_value

        # Create the event counter.
        # Create the name of the counter.
        name = HDLRuby.uniq_name
        # Declare the counter.
        [times.width].inner(name)
        # Get the signal of the counter.
        counter = get_inner(name)

        # Create the inverted event counter.
        # Create the name of the counter.
        name = HDLRuby.uniq_name
        # Declare the counter.
        [times.width].inner(name)
        # Get the signal of the counter.
        counter_inv = get_inner(name)

        # Create the clock.
        # Create the name of the clock.
        name = HDLRuby.uniq_name
        # Declare the clock.
        bit.inner(name)
        # Get the signal of the clock.
        clock = get_inner(name)

        # Control the event counter
        par(event) do
            hif(@@__clocks_rst | counter.to_expr == 0) do
                counter.to_ref <= times.to_expr/2 + 1
            end
        end
        # Control the inverteed event counter
        par(event.invert) do
            hif(@@__clocks_rst | counter_inv.to_expr == 0) do
                counter_inv.to_ref <= times.to_expr/2 + 1
            end
        end
        # Compute the clock.
        clock.to_ref <= (counter.to_expr == times.to_expr/2 + 1) |
            (counter_inv.to_expr == times.to_expr/2 + 1)
    end
    # Return it.
    return clock
end
make_clock(event, times) click to toggle source

Create a clock inverted every times occurence of an event.

# File lib/HDLRuby/std/clocks.rb, line 15
def make_clock(event, times)
    clock = nil # The resulting clock

    # Enters the current system
    HDLRuby::High.cur_system.open do

        # Ensures times is a value.
        times = times.to_value

        # Create the counter.
        # Create the name of the counter.
        name = HDLRuby.uniq_name
        # Declare the counter.
        [times.width].inner(name)
        # Get the signal of the counter.
        counter = get_inner(name)

        # Create the clock.
        # Create the name of the clock.
        name = HDLRuby.uniq_name
        # Declares the clock.
        bit.inner(name)
        # Get the signal of the clock.
        clock = get_inner(name)
        
        # Control it.
        par(event) do
            hif(@@__clocks_rst) do
                counter.to_ref <= times.to_expr
                clock.to_ref <= 0
            end
            helsif(counter.to_expr == 0) do
                counter.to_ref <= times.to_expr 
                clock.to_ref <= ~ clock.to_expr
            end
            helse do
                counter.to_ref <= counter.to_expr + 1
            end
        end
    end
    return clock
end
pipeline(name) click to toggle source

Declare a new pipeline with name.

# File lib/HDLRuby/std/pipeline.rb, line 216
def pipeline(name)
    return PipelineT.new(name)
end
reconf(name,&ruby_block) click to toggle source

Creates a new reconfigurable component type named name whose instances are creating executing ruby_block.

# File lib/HDLRuby/std/reconf.rb, line 59
def reconf(name,&ruby_block)
    # puts "reconf with ruby_block=#{ruby_block}"
    return ReconfT.new(name,&ruby_block)
end
req_ack(clk_e,req,ack,port) click to toggle source

Encapsulate a task for integrating a control with simple request and acknowledge (ack) signals, synchronised on clk_e. port is assumed to return a TaskPortSA. If clk_e is nil, work in asynchronous mode.

# File lib/HDLRuby/std/task.rb, line 846
def req_ack(clk_e,req,ack,port)
    rst_req_ack(clk_e,nil,req,ack,port)
end
rst_req_ack(clk_e,rst,req,ack,port) click to toggle source

Encapsulate a task for integrating a control with simple reset (rst), request and acknowledge (ack) signals, synchronised on clk_e. port is assumed to return a TaskPortSA. If clk_e is nil, work in asynchronous mode. If rst is nil, no reset is handled.

# File lib/HDLRuby/std/task.rb, line 814
def rst_req_ack(clk_e,rst,req,ack,port)
    if clk_e then
        # Ensures clk_e is an event.
        clk_e = clk_e.posedge unless clk_e.is_a?(Event)
        par(clk_e) do
            # Handle the reset.
            hif(rst) { port.reset } if rst
            ack <= 0
            # Control the start of the task.
            hif(req) { port.run }
            # Control the end of the task: set ack to 1.
            port.finish { ack <= 1 }
        end
    else
        par do
            # Handle the reset
            hif(rst) { port.reset } if rst
            # Control the start of the task.
            hif(req) { port.run }
            ack <= 0
            # Control the end of the task: set ack to 1.
            port.finish { ack <= 1 }
        end
    end
end
task(name,&ruby_block) click to toggle source

Creates a new task type named name whose instances are creating executing ruby_block.

# File lib/HDLRuby/std/task.rb, line 66
def task(name,&ruby_block)
    HDLRuby::High::Std.task(name,&ruby_block)
end
task_instance(name,*args,&ruby_block) click to toggle source

Creates directly an instance of task named name using ruby_block built with args.

# File lib/HDLRuby/std/task.rb, line 79
def task_instance(name,*args,&ruby_block)
    HDLRuby::High::Std.task_instance(name,*args,&ruby_block)
end
with_counter(init, rst = $rst, clk = $clk, &code) click to toggle source

Sets a counter to init when rst is 1 that is decreased according to clk. code will be applied on this counter. When not within a block, a behavior will be created which is activated on the rising edge of clk.

# File lib/HDLRuby/std/counters.rb, line 13
def with_counter(init, rst = $rst, clk = $clk, &code)
    # Are we in a block?
    if HDLRuby::High.top_user.is_a?(HDLRuby::High::SystemT) then
        # No, create a behavior.
        behavior(clk.posedge) do
            with_counter(init,rst,clk,&code)
        end
    else
        # Ensure init is a value.
        init = init.to_value
        # Creates the counter
        # counter = HDLRuby::High::SignalI.new(HDLRuby.uniq_name,
        #                           TypeVector.new(:"",bit,init.width),
        #                           :inner)
        # Create the name of the counter.
        name = HDLRuby.uniq_name
        # Declare the counter.
        [init.width].inner(name)
        # Get the signal of the counter.
        counter = HDLRuby::High.cur_block.get_inner(name)
        # Apply the code on the counter.
        # code.call(counter)
        instance_exec(counter,&code)
    end
end