In MyHDL source code, "front-end" means the simulation part, and "back-end" usually means the conversion (MyHDL to Verilog or VHDL) part. The code of conversion part is in
myhdl/conversion path, while the unit tests are in
First, let's see
myhdl/conversion/__init__.py in this directory about what it provides to users:
This is rather simple. The most useful things we provide are
toVHDL. If you don't know about the usage of these methods, please refer to related contents in MyHDL documentation.
Also, we could see that the function
analyze does not come from
_analyze.py. Instead, it comes from
_verify.py. The reason will be explained in later posts for
_misc.py, some helper functions are provided. It is better to examine them when we need them.
What Do We Call When We Call
Let's get a head start of the whole back-end from
_toVerilog.py. We can see that in
__init__.py, it imports a
toVerilog object in Verilog. So, what is
_toVerilog.py, we could find a line of its definition:
So it is an instance of
In the definition of
_ToVerilogConvertor, it has four methods:
_convert_filter. The last two methods are helpers for the code in
__call__. We can ignore them at this time.
myhdl, the previously mentioned
toVerilog = _ToVerilogConvertor() will be executed, so that
_ToVerilogConvertor.__init__ will be called at this time. When user code calls
toVerilog such as
toVerilog(...), it is actually
_ToVerilogConvertor.__call__(...). So, even though
toVerilog looks like a function while using, it is actually implemented by the class
We could see a lot of examples of this kind of design pattern.
_ToVerilogConvertor.__init__, it only defines some necessary attributes for conversion. It is similar to
_ToVerilogConvertor.__call__, the code is longer, so some necessary checks and initializations will be skipped in the analysis. It works as following steps:
This method first defines the file name and its path, and open it as a file called
It extracts a flattened list of arguments of the whole hierarchy. Also a list of signals and a list of generators will be analyzed. And then, it infers the interface of the top module.
It extracts document string from the top level by calling
inspectmodule, which is a default module in Python.
It writes the file header, the module header, the signal declarations in
vfileby using the extracted interface and the list of signals above.
It converts generators to Verilog code by visiting the abstract syntax tree (AST) of it. The conversion from Python code to AST is done by the module
ast, which is provided in the default Python implementation. The Verilog code will be written into
It writes the module footer
If the test bench is valid for the code, it will also converts the test bench into Verilog.
It builds a port map from the interface for co-simulation.
Note: If you don't know what an AST is, please refer to here as a tutorial. This concept is very important in MyHDL back-end.
Functions provided in
_analyze.py is heavily used in
_ToVerilogConvertor.__call__. Some other code, even if they are not in
myhdl/conversion, are called in the implementation. So, if you want to make every details clear, it is necessary to read the code of the whole project.
Walking Through AST
To see how AST has been walked through, it is better to take a look at method
_convertGens at first. It uses with different visitors when the tree is in different kinds of blocks, like
always_seq, etc. However, all of these visitors are derived from
_ConvertVisitor, with only a few differences.
_ConvertVisitor is derived from
ast.NodeVisitor. We could see that it has different types of methods for visiting different types of AST nodes. The visitor will walk through the tree by using these methods.
Since there is already many types of AST nodes, and the code is not difficult, it is recommended to read the code and see what does the convertor do during visiting different kinds of nodes if you are interested in it.
For the documentation of different types of nodes, please refer to Green Tree Snake.