2003-11-28 15:12:59 +00:00
|
|
|
\documentclass{howto}
|
|
|
|
% \usepackage{distutils}
|
|
|
|
\usepackage{palatino}
|
|
|
|
\renewcommand{\ttdefault}{cmtt}
|
|
|
|
\renewcommand{\sfdefault}{cmss}
|
|
|
|
\newcommand{\myhdl}{\protect \mbox{MyHDL}}
|
|
|
|
\usepackage{graphicx}
|
|
|
|
% $Id$
|
|
|
|
|
2004-01-29 22:58:53 +00:00
|
|
|
\title{New in \myhdl\ 0.4: Verilog conversion for implementation}
|
2003-11-28 15:12:59 +00:00
|
|
|
\release{0.4}
|
|
|
|
\author{Jan Decaluwe}
|
|
|
|
\authoraddress{\email{jan@jandecaluwe.com}}
|
|
|
|
|
|
|
|
\begin{document}
|
|
|
|
\maketitle
|
|
|
|
\tableofcontents
|
|
|
|
|
|
|
|
|
2004-01-29 22:58:53 +00:00
|
|
|
\section{Introduction and rationale\label{section-intro}}
|
2004-01-07 21:21:42 +00:00
|
|
|
|
2004-01-29 22:58:53 +00:00
|
|
|
MyHDL 0.4 provides a path to automatic implementation
|
|
|
|
through conversion to Verilog. Automatic implementation
|
|
|
|
is called \emph{synthesis} in the hardware design
|
|
|
|
world and the corresponding source code is called
|
|
|
|
\emph{synthesizable code}.
|
|
|
|
|
|
|
|
In a typical design project, the amount of synthesizable code is
|
|
|
|
only a small fraction all source code: the larger part will consist of
|
|
|
|
high-level models, project maintenance and automation code, and
|
|
|
|
verification related code such as test benches.
|
|
|
|
|
|
|
|
Still, synthesizable code is of special importance in several
|
|
|
|
ways. First, the implementation is what counts in the end. Secondly,
|
|
|
|
synthesizable code has important restrictions and a different concept
|
|
|
|
of Quality of Results. Finally, synthesizable code is what many
|
|
|
|
designers like to do most and first (regardless of whether this is a
|
|
|
|
good idea from a methodology viewpoint).
|
|
|
|
|
|
|
|
MyHDL aims to be a complete solution, but prior to 0.4 a MyHDL user
|
|
|
|
had to translate synthesizable code manually to Verilog or
|
|
|
|
VHDL. Needless to say, this is very inconvenient. With 0.4,
|
|
|
|
this manual step should no longer be necessary. XXX advantages.
|
|
|
|
|
|
|
|
\section{Solution description\label{section-solution}}
|
2004-01-07 21:21:42 +00:00
|
|
|
|
|
|
|
The solution works as follows. The hardware description should be
|
2004-01-29 22:58:53 +00:00
|
|
|
modeled in \myhdl\ style, and satisfy certain constraints
|
2004-01-28 09:55:45 +00:00
|
|
|
that are typical for implementation-oriented hardware modeling.
|
2004-01-07 21:21:42 +00:00
|
|
|
Subsequently, such a design is converted to an equivalent model in the
|
2004-01-29 22:58:53 +00:00
|
|
|
Verilog language, using the function \function{toVerilog}
|
|
|
|
from the \myhdl\ library. Finally,
|
2004-01-07 21:21:42 +00:00
|
|
|
an third-party \emph{synthesis tool} is used to convert the Verilog
|
|
|
|
design into a gate implementation for an ASIC or FPGA. There are a
|
|
|
|
number of Verilog synthesis tools available, varying in price,
|
|
|
|
capabilities, and target implementation space.
|
|
|
|
|
|
|
|
|
2004-01-29 22:58:53 +00:00
|
|
|
\section{Features\label{section-features}}
|
2004-01-07 21:21:42 +00:00
|
|
|
|
2004-01-29 22:58:53 +00:00
|
|
|
\subsection{The design is converted after elaboration}
|
2004-01-07 21:21:42 +00:00
|
|
|
\emph{Elaboration} refers to the initial processing of
|
2004-01-29 22:58:53 +00:00
|
|
|
a hardware description to achieve a representation of a
|
|
|
|
design instance that
|
2004-01-07 21:21:42 +00:00
|
|
|
is ready for simulation or synthesis. In particular, structural
|
|
|
|
parameters and constructs are processed in this step. In
|
2004-01-28 16:20:52 +00:00
|
|
|
\myhdl{}, the Python interpreter itself is used for elaboration.
|
2004-01-29 22:58:53 +00:00
|
|
|
A \class{Simulation} 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.
|
|
|
|
|
|
|
|
\subsection{The structural description can be arbitrarily complex and hierarchical}
|
|
|
|
As the conversion works on an elaborated design instance, any modeling
|
2004-01-07 21:21:42 +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:
|
2004-01-28 16:20:52 +00:00
|
|
|
Python's full power can be used for that purpose. Also, the
|
|
|
|
design hierarchy can be arbitrarily deep.
|
2004-01-07 21:21:42 +00:00
|
|
|
|
2004-01-29 22:58:53 +00:00
|
|
|
\subsection{If-then-else structures may be mapped to case statements}
|
2004-01-07 21:21:42 +00:00
|
|
|
Python does not provide a case statement. However,
|
2004-01-28 09:55:45 +00:00
|
|
|
the converter recognizes if-then-else structures in which a variable is
|
2004-01-07 21:21:42 +00:00
|
|
|
sequentially compared to items of an enumeration type, and maps
|
|
|
|
such a structure to a Verilog case statement with the appropriate
|
|
|
|
synthesis attributes.
|
|
|
|
|
2004-01-29 22:58:53 +00:00
|
|
|
\subsection{Support for one hot and one cold encoding}
|
2004-01-07 21:21:42 +00:00
|
|
|
The \function{enum} function in \myhdl\ returns an enumeration type. This
|
2004-01-28 09:55:45 +00:00
|
|
|
function takes an additional parameter \var{encoding} that specifies the
|
2004-01-07 21:21:42 +00:00
|
|
|
desired encoding in the implementation: binary, one hot, or one cold.
|
2004-01-28 16:20:52 +00:00
|
|
|
The Verilog converter generates the appropriate code.
|
2004-01-07 21:21:42 +00:00
|
|
|
|
|
|
|
|
2004-01-29 22:58:53 +00:00
|
|
|
\section{The convertible subset}
|
|
|
|
|
|
|
|
\subsection{Introduction}
|
|
|
|
|
|
|
|
Unsurprisingly, not all Python code can be converted into Verilog. In
|
|
|
|
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 implementation
|
|
|
|
attempts to issue clear error messages when it encounters a construct
|
|
|
|
that cannot be converted.
|
|
|
|
|
|
|
|
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 was done. For example, it is actually easier to convert
|
|
|
|
while loops than for loops even though they are not RTL-synthesizable.
|
|
|
|
As another example, '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.
|
|
|
|
|
|
|
|
Recall that any restrictions only apply to the design post
|
|
|
|
elaboration. In practice, this means that they apply only to the code
|
|
|
|
of the generators, that are the "leaf" functional blocks in a MyHDL
|
|
|
|
design.
|
|
|
|
|
|
|
|
\subsection{Coding style}
|
|
|
|
|
|
|
|
A natural restriction on convertible code is that it should be
|
|
|
|
written in MyHDL style: cooperating generators, communicating through
|
|
|
|
signals, and with \code{yield} statements specifying wait points and resume
|
|
|
|
conditions. Supported resume conditions are a signal edge, a signal
|
|
|
|
change, or a tuple of such conditions.
|
|
|
|
|
|
|
|
\subsection{Supported types}
|
|
|
|
|
|
|
|
The most important restriction regards object types. Verilog is an
|
|
|
|
almost typeless language, while Python is strongly (albeit
|
|
|
|
dynamically) typed. The converter needs to infer the types of
|
|
|
|
variables and map them to Verilog types. Therefore, it does type
|
2004-01-30 16:35:47 +00:00
|
|
|
inferencing of object constructors and expressions.
|
|
|
|
|
|
|
|
Only a limited amount of types can be converted.
|
|
|
|
Python \class{int} and \class{long} objects are mapped to Verilog
|
2004-01-29 22:58:53 +00:00
|
|
|
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}.
|
|
|
|
|
|
|
|
\class{intbv} objects need to be constructed so that a bit
|
2004-01-30 16:35:47 +00:00
|
|
|
width can be inferred. This can be done by specifying minimum
|
|
|
|
and maximum values, e.g. as follows:
|
|
|
|
|
|
|
|
\begin{verbatim}
|
|
|
|
index = intbv(0, min=0, max=2**N)
|
|
|
|
\end{verbatim}
|
|
|
|
|
|
|
|
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} inclusive, and maximum value \code{2**N} exclusive.
|
|
|
|
|
2004-01-29 22:58:53 +00:00
|
|
|
|
|
|
|
\subsection{Supported statements}
|
|
|
|
|
|
|
|
The following is a list of the statements that are supported by the
|
|
|
|
Verilog converter, possibly qualified with restrictions. Recall that
|
|
|
|
this list only applies to the design post elaboration: in practice,
|
|
|
|
this means it applies to the code of the generators that are the leaf
|
|
|
|
blocks in a design.
|
|
|
|
|
|
|
|
\begin{description}
|
|
|
|
|
|
|
|
\item[The \keyword{break} statement.]
|
|
|
|
|
|
|
|
\item[The \keyword{continue} statement.]
|
|
|
|
|
|
|
|
\item[The \keyword{def} statement.]
|
|
|
|
|
|
|
|
\item[The \keyword{for} statement.]
|
2004-01-30 16:35:47 +00:00
|
|
|
The only supported iteration scheme is through lists of
|
|
|
|
integers returned by builtin function \function{range}
|
|
|
|
or \myhdl\ function \function{downrange} is supported.
|
2004-01-29 22:58:53 +00:00
|
|
|
The optional \keyword{else}
|
2004-01-30 16:35:47 +00:00
|
|
|
clause is not supported.
|
2004-01-29 22:58:53 +00:00
|
|
|
|
|
|
|
\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-01-30 16:35:47 +00:00
|
|
|
The only supported expression for printing is
|
|
|
|
a single literal string.
|
|
|
|
The string can be interpolated, but the format specifiers
|
|
|
|
are copied verbatim to the Verilog output.
|
|
|
|
Print to a file with syntax \code{'>>'} is not supported.
|
2004-01-29 22:58:53 +00:00
|
|
|
|
|
|
|
\item[The \keyword{raise} statement.]
|
2004-01-30 16:35:47 +00:00
|
|
|
This statement is mapped to Verilog statements
|
|
|
|
that end the simulation with an error message.
|
2004-01-29 22:58:53 +00:00
|
|
|
|
|
|
|
\item[The \keyword{return} statement.]
|
|
|
|
|
|
|
|
\item[The \keyword{yield} statement.]
|
2004-01-30 16:35:47 +00:00
|
|
|
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.
|
2004-01-29 22:58:53 +00:00
|
|
|
|
|
|
|
\item[The \keyword{while} statement.]
|
|
|
|
The optional \keyword{else}
|
2004-01-30 16:35:47 +00:00
|
|
|
clause is not supported.
|
2004-01-29 22:58:53 +00:00
|
|
|
|
2004-01-07 21:21:42 +00:00
|
|
|
\end{description}
|
|
|
|
|
2004-01-30 16:35:47 +00:00
|
|
|
\section{Methodology notes}
|
|
|
|
XXX
|
|
|
|
|
2004-01-28 16:20:52 +00:00
|
|
|
\section{Converter usage}
|
|
|
|
|
|
|
|
We will demonstrate the conversion process by showing some examples.
|
|
|
|
|
|
|
|
\subsection{A small design with a single generator}
|
|
|
|
|
|
|
|
Consider the following MyHDL code for an incrementer module:
|
|
|
|
|
|
|
|
\begin{verbatim}
|
|
|
|
def inc(count, enable, clock, reset, n):
|
|
|
|
""" Incrementer with enable.
|
|
|
|
|
|
|
|
count -- output
|
|
|
|
enable -- control input, increment when 1
|
|
|
|
clock -- clock input
|
|
|
|
reset -- asynchronous reset input
|
|
|
|
n -- counter max value
|
|
|
|
"""
|
|
|
|
def incProcess():
|
|
|
|
while 1:
|
|
|
|
yield posedge(clock), negedge(reset)
|
|
|
|
if reset == ACTIVE_LOW:
|
|
|
|
count.next = 0
|
|
|
|
else:
|
|
|
|
if enable:
|
|
|
|
count.next = (count + 1) % n
|
|
|
|
return incProcess()
|
|
|
|
\end{verbatim}
|
|
|
|
|
|
|
|
In Verilog terminology, function \function{inc} corresponds to a
|
|
|
|
module, while generator function \function{incProcess}
|
|
|
|
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
|
|
|
|
effect, it also generates a Verilog module in file \file{inc_inst.v},
|
|
|
|
that is supposed to have identical behavior. The Verilog code
|
|
|
|
is as follows:
|
|
|
|
|
|
|
|
\begin{verbatim}
|
|
|
|
module inc_inst (
|
|
|
|
count,
|
|
|
|
enable,
|
|
|
|
clock,
|
|
|
|
reset
|
|
|
|
);
|
|
|
|
|
|
|
|
output [7:0] count;
|
|
|
|
reg [7:0] count;
|
|
|
|
input enable;
|
|
|
|
input clock;
|
|
|
|
input reset;
|
|
|
|
|
|
|
|
|
2004-01-30 10:25:58 +00:00
|
|
|
always @(posedge clock or negedge reset) begin: _MYHDL1_BLOCK
|
2004-01-28 16:20:52 +00:00
|
|
|
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.
|
|
|
|
|
|
|
|
\subsection{Converting a generator directly}
|
|
|
|
|
|
|
|
It is also possible to convert a generator
|
|
|
|
directly. For example, consider the following generator function:
|
|
|
|
|
|
|
|
\begin{verbatim}
|
|
|
|
def bin2gray(B, G, width):
|
|
|
|
""" Gray encoder.
|
|
|
|
|
|
|
|
B -- input intbv signal, binary encoded
|
|
|
|
G -- output intbv signal, gray encoded
|
|
|
|
width -- bit width
|
|
|
|
"""
|
|
|
|
Bext = intbv(0)[width+1:]
|
|
|
|
while 1:
|
|
|
|
yield B
|
|
|
|
Bext[:] = B
|
|
|
|
for i in range(width):
|
|
|
|
G.next[i] = Bext[i+1] ^ Bext[i]
|
|
|
|
\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}
|
|
|
|
|
|
|
|
The generate Verilog module is as follows:
|
|
|
|
|
|
|
|
\begin{verbatim}
|
|
|
|
module bin2gray_inst (
|
|
|
|
B,
|
|
|
|
G
|
|
|
|
);
|
|
|
|
|
|
|
|
input [7:0] B;
|
|
|
|
output [7:0] G;
|
|
|
|
reg [7:0] G;
|
|
|
|
|
2004-01-30 10:25:58 +00:00
|
|
|
always @(B) begin: _MYHDL1_BLOCK
|
2004-01-28 16:20:52 +00:00
|
|
|
integer i;
|
|
|
|
reg [9-1:0] Bext;
|
|
|
|
Bext[9-1:0] = B;
|
|
|
|
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}
|
|
|
|
The hierarchy of convertible designs can be
|
|
|
|
arbitrarily deep.
|
|
|
|
|
|
|
|
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}
|
|
|
|
def GrayInc(graycnt, enable, clock, reset, width):
|
|
|
|
|
|
|
|
bincnt = Signal(intbv()[width:])
|
|
|
|
|
|
|
|
INC_1 = inc(bincnt, enable, clock, reset, n=2**width)
|
|
|
|
BIN2GRAY_1 = bin2gray(B=bincnt, G=graycnt, width=width)
|
|
|
|
|
|
|
|
return INC_1, BIN2GRAY_1
|
|
|
|
\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
|
|
|
|
hierarchy an add an output register to the design.
|
|
|
|
(This will create an additional latency of a clock
|
|
|
|
cycle, which may not be acceptable, but we will
|
|
|
|
ignore that here.)
|
|
|
|
|
|
|
|
\begin{verbatim}
|
|
|
|
def GrayIncReg(graycnt, enable, clock, reset, width):
|
|
|
|
|
|
|
|
graycnt_comb = Signal(intbv()[width:])
|
|
|
|
|
|
|
|
GRAY_INC_1 = GrayInc(graycnt_comb, enable, clock, reset, width)
|
|
|
|
|
|
|
|
def reg():
|
|
|
|
while 1:
|
|
|
|
yield posedge(clock)
|
|
|
|
graycnt.next = graycnt_comb
|
|
|
|
REG_1 = reg()
|
|
|
|
|
|
|
|
return GRAY_INC_1, REG_1
|
|
|
|
\end{verbatim}
|
|
|
|
|
|
|
|
We can convert this hierchical design as usual:
|
|
|
|
|
|
|
|
\begin{verbatim}
|
|
|
|
width = 8
|
|
|
|
graycnt = Signal(intbv()[width:])
|
|
|
|
enable, clock, reset = [Signal(bool()) for i in range(3)]
|
|
|
|
|
2004-01-28 23:07:16 +00:00
|
|
|
GRAY_INC_REG_1 = toVerilog(GrayIncReg, graycnt, enable, clock, reset, width)
|
2004-01-28 16:20:52 +00:00
|
|
|
\end{verbatim}
|
|
|
|
|
|
|
|
The Verilog output module looks as follows:
|
|
|
|
|
|
|
|
\begin{verbatim}
|
|
|
|
module GRAY_INC_REG_1 (
|
|
|
|
graycnt,
|
|
|
|
enable,
|
|
|
|
clock,
|
|
|
|
reset
|
|
|
|
);
|
|
|
|
|
|
|
|
output [7:0] graycnt;
|
|
|
|
reg [7:0] graycnt;
|
|
|
|
input enable;
|
|
|
|
input clock;
|
|
|
|
input reset;
|
|
|
|
|
|
|
|
reg [7:0] graycnt_comb;
|
|
|
|
reg [7:0] _GRAY_INC_1_bincnt;
|
|
|
|
|
2004-01-30 10:25:58 +00:00
|
|
|
always @(posedge clock or negedge reset) begin: _MYHDL1_BLOCK
|
2004-01-28 16:20:52 +00:00
|
|
|
if ((reset == 0)) begin
|
|
|
|
_GRAY_INC_1_bincnt <= 0;
|
|
|
|
end
|
|
|
|
else begin
|
|
|
|
if (enable) begin
|
|
|
|
_GRAY_INC_1_bincnt <= ((_GRAY_INC_1_bincnt + 1) % 256);
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2004-01-30 10:25:58 +00:00
|
|
|
always @(_GRAY_INC_1_bincnt) begin: _MYHDL4_BLOCK
|
2004-01-28 16:20:52 +00:00
|
|
|
integer i;
|
|
|
|
reg [9-1:0] Bext;
|
|
|
|
Bext[9-1:0] = _GRAY_INC_1_bincnt;
|
|
|
|
for (i=0; i<8; i=i+1) begin
|
|
|
|
graycnt_comb[i] <= (Bext[(i + 1)] ^ Bext[i]);
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2004-01-30 10:25:58 +00:00
|
|
|
always @(posedge clock) begin: _MYHDL9_BLOCK
|
2004-01-28 16:20:52 +00:00
|
|
|
graycnt <= graycnt_comb;
|
|
|
|
end
|
|
|
|
|
|
|
|
endmodule
|
|
|
|
\end{verbatim}
|
|
|
|
|
|
|
|
Note that the output is a flat ``netlist of blocks'', and
|
|
|
|
that hierarchical signal names are generated as necessary.
|
|
|
|
|
2004-01-29 22:58:53 +00:00
|
|
|
\subsection{Optimizations for finite state machines}
|
2004-01-28 22:45:06 +00:00
|
|
|
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
|
|
|
|
'encoding'. For example:
|
|
|
|
|
|
|
|
\begin{verbatim}
|
|
|
|
t_State = enum('SEARCH', 'CONFIRM', 'SYNC', encoding="one_hot")
|
|
|
|
\end{verbatim}
|
|
|
|
|
|
|
|
The default encoding is \code{binary}; the other possibilities are \code{one_hot} and
|
|
|
|
\code{one_cold}. This parameter only affects the conversion output, not the
|
|
|
|
behavior of the type. Verilog case statements are optimized for an
|
|
|
|
efficient implementation according to the encoding. Note that in
|
|
|
|
contrast, a Verilog designer needs to make nontrivial code changes to
|
|
|
|
implement a different encoding scheme.
|
|
|
|
|
|
|
|
As an example, consider the following finite state machine, whose
|
|
|
|
state variable used the enumeration type defined above:
|
|
|
|
|
|
|
|
\begin{verbatim}
|
2004-01-30 10:25:58 +00:00
|
|
|
FRAME_SIZE = 8
|
|
|
|
|
2004-01-28 22:45:06 +00:00
|
|
|
def FramerCtrl(SOF, state, syncFlag, clk, reset_n):
|
|
|
|
|
|
|
|
""" 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
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
2004-01-30 10:25:58 +00:00
|
|
|
index = intbv(0, min=0, max=8) # position in frame
|
2004-01-28 22:45:06 +00:00
|
|
|
while 1:
|
|
|
|
yield posedge(clk), negedge(reset_n)
|
|
|
|
if reset_n == ACTIVE_LOW:
|
|
|
|
SOF.next = 0
|
|
|
|
index[:] = 0
|
|
|
|
state.next = t_State.SEARCH
|
|
|
|
else:
|
|
|
|
SOF.next = 0
|
|
|
|
if state == t_State.SEARCH:
|
|
|
|
index[:] = 0
|
|
|
|
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")
|
|
|
|
index[:]= (index + 1) % FRAME_SIZE
|
|
|
|
|
|
|
|
\end{verbatim}
|
|
|
|
|
|
|
|
The conversion is done as usual:
|
|
|
|
|
|
|
|
\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}
|
|
|
|
module framerctrl_inst (
|
|
|
|
SOF,
|
|
|
|
state,
|
|
|
|
syncFlag,
|
|
|
|
clk,
|
2004-01-30 10:25:58 +00:00
|
|
|
reset_n
|
2004-01-28 22:45:06 +00:00
|
|
|
);
|
|
|
|
output SOF;
|
|
|
|
reg SOF;
|
|
|
|
output [2:0] state;
|
|
|
|
reg [2:0] state;
|
|
|
|
input syncFlag;
|
|
|
|
input clk;
|
|
|
|
input reset_n;
|
|
|
|
|
2004-01-30 10:25:58 +00:00
|
|
|
always @(posedge clk or negedge reset_n) begin: _MYHDL1_BLOCK
|
|
|
|
reg [3-1:0] index;
|
2004-01-28 22:45:06 +00:00
|
|
|
if ((reset_n == 0)) begin
|
|
|
|
SOF <= 0;
|
2004-01-30 10:25:58 +00:00
|
|
|
index[3-1:0] = 0;
|
2004-01-28 22:45:06 +00:00
|
|
|
state <= 3'b001;
|
|
|
|
end
|
|
|
|
else begin
|
|
|
|
SOF <= 0;
|
|
|
|
// synthesis parallel_case full_case
|
|
|
|
casez (state)
|
|
|
|
3'b??1: begin
|
2004-01-30 10:25:58 +00:00
|
|
|
index[3-1:0] = 0;
|
2004-01-28 22:45:06 +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
|
|
|
|
$display("Verilog: ValueError(Undefined state)");
|
|
|
|
$finish;
|
|
|
|
end
|
|
|
|
endcase
|
2004-01-30 10:25:58 +00:00
|
|
|
index[3-1:0] = ((index + 1) % 8);
|
2004-01-28 22:45:06 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
endmodule
|
|
|
|
\end{verbatim}
|
|
|
|
|
2004-01-28 16:20:52 +00:00
|
|
|
|
2004-01-07 21:21:42 +00:00
|
|
|
\section{Known issues}
|
|
|
|
\begin{description}
|
|
|
|
|
|
|
|
\item[Negative values of \class{intbv} instances are not supported.]
|
|
|
|
The \class{intbv} class is quite capable of representing negative
|
|
|
|
values. However, the \code{signed} type support in Verilog is
|
2004-01-28 09:55:45 +00:00
|
|
|
relatively recent and mapping to it may be tricky. In my judgment,
|
2004-01-07 21:21:42 +00:00
|
|
|
this is not the most urgent requirement, so
|
|
|
|
I decided to leave this for later.
|
|
|
|
|
2004-01-28 16:20:52 +00:00
|
|
|
\item[Verilog integers are 32 bit wide]
|
|
|
|
Usually, Verilog integers are 32 bit wide. In contrast, Python is
|
|
|
|
moving towards integers with undefined width. Python \class{int}
|
|
|
|
and \class{long} variables are mapped to Verilog integers; so for values
|
|
|
|
larger than 32 bit this mapping is incorrect.
|
|
|
|
|
2004-01-28 09:55:45 +00:00
|
|
|
\item[Synthesis pragmas are specified as Verilog comments.] The recommended
|
2004-01-07 21:21:42 +00:00
|
|
|
way to specify synthesis pragmas in Verilog is through attribute
|
2004-01-28 09:55:45 +00:00
|
|
|
lists. However, my Verilog simulator (Icarus) doesn't support them
|
2004-01-07 21:21:42 +00:00
|
|
|
for \code{case} statements (to specify \code{parallel_case} and
|
|
|
|
\code{full_case} pragmas). Therefore, I still used the old
|
|
|
|
but deprecated method of synthesis pragmas in Verilog comments.
|
|
|
|
|
2004-01-28 09:55:45 +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.]
|
2004-01-07 21:21:42 +00:00
|
|
|
I didn't get non-blocking (signal) assignments to task arguments to
|
|
|
|
work. I don't know yet whether the issue is my own, a Verilog issue,
|
|
|
|
or an issue with my Verilog simulator Icarus. I'll need to check this
|
|
|
|
further.
|
|
|
|
|
|
|
|
|
|
|
|
\end{description}
|
2003-11-28 15:12:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
\end{document}
|