1
0
mirror of https://github.com/myhdl/myhdl.git synced 2024-12-14 07:44:38 +08:00
myhdl/doc/whatsnew04/whatsnew04.tex

673 lines
20 KiB
TeX
Raw Normal View History

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}