This is a quick post about the setup I am using for writing RTL and seeing the synthesis output in real time. This is kind of a poor man’s IDE by opening multiple VS Code files and rerunning the commands automatically.
This is also a good chance to talk more about yosys flow and commands. Starting with my go-to Makefile
to play with yosys:
all:
yosys synth.ys
netlistsvg top.vis.json -o top.vis.svg
convert top.vis.svg top.vis.png
netlistsvg top.synth.json -o top.synth.svg
convert top.synth.svg top.synth.png
netlistsvg top.pdk.json -o top.pdk.svg
convert top.pdk.svg top.pdk.png
Yosys Script Link to heading
The first thing is reading the Verilog code with read_verilog
. For this setup, I will use one file called top.v
to make my life easier.
read_verilog -sv top.v
prep Link to heading
For the next stage, we will prep
, which does the following 3 stages:
- proc turns always processes into lower-level logic.
- flatten replaces instantiated submodules with their implementation.
- opt basic optimizations (remove unused wires).
prep -top top
write_json top.vis.json
write_verilog top.vis.v
show -format png -prefix top.vis.yosys
From this stage we get two PNGs, one coming from Yosys with Graphviz top.vis.yosys.png
with show -format png -prefix top.vis.yosys
.
The second cleaner diagram comes from feeding JSON to netlistsvg
and converting SVG to PNG.
At the end of prep
, we can print Yosys stats as follows:
2.12. Printing statistics.
=== top ===
Number of wires: 50
Number of wire bits: 92
Number of public wires: 11
Number of public wire bits: 33
Number of ports: 4
Number of port bits: 7
Number of memories: 0
Number of memory bits: 0
Number of processes: 0
Number of cells: 47
$add 2
$adff 8
$eq 23
$logic_not 3
$mux 3
$not 1
$pmux 4
$reduce_or 3
Synth Link to heading
Now we need to look at the netlist (generic at this point) from our RTL. The command synth
starts the netlist generation. Typical passes inside synth:
- Calls proc, opt, memory passes.
- Performs logic optimization.
- Converts processes, memories, FSMs into gates.
synth -top top
write_json top.synth.json
write_verilog top.synth.v
write_blif top.synth.blif
write_edif top.synth.edif
show -format png -prefix top.synth.yosys
At this stage, we generate 2 diagrams of the netlist (one from Yosys and one from netlistsvg).
Finally, we can see the synthesis report with technology-independent cells.
6.25. Printing statistics.
=== top ===
Number of wires: 120
Number of wire bits: 178
Number of public wires: 11
Number of public wire bits: 33
Number of ports: 4
Number of port bits: 7
Number of memories: 0
Number of memory bits: 0
Number of processes: 0
Number of cells: 146
$_ANDNOT_ 32
$_AND_ 8
$_DFFE_PN0N_ 1
$_DFF_PN0_ 22
$_MUX_ 3
$_NAND_ 15
$_NOR_ 3
$_NOT_ 4
$_ORNOT_ 8
$_OR_ 38
$_XNOR_ 2
$_XOR_ 10
dfflibmap and abc Link to heading
The last step is mapping cells to specific technology. I usually use NangateOpenCellLibrary_typical.lib
. That said, it’s not worth looking at diagrams at this point for two reasons:
- It is really hard to trace stuff on the netlist after mapping with a large number of cells and wires.
- And what makes it even worse,
netlistsvg
can’t even process the netlist at this point.dfflibmap
is called for mappingdff
from the generic netlist.abc
does the combinational logic mapping:
dfflibmap -prepare -liberty NangateOpenCellLibrary_typical.lib
abc -liberty NangateOpenCellLibrary_typical.lib
dfflibmap -liberty NangateOpenCellLibrary_typical.lib
write_json top.pdk.json
write_verilog top.pdk.v
write_blif top.pdk.blif
write_edif top.pdk.edif
show -format png -prefix top.pdk.yosys
stat
As always, looking at the stats:
1. Printing statistics.
=== top ===
Number of wires: 225
Number of wire bits: 283
Number of public wires: 11
Number of public wire bits: 33
Number of ports: 4
Number of port bits: 7
Number of memories: 0
Number of memory bits: 0
Number of processes: 0
Number of cells: 77
AND2_X1 3
AND4_X1 1
AOI21_X1 6
AOI221_X1 2
AOI222_X1 2
AOI22_X1 4
DFFR_X1 23
INV_X1 7
MUX2_X1 1
NAND2_X1 4
NAND3_X1 3
NAND4_X1 2
NOR2_X1 5
OR2_X1 1
XNOR2_X1 9
XOR2_X1 4
Bonus: Build on Save Link to heading
I am using the Build on Save
VS Code extension to call make every time I save the file. This is a sample of .vscode/settings.json
:
{
"emeraldwalk.runonsave": {
"commands": [
{
"match": "top.v",
"cmd": "make"
}
]
}
}
Bonus: OpenSTA Link to heading
Another nice thing to see from the RTL is running OpenSTA
to get an indication about negative slack or timing checks. We need to create a simple SDC named constraints.sdc
.
# Define the clock
create_clock -name CLK -period 10 [get_ports clk]
And adding the command to the all
target in the Makefile
:
sta run_sta.tcl
read_verilog top.synth.v
read_liberty NangateOpenCellLibrary_typical.lib
link_design top
read_sdc constraints.sdc
report_checks
report_tns
report_wns
report_checks -path_delay min -format full > sta.setup_report.rpt
report_checks -path_delay max -format full > sta.hold_report.rpt
Adding the command to the Makefile, it will make STA run every time the file is saved.
Delay Time Description
---------------------------------------------------------
0.00 0.00 clock CLK (rise edge)
0.00 0.00 clock network delay (ideal)
0.00 0.00 ^ _1247_/CK (DFFR_X1)
0.11 0.11 ^ _1247_/Q (DFFR_X1)
0.06 0.17 ^ _0914_/Z (XOR2_X1)
0.03 0.20 v _0915_/ZN (XNOR2_X1)
0.06 0.26 v _0917_/Z (XOR2_X1)
0.06 0.32 v _0918_/Z (XOR2_X1)
0.06 0.38 ^ _0921_/ZN (NOR3_X1)
0.03 0.41 v _0926_/ZN (OAI21_X1)
0.06 0.47 ^ _0966_/ZN (AOI211_X1)
0.04 0.51 v _0971_/ZN (OAI33_X1)
0.05 0.56 ^ _0984_/ZN (AOI21_X1)
0.03 0.59 v _0999_/ZN (OAI21_X1)
0.04 0.63 ^ _1013_/ZN (AOI21_X1)
0.03 0.66 v _1030_/ZN (OAI21_X1)
0.05 0.71 ^ _1043_/ZN (AOI21_X1)
0.03 0.75 v _1084_/ZN (OAI211_X1)
0.05 0.79 v _1085_/ZN (AND3_X1)
0.10 0.89 ^ _1121_/ZN (OAI33_X1)
0.03 0.93 v _1124_/ZN (OAI21_X1)
0.04 0.97 v _1130_/ZN (XNOR2_X1)
0.06 1.03 v _1131_/Z (MUX2_X1)
0.00 1.03 v _1224_/D (DFFR_X1)
1.03 data arrival time
1.00 1.00 clock CLK (rise edge)
0.00 1.00 clock network delay (ideal)
0.00 1.00 clock reconvergence pessimism
1.00 ^ _1224_/CK (DFFR_X1)
-0.04 0.96 library setup time
0.96 data required time
---------------------------------------------------------
0.96 data required time
-1.03 data arrival time
---------------------------------------------------------
-0.07 slack (VIOLATED)
tns max -0.15
wns max -0.07