3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-06-13 01:16:16 +00:00

Updated ABC info

Includes comparison of `abc` v `abc9`. Also creates a new subsection of the
yosys internals for extending yosys (moving the previous extensions.rst into it).

Co-authored-by: Lofty <dan.ravensloft@gmail.com>
This commit is contained in:
Krystine Sherwin 2023-12-13 10:08:45 +13:00
parent e34a25ea27
commit 1733a76273
No known key found for this signature in database
6 changed files with 196 additions and 45 deletions

View file

@ -0,0 +1,76 @@
Setting up a flow for ABC9
--------------------------
Much of the configuration comes from attributes and ``specify`` blocks in
Verilog simulation models.
``specify`` syntax
~~~~~~~~~~~~~~~~~~
Since ``specify`` is a relatively obscure part of the Verilog standard, a quick
guide to the syntax:
.. code-block:: verilog
specify // begins a specify block
(A => B) = 123; // simple combinational path from A to B with a delay of 123.
(A *> B) = 123; // simple combinational path from A to all bits of B with a delay of 123 for all.
if (FOO) (A => B) = 123; // paths may apply under specific conditions.
(posedge CLK => (Q : D)) = 123; // combinational path triggered on the positive edge of CLK; used for clock-to-Q arrival paths.
$setup(A, posedge CLK, 123); // setup constraint for an input relative to a clock.
endspecify // ends a specify block
By convention, all delays in ``specify`` blocks are in integer picoseconds.
Files containing ``specify`` blocks should be read with the ``-specify`` option
to ``read_verilog`` so that they aren't skipped.
LUTs
^^^^
LUTs need to be annotated with an ``(* abc9_lut=N *)`` attribute, where ``N`` is
the relative area of that LUT model. For example, if an architecture can combine
LUTs to produce larger LUTs, then the combined LUTs would have increasingly
larger ``N``. Conversely, if an architecture can split larger LUTs into smaller
LUTs, then the smaller LUTs would have smaller ``N``.
LUTs are generally specified with simple combinational paths from the LUT inputs
to the LUT output.
DFFs
^^^^
DFFs should be annotated with an ``(* abc9_flop *)`` attribute, however ABC9 has
some specific requirements for this to be valid: - the DFF must initialise to
zero (consider using ``dfflegalize`` to ensure this). - the DFF cannot have any
asynchronous resets/sets (see the simplification idiom and the Boxes section for
what to do here).
It is worth noting that in pure ``abc9`` mode, only the setup and arrival times
are passed to ABC9 (specifically, they are modelled as buffers with the given
delay). In ``abc9 -dff``, the flop itself is passed to ABC9, permitting
sequential optimisations.
Some vendors have universal DFF models which include async sets/resets even when
they're unused. Therefore *the simplification idiom* exists to handle this: by
using a ``techmap`` file to discover flops which have a constant driver to those
asynchronous controls, they can be mapped into an intermediate, simplified flop
which qualifies as an ``(* abc9_flop *)``, ran through :cmd:ref:`abc9`, and then
mapped back to the original flop. This is used in :cmd:ref:`synth_intel_alm` and
:cmd:ref:`synth_quicklogic` for the PolarPro3.
DFFs are usually specified to have setup constraints against the clock on the
input signals, and an arrival time for the Q output.
Boxes
^^^^^
A "box" is a purely-combinational piece of hard logic. If the logic is exposed
to ABC9, it's a "whitebox", otherwise it's a "blackbox". Carry chains would be
best implemented as whiteboxes, but a DSP would be best implemented as a
blackbox (multipliers are too complex to easily work with). LUT RAMs can be
implemented as whiteboxes too.
Boxes are arguably the biggest advantage that ABC9 has over ABC: by being aware
of carry chains and DSPs, it avoids optimising for a path that isn't the actual
critical path, while the generally-longer paths result in ABC9 being able to
reduce design area by mapping other logic to larger-but-slower cells.

View file

@ -0,0 +1,258 @@
Writing extensions
==================
.. todo:: check text is coherent
This chapter contains some bits and pieces of information about programming
yosys extensions. 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/code_examples/stubnets/stubnets.cc``.
.. literalinclude:: /code_examples/stubnets/stubnets.cc
:language: c++
:linenos:
:caption: docs/source/code_examples/stubnets/stubnets.cc
.. literalinclude:: /code_examples/stubnets/Makefile
:language: makefile
:linenos:
:caption: docs/source/code_examples/stubnets/Makefile
.. literalinclude:: /code_examples/stubnets/test.v
:language: verilog
:linenos:
:caption: docs/source/code_examples/stubnets/test.v
Quick guide
-----------
See also: ``docs/resources/PRESENTATION_Prog/*``.
Program components and data formats
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
See :doc:`/yosys_internals/formats/rtlil_rep` document for more information
about the internal data storage format used in Yosys and the classes that it
provides.
This document will focus on the much simpler version of RTLIL left after the
commands :cmd:ref:`proc` and :cmd:ref:`memory` (or ``memory -nomap``):
.. figure:: /_images/internals/simplified_rtlil.*
:class: width-helper
:name: fig:Simplified_RTLIL
Simplified RTLIL entity-relationship diagram without memories and processes
It is possible to only work on this simpler version:
.. code:: c++
for (RTLIL::Module *module : design->selected_modules() {
if (module->has_memories_warn() || module->has_processes_warn())
continue;
....
}
When trying to understand what a command does, creating a small test case to
look at the output of :cmd:ref:`dump` and :cmd:ref:`show` before and after the
command has been executed can be helpful. The
:doc:`/using_yosys/more_scripting/selections` document has more information on
using these commands.
Creating modules from scratch
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. todo:: add/expand supporting text, also use files in docs/resources/PRESENTATION_Prog
Let's create the following module using the RTLIL API:
.. literalinclude:: ../../../resources/PRESENTATION_Prog/absval_ref.v
:language: Verilog
:caption: docs/resources/PRESENTATION_Prog/absval_ref.v
.. code:: C++
RTLIL::Module *module = new RTLIL::Module;
module->name = "\\absval";
RTLIL::Wire *a = module->addWire("\\a", 4);
a->port_input = true;
a->port_id = 1;
RTLIL::Wire *y = module->addWire("\\y", 4);
y->port_output = true;
y->port_id = 2;
RTLIL::Wire *a_inv = module->addWire(NEW_ID, 4);
module->addNeg(NEW_ID, a, a_inv, true);
module->addMux(NEW_ID, a, a_inv, RTLIL::SigSpec(a, 1, 3), y);
module->fixup_ports();
Modifying modules
~~~~~~~~~~~~~~~~~
Most commands modify existing modules, not create new ones.
When modifying existing modules, stick to the following DOs and DON'Ts:
- Do not remove wires. Simply disconnect them and let a successive
:cmd:ref:`clean` command worry about removing it.
- Use ``module->fixup_ports()`` after changing the ``port_*`` properties of
wires.
- You can safely remove cells or change the ``connections`` property of a cell,
but be careful when changing the size of the ``SigSpec`` connected to a cell
port.
- Use the ``SigMap`` helper class (see next section) when you need a unique
handle for each signal bit.
Using the SigMap helper class
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Consider the following module:
.. code:: Verilog
module test(input a, output x, y);
assign x = a, y = a;
endmodule
In this case ``a``, ``x``, and ``y`` are all different names for the same signal. However:
.. code:: C++
RTLIL::SigSpec a(module->wire("\\a")), x(module->wire("\\x")),
y(module->wire("\\y"));
log("%d %d %d\n", a == x, x == y, y == a); // will print "0 0 0"
The ``SigMap`` helper class can be used to map all such aliasing signals to a
unique signal from the group (usually the wire that is directly driven by a cell or port).
.. code:: C++
SigMap sigmap(module);
log("%d %d %d\n", sigmap(a) == sigmap(x), sigmap(x) == sigmap(y),
sigmap(y) == sigmap(a)); // will print "1 1 1"
Printing log messages
~~~~~~~~~~~~~~~~~~~~~
The ``log()`` function is a ``printf()``-like function that can be used to create log messages.
Use ``log_signal()`` to create a C-string for a SigSpec object:
.. code:: C++
log("Mapped signal x: %s\n", log_signal(sigmap(x)));
The pointer returned by ``log_signal()`` is automatically freed by the log
framework at a later time.
Use ``log_id()`` to create a C-string for an ``RTLIL::IdString``:
.. code:: C++
log("Name of this module: %s\n", log_id(module->name));
Use ``log_header()`` and ``log_push()``/``log_pop()`` to structure log messages:
.. code:: C++
log_header(design, "Doing important stuff!\n");
log_push();
for (int i = 0; i < 10; i++)
log("Log message #%d.\n", i);
log_pop();
Error handling
~~~~~~~~~~~~~~
Use ``log_error()`` to report a non-recoverable error:
.. code:: C++
if (design->modules.count(module->name) != 0)
log_error("A module with the name %s already exists!\n",
RTLIL::id2cstr(module->name));
Use ``log_cmd_error()`` to report a recoverable error:
.. code:: C++
if (design->selection_stack.back().empty())
log_cmd_error("This command can't operator on an empty selection!\n");
Use ``log_assert()`` and ``log_abort()`` instead of ``assert()`` and ``abort()``.
Creating a command
~~~~~~~~~~~~~~~~~~
Simply create a global instance of a class derived from ``Pass`` to create
a new yosys command:
.. code:: C++
#include "kernel/yosys.h"
USING_YOSYS_NAMESPACE
struct MyPass : public Pass {
MyPass() : Pass("my_cmd", "just a simple test") { }
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
log("Arguments to my_cmd:\n");
for (auto &arg : args)
log(" %s\n", arg.c_str());
log("Modules in current design:\n");
for (auto mod : design->modules())
log(" %s (%d wires, %d cells)\n", log_id(mod),
GetSize(mod->wires()), GetSize(mod->cells()));
}
} MyPass;
Creating a plugin
~~~~~~~~~~~~~~~~~
Yosys can be extended by adding additional C++ code to the Yosys code base, or
by loading plugins into Yosys.
Use the following command to compile a Yosys plugin:
.. code::
yosys-config --exec --cxx --cxxflags --ldflags \
-o my_cmd.so -shared my_cmd.cc --ldlibs
Or shorter:
.. code::
yosys-config --build my_cmd.so my_cmd.cc
Load the plugin using the yosys ``-m`` option:
.. code::
yosys -m ./my_cmd.so -p 'my_cmd foo bar'

View file

@ -0,0 +1,11 @@
Extending Yosys
---------------
.. todo:: brief overview for the extending Yosys index
.. toctree::
:maxdepth: 3
extensions
abc_flow