mirror of
https://github.com/YosysHQ/yosys
synced 2025-06-16 19:06:18 +00:00
parent
853f4bb3c6
commit
a14dec79eb
57 changed files with 7792 additions and 2 deletions
336
docs/source/appendix/APPNOTE_010_Verilog_to_BLIF.rst
Normal file
336
docs/source/appendix/APPNOTE_010_Verilog_to_BLIF.rst
Normal file
|
@ -0,0 +1,336 @@
|
|||
====================================
|
||||
010: Converting Verilog to BLIF page
|
||||
====================================
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
Yosys written in C++ (using features from C++11) and is tested on modern
|
||||
Linux. It should compile fine on most UNIX systems with a C++11
|
||||
compiler. The README file contains useful information on building Yosys
|
||||
and its prerequisites.
|
||||
|
||||
Yosys is a large and feature-rich program with a couple of dependencies.
|
||||
It is, however, possible to deactivate some of the dependencies in the
|
||||
Makefile, resulting in features in Yosys becoming unavailable. When
|
||||
problems with building Yosys are encountered, a user who is only
|
||||
interested in the features of Yosys that are discussed in this
|
||||
Application Note may deactivate TCL, Qt and MiniSAT support in the
|
||||
Makefile and may opt against building yosys-abc.
|
||||
|
||||
This Application Note is based on `Yosys GIT`_ `Rev. e216e0e`_ from 2013-11-23.
|
||||
The Verilog sources used for the examples are taken from `yosys-bigsim`_, a
|
||||
collection of real-world designs used for regression testing Yosys.
|
||||
|
||||
.. _Yosys GIT: https://github.com/YosysHQ/yosys
|
||||
|
||||
.. _Rev. e216e0e: https://github.com/YosysHQ/yosys/tree/e216e0e
|
||||
|
||||
.. _yosys-bigsim: https://github.com/YosysHQ/yosys-bigsim
|
||||
|
||||
Getting started
|
||||
===============
|
||||
|
||||
We start our tour with the Navré processor from yosys-bigsim. The `Navré
|
||||
processor`_ is an Open Source AVR clone. It is a single module (softusb_navre)
|
||||
in a single design file (softusb_navre.v). It also is using only features that
|
||||
map nicely to the BLIF format, for example it only uses synchronous resets.
|
||||
|
||||
.. _Navré processor: http://opencores.org/projects/navre
|
||||
|
||||
Converting softusb_navre.v to softusb_navre.blif could not be easier:
|
||||
|
||||
.. code:: sh
|
||||
|
||||
yosys -o softusb_navre.blif -S softusb_navre.v
|
||||
|
||||
Behind the scenes Yosys is controlled by synthesis scripts that execute
|
||||
commands that operate on Yosys' internal state. For example, the -o
|
||||
softusb_navre.blif option just adds the command write_blif
|
||||
softusb_navre.blif to the end of the script. Likewise a file on the
|
||||
command line – softusb_navre.v in this case – adds the command
|
||||
read_verilog softusb_navre.v to the beginning of the synthesis script.
|
||||
In both cases the file type is detected from the file extension.
|
||||
|
||||
Finally the option -S instantiates a built-in default synthesis script.
|
||||
Instead of using -S one could also specify the synthesis commands for
|
||||
the script on the command line using the -p option, either using
|
||||
individual options for each command or by passing one big command string
|
||||
with a semicolon-separated list of commands. But in most cases it is
|
||||
more convenient to use an actual script file.
|
||||
|
||||
Using a synthesis script
|
||||
========================
|
||||
|
||||
With a script file we have better control over Yosys. The following
|
||||
script file replicates what the command from the last section did:
|
||||
|
||||
.. code:: yoscrypt
|
||||
|
||||
read_verilog softusb_navre.v
|
||||
hierarchy
|
||||
proc; opt; memory; opt; techmap; opt
|
||||
write_blif softusb_navre.blif
|
||||
|
||||
The first and last line obviously read the Verilog file and write the
|
||||
BLIF file.
|
||||
|
||||
The 2nd line checks the design hierarchy and instantiates parametrized
|
||||
versions of the modules in the design, if necessary. In the case of this
|
||||
simple design this is a no-op. However, as a general rule a synthesis
|
||||
script should always contain this command as first command after reading
|
||||
the input files.
|
||||
|
||||
The 3rd line does most of the actual work:
|
||||
|
||||
- The command opt is the Yosys' built-in optimizer. It can perform some
|
||||
simple optimizations such as const-folding and removing unconnected
|
||||
parts of the design. It is common practice to call opt after each
|
||||
major step in the synthesis procedure. In cases where too much
|
||||
optimization is not appreciated (for example when analyzing a
|
||||
design), it is recommended to call clean instead of opt.
|
||||
|
||||
- The command proc converts processes (Yosys' internal representation
|
||||
of Verilog always- and initial-blocks) to circuits of multiplexers
|
||||
and storage elements (various types of flip-flops).
|
||||
|
||||
- The command memory converts Yosys' internal representations of arrays
|
||||
and array accesses to multi-port block memories, and then maps this
|
||||
block memories to address decoders and flip-flops, unless the option
|
||||
-nomap is used, in which case the multi-port block memories stay in
|
||||
the design and can then be mapped to architecture-specific memory
|
||||
primitives using other commands.
|
||||
|
||||
- The command techmap turns a high-level circuit with coarse grain
|
||||
cells such as wide adders and multipliers to a fine-grain circuit of
|
||||
simple logic primitives and single-bit storage elements. The command
|
||||
does that by substituting the complex cells by circuits of simpler
|
||||
cells. It is possible to provide a custom set of rules for this
|
||||
process in the form of a Verilog source file, as we will see in the
|
||||
next section.
|
||||
|
||||
Now Yosys can be run with the filename of the synthesis script as
|
||||
argument:
|
||||
|
||||
.. code:: sh
|
||||
|
||||
yosys softusb_navre.ys
|
||||
|
||||
Now that we are using a synthesis script we can easily modify how Yosys
|
||||
synthesizes the design. The first thing we should customize is the call
|
||||
to the hierarchy command:
|
||||
|
||||
Whenever it is known that there are no implicit blackboxes in the
|
||||
design, i.e. modules that are referenced but are not defined, the
|
||||
hierarchy command should be called with the -check option. This will
|
||||
then cause synthesis to fail when implicit blackboxes are found in the
|
||||
design.
|
||||
|
||||
The 2nd thing we can improve regarding the hierarchy command is that we
|
||||
can tell it the name of the top level module of the design hierarchy. It
|
||||
will then automatically remove all modules that are not referenced from
|
||||
this top level module.
|
||||
|
||||
For many designs it is also desired to optimize the encodings for the
|
||||
finite state machines (FSMs) in the design. The fsm command finds FSMs,
|
||||
extracts them, performs some basic optimizations and then generate a
|
||||
circuit from the extracted and optimized description. It would also be
|
||||
possible to tell the fsm command to leave the FSMs in their extracted
|
||||
form, so they can be further processed using custom commands. But in
|
||||
this case we don't want that.
|
||||
|
||||
So now we have the final synthesis script for generating a BLIF file for
|
||||
the Navré CPU:
|
||||
|
||||
.. code:: yoscrypt
|
||||
|
||||
read_verilog softusb_navre.v
|
||||
hierarchy -check -top softusb_navre
|
||||
proc; opt; memory; opt; fsm; opt; techmap; opt
|
||||
write_blif softusb_navre.blif
|
||||
|
||||
Advanced example: The Amber23 ARMv2a CPU
|
||||
========================================
|
||||
|
||||
Our 2nd example is the `Amber23 ARMv2a CPU`_. Once again we base our example on
|
||||
the Verilog code that is included in `yosys-bigsim`_.
|
||||
|
||||
.. _Amber23 ARMv2a CPU: http://opencores.org/projects/amber
|
||||
|
||||
.. code-block:: yoscrypt
|
||||
:caption: `amber23.ys`
|
||||
:name: amber23.ys
|
||||
|
||||
read_verilog a23_alu.v
|
||||
read_verilog a23_barrel_shift_fpga.v
|
||||
read_verilog a23_barrel_shift.v
|
||||
read_verilog a23_cache.v
|
||||
read_verilog a23_coprocessor.v
|
||||
read_verilog a23_core.v
|
||||
read_verilog a23_decode.v
|
||||
read_verilog a23_execute.v
|
||||
read_verilog a23_fetch.v
|
||||
read_verilog a23_multiply.v
|
||||
read_verilog a23_ram_register_bank.v
|
||||
read_verilog a23_register_bank.v
|
||||
read_verilog a23_wishbone.v
|
||||
read_verilog generic_sram_byte_en.v
|
||||
read_verilog generic_sram_line_en.v
|
||||
hierarchy -check -top a23_core
|
||||
add -global_input globrst 1
|
||||
proc -global_arst globrst
|
||||
techmap -map adff2dff.v
|
||||
opt; memory; opt; fsm; opt; techmap
|
||||
write_blif amber23.blif
|
||||
|
||||
The problem with this core is that it contains no dedicated reset logic. Instead
|
||||
the coding techniques shown in :numref:`glob_arst` are used to define reset
|
||||
values for the global asynchronous reset in an FPGA implementation. This design
|
||||
can not be expressed in BLIF as it is. Instead we need to use a synthesis script
|
||||
that transforms this form to synchronous resets that can be expressed in BLIF.
|
||||
|
||||
(Note that there is no problem if this coding techniques are used to
|
||||
model ROM, where the register is initialized using this syntax but is
|
||||
never updated otherwise.)
|
||||
|
||||
:numref:`amber23.ys` shows the synthesis script for the Amber23 core. In line 17
|
||||
the add command is used to add a 1-bit wide global input signal with the name
|
||||
globrst. That means that an input with that name is added to each module in the
|
||||
design hierarchy and then all module instantiations are altered so that this new
|
||||
signal is connected throughout the whole design hierarchy.
|
||||
|
||||
.. code-block:: verilog
|
||||
:caption: Implicit coding of global asynchronous resets
|
||||
:name: glob_arst
|
||||
|
||||
reg [7:0] a = 13, b;
|
||||
initial b = 37;
|
||||
|
||||
.. code-block:: verilog
|
||||
:caption: `adff2dff.v`
|
||||
:name: adff2dff.v
|
||||
|
||||
(* techmap_celltype = "$adff" *)
|
||||
module adff2dff (CLK, ARST, D, Q);
|
||||
|
||||
parameter WIDTH = 1;
|
||||
parameter CLK_POLARITY = 1;
|
||||
parameter ARST_POLARITY = 1;
|
||||
parameter ARST_VALUE = 0;
|
||||
|
||||
input CLK, ARST;
|
||||
input [WIDTH-1:0] D;
|
||||
output reg [WIDTH-1:0] Q;
|
||||
|
||||
wire [1023:0] _TECHMAP_DO_ = "proc";
|
||||
|
||||
wire _TECHMAP_FAIL_ =
|
||||
!CLK_POLARITY || !ARST_POLARITY;
|
||||
|
||||
always @(posedge CLK)
|
||||
if (ARST)
|
||||
Q <= ARST_VALUE;
|
||||
else
|
||||
Q <= D;
|
||||
|
||||
endmodule
|
||||
|
||||
In line 18 the proc command is called. But in this script the signal
|
||||
name globrst is passed to the command as a global reset signal for
|
||||
resetting the registers to their assigned initial values.
|
||||
|
||||
Finally in line 19 the techmap command is used to replace all instances of
|
||||
flip-flops with asynchronous resets with flip-flops with synchronous resets. The
|
||||
map file used for this is shown in :numref:`adff2dff.v`. Note how the
|
||||
techmap_celltype attribute is used in line 1 to tell the techmap command which
|
||||
cells to replace in the design, how the \_TECHMAP_FAIL\_ wire in lines 15 and 16
|
||||
(which evaluates to a constant value) determines if the parameter set is
|
||||
compatible with this replacement circuit, and how the \_TECHMAP_DO\_ wire in
|
||||
line 13 provides a mini synthesis-script to be used to process this cell.
|
||||
|
||||
.. code-block:: c
|
||||
:caption: Test program for the Amber23 CPU (Sieve of Eratosthenes). Compiled
|
||||
using GCC 4.6.3 for ARM with ``-Os -marm -march=armv2a
|
||||
-mno-thumb-interwork -ffreestanding``, linked with ``--fix-v4bx``
|
||||
set and booted with a custom setup routine written in ARM assembler.
|
||||
:name: sieve
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define BITMAP_SIZE 64
|
||||
#define OUTPORT 0x10000000
|
||||
|
||||
static uint32_t bitmap[BITMAP_SIZE/32];
|
||||
|
||||
static void bitmap_set(uint32_t idx) { bitmap[idx/32] |= 1 << (idx % 32); }
|
||||
static bool bitmap_get(uint32_t idx) { return (bitmap[idx/32] & (1 << (idx % 32))) != 0; }
|
||||
static void output(uint32_t val) { *((volatile uint32_t*)OUTPORT) = val; }
|
||||
|
||||
int main() {
|
||||
uint32_t i, j, k;
|
||||
output(2);
|
||||
for (i = 0; i < BITMAP_SIZE; i++) {
|
||||
if (bitmap_get(i)) continue;
|
||||
output(3+2*i);
|
||||
for (j = 2*(3+2*i);; j += 3+2*i) {
|
||||
if (j%2 == 0) continue;
|
||||
k = (j-3)/2;
|
||||
if (k >= BITMAP_SIZE) break;
|
||||
bitmap_set(k);
|
||||
}
|
||||
}
|
||||
output(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Verification of the Amber23 CPU
|
||||
===============================
|
||||
|
||||
The BLIF file for the Amber23 core, generated using :numref:`amber23.ys` and
|
||||
:numref:`adff2dff.v` and the version of the Amber23 RTL source that is bundled
|
||||
with yosys-bigsim, was verified using the test-bench from yosys-bigsim. It
|
||||
successfully executed the program shown in :numref:`sieve` in the test-bench.
|
||||
|
||||
For simulation the BLIF file was converted back to Verilog using `ABC`_. So this
|
||||
test includes the successful transformation of the BLIF file into ABC's internal
|
||||
format as well.
|
||||
|
||||
.. _ABC: https://github.com/berkeley-abc/abc
|
||||
|
||||
The only thing left to write about the simulation itself is that it
|
||||
probably was one of the most energy inefficient and time consuming ways
|
||||
of successfully calculating the first 31 primes the author has ever
|
||||
conducted.
|
||||
|
||||
Limitations
|
||||
===========
|
||||
|
||||
At the time of this writing Yosys does not support multi-dimensional
|
||||
memories, does not support writing to individual bits of array elements,
|
||||
does not support initialization of arrays with $readmemb and $readmemh,
|
||||
and has only limited support for tristate logic, to name just a few
|
||||
limitations.
|
||||
|
||||
That being said, Yosys can synthesize an overwhelming majority of
|
||||
real-world Verilog RTL code. The remaining cases can usually be modified
|
||||
to be compatible with Yosys quite easily.
|
||||
|
||||
The various designs in yosys-bigsim are a good place to look for
|
||||
examples of what is within the capabilities of Yosys.
|
||||
|
||||
Conclusion
|
||||
==========
|
||||
|
||||
Yosys is a feature-rich Verilog-2005 synthesis tool. It has many uses,
|
||||
but one is to provide an easy gateway from high-level Verilog code to
|
||||
low-level logic circuits.
|
||||
|
||||
The command line option -S can be used to quickly synthesize Verilog
|
||||
code to BLIF files without a hassle.
|
||||
|
||||
With custom synthesis scripts it becomes possible to easily perform
|
||||
high-level optimizations, such as re-encoding FSMs. In some extreme
|
||||
cases, such as the Amber23 ARMv2 CPU, the more advanced Yosys features
|
||||
can be used to change a design to fit a certain need without actually
|
||||
touching the RTL code.
|
Loading…
Add table
Add a link
Reference in a new issue