6.6.7 User-defined Verilog code

MyHDL provides a way to include user-defined Verilog code during the conversion process.

MyHDL defines a hook that is understood by the converter but ignored by the simulator. The hook is called __verilog__. It operates like a special return value. When a MyHDL function defines __verilog__, the Verilog converter will use its value instead of the regular return value.

The value of __verilog__ should be a format string that uses keys in its format specifiers. The keys refer to the variable names in the context of the string.

Example:

def inc_comb(nextCount, count, n):

    @always_comb
    def logic():
        # note: '-' instead of '+'
        nextCount.next = (count - 1) % n

    nextCount.driven = "wire"

    __verilog__ =\
"""
assign %(nextCount)s = (%(count)s + 1) %% %(n)s;
"""

    return logic

The converted code looks as follows:

module inc_comb (
    nextCount,
    count
);

output [7:0] nextCount;
wire [7:0] nextCount;
input [7:0] count;

assign nextCount = (count + 1) % 128;

endmodule

In this example, conversion of the inc_comb function is bypassed and the user-defined Verilog code is inserted instead. Note that the user-defined code refers to signals and parameters in the MyHDL context by using format specifiers. During conversion, the appropriate hierarchical names and parameter values will be filled in. Note also that the format specifier indicator % needs to be escaped (by doubling it) if it is required in the user-defined code.

There is one more issue that needs user attention. Normally, the Verilog converter infers inputs, internal signals, and outputs. It also detects undriven and multiple driven signals. To do this, it assumes that signals are not driven by default. It then processes the code to find out which signals are driven from where. However, it cannot do this for user-defined code. Without additional help, this will result in warnings or errors during the inference process, or in compilation errors from invalid Verilog code. The user should solve this by setting the driven attribute for signals that are driven from the user-defined code. In the example code above, note the following assignment:

nextCount.driven = "wire"

This specifies that the nextCount signal is driven as a Verilog wire from this module. The allowed values of the driven attribute are 'wire' and 'reg'. The value specifies how the user-defined Verilog code drives the signal in Verilog. To decide which value to use, consider how the signal should be declared in Verilog after the user-defined code is inserted.

About this document