MyHDL is implemented as a Python package called myhdl. This chapter describes the objects that are exported by this package.
A Simulation object has the following method:
Enables signal tracing to a VCD file for waveform viewing. func is a function that returns an instance. traceSignals() calls func under its control and passes *args and **kwargs to the call. In this way, it finds the hierarchy and the signals to be traced.
The return value is the same as would be returned by the call func(*args, **kwargs). The top-level instance name and the basename of the VCD output filename is func.func_name by default. If the VCD file exists already, it will be moved to a backup file by attaching a timestamp to it, before creating the new file.
The traceSignals callable has the following attribute:
A Signal object has the following attributes:
Read-only attribute that represents the current value of the signal.
This attribute is always available to access the current value; however in many practical case it will not be needed. Whenever there is no ambiguity, the Signal object’s current value is used implicitly. In particular, all Python’s standard numeric, bit-wise, logical and comparison operators are implemented on a Signal object by delegating to its current value. The exception is augmented assignment. These operators are not implemented as they would break the rule that the current value should be a read-only attribute. In addition, when a Signal object is assigned to the next attribute of another Signal object, its current value is assigned instead.
Writable attribute that can be used to indicate that the signal is supposed to be driven from the MyHDL code, and how it should be declared in Verilog after conversion. The allowed values are 'reg' and 'wire'.
This attribute is useful when the Verilog converter cannot infer automatically whether and how a signal is driven. This occurs when the signal is driven from user-defined Verilog code.
MyHDL generators are standard Python generators with specialized yield statements. In hardware description languages, the equivalent statements are called sensitivity lists. The general format of yield statements in in MyHDL generators is:
yield clause [, clause ...]
When a generator executes a yield statement, its execution is suspended at that point. At the same time, each clause is a trigger object which defines the condition upon which the generator should be resumed. However, per invocation of a yield statement, the generator resumes exactly once, regardless of the number of clauses. This happens on the first trigger that occurs.
In this section, the trigger objects and their functionality will be described.
Some MyHDL objects that are described elsewhere can directly be used as trigger objects. In particular, a Signal can be used as a trigger object. Whenever a signal changes value, the generator resumes. Likewise, the objects referred to by the signal attributes posedge and negedge are trigger objects. The generator resumes on the occurrence of a positive or a negative edge on the signal, respectively. An edge occurs when there is a change from false to true (positive) or vice versa (negative). For the full description of the Signal class and its attributes, see section The Signal class.
Furthermore, MyHDL generators can be used as clauses in yield statements. Such a generator is forked, and starts operating immediately, while the original generator waits for it to complete. The original generator resumes when the forked generator returns.
In addition, the following functions return trigger objects:
Finally, as a special case, the Python None object can be present in a yield statement. It is the do-nothing trigger object. The generator immediately resumes, as if no yield statement were present. This can be useful if the yield statement also has generator clauses: those generators are forked, while the original generator resumes immediately.
MyHDL defines a number of decorator functions, that make it easier to create generators from local generator functions.
The instance() decorator is the most general decorator. It automatically creates a generator by calling the decorated generator function.
It is used as follows:
def top(...):
...
@instance
def inst():
<generator body>
...
return inst, ...
This is equivalent to:
def top(...):
...
def _gen_func():
<generator body>
...
inst = _gen_func()
...
return inst, ...
The always() decorator is a specialized decorator that targets a widely used coding pattern. It is used as follows:
def top(...):
...
@always(event1, event2, ...)
def inst()
<body>
...
return inst, ...
This is equivalent to the following:
def top(...):
...
def _func():
<body>
def _gen_func()
while True:
yield event1, event2, ...
_func()
...
inst = _gen_func()
...
return inst, ...
The argument list of the decorator corresponds to the sensitivity list. Only signals, edge specifiers, or delay objects are allowed. The decorated function should be a classic function.
The always_comb() decorator is used to describe combinatorial logic.
def top(...):
...
@always_comb
def comb_inst():
<combinatorial body>
...
return comb_inst, ...
The always_comb() decorator infers the inputs of the combinatorial logic and the corresponding sensitivity list automatically. The decorated function should be a classic function.
The minimum and maximum values of an intbv object are available as attributes:
Interpretes the msb bit as as sign bit and extends it into the higher-order bits of the underlying object value. The msb bit is the highest-order bit within the object’s bit width.
| Return type: | integer |
|---|
Unlike int objects, intbv objects are mutable; this is also the reason for their existence. Mutability is needed to support assignment to indexes and slices, as is common in hardware design. For the same reason, intbv is not a subclass from int, even though int provides most of the desired functionality. (It is not possible to derive a mutable subtype from an immutable base type.)
An intbv object supports the same comparison, numeric, bitwise, logical, and conversion operations as int objects. See http://www.python.org/doc/current/lib/typesnumeric.html for more information on such operations. In all binary operations, intbv objects can work together with int objects. For mixed-type numeric operations, the result type is an int or a long. For mixed-type bitwise operations, the result type is an intbv.
In addition, intbv supports a number of sequence operators. In particular, the len() function returns the object’s bit width. Furthermore, intbv objects support indexing and slicing operations:
| Operation | Result | Notes |
|---|---|---|
| bv[i] | item i of bv | (1) |
| bv[i] = x | item i of bv is replaced by x | (1) |
| bv[i:j] | slice of bv from i downto j | (2)(3) |
| bv[i:j] = t | slice of bv from i downto j is replaced by t | (2)(4) |
In addition, an intbv object supports the iterator protocol. This makes it possible to iterate over all its bits, from the high index to index 0. This is only possible for intbv objects with a defined bit width.
Returns a bit string representation. If the optional width is provided, and if it is larger than the width of the default representation, the bit string is padded with the sign bit.
This function complements the standard Python conversion functions hex and oct. A binary string representation is often useful in hardware design.
| Return type: | string |
|---|
Returns an intbv object formed by concatenating the arguments.
The following argument types are supported: intbv objects with a defined bit width, bool objects, signals of the previous objects, and bit strings. All these objects have a defined bit width. The first argument base is special as it doesn’t need to have a defined bit width. In addition to the previously mentioned objects, unsized intbv, int and long objects are supported, as well as signals of such objects.
| Return type: | intbv |
|---|
Generates a downward range list of integers.
This function is modeled after the standard range function, but works in the downward direction. The returned interval is half-open, with the high index not included. low is optional and defaults to zero. This function is especially useful in conjunction with the intbv class, that also works with downward indexing.
Returns an enumeration type.
The arguments should be string literals that represent the desired names of the enumeration type attributes. The returned type should be assigned to a type name. For example:
t_EnumType = enum('ATTR_NAME_1', 'ATTR_NAME_2', ...)
The enumeration type identifiers are available as attributes of the type name, for example: t_EnumType.ATTR_NAME_1
The optional keyword argument encoding specifies the encoding scheme used in Verilog output. The available encodings are 'binary', 'one_hot', and 'one_cold'.
Looks up all MyHDL instances in the local name space and returns them in a list.
| Return type: | list |
|---|
Class to construct a new Cosimulation object.
The exe argument is a command string to execute an HDL simulation. The kwargs keyword arguments provide a named association between signals (regs & nets) in the HDL simulator and signals in the MyHDL simulator. Each keyword should be a name listed in a $to_myhdl or $from_myhdl call in the HDL code. Each argument should be a Signal declared in the MyHDL code.
Converts a MyHDL design instance to equivalent Verilog code, and also generates a test bench to verify it. func is a function that returns an instance. toVerilog() calls func under its control and passes *args and **kwargs to the call.
The return value is the same as would be returned by the call func(*args, **kwargs). It should be assigned to an instance name.
The top-level instance name and the basename of the Verilog output filename is func.func_name by default.
For more information about the restrictions on convertible MyHDL code, see section The convertible subset in Chapter Conversion to Verilog and VHDL.
toVerilog() has the following attribute:
Converts a MyHDL design instance to equivalent VHDL code. func is a function that returns an instance. toVHDL() calls func under its control and passes *args and **kwargs to the call.
The return value is the same as would be returned by the call func(*args, **kwargs). It can be assigned to an instance name. The top-level instance name and the basename of the Verilog output filename is func.func_name by default.
toVHDL() has the following attributes:
A user can insert user-defined code in the Verilog or VHDL output by using the __verilog__ or __vhdl__ hook respectively.
These hooks cannot be used inside generator functions or decorated local functions, as these are not elaborated. In other words, they should be used in functions that define structure.
All functions related to conversion verification are implemented in the myhdl.conversion package.
The two previous functions have the following attribute:
To be able to use a HDL simulator to verify conversions, it needs to be registered first. This is needed once per simulator (or rather, per set of analysis and simulation commands). Registering is done with the following function:
Registers a particular HDL simulator to be used by verify() and analyze(). name is the name of the simulator. hdl specifies the HDL: "VHDL" or "Verilog". analyze is a command string to analyze the HDL source code. elaborate is a command string to elaborate the HDL code. This command is optional. simulate is a command string to simulate the HDL code. offset is an integer specifying the number of initial lines to be ignored from the HDL simulator output.
The command strings should be string templates that refer to the topname variable that specifies the design name. The templates can also use the unitname variable which is the lower case version of topname. The command strings can assume that a subdirectory called work is available in the current working directory. Analysis and elaboration results can be put there if desired.
The analyze() function uses the analyze command. The verify() function uses the analyze command, then the elaborate command if any, and then the simulate command.
A number of open-source HDL simulators are preregistered in the MyHDL distribution, as follows:
registerSimulator(
name="GHDL",
hdl="VHDL",
analyze="ghdl -a --workdir=work pck_myhdl_%(version)s.vhd %(topname)s.vhd",
elaborate="ghdl -e --workdir=work -o %(unitname)s_ghdl %(topname)s",
simulate="ghdl -r %(unitname)s_ghdl"
)
registerSimulator(
name="icarus",
hdl="Verilog",
analyze="iverilog -o %(topname)s.o %(topname)s.v",
simulate="vvp %(topname)s.o"
)
registerSimulator(
name="cver",
hdl="Verilog",
analyze="cver -c -q %(topname)s.v",
simulate="cver -q %(topname)s.v",
offset=3
)