summaryrefslogtreecommitdiff
path: root/manual/PRESENTATION_Prog.tex
diff options
context:
space:
mode:
Diffstat (limited to 'manual/PRESENTATION_Prog.tex')
-rw-r--r--manual/PRESENTATION_Prog.tex440
1 files changed, 398 insertions, 42 deletions
diff --git a/manual/PRESENTATION_Prog.tex b/manual/PRESENTATION_Prog.tex
index 45f0cb0c..1e7f697b 100644
--- a/manual/PRESENTATION_Prog.tex
+++ b/manual/PRESENTATION_Prog.tex
@@ -7,14 +7,6 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-\subsection{Why writing Yosys extensions?}
-
-\begin{frame}{\subsecname}
-TBD
-\end{frame}
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
\subsection{Program Components and Data Formats}
\begin{frame}{\subsecname}
@@ -109,55 +101,293 @@ For simplicity we only discuss this version of RTLIL in this presentation.
\subsection{Using dump and show commands}
\begin{frame}{\subsecname}
-TBD
+\begin{itemize}
+\item The {\tt dump} command prints the design (or parts of it) in ILANG format. This is
+a text representation of RTLIL.
+
+\bigskip
+\item The {\tt show} command visualizes how the components in the design are connected.
+\end{itemize}
+
+\bigskip
+When trying to understand what a command does, create a small test case and
+look at the output of {\tt dump} and {\tt show} before and after the command
+has been executed.
\end{frame}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-\subsection{The RTLIL::Const Structure}
+\subsection{The RTLIL Data Structures}
\begin{frame}{\subsecname}
-TBD
+The RTLIL data structures are simple structs utilizing C++ {\tt std::}
+containers.
+
+\bigskip
+\begin{itemize}
+\item Most operations are performed directly on the RTLIL structs without
+setter or getter functions.
+
+\bigskip
+\item In debug builds a consistency checker is run over the in-memory design
+between commands to make sure that the RTLIL representation is intact.
+
+\bigskip
+\item Most RTLIL structs have helper methods that perform the most common operations.
+\end{itemize}
+
+\bigskip
+See {\tt yosys/kernel/rtlil.h} for details.
\end{frame}
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsubsection{RTLIL::IdString}
-\subsection{The RTLIL::SigSpec Structure}
+\begin{frame}{\subsubsecname}{}
+{\tt RTLIL::IdString} is a simple wrapper for {\tt std::string}. It is used for names of RTLIL objects.
-\begin{frame}{\subsecname}
-TBD
+\medskip
+The first character of a {\tt RTLIL::IdString} specifies if the name is {\it public\/} or {\it private\/}:
+
+\medskip
+\begin{itemize}
+\item {\tt RTLIL::IdString[0] == '\textbackslash\textbackslash'}: \\
+This is a public name. Usually this means it is a name that was declared in a Verilog file.
+
+\bigskip
+\item {\tt RTLIL::IdString[0] == '\$'}: \\
+This is a private name. It was assigned by Yosys.
+\end{itemize}
+
+\bigskip
+Use the {\tt NEW\_ID} macro to create a new unique private name.
\end{frame}
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsubsection{RTLIL::Design and RTLIL::Module}
-\subsection{RTLIL::Design, RTLIL::Module}
+\begin{frame}[t, fragile]{\subsubsecname}
+The {\tt RTLIL::Design} and {\tt RTLIL::Module} structs are the top-level RTLIL
+data structures.
-\begin{frame}{\subsecname}
-TBD
+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;
+ ...
+};
+
+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;
+ ...
+};
+\end{lstlisting}
\end{frame}
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsubsection{The RTLIL::Wire Structure}
-\subsection{RTLIL::Wire and connections}
+\begin{frame}[t, fragile]{\subsubsecname}
+Each wire in the design is represented by a {\tt RTLIL::Wire} struct:
-\begin{frame}{\subsecname}
-TBD
+\medskip
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
+struct RTLIL::Wire {
+ RTLIL::IdString name;
+ int width, start_offset, port_id;
+ bool port_input, port_output;
+ ...
+};
+\end{lstlisting}
+
+\medskip
+\hfil\begin{tabular}{p{3cm}l}
+{\tt width} \dotfill & The total number of bits. E.g. 10 for {\tt [9:0]}. \\
+{\tt start\_offset} \dotfill & The lowest bit index. E.g. 3 for {\tt [5:3]}. \\
+{\tt port\_id} \dotfill & Zero for non-ports. Positive index for ports. \\
+{\tt port\_input} \dotfill & True for {\tt input} and {\tt inout} ports. \\
+{\tt port\_output} \dotfill & True for {\tt output} and {\tt inout} ports. \\
+\end{tabular}
\end{frame}
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsubsection{RTLIL::State and RTLIL::Const}
+
+\begin{frame}[t, fragile]{\subsubsecname}
+The {\tt RTLIL::State} enum represents a simple 1-bit logic level:
+
+\smallskip
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
+enum RTLIL::State {
+ S0 = 0,
+ S1 = 1,
+ Sx = 2, // undefined value or conflict
+ Sz = 3, // high-impedance / not-connected
+ Sa = 4, // don't care (used only in cases)
+ Sm = 5 // marker (used internally by some passes)
+};
+\end{lstlisting}
-\subsection{RTLIL::Cell}
+\bigskip
+The {\tt RTLIL::Const} struct represents a constant multi-bit value:
+
+\smallskip
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
+struct RTLIL::Const {
+ std::vector<RTLIL::State> bits;
+ ...
+};
+\end{lstlisting}
-\begin{frame}{\subsecname}
-TBD
+\bigskip
+Notice that Yosys is not using special {\tt VCC} or {\tt GND} driver cells to represent constants. Instead
+constants are part of the RTLIL representation itself.
+\end{frame}
+
+\subsubsection{The RTLIL::SigSpec 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}:
+
+\bigskip
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
+struct RTLIL::SigChunk {
+ RTLIL::Wire *wire;
+ RTLIL::Const data; // only used if wire == NULL, LSB at index 0
+ int width, offset;
+ ...
+};
+
+struct RTLIL::SigSpec {
+ std::vector<RTLIL::SigChunk> chunks; // LSB at index 0
+ int width;
+ ...
+};
+\end{lstlisting}
+
+\bigskip
+The {\tt RTLIL::SigSpec} struct has a ton of additional helper methods to compare, analyze, and
+manipulate instances of {\tt RTLIL::SigSpec}.
+\end{frame}
+
+\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.
+
+\smallskip
+The ports of the cell
+are associated with {\tt RTLIL::SigSpec} instances and the parameters are associated with {\tt RTLIL::Const}
+instances:
+
+\bigskip
+\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;
+ ...
+};
+\end{lstlisting}
+
+\bigskip
+The {\tt type} may refer to another module in the same design, a cell name from a cell library, or a
+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
+$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_
+$_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_
+$_DLATCHSR_NPN_ $_DLATCHSR_NPP_ $_DLATCHSR_PNN_ $_DLATCHSR_PNP_ $_DLATCHSR_PPN_ $_DLATCHSR_PPP_
+\end{lstlisting}
+\end{frame}
+
+\begin{frame}[t, fragile]{\subsubsecname (2/2)}
+Simulation models (i.e. {\it documentation\/}) for the internal cell library:
+
+\smallskip
+\hskip2em {\tt yosys/techlibs/common/simlib.v} and \\
+\hskip2em {\tt yosys/techlibs/common/simcells.v}
+
+\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}.
+
+\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
+in {\tt simcells.v}.
+
+\bigskip
+The consistency checker also checks the interfaces to the internal cell library.
+If you want to use private cell types for your own purposes, use the {\tt \$\_\_}-prefix
+to avoid name collisions.
+\end{frame}
+
+\subsubsection{Connecting wires or constant drivers}
+
+\begin{frame}[t, fragile]{\subsubsecname}
+Additional connections between wires or between wires and constants are modelled using
+{\tt RTLIL::Module::connections}:
+
+\bigskip
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
+typedef std::pair<RTLIL::SigSpec, RTLIL::SigSpec> RTLIL::SigSig;
+
+struct RTLIL::Module {
+ ...
+ std::vector<RTLIL::SigSig> connections;
+ ...
+};
+\end{lstlisting}
+
+\bigskip
+{\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)));
+\end{lstlisting}
\end{frame}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Creating modules from scratch}
-\begin{frame}{\subsecname}
-TBD
+\begin{frame}[t, fragile]{\subsecname}
+Let's create the following module using the RTLIL API:
+
+\smallskip
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=Verilog]
+module absval(input signed [3:0] a, output [3:0] y);
+ assign y = a[3] ? -a : a;
+endmodule
+\end{lstlisting}
+
+\smallskip
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
+RTLIL::Module *module = new RTLIL::Module;
+module->name = "\\absval";
+
+RTLIL::Wire *a = module->new_wire(4, "\\a");
+a->port_input = true;
+a->port_id = 1;
+
+RTLIL::Wire *y = module->new_wire(4, "\\y");
+y->port_output = true;
+y->port_id = 2;
+
+RTLIL::Wire *a_inv = module->new_wire(4, NEW_ID);
+module->addNeg(NEW_ID, a, a_inv, true);
+module->addMux(NEW_ID, a, a_inv, RTLIL::SigSpec(a, 1, 3), y);
+\end{lstlisting}
\end{frame}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -165,39 +395,163 @@ TBD
\subsection{Modifying modules}
\begin{frame}{\subsecname}
-TBD
+Most commands modify existing modules, not create new ones.
+
+When modifying existing modules, stick to the following DOs and DON'Ts:
+
+\begin{itemize}
+\item Do not remove wires. Simply disconnect them and let a successive {\tt clean} command worry about removing it.
+
+\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
+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.
+\end{itemize}
\end{frame}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Using the SigMap helper class}
-\begin{frame}{\subsecname}
-TBD
+\begin{frame}[t, fragile]{\subsecname}
+Consider the following module:
+
+\smallskip
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=Verilog]
+module test(input a, output x, y);
+ assign x = a, y = a;
+endmodule
+\end{lstlisting}
+
+In this case {\tt a}, {\tt x}, and {\tt y} are all different names for the same signal. However:
+
+\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"));
+log("%d %d %d\n", a == x, x == y, y == a); // will print "0 0 0"
+\end{lstlisting}
+
+The {\tt SigMap} helper class can be used to map all such aliasing signals to a
+unique signal from the group (usually the wire that is directly driven by a cell or port).
+
+\smallskip
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
+SigMap sigmap(module);
+log("%d %d %d\n", sigmap(a) == sigmap(x), sigmap(x) == sigmap(y),
+ sigmap(y) == sigmap(a)); // will print "1 1 1"
+\end{lstlisting}
\end{frame}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Printing log messages}
-\begin{frame}{\subsecname}
-TBD
+\begin{frame}[t, fragile]{\subsecname}
+The {\tt log()} function is a {\tt printf()}-like function that can be used to create log messages.
+
+\medskip
+Use {\tt log\_signal()} to create a C-string for a SigSpec object\footnote[frame]{The pointer returned
+by {\tt log\_signal()} is automatically freed by the log framework at a later time.}:
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
+log("Mapped signal x: %s\n", log_signal(sigmap(x)));
+\end{lstlisting}
+
+\medskip
+Use {\tt RTLIL::id2cstr()} 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));
+\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_push();
+for (int i = 0; i < 10; i++)
+ log("Log message #%d.\n", i);
+log_pop();
+\end{lstlisting}
+\end{frame}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\subsection{Error handling}
+
+\begin{frame}[t, fragile]{\subsecname}
+Use {\tt log\_error()} to report a non-recoverable error:
+
+\medskip
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
+if (design->modules.count(module->name) != 0)
+ log_error("A module with the name %s already exists!\n",
+ RTLIL::id2cstr(module->name));
+\end{lstlisting}
+
+\bigskip
+Use {\tt log\_cmd\_error()} to report a recoverable error:
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
+if (design->selection_stack.back().empty())
+ log_cmd_error("This command can't operator on an empty selection!\n");
+\end{lstlisting}
+
+\bigskip
+Use {\tt log\_assert()} and {\tt log\_abort()} instead of {\tt assert()} and {\tt abort()}.
\end{frame}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Creating a command}
-\begin{frame}{\subsecname}
-TBD
+\begin{frame}[t, fragile]{\subsecname}
+Simply create a global instance of a class derived from {\tt Pass} to create
+a new yosys command:
+
+\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"
+
+struct MyPass : public Pass {
+ MyPass() : Pass("my_cmd", "just a simple test") { }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log("Arguments to my_cmd:\n");
+ for (auto &arg : args)
+ log(" %s\n", arg.c_str());
+
+ log("Modules in current design:\n");
+ for (auto &mod : design->modules)
+ log(" %s (%zd wires, %zd cells)\n", RTLIL::id2cstr(mod.first),
+ mod.second->wires.size(), mod.second->cells.size());
+ }
+} MyPass;
+\end{lstlisting}
\end{frame}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Creating a plugin}
-\begin{frame}{\subsecname}
-TBD
+\begin{frame}[fragile]{\subsecname}
+Yosys can be extended by adding additional C++ code to the Yosys code base, or
+by loading plugins into Yosys.
+
+\bigskip
+Use the following command to compile a Yosys plugin:
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont]
+yosys-config --exec --cxx --cxxflags --ldflags \
+ -o my_cmd.so -shared my_cmd.cc --ldlibs
+\end{lstlisting}
+
+\bigskip
+Load the plugin using the yosys {\tt -m} option:
+\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont]
+yosys -m ./my_cmd.so -p 'my_cmd foo bar'
+\end{lstlisting}
\end{frame}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -206,10 +560,12 @@ TBD
\begin{frame}{\subsecname}
\begin{itemize}
-\item TBD
-\item TBD
-\item TBD
-\item TBD
+\item Writing Yosys extensions is very straight-forward.
+\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
+part of the Yosys framework.
\end{itemize}
\bigskip