mirror of
https://github.com/YosysHQ/yosys
synced 2025-06-06 14:13:23 +00:00
Reorganising documentation
Also changing to furo theme.
This commit is contained in:
parent
4f1cd66829
commit
045c04096e
40 changed files with 661 additions and 1282 deletions
48
docs/source/yosys_internals/extensions.rst
Normal file
48
docs/source/yosys_internals/extensions.rst
Normal file
|
@ -0,0 +1,48 @@
|
|||
.. _chapter:prog:
|
||||
|
||||
Writing extensions
|
||||
==================
|
||||
|
||||
.. TODO: copypaste
|
||||
|
||||
This chapter contains some bits and pieces of information about
|
||||
programming yosys extensions. Also consult the section on programming in
|
||||
the "Yosys Presentation" (can be downloaded from the Yosys website as
|
||||
PDF) and don't be afraid to ask questions on the YosysHQ Slack.
|
||||
|
||||
Guidelines
|
||||
----------
|
||||
|
||||
The guidelines directory contains notes on various aspects of Yosys
|
||||
development. The files GettingStarted and CodingStyle may be of
|
||||
particular interest, and are reproduced here.
|
||||
|
||||
.. literalinclude:: ../temp/GettingStarted
|
||||
:language: none
|
||||
:caption: guidelines/GettingStarted
|
||||
|
||||
.. literalinclude:: ../temp/CodingStyle
|
||||
:language: none
|
||||
:caption: guidelines/CodingStyle
|
||||
|
||||
The "stubsnets" example module
|
||||
------------------------------
|
||||
|
||||
The following is the complete code of the "stubsnets" example module. It
|
||||
is included in the Yosys source distribution as
|
||||
docs/source/CHAPTER_Prog/stubnets.cc.
|
||||
|
||||
.. literalinclude:: ../CHAPTER_Prog/stubnets.cc
|
||||
:language: c++
|
||||
:linenos:
|
||||
:caption: docs/source/CHAPTER_Prog/stubnets.cc
|
||||
|
||||
.. literalinclude:: ../CHAPTER_Prog/Makefile
|
||||
:language: makefile
|
||||
:linenos:
|
||||
:caption: docs/source/CHAPTER_Prog/Makefile
|
||||
|
||||
.. literalinclude:: ../CHAPTER_Prog/test.v
|
||||
:language: verilog
|
||||
:linenos:
|
||||
:caption: docs/source/CHAPTER_Prog/test.v
|
31
docs/source/yosys_internals/flow/control_and_data.rst
Normal file
31
docs/source/yosys_internals/flow/control_and_data.rst
Normal file
|
@ -0,0 +1,31 @@
|
|||
Control and data flow
|
||||
=====================
|
||||
|
||||
.. TODO: copypaste
|
||||
|
||||
The data- and control-flow of a typical synthesis tool is very similar to the
|
||||
data- and control-flow of a typical compiler: different subsystems are called in
|
||||
a predetermined order, each consuming the data generated by the last subsystem
|
||||
and generating the data for the next subsystem (see :numref:`Fig. %s
|
||||
<fig:approach_flow>`).
|
||||
|
||||
.. figure:: ../../../images/approach_flow.*
|
||||
:class: width-helper
|
||||
:name: fig:approach_flow
|
||||
|
||||
General data- and control-flow of a synthesis tool
|
||||
|
||||
The first subsystem to be called is usually called a frontend. It does not
|
||||
process the data generated by another subsystem but instead reads the user
|
||||
input—in the case of a HDL synthesis tool, the behavioural HDL code.
|
||||
|
||||
The subsystems that consume data from previous subsystems and produce data for
|
||||
the next subsystems (usually in the same or a similar format) are called passes.
|
||||
|
||||
The last subsystem that is executed transforms the data generated by the last
|
||||
pass into a suitable output format and writes it to a disk file. This subsystem
|
||||
is usually called the backend.
|
||||
|
||||
In Yosys all frontends, passes and backends are directly available as commands
|
||||
in the synthesis script. Thus the user can easily create a custom synthesis flow
|
||||
just by calling passes in the right order in a synthesis script.
|
10
docs/source/yosys_internals/flow/index.rst
Normal file
10
docs/source/yosys_internals/flow/index.rst
Normal file
|
@ -0,0 +1,10 @@
|
|||
Internal flow
|
||||
=============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
overview
|
||||
control_and_data
|
||||
verilog_frontend
|
||||
|
48
docs/source/yosys_internals/flow/overview.rst
Normal file
48
docs/source/yosys_internals/flow/overview.rst
Normal file
|
@ -0,0 +1,48 @@
|
|||
Flow overview
|
||||
=============
|
||||
|
||||
.. TODO: copypaste
|
||||
|
||||
:numref:`Figure %s <fig:Overview_flow>` shows the simplified data flow within
|
||||
Yosys. Rectangles in the figure represent program modules and ellipses internal
|
||||
data structures that are used to exchange design data between the program
|
||||
modules.
|
||||
|
||||
Design data is read in using one of the frontend modules. The high-level HDL
|
||||
frontends for Verilog and VHDL code generate an abstract syntax tree (AST) that
|
||||
is then passed to the AST frontend. Note that both HDL frontends use the same
|
||||
AST representation that is powerful enough to cover the Verilog HDL and VHDL
|
||||
language.
|
||||
|
||||
The AST Frontend then compiles the AST to Yosys's main internal data format, the
|
||||
RTL Intermediate Language (RTLIL). A more detailed description of this format is
|
||||
given in the next section.
|
||||
|
||||
There is also a text representation of the RTLIL data structure that can be
|
||||
parsed using the RTLIL Frontend.
|
||||
|
||||
The design data may then be transformed using a series of passes that all
|
||||
operate on the RTLIL representation of the design.
|
||||
|
||||
Finally the design in RTLIL representation is converted back to text by one of
|
||||
the backends, namely the Verilog Backend for generating Verilog netlists and the
|
||||
RTLIL Backend for writing the RTLIL data in the same format that is understood
|
||||
by the RTLIL Frontend.
|
||||
|
||||
With the exception of the AST Frontend, which is called by the high-level HDL
|
||||
frontends and can't be called directly by the user, all program modules are
|
||||
called by the user (usually using a synthesis script that contains text commands
|
||||
for Yosys).
|
||||
|
||||
By combining passes in different ways and/or adding additional passes to Yosys
|
||||
it is possible to adapt Yosys to a wide range of applications. For this to be
|
||||
possible it is key that (1) all passes operate on the same data structure
|
||||
(RTLIL) and (2) that this data structure is powerful enough to represent the
|
||||
design in different stages of the synthesis.
|
||||
|
||||
.. figure:: ../../../images/overview_flow.*
|
||||
:class: width-helper
|
||||
:name: fig:Overview_flow
|
||||
|
||||
Yosys simplified data flow (ellipses: data structures, rectangles:
|
||||
program modules)
|
666
docs/source/yosys_internals/flow/verilog_frontend.rst
Normal file
666
docs/source/yosys_internals/flow/verilog_frontend.rst
Normal file
|
@ -0,0 +1,666 @@
|
|||
.. _chapter:verilog:
|
||||
|
||||
The Verilog and AST frontends
|
||||
=============================
|
||||
|
||||
This chapter provides an overview of the implementation of the Yosys Verilog and
|
||||
AST frontends. The Verilog frontend reads Verilog-2005 code and creates an
|
||||
abstract syntax tree (AST) representation of the input. This AST representation
|
||||
is then passed to the AST frontend that converts it to RTLIL data, as
|
||||
illustrated in :numref:`Fig. %s <fig:Verilog_flow>`.
|
||||
|
||||
.. figure:: ../../../images/verilog_flow.*
|
||||
:class: width-helper
|
||||
:name: fig:Verilog_flow
|
||||
|
||||
Simplified Verilog to RTLIL data flow
|
||||
|
||||
Transforming Verilog to AST
|
||||
---------------------------
|
||||
|
||||
The Verilog frontend converts the Verilog sources to an internal AST
|
||||
representation that closely resembles the structure of the original
|
||||
Verilog code. The Verilog frontend consists of three components, the
|
||||
Preprocessor, the Lexer and the Parser.
|
||||
|
||||
The source code to the Verilog frontend can be found in
|
||||
frontends/verilog/ in the Yosys source tree.
|
||||
|
||||
The Verilog preprocessor
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The Verilog preprocessor scans over the Verilog source code and
|
||||
interprets some of the Verilog compiler directives such as
|
||||
:literal:`\`include`, :literal:`\`define` and :literal:`\`ifdef`.
|
||||
|
||||
It is implemented as a C++ function that is passed a file descriptor as
|
||||
input and returns the pre-processed Verilog code as a ``std::string``.
|
||||
|
||||
The source code to the Verilog Preprocessor can be found in
|
||||
frontends/verilog/preproc.cc in the Yosys source tree.
|
||||
|
||||
The Verilog lexer
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
The Verilog Lexer is written using the lexer generator flex . Its source
|
||||
code can be found in frontends/verilog/verilog_lexer.l in the Yosys
|
||||
source tree. The lexer does little more than identifying all keywords
|
||||
and literals recognised by the Yosys Verilog frontend.
|
||||
|
||||
The lexer keeps track of the current location in the Verilog source code
|
||||
using some global variables. These variables are used by the constructor
|
||||
of AST nodes to annotate each node with the source code location it
|
||||
originated from.
|
||||
|
||||
Finally the lexer identifies and handles special comments such as
|
||||
"``// synopsys translate_off``" and "``// synopsys full_case``". (It is
|
||||
recommended to use :literal:`\`ifdef` constructs instead of the
|
||||
Synsopsys translate_on/off comments and attributes such as
|
||||
``(* full_case *)`` over "``// synopsys full_case``" whenever possible.)
|
||||
|
||||
The Verilog parser
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The Verilog Parser is written using the parser generator bison . Its
|
||||
source code can be found in frontends/verilog/verilog_parser.y in the
|
||||
Yosys source tree.
|
||||
|
||||
It generates an AST using the ``AST::AstNode`` data structure defined in
|
||||
frontends/ast/ast.h. An ``AST::AstNode`` object has the following
|
||||
properties:
|
||||
|
||||
.. list-table:: AST node types with their corresponding Verilog constructs.
|
||||
:name: tab:Verilog_AstNodeType
|
||||
:widths: 50 50
|
||||
|
||||
* - AST Node Type
|
||||
- Corresponding Verilog Construct
|
||||
* - AST_NONE
|
||||
- This Node type should never be used.
|
||||
* - AST_DESIGN
|
||||
- This node type is used for the top node of the AST tree. It has no corresponding Verilog construct.
|
||||
* - AST_MODULE, AST_TASK, AST_FUNCTION
|
||||
- ``module``, ``task`` and ``function``
|
||||
* - AST_WIRE
|
||||
- ``input``, ``output``, ``wire``, ``reg`` and ``integer``
|
||||
* - AST_MEMORY
|
||||
- Verilog Arrays
|
||||
* - AST_AUTOWIRE
|
||||
- Created by the simplifier when an undeclared signal name is used.
|
||||
* - AST_PARAMETER, AST_LOCALPARAM
|
||||
- ``parameter`` and ``localparam``
|
||||
* - AST_PARASET
|
||||
- Parameter set in cell instantiation
|
||||
* - AST_ARGUMENT
|
||||
- Port connection in cell instantiation
|
||||
* - AST_RANGE
|
||||
- Bit-Index in a signal or element index in array
|
||||
* - AST_CONSTANT
|
||||
- A literal value
|
||||
* - AST_CELLTYPE
|
||||
- The type of cell in cell instantiation
|
||||
* - AST_IDENTIFIER
|
||||
- An Identifier (signal name in expression or cell/task/etc. name in other contexts)
|
||||
* - AST_PREFIX
|
||||
- Construct an identifier in the form <prefix>[<index>].<suffix> (used only in advanced generate constructs)
|
||||
* - AST_FCALL, AST_TCALL
|
||||
- Call to function or task
|
||||
* - AST_TO_SIGNED, AST_TO_UNSIGNED
|
||||
- The ``$signed()`` and ``$unsigned()`` functions
|
||||
* - AST_CONCAT, AST_REPLICATE
|
||||
- The ``{...}`` and ``{...{...}}`` operators
|
||||
* - AST_BIT_NOT, AST_BIT_AND, AST_BIT_OR, AST_BIT_XOR, AST_BIT_XNOR
|
||||
- The bitwise operators ``~``, ``&``, ``|``, ``^`` and ``~^``
|
||||
* - AST_REDUCE_AND, AST_REDUCE_OR, AST_REDUCE_XOR, AST_REDUCE_XNOR
|
||||
- The unary reduction operators ``~``, ``&``, ``|``, ``^`` and ``~^``
|
||||
* - AST_REDUCE_BOOL
|
||||
- Conversion from multi-bit value to boolean value (equivalent to AST_REDUCE_OR)
|
||||
* - AST_SHIFT_LEFT, AST_SHIFT_RIGHT, AST_SHIFT_SLEFT, AST_SHIFT_SRIGHT
|
||||
- The shift operators ``<<``, ``>>``, ``<<<`` and ``>>>``
|
||||
* - AST_LT, AST_LE, AST_EQ, AST_NE, AST_GE, AST_GT
|
||||
- The relational operators ``<``, ``<=``, ``==``, ``!=``, ``>=`` and ``>``
|
||||
* - AST_ADD, AST_SUB, AST_MUL, AST_DIV, AST_MOD, AST_POW
|
||||
- The binary operators ``+``, ``-``, ``*``, ``/``, ``%`` and ``**``
|
||||
* - AST_POS, AST_NEG
|
||||
- The prefix operators ``+`` and ``-``
|
||||
* - AST_LOGIC_AND, AST_LOGIC_OR, AST_LOGIC_NOT
|
||||
- The logic operators ``&&``, ``||`` and ``!``
|
||||
* - AST_TERNARY
|
||||
- The ternary ``?:``-operator
|
||||
* - AST_MEMRD AST_MEMWR
|
||||
- Read and write memories. These nodes are generated by the AST simplifier for writes/reads to/from Verilog arrays.
|
||||
* - AST_ASSIGN
|
||||
- An ``assign`` statement
|
||||
* - AST_CELL
|
||||
- A cell instantiation
|
||||
* - AST_PRIMITIVE
|
||||
- A primitive cell (``and``, ``nand``, ``or``, etc.)
|
||||
* - AST_ALWAYS, AST_INITIAL
|
||||
- Verilog ``always``- and ``initial``-blocks
|
||||
* - AST_BLOCK
|
||||
- A ``begin``-``end``-block
|
||||
* - AST_ASSIGN_EQ. AST_ASSIGN_LE
|
||||
- Blocking (``=``) and nonblocking (``<=``) assignments within an ``always``- or ``initial``-block
|
||||
* - AST_CASE. AST_COND, AST_DEFAULT
|
||||
- The ``case`` (``if``) statements, conditions within a case and the default case respectively
|
||||
* - AST_FOR
|
||||
- A ``for``-loop with an ``always``- or ``initial``-block
|
||||
* - AST_GENVAR, AST_GENBLOCK, AST_GENFOR, AST_GENIF
|
||||
- The ``genvar`` and ``generate`` keywords and ``for`` and ``if`` within a generate block.
|
||||
* - AST_POSEDGE, AST_NEGEDGE, AST_EDGE
|
||||
- Event conditions for ``always`` blocks.
|
||||
|
||||
- | The node type
|
||||
| This enum (``AST::AstNodeType``) specifies the role of the node.
|
||||
:numref:`Table %s <tab:Verilog_AstNodeType>`
|
||||
contains a list of all node types.
|
||||
|
||||
- | The child nodes
|
||||
| This is a list of pointers to all children in the abstract syntax
|
||||
tree.
|
||||
|
||||
- | Attributes
|
||||
| As almost every AST node might have Verilog attributes assigned to
|
||||
it, the ``AST::AstNode`` has direct support for attributes. Note
|
||||
that the attribute values are again AST nodes.
|
||||
|
||||
- | Node content
|
||||
| Each node might have additional content data. A series of member
|
||||
variables exist to hold such data. For example the member
|
||||
``std::string str`` can hold a string value and is used e.g. in the
|
||||
AST_IDENTIFIER node type to store the identifier name.
|
||||
|
||||
- | Source code location
|
||||
| Each ``AST::AstNode`` is automatically annotated with the current
|
||||
source code location by the ``AST::AstNode`` constructor. It is
|
||||
stored in the ``std::string filename`` and ``int linenum`` member
|
||||
variables.
|
||||
|
||||
The ``AST::AstNode`` constructor can be called with up to two child
|
||||
nodes that are automatically added to the list of child nodes for the
|
||||
new object. This simplifies the creation of AST nodes for simple
|
||||
expressions a bit. For example the bison code for parsing
|
||||
multiplications:
|
||||
|
||||
.. code:: none
|
||||
:number-lines:
|
||||
|
||||
basic_expr '*' attr basic_expr {
|
||||
$$ = new AstNode(AST_MUL, $1, $4);
|
||||
append_attr($$, $3);
|
||||
} |
|
||||
|
||||
The generated AST data structure is then passed directly to the AST
|
||||
frontend that performs the actual conversion to RTLIL.
|
||||
|
||||
Note that the Yosys command ``read_verilog`` provides the options ``-yydebug``
|
||||
and ``-dump_ast`` that can be used to print the parse tree or abstract
|
||||
syntax tree respectively.
|
||||
|
||||
Transforming AST to RTLIL
|
||||
-------------------------
|
||||
|
||||
The AST Frontend converts a set of modules in AST representation to
|
||||
modules in RTLIL representation and adds them to the current design.
|
||||
This is done in two steps: simplification and RTLIL generation.
|
||||
|
||||
The source code to the AST frontend can be found in ``frontends/ast/`` in
|
||||
the Yosys source tree.
|
||||
|
||||
AST simplification
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A full-featured AST is too complex to be transformed into RTLIL
|
||||
directly. Therefore it must first be brought into a simpler form. This
|
||||
is done by calling the ``AST::AstNode::simplify()`` method of all
|
||||
AST_MODULE nodes in the AST. This initiates a recursive process that
|
||||
performs the following transformations on the AST data structure:
|
||||
|
||||
- Inline all task and function calls.
|
||||
|
||||
- Evaluate all ``generate``-statements and unroll all ``for``-loops.
|
||||
|
||||
- Perform const folding where it is necessary (e.g. in the value part
|
||||
of AST_PARAMETER, AST_LOCALPARAM, AST_PARASET and AST_RANGE nodes).
|
||||
|
||||
- Replace AST_PRIMITIVE nodes with appropriate AST_ASSIGN nodes.
|
||||
|
||||
- Replace dynamic bit ranges in the left-hand-side of assignments with
|
||||
AST_CASE nodes with AST_COND children for each possible case.
|
||||
|
||||
- Detect array access patterns that are too complicated for the
|
||||
RTLIL::Memory abstraction and replace them with a set of signals and
|
||||
cases for all reads and/or writes.
|
||||
|
||||
- Otherwise replace array accesses with AST_MEMRD and AST_MEMWR nodes.
|
||||
|
||||
In addition to these transformations, the simplifier also annotates the
|
||||
AST with additional information that is needed for the RTLIL generator,
|
||||
namely:
|
||||
|
||||
- All ranges (width of signals and bit selections) are not only const
|
||||
folded but (when a constant value is found) are also written to
|
||||
member variables in the AST_RANGE node.
|
||||
|
||||
- All identifiers are resolved and all AST_IDENTIFIER nodes are
|
||||
annotated with a pointer to the AST node that contains the
|
||||
declaration of the identifier. If no declaration has been found, an
|
||||
AST_AUTOWIRE node is created and used for the annotation.
|
||||
|
||||
This produces an AST that is fairly easy to convert to the RTLIL format.
|
||||
|
||||
Generating RTLIL
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
After AST simplification, the ``AST::AstNode::genRTLIL()`` method of
|
||||
each AST_MODULE node in the AST is called. This initiates a recursive
|
||||
process that generates equivalent RTLIL data for the AST data.
|
||||
|
||||
The ``AST::AstNode::genRTLIL()`` method returns an ``RTLIL::SigSpec``
|
||||
structure. For nodes that represent expressions (operators, constants,
|
||||
signals, etc.), the cells needed to implement the calculation described
|
||||
by the expression are created and the resulting signal is returned. That
|
||||
way it is easy to generate the circuits for large expressions using
|
||||
depth-first recursion. For nodes that do not represent an expression
|
||||
(such as AST_CELL), the corresponding circuit is generated and an empty
|
||||
``RTLIL::SigSpec`` is returned.
|
||||
|
||||
Synthesizing Verilog always blocks
|
||||
--------------------------------------
|
||||
|
||||
For behavioural Verilog code (code utilizing ``always``- and
|
||||
``initial``-blocks) it is necessary to also generate ``RTLIL::Process``
|
||||
objects. This is done in the following way:
|
||||
|
||||
Whenever ``AST::AstNode::genRTLIL()`` encounters an ``always``- or
|
||||
``initial``-block, it creates an instance of
|
||||
``AST_INTERNAL::ProcessGenerator``. This object then generates the
|
||||
``RTLIL::Process`` object for the block. It also calls
|
||||
``AST::AstNode::genRTLIL()`` for all right-hand-side expressions
|
||||
contained within the block.
|
||||
|
||||
First the ``AST_INTERNAL::ProcessGenerator`` creates a list of all
|
||||
signals assigned within the block. It then creates a set of temporary
|
||||
signals using the naming scheme $\ <number> \\\ <original_name> for each
|
||||
of the assigned signals.
|
||||
|
||||
Then an ``RTLIL::Process`` is created that assigns all intermediate
|
||||
values for each left-hand-side signal to the temporary signal in its
|
||||
``RTLIL::CaseRule``/``RTLIL::SwitchRule`` tree.
|
||||
|
||||
Finally a ``RTLIL::SyncRule`` is created for the ``RTLIL::Process`` that
|
||||
assigns the temporary signals for the final values to the actual
|
||||
signals.
|
||||
|
||||
A process may also contain memory writes. A ``RTLIL::MemWriteAction`` is
|
||||
created for each of them.
|
||||
|
||||
Calls to ``AST::AstNode::genRTLIL()`` are generated for right hand sides
|
||||
as needed. When blocking assignments are used,
|
||||
``AST::AstNode::genRTLIL()`` is configured using global variables to use
|
||||
the temporary signals that hold the correct intermediate values whenever
|
||||
one of the previously assigned signals is used in an expression.
|
||||
|
||||
Unfortunately the generation of a correct
|
||||
``RTLIL::CaseRule``/``RTLIL::SwitchRule`` tree for behavioural code is a
|
||||
non-trivial task. The AST frontend solves the problem using the approach
|
||||
described on the following pages. The following example illustrates what
|
||||
the algorithm is supposed to do. Consider the following Verilog code:
|
||||
|
||||
.. code:: verilog
|
||||
:number-lines:
|
||||
|
||||
always @(posedge clock) begin
|
||||
out1 = in1;
|
||||
if (in2)
|
||||
out1 = !out1;
|
||||
out2 <= out1;
|
||||
if (in3)
|
||||
out2 <= out2;
|
||||
if (in4)
|
||||
if (in5)
|
||||
out3 <= in6;
|
||||
else
|
||||
out3 <= in7;
|
||||
out1 = out1 ^ out2;
|
||||
end
|
||||
|
||||
This is translated by the Verilog and AST frontends into the following
|
||||
RTLIL code (attributes, cell parameters and wire declarations not
|
||||
included):
|
||||
|
||||
.. code:: RTLIL
|
||||
:number-lines:
|
||||
|
||||
cell $logic_not $logic_not$<input>:4$2
|
||||
connect \A \in1
|
||||
connect \Y $logic_not$<input>:4$2_Y
|
||||
end
|
||||
cell $xor $xor$<input>:13$3
|
||||
connect \A $1\out1[0:0]
|
||||
connect \B \out2
|
||||
connect \Y $xor$<input>:13$3_Y
|
||||
end
|
||||
process $proc$<input>:1$1
|
||||
assign $0\out3[0:0] \out3
|
||||
assign $0\out2[0:0] $1\out1[0:0]
|
||||
assign $0\out1[0:0] $xor$<input>:13$3_Y
|
||||
switch \in2
|
||||
case 1'1
|
||||
assign $1\out1[0:0] $logic_not$<input>:4$2_Y
|
||||
case
|
||||
assign $1\out1[0:0] \in1
|
||||
end
|
||||
switch \in3
|
||||
case 1'1
|
||||
assign $0\out2[0:0] \out2
|
||||
case
|
||||
end
|
||||
switch \in4
|
||||
case 1'1
|
||||
switch \in5
|
||||
case 1'1
|
||||
assign $0\out3[0:0] \in6
|
||||
case
|
||||
assign $0\out3[0:0] \in7
|
||||
end
|
||||
case
|
||||
end
|
||||
sync posedge \clock
|
||||
update \out1 $0\out1[0:0]
|
||||
update \out2 $0\out2[0:0]
|
||||
update \out3 $0\out3[0:0]
|
||||
end
|
||||
|
||||
Note that the two operators are translated into separate cells outside
|
||||
the generated process. The signal ``out1`` is assigned using blocking
|
||||
assignments and therefore ``out1`` has been replaced with a different
|
||||
signal in all expressions after the initial assignment. The signal
|
||||
``out2`` is assigned using nonblocking assignments and therefore is not
|
||||
substituted on the right-hand-side expressions.
|
||||
|
||||
The ``RTLIL::CaseRule``/``RTLIL::SwitchRule`` tree must be interpreted
|
||||
the following way:
|
||||
|
||||
- On each case level (the body of the process is the root case), first
|
||||
the actions on this level are evaluated and then the switches within
|
||||
the case are evaluated. (Note that the last assignment on line 13 of
|
||||
the Verilog code has been moved to the beginning of the RTLIL process
|
||||
to line 13 of the RTLIL listing.)
|
||||
|
||||
I.e. the special cases deeper in the switch hierarchy override the
|
||||
defaults on the upper levels. The assignments in lines 12 and 22 of
|
||||
the RTLIL code serve as an example for this.
|
||||
|
||||
Note that in contrast to this, the order within the
|
||||
``RTLIL::SwitchRule`` objects within a ``RTLIL::CaseRule`` is
|
||||
preserved with respect to the original AST and Verilog code.
|
||||
|
||||
- The whole ``RTLIL::CaseRule``/``RTLIL::SwitchRule`` tree describes an
|
||||
asynchronous circuit. I.e. the decision tree formed by the switches
|
||||
can be seen independently for each assigned signal. Whenever one
|
||||
assigned signal changes, all signals that depend on the changed
|
||||
signals are to be updated. For example the assignments in lines 16
|
||||
and 18 in the RTLIL code in fact influence the assignment in line 12,
|
||||
even though they are in the "wrong order".
|
||||
|
||||
The only synchronous part of the process is in the ``RTLIL::SyncRule``
|
||||
object generated at line 35 in the RTLIL code. The sync rule is the only
|
||||
part of the process where the original signals are assigned. The
|
||||
synchronization event from the original Verilog code has been translated
|
||||
into the synchronization type (posedge) and signal (\\clock) for the
|
||||
``RTLIL::SyncRule`` object. In the case of this simple example the
|
||||
``RTLIL::SyncRule`` object is later simply transformed into a set of
|
||||
d-type flip-flops and the ``RTLIL::CaseRule``/``RTLIL::SwitchRule`` tree
|
||||
to a decision tree using multiplexers.
|
||||
|
||||
In more complex examples (e.g. asynchronous resets) the part of the
|
||||
``RTLIL::CaseRule``/``RTLIL::SwitchRule`` tree that describes the
|
||||
asynchronous reset must first be transformed to the correct
|
||||
``RTLIL::SyncRule`` objects. This is done by the proc_adff pass.
|
||||
|
||||
The ProcessGenerator algorithm
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The ``AST_INTERNAL::ProcessGenerator`` uses the following internal state
|
||||
variables:
|
||||
|
||||
- | ``subst_rvalue_from`` and ``subst_rvalue_to``
|
||||
| These two variables hold the replacement pattern that should be
|
||||
used by ``AST::AstNode::genRTLIL()`` for signals with blocking
|
||||
assignments. After initialization of
|
||||
``AST_INTERNAL::ProcessGenerator`` these two variables are empty.
|
||||
|
||||
- | ``subst_lvalue_from`` and ``subst_lvalue_to``
|
||||
| These two variables contain the mapping from left-hand-side signals
|
||||
(\\\ <name>) to the current temporary signal for the same thing
|
||||
(initially $0\\\ <name>).
|
||||
|
||||
- | ``current_case``
|
||||
| A pointer to a ``RTLIL::CaseRule`` object. Initially this is the
|
||||
root case of the generated ``RTLIL::Process``.
|
||||
|
||||
As the algorithm runs these variables are continuously modified as well
|
||||
as pushed to the stack and later restored to their earlier values by
|
||||
popping from the stack.
|
||||
|
||||
On startup the ProcessGenerator generates a new ``RTLIL::Process``
|
||||
object with an empty root case and initializes its state variables as
|
||||
described above. Then the ``RTLIL::SyncRule`` objects are created using
|
||||
the synchronization events from the AST_ALWAYS node and the initial
|
||||
values of ``subst_lvalue_from`` and ``subst_lvalue_to``. Then the AST
|
||||
for this process is evaluated recursively.
|
||||
|
||||
During this recursive evaluation, three different relevant types of AST
|
||||
nodes can be discovered: AST_ASSIGN_LE (nonblocking assignments),
|
||||
AST_ASSIGN_EQ (blocking assignments) and AST_CASE (``if`` or ``case``
|
||||
statement).
|
||||
|
||||
Handling of nonblocking assignments
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When an AST_ASSIGN_LE node is discovered, the following actions are
|
||||
performed by the ProcessGenerator:
|
||||
|
||||
- The left-hand-side is evaluated using ``AST::AstNode::genRTLIL()``
|
||||
and mapped to a temporary signal name using ``subst_lvalue_from`` and
|
||||
``subst_lvalue_to``.
|
||||
|
||||
- The right-hand-side is evaluated using ``AST::AstNode::genRTLIL()``.
|
||||
For this call, the values of ``subst_rvalue_from`` and
|
||||
``subst_rvalue_to`` are used to map blocking-assigned signals
|
||||
correctly.
|
||||
|
||||
- Remove all assignments to the same left-hand-side as this assignment
|
||||
from the ``current_case`` and all cases within it.
|
||||
|
||||
- Add the new assignment to the ``current_case``.
|
||||
|
||||
Handling of blocking assignments
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When an AST_ASSIGN_EQ node is discovered, the following actions are
|
||||
performed by the ProcessGenerator:
|
||||
|
||||
- Perform all the steps that would be performed for a nonblocking
|
||||
assignment (see above).
|
||||
|
||||
- Remove the found left-hand-side (before lvalue mapping) from
|
||||
``subst_rvalue_from`` and also remove the respective bits from
|
||||
``subst_rvalue_to``.
|
||||
|
||||
- Append the found left-hand-side (before lvalue mapping) to
|
||||
``subst_rvalue_from`` and append the found right-hand-side to
|
||||
``subst_rvalue_to``.
|
||||
|
||||
Handling of cases and if-statements
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When an AST_CASE node is discovered, the following actions are performed
|
||||
by the ProcessGenerator:
|
||||
|
||||
- The values of ``subst_rvalue_from``, ``subst_rvalue_to``,
|
||||
``subst_lvalue_from`` and ``subst_lvalue_to`` are pushed to the
|
||||
stack.
|
||||
|
||||
- A new ``RTLIL::SwitchRule`` object is generated, the selection
|
||||
expression is evaluated using ``AST::AstNode::genRTLIL()`` (with the
|
||||
use of ``subst_rvalue_from`` and ``subst_rvalue_to``) and added to
|
||||
the ``RTLIL::SwitchRule`` object and the object is added to the
|
||||
``current_case``.
|
||||
|
||||
- All lvalues assigned to within the AST_CASE node using blocking
|
||||
assignments are collected and saved in the local variable
|
||||
``this_case_eq_lvalue``.
|
||||
|
||||
- New temporary signals are generated for all signals in
|
||||
``this_case_eq_lvalue`` and stored in ``this_case_eq_ltemp``.
|
||||
|
||||
- The signals in ``this_case_eq_lvalue`` are mapped using
|
||||
``subst_rvalue_from`` and ``subst_rvalue_to`` and the resulting set
|
||||
of signals is stored in ``this_case_eq_rvalue``.
|
||||
|
||||
Then the following steps are performed for each AST_COND node within the
|
||||
AST_CASE node:
|
||||
|
||||
- Set ``subst_rvalue_from``, ``subst_rvalue_to``, ``subst_lvalue_from``
|
||||
and ``subst_lvalue_to`` to the values that have been pushed to the
|
||||
stack.
|
||||
|
||||
- Remove ``this_case_eq_lvalue`` from
|
||||
``subst_lvalue_from``/``subst_lvalue_to``.
|
||||
|
||||
- Append ``this_case_eq_lvalue`` to ``subst_lvalue_from`` and append
|
||||
``this_case_eq_ltemp`` to ``subst_lvalue_to``.
|
||||
|
||||
- Push the value of ``current_case``.
|
||||
|
||||
- Create a new ``RTLIL::CaseRule``. Set ``current_case`` to the new
|
||||
object and add the new object to the ``RTLIL::SwitchRule`` created
|
||||
above.
|
||||
|
||||
- Add an assignment from ``this_case_eq_rvalue`` to
|
||||
``this_case_eq_ltemp`` to the new ``current_case``.
|
||||
|
||||
- Evaluate the compare value for this case using
|
||||
``AST::AstNode::genRTLIL()`` (with the use of ``subst_rvalue_from``
|
||||
and ``subst_rvalue_to``) modify the new ``current_case`` accordingly.
|
||||
|
||||
- Recursion into the children of the AST_COND node.
|
||||
|
||||
- Restore ``current_case`` by popping the old value from the stack.
|
||||
|
||||
Finally the following steps are performed:
|
||||
|
||||
- The values of ``subst_rvalue_from``, ``subst_rvalue_to``,
|
||||
``subst_lvalue_from`` and ``subst_lvalue_to`` are popped from the
|
||||
stack.
|
||||
|
||||
- The signals from ``this_case_eq_lvalue`` are removed from the
|
||||
``subst_rvalue_from``/``subst_rvalue_to``-pair.
|
||||
|
||||
- The value of ``this_case_eq_lvalue`` is appended to
|
||||
``subst_rvalue_from`` and the value of ``this_case_eq_ltemp`` is
|
||||
appended to ``subst_rvalue_to``.
|
||||
|
||||
- Map the signals in ``this_case_eq_lvalue`` using
|
||||
``subst_lvalue_from``/``subst_lvalue_to``.
|
||||
|
||||
- Remove all assignments to signals in ``this_case_eq_lvalue`` in
|
||||
``current_case`` and all cases within it.
|
||||
|
||||
- Add an assignment from ``this_case_eq_ltemp`` to
|
||||
``this_case_eq_lvalue`` to ``current_case``.
|
||||
|
||||
Further analysis of the algorithm for cases and if-statements
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
With respect to nonblocking assignments the algorithm is easy: later
|
||||
assignments invalidate earlier assignments. For each signal assigned
|
||||
using nonblocking assignments exactly one temporary variable is
|
||||
generated (with the $0-prefix) and this variable is used for all
|
||||
assignments of the variable.
|
||||
|
||||
Note how all the ``_eq_``-variables become empty when no blocking
|
||||
assignments are used and many of the steps in the algorithm can then be
|
||||
ignored as a result of this.
|
||||
|
||||
For a variable with blocking assignments the algorithm shows the
|
||||
following behaviour: First a new temporary variable is created. This new
|
||||
temporary variable is then registered as the assignment target for all
|
||||
assignments for this variable within the cases for this AST_CASE node.
|
||||
Then for each case the new temporary variable is first assigned the old
|
||||
temporary variable. This assignment is overwritten if the variable is
|
||||
actually assigned in this case and is kept as a default value otherwise.
|
||||
|
||||
This yields an ``RTLIL::CaseRule`` that assigns the new temporary
|
||||
variable in all branches. So when all cases have been processed a final
|
||||
assignment is added to the containing block that assigns the new
|
||||
temporary variable to the old one. Note how this step always overrides a
|
||||
previous assignment to the old temporary variable. Other than
|
||||
nonblocking assignments, the old assignment could still have an effect
|
||||
somewhere in the design, as there have been calls to
|
||||
``AST::AstNode::genRTLIL()`` with a
|
||||
``subst_rvalue_from``/``subst_rvalue_to``-tuple that contained the
|
||||
right-hand-side of the old assignment.
|
||||
|
||||
The proc pass
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
The ProcessGenerator converts a behavioural model in AST representation
|
||||
to a behavioural model in ``RTLIL::Process`` representation. The actual
|
||||
conversion from a behavioural model to an RTL representation is
|
||||
performed by the proc pass and the passes it launches:
|
||||
|
||||
- | proc_clean and proc_rmdead
|
||||
| These two passes just clean up the ``RTLIL::Process`` structure.
|
||||
The proc_clean pass removes empty parts (eg. empty assignments)
|
||||
from the process and proc_rmdead detects and removes unreachable
|
||||
branches from the process's decision trees.
|
||||
|
||||
- | proc_arst
|
||||
| This pass detects processes that describe d-type flip-flops with
|
||||
asynchronous resets and rewrites the process to better reflect what
|
||||
they are modelling: Before this pass, an asynchronous reset has two
|
||||
edge-sensitive sync rules and one top-level for the reset path.
|
||||
After this pass the sync rule for the reset is level-sensitive and
|
||||
the top-level has been removed.
|
||||
|
||||
- | proc_mux
|
||||
| This pass converts the /-tree to a tree of multiplexers per written
|
||||
signal. After this, the structure only contains the s that describe
|
||||
the output registers.
|
||||
|
||||
- | proc_dff
|
||||
| This pass replaces the s to d-type flip-flops (with asynchronous
|
||||
resets if necessary).
|
||||
|
||||
- | proc_dff
|
||||
| This pass replaces the s with $memwr cells.
|
||||
|
||||
- | proc_clean
|
||||
| A final call to proc_clean removes the now empty objects.
|
||||
|
||||
Performing these last processing steps in passes instead of in the
|
||||
Verilog frontend has two important benefits:
|
||||
|
||||
First it improves the transparency of the process. Everything that
|
||||
happens in a separate pass is easier to debug, as the RTLIL data
|
||||
structures can be easily investigated before and after each of the
|
||||
steps.
|
||||
|
||||
Second it improves flexibility. This scheme can easily be extended to
|
||||
support other types of storage-elements, such as sr-latches or
|
||||
d-latches, without having to extend the actual Verilog frontend.
|
||||
|
||||
Synthesizing Verilog arrays
|
||||
---------------------------
|
||||
|
||||
Add some information on the generation of $memrd and $memwr cells and
|
||||
how they are processed in the memory pass.
|
||||
|
||||
Synthesizing parametric designs
|
||||
-------------------------------
|
||||
|
||||
Add some information on the ``RTLIL::Module::derive()`` method and how
|
||||
it is used to synthesize parametric modules via the hierarchy pass.
|
1022
docs/source/yosys_internals/formats/cell_library.rst
Normal file
1022
docs/source/yosys_internals/formats/cell_library.rst
Normal file
File diff suppressed because it is too large
Load diff
11
docs/source/yosys_internals/formats/index.rst
Normal file
11
docs/source/yosys_internals/formats/index.rst
Normal file
|
@ -0,0 +1,11 @@
|
|||
Internal formats
|
||||
================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
overview
|
||||
rtlil
|
||||
rtlil_text
|
||||
cell_library
|
||||
|
53
docs/source/yosys_internals/formats/overview.rst
Normal file
53
docs/source/yosys_internals/formats/overview.rst
Normal file
|
@ -0,0 +1,53 @@
|
|||
Format overview
|
||||
===============
|
||||
|
||||
Yosys uses two different internal formats. The first is used to store an
|
||||
abstract syntax tree (AST) of a Verilog input file. This format is simply called
|
||||
AST and is generated by the Verilog Frontend. This data structure is consumed by
|
||||
a subsystem called AST Frontend [1]_. This AST Frontend then generates a design
|
||||
in Yosys' main internal format, the
|
||||
Register-Transfer-Level-Intermediate-Language (RTLIL) representation. It does
|
||||
that by first performing a number of simplifications within the AST
|
||||
representation and then generating RTLIL from the simplified AST data structure.
|
||||
|
||||
The RTLIL representation is used by all passes as input and outputs. This has
|
||||
the following advantages over using different representational formats between
|
||||
different passes:
|
||||
|
||||
- The passes can be rearranged in a different order and passes can be removed
|
||||
or inserted.
|
||||
|
||||
- Passes can simply pass-thru the parts of the design they don't change without
|
||||
the need to convert between formats. In fact Yosys passes output the same
|
||||
data structure they received as input and performs all changes in place.
|
||||
|
||||
- All passes use the same interface, thus reducing the effort required to
|
||||
understand a pass when reading the Yosys source code, e.g. when adding
|
||||
additional features.
|
||||
|
||||
The RTLIL representation is basically a netlist representation with the
|
||||
following additional features:
|
||||
|
||||
- An internal cell library with fixed-function cells to represent RTL datapath
|
||||
and register cells as well as logical gate-level cells (single-bit gates and
|
||||
registers).
|
||||
|
||||
- Support for multi-bit values that can use individual bits from wires as well
|
||||
as constant bits to represent coarse-grain netlists.
|
||||
|
||||
- Support for basic behavioural constructs (if-then-else structures and
|
||||
multi-case switches with a sensitivity list for updating the outputs).
|
||||
|
||||
- Support for multi-port memories.
|
||||
|
||||
The use of RTLIL also has the disadvantage of having a very powerful format
|
||||
between all passes, even when doing gate-level synthesis where the more advanced
|
||||
features are not needed. In order to reduce complexity for passes that operate
|
||||
on a low-level representation, these passes check the features used in the input
|
||||
RTLIL and fail to run when unsupported high-level constructs are used. In such
|
||||
cases a pass that transforms the higher-level constructs to lower-level
|
||||
constructs must be called from the synthesis script first.
|
||||
|
||||
.. [1]
|
||||
In Yosys the term pass is only used to refer to commands that operate on the
|
||||
RTLIL data structure.
|
408
docs/source/yosys_internals/formats/rtlil.rst
Normal file
408
docs/source/yosys_internals/formats/rtlil.rst
Normal file
|
@ -0,0 +1,408 @@
|
|||
The RTL Intermediate Language (RTLIL)
|
||||
=====================================
|
||||
|
||||
All frontends, passes and backends in Yosys operate on a design in RTLIL
|
||||
representation. The only exception are the high-level frontends that use the AST
|
||||
representation as an intermediate step before generating RTLIL data.
|
||||
|
||||
In order to avoid reinventing names for the RTLIL classes, they are simply
|
||||
referred to by their full C++ name, i.e. including the RTLIL:: namespace prefix,
|
||||
in this document.
|
||||
|
||||
:numref:`Figure %s <fig:Overview_RTLIL>` shows a simplified Entity-Relationship
|
||||
Diagram (ER Diagram) of RTLIL. In :math:`1:N` relationships the arrow points
|
||||
from the :math:`N` side to the :math:`1`. For example one RTLIL::Design contains
|
||||
:math:`N` (zero to many) instances of RTLIL::Module. A two-pointed arrow
|
||||
indicates a :math:`1:1` relationship.
|
||||
|
||||
The RTLIL::Design is the root object of the RTLIL data structure. There is
|
||||
always one "current design" in memory which passes operate on, frontends add
|
||||
data to and backends convert to exportable formats. But in some cases passes
|
||||
internally generate additional RTLIL::Design objects. For example when a pass is
|
||||
reading an auxiliary Verilog file such as a cell library, it might create an
|
||||
additional RTLIL::Design object and call the Verilog frontend with this other
|
||||
object to parse the cell library.
|
||||
|
||||
.. figure:: ../../../images/overview_rtlil.*
|
||||
:class: width-helper
|
||||
:name: fig:Overview_RTLIL
|
||||
|
||||
Simplified RTLIL Entity-Relationship Diagram
|
||||
|
||||
There is only one active RTLIL::Design object that is used by all frontends,
|
||||
passes and backends called by the user, e.g. using a synthesis script. The
|
||||
RTLIL::Design then contains zero to many RTLIL::Module objects. This corresponds
|
||||
to modules in Verilog or entities in VHDL. Each module in turn contains objects
|
||||
from three different categories:
|
||||
|
||||
- RTLIL::Cell and RTLIL::Wire objects represent classical netlist data.
|
||||
|
||||
- RTLIL::Process objects represent the decision trees (if-then-else statements,
|
||||
etc.) and synchronization declarations (clock signals and sensitivity) from
|
||||
Verilog always and VHDL process blocks.
|
||||
|
||||
- RTLIL::Memory objects represent addressable memories (arrays).
|
||||
|
||||
Usually the output of the synthesis procedure is a netlist, i.e. all
|
||||
RTLIL::Process and RTLIL::Memory objects must be replaced by RTLIL::Cell and
|
||||
RTLIL::Wire objects by synthesis passes.
|
||||
|
||||
All features of the HDL that cannot be mapped directly to these RTLIL classes
|
||||
must be transformed to an RTLIL-compatible representation by the HDL frontend.
|
||||
This includes Verilog-features such as generate-blocks, loops and parameters.
|
||||
|
||||
The following sections contain a more detailed description of the different
|
||||
parts of RTLIL and rationale behind some of the design decisions.
|
||||
|
||||
RTLIL identifiers
|
||||
-----------------
|
||||
|
||||
All identifiers in RTLIL (such as module names, port names, signal names, cell
|
||||
types, etc.) follow the following naming convention: they must either start with
|
||||
a backslash (\) or a dollar sign ($).
|
||||
|
||||
Identifiers starting with a backslash are public visible identifiers. Usually
|
||||
they originate from one of the HDL input files. For example the signal name
|
||||
"\\sig42" is most likely a signal that was declared using the name "sig42" in an
|
||||
HDL input file. On the other hand the signal name "$sig42" is an auto-generated
|
||||
signal name. The backends convert all identifiers that start with a dollar sign
|
||||
to identifiers that do not collide with identifiers that start with a backslash.
|
||||
|
||||
This has three advantages:
|
||||
|
||||
- First, it is impossible that an auto-generated identifier collides with an
|
||||
identifier that was provided by the user.
|
||||
|
||||
- Second, the information about which identifiers were originally provided by
|
||||
the user is always available which can help guide some optimizations. For
|
||||
example the "opt_rmunused" tries to preserve signals with a user-provided
|
||||
name but doesn't hesitate to delete signals that have auto-generated names
|
||||
when they just duplicate other signals.
|
||||
|
||||
- Third, the delicate job of finding suitable auto-generated public visible
|
||||
names is deferred to one central location. Internally auto-generated names
|
||||
that may hold important information for Yosys developers can be used without
|
||||
disturbing external tools. For example the Verilog backend assigns names in
|
||||
the form \_integer\_.
|
||||
|
||||
Whitespace and control characters (any character with an ASCII code 32 or less)
|
||||
are not allowed in RTLIL identifiers; most frontends and backends cannot support
|
||||
these characters in identifiers.
|
||||
|
||||
In order to avoid programming errors, the RTLIL data structures check if all
|
||||
identifiers start with either a backslash or a dollar sign, and contain no
|
||||
whitespace or control characters. Violating these rules results in a runtime
|
||||
error.
|
||||
|
||||
All RTLIL identifiers are case sensitive.
|
||||
|
||||
Some transformations, such as flattening, may have to change identifiers
|
||||
provided by the user to avoid name collisions. When that happens, attribute
|
||||
"hdlname" is attached to the object with the changed identifier. This attribute
|
||||
contains one name (if emitted directly by the frontend, or is a result of
|
||||
disambiguation) or multiple names separated by spaces (if a result of
|
||||
flattening). All names specified in the "hdlname" attribute are public and do
|
||||
not include the leading "\".
|
||||
|
||||
RTLIL::Design and RTLIL::Module
|
||||
-------------------------------
|
||||
|
||||
The RTLIL::Design object is basically just a container for RTLIL::Module
|
||||
objects. In addition to a list of RTLIL::Module objects the RTLIL::Design also
|
||||
keeps a list of selected objects, i.e. the objects that passes should operate
|
||||
on. In most cases the whole design is selected and therefore passes operate on
|
||||
the whole design. But this mechanism can be useful for more complex synthesis
|
||||
jobs in which only parts of the design should be affected by certain passes.
|
||||
|
||||
Besides the objects shown in the ER diagram in :numref:`Fig. %s
|
||||
<fig:Overview_RTLIL>` an RTLIL::Module object contains the following additional
|
||||
properties:
|
||||
|
||||
- The module name
|
||||
- A list of attributes
|
||||
- A list of connections between wires
|
||||
- An optional frontend callback used to derive parametrized variations of the
|
||||
module
|
||||
|
||||
The attributes can be Verilog attributes imported by the Verilog frontend or
|
||||
attributes assigned by passes. They can be used to store additional metadata
|
||||
about modules or just mark them to be used by certain part of the synthesis
|
||||
script but not by others.
|
||||
|
||||
Verilog and VHDL both support parametric modules (known as "generic entities" in
|
||||
VHDL). The RTLIL format does not support parametric modules itself. Instead each
|
||||
module contains a callback function into the AST frontend to generate a
|
||||
parametrized variation of the RTLIL::Module as needed. This callback then
|
||||
returns the auto-generated name of the parametrized variation of the module. (A
|
||||
hash over the parameters and the module name is used to prohibit the same
|
||||
parametrized variation from being generated twice. For modules with only a few
|
||||
parameters, a name directly containing all parameters is generated instead of a
|
||||
hash string.)
|
||||
|
||||
.. _sec:rtlil_cell_wire:
|
||||
|
||||
RTLIL::Cell and RTLIL::Wire
|
||||
---------------------------
|
||||
|
||||
A module contains zero to many RTLIL::Cell and RTLIL::Wire objects. Objects of
|
||||
these types are used to model netlists. Usually the goal of all synthesis
|
||||
efforts is to convert all modules to a state where the functionality of the
|
||||
module is implemented only by cells from a given cell library and wires to
|
||||
connect these cells with each other. Note that module ports are just wires with
|
||||
a special property.
|
||||
|
||||
An RTLIL::Wire object has the following properties:
|
||||
|
||||
- The wire name
|
||||
- A list of attributes
|
||||
- A width (buses are just wires with a width > 1)
|
||||
- Bus direction (MSB to LSB or vice versa)
|
||||
- Lowest valid bit index (LSB or MSB depending on bus direction)
|
||||
- If the wire is a port: port number and direction (input/output/inout)
|
||||
|
||||
As with modules, the attributes can be Verilog attributes imported by the
|
||||
Verilog frontend or attributes assigned by passes.
|
||||
|
||||
In Yosys, busses (signal vectors) are represented using a single wire object
|
||||
with a width > 1. So Yosys does not convert signal vectors to individual
|
||||
signals. This makes some aspects of RTLIL more complex but enables Yosys to be
|
||||
used for coarse grain synthesis where the cells of the target architecture
|
||||
operate on entire signal vectors instead of single bit wires.
|
||||
|
||||
In Verilog and VHDL, busses may have arbitrary bounds, and LSB can have either
|
||||
the lowest or the highest bit index. In RTLIL, bit 0 always corresponds to LSB;
|
||||
however, information from the HDL frontend is preserved so that the bus will be
|
||||
correctly indexed in error messages, backend output, constraint files, etc.
|
||||
|
||||
An RTLIL::Cell object has the following properties:
|
||||
|
||||
- The cell name and type
|
||||
- A list of attributes
|
||||
- A list of parameters (for parametric cells)
|
||||
- Cell ports and the connections of ports to wires and constants
|
||||
|
||||
The connections of ports to wires are coded by assigning an RTLIL::SigSpec to
|
||||
each cell port. The RTLIL::SigSpec data type is described in the next section.
|
||||
|
||||
.. _sec:rtlil_sigspec:
|
||||
|
||||
RTLIL::SigSpec
|
||||
--------------
|
||||
|
||||
A "signal" is everything that can be applied to a cell port. I.e.
|
||||
|
||||
- | Any constant value of arbitrary bit-width
|
||||
| 1em For example: ``1337, 16'b0000010100111001, 1'b1, 1'bx``
|
||||
|
||||
- | All bits of a wire or a selection of bits from a wire
|
||||
| 1em For example: ``mywire, mywire[24], mywire[15:8]``
|
||||
|
||||
- | Concatenations of the above
|
||||
| 1em For example: ``{16'd1337, mywire[15:8]}``
|
||||
|
||||
The RTLIL::SigSpec data type is used to represent signals. The RTLIL::Cell
|
||||
object contains one RTLIL::SigSpec for each cell port.
|
||||
|
||||
In addition, connections between wires are represented using a pair of
|
||||
RTLIL::SigSpec objects. Such pairs are needed in different locations. Therefore
|
||||
the type name RTLIL::SigSig was defined for such a pair.
|
||||
|
||||
.. _sec:rtlil_process:
|
||||
|
||||
RTLIL::Process
|
||||
--------------
|
||||
|
||||
When a high-level HDL frontend processes behavioural code it splits it up into
|
||||
data path logic (e.g. the expression a + b is replaced by the output of an adder
|
||||
that takes a and b as inputs) and an RTLIL::Process that models the control
|
||||
logic of the behavioural code. Let's consider a simple example:
|
||||
|
||||
.. code:: verilog
|
||||
:number-lines:
|
||||
|
||||
module ff_with_en_and_async_reset(clock, reset, enable, d, q);
|
||||
input clock, reset, enable, d;
|
||||
output reg q;
|
||||
always @(posedge clock, posedge reset)
|
||||
if (reset)
|
||||
q <= 0;
|
||||
else if (enable)
|
||||
q <= d;
|
||||
endmodule
|
||||
|
||||
In this example there is no data path and therefore the RTLIL::Module generated
|
||||
by the frontend only contains a few RTLIL::Wire objects and an RTLIL::Process.
|
||||
The RTLIL::Process in RTLIL syntax:
|
||||
|
||||
.. code:: RTLIL
|
||||
:number-lines:
|
||||
|
||||
process $proc$ff_with_en_and_async_reset.v:4$1
|
||||
assign $0\q[0:0] \q
|
||||
switch \reset
|
||||
case 1'1
|
||||
assign $0\q[0:0] 1'0
|
||||
case
|
||||
switch \enable
|
||||
case 1'1
|
||||
assign $0\q[0:0] \d
|
||||
case
|
||||
end
|
||||
end
|
||||
sync posedge \clock
|
||||
update \q $0\q[0:0]
|
||||
sync posedge \reset
|
||||
update \q $0\q[0:0]
|
||||
end
|
||||
|
||||
This RTLIL::Process contains two RTLIL::SyncRule objects, two RTLIL::SwitchRule
|
||||
objects and five RTLIL::CaseRule objects. The wire $0\q[0:0] is an automatically
|
||||
created wire that holds the next value of \\q. The lines :math:`2 \dots 12`
|
||||
describe how $0\q[0:0] should be calculated. The lines :math:`13 \dots 16`
|
||||
describe how the value of $0\q[0:0] is used to update \\q.
|
||||
|
||||
An RTLIL::Process is a container for zero or more RTLIL::SyncRule objects and
|
||||
exactly one RTLIL::CaseRule object, which is called the root case.
|
||||
|
||||
An RTLIL::SyncRule object contains an (optional) synchronization condition
|
||||
(signal and edge-type), zero or more assignments (RTLIL::SigSig), and zero or
|
||||
more memory writes (RTLIL::MemWriteAction). The always synchronization condition
|
||||
is used to break combinatorial loops when a latch should be inferred instead.
|
||||
|
||||
An RTLIL::CaseRule is a container for zero or more assignments (RTLIL::SigSig)
|
||||
and zero or more RTLIL::SwitchRule objects. An RTLIL::SwitchRule objects is a
|
||||
container for zero or more RTLIL::CaseRule objects.
|
||||
|
||||
In the above example the lines :math:`2 \dots 12` are the root case. Here
|
||||
$0\q[0:0] is first assigned the old value \\q as default value (line 2). The
|
||||
root case also contains an RTLIL::SwitchRule object (lines :math:`3 \dots 12`).
|
||||
Such an object is very similar to the C switch statement as it uses a control
|
||||
signal (\\reset in this case) to determine which of its cases should be active.
|
||||
The RTLIL::SwitchRule object then contains one RTLIL::CaseRule object per case.
|
||||
In this example there is a case [1]_ for \\reset == 1 that causes $0\q[0:0] to
|
||||
be set (lines 4 and 5) and a default case that in turn contains a switch that
|
||||
sets $0\q[0:0] to the value of \\d if \\enable is active (lines :math:`6 \dots
|
||||
11`).
|
||||
|
||||
A case can specify zero or more compare values that will determine whether it
|
||||
matches. Each of the compare values must be the exact same width as the control
|
||||
signal. When more than one compare value is specified, the case matches if any
|
||||
of them matches the control signal; when zero compare values are specified, the
|
||||
case always matches (i.e. it is the default case).
|
||||
|
||||
A switch prioritizes cases from first to last: multiple cases can match, but
|
||||
only the first matched case becomes active. This normally synthesizes to a
|
||||
priority encoder. The parallel_case attribute allows passes to assume that no
|
||||
more than one case will match, and full_case attribute allows passes to assume
|
||||
that exactly one case will match; if these invariants are ever dynamically
|
||||
violated, the behavior is undefined. These attributes are useful when an
|
||||
invariant invisible to the synthesizer causes the control signal to never take
|
||||
certain bit patterns.
|
||||
|
||||
The lines :math:`13 \dots 16` then cause \\q to be updated whenever there is a
|
||||
positive clock edge on \\clock or \\reset.
|
||||
|
||||
In order to generate such a representation, the language frontend must be able
|
||||
to handle blocking and nonblocking assignments correctly. However, the language
|
||||
frontend does not need to identify the correct type of storage element for the
|
||||
output signal or generate multiplexers for the decision tree. This is done by
|
||||
passes that work on the RTLIL representation. Therefore it is relatively easy to
|
||||
substitute these steps with other algorithms that target different target
|
||||
architectures or perform optimizations or other transformations on the decision
|
||||
trees before further processing them.
|
||||
|
||||
One of the first actions performed on a design in RTLIL representation in most
|
||||
synthesis scripts is identifying asynchronous resets. This is usually done using
|
||||
the proc_arst pass. This pass transforms the above example to the following
|
||||
RTLIL::Process:
|
||||
|
||||
.. code:: RTLIL
|
||||
:number-lines:
|
||||
|
||||
process $proc$ff_with_en_and_async_reset.v:4$1
|
||||
assign $0\q[0:0] \q
|
||||
switch \enable
|
||||
case 1'1
|
||||
assign $0\q[0:0] \d
|
||||
case
|
||||
end
|
||||
sync posedge \clock
|
||||
update \q $0\q[0:0]
|
||||
sync high \reset
|
||||
update \q 1'0
|
||||
end
|
||||
|
||||
This pass has transformed the outer RTLIL::SwitchRule into a modified
|
||||
RTLIL::SyncRule object for the \\reset signal. Further processing converts the
|
||||
RTLIL::Process into e.g. a d-type flip-flop with asynchronous reset and a
|
||||
multiplexer for the enable signal:
|
||||
|
||||
.. code:: RTLIL
|
||||
:number-lines:
|
||||
|
||||
cell $adff $procdff$6
|
||||
parameter \ARST_POLARITY 1'1
|
||||
parameter \ARST_VALUE 1'0
|
||||
parameter \CLK_POLARITY 1'1
|
||||
parameter \WIDTH 1
|
||||
connect \ARST \reset
|
||||
connect \CLK \clock
|
||||
connect \D $0\q[0:0]
|
||||
connect \Q \q
|
||||
end
|
||||
cell $mux $procmux$3
|
||||
parameter \WIDTH 1
|
||||
connect \A \q
|
||||
connect \B \d
|
||||
connect \S \enable
|
||||
connect \Y $0\q[0:0]
|
||||
end
|
||||
|
||||
Different combinations of passes may yield different results. Note that $adff
|
||||
and $mux are internal cell types that still need to be mapped to cell types from
|
||||
the target cell library.
|
||||
|
||||
Some passes refuse to operate on modules that still contain RTLIL::Process
|
||||
objects as the presence of these objects in a module increases the complexity.
|
||||
Therefore the passes to translate processes to a netlist of cells are usually
|
||||
called early in a synthesis script. The proc pass calls a series of other passes
|
||||
that together perform this conversion in a way that is suitable for most
|
||||
synthesis tasks.
|
||||
|
||||
.. _sec:rtlil_memory:
|
||||
|
||||
RTLIL::Memory
|
||||
-------------
|
||||
|
||||
For every array (memory) in the HDL code an RTLIL::Memory object is created. A
|
||||
memory object has the following properties:
|
||||
|
||||
- The memory name
|
||||
- A list of attributes
|
||||
- The width of an addressable word
|
||||
- The size of the memory in number of words
|
||||
|
||||
All read accesses to the memory are transformed to $memrd cells and all write
|
||||
accesses to $memwr cells by the language frontend. These cells consist of
|
||||
independent read- and write-ports to the memory. Memory initialization is
|
||||
transformed to $meminit cells by the language frontend. The ``\MEMID`` parameter
|
||||
on these cells is used to link them together and to the RTLIL::Memory object
|
||||
they belong to.
|
||||
|
||||
The rationale behind using separate cells for the individual ports versus
|
||||
creating a large multiport memory cell right in the language frontend is that
|
||||
the separate $memrd and $memwr cells can be consolidated using resource sharing.
|
||||
As resource sharing is a non-trivial optimization problem where different
|
||||
synthesis tasks can have different requirements it lends itself to do the
|
||||
optimisation in separate passes and merge the RTLIL::Memory objects and $memrd
|
||||
and $memwr cells to multiport memory blocks after resource sharing is completed.
|
||||
|
||||
The memory pass performs this conversion and can (depending on the options
|
||||
passed to it) transform the memories directly to d-type flip-flops and address
|
||||
logic or yield multiport memory blocks (represented using $mem cells).
|
||||
|
||||
See :ref:`sec:memcells` for details about the memory cell types.
|
||||
|
||||
.. [1]
|
||||
The syntax 1'1 in the RTLIL code specifies a constant with a length of one
|
||||
bit (the first "1"), and this bit is a one (the second "1").
|
297
docs/source/yosys_internals/formats/rtlil_text.rst
Normal file
297
docs/source/yosys_internals/formats/rtlil_text.rst
Normal file
|
@ -0,0 +1,297 @@
|
|||
.. _chapter:textrtlil:
|
||||
|
||||
RTLIL text representation
|
||||
-------------------------
|
||||
|
||||
This appendix documents the text representation of RTLIL in extended Backus-Naur
|
||||
form (EBNF).
|
||||
|
||||
The grammar is not meant to represent semantic limitations. That is, the grammar
|
||||
is "permissive", and later stages of processing perform more rigorous checks.
|
||||
|
||||
The grammar is also not meant to represent the exact grammar used in the RTLIL
|
||||
frontend, since that grammar is specific to processing by lex and yacc, is even
|
||||
more permissive, and is somewhat less understandable than simple EBNF notation.
|
||||
|
||||
Finally, note that all statements (rules ending in ``-stmt``) terminate in an
|
||||
end-of-line. Because of this, a statement cannot be broken into multiple lines.
|
||||
|
||||
Lexical elements
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Characters
|
||||
^^^^^^^^^^
|
||||
|
||||
An RTLIL file is a stream of bytes. Strictly speaking, a "character" in an RTLIL
|
||||
file is a single byte. The lexer treats multi-byte encoded characters as
|
||||
consecutive single-byte characters. While other encodings *may* work, UTF-8 is
|
||||
known to be safe to use. Byte order marks at the beginning of the file will
|
||||
cause an error.
|
||||
|
||||
ASCII spaces (32) and tabs (9) separate lexer tokens.
|
||||
|
||||
A ``nonws`` character, used in identifiers, is any character whose encoding
|
||||
consists solely of bytes above ASCII space (32).
|
||||
|
||||
An ``eol`` is one or more consecutive ASCII newlines (10) and carriage returns
|
||||
(13).
|
||||
|
||||
Identifiers
|
||||
^^^^^^^^^^^
|
||||
|
||||
There are two types of identifiers in RTLIL:
|
||||
|
||||
- Publically visible identifiers
|
||||
- Auto-generated identifiers
|
||||
|
||||
.. code:: BNF
|
||||
|
||||
<id> ::= <public-id> | <autogen-id>
|
||||
<public-id> ::= \ <nonws>+
|
||||
<autogen-id> ::= $ <nonws>+
|
||||
|
||||
Values
|
||||
^^^^^^
|
||||
|
||||
A *value* consists of a width in bits and a bit representation, most
|
||||
significant bit first. Bits may be any of:
|
||||
|
||||
- ``0``: A logic zero value
|
||||
- ``1``: A logic one value
|
||||
- ``x``: An unknown logic value (or don't care in case patterns)
|
||||
- ``z``: A high-impedance value (or don't care in case patterns)
|
||||
- ``m``: A marked bit (internal use only)
|
||||
- ``-``: A don't care value
|
||||
|
||||
An *integer* is simply a signed integer value in decimal format. **Warning:**
|
||||
Integer constants are limited to 32 bits. That is, they may only be in the range
|
||||
:math:`[-2147483648, 2147483648)`. Integers outside this range will result in an
|
||||
error.
|
||||
|
||||
.. code:: BNF
|
||||
|
||||
<value> ::= <decimal-digit>+ ' <binary-digit>*
|
||||
<decimal-digit> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
|
||||
<binary-digit> ::= 0 | 1 | x | z | m | -
|
||||
<integer> ::= -? <decimal-digit>+
|
||||
|
||||
Strings
|
||||
^^^^^^^
|
||||
|
||||
A string is a series of characters delimited by double-quote characters. Within
|
||||
a string, any character except ASCII NUL (0) may be used. In addition, certain
|
||||
escapes can be used:
|
||||
|
||||
- ``\n``: A newline
|
||||
- ``\t``: A tab
|
||||
- ``\ooo``: A character specified as a one, two, or three digit octal value
|
||||
|
||||
All other characters may be escaped by a backslash, and become the following
|
||||
character. Thus:
|
||||
|
||||
- ``\\``: A backslash
|
||||
- ``\"``: A double-quote
|
||||
- ``\r``: An 'r' character
|
||||
|
||||
Comments
|
||||
^^^^^^^^
|
||||
|
||||
A comment starts with a ``#`` character and proceeds to the end of the line. All
|
||||
comments are ignored.
|
||||
|
||||
File
|
||||
~~~~
|
||||
|
||||
A file consists of an optional autoindex statement followed by zero or more
|
||||
modules.
|
||||
|
||||
.. code:: BNF
|
||||
|
||||
<file> ::= <autoidx-stmt>? <module>*
|
||||
|
||||
Autoindex statements
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The autoindex statement sets the global autoindex value used by Yosys when it
|
||||
needs to generate a unique name, e.g. ``flattenN``. The N part is filled with
|
||||
the value of the global autoindex value, which is subsequently incremented. This
|
||||
global has to be dumped into RTLIL, otherwise e.g. dumping and running a pass
|
||||
would have different properties than just running a pass on a warm design.
|
||||
|
||||
.. code:: BNF
|
||||
|
||||
<autoidx-stmt> ::= autoidx <integer> <eol>
|
||||
|
||||
Modules
|
||||
^^^^^^^
|
||||
|
||||
Declares a module, with zero or more attributes, consisting of zero or more
|
||||
wires, memories, cells, processes, and connections.
|
||||
|
||||
.. code:: BNF
|
||||
|
||||
<module> ::= <attr-stmt>* <module-stmt> <module-body> <module-end-stmt>
|
||||
<module-stmt> ::= module <id> <eol>
|
||||
<module-body> ::= (<param-stmt>
|
||||
| <wire>
|
||||
| <memory>
|
||||
| <cell>
|
||||
| <process>)*
|
||||
<param-stmt> ::= parameter <id> <constant>? <eol>
|
||||
<constant> ::= <value> | <integer> | <string>
|
||||
<module-end-stmt> ::= end <eol>
|
||||
|
||||
Attribute statements
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Declares an attribute with the given identifier and value.
|
||||
|
||||
.. code:: BNF
|
||||
|
||||
<attr-stmt> ::= attribute <id> <constant> <eol>
|
||||
|
||||
Signal specifications
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
A signal is anything that can be applied to a cell port, i.e. a constant value,
|
||||
all bits or a selection of bits from a wire, or concatenations of those.
|
||||
|
||||
**Warning:** When an integer constant is a sigspec, it is always 32 bits wide,
|
||||
2's complement. For example, a constant of :math:`-1` is the same as
|
||||
``32'11111111111111111111111111111111``, while a constant of :math:`1` is the
|
||||
same as ``32'1``.
|
||||
|
||||
See :ref:`sec:rtlil_sigspec` for an overview of signal specifications.
|
||||
|
||||
.. code:: BNF
|
||||
|
||||
<sigspec> ::= <constant>
|
||||
| <wire-id>
|
||||
| <sigspec> [ <integer> (:<integer>)? ]
|
||||
| { <sigspec>* }
|
||||
|
||||
Connections
|
||||
^^^^^^^^^^^
|
||||
|
||||
Declares a connection between the given signals.
|
||||
|
||||
.. code:: BNF
|
||||
|
||||
<conn-stmt> ::= connect <sigspec> <sigspec> <eol>
|
||||
|
||||
Wires
|
||||
^^^^^
|
||||
|
||||
Declares a wire, with zero or more attributes, with the given identifier and
|
||||
options in the enclosing module.
|
||||
|
||||
See :ref:`sec:rtlil_cell_wire` for an overview of wires.
|
||||
|
||||
.. code:: BNF
|
||||
|
||||
<wire> ::= <attr-stmt>* <wire-stmt>
|
||||
<wire-stmt> ::= wire <wire-option>* <wire-id> <eol>
|
||||
<wire-id> ::= <id>
|
||||
<wire-option> ::= width <integer>
|
||||
| offset <integer>
|
||||
| input <integer>
|
||||
| output <integer>
|
||||
| inout <integer>
|
||||
| upto
|
||||
| signed
|
||||
|
||||
Memories
|
||||
^^^^^^^^
|
||||
|
||||
Declares a memory, with zero or more attributes, with the given identifier and
|
||||
options in the enclosing module.
|
||||
|
||||
See :ref:`sec:rtlil_memory` for an overview of memory cells, and
|
||||
:ref:`sec:memcells` for details about memory cell types.
|
||||
|
||||
.. code:: BNF
|
||||
|
||||
<memory> ::= <attr-stmt>* <memory-stmt>
|
||||
<memory-stmt> ::= memory <memory-option>* <id> <eol>
|
||||
<memory-option> ::= width <integer>
|
||||
| size <integer>
|
||||
| offset <integer>
|
||||
|
||||
Cells
|
||||
^^^^^
|
||||
|
||||
Declares a cell, with zero or more attributes, with the given identifier and
|
||||
type in the enclosing module.
|
||||
|
||||
Cells perform functions on input signals. See :ref:`chapter:celllib` for a
|
||||
detailed list of cell types.
|
||||
|
||||
.. code:: BNF
|
||||
|
||||
<cell> ::= <attr-stmt>* <cell-stmt> <cell-body-stmt>* <cell-end-stmt>
|
||||
<cell-stmt> ::= cell <cell-type> <cell-id> <eol>
|
||||
<cell-id> ::= <id>
|
||||
<cell-type> ::= <id>
|
||||
<cell-body-stmt> ::= parameter (signed | real)? <id> <constant> <eol>
|
||||
| connect <id> <sigspec> <eol>
|
||||
<cell-end-stmt> ::= end <eol>
|
||||
|
||||
|
||||
Processes
|
||||
^^^^^^^^^
|
||||
|
||||
Declares a process, with zero or more attributes, with the given identifier in
|
||||
the enclosing module. The body of a process consists of zero or more
|
||||
assignments, exactly one switch, and zero or more syncs.
|
||||
|
||||
See :ref:`sec:rtlil_process` for an overview of processes.
|
||||
|
||||
.. code:: BNF
|
||||
|
||||
<process> ::= <attr-stmt>* <proc-stmt> <process-body> <proc-end-stmt>
|
||||
<proc-stmt> ::= process <id> <eol>
|
||||
<process-body> ::= <assign-stmt>* <switch>? <assign-stmt>* <sync>*
|
||||
<assign-stmt> ::= assign <dest-sigspec> <src-sigspec> <eol>
|
||||
<dest-sigspec> ::= <sigspec>
|
||||
<src-sigspec> ::= <sigspec>
|
||||
<proc-end-stmt> ::= end <eol>
|
||||
|
||||
Switches
|
||||
^^^^^^^^
|
||||
|
||||
Switches test a signal for equality against a list of cases. Each case specifies
|
||||
a comma-separated list of signals to check against. If there are no signals in
|
||||
the list, then the case is the default case. The body of a case consists of zero
|
||||
or more switches and assignments. Both switches and cases may have zero or more
|
||||
attributes.
|
||||
|
||||
.. code:: BNF
|
||||
|
||||
<switch> ::= <switch-stmt> <case>* <switch-end-stmt>
|
||||
<switch-stmt> := <attr-stmt>* switch <sigspec> <eol>
|
||||
<case> ::= <attr-stmt>* <case-stmt> <case-body>
|
||||
<case-stmt> ::= case <compare>? <eol>
|
||||
<compare> ::= <sigspec> (, <sigspec>)*
|
||||
<case-body> ::= (<switch> | <assign-stmt>)*
|
||||
<switch-end-stmt> ::= end <eol>
|
||||
|
||||
Syncs
|
||||
^^^^^
|
||||
|
||||
Syncs update signals with other signals when an event happens. Such an event may
|
||||
be:
|
||||
|
||||
- An edge or level on a signal
|
||||
- Global clock ticks
|
||||
- Initialization
|
||||
- Always
|
||||
|
||||
.. code:: BNF
|
||||
|
||||
<sync> ::= <sync-stmt> <update-stmt>*
|
||||
<sync-stmt> ::= sync <sync-type> <sigspec> <eol>
|
||||
| sync global <eol>
|
||||
| sync init <eol>
|
||||
| sync always <eol>
|
||||
<sync-type> ::= low | high | posedge | negedge | edge
|
||||
<update-stmt> ::= update <dest-sigspec> <src-sigspec> <eol>
|
41
docs/source/yosys_internals/index.rst
Normal file
41
docs/source/yosys_internals/index.rst
Normal file
|
@ -0,0 +1,41 @@
|
|||
.. _chapter:overview:
|
||||
|
||||
Yosys internals
|
||||
===============
|
||||
|
||||
.. TODO: copypaste
|
||||
|
||||
Yosys is an extensible open source hardware synthesis tool. It is aimed at
|
||||
designers who are looking for an easily accessible, universal, and
|
||||
vendor-independent synthesis tool, as well as scientists who do research in
|
||||
electronic design automation (EDA) and are looking for an open synthesis
|
||||
framework that can be used to test algorithms on complex real-world designs.
|
||||
|
||||
Yosys can synthesize a large subset of Verilog 2005 and has been tested with a
|
||||
wide range of real-world designs, including the `OpenRISC 1200 CPU`_, the
|
||||
`openMSP430 CPU`_, the `OpenCores I2C master`_, and the `k68 CPU`_.
|
||||
|
||||
.. _OpenRISC 1200 CPU: https://github.com/openrisc/or1200
|
||||
|
||||
.. _openMSP430 CPU: http://opencores.org/projects/openmsp430
|
||||
|
||||
.. _OpenCores I2C master: http://opencores.org/projects/i2c
|
||||
|
||||
.. _k68 CPU: http://opencores.org/projects/k68
|
||||
|
||||
As of this writing a Yosys VHDL frontend is in development.
|
||||
|
||||
Yosys is written in C++ (using some features from the new C++11 standard). This
|
||||
chapter describes some of the fundamental Yosys data structures. For the sake of
|
||||
simplicity the C++ type names used in the Yosys implementation are used in this
|
||||
chapter, even though the chapter only explains the conceptual idea behind it and
|
||||
can be used as reference to implement a similar system in any language.
|
||||
|
||||
.. toctree::
|
||||
|
||||
flow/index
|
||||
formats/index
|
||||
techmap
|
||||
extensions
|
||||
|
||||
.. TODO: copypaste
|
107
docs/source/yosys_internals/techmap.rst
Normal file
107
docs/source/yosys_internals/techmap.rst
Normal file
|
@ -0,0 +1,107 @@
|
|||
.. _chapter:techmap:
|
||||
|
||||
.. TODO: copypaste
|
||||
|
||||
Technology mapping
|
||||
==================
|
||||
|
||||
Previous chapters outlined how HDL code is transformed into an RTL netlist. The
|
||||
RTL netlist is still based on abstract coarse-grain cell types like arbitrary
|
||||
width adders and even multipliers. This chapter covers how an RTL netlist is
|
||||
transformed into a functionally equivalent netlist utilizing the cell types
|
||||
available in the target architecture.
|
||||
|
||||
Technology mapping is often performed in two phases. In the first phase RTL
|
||||
cells are mapped to an internal library of single-bit cells (see
|
||||
:ref:`sec:celllib_gates`). In the second phase this netlist of internal gate
|
||||
types is transformed to a netlist of gates from the target technology library.
|
||||
|
||||
When the target architecture provides coarse-grain cells (such as block ram or
|
||||
ALUs), these must be mapped to directly form the RTL netlist, as information on
|
||||
the coarse-grain structure of the design is lost when it is mapped to bit-width
|
||||
gate types.
|
||||
|
||||
Cell substitution
|
||||
-----------------
|
||||
|
||||
The simplest form of technology mapping is cell substitution, as performed by
|
||||
the techmap pass. This pass, when provided with a Verilog file that implements
|
||||
the RTL cell types using simpler cells, simply replaces the RTL cells with the
|
||||
provided implementation.
|
||||
|
||||
When no map file is provided, techmap uses a built-in map file that maps the
|
||||
Yosys RTL cell types to the internal gate library used by Yosys. The curious
|
||||
reader may find this map file as techlibs/common/techmap.v in the Yosys source
|
||||
tree.
|
||||
|
||||
Additional features have been added to techmap to allow for conditional mapping
|
||||
of cells (see :doc:`/cmd/techmap`). This can for example be useful if the target
|
||||
architecture supports hardware multipliers for certain bit-widths but not for
|
||||
others.
|
||||
|
||||
A usual synthesis flow would first use the techmap pass to directly map some RTL
|
||||
cells to coarse-grain cells provided by the target architecture (if any) and
|
||||
then use techmap with the built-in default file to map the remaining RTL cells
|
||||
to gate logic.
|
||||
|
||||
Subcircuit substitution
|
||||
-----------------------
|
||||
|
||||
Sometimes the target architecture provides cells that are more powerful than the
|
||||
RTL cells used by Yosys. For example a cell in the target architecture that can
|
||||
calculate the absolute-difference of two numbers does not match any single RTL
|
||||
cell type but only combinations of cells.
|
||||
|
||||
For these cases Yosys provides the extract pass that can match a given set of
|
||||
modules against a design and identify the portions of the design that are
|
||||
identical (i.e. isomorphic subcircuits) to any of the given modules. These
|
||||
matched subcircuits are then replaced by instances of the given modules.
|
||||
|
||||
The extract pass also finds basic variations of the given modules, such as
|
||||
swapped inputs on commutative cell types.
|
||||
|
||||
In addition to this the extract pass also has limited support for frequent
|
||||
subcircuit mining, i.e. the process of finding recurring subcircuits in the
|
||||
design. This has a few applications, including the design of new coarse-grain
|
||||
architectures :cite:p:`intersynthFdlBookChapter`.
|
||||
|
||||
The hard algorithmic work done by the extract pass (solving the isomorphic
|
||||
subcircuit problem and frequent subcircuit mining) is performed using the
|
||||
SubCircuit library that can also be used stand-alone without Yosys (see
|
||||
:ref:`sec:SubCircuit`).
|
||||
|
||||
.. _sec:techmap_extern:
|
||||
|
||||
Gate-level technology mapping
|
||||
-----------------------------
|
||||
|
||||
On the gate-level the target architecture is usually described by a "Liberty
|
||||
file". The Liberty file format is an industry standard format that can be used
|
||||
to describe the behaviour and other properties of standard library cells .
|
||||
|
||||
Mapping a design utilizing the Yosys internal gate library (e.g. as a result of
|
||||
mapping it to this representation using the techmap pass) is performed in two
|
||||
phases.
|
||||
|
||||
First the register cells must be mapped to the registers that are available on
|
||||
the target architectures. The target architecture might not provide all
|
||||
variations of d-type flip-flops with positive and negative clock edge,
|
||||
high-active and low-active asynchronous set and/or reset, etc. Therefore the
|
||||
process of mapping the registers might add additional inverters to the design
|
||||
and thus it is important to map the register cells first.
|
||||
|
||||
Mapping of the register cells may be performed by using the dfflibmap pass. This
|
||||
pass expects a Liberty file as argument (using the -liberty option) and only
|
||||
uses the register cells from the Liberty file.
|
||||
|
||||
Secondly the combinational logic must be mapped to the target architecture. This
|
||||
is done using the external program ABC via the abc pass by using the -liberty
|
||||
option to the pass. Note that in this case only the combinatorial cells are used
|
||||
from the cell library.
|
||||
|
||||
Occasionally Liberty files contain trade secrets (such as sensitive timing
|
||||
information) that cannot be shared freely. This complicates processes such as
|
||||
reporting bugs in the tools involved. When the information in the Liberty file
|
||||
used by Yosys and ABC are not part of the sensitive information, the additional
|
||||
tool yosys-filterlib (see :ref:`sec:filterlib`) can be used to strip the
|
||||
sensitive information from the Liberty file.
|
Loading…
Add table
Add a link
Reference in a new issue