-\section{Programming Yosys Extensions}
+\section{Writing Yosys extensions in C++}
\begin{frame}
\sectionpage
\subsection{Simplified RTLIL Entity-Relationship Diagram}
\begin{frame}{\subsecname}
-Between passses and frontends/backends the design in stored in Yosys' internal RTLIL (RTL Intermediate Language) format. For
-writing Yosys extensions it is key to understand this format.
+Between passses and frontends/backends the design is stored in Yosys' internal
+RTLIL (RTL Intermediate Language) format. For writing Yosys extensions it is
+key to understand this format.
\bigskip
\begin{center}
\subsection{RTLIL without memories and processes}
\begin{frame}[fragile]{\subsecname}
-After the command {\tt proc} and {\tt memory} (or {\tt memory -nomap}), we are left with a much simpler version of RTLIL:
+After the commands {\tt proc} and {\tt memory} (or {\tt memory -nomap}), we are
+left with a much simpler version of RTLIL:
\begin{center}
\begin{tikzpicture}[scale=0.6, every node/.style={transform shape}]
\end{center}
\bigskip
-Many command simply choose to only work on this simpler version:
+Many commands simply choose to only work on this simpler version:
\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont]
-if (module->processes.size() != 0 || module->memories.size() != 0)
- log_error("This command does not operate on modules with processes "
- "and/or memories! Run 'proc' and 'memory' first.\n");
+for (RTLIL::Module *module : design->selected_modules() {
+ if (module->has_memories_warn() || module->has_processes_warn())
+ continue;
+ ....
+}
\end{lstlisting}
-\bigskip
For simplicity we only discuss this version of RTLIL in this presentation.
\end{frame}
\subsection{The RTLIL Data Structures}
\begin{frame}{\subsecname}
-The RTLIL data structures are simple structs utilizing C++ {\tt std::}
-containers.
+The RTLIL data structures are simple structs utilizing {\tt pool<>} and
+{\tt dict<>} containers (drop-in replacements for {\tt
+std::unordered\_set<>} and {\tt std::unordered\_map<>}).
\bigskip
\begin{itemize}
\subsubsection{RTLIL::IdString}
\begin{frame}{\subsubsecname}{}
-{\tt RTLIL::IdString} is a simple wrapper for {\tt std::string}. It is used for names of RTLIL objects.
+{\tt RTLIL::IdString} in many ways behave like a {\tt std::string}. It is used
+for names of RTLIL objects. Internally a RTLIL::IdString object is only a
+single integer.
\medskip
The first character of a {\tt RTLIL::IdString} specifies if the name is {\it public\/} or {\it private\/}:
\begin{frame}[t, fragile]{\subsubsecname}
The {\tt RTLIL::Design} and {\tt RTLIL::Module} structs are the top-level RTLIL
-data structures.
-
-Yosys always operates on one active design, but can hold many designs in memory.
+data structures. Yosys always operates on one active design, but can hold many designs in memory.
\bigskip
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
struct RTLIL::Design {
- std::map<RTLIL::IdString, RTLIL::Module*> modules;
+ dict<RTLIL::IdString, RTLIL::Module*> modules_;
...
};
struct RTLIL::Module {
RTLIL::IdString name;
- std::map<RTLIL::IdString, RTLIL::Wire*> wires;
- std::map<RTLIL::IdString, RTLIL::Cell*> cells;
- std::vector<RTLIL::SigSig> connections;
+ dict<RTLIL::IdString, RTLIL::Wire*> wires_;
+ dict<RTLIL::IdString, RTLIL::Cell*> cells_;
+ std::vector<RTLIL::SigSig> connections_;
...
};
\end{lstlisting}
+
+(Use the various accessor functions instead of directly working with the {\tt *\_} members.)
\end{frame}
\subsubsection{The RTLIL::Wire Structure}
\begin{frame}[t, fragile]{\subsubsecname}
The {\tt RTLIL::SigSpec} struct represents a signal vector. Each bit can either be a bit from a wire
-or a constant value. Consecutive bits from a wire or consecutive constant bits are consolidated into
-a {\tt RTLIL::SigChunk}:
+or a constant value.
\bigskip
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
-struct RTLIL::SigChunk {
+struct RTLIL::SigBit
+{
RTLIL::Wire *wire;
- RTLIL::Const data; // only used if wire == NULL, LSB at index 0
- int width, offset;
+ union {
+ RTLIL::State data; // used if wire == NULL
+ int offset; // used if wire != NULL
+ };
...
};
struct RTLIL::SigSpec {
- std::vector<RTLIL::SigChunk> chunks; // LSB at index 0
- int width;
+ std::vector<RTLIL::SigBit> bits_; // LSB at index 0
...
};
\end{lstlisting}
\subsubsection{The RTLIL::Cell Structure}
\begin{frame}[t, fragile]{\subsubsecname (1/2)}
-The {\tt RTLIL::Cell} strcut represents an instance of a module or library cell.
+The {\tt RTLIL::Cell} struct represents an instance of a module or library cell.
\smallskip
The ports of the cell
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
struct RTLIL::Cell {
RTLIL::IdString name, type;
- std::map<RTLIL::IdString, RTLIL::SigSpec> connections;
- std::map<RTLIL::IdString, RTLIL::Const> parameters;
+ dict<RTLIL::IdString, RTLIL::SigSpec> connections_;
+ dict<RTLIL::IdString, RTLIL::Const> parameters;
...
};
\end{lstlisting}
cell name from the internal cell library:
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{6pt}{7pt}\selectfont]
-$not $pos $bu0 $neg $and $or $xor $xnor $reduce_and $reduce_or $reduce_xor $reduce_xnor
+$not $pos $neg $and $or $xor $xnor $reduce_and $reduce_or $reduce_xor $reduce_xnor
$reduce_bool $shl $shr $sshl $sshr $lt $le $eq $ne $eqx $nex $ge $gt $add $sub $mul $div $mod
-$pow $logic_not $logic_and $logic_or $mux $pmux $slice $concat $safe_pmux $lut $assert $sr $dff
-$dffsr $adff $dlatch $dlatchsr $memrd $memwr $mem $fsm $_INV_ $_AND_ $_OR_ $_XOR_ $_MUX_ $_SR_NN_
+$pow $logic_not $logic_and $logic_or $mux $pmux $slice $concat $lut $assert $sr $dff
+$dffsr $adff $dlatch $dlatchsr $memrd $memwr $mem $fsm $_NOT_ $_AND_ $_OR_ $_XOR_ $_MUX_ $_SR_NN_
$_SR_NP_ $_SR_PN_ $_SR_PP_ $_DFF_N_ $_DFF_P_ $_DFF_NN0_ $_DFF_NN1_ $_DFF_NP0_ $_DFF_NP1_ $_DFF_PN0_
$_DFF_PN1_ $_DFF_PP0_ $_DFF_PP1_ $_DFFSR_NNN_ $_DFFSR_NNP_ $_DFFSR_NPN_ $_DFFSR_NPP_ $_DFFSR_PNN_
$_DFFSR_PNP_ $_DFFSR_PPN_ $_DFFSR_PPP_ $_DLATCH_N_ $_DLATCH_P_ $_DLATCHSR_NNN_ $_DLATCHSR_NNP_
\end{frame}
\begin{frame}[t, fragile]{\subsubsecname (2/2)}
-Simulation models (i.e. {\it documentation\/}) for the internal cell library:
+Simulation models (i.e. {\it documentation\/} :-) for the internal cell library:
\smallskip
\hskip2em {\tt yosys/techlibs/common/simlib.v} and \\
\bigskip
The lower-case cell types (such as {\tt \$and}) are parameterized cells of variable
-width. This so-called {\it RTL cells\/} are the cells described in {\tt simlib.v}.
+width. This so-called {\it RTL Cells\/} are the cells described in {\tt simlib.v}.
\bigskip
-The upper-case cell types (such as {\tt \$\_AND\_}) single-bit cells that are not
-parameterized. This so-called {\it internal Logic Gates} are the cells described
+The upper-case cell types (such as {\tt \$\_AND\_}) are single-bit cells that are not
+parameterized. This so-called {\it Internal Logic Gates} are the cells described
in {\tt simcells.v}.
\bigskip
struct RTLIL::Module {
...
- std::vector<RTLIL::SigSig> connections;
+ std::vector<RTLIL::SigSig> connections_;
...
};
\end{lstlisting}
{\tt RTLIL::SigSig::first} is the driven signal and {\tt RTLIL::SigSig::second} is the driving signal.
Example usage (setting wire {\tt foo} to value {\tt 42}):
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
-module->connections.push_back(RTLIL::SigSig(module->wires.at("\\foo"),
- RTLIL::SigSpec(42, module->wires.at("\\foo")->width)));
+module->connect(module->wire("\\foo"),
+ RTLIL::SigSpec(42, module->wire("\\foo")->width));
\end{lstlisting}
\end{frame}
RTLIL::Module *module = new RTLIL::Module;
module->name = "\\absval";
-RTLIL::Wire *a = module->new_wire(4, "\\a");
+RTLIL::Wire *a = module->addWire("\\a", 4);
a->port_input = true;
a->port_id = 1;
-RTLIL::Wire *y = module->new_wire(4, "\\y");
+RTLIL::Wire *y = module->addWire("\\y", 4);
y->port_output = true;
y->port_id = 2;
-RTLIL::Wire *a_inv = module->new_wire(4, NEW_ID);
+RTLIL::Wire *a_inv = module->addWire(NEW_ID, 4);
module->addNeg(NEW_ID, a, a_inv, true);
module->addMux(NEW_ID, a, a_inv, RTLIL::SigSpec(a, 1, 3), y);
+
+module->fixup_ports();
\end{lstlisting}
\end{frame}
\item Use {\tt module->fixup\_ports()} after changing the {\tt port\_*} properties of wires.
-\item You can safely remove cells or change the {\tt connetions} property of a cell, but be careful when
+\item You can safely remove cells or change the {\tt connections} property of a cell, but be careful when
changing the size of the {\tt SigSpec} connected to a cell port.
\item Use the {\tt SigMap} helper class (see next slide) when you need a unique handle for each signal bit.
\smallskip
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
-RTLIL::SigSpec a(module->wires.at("\\a")), x(module->wires.at("\\x")),
- y(module->wires.at("\\y"));
+RTLIL::SigSpec a(module->wire("\\a")), x(module->wire("\\x")),
+ y(module->wire("\\y"));
log("%d %d %d\n", a == x, x == y, y == a); // will print "0 0 0"
\end{lstlisting}
\end{lstlisting}
\medskip
-Use {\tt RTLIL::id2cstr()} to create a C-string for an {\tt RTLIL::IdString}:
+Use {\tt log\_id()} to create a C-string for an {\tt RTLIL::IdString}:
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
-log("Name of this module: %s\n", RTLIL::id2cstr(module->name));
+log("Name of this module: %s\n", log_id(module->name));
\end{lstlisting}
\medskip
Use {\tt log\_header()} and {\tt log\_push()}/{\tt log\_pop()} to structure log messages:
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
-log_header("Doing important stuff!\n");
+log_header(design, "Doing important stuff!\n");
log_push();
for (int i = 0; i < 10; i++)
log("Log message #%d.\n", i);
\bigskip
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
-#include "kernel/rtlil.h"
-#include "kernel/register.h"
-#include "kernel/log.h"
+#include "kernel/yosys.h"
+USING_YOSYS_NAMESPACE
struct MyPass : public Pass {
MyPass() : Pass("my_cmd", "just a simple test") { }
log(" %s\n", arg.c_str());
log("Modules in current design:\n");
- for (auto &mod : design->modules)
- log(" %s (%zd wires, %zd cells)\n", RTLIL::id2cstr(mod.first),
- mod.second->wires.size(), mod.second->cells.size());
+ for (auto mod : design->modules())
+ log(" %s (%d wires, %d cells)\n", log_id(mod),
+ GetSize(mod->wires()), GetSize(mod->cells()));
}
} MyPass;
\end{lstlisting}
-o my_cmd.so -shared my_cmd.cc --ldlibs
\end{lstlisting}
+\bigskip
+Or shorter:
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont]
+yosys-config --build my_cmd.so my_cmd.cc
+\end{lstlisting}
+
\bigskip
Load the plugin using the yosys {\tt -m} option:
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont]
\item \dots and even simpler if you don't need RTLIL::Memory or RTLIL::Process objects.
\bigskip
-\item Writing synthesis software? Consider learning the Yosys API and make your stuff
+\item Writing synthesis software? Consider learning the Yosys API and make your work
part of the Yosys framework.
\end{itemize}