Yosys Manual
Clifford Wolf
Abstract
Most of today’s digital design is done in HDL code (mostly Verilog or VHDL) and with the help of HDL
synthesis tools.
In special cases such as synthesis for coarse-grain cell libraries or when testing new synthesis algorithms
it might be necessary to write a custom HDL synthesis tool or add new features to an existing one. It
this cases the availability of a Free and Open Source (FOSS) synthesis tool that can be used as basis for
custom tools would be helpful.
In the absence of such a tool, the Yosys Open SYnthesis Suite (Yosys) was developed. This document
covers the design and implementation of this tool. At the moment the main focus of Yosys lies on the
high-level aspects of digital synthesis. The pre-existing FOSS logic-synthesis tool ABC is used by Yosys
to perform advanced gate-level optimizations.
An evaluation of Yosys based on real-world designs is included. It is shown that Yosys can be used as-is
to synthesize such designs. The results produced by Yosys in this tests where successfully verified using
formal verification and are comparable in quality to the results produced by a commercial synthesis tool.
This document was originally published as bachelor thesis at the Vienna University of Technology [Wol13].
2
Abbreviations
AIG
ASIC
AST
BDD
BLIF
EDA
EDIF
ER Diagram
FOSS
FPGA
FSM
HDL
LPM
RTLIL
RTL
SAT
VHDL
VHSIC
YOSYS
And-Inverter-Graph
Application-Specific Integrated Circuit
Abstract Syntax Tree
Binary Decision Diagram
Berkeley Logic Interchange Format
Electronic Design Automation
Electronic Design Interchange Format
Entity-Relationship Diagram
Free and Open-Source Software
Field-Programmable Gate Array
Finite-state machine
Hardware Description Language
Library of Parameterized Modules
RTL Intermediate Language
Register Transfer Level
Satisfiability Problem
VHSIC Hardware Description Language
Very-High-Speed Integrated Circuit
Yosys Open SYnthesis Suite
3
Contents
1 Introduction
12
1.1
History of Yosys . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12
1.2
Structure of this Document . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
13
2 Basic Principles
2.1
14
Levels of Abstraction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14
2.1.1
System Level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
2.1.2
High Level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
2.1.3
Behavioural Level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
2.1.4
Register-Transfer Level (RTL) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16
2.1.5
Logical Gate Level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16
2.1.6
Physical Gate Level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
17
2.1.7
Switch Level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
17
2.1.8
Yosys . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
17
Features of Synthesizable Verilog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
17
2.2.1
Structural Verilog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
18
2.2.2
Expressions in Verilog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
18
2.2.3
Behavioural Modelling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
18
2.2.4
Functions and Tasks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
19
2.2.5
Conditionals, Loops and Generate-Statements . . . . . . . . . . . . . . . . . . . . . .
19
2.2.6
Arrays and Memories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
20
Challenges in Digital Circuit Synthesis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
20
2.3.1
Standards Compliance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
20
2.3.2
Optimizations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
21
2.3.3
Technology Mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
21
2.4
Script-Based Synthesis Flows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
21
2.5
Methods from Compiler Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
22
2.5.1
Lexing and Parsing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
22
2.5.2
Multi-Pass Compilation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
24
2.2
2.3
4
CONTENTS
3 Approach
25
3.1
Data- and Control-Flow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
25
3.2
Internal Formats in Yosys . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
26
3.3
Typical Use Case . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
26
4 Implementation Overview
28
4.1
Simplified Data Flow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
28
4.2
The RTL Intermediate Language . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
29
4.2.1
RTLIL Identifiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
30
4.2.2
RTLIL::Design and RTLIL::Module
. . . . . . . . . . . . . . . . . . . . . . . . . . .
31
4.2.3
RTLIL::Cell and RTLIL::Wire
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
31
4.2.4
RTLIL::SigSpec . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
32
4.2.5
RTLIL::Process . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
32
4.2.6
RTLIL::Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
34
4.3
Command Interface and Synthesis Scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . .
35
4.4
Source Tree and Build System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
35
5 Internal Cell Library
5.1
5.2
37
RTL Cells . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
37
5.1.1
Unary Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
37
5.1.2
Binary Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
38
5.1.3
Multiplexers
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
38
5.1.4
Registers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
39
5.1.5
Memories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
39
5.1.6
Finite State Machines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
42
Gates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
42
6 Programming Yosys Extensions
44
6.1
The “CodingReadme” File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
44
6.2
The “stubsnets” Example Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
49
5
CONTENTS
7 The Verilog and AST Frontends
7.1
52
Transforming Verilog to AST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
52
7.1.1
The Verilog Preprocessor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
53
7.1.2
The Verilog Lexer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
53
7.1.3
The Verilog Parser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
53
Transforming AST to RTLIL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
54
7.2.1
AST Simplification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
54
7.2.2
Generating RTLIL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
56
Synthesizing Verilog always Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
56
7.3.1
The ProcessGenerator Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
58
7.3.2
The proc pass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
61
7.4
Synthesizing Verilog Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
61
7.5
Synthesizing Parametric Designs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
61
7.2
7.3
8 Optimizations
8.1
8.2
8.3
Simple Optimizations
62
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
62
8.1.1
The opt_expr pass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
62
8.1.2
The opt_muxtree pass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
63
8.1.3
The opt_reduce pass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
63
8.1.4
The opt_rmdff pass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
64
8.1.5
The opt_clean pass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
64
8.1.6
The opt_merge pass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
64
FSM Extraction and Encoding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
64
8.2.1
FSM Detection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
65
8.2.2
FSM Extraction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
65
8.2.3
FSM Optimization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
66
8.2.4
FSM Recoding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
67
Logic Optimization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
67
9 Technology Mapping
68
9.1
Cell Substitution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
68
9.2
Subcircuit Substitution
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
68
9.3
Gate-Level Technology Mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
69
A Auxiliary Libraries
70
A.1 SHA1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
70
A.2 BigInt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
70
A.3 SubCircuit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
70
A.4 ezSAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
70
6
CONTENTS
B Auxiliary Programs
71
B.1 yosys-config . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
71
B.2 yosys-filterlib . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
71
B.3 yosys-abc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
71
C Command Reference Manual
72
C.1 abc – use ABC for technology mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
72
C.2 add – add objects to the design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
75
C.3 aigmap – map logic to and-inverter-graph circuit . . . . . . . . . . . . . . . . . . . . . . . .
75
C.4 alumacc – extract ALU and MACC cells . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
75
C.5 assertpmux – convert internal signals to module ports . . . . . . . . . . . . . . . . . . . . .
75
C.6 attrmap – renaming attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
76
C.7 attrmvcp – move or copy attributes from wires to driving cells
. . . . . . . . . . . . . . . .
76
C.8 cd – a shortcut for ’select -module ’ . . . . . . . . . . . . . . . . . . . . . . . . . . .
77
C.9 check – check for obvious problems in the design . . . . . . . . . . . . . . . . . . . . . . . .
77
C.10 chparam – re-evaluate modules with new parameters . . . . . . . . . . . . . . . . . . . . . .
78
C.11 clean – remove unused cells and wires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
78
C.12 clk2fflogic – convert clocked FFs to generic $ff cells . . . . . . . . . . . . . . . . . . . . . . .
78
C.13 connect – create or remove connections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
78
C.14 connwrappers – replace undef values with defined constants . . . . . . . . . . . . . . . . . .
79
C.15 copy – copy modules in the design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
79
C.16 cover – print code coverage counters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
79
C.17 delete – delete objects in the design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
80
C.18 deminout – demote inout ports to input or output . . . . . . . . . . . . . . . . . . . . . . .
81
C.19 design – save, restore and reset current design . . . . . . . . . . . . . . . . . . . . . . . . . .
81
C.20 dff2dffe – transform $dff cells to $dffe cells . . . . . . . . . . . . . . . . . . . . . . . . . . . .
81
C.21 dffinit – set INIT param on FF cells . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
82
C.22 dfflibmap – technology mapping of flip-flops . . . . . . . . . . . . . . . . . . . . . . . . . . .
82
C.23 dffsr2dff – convert DFFSR cells to simpler FF cell types . . . . . . . . . . . . . . . . . . . .
83
C.24 dump – print parts of the design in ilang format . . . . . . . . . . . . . . . . . . . . . . . .
83
C.25 echo – turning echoing back of commands on and off . . . . . . . . . . . . . . . . . . . . . .
83
C.26 edgetypes – list all types of edges in selection . . . . . . . . . . . . . . . . . . . . . . . . . .
83
C.27 equiv_add – add a $equiv cell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
84
C.28 equiv_induct – proving $equiv cells using temporal induction . . . . . . . . . . . . . . . . .
84
C.29 equiv_make – prepare a circuit for equivalence checking . . . . . . . . . . . . . . . . . . . .
84
C.30 equiv_mark – mark equivalence checking regions . . . . . . . . . . . . . . . . . . . . . . . .
85
C.31 equiv_miter – extract miter from equiv circuit . . . . . . . . . . . . . . . . . . . . . . . . .
85
7
CONTENTS
C.32 equiv_purge – purge equivalence checking module . . . . . . . . . . . . . . . . . . . . . . .
85
C.33 equiv_remove – remove $equiv cells . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
86
C.34 equiv_simple – try proving simple $equiv instances . . . . . . . . . . . . . . . . . . . . . . .
86
C.35 equiv_status – print status of equivalent checking module . . . . . . . . . . . . . . . . . . .
86
C.36 equiv_struct – structural equivalence checking . . . . . . . . . . . . . . . . . . . . . . . . .
86
C.37 eval – evaluate the circuit given an input . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
87
C.38 expose – convert internal signals to module ports . . . . . . . . . . . . . . . . . . . . . . . .
87
C.39 extract – find subcircuits and replace them with cells . . . . . . . . . . . . . . . . . . . . . .
88
C.40 flatten – flatten design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
90
C.41 freduce – perform functional reduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
90
C.42 fsm – extract and optimize finite state machines
. . . . . . . . . . . . . . . . . . . . . . . .
90
C.43 fsm_detect – finding FSMs in design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
91
C.44 fsm_expand – expand FSM cells by merging logic into it . . . . . . . . . . . . . . . . . . . .
91
C.45 fsm_export – exporting FSMs to KISS2 files . . . . . . . . . . . . . . . . . . . . . . . . . .
92
C.46 fsm_extract – extracting FSMs in design . . . . . . . . . . . . . . . . . . . . . . . . . . . .
92
C.47 fsm_info – print information on finite state machines . . . . . . . . . . . . . . . . . . . . . .
92
C.48 fsm_map – mapping FSMs to basic logic . . . . . . . . . . . . . . . . . . . . . . . . . . . .
93
C.49 fsm_opt – optimize finite state machines . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
93
C.50 fsm_recode – recoding finite state machines . . . . . . . . . . . . . . . . . . . . . . . . . . .
93
C.51 greenpak4_counters – Extract GreenPak4 counter cells . . . . . . . . . . . . . . . . . . . . .
93
C.52 greenpak4_dffinv – merge greenpak4 inverters and DFFs . . . . . . . . . . . . . . . . . . . .
94
C.53 help – display help messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
94
C.54 hierarchy – check, expand and clean up design hierarchy . . . . . . . . . . . . . . . . . . . .
94
C.55 hilomap – technology mapping of constant hi- and/or lo-drivers . . . . . . . . . . . . . . . .
95
C.56 history – show last interactive commands . . . . . . . . . . . . . . . . . . . . . . . . . . . .
95
C.57 ice40_ffinit – iCE40: handle FF init values . . . . . . . . . . . . . . . . . . . . . . . . . . .
96
C.58 ice40_ffssr – iCE40: merge synchronous set/reset into FF cells . . . . . . . . . . . . . . . .
96
C.59 ice40_opt – iCE40: perform simple optimizations . . . . . . . . . . . . . . . . . . . . . . . .
96
C.60 insbuf – insert buffer cells for connected wires . . . . . . . . . . . . . . . . . . . . . . . . . .
96
C.61 iopadmap – technology mapping of i/o pads (or buffers) . . . . . . . . . . . . . . . . . . . .
97
C.62 json – write design in JSON format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
97
C.63 log – print text and log files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
98
C.64 ls – list modules or objects in modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
98
C.65 lut2mux – convert $lut to $_MUX_ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
98
C.66 maccmap – mapping macc cells . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
98
C.67 memory – translate memories to basic cells . . . . . . . . . . . . . . . . . . . . . . . . . . .
99
8
CONTENTS
C.68 memory_bram – map memories to block rams . . . . . . . . . . . . . . . . . . . . . . . . .
99
C.69 memory_collect – creating multi-port memory cells . . . . . . . . . . . . . . . . . . . . . . . 101
C.70 memory_dff – merge input/output DFFs into memories . . . . . . . . . . . . . . . . . . . . 101
C.71 memory_map – translate multiport memories to basic cells . . . . . . . . . . . . . . . . . . 101
C.72 memory_memx – emulate vlog sim behavior for mem ports . . . . . . . . . . . . . . . . . . 101
C.73 memory_share – consolidate memory ports . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
C.74 memory_unpack – unpack multi-port memory cells . . . . . . . . . . . . . . . . . . . . . . . 102
C.75 miter – automatically create a miter circuit . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
C.76 muxcover – cover trees of MUX cells with wider MUXes . . . . . . . . . . . . . . . . . . . . 103
C.77 nlutmap – map to LUTs of different sizes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
C.78 opt – perform simple optimizations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
C.79 opt_clean – remove unused cells and wires . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
C.80 opt_expr – perform const folding and simple expression rewriting . . . . . . . . . . . . . . . 104
C.81 opt_merge – consolidate identical cells . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
C.82 opt_muxtree – eliminate dead trees in multiplexer trees . . . . . . . . . . . . . . . . . . . . 105
C.83 opt_reduce – simplify large MUXes and AND/OR gates . . . . . . . . . . . . . . . . . . . . 105
C.84 opt_rmdff – remove DFFs with constant inputs . . . . . . . . . . . . . . . . . . . . . . . . . 106
C.85 plugin – load and list loaded plugins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
C.86 pmuxtree – transform $pmux cells to trees of $mux cells . . . . . . . . . . . . . . . . . . . . 106
C.87 prep – generic synthesis script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
C.88 proc – translate processes to netlists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
C.89 proc_arst – detect asynchronous resets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
C.90 proc_clean – remove empty parts of processes . . . . . . . . . . . . . . . . . . . . . . . . . . 109
C.91 proc_dff – extract flip-flops from processes . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
C.92 proc_dlatch – extract latches from processes . . . . . . . . . . . . . . . . . . . . . . . . . . 109
C.93 proc_init – convert initial block to init attributes . . . . . . . . . . . . . . . . . . . . . . . . 109
C.94 proc_mux – convert decision trees to multiplexers . . . . . . . . . . . . . . . . . . . . . . . 109
C.95 proc_rmdead – eliminate dead trees in decision trees . . . . . . . . . . . . . . . . . . . . . . 110
C.96 qwp – quadratic wirelength placer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
C.97 read_blif – read BLIF file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
C.98 read_ilang – read modules from ilang file . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
C.99 read_liberty – read cells from liberty file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
C.100read_verilog – read modules from Verilog file . . . . . . . . . . . . . . . . . . . . . . . . . . 111
C.101rename – rename object in the design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
C.102sat – solve a SAT problem in the circuit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
C.103scatter – add additional intermediate nets . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
9
CONTENTS
C.104scc – detect strongly connected components (logic loops) . . . . . . . . . . . . . . . . . . . . 117
C.105script – execute commands from script file . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
C.106select – modify and view the list of selected objects . . . . . . . . . . . . . . . . . . . . . . . 118
C.107setattr – set/unset attributes on objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
C.108setparam – set/unset parameters on objects . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
C.109setundef – replace undef values with defined constants . . . . . . . . . . . . . . . . . . . . . 122
C.110share – perform sat-based resource sharing . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
C.111shell – enter interactive command mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
C.112show – generate schematics using graphviz . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
C.113shregmap – map shift registers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
C.114simplemap – mapping simple coarse-grain cells . . . . . . . . . . . . . . . . . . . . . . . . . 127
C.115singleton – create singleton modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
C.116splice – create explicit splicing cells . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
C.117splitnets – split up multi-bit nets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
C.118stat – print some statistics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
C.119submod – moving part of a module to a new submodule . . . . . . . . . . . . . . . . . . . . 129
C.120synth – generic synthesis script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
C.121synth_gowin – synthesis for Gowin FPGAs . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
C.122synth_greenpak4 – synthesis for GreenPAK4 FPGAs . . . . . . . . . . . . . . . . . . . . . . 132
C.123synth_ice40 – synthesis for iCE40 FPGAs . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
C.124synth_xilinx – synthesis for Xilinx FPGAs . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
C.125tcl – execute a TCL script file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
C.126techmap – generic technology mapper . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
C.127tee – redirect command output to file
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
C.128test_abcloop – automatically test handling of loops in abc command . . . . . . . . . . . . . 140
C.129test_autotb – generate simple test benches . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
C.130test_cell – automatically test the implementation of a cell type . . . . . . . . . . . . . . . . 141
C.131torder – print cells in topological order . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
C.132trace – redirect command output to file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
C.133tribuf – infer tri-state buffers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
C.134verific – load Verilog and VHDL designs using Verific . . . . . . . . . . . . . . . . . . . . . . 142
C.135verilog_defaults – set default options for read_verilog . . . . . . . . . . . . . . . . . . . . . 143
C.136vhdl2verilog – importing VHDL designs using vhdl2verilog . . . . . . . . . . . . . . . . . . . 143
C.137wreduce – reduce the word size of operations if possible . . . . . . . . . . . . . . . . . . . . 144
C.138write_blif – write design to BLIF file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
C.139write_btor – write design to BTOR file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
10
CONTENTS
C.140write_edif – write design to EDIF netlist file . . . . . . . . . . . . . . . . . . . . . . . . . . 146
C.141write_file – write a text to a file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
C.142write_ilang – write design to ilang file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
C.143write_intersynth – write design to InterSynth netlist file . . . . . . . . . . . . . . . . . . . . 146
C.144write_json – write design to a JSON file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
C.145write_smt2 – write design to SMT-LIBv2 file . . . . . . . . . . . . . . . . . . . . . . . . . . 151
C.146write_smv – write design to SMV file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
C.147write_spice – write design to SPICE netlist file . . . . . . . . . . . . . . . . . . . . . . . . . 153
C.148write_verilog – write design to Verilog file . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
C.149zinit – add inverters so all FF are zero-initialized . . . . . . . . . . . . . . . . . . . . . . . . 155
D Application Notes
156
11
Chapter 1
Introduction
This document presents the Free and Open Source (FOSS) Verilog HDL synthesis tool “Yosys”. Its design
and implementation as well as its performance on real-world designs is discussed in this document.
1.1
History of Yosys
A Hardware Description Language (HDL) is a computer language used to describe circuits. A HDL
synthesis tool is a computer program that takes a formal description of a circuit written in an HDL as
input and generates a netlist that implements the given circuit as output.
Currently the most widely used and supported HDLs for digital circuits are Verilog [Ver06][Ver02] and
VHDL1 [VHD09][VHD04]. Both HDLs are used for test and verification purposes as well as logic synthesis,
resulting in a set of synthesizable and a set of non-synthesizable language features. In this document we
only look at the synthesizable subset of the language features.
In recent work on heterogeneous coarse-grain reconfigurable logic [WGS+ 12] the need for a custom applicationspecific HDL synthesis tool emerged. It was soon realised that a synthesis tool that understood Verilog
or VHDL would be preferred over a synthesis tool for a custom HDL. Given an existing Verilog or VHDL
front end, the work for writing the necessary additional features and integrating them in an existing tool
can be estimated to be about the same as writing a new tool with support for a minimalistic custom HDL.
The proposed custom HDL synthesis tool should be licensed under a Free and Open Source Software
(FOSS) licence. So an existing FOSS Verilog or VHDL synthesis tool would have been needed as basis
to build upon. The main advantages of choosing Verilog or VHDL is the ability to synthesize existing
HDL code and to mitigate the requirement for circuit-designers to learn a new language. In order to
take full advantage of any existing FOSS Verilog or VHDL tool, such a tool would have to provide a
feature-complete implementation of the synthesizable HDL subset.
Basic RTL synthesis is a well understood field [HS96]. Lexing, parsing and processing of computer languages [ASU86] is a thoroughly researched field. All the information required to write such tools has
been openly available for a long time, and it is therefore likely that a FOSS HDL synthesis tool with a
feature-complete Verilog or VHDL front end must exist which can be used as a basis for a custom RTL
synthesis tool.
Due to the author’s preference for Verilog over VHDL it was decided early on to go for Verilog instead of
VHDL2 . So the existing FOSS Verilog synthesis tools were evaluated (see App. ??). The results of this
evaluation are utterly devastating. Therefore a completely new Verilog synthesis tool was implemented
and is recommended as basis for custom synthesis tools. This is the tool that is discussed in this document.
1 VHDL is an acronym for “VHSIC hardware description language” and VHSIC is an acronym for “Very-High-Speed
Integrated Circuits”.
2 A quick investigation into FOSS VHDL tools yielded similar grim results for FOSS VHDL synthesis tools.
12
CHAPTER 1. INTRODUCTION
1.2
Structure of this Document
The structure of this document is as follows:
Chapter 1 is this introduction.
Chapter 2 covers a short introduction to the world of HDL synthesis. Basic principles and the terminology
are outlined in this chapter.
Chapter 3 gives the quickest possible outline to how the problem of implementing a HDL synthesis tool is
approached in the case of Yosys.
Chapter 4 contains a more detailed overview of the implementation of Yosys. This chapter covers the data
structures used in Yosys to represent a design in detail and is therefore recommended reading for everyone
who is interested in understanding the Yosys internals.
Chapter 5 covers the internal cell library used by Yosys. This is especially important knowledge for anyone
who wants to understand the intermediate netlists used internally by Yosys.
Chapter 6 gives a tour to the internal APIs of Yosys. This is recommended reading for everyone who
actually wants to read or write Yosys source code. The chapter concludes with an example loadable module
for Yosys.
Chapters 7, 8, and 9 cover three important pieces of the synthesis pipeline: The Verilog frontend, the
optimization passes and the technology mapping to the target architecture, respectively.
Chapter ?? covers the evaluation of the performance (correctness and quality) of Yosys on real-world input
data. The chapter concludes the main part of this document with conclusions and outlook to future work.
Various appendices, including a command reference manual (App. C) and an evaluation of pre-existing
FOSS Verilog synthesis tools (App. ??) complete this document.
13
Chapter 2
Basic Principles
This chapter contains a short introduction to the basic principles of digital circuit synthesis.
2.1
Levels of Abstraction
Digital circuits can be represented at different levels of abstraction. During the design process a circuit is
usually first specified using a higher level abstraction. Implementation can then be understood as finding a
functionally equivalent representation at a lower abstraction level. When this is done automatically using
software, the term synthesis is used.
So synthesis is the automatic conversion of a high-level representation of a circuit to a functionally equivalent low-level representation of a circuit. Figure 2.1 lists the different levels of abstraction and how they
relate to different kinds of synthesis.
Regardless of the way a lower level representation of a circuit is obtained (synthesis or manual design),
the lower level representation is usually verified by comparing simulation results of the lower level and
the higher level representation 1 . Therefore even if no synthesis is used, there must still be a simulatable
representation of the circuit in all levels to allow for verification of the design.
1 In recent years formal equivalence checking also became an important verification method for validating RTL and lower
abstraction representation of the design.
System Level
System Design
High Level
High Level Synthesis (HLS)
Behavioral Level
Behavioral Synthesis
Register-Transfer Level (RTL)
RTL Synthesis
Logical Gate Level
Logic Synthesis
Physical Gate Level
Cell Library
Switch Level
Figure 2.1: Different levels of abstraction and synthesis.
14
Yosys
CHAPTER 2. BASIC PRINCIPLES
Note: The exact meaning of terminology such as “High-Level” is of course not fixed over time. For example
the HDL “ABEL” was first introduced in 1985 as “A High-Level Design Language for Programmable Logic
Devices” [LHBB85], but would not be considered a “High-Level Language” today.
2.1.1
System Level
The System Level abstraction of a system only looks at its biggest building blocks like CPUs and computing
cores. At this level the circuit is usually described using traditional programming languages like C/C++ or
Matlab. Sometimes special software libraries are used that are aimed at simulation circuits on the system
level, such as SystemC.
Usually no synthesis tools are used to automatically transform a system level representation of a circuit to
a lower-level representation. But system level design tools exist that can be used to connect system level
building blocks.
The IEEE 1685-2009 standard defines the IP-XACT file format that can be used to represent designs on
the system level and building blocks that can be used in such system level designs. [IP-10]
2.1.2
High Level
The high-level abstraction of a system (sometimes referred to as algorithmic level) is also often represented
using traditional programming languages, but with a reduced feature set. For example when representing
a design at the high level abstraction in C, pointers can only be used to mimic concepts that can be found
in hardware, such as memory interfaces. Full featured dynamic memory management is not allowed as it
has no corresponding concept in digital circuits.
Tools exist to synthesize high level code (usually in the form of C/C++/SystemC code with additional
metadata) to behavioural HDL code (usually in the form of Verilog or VHDL code). Aside from the many
commercial tools for high level synthesis there are also a number of FOSS tools for high level synthesis
[16] [19].
2.1.3
Behavioural Level
At the behavioural abstraction level a language aimed at hardware description such as Verilog or VHDL
is used to describe the circuit, but so-called behavioural modelling is used in at least part of the circuit
description. In behavioural modelling there must be a language feature that allows for imperative programming to be used to describe data paths and registers. This is the always-block in Verilog and the
process-block in VHDL.
In behavioural modelling, code fragments are provided together with a sensitivity list; a list of signals and
conditions. In simulation, the code fragment is executed whenever a signal in the sensitivity list changes
its value or a condition in the sensitivity list is triggered. A synthesis tool must be able to transfer this
representation into an appropriate datapath followed by the appropriate types of register.
For example consider the following Verilog code fragment:
1
2
always @(posedge clk)
y <= a + b;
In simulation the statement y <= a + b is executed whenever a positive edge on the signal clk is detected.
The synthesis result however will contain an adder that calculates the sum a + b all the time, followed by
a d-type flip-flop with the adder output on its D-input and the signal y on its Q-output.
15
CHAPTER 2. BASIC PRINCIPLES
Usually the imperative code fragments used in behavioural modelling can contain statements for conditional
execution (if- and case-statements in Verilog) as well as loops, as long as those loops can be completely
unrolled.
Interestingly there seems to be no other FOSS Tool that is capable of performing Verilog or VHDL
behavioural syntheses besides Yosys (see App. ??).
2.1.4
Register-Transfer Level (RTL)
On the Register-Transfer Level the design is represented by combinatorial data paths and registers (usually
d-type flip flops). The following Verilog code fragment is equivalent to the previous Verilog example, but
is in RTL representation:
1
2
3
4
assign tmp = a + b;
// combinatorial data path
always @(posedge clk)
// register
y <= tmp;
A design in RTL representation is usually stored using HDLs like Verilog and VHDL. But only a very
limited subset of features is used, namely minimalistic always-blocks (Verilog) or process-blocks (VHDL)
that model the register type used and unconditional assignments for the datapath logic. The use of
HDLs on this level simplifies simulation as no additional tools are required to simulate a design in RTL
representation.
Many optimizations and analyses can be performed best at the RTL level. Examples include FSM detection
and optimization, identification of memories or other larger building blocks and identification of shareable
resources.
Note that RTL is the first abstraction level in which the circuit is represented as a graph of circuit elements
(registers and combinatorial cells) and signals. Such a graph, when encoded as list of cells and connections,
is called a netlist.
RTL synthesis is easy as each circuit node element in the netlist can simply be replaced with an equivalent
gate-level circuit. However, usually the term RTL synthesis does not only refer to synthesizing an RTL
netlist to a gate level netlist but also to performing a number of highly sophisticated optimizations within
the RTL representation, such as the examples listed above.
A number of FOSS tools exist that can perform isolated tasks within the domain of RTL synthesis steps.
But there seems to be no FOSS tool that covers a wide range of RTL synthesis operations.
2.1.5
Logical Gate Level
At the logical gate level the design is represented by a netlist that uses only cells from a small number
of single-bit cells, such as basic logic gates (AND, OR, NOT, XOR, etc.) and registers (usually D-Type
Flip-flops).
A number of netlist formats exists that can be used on this level, e.g. the Electronic Design Interchange
Format (EDIF), but for ease of simulation often a HDL netlist is used. The latter is a HDL file (Verilog
or VHDL) that only uses the most basic language constructs for instantiation and connecting of cells.
There are two challenges in logic synthesis: First finding opportunities for optimizations within the gate
level netlist and second the optimal (or at least good) mapping of the logic gate netlist to an equivalent
netlist of physically available gate types.
The simplest approach to logic synthesis is two-level logic synthesis, where a logic function is converted
into a sum-of-products representation, e.g. using a Karnaugh map. This is a simple approach, but has
16
CHAPTER 2. BASIC PRINCIPLES
exponential worst-case effort and cannot make efficient use of physical gates other than AND/NAND-,
OR/NOR- and NOT-Gates.
Therefore modern logic synthesis tools utilize much more complicated multi-level logic synthesis algorithms
[BHSV90]. Most of these algorithms convert the logic function to a Binary-Decision-Diagram (BDD) or
And-Inverter-Graph (AIG) and work from that representation. The former has the advantage that it has a
unique normalized form. The latter has much better worst case performance and is therefore better suited
for the synthesis of large logic functions.
Good FOSS tools exists for multi-level logic synthesis [27] [26] [28].
Yosys contains basic logic synthesis functionality but can also use ABC [27] for the logic synthesis step.
Using ABC is recommended.
2.1.6
Physical Gate Level
On the physical gate level only gates are used that are physically available on the target architecture. In
some cases this may only be NAND, NOR and NOT gates as well as D-Type registers. In other cases
this might include cells that are more complex than the cells used at the logical gate level (e.g. complete
half-adders). In the case of an FPGA-based design the physical gate level representation is a netlist of
LUTs with optional output registers, as these are the basic building blocks of FPGA logic cells.
For the synthesis tool chain this abstraction is usually the lowest level. In case of an ASIC-based design
the cell library might contain further information on how the physical cells map to individual switches
(transistors).
2.1.7
Switch Level
A switch level representation of a circuit is a netlist utilizing single transistors as cells. Switch level
modelling is possible in Verilog and VHDL, but is seldom used in modern designs, as in modern digital
ASIC or FPGA flows the physical gates are considered the atomic build blocks of the logic circuit.
2.1.8
Yosys
Yosys is a Verilog HDL synthesis tool. This means that it takes a behavioural design description as input
and generates an RTL, logical gate or physical gate level description of the design as output. Yosys’ main
strengths are behavioural and RTL synthesis. A wide range of commands (synthesis passes) exist within
Yosys that can be used to perform a wide range of synthesis tasks within the domain of behavioural, rtl
and logic synthesis. Yosys is designed to be extensible and therefore is a good basis for implementing
custom synthesis tools for specialised tasks.
2.2
Features of Synthesizable Verilog
The subset of Verilog [Ver06] that is synthesizable is specified in a separate IEEE standards document,
the IEEE standard 1364.1-2002 [Ver02]. This standard also describes how certain language constructs are
to be interpreted in the scope of synthesis.
This section provides a quick overview of the most important features of synthesizable Verilog, structured
in order of increasing complexity.
17
CHAPTER 2. BASIC PRINCIPLES
2.2.1
Structural Verilog
Structural Verilog (also known as Verilog Netlists) is a Netlist in Verilog syntax. Only the following
language constructs are used in this case:
• Constant values
• Wire and port declarations
• Static assignments of signals to other signals
• Cell instantiations
Many tools (especially at the back end of the synthesis chain) only support structural Verilog as input.
ABC is an example of such a tool. Unfortunately there is no standard specifying what Structural Verilog
actually is, leading to some confusion about what syntax constructs are supported in structural Verilog
when it comes to features such as attributes or multi-bit signals.
2.2.2
Expressions in Verilog
In all situations where Verilog accepts a constant value or signal name, expressions using arithmetic
operations such as +, - and *, boolean operations such as & (AND), | (OR) and ^ (XOR) and many others
(comparison operations, unary operator, etc.) can also be used.
During synthesis these operators are replaced by cells that implement the respective function.
Many FOSS tools that claim to be able to process Verilog in fact only support basic structural Verilog and
simple expressions. Yosys can be used to convert full featured synthesizable Verilog to this simpler subset,
thus enabling such applications to be used with a richer set of Verilog features.
2.2.3
Behavioural Modelling
Code that utilizes the Verilog always statement is using Behavioural Modelling. In behavioural modelling,
a circuit is described by means of imperative program code that is executed on certain events, namely any
change, a rising edge, or a falling edge of a signal. This is a very flexible construct during simulation but
is only synthesizable when one of the following is modelled:
• Asynchronous or latched logic
In this case the sensitivity list must contain all expressions that are used within the always block.
The syntax @* can be used for these cases. Examples of this kind include:
1
2
3
4
5
6
7
8
9
10
11
12
13
// asynchronous
always @* begin
if (add_mode)
y <= a + b;
else
y <= a - b;
end
// latched
always @* begin
if (!hold)
y <= a + b;
end
18
CHAPTER 2. BASIC PRINCIPLES
Note that latched logic is often considered bad style and in many cases just the result of sloppy HDL
design. Therefore many synthesis tools generate warnings whenever latched logic is generated.
• Synchronous logic (with optional synchronous reset)
This is logic with d-type flip-flops on the output. In this case the sensitivity list must only contain
the respective clock edge. Example:
1
2
3
4
5
6
7
// counter with synchronous reset
always @(posedge clk) begin
if (reset)
y <= 0;
else
y <= y + 1;
end
• Synchronous logic with asynchronous reset
This is logic with d-type flip-flops with asynchronous resets on the output. In this case the sensitivity
list must only contain the respective clock and reset edges. The values assigned in the reset branch
must be constant. Example:
1
2
3
4
5
6
7
// counter with asynchronous reset
always @(posedge clk, posedge reset) begin
if (reset)
y <= 0;
else
y <= y + 1;
end
Many synthesis tools support a wider subset of flip-flops that can be modelled using always-statements
(including Yosys). But only the ones listed above are covered by the Verilog synthesis standard and when
writing new designs one should limit herself or himself to these cases.
In behavioural modelling, blocking assignments (=) and non-blocking assignments (<=) can be used. The
concept of blocking vs. non-blocking assignment is one of the most misunderstood constructs in Verilog
[CI00].
The blocking assignment behaves exactly like an assignment in any imperative programming language,
while with the non-blocking assignment the right hand side of the assignment is evaluated immediately
but the actual update of the left hand side register is delayed until the end of the time-step. For example
the Verilog code a <= b; b <= a; exchanges the values of the two registers. See Sec. ?? for a more detailed
description of this behaviour.
2.2.4
Functions and Tasks
Verilog supports Functions and Tasks to bundle statements that are used in multiple places (similar to
Procedures in imperative programming). Both constructs can be implemented easily by substituting the
function/task-call with the body of the function or task.
2.2.5
Conditionals, Loops and Generate-Statements
Verilog supports if-else-statements and for-loops inside always-statements.
It also supports both features in generate-statements on the module level. This can be used to selectively
enable or disable parts of the module based on the module parameters (if-else) or to generate a set of
similar subcircuits (for).
19
CHAPTER 2. BASIC PRINCIPLES
While the if-else-statement inside an always-block is part of behavioural modelling, the three other cases
are (at least for a synthesis tool) part of a built-in macro processor. Therefore it must be possible for
the synthesis tool to completely unroll all loops and evaluate the condition in all if-else-statement in
generate-statements using const-folding.
Examples for this can be found in Fig. ?? and Fig. ?? in App. ??.
2.2.6
Arrays and Memories
Verilog supports arrays. This is in general a synthesizable language feature. In most cases arrays can be
synthesized by generating addressable memories. However, when complex or asynchronous access patterns
are used, it is not possible to model an array as memory. In these cases the array must be modelled using
individual signals for each word and all accesses to the array must be implemented using large multiplexers.
In some cases it would be possible to model an array using memories, but it is not desired. Consider the
following delay circuit:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
module (clk, in_data, out_data);
parameter BITS = 8;
parameter STAGES = 4;
input clk;
input [BITS-1:0] in_data;
output [BITS-1:0] out_data;
reg [BITS-1:0] ffs [STAGES-1:0];
integer i;
always @(posedge clk) begin
ffs[0] <= in_data;
for (i = 1; i < STAGES; i = i+1)
ffs[i] <= ffs[i-1];
end
assign out_data = ffs[STAGES-1];
endmodule
This could be implemented using an addressable memory with STAGES input and output ports. A better
implementation would be to use a simple chain of flip-flops (a so-called shift register). This better implementation can either be obtained by first creating a memory-based implementation and then optimizing
it based on the static address signals for all ports or directly identifying such situations in the language
front end and converting all memory accesses to direct accesses to the correct signals.
2.3
Challenges in Digital Circuit Synthesis
This section summarizes the most important challenges in digital circuit synthesis. Tools can be characterized by how well they address these topics.
2.3.1
Standards Compliance
The most important challenge is compliance with the HDL standards in question (in case of Verilog the
IEEE Standards 1364.1-2002 and 1364-2005). This can be broken down in two items:
20
CHAPTER 2. BASIC PRINCIPLES
• Completeness of implementation of the standard
• Correctness of implementation of the standard
Completeness is mostly important to guarantee compatibility with existing HDL code. Once a design has
been verified and tested, HDL designers are very reluctant regarding changes to the design, even if it is
only about a few minor changes to work around a missing feature in a new synthesis tool.
Correctness is crucial. In some areas this is obvious (such as correct synthesis of basic behavioural models).
But it is also crucial for the areas that concern minor details of the standard, such as the exact rules for
handling signed expressions, even when the HDL code does not target different synthesis tools. This is
because (unlike software source code that is only processed by compilers), in most design flows HDL code
is not only processed by the synthesis tool but also by one or more simulators and sometimes even a formal
verification tool. It is key for this verification process that all these tools use the same interpretation for
the HDL code.
2.3.2
Optimizations
Generally it is hard to give a one-dimensional description of how well a synthesis tool optimizes the design.
First of all because not all optimizations are applicable to all designs and all synthesis tasks. Some
optimizations work (best) on a coarse-grained level (with complex cells such as adders or multipliers) and
others work (best) on a fine-grained level (single bit gates). Some optimizations target area and others
target speed. Some work well on large designs while others don’t scale well and can only be applied to
small designs.
A good tool is capable of applying a wide range of optimizations at different levels of abstraction and gives
the designer control over which optimizations are performed (or skipped) and what the optimization goals
are.
2.3.3
Technology Mapping
Technology mapping is the process of converting the design into a netlist of cells that are available in the
target architecture. In an ASIC flow this might be the process-specific cell library provided by the fab. In
an FPGA flow this might be LUT cells as well as special function units such as dedicated multipliers. In
a coarse-grain flow this might even be more complex special function units.
An open and vendor independent tool is especially of interest if it supports a wide range of different types
of target architectures.
2.4
Script-Based Synthesis Flows
A digital design is usually started by implementing a high-level or system-level simulation of the desired
function. This description is then manually transformed (or re-implemented) into a synthesizable lowerlevel description (usually at the behavioural level) and the equivalence of the two representations is verified
by simulating both and comparing the simulation results.
Then the synthesizable description is transformed to lower-level representations using a series of tools and
the results are again verified using simulation. This process is illustrated in Fig. 2.2.
In this example the System Level Model and the Behavioural Model are both manually written design
files. After the equivalence of system level model and behavioural model has been verified, the lower level
representations of the design can be generated using synthesis tools. Finally the RTL Model and the
Gate-Level Model are verified and the design process is finished.
21
CHAPTER 2. BASIC PRINCIPLES
synthesis
System Level
Model
Behavioral
Model
verify
synthesis
RTL
Model
verify
Gate-Level
Model
verify
Figure 2.2: Typical design flow. Green boxes represent manually created models. Orange boxes represent
models generated by synthesis tools.
However, in any real-world design effort there will be multiple iterations for this design process. The reason
for this can be the late change of a design requirement or the fact that the analysis of a low-abstraction
model (e.g. gate-level timing analysis) revealed that a design change is required in order to meet the design
requirements (e.g. maximum possible clock speed).
Whenever the behavioural model or the system level model is changed their equivalence must be re-verified
by re-running the simulations and comparing the results. Whenever the behavioural model is changed the
synthesis must be re-run and the synthesis results must be re-verified.
In order to guarantee reproducibility it is important to be able to re-run all automatic steps in a design
project with a fixed set of settings easily. Because of this, usually all programs used in a synthesis flow can
be controlled using scripts. This means that all functions are available via text commands. When such a
tool provides a GUI, this is complementary to, and not instead of, a command line interface.
Usually a synthesis flow in an UNIX/Linux environment would be controlled by a shell script that calls all
required tools (synthesis and simulation/verification in this example) in the correct order. Each of these
tools would be called with a script file containing commands for the respective tool. All settings required
for the tool would be provided by these script files so that no manual interaction would be necessary. These
script files are considered design sources and should be kept under version control just like the source code
of the system level and the behavioural model.
2.5
Methods from Compiler Design
Some parts of synthesis tools involve problem domains that are traditionally known from compiler design.
This section addresses some of these domains.
2.5.1
Lexing and Parsing
The best known concepts from compiler design are probably lexing and parsing. These are two methods
that together can be used to process complex computer languages easily. [ASU86]
A lexer consumes single characters from the input and generates a stream of lexical tokens that consist of
a type and a value. For example the Verilog input “assign foo = bar + 42;” might be translated by the
lexer to the list of lexical tokens given in Tab. 2.1.
The lexer is usually generated by a lexer generator (e.g. flex [17]) from a description file that is using
regular expressions to specify the text pattern that should match the individual tokens.
The lexer is also responsible for skipping ignored characters (such as whitespace outside string constants
and comments in the case of Verilog) and converting the original text snippet to a token value.
Note that individual keywords use different token types (instead of a keyword type with different token
values). This is because the parser usually can only use the Token-Type to make a decision on the
grammatical role of a token.
22
CHAPTER 2. BASIC PRINCIPLES
Token-Type
TOK_ASSIGN
TOK_IDENTIFIER
TOK_EQ
TOK_IDENTIFIER
TOK_PLUS
TOK_NUMBER
TOK_SEMICOLON
Token-Value
“foo”
“bar”
42
-
Table 2.1: Exemplary token list for the statement “assign
foo = bar + 42;”.
The parser then transforms the list of tokens into a parse tree that closely resembles the productions from
the computer languages grammar. As the lexer, the parser is also typically generated by a code generator
(e.g. bison [18]) from a grammar description in Backus-Naur Form (BNF).
Let’s consider the following BNF (in Bison syntax):
1
2
assign_stmt: TOK_ASSIGN TOK_IDENTIFIER TOK_EQ expr TOK_SEMICOLON;
expr: TOK_IDENTIFIER | TOK_NUMBER | expr TOK_PLUS expr;
The parser converts the token list to the parse tree in Fig. 2.3. Note that the parse tree never actually exists
as a whole as data structure in memory. Instead the parser calls user-specified code snippets (so-called
reduce-functions) for all inner nodes of the parse tree in depth-first order.
In some very simple applications (e.g. code generation for stack machines) it is possible to perform the
task at hand directly in the reduce functions. But usually the reduce functions are only used to build an
in-memory data structure with the relevant information from the parse tree. This data structure is called
an abstract syntax tree (AST).
The exact format for the abstract syntax tree is application specific (while the format of the parse tree
and token list are mostly dictated by the grammar of the language at hand). Figure 2.4 illustrates what
an AST for the parse tree in Fig. 2.3 could look like.
Usually the AST is then converted into yet another representation that is more suitable for further processing. In compilers this is often an assembler-like three-address-code intermediate representation. [ASU86]
assign_stmt
TOK_EQ
TOK_ASSIGN
TOK_SEMICOLON
expr
TOK_IDENTIFIER
expr
expr
TOK_PLUS
TOK_IDENTIFIER
TOK_NUMBER
Figure 2.3: Example parse tree for the Verilog expression “assign
23
foo = bar + 42;”.
CHAPTER 2. BASIC PRINCIPLES
ASSIGN
PLUS
ID: foo
CONST: 42
ID: bar
Figure 2.4: Example abstract syntax tree for the Verilog expression “assign
2.5.2
foo = bar + 42;”.
Multi-Pass Compilation
Complex problems are often best solved when split up into smaller problems. This is certainly true for
compilers as well as for synthesis tools. The components responsible for solving the smaller problems can
be connected in two different ways: through Single-Pass Pipelining and by using Multiple Passes.
Traditionally a parser and lexer are connected using the pipelined approach: The lexer provides a function
that is called by the parser. This function reads data from the input until a complete lexical token has
been read. Then this token is returned to the parser. So the lexer does not first generate a complete list
of lexical tokens and then pass it to the parser. Instead they run concurrently and the parser can consume
tokens as the lexer produces them.
The single-pass pipelining approach has the advantage of lower memory footprint (at no time must the
complete design be kept in memory) but has the disadvantage of tighter coupling between the interacting
components.
Therefore single-pass pipelining should only be used when the lower memory footprint is required or the
components are also conceptually tightly coupled. The latter certainly is the case for a parser and its
lexer. But when data is passed between two conceptually loosely coupled components it is often beneficial
to use a multi-pass approach.
In the multi-pass approach the first component processes all the data and the result is stored in a inmemory data structure. Then the second component is called with this data. This reduces complexity,
as only one component is running at a time. It also improves flexibility as components can be exchanged
easier.
Most modern compilers are multi-pass compilers.
24
Chapter 3
Approach
Yosys is a tool for synthesising (behavioural) Verilog HDL code to target architecture netlists. Yosys aims
at a wide range of application domains and thus must be flexible and easy to adapt to new tasks. This
chapter covers the general approach followed in the effort to implement this tool.
3.1
Data- and Control-Flow
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 Fig. 3.1).
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.
High-Level
HDL
Backend
Pass
Pass
Pass
Frontend
Low-Level
Internal Format(s)
Figure 3.1: General data- and control-flow of a synthesis tool
25
Netlist
CHAPTER 3. APPROACH
3.2
Internal Formats in Yosys
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 Frontend1 . 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.
3.3
Typical Use Case
The following example script may be used in a synthesis flow to convert the behavioural Verilog code from
the input file design.v to a gate-level netlist synth.v using the cell library described by the Liberty file
[25] cells.lib:
1
2
3
4
5
# read input file to internal representation
read_verilog design.v
# convert high-level behavioral parts ("processes") to d-type flip-flops and muxes
proc
1 In
Yosys the term pass is only used to refer to commands that operate on the RTLIL data structure.
26
CHAPTER 3. APPROACH
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# perform some simple optimizations
opt
# convert high-level memory constructs to d-type flip-flops and multiplexers
memory
# perform some simple optimizations
opt
# convert design to (logical) gate-level netlists
techmap
# perform some simple optimizations
opt
# map internal register types to the ones from the cell library
dfflibmap -liberty cells.lib
# use ABC to map remaining logic to cells from the cell library
abc -liberty cells.lib
# cleanup
opt
# write results to output file
write_verilog synth.v
A detailed description of the commands available in Yosys can be found in App. C.
27
Chapter 4
Implementation Overview
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 [23], the openMSP430 CPU [22], the OpenCores I2 C master
[20] and the k68 CPU [21].
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.
4.1
Simplified Data Flow
Figure 4.1 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 ILANG
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 ILANG Backend for writing the RTLIL data in
the same format that is understood by the ILANG 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).
28
CHAPTER 4. IMPLEMENTATION OVERVIEW
Verilog Frontend
VHDL Frontend
ILANG Frontend
AST
AST Frontend
RTLIL
Verilog Backend
ILANG Backend
Passes
Other Backends
Figure 4.1: Yosys simplified data flow (ellipses: data structures, rectangles: program modules)
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.
4.2
The RTL Intermediate Language
All frontends, passes and backends in Yosys operate on a design in RTLIL1 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.
Figure 4.2 shows a simplified Entity-Relationship Diagram (ER Diagram) of RTLIL. In 1 : N relationships
the arrow points from the N side to the 1. For example one RTLIL::Design contains N (zero to many)
instances of RTLIL::Module. A two-pointed arrow indicates a 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.
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:
1 The Language in RTL Intermediate Language refers to the fact, that RTLIL also has a text representation, usually
referred to as Intermediate Language (ILANG).
29
CHAPTER 4. IMPLEMENTATION OVERVIEW
RTLIL::Cell
RTLIL::Design
1
N
RTLIL::Module
RTLIL::Wire
RTLIL::SyncRule
RTLIL::Process
RTLIL::CaseRule
RTLIL::Memory
RTLIL::SwitchRule
Figure 4.2: Simplified RTLIL Entity-Relationship Diagram
• 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 generateblocks, 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.
4.2.1
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.
30
CHAPTER 4. IMPLEMENTATION OVERVIEW
• 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_.
In order to avoid programming errors, the RTLIL data structures check if all identifiers start with either
a backslash or a dollar sign and generate a runtime error if this rule is violated.
All RTLIL identifiers are case sensitive.
4.2.2
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 Fig. 4.2 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.)
4.2.3
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)
31
CHAPTER 4. IMPLEMENTATION OVERVIEW
• 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.
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.
4.2.4
RTLIL::SigSpec
A “signal” is everything that can be applied to a cell port. I.e.
• Any constant value of arbitrary bit-width
For example: 1337, 16’b0000010100111001, 1’b1, 1’bx
• All bits of a wire or a selection of bits from a wire
For example: mywire, mywire[24], mywire[15:8]
• Concatenations of the above
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.
4.2.5
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:
1
2
3
4
5
6
7
8
9
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
32
CHAPTER 4. IMPLEMENTATION OVERVIEW
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 ILANG syntax:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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 2 . . . 12 describe how $0\q[0:0] should be calculated. The lines 13 . . . 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) and
zero or more assignments (RTLIL::SigSig).
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 2 . . . 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 3 . . . 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 case2 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 6 . . . 11).
The lines 13 . . . 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:
2 The syntax 1’1 in the ILANG code specifies a constant with a length of one bit (the first “1”), and this bit is a one (the
second “1”).
33
CHAPTER 4. IMPLEMENTATION OVERVIEW
1
2
3
4
5
6
7
8
9
10
11
12
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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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.
4.2.6
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
34
CHAPTER 4. IMPLEMENTATION OVERVIEW
• 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. 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 Sec. 5.1.5 for details about the memory cell types.
4.3
Command Interface and Synthesis Scripts
Yosys reads and processes commands from synthesis scripts, command line arguments and an interactive
command prompt. Yosys commands consist of a command name and an optional whitespace separated
list of arguments. Commands are terminated using the newline character or a semicolon (;). Empty lines
and lines starting with the hash sign (#) are ignored. See Sec. 3.3 for an example synthesis script.
The command help can be used to access the command reference manual.
Most commands can operate not only on the entire design but also specifically on selected parts of the
design. For example the command dump will print all selected objects in the current design while dump
foobar will only print the module foobar and dump * will print the entire design regardless of the current
selection.
The selection mechanism is very powerful. For example the command dump */t:$add %x:+[A] */w:* %i
will print all wires that are connected to the \A port of a $add cell. Detailed documentation of the select
framework can be found in the command reference for the select command.
4.4
Source Tree and Build System
The Yosys source tree is organized into the following top-level directories:
• backends/
This directory contains a subdirectory for each of the backend modules.
• frontends/
This directory contains a subdirectory for each of the frontend modules.
• kernel/
This directory contains all the core functionality of Yosys. This includes the functions and definitions
for working with the RTLIL data structures (rtlil.h and rtlil.cc), the main() function (driver.cc),
the internal framework for generating log messages (log.h and log.cc), the internal framework for
registering and calling passes (register.h and register.cc), some core commands that are not really
passes (select.cc, show.cc, . . . ) and a couple of other small utility libraries.
35
CHAPTER 4. IMPLEMENTATION OVERVIEW
• passes/
This directory contains a subdirectory for each pass or group of passes. For example as of this
writing the directory passes/opt/ contains the code for seven passes: opt, opt_expr, opt_muxtree,
opt_reduce, opt_rmdff, opt_rmunused and opt_merge.
• techlibs/
This directory contains simulation models and standard implementations for the cells from the internal cell library.
• tests/
This directory contains a couple of test cases. Most of the smaller tests are executed automatically
when make test is called. The larger tests must be executed manually. Most of the larger tests require
downloading external HDL source code and/or external tools. The tests range from comparing
simulation results of the synthesized design to the original sources to logic equivalence checking of
entire CPU cores.
frontends/*/Makefile.inc,
passes/*/Makefile.inc
and
extending Yosys it is enough to create a new directory in
your sources and a Makefile.inc. The Yosys kernel automatically
detects all commands linked with Yosys. So it is not needed to add additional commands to a central list
of commands.
The
top-level
Makefile
includes
backends/*/Makefile.inc.
So when
frontends/, passes/ or backends/ with
Good starting points for reading example source code to learn how to write passes are passes/opt/opt_rmdff.cc
and passes/opt/opt_merge.cc.
See the top-level README file for a quick Getting Started guide and build instructions. The Yosys build
is based solely on Makefiles.
Users of the Qt Creator IDE can generate a QT Creator project file using make qtcreator. Users of the
Eclipse IDE can use the “Makefile Project with Existing Code” project type in the Eclipse “New Project”
dialog (only available after the CDT plugin has been installed) to create an Eclipse project in order to
programming extensions to Yosys or just browse the Yosys code base.
36
Chapter 5
Internal Cell Library
Most of the passes in Yosys operate on netlists, i.e. they only care about the RTLIL::Wire and RTLIL::Cell
objects in an RTLIL::Module. This chapter discusses the cell types used by Yosys to represent a behavioural
design internally.
This chapter is split in two parts. In the first part the internal RTL cells are covered. These cells are used
to represent the design on a coarse grain level. Like in the original HDL code on this level the cells operate
on vectors of signals and complex cells like adders exist. In the second part the internal gate cells are
covered. These cells are used to represent the design on a fine-grain gate-level. All cells from this category
operate on single bit signals.
5.1
RTL Cells
Most of the RTL cells closely resemble the operators available in HDLs such as Verilog or VHDL. Therefore
Verilog operators are used in the following sections to define the behaviour of the RTL cells.
Note that all RTL cells have parameters indicating the size of inputs and outputs. When passes modify
RTL cells they must always keep the values of these parameters in sync with the size of the signals
connected to the inputs and outputs.
Simulation models for the RTL cells can be found in the file techlibs/common/simlib.v in the Yosys source
tree.
5.1.1
Unary Operators
All unary RTL cells have one input port \A and one output port \Y. They also have the following parameters:
• \A_SIGNED
Set to a non-zero value if the input \A is signed and therefore should be sign-extended when needed.
• \A_WIDTH
The width of the input port \A.
• \Y_WIDTH
The width of the output port \Y.
Table 5.1 lists all cells for unary RTL operators.
Note that $reduce_or and $reduce_bool actually represent the same logic function. But the HDL frontends
generate them in different situations. A $reduce_or cell is generated when the prefix | operator is being
used. A $reduce_bool cell is generated when a bit vector is used as a condition in an if-statement or
?:-expression.
37
CHAPTER 5. INTERNAL CELL LIBRARY
Verilog
Cell Type
Y = ~A
$not
Y = +A
Y = -A
$pos
$neg
Y = &A
$reduce_and
Y = |A
Y = ^A
Y = ~^A
$reduce_or
$reduce_xor
$reduce_xnor
Y = |A
Y = !A
$reduce_bool
$logic_not
Table 5.1: Cell types for unary operators with their corresponding Verilog expressions.
5.1.2
Binary Operators
All binary RTL cells have two input ports \A and \B and one output port \Y. They also have the following
parameters:
• \A_SIGNED
Set to a non-zero value if the input \A is signed and therefore should be sign-extended when needed.
• \A_WIDTH
The width of the input port \A.
• \B_SIGNED
Set to a non-zero value if the input \B is signed and therefore should be sign-extended when needed.
• \B_WIDTH
The width of the input port \B.
• \Y_WIDTH
The width of the output port \Y.
Table 5.2 lists all cells for binary RTL operators.
5.1.3
Multiplexers
Multiplexers are generated by the Verilog HDL frontend for ?:-expressions. Multiplexers are also generated
by the proc pass to map the decision trees from RTLIL::Process objects to logic.
The simplest multiplexer cell type is $mux. Cells of this type have a \WIDTH parameter and data inputs \A
and \B and a data output \Y, all of the specified width. This cell also has a single bit control input \S. If
\S is 0 the value from the \A input is sent to the output, if it is 1 the value from the \B input is sent to
the output. So the $mux cell implements the function Y = S ? B : A.
The $pmux cell is used to multiplex between many inputs using a one-hot select signal. Cells of this type have
a \WIDTH and a \S_WIDTH parameter and inputs \A, \B, and \S and an output \Y. The \S input is \S_WIDTH
bits wide. The \A input and the output are both \WIDTH bits wide and the \B input is \WIDTH*\S_WIDTH
bits wide. When all bits of \S are zero, the value from \A input is sent to the output. If the n’th bit from
\S is set, the value n’th \WIDTH bits wide slice of the \B input is sent to the output. When more than one
bit from \S is set the output is undefined. Cells of this type are used to model “parallel cases” (defined by
using the parallel_case attribute or detected by an optimization).
Behavioural code with cascaded if-then-else- and case-statements usually results in trees of multiplexer
cells. Many passes (from various optimizations to FSM extraction) heavily depend on these multiplexer
trees to understand dependencies between signals. Therefore optimizations should not break these multiplexer trees (e.g. by replacing a multiplexer between a calculated signal and a constant zero with an $and
gate).
38
CHAPTER 5. INTERNAL CELL LIBRARY
Verilog
Cell Type
Verilog
Cell Type
Y = A & B
$and
Y = A < B
$lt
Y = A | B
Y = A ^ B
Y = A ~^ B
$or
$xor
$xnor
Y
Y
Y
Y
$shl
$shr
$sshl
$sshr
Y
Y
Y
Y
Y
=
=
=
=
=
A
A
A
A
A
<= B
== B
!= B
>= B
> B
$le
$eq
$ne
$ge
$gt
=
=
=
=
A
A
A
A
+ B
- B
* B
/ B
$add
$sub
$mul
$div
=
=
=
=
A
A
A
A
<< B
>> B
<<< B
>>> B
Y = A && B
Y = A || B
$logic_and
$logic_or
Y
Y
Y
Y
Y = A === B
Y = A !== B
$eqx
$nex
Y = A % B
Y = A ** B
$mod
$pow
Table 5.2: Cell types for binary operators with their corresponding Verilog expressions.
5.1.4
Registers
D-Type Flip-Flops are represented by $dff cells. These cells have a clock port \CLK, an input port \D and
an output port \Q. The following parameters are available for $dff cells:
• \WIDTH
The width of input \D and output \Q.
• \CLK_POLARITY
Clock is active on the positive edge if this parameter has the value 1’b1 and on the negative edge if
this parameter is 1’b0.
D-Type Flip-Flops with asynchronous resets are represented by $adff cells. As the $dff cells they have
and \Q ports. In addition they also have a single-bit \ARST input port for the reset pin and the
following additional two parameters:
\CLK, \D
• \ARST_POLARITY
The asynchronous reset is high-active if this parameter has the value 1’b1 and low-active if this
parameter is 1’b0.
• \ARST_VALUE
The state of \Q will be set to this value when the reset is active.
Note that the $adff cell can only be used when the reset value is constant.
Usually these cells are generated by the proc pass using the information in the designs RTLIL::Process
objects.
FIXME:
Add information about $sr cells (set-reset flip-flops) and d-type latches.
5.1.5
Memories
Memories are either represented using RTLIL::Memory objects and $memrd and $memwr cells or simply by
using $mem cells.
In the first alternative the RTLIL::Memory objects hold the general metadata for the memory (bit width,
size in number of words, etc.) and for each port a $memrd (read port) or $memwr (write port) cell is created.
39
CHAPTER 5. INTERNAL CELL LIBRARY
Having individual cells for read and write ports has the advantage that they can be consolidated using
resource sharing passes. In some cases this drastically reduces the number of required ports on the memory
cell.
The $memrd cells have a clock input \CLK, an enable input \EN, an address input \ADDR, and a data output
\DATA. They also have the following parameters:
• \MEMID
The name of the RTLIL::Memory object that is associated with this read port.
• \ABITS
The number of address bits (width of the \ADDR input port).
• \WIDTH
The number of data bits (width of the \DATA output port).
• \CLK_ENABLE
When this parameter is non-zero, the clock is used. Otherwise this read port is asynchronous and
the \CLK input is not used.
• \CLK_POLARITY
Clock is active on the positive edge if this parameter has the value 1’b1 and on the negative edge if
this parameter is 1’b0.
• \TRANSPARENT
If this parameter is set to 1’b1, a read and write to the same address in the same cycle will return
the new value. Otherwise the old value is returned.
The $memwr cells have a clock input \CLK, an enable input \EN (one enable bit for each data bit), an address
input \ADDR and a data input \DATA. They also have the following parameters:
• \MEMID
The name of the RTLIL::Memory object that is associated with this read port.
• \ABITS
The number of address bits (width of the \ADDR input port).
• \WIDTH
The number of data bits (width of the \DATA output port).
• \CLK_ENABLE
When this parameter is non-zero, the clock is used. Otherwise this read port is asynchronous and
the \CLK input is not used.
• \CLK_POLARITY
Clock is active on positive edge if this parameter has the value 1’b1 and on the negative edge if this
parameter is 1’b0.
• \PRIORITY
The cell with the higher integer value in this parameter wins a write conflict.
The HDL frontend models a memory using RTLIL::Memory objects and asynchronous $memrd and $memwr
cells. The memory pass (i.e. its various sub-passes) migrates $dff cells into the $memrd and $memwr cells
making them synchronous, then converts them to a single $mem cell and (optionally) maps this cell type to
$dff cells for the individual words and multiplexer-based address decoders for the read and write interfaces.
When the last step is disabled or not possible, a $mem cell is left in the design.
The $mem cell provides the following parameters:
40
CHAPTER 5. INTERNAL CELL LIBRARY
• \MEMID
The name of the original RTLIL::Memory object that became this $mem cell.
• \SIZE
The number of words in the memory.
• \ABITS
The number of address bits.
• \WIDTH
The number of data bits per word.
• \RD_PORTS
The number of read ports on this memory cell.
• \RD_CLK_ENABLE
This parameter is \RD_PORTS bits wide, containing a clock enable bit for each read port.
• \RD_CLK_POLARITY
This parameter is \RD_PORTS bits wide, containing a clock polarity bit for each read port.
• \RD_TRANSPARENT
This parameter is \RD_PORTS bits wide, containing a transparent bit for each read port.
• \WR_PORTS
The number of write ports on this memory cell.
• \WR_CLK_ENABLE
This parameter is \WR_PORTS bits wide, containing a clock enable bit for each write port.
• \WR_CLK_POLARITY
This parameter is \WR_PORTS bits wide, containing a clock polarity bit for each write port.
The $mem cell has the following ports:
• \RD_CLK
This input is \RD_PORTS bits wide, containing all clock signals for the read ports.
• \RD_EN
This input is \RD_PORTS bits wide, containing all enable signals for the read ports.
• \RD_ADDR
This input is \RD_PORTS*\ABITS bits wide, containing all address signals for the read ports.
• \RD_DATA
This input is \RD_PORTS*\WIDTH bits wide, containing all data signals for the read ports.
• \WR_CLK
This input is \WR_PORTS bits wide, containing all clock signals for the write ports.
• \WR_EN
This input is \WR_PORTS*\WIDTH bits wide, containing all enable signals for the write ports.
• \WR_ADDR
This input is \WR_PORTS*\ABITS bits wide, containing all address signals for the write ports.
• \WR_DATA
This input is \WR_PORTS*\WIDTH bits wide, containing all data signals for the write ports.
The techmap pass can be used to manually map $mem cells to specialized memory cells on the target
architecture, such as block ram resources on an FPGA.
41
CHAPTER 5. INTERNAL CELL LIBRARY
Verilog
Y = ~A
Y
Y
Y
Y
=
=
=
=
A
A
A
S
&
|
^
?
B
B
B
B : A
always @(negedge C) Q <= D
always @(posedge C) Q <= D
Cell Type
ClkEdge
RstLvl
RstV al
Cell Type
$_NOT_
negedge
0
0
$_DFF_NN0_
$_AND_
$_OR_
$_XOR_
$_MUX_
negedge
negedge
negedge
posedge
posedge
posedge
0
1
1
0
0
1
1
0
1
0
1
0
$_DFF_NN1_
$_DFF_NP0_
$_DFF_NP1_
$_DFF_PN0_
$_DFF_PN1_
$_DFF_PP0_
posedge
1
1
$_DFF_PP1_
$_DFF_N_
$_DFF_P_
Table 5.3: Cell types for gate level logic networks
5.1.6
Finite State Machines
FIXME:
Add a brief description of the $fsm cell type.
5.2
Gates
For gate level logic networks, fixed function single bit cells are used that do not provide any parameters.
Simulation models for these cells can be found in the file techlibs/common/simcells.v in the Yosys source
tree.
Table 5.3 lists all cell types used for gate level logic. The cell types $_NOT_, $_AND_, $_OR_, $_XOR_ and
$_MUX_ are used to model combinatorial logic. The cell types $_DFF_N_ and $_DFF_P_ represent d-type
flip-flops.
The cell types $_DFF_NN0_, $_DFF_NN1_, $_DFF_NP0_, $_DFF_NP1_, $_DFF_PN0_, $_DFF_PN1_, $_DFF_PP0_ and
implement d-type flip-flops with asynchronous resets. The values in the table for these cell
types relate to the following Verilog code template, where RstEdge is posedge if RstLvl if 1, and negedge
otherwise.
$_DFF_PP1_
always @(ClkEdge C, RstEdge R)
if (R == RstLvl)
Q <= RstV al;
else
Q <= D;
In most cases gate level logic networks are created from RTL networks using the techmap pass. The flip-flop
cells from the gate level logic network can be mapped to physical flip-flop cells from a Liberty file using
the dfflibmap pass. The combinatorial logic cells can be mapped to physical cells from a Liberty file via
ABC [27] using the abc pass.
FIXME:
Add information about $assert, $assume, $live, $fair, $cover, $equiv, $initstate, $anyconst, and
$anyseq cells.
FIXME:
Add information about $slice and $concat cells.
FIXME:
Add information about $lut and $sop cells.
FIXME:
Add information about $alu, $macc, $fa, and $lcu cells.
42
CHAPTER 5. INTERNAL CELL LIBRARY
FIXME:
Add information about $ff and $_FF_ cells.
FIXME:
Add information about $dffe, $dffsr, $dlatch, and $dlatchsr cells.
FIXME:
Add information about $_DFFE_??_, $_DFFSR_???_, $_DLATCH_?_, and $_DLATCHSR_???_ cells.
FIXME:
Add information about $_NAND_, $_NOR_, $_XNOR_, $_ANDNOT_, $_ORNOT_, $_AOI3_, $_OAI3_, $_AOI4_, and
$_OAI4_ cells.
43
Chapter 6
Programming Yosys Extensions
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 Yosys Subreddit.
6.1
The “CodingReadme” File
The following is an excerpt of the CodingReadme file from the Yosys source tree.
CodingReadme
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Getting Started
===============
Outline of a Yosys command
-------------------------Here is a the C++ code for a "hello_world" Yosys command (hello.cc):
#include "kernel/yosys.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct HelloWorldPass : public Pass {
HelloWorldPass() : Pass("hello_world") { }
virtual void execute(vector, Design*) {
log("Hello World!\n");
}
} HelloWorldPass;
PRIVATE_NAMESPACE_END
This can be built into a Yosys module using the following command:
yosys-config --exec --cxx --cxxflags --ldflags -o hello.so -shared hello.cc --ldlibs
44
CHAPTER 6. PROGRAMMING YOSYS EXTENSIONS
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
Or short:
yosys-config --build hello.so hello.cc
And then executed using the following command:
yosys -m hello.so -p hello_world
Yosys Data Structures
--------------------Here is a short list of data structures that you should make yourself familiar
with before you write C++ code for Yosys. The following data structures are all
defined when "kernel/yosys.h" is included and USING_YOSYS_NAMESPACE is used.
1. Yosys Container Classes
Yosys uses dict and pool as main container classes. dict is
essentially a replacement for std::unordered_map and pool is a
replacement for std::unordered_set. The main characteristics are:
- dict and pool are about 2x faster than the std containers
- references to elements in a dict or pool are invalidated by
insert and remove operations (similar to std::vector on push_back()).
- some iterators are invalidated by erase(). specifically, iterators
that have not passed the erased element yet are invalidated. (erase()
itself returns valid iterator to the next element.)
- no iterators are invalidated by insert(). elements are inserted at
begin(). i.e. only a new iterator that starts at begin() will see the
inserted elements.
- the method .count(key, iterator) is like .count(key) but only
considers elements that can be reached via the iterator.
- iterators can be compared. it1 < it2 means that the position of t2
can be reached via t1 but not vice versa.
- the method .sort() can be used to sort the elements in the container
the container stays sorted until elements are added or removed.
- dict and pool will have the same order of iteration across
all compilers, standard libraries and architectures.
In addition to dict and pool there is also an idict that
creates a bijective map from K to the integers. For example:
idict si;
log("%d\n", si("hello"));
// will print 42
log("%d\n", si("world"));
log("%d\n", si.at("world"));
// will print 43
// will print 43
45
CHAPTER 6. PROGRAMMING YOSYS EXTENSIONS
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
log("%d\n",
log("%s\n",
log("%s\n",
log("%s\n",
si.at("dummy"));
si[42].c_str()));
si[43].c_str()));
si[44].c_str()));
//
//
//
//
will
will
will
will
throw
print
print
throw
exception
hello
world
exception
It is not possible to remove elements from an idict.
Finally mfp implements a merge-find set data structure (aka. disjoint-set or
union-find) over the type K ("mfp" = merge-find-promote).
2. Standard STL data types
In Yosys we use std::vector and std::string whenever applicable. When
dict and pool are not suitable then std::map and std::set
are used instead.
The types std::vector and std::string are also available as vector
and string in the Yosys namespace.
3. RTLIL objects
The current design (essentially a collection of modules, each defined by a
netlist) is stored in memory using RTLIL object (declared in kernel/rtlil.h,
automatically included by kernel/yosys.h). You should glance over at least
the declarations for the following types in kernel/rtlil.h:
RTLIL::IdString
This is a handle for an identifier (e.g. cell or wire name).
It feels a lot like a std::string, but is only a single int
in size. (The actual string is stored in a global lookup
table.)
RTLIL::SigBit
A single signal bit. I.e. either a constant state (0, 1,
x, z) or a single bit from a wire.
RTLIL::SigSpec
Essentially a vector of SigBits.
RTLIL::Wire
RTLIL::Cell
The building blocks of the netlist in a module.
RTLIL::Module
RTLIL::Design
The module is a container with connected cells and wires
in it. The design is a container with modules in it.
All this types are also available without the RTLIL:: prefix in the Yosys
namespace.
4. SigMap and other Helper Classes
There are a couple of additional helper classes that are in wide use
46
CHAPTER 6. PROGRAMMING YOSYS EXTENSIONS
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
in Yosys. Most importantly there is SigMap (declared in kernel/sigtools.h).
When a design has many wires in it that are connected to each other, then a
single signal bit can have multiple valid names. The SigMap object can be used
to map SigSpecs or SigBits to unique SigSpecs and SigBits that consistently
only use one wire from such a group of connected wires. For example:
SigBit a = module->addWire(NEW_ID);
SigBit b = module->addWire(NEW_ID);
module->connect(a, b);
log("%d\n", a == b); // will print 0
SigMap sigmap(module);
log("%d\n", sigmap(a) == sigmap(b)); // will print 1
Using the RTLIL Netlist Format
-----------------------------In the RTLIL netlist format the cell ports contain SigSpecs that point to the
Wires. There are no references in the other direction. This has two direct
consequences:
(1) It is very easy to go from cells to wires but hard to go in the other way.
(2) There is no danger in removing cells from the netlists, but removing wires
can break the netlist format when there are still references to the wire
somewhere in the netlist.
The solution to (1) is easy: Create custom indexes that allow you to make fast
lookups for the wire-to-cell direction. You can either use existing generic
index structures to do that (such as the ModIndex class) or write your own
index. For many application it is simplest to construct a custom index. For
example:
SigMap sigmap(module);
dict sigbit_to_driver_index;
for (auto cell : module->cells())
for (auto &conn : cell->connections())
if (cell->output(conn.first))
for (auto bit : sigmap(conn.second))
sigbit_to_driver_index[bit] = cell;
Regarding (2): There is a general theme in Yosys that you don’t remove wires
from the design. You can rename them, unconnect them, but you do not actually remove
the Wire object from the module. Instead you let the "clean" command take care
of the dangling wires. On the other hand it is safe to remove cells (as long as
you make sure this does not invalidate a custom index you are using in your code).
Example Code
------------
47
CHAPTER 6. PROGRAMMING YOSYS EXTENSIONS
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
The following yosys commands are a good starting point if you are looking for examples
of how to use the Yosys API:
manual/CHAPTER_Prog/stubnets.cc
manual/PRESENTATION_Prog/my_cmd.cc
Notes on the existing codebase
-----------------------------For historical reasons not all parts of Yosys adhere to the current coding
style. When adding code to existing parts of the system, adhere to this guide
for the new code instead of trying to mimic the style of the surrounding code.
Coding Style
============
Formatting of code
------------------ Yosys code is using tabs for indentation. Tabs are 8 characters.
- A continuation of a statement in the following line is indented by
two additional tabs.
- Lines are as long as you want them to be. A good rule of thumb is
to break lines at about column 150.
- Opening braces can be put on the same or next line as the statement
opening the block (if, switch, for, while, do). Put the opening brace
on its own line for larger blocks, especially blocks that contains
blank lines.
- Otherwise stick to the Linux Kernel Coding Style:
https://www.kernel.org/doc/Documentation/CodingStyle
C++ Language
------------Yosys is written in C++11. At the moment only constructs supported by
gcc 4.8 are allowed in Yosys code. This will change in future releases.
In general Yosys uses "int" instead of "size_t". To avoid compiler
warnings for implicit type casts, always use "GetSize(foobar)" instead
of "foobar.size()". (GetSize() is defined in kernel/yosys.h)
Use range-based for loops whenever applicable.
48
CHAPTER 6. PROGRAMMING YOSYS EXTENSIONS
6.2
The “stubsnets” Example Module
The following is the complete code of the “stubsnets” example module. It is included in the Yosys source
distribution as manual/CHAPTER_Prog/stubnets.cc.
stubnets.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
#include
#include