Skip to content
Fetching contributors…
Cannot retrieve contributors at this time
201 lines (161 sloc) 9.04 KB
* Copyright (c) 1998-1999 Stephen Williams (
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
#ident "$Id: netlist.txt,v 1.3 1999/07/24 02:11:20 steve Exp $"
Note that the netlist.h header contains detailed descriptions of how
things work. This is just an overview.
The output from the parse and elaboration steps is a "netlist" rooted
in a Design object. Parsing translates the design described in the
initial source file into a temporary symbolic "pform". Elaboration
then expands the design, resolving references and expanding
hierarchies, to produce a flattened netlist. This is the form that
optimizers and code generators use.
The design optimization processes all manipulate the netlist,
translating it to a (hopefully) better netlist after each step. The
complete netlist is then passed to the code generator, the emit
function, where the final code (in the target format) is produced.
Components and wires, memories and registers all at their base are
either NetNode objects or NetNet objects. Even these classes are
derived from the NetObj class.
All NetNode and NetNet objects have a name and some number of
pins. The name usually comes from the Verilog source that represents
that object, although objects that are artifacts of elaboration will
have a generated (and probably unreadable) name. The pins are the
ports into the device. NetNode objects have a pin for each pin of the
component it represents, and NetNet objects have a pin for each signal
in the vector.
Node and net pins can be connected together via the connect
function. Connections are transitive (A==B and B==c means A==C) so
connections accumulate on a link as items are connected to it. The
descructors for nets and nodes automatically arrange for pins to be
disconnected when the item is deleted, so that the netlist can be
changed during processing.
BEHAVIORAL ITEMS: NetProcTop, NetProc and derived classes
Behavioral items are not in general linked to the netlist. Instead,
they represent elabrated behavioral statements. The type of the object
implies what the behavior of the statement does. For example, a
NetCondit object represents an ``if'' statement, and carries a
condition expression and up to two alternative sub-statements.
At the root of a process is a NetProcTop object. This class carries a
type flag (initial or always) and a single NetProc object. The
contained statement may, depending on the derived class, refer to
other statements, compound statements, so on. But at the root of the
tree is the NetProcTop object. The Design class keeps a list of the
elaborated NetProcTop objects. That list represents the list of
processes in the design.
The behavioral statements in a Verilog design effect the structural
aspects through assignments to registers. Registers are structural
items represented by the NetNet class, linked to the assignment
statement through pins. This implies that the l-value of an assignment
is structural. It also implies that the statement itself is
structural, and indeed it is derived from NetNode.
The NetAssign_ class is also derived from the NetProc class because
what it does is brought on by executing the process. By multiple
inheritance we have therefore that the assignment is both a NetNode
and a NetProc. The NetAssign_ node has pins that represent the l-value
of the statement, and carries behavioral expressions that represent
the r-value of the assignment.
Expressions are represented as a tree of NetExpr nodes. The NetExpr
base class contains the core methods that represent an expression
node, including virtual methods to help with dealing with nested
complexities of expressions.
Expressions (as expressed in the source and p-form) may also be
elaborated structurally, where it makes sense. For example, assignment
l-value expressions are represented as connections to pins. Also,
continuous assignment module items are elaborated as gates instead of
as a procedural expression. Event expressions are also elaborated
structurally as events are like devices that trigger behavioral
However, typical expressions the behavioral description are
represented as a tree of NetExpr nodes. The derived clas of the node
encodes what kind of operator the node represents.
The expression (represented by the NetExpr class) has a bit width that
it either explicitly specified, or implied by context or contents.
When each node of the expression is first constructed during
elaboration, it is given, by type and parameters, an idea what its
width should be. It certain cases, this is definitive, for example
with signals. In others, it is ambiguous, as with unsized constants.
As the expression is built up by elaboration, operators that combine
expressions impose bit widths of the environment or expose the bit
widths of the sub expressions. For example, the bitwise AND (&)
operator has a bit size implied by its operands, whereas the
comparison (==) operator has a bit size of 1. The building up of the
elaborated expression checks and adjusts the bit widths as the
expression is built up, until finally the context of the expression
takes the final bit width and makes any final adjustments.
The NetExpr::expr_width() method returns the calculated (or guessed)
expression width. This method will return 0 until the width is set by
calculation or context. If this method returns false, then it is up to
the context that wants the width to set one. The elaboration phase
will call the NetExpr::set_width method on an expression as soon as it
gets to a point where it believes that it knows what the width should
The NetExpr::set_width(unsigned) virtual method is used by the context
of an expression node to note to the expression that the width is
determined and please adapt. If the expression cannot reasonably
adapt, it will return false. Otherwise, it will adjust bit widths and
return true.
XXXX I do not yet properly deal with cases where elaboration knows for
XXXX certain that the bit width does not matter. In this case, I
XXXX really should tell the expression node about it so that it can
XXXX pick a practical (and optimal) width.
The NetAssign_ class described above is the means for processes to
manipulate the net, but values are read from the net by NetESignal
objects. These objects are class NetExpr because they can appear in
expressions (and have width) but are also class NetNode because they
connect to and receive signals from the structural aspects of the
The pins of a NetESignal object are passive. The values at the pin are
only sampled when the process evaluates the expression that includes
the NetESignal object.
The obvious hierarchical structure of verilog is the module. The
Verilog program may contain any number of instantiations of modules in
order to form an hierarchical design. However, the elaboration of the
design into a netlist erases module boundaries. Modules are expanded
each place they are used, with the hierarchical instance name used to
name the components of the module instance. However, the fact that a
wire or register is a module port is lost.
The advantage of this behavior is first the simplification of the
netlist structure itself. Backends that process netlists only need to
cope with a list of nets, a list of nodes and a list of
processes. This eases the task of the backend code generators.
Another advantage of this flattening of the netlist is that optimizers
can operate globally, with optimizations freely crossing module
boundaries. This makes coding of netlist transform functions such as
constant propagation more effective and easier to write.
The flattening of the design does not include tasks and named
begin-end blocks. Tasks are behavioral hierarchy (whereas modules are
structural) so do not easily succumb to the flattening process. In
particular, it is logically impossible to flatten tasks that
recurse. (The elaboration process does reserve the right to flatten
some task calls. C++ programmers recognize this as inlining a task.)
$Log: netlist.txt,v $
Revision 1.3 1999/07/24 02:11:20 steve
Elaborate task input ports.
Revision 1.2 1999/07/21 01:15:29 steve
Document netlist semantics.
Revision 1.1 1999/05/27 04:13:08 steve
Handle expression bit widths with non-fatal errors.
Something went wrong with that request. Please try again.