Mira
Mira

Reputation: 2161

How to receive an input bus in MyHDL?

I'm trying to learn MyHDL and for that I was trying to create a very simple artificial neuron that could later be used in a simple artificial neural network. First I designed an artificial neuron that could only handle a single input and weight signal and returned an output signal.

@block
def input_perceptron(clk, max_res, in_signal, w_signal, out_signal):
    '''a hidden layer neuron
    out_signal is the result of: transfer_function( input_i x weight_i )
    '''
    @always(clk.posedge)
    def logic():
        # Multiply inputs and scale down with the shift
        weighted_signal = (in_signal * w_signal) >> max_res+1
        # Perform desired transfer function
        tf_result = rect_transfer_func( weighted_signal, max_res )
        # Assign new result
        out_signal.next = tf_result
    # The perceptron block must return this - MyHDL syntax
    return instances()

To convert it to Verilog I used another function:

def converter(max_res=16, hdl='Verilog'):
    # Initialize Signals
    max_val    = 1 << max_res + 1
    clk        = Signal( bool(0) )
    in_signal  = Signal( intbv( randrange(max_val), min=0, max=max_val ) )
    w_signal   = Signal( intbv( randrange(max_val), min=0, max=max_val ) )
    out_signal = Signal( intbv( 0,                  min=0, max=max_val ) )
    # Instantiate component
    perceptron_inst = input_perceptron(clk, max_res, in_signal, w_signal, out_signal)
    # Convert component to desired HDL language
    perceptron_inst.convert(hdl=hdl)

Everything was going great so far. Not only were the simulations showing me what I expected, but also the converted code was correct and I was able to synthesize it in Vivado. However, in a neural network, the hidden and output layer neurons must be able to handle information coming from multiple sources, a.k.a a list or bus of signals, and this is where I'm having trouble.

By using MyHDL's and Python's amazing functions for running simulations I was able to correctly simulate a simple perceptron with the following code by using lists of signals for the inputs and weights:

@block
def perceptron(clk, max_val, max_res, in_bus, w_bus, out_signal):
    ''' Perceptron
    out_signal is the result of: transfer_function( sum( input_i x weight_i ) )
    '''
    @always(clk.posedge)
    def logic():
        # Multiply inputs and scale down
        sum_weighted_inputs = 0
        for i in range(len(in_bus)):
            weighted_input = in_bus[i] * w_bus[i] >> max_res+1
            sum_weighted_inputs += weighted_input
        # Perform desired transfer function
        tf = step_transfer_func(sum_weighted_inputs, max_res, max_val)
        # Assign new result to ouput port
        out_signal.next = tf
    return instances()

After going through the docs (docs) I understood that in MyHDL a block can't use a list of signals as a port, and that according to this chapter I should convert my list of signals into a ConcatSignal, which I did like so:

def converter(max_res, num_inputs, hdl='Verilog'):
    # Clock parameters
    clk        = Signal( bool(0) )
    # Signal parameters: inputs, weights and outputs
    max_val    = 1 << max_res + 1
    out_signal = Signal( intbv( 0, min=0, max=max_val )[max_res+1:] )
    in_list    = [Signal( intbv( randrange(max_val), min=0, max=max_val )[max_res+1:] ) for i in range(num_inputs)]
    w_list     = [Signal( intbv( randrange(max_val), min=0, max=max_val )[max_res+1:] ) for i in range(num_inputs)]
    # Converting to a bus in HDL
    input_bus  = ConcatSignal(*reversed(in_list))
    weight_bus = ConcatSignal(*reversed(w_list))
    # Instantiate component
    perceptron_inst = perceptron(clk, max_val, max_res, input_bus, weight_bus, out_signal)
    # Convert component to desired HDL language
    perceptron_inst.convert(hdl=hdl)

When I try to simulate the design everything works as expected, however when converting there is a small error: the in_bus and w_bus inputs to the perceptron are defined in Verilog as output ports instead of input ports. As a consequence of this 2 wires for those ports are also generated and they're assigned a value of None.

The interesting bit is that the rest of the Verilog code is correct and if I simply delete the generated wires and None assignment, and if I manually change output to input for the in_bus and w_bus in the Verilog file then the code is synthesizable. If I look at the elaborated design by Vivado after these changes the module seems to be exactly what I intended.

Although I could manually fix this problem in the Verilog files I feel this problem comes from a wrong use/lack of understanding of MyHDL on my part. I cannot understand why the use of a ConcatSignal suddenly turns the input ports into output ports.

Any idea on what I'm missing here?

Upvotes: 2

Views: 310

Answers (1)

Christopher Felton
Christopher Felton

Reputation: 420

You cannot use list-of-signals as a top-level port, you will want to create a wrapper that has a single input, creates your list-of-signals, then it can be passed to the generic.

Upvotes: 1

Related Questions