1
0
mirror of https://github.com/myhdl/myhdl.git synced 2025-01-24 21:52:56 +08:00
myhdl/doc/manual/conversion.tex

1022 lines
32 KiB
TeX
Raw Normal View History

2004-02-02 11:38:22 +00:00
\section{Introduction\label{conv-intro}}
2005-12-27 12:58:07 +00:00
\myhdl\ supports the automatic conversion of implementation-oriented
2005-12-27 15:21:01 +00:00
\myhdl\ code to Verilog code. This feature provides a
2005-12-27 12:58:07 +00:00
direct path from Python to an FPGA or ASIC implementation.
2004-02-02 11:38:22 +00:00
\section{Solution description\label{conv-solution}}
2005-12-27 15:21:01 +00:00
The solution works as follows. The hardware description should
2005-12-27 12:58:07 +00:00
satisfy certain constraints that are typical for
implementation-oriented hardware modeling. Subsequently, such a
design is converted to an equivalent model in the Verilog language,
using the function \function{toVerilog} from the \myhdl\
2004-02-02 21:52:02 +00:00
library. Finally, a third-party \emph{synthesis tool} is used to
2004-02-04 15:36:03 +00:00
convert the Verilog design to a gate implementation for an ASIC or
2004-02-02 21:52:02 +00:00
FPGA. There are a number of Verilog synthesis tools available, varying
2004-02-03 15:20:18 +00:00
in price, capabilities, and target implementation technology.
2004-02-02 11:38:22 +00:00
2005-12-27 12:58:07 +00:00
The conversion does not start from source files, but from an
instantiated design that has been \emph{elaborated} by the Python
interpreter. The converter uses the Python profiler to track the
interpreter's operation and to infer the design structure and name
spaces. It then selectively compiles pieces of source code for
additional analysis and for conversion. This is done using the Python
compiler package.
2004-02-02 11:38:22 +00:00
\section{Features\label{conv-features}}
\subsection{The design is converted after elaboration\label{conv-features-elab}}
2004-02-02 21:52:02 +00:00
\emph{Elaboration} refers to the initial processing of a hardware
description to achieve a representation of a design instance that is
ready for simulation or synthesis. In particular, structural
parameters and constructs are processed in this step. In \myhdl{}, the
Python interpreter itself is used for elaboration. A
\class{Simulation} object is constructed with elaborated design
instances as arguments. Likewise, the Verilog conversion works on an
elaborated design instance. The Python interpreter is thus used as
much as possible.
2004-02-02 11:38:22 +00:00
\subsection{The structural description can be arbitrarily complex and hierarchical\label{conv-features-struc}}
As the conversion works on an elaborated design instance, any modeling
2004-02-02 21:52:02 +00:00
constraints only apply to the leaf elements of the design structure,
that is, the co-operating generators. In other words, there are no
restrictions on the description of the design structure: Python's full
power can be used for that purpose. Also, the design hierarchy can be
arbitrarily deep.
2004-02-02 11:38:22 +00:00
\subsection{Generators are mapped to Verilog always or initial blocks\label{conv-features-gen}}
The converter analyzes the code of each generator and maps it
2004-02-04 15:36:03 +00:00
to a Verilog \code{always} blocks if possible, and to
2004-02-02 11:38:22 +00:00
an \code{initial} block otherwise.
The converted Verilog design will be a flat
"net list of blocks".
2004-02-03 15:20:18 +00:00
\subsection{The Verilog module interface is inferred from signal usage\label{conv-features-intf}}
2004-02-02 11:38:22 +00:00
In \myhdl{}, the input or output direction of interface signals
is not explicitly declared. The converter investigates signal usage
2004-02-04 15:36:03 +00:00
in the design hierarchy to infer whether a signal is used as
input, output, or as an internal signal. Internal signals are
2004-02-02 11:38:22 +00:00
given a hierarchical name in the Verilog output.
2004-02-04 15:36:03 +00:00
\subsection{Function calls are mapped to a unique Verilog function or task call\label{conv-features-func}}
2004-02-02 11:38:22 +00:00
The converter analyzes function calls and function code to see if they
should be mapped to Verilog functions or to tasks. Python functions
are much more powerful than Verilog subprograms; for example, they are
inherently generic, and they can be called with named association. To
support this power in Verilog, a unique Verilog function or task is
generated per Python function call.
\subsection{If-then-else structures may be mapped to Verilog case statements\label{conv-features-if}}
Python does not provide a case statement. However,
the converter recognizes if-then-else structures in which a variable is
sequentially compared to items of an enumeration type, and maps
such a structure to a Verilog case statement with the appropriate
synthesis attributes.
\subsection{Choice of encoding schemes for enumeration types\label{conv-features-enum}}
The \function{enum} function in \myhdl\ returns an enumeration type. This
function takes an additional parameter \var{encoding} that specifies the
desired encoding in the implementation: binary, one hot, or one cold.
The Verilog converter generates the appropriate code.
2005-12-19 11:20:04 +00:00
\subsection{Support for RAM inference \label{conf-features-ram}}
Certain synthesis tools can map Verilog memories to RAM
2005-12-19 11:25:14 +00:00
structures. To support this interesting feature, the Verilog converter
2005-12-16 22:38:32 +00:00
maps lists of signals to Verilog memories.
2005-12-19 11:20:04 +00:00
\subsection{Support for ROM memory \label{conf-features-rom}}
Some synthesis tools can infer a ROM
2005-12-19 11:25:14 +00:00
from a case statement. The Verilog converter does the expansion into
2005-12-16 22:38:32 +00:00
a case statement automatically, based on a higher level
2005-12-27 12:58:07 +00:00
description. The ROM access is described in a single line, by
2005-12-16 22:38:32 +00:00
indexing into a tuple of integers.
\subsection{Support for signed arithmetic \label{conf-features-signed}}
In MyHDL, working with negative numbers is trivial: one just uses
2005-12-27 12:58:07 +00:00
\code{intbv} objects with negative values.
2005-12-19 11:20:04 +00:00
By contrast, negative numbers are tricky in Verilog. The language
makes a difference between an unsigned and a signed representation,
and the user has to declare signed variables explicitly. When the two
representations are mixed in an expression, all operands are
interpreted as unsigned, which typically leads to unexpected results.
2005-12-16 22:38:32 +00:00
2005-12-19 11:25:14 +00:00
The Verilog converter handles negative \code{intbv} objects by using
2005-12-27 12:58:07 +00:00
a signed Verilog representation. Also, it automatically performs sign
2005-12-16 22:38:32 +00:00
extension and casting to a signed representation when unsigned numbers
are used in a mixed expression. In this way, it automates a task which
2005-12-27 12:58:07 +00:00
is notoriously hard to get right in Verilog directly.
2005-12-16 22:38:32 +00:00
\subsection{Support for user-defined Verilog code \label{conf-features-udfv}}
If desired, the user can bypass the regular Verilog conversion
and describe user-defined code to be inserted instead.
2004-02-02 11:38:22 +00:00
\section{The convertible subset\label{conv-subset}}
\subsection{Introduction\label{conv-subset-intro}}
2004-02-04 15:36:03 +00:00
Unsurprisingly, not all \myhdl\ code can be converted to Verilog. In
2004-02-02 11:38:22 +00:00
fact, there are very important restrictions. As the goal of the
conversion functionality is implementation, this should not be a big
issue: anyone familiar with synthesis is used to similar restrictions
in the \emph{synthesizable subset} of Verilog and VHDL. The converter
attempts to issue clear error messages when it encounters a construct
that cannot be converted.
2004-02-02 21:52:02 +00:00
In practice, the synthesizable subset usually refers to RTL synthesis,
which is by far the most popular type of synthesis today. There are
industry standards that define the RTL synthesis subset. However,
those were not used as a model for the restrictions of the MyHDL
converter, but as a minimal starting point. On that basis, whenever
it was judged easy or useful to support an additional feature, this
2004-02-03 15:20:18 +00:00
was done. For example, it is actually easier to convert
\keyword{while} loops than \keyword{for} loops even though they are
not RTL-synthesizable. As another example, \keyword{print} is
supported because it's so useful for debugging, even though it's not
synthesizable. In summary, the convertible subset is a superset of
the standard RTL synthesis subset, and supports synthesis tools with
more advanced capabilities, such as behavioral synthesis.
2004-02-02 11:38:22 +00:00
Recall that any restrictions only apply to the design post
elaboration. In practice, this means that they apply only to the code
2004-02-04 15:36:03 +00:00
of the generators, that are the leaf functional blocks in a MyHDL
2004-02-02 11:38:22 +00:00
design.
\subsection{Coding style\label{conv-subset-style}}
A natural restriction on convertible code is that it should be
written in MyHDL style: cooperating generators, communicating through
2005-12-16 22:38:32 +00:00
signals, and with sensitivity lists specifying wait points and resume
2004-02-02 11:38:22 +00:00
conditions. Supported resume conditions are a signal edge, a signal
change, or a tuple of such conditions.
2004-02-02 11:40:20 +00:00
\subsection{Supported types\label{conv-subset-types}}
2004-02-02 11:38:22 +00:00
The most important restriction regards object types. Verilog is an
almost typeless language, while Python is strongly (albeit
2004-02-04 15:36:03 +00:00
dynamically) typed. The converter has to infer the types of names
used in the code, and map those names to Verilog variables.
2004-02-02 11:38:22 +00:00
Only a limited amount of types can be converted.
Python \class{int} and \class{long} objects are mapped to Verilog
integers. All other supported types are mapped to Verilog regs (or
wires), and therefore need to have a defined bit width. The supported
types are the Python \class{bool} type, the MyHDL \class{intbv} type,
and MyHDL enumeration types returned by function \function{enum}. The
latter objects can also be used as the base object of a
\class{Signal}.
2004-02-04 15:36:03 +00:00
\class{intbv} objects must be constructed so that a bit
2004-02-02 11:38:22 +00:00
width can be inferred. This can be done by specifying minimum
and maximum values, e.g. as follows:
\begin{verbatim}
2005-12-16 22:38:32 +00:00
index = intbv(0, min=MIN, max=MAX)
2004-02-02 11:38:22 +00:00
\end{verbatim}
2005-12-19 11:25:14 +00:00
The Verilog converter supports \class{intbv} objects that
2005-12-16 22:38:32 +00:00
can take negative values.
2004-02-02 11:38:22 +00:00
Alternatively, a slice can be taken from an \class{intbv} object
as follows:
\begin{verbatim}
index = intbv(0)[N:]
\end{verbatim}
Such as slice returns a new \class{intbv} object, with minimum
value \code{0} , and maximum value \code{2**N}.
\subsection{Supported statements\label{conv-subset-statements}}
The following is a list of the statements that are supported by the
Verilog converter, possibly qualified with restrictions
2004-02-04 15:36:03 +00:00
or usage notes.
2004-02-02 11:38:22 +00:00
\begin{description}
\item[The \keyword{break} statement.]
\item[The \keyword{continue} statement.]
\item[The \keyword{def} statement.]
\item[The \keyword{for} statement.]
The only supported iteration scheme is iterating through sequences of
integers returned by built-in function \function{range} or \myhdl\
function \function{downrange}. The optional \keyword{else} clause is
not supported.
\item[The \keyword{if} statement.]
\keyword{if}, \keyword{elif}, and \keyword{else} clauses
are fully supported.
\item[The \keyword{pass} statement.]
\item[The \keyword{print} statement.]
2004-02-04 15:36:03 +00:00
When printing an interpolated string, the format specifiers are copied
verbatim to the Verilog output. Printing to a file (with syntax
\code{'>>'}) is not supported.
2004-02-02 11:38:22 +00:00
\item[The \keyword{raise} statement.]
This statement is mapped to Verilog statements
that end the simulation with an error message.
\item[The \keyword{return} statement.]
\item[The \keyword{yield} statement.]
The yielded expression can be a signal, a signal edge
as specified by \myhdl\ functions \function{posedge}
or \function{negedge}, or a tuple of signals and
edge specifications.
\item[The \keyword{while} statement.]
The optional \keyword{else}
clause is not supported.
\end{description}
\section{Methodology notes\label{conv-meth}}
\subsection{Simulation\label{conv-meth-sim}}
In the Python philosophy, the run-time rules. The Python compiler
doesn't attempt to detect a lot of errors beyond syntax errors, which
given Python's ultra-dynamic nature would be an almost impossible task
anyway. To verify a Python program, one should run it, preferably
using unit testing to verify each feature.
The same philosophy should be used when converting a MyHDL description
to Verilog: make sure the simulation runs fine first. Although the
converter checks many things and attempts to issue clear error
messages, there is no guarantee that it does a meaningful job unless
the simulation runs fine.
\subsection{Conversion output verification\label{conv-meth-conv}}
It is always prudent to verify the converted Verilog output.
To make this task easier, the converter also generates a
test bench that makes it possible to simulate the Verilog
design using the Verilog co-simulation interface. This
permits to verify the Verilog code with the same test
bench used for the \myhdl\ code. This is also how
the Verilog converter development is being verified.
\subsection{Assignment issues\label{conv-meth-assign}}
\subsubsection{Name assignment in Python\label{conv-meth-assign-python}}
Name assignment in Python is a different concept than in
many other languages. This point is very important for
effective modeling in Python, and even more so
for synthesizable \myhdl\ code. Therefore, the issues are
2004-02-04 15:36:03 +00:00
discussed here explicitly.
2004-02-02 11:38:22 +00:00
Consider the following name assignments:
\begin{verbatim}
a = 4
a = ``a string''
a = False
\end{verbatim}
In many languages, the meaning would be that an
existing variable \var{a} gets a number of different values.
In Python, such a concept of a variable doesn't exist. Instead,
assignment merely creates a new binding of a name to a
certain object, that replaces any previous binding.
So in the example, the name \var{a} is bound a
number of different objects in sequence.
The Verilog converter has to investigate name
assignment and usage in \myhdl\ code, and to map
names to Verilog variables. To achieve that,
it tries to infer the type and possibly the
bit width of each expression that is assigned
to a name.
Multiple assignments to the same name can be supported if it can be
determined that a consistent type and bit width is being used in the
assignments. This can be done for boolean expressions, numeric
expressions, and enumeration type literals. In Verilog, the
corresponding name is mapped to a single bit \code{reg}, an
2004-02-04 15:36:03 +00:00
\code{integer}, or a \code{reg} with the appropriate width, respectively.
2004-02-02 11:38:22 +00:00
In other cases, a single assignment should be used when an object is
created. Subsequent value changes are then achieved by modification of
an existing object. This technique should be used for \class{Signal}
and \class{intbv} objects.
\subsubsection{Signal assignment\label{conv-meth-assign-signal}}
Signal assignment in \myhdl\ is implemented using attribute assignment
to attribute \code{next}. Value changes are thus modeled by
modification of the existing object. The converter investigates the
\class{Signal} object to infer the type and bit width of the
corresponding Verilog variable.
\subsubsection{\class{intbv} objects\label{conv-meth-assign-intbv}}
Type \class{intbv} is likely to be the workhorse for synthesizable
modeling in \myhdl{}. An \class{intbv} instance behaves like a
(mutable) integer whose individual bits can be accessed and
modified. Also, it is possible to constrain its set of values. In
addition to error checking, this makes it possible to infer a bit
width, which is required for implementation.
In Verilog, an \class{intbv} instance will be mapped to a \code{reg}
with an appropriate width. As noted before, it is not possible
to modify its value using name assignment. In the following, we
will show how it can be done instead. Consider:
\begin{verbatim}
a = intbv(0)[8:]
\end{verbatim}
This is an \class{intbv} object with initial value \code{0} and
bit width 8. The change its value to \code{5}, we can use
slice assignment:
\begin{verbatim}
a[8:] = 5
\end{verbatim}
The same can be achieved by leaving the bit width unspecified,
which has the meaning to change ``all'' bits:
\begin{verbatim}
a[:] = 5
\end{verbatim}
Often the new value will depend on the old one. For example,
to increment an \class{intbv} with the technique above:
\begin{verbatim}
a[:] = a + 1
\end{verbatim}
Python also provides \emph{augmented} assignment operators,
which can be used to implement in-place operations. These are supported
on \class{intbv} objects and by the converter, so that the increment
can also be done as follows:
\begin{verbatim}
a += 1
\end{verbatim}
\section{Converter usage\label{conv-usage}}
We will demonstrate the conversion process by showing some examples.
2005-12-16 22:38:32 +00:00
\subsection{A small sequential design\label{conv-usage-seq}}
2004-02-02 11:38:22 +00:00
Consider the following MyHDL code for an incrementer module:
\begin{verbatim}
2005-12-16 22:38:32 +00:00
ACTIVE_LOW, INACTIVE_HIGH = 0, 1
2004-02-02 11:38:22 +00:00
def inc(count, enable, clock, reset, n):
2005-12-16 22:38:32 +00:00
2004-02-02 11:38:22 +00:00
""" Incrementer with enable.
count -- output
enable -- control input, increment when 1
clock -- clock input
reset -- asynchronous reset input
n -- counter max value
2005-12-16 22:38:32 +00:00
2004-02-02 11:38:22 +00:00
"""
2005-12-16 22:38:32 +00:00
@always(clock.posedge, reset.negedge)
2004-02-02 11:38:22 +00:00
def incProcess():
2005-12-16 22:38:32 +00:00
if reset == ACTIVE_LOW:
count.next = 0
else:
if enable:
count.next = (count + 1) % n
return incProcess
2004-02-02 11:38:22 +00:00
\end{verbatim}
In Verilog terminology, function \function{inc} corresponds to a
2005-12-16 22:38:32 +00:00
module, while the decorated function \function{incProcess}
2004-02-02 11:38:22 +00:00
roughly corresponds to an always block.
Normally, to simulate the design, we would "elaborate" an instance
as follows:
\begin{verbatim}
m = 8
n = 2 ** m
count = Signal(intbv(0)[m:])
enable = Signal(bool(0))
clock, reset = [Signal(bool()) for i in range(2)]
inc_inst = inc(count, enable, clock, reset, n=n)
\end{verbatim}
\code{inc_inst} is an elaborated design instance that can be simulated. To
convert it to Verilog, we change the last line as follows:
\begin{verbatim}
inc_inst = toVerilog(inc, count, enable, clock, reset, n=n)
\end{verbatim}
Again, this creates an instance that can be simulated, but as a side
2005-12-16 22:38:32 +00:00
effect, it also generates an equivalent Verilog module in file \file{inc.v}.
2004-02-04 15:36:03 +00:00
The Verilog code looks as follows:
2004-02-02 11:38:22 +00:00
\begin{verbatim}
module inc_inst (
count,
enable,
clock,
reset
);
output [7:0] count;
reg [7:0] count;
input enable;
input clock;
input reset;
always @(posedge clock or negedge reset) begin: _MYHDL1_BLOCK
if ((reset == 0)) begin
count <= 0;
end
else begin
if (enable) begin
count <= ((count + 1) % 256);
end
end
end
endmodule
\end{verbatim}
You can see the module interface and the always block, as expected
from the MyHDL design.
2005-12-16 22:38:32 +00:00
\subsection{A small combinatorial design\label{conv-usage-comb}}
2004-02-02 11:38:22 +00:00
2005-12-19 11:25:14 +00:00
The second example is a small combinatorial design, more
specifically the binary to Gray code converter from previous chapters:
2004-02-02 11:38:22 +00:00
\begin{verbatim}
def bin2gray(B, G, width):
2005-12-16 22:38:32 +00:00
2004-02-02 11:38:22 +00:00
""" Gray encoder.
B -- input intbv signal, binary encoded
G -- output intbv signal, gray encoded
width -- bit width
2005-12-16 22:38:32 +00:00
2004-02-02 11:38:22 +00:00
"""
2005-12-16 22:38:32 +00:00
@always_comb
def logic():
Bext = intbv(0)[width+1:]
2004-02-02 11:38:22 +00:00
Bext[:] = B
for i in range(width):
G.next[i] = Bext[i+1] ^ Bext[i]
2005-12-16 22:38:32 +00:00
return logic
2004-02-02 11:38:22 +00:00
\end{verbatim}
As before, you can create an instance and convert to
Verilog as follows:
\begin{verbatim}
width = 8
B = Signal(intbv(0)[width:])
G = Signal(intbv(0)[width:])
bin2gray_inst = toVerilog(bin2gray, B, G, width)
\end{verbatim}
2004-02-04 16:11:38 +00:00
The generated Verilog code looks as follows:
2004-02-02 11:38:22 +00:00
\begin{verbatim}
2005-12-16 22:38:32 +00:00
module bin2gray (
2004-02-02 11:38:22 +00:00
B,
G
);
input [7:0] B;
output [7:0] G;
reg [7:0] G;
2005-12-16 22:38:32 +00:00
always @(B) begin: _bin2gray_logic
2004-02-02 11:38:22 +00:00
integer i;
reg [9-1:0] Bext;
2005-12-16 22:38:32 +00:00
Bext = 9'h0;
Bext = B;
2004-02-02 11:38:22 +00:00
for (i=0; i<8; i=i+1) begin
G[i] <= (Bext[(i + 1)] ^ Bext[i]);
end
end
endmodule
\end{verbatim}
\subsection{A hierarchical design\label{conv-usage-hier}}
2005-12-19 11:25:14 +00:00
The Verilog converter can handle designs with an
2005-12-19 11:20:04 +00:00
arbitrarily deep hierarchy.
2004-02-02 11:38:22 +00:00
For example, suppose we want to design an
incrementer with Gray code output. Using the
designs from previous sections, we can proceed
as follows:
\begin{verbatim}
2005-12-16 22:38:32 +00:00
ACTIVE_LOW, INACTIVE_HIGH = 0, 1
2004-02-02 11:38:22 +00:00
def GrayInc(graycnt, enable, clock, reset, width):
2005-12-16 22:38:32 +00:00
bincnt = Signal(intbv(0)[width:])
2004-02-02 11:38:22 +00:00
2005-12-16 22:38:32 +00:00
inc_1 = inc(bincnt, enable, clock, reset, n=2**width)
bin2gray_1 = bin2gray(B=bincnt, G=graycnt, width=width)
2004-02-02 11:38:22 +00:00
2005-12-16 22:38:32 +00:00
return inc_1, bin2gray_1
2004-02-02 11:38:22 +00:00
\end{verbatim}
According to Gray code properties, only a single bit
will change in consecutive values. However, as the
\code{bin2gray} module is combinatorial, the output bits
may have transient glitches, which may not be desirable.
To solve this, let's create an additional level of
2004-02-04 15:36:03 +00:00
hierarchy and add an output register to the design.
2004-02-02 11:38:22 +00:00
(This will create an additional latency of a clock
cycle, which may not be acceptable, but we will
ignore that here.)
\begin{verbatim}
2005-12-16 22:38:32 +00:00
2004-02-02 11:38:22 +00:00
def GrayIncReg(graycnt, enable, clock, reset, width):
2005-12-16 22:38:32 +00:00
graycnt_comb = Signal(intbv(0)[width:])
2004-02-02 11:38:22 +00:00
2005-12-16 22:38:32 +00:00
gray_inc_1 = GrayInc(graycnt_comb, enable, clock, reset, width)
@always(clock.posedge)
def reg_1():
graycnt.next = graycnt_comb
2004-02-02 11:38:22 +00:00
2005-12-16 22:38:32 +00:00
return gray_inc_1, reg_1
2004-02-02 11:38:22 +00:00
\end{verbatim}
We can convert this hierarchical design as before:
\begin{verbatim}
width = 8
graycnt = Signal(intbv()[width:])
enable, clock, reset = [Signal(bool()) for i in range(3)]
2005-12-16 22:38:32 +00:00
gray_inc_reg_1 = toVerilog(GrayIncReg, graycnt, enable, clock, reset, width)
2004-02-02 11:38:22 +00:00
\end{verbatim}
2004-02-04 15:36:03 +00:00
The Verilog output code looks as follows:
2004-02-02 11:38:22 +00:00
\begin{verbatim}
2005-12-16 22:38:32 +00:00
module GrayIncReg (
2004-02-02 11:38:22 +00:00
graycnt,
enable,
clock,
reset
);
2005-12-16 22:38:32 +00:00
2004-02-02 11:38:22 +00:00
output [7:0] graycnt;
reg [7:0] graycnt;
input enable;
input clock;
input reset;
2005-12-16 22:38:32 +00:00
2004-02-02 11:38:22 +00:00
reg [7:0] graycnt_comb;
2005-12-16 22:38:32 +00:00
reg [7:0] _gray_inc_1_bincnt;
always @(posedge clock or negedge reset) begin: _GrayIncReg_gray_inc_1_inc_1_incProcess
2004-02-02 11:38:22 +00:00
if ((reset == 0)) begin
2005-12-16 22:38:32 +00:00
_gray_inc_1_bincnt <= 0;
2004-02-02 11:38:22 +00:00
end
else begin
if (enable) begin
2005-12-16 22:38:32 +00:00
_gray_inc_1_bincnt <= ((_gray_inc_1_bincnt + 1) % 256);
2004-02-02 11:38:22 +00:00
end
end
end
2005-12-16 22:38:32 +00:00
always @(_gray_inc_1_bincnt) begin: _GrayIncReg_gray_inc_1_bin2gray_1_logic
2004-02-02 11:38:22 +00:00
integer i;
reg [9-1:0] Bext;
2005-12-16 22:38:32 +00:00
Bext = 9'h0;
Bext = _gray_inc_1_bincnt;
2004-02-02 11:38:22 +00:00
for (i=0; i<8; i=i+1) begin
graycnt_comb[i] <= (Bext[(i + 1)] ^ Bext[i]);
end
end
2005-12-16 22:38:32 +00:00
always @(posedge clock) begin: _GrayIncReg_reg_1
2004-02-02 11:38:22 +00:00
graycnt <= graycnt_comb;
end
2005-12-16 22:38:32 +00:00
2004-02-02 11:38:22 +00:00
endmodule
\end{verbatim}
Note that the output is a flat ``net list of blocks'', and
that hierarchical signal names are generated as necessary.
\subsection{Optimizations for finite state machines\label{conv-usage-fsm}}
As often in hardware design, finite state machines deserve special attention.
In Verilog and VHDL, finite state machines are typically described
using case statements. Python doesn't have a case statement, but the
converter recognizes particular if-then-else structures and maps them
to case statements. This optimization occurs when a variable whose
type is an enumerated type is sequentially tested against enumeration
items in an if-then-else structure. Also, the appropriate synthesis
pragmas for efficient synthesis are generated in the Verilog code.
As a further optimization, function \function{enum} was enhanced to support
alternative encoding schemes elegantly, using an additional parameter
2004-02-04 15:36:03 +00:00
\var{encoding}. For example:
2004-02-02 11:38:22 +00:00
\begin{verbatim}
2004-02-04 15:40:19 +00:00
t_State = enum('SEARCH', 'CONFIRM', 'SYNC', encoding='one_hot')
2004-02-02 11:38:22 +00:00
\end{verbatim}
2004-02-04 15:40:19 +00:00
The default encoding is \code{'binary'}; the other possibilities are
2004-02-04 16:14:17 +00:00
\code{'one_hot'} and \code{'one_cold'}. This parameter only affects
the conversion output, not the behavior of the type. The generated
Verilog code for case statements is optimized for an efficient
implementation according to the encoding. Note that in contrast, a
Verilog designer has to make nontrivial code changes to implement a
different encoding scheme.
2004-02-02 11:38:22 +00:00
As an example, consider the following finite state machine, whose
2004-02-04 15:36:03 +00:00
state variable uses the enumeration type defined above:
2004-02-02 11:38:22 +00:00
\begin{verbatim}
2005-12-19 11:20:04 +00:00
ACTIVE_LOW = 0
2004-02-02 11:38:22 +00:00
FRAME_SIZE = 8
2005-12-19 11:20:04 +00:00
def FramerCtrl(SOF, state, syncFlag, clk, reset_n, t_State):
2004-02-02 11:38:22 +00:00
""" Framing control FSM.
SOF -- start-of-frame output bit
state -- FramerState output
syncFlag -- sync pattern found indication input
clk -- clock input
reset_n -- active low reset
"""
2005-12-19 11:20:04 +00:00
index = Signal(intbv(0)[8:]) # position in frame
@always(clk.posedge, reset_n.negedge)
def FSM():
2004-02-02 11:38:22 +00:00
if reset_n == ACTIVE_LOW:
SOF.next = 0
2005-12-19 11:20:04 +00:00
index.next = 0
2004-02-02 11:38:22 +00:00
state.next = t_State.SEARCH
else:
2005-12-19 11:20:04 +00:00
index.next = (index + 1) % FRAME_SIZE
2004-02-02 11:38:22 +00:00
SOF.next = 0
if state == t_State.SEARCH:
2005-12-19 11:20:04 +00:00
index.next = 1
2004-02-02 11:38:22 +00:00
if syncFlag:
state.next = t_State.CONFIRM
elif state == t_State.CONFIRM:
if index == 0:
if syncFlag:
state.next = t_State.SYNC
else:
state.next = t_State.SEARCH
elif state == t_State.SYNC:
if index == 0:
if not syncFlag:
state.next = t_State.SEARCH
SOF.next = (index == FRAME_SIZE-1)
else:
raise ValueError("Undefined state")
2005-12-19 11:20:04 +00:00
return FSM
2004-02-02 11:38:22 +00:00
\end{verbatim}
The conversion is done as before:
\begin{verbatim}
SOF = Signal(bool(0))
syncFlag = Signal(bool(0))
clk = Signal(bool(0))
reset_n = Signal(bool(1))
state = Signal(t_State.SEARCH)
framerctrl_inst = toVerilog(FramerCtrl, SOF, state, syncFlag, clk, reset_n)
\end{verbatim}
The Verilog output looks as follows:
\begin{verbatim}
2005-12-19 11:20:04 +00:00
module FramerCtrl (
2004-02-02 11:38:22 +00:00
SOF,
state,
syncFlag,
clk,
reset_n
);
2005-12-19 11:20:04 +00:00
2004-02-02 11:38:22 +00:00
output SOF;
reg SOF;
output [2:0] state;
reg [2:0] state;
input syncFlag;
input clk;
input reset_n;
2005-12-19 11:20:04 +00:00
reg [7:0] index;
always @(posedge clk or negedge reset_n) begin: _FramerCtrl_FSM
2004-02-02 11:38:22 +00:00
if ((reset_n == 0)) begin
SOF <= 0;
2005-12-19 11:20:04 +00:00
index <= 0;
2004-02-02 11:38:22 +00:00
state <= 3'b001;
end
else begin
2005-12-19 11:20:04 +00:00
index <= ((index + 1) % 8);
2004-02-02 11:38:22 +00:00
SOF <= 0;
// synthesis parallel_case full_case
casez (state)
3'b??1: begin
2005-12-19 11:20:04 +00:00
index <= 1;
2004-02-02 11:38:22 +00:00
if (syncFlag) begin
state <= 3'b010;
end
end
3'b?1?: begin
if ((index == 0)) begin
if (syncFlag) begin
state <= 3'b100;
end
else begin
state <= 3'b001;
end
end
end
3'b1??: begin
if ((index == 0)) begin
if ((!syncFlag)) begin
state <= 3'b001;
end
end
SOF <= (index == (8 - 1));
end
default: begin
2005-12-19 11:20:04 +00:00
$display("ValueError(Undefined state)");
2004-02-02 11:38:22 +00:00
$finish;
end
endcase
end
end
2005-12-19 11:20:04 +00:00
2004-02-02 11:38:22 +00:00
endmodule
\end{verbatim}
2005-12-19 11:20:04 +00:00
\subsection{RAM inference \label{conf-usage-RAM}}
Certain synthesis tools can map Verilog memories to RAM
2005-12-19 11:25:14 +00:00
structures. To support this interesting feature, the Verilog converter
2005-12-19 11:20:04 +00:00
maps lists of signals in MyHDL to Verilog memories.
The following MyHDL example is a ram model that uses a list of signals
to model the internal memory.
\begin{verbatim}
def RAM(dout, din, addr, we, clk, depth=128):
""" Ram model """
mem = [Signal(intbv(0)[8:]) for i in range(depth)]
@always(clk.posedge)
def write():
if we:
mem[int(addr)].next = din
@always_comb
def read():
dout.next = mem[int(addr)]
return write, read
\end{verbatim}
With the appropriate signal definitions for the interface ports, it is
converted to the following Verilog code. Note how the
list of signals \code{mem} is mapped to a Verilog memory.
\begin{verbatim}
module RAM (
dout,
din,
addr,
we,
clk
);
output [7:0] dout;
wire [7:0] dout;
input [7:0] din;
input [6:0] addr;
input we;
input clk;
reg [7:0] mem [0:128-1];
always @(posedge clk) begin: _RAM_write
if (we) begin
mem[addr] <= din;
end
end
assign dout = mem[addr];
endmodule
\end{verbatim}
\subsection{ROM inference \label{conf-usage-ROM}}
Some synthesis tools can infer a ROM memory from a case statement. The
2005-12-19 11:25:14 +00:00
Verilog converter can perform the expansion into a case statement
2005-12-19 11:20:04 +00:00
automatically, based on a higher level description. The ROM access is
described in a single line, by indexing into a tuple of integers. The
tuple can be described manually, but also by programmatical
means. Note that a tuple is used instead of a list to stress the
read-only character of the memory.
The following example illustrates this functionality. ROM access
is described as follows:
\begin{verbatim}
def rom(dout, addr, CONTENT):
@always_comb
def read():
dout.next = CONTENT[int(addr)]
return read
\end{verbatim}
2005-12-29 22:01:00 +00:00
The ROM content is described as a tuple of integers. When the
ROM content is defined, the conversion can be performed:
2004-02-02 11:38:22 +00:00
2005-12-19 11:20:04 +00:00
\begin{verbatim}
CONTENT = (17, 134, 52, 9)
dout = Signal(intbv(0)[8:])
addr = Signal(intbv(0)[4:])
toVerilog(rom, dout, addr, CONTENT)
\end{verbatim}
The Verilog output code is as follows:
\begin{verbatim}
module rom (
dout,
addr
);
output [7:0] dout;
reg [7:0] dout;
input [3:0] addr;
always @(addr) begin: _rom_read
// synthesis parallel_case full_case
case (addr)
0: dout <= 17;
1: dout <= 134;
2: dout <= 52;
default: dout <= 9;
endcase
end
endmodule
\end{verbatim}
\subsection{User-defined Verilog code \label{conf-usage-custom}}
2005-12-27 12:58:07 +00:00
MyHDL provides a way to include user-defined Verilog
2005-12-19 11:20:04 +00:00
code during the conversion process.
2005-12-19 11:25:14 +00:00
MyHDL defines a hook that is understood by the converter but ignored by
2005-12-19 11:20:04 +00:00
the simulator. The hook is called \code{__verilog__}. It operates
like a special return value. When a MyHDL function defines
\code{__verilog__}, the Verilog converter will use its value instead of the
regular return value.
The value of \code{__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:
\begin{verbatim}
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;
"""
2004-02-02 11:38:22 +00:00
2005-12-19 11:20:04 +00:00
return logic
\end{verbatim}
The converted code looks as follows:
\begin{verbatim}
module inc_comb (
nextCount,
count
);
output [7:0] nextCount;
wire [7:0] nextCount;
input [7:0] count;
assign nextCount = (count + 1) % 128;
endmodule
\end{verbatim}
In this example, conversion of the \function{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
2005-12-19 11:25:14 +00:00
Verilog converter infers inputs, internal signals, and outputs. It
2005-12-19 11:20:04 +00:00
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 \code{driven} attribute for signals that are driven from
the user-defined code. In the example code above, note the following
assignment:
\begin{verbatim}
nextCount.driven = "wire"
\end{verbatim}
This specifies that the nextCount signal is driven as a Verilog wire
from this module. The allowed values of the driven attribute are
2005-12-29 22:01:00 +00:00
\code{'wire'} and \code{'reg'}. The value specifies how the
2005-12-19 11:20:04 +00:00
user-defined Verilog code drives the signal in Verilog. To decide
which value to use, consider how the signal should be declared in
2005-12-29 22:01:00 +00:00
Verilog after the user-defined code is inserted.
2005-12-19 11:20:04 +00:00
\section{Known issues\label{conv-issues}}
\begin{description}
2004-02-02 11:38:22 +00:00
\item[Verilog integers are 32 bit wide]
Usually, Verilog integers are 32 bit wide. In contrast, Python is
moving toward integers with undefined width. Python \class{int}
and \class{long} variables are mapped to Verilog integers; so for values
2004-02-04 15:36:03 +00:00
wider than 32 bit this mapping is incorrect.
2004-02-02 11:38:22 +00:00
\item[Synthesis pragmas are specified as Verilog comments.] The recommended
way to specify synthesis pragmas in Verilog is through attribute
2005-12-29 22:01:00 +00:00
lists. However, the Icarus simulator doesn't support them
2004-02-02 11:38:22 +00:00
for \code{case} statements (to specify \code{parallel_case} and
2005-12-29 22:01:00 +00:00
\code{full_case} pragmas). Therefore, the old
but deprecated method of synthesis pragmas in Verilog comments
is still used.
2004-02-02 11:38:22 +00:00
\item[Inconsistent place of the sensitivity list inferred from \code{always_comb}.]
The semantics of \code{always_comb}, both in Verilog and \myhdl{}, is to
have an implicit sensitivity list at the end of the code. However, this
may not be synthesizable. Therefore, the inferred sensitivity list is
put at the top of the corresponding \code{always} block.
This may cause inconsistent behavior at the start of the
simulation. The workaround is to create events at time 0.
\item[Non-blocking assignments to task arguments don't work.]
2005-12-29 22:01:00 +00:00
Non-blocking (signal) assignments to task arguments don't work
for an as yet unknown reason.
2004-02-02 11:38:22 +00:00
\end{description}