diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | frontends/ast/genrtlil.cc | 3 | ||||
-rw-r--r-- | manual/APPNOTE_011_Design_Investigation.tex | 239 | ||||
-rw-r--r-- | manual/APPNOTE_011_Design_Investigation/.gitignore | 4 | ||||
-rw-r--r-- | manual/APPNOTE_011_Design_Investigation/example.v | 5 | ||||
-rw-r--r-- | manual/APPNOTE_011_Design_Investigation/example.ys | 6 | ||||
-rw-r--r-- | manual/APPNOTE_011_Design_Investigation/make.sh | 8 | ||||
-rw-r--r-- | manual/APPNOTE_011_Design_Investigation/splice.v | 9 | ||||
-rw-r--r-- | manual/make_appnotes.sh | 4 | ||||
-rw-r--r-- | passes/cmds/select.cc | 79 | ||||
-rw-r--r-- | passes/cmds/show.cc | 91 |
11 files changed, 399 insertions, 51 deletions
@@ -146,7 +146,7 @@ clean: rm -f $(OBJS) $(GENFILES) $(TARGETS) rm -f kernel/version_*.o kernel/version_*.cc abc/abc-[0-9a-f]* rm -f libs/*/*.d frontends/*/*.d passes/*/*.d backends/*/*.d kernel/*.d - cd manual && rm -f *.aux *.bbl *.blg *.idx *.log *.out *.pdf *.toc + cd manual && rm -f *.aux *.bbl *.blg *.idx *.log *.out *.pdf *.toc *.ok test ! -f libs/svgviewer/Makefile || make -C libs/svgviewer distclean mrproper: clean diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index f7e7b852c..1453d13a9 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -265,6 +265,7 @@ struct AST_INTERNAL::ProcessGenerator { // generate process and simple root case proc = new RTLIL::Process; + proc->attributes["\\src"] = stringf("%s:%d", always->filename.c_str(), always->linenum); proc->name = stringf("$proc$%s:%d$%d", always->filename.c_str(), always->linenum, RTLIL::autoidx++); for (auto &attr : always->attributes) { if (attr.second->type != AST_CONSTANT) @@ -360,6 +361,8 @@ struct AST_INTERNAL::ProcessGenerator do { wire->name = stringf("$%d%s[%d:%d]", new_temp_count[chunk.wire]++, chunk.wire->name.c_str(), chunk.width+chunk.offset-1, chunk.offset);; + if (chunk.wire->name.find('$') != std::string::npos) + wire->name += stringf("$%d", RTLIL::autoidx++); } while (current_module->wires.count(wire->name) > 0); wire->width = chunk.width; current_module->wires[wire->name] = wire; diff --git a/manual/APPNOTE_011_Design_Investigation.tex b/manual/APPNOTE_011_Design_Investigation.tex new file mode 100644 index 000000000..9791ef797 --- /dev/null +++ b/manual/APPNOTE_011_Design_Investigation.tex @@ -0,0 +1,239 @@ + +% IEEEtran howto: +% http://ftp.univie.ac.at/packages/tex/macros/latex/contrib/IEEEtran/IEEEtran_HOWTO.pdf +\documentclass[9pt,technote,a4paper]{IEEEtran} + +\usepackage[T1]{fontenc} % required for luximono! +\usepackage[scaled=0.8]{luximono} % typewriter font with bold face + +% To install the luximono font files: +% getnonfreefonts-sys --all or +% getnonfreefonts-sys luximono +% +% when there are trouble you might need to: +% - Create /etc/texmf/updmap.d/99local-luximono.cfg +% containing the single line: Map ul9.map +% - Run update-updmap followed by mktexlsr and updmap-sys +% +% This commands must be executed as root with a root environment +% (i.e. run "sudo su" and then execute the commands in the root +% shell, don't just prefix the commands with "sudo"). + +\usepackage[unicode,bookmarks=false]{hyperref} +\usepackage[english]{babel} +\usepackage[utf8]{inputenc} +\usepackage{amssymb} +\usepackage{amsmath} +\usepackage{amsfonts} +\usepackage{units} +\usepackage{nicefrac} +\usepackage{eurosym} +\usepackage{graphicx} +\usepackage{verbatim} +\usepackage{algpseudocode} +\usepackage{scalefnt} +\usepackage{xspace} +\usepackage{color} +\usepackage{colortbl} +\usepackage{multirow} +\usepackage{hhline} +\usepackage{listings} +\usepackage{float} + +\usepackage{tikz} +\usetikzlibrary{calc} +\usetikzlibrary{arrows} +\usetikzlibrary{scopes} +\usetikzlibrary{through} +\usetikzlibrary{shapes.geometric} + +\def\FIXME{{\color{red}\bf FIXME}} + +\lstset{basicstyle=\ttfamily,frame=trBL,xleftmargin=2em,xrightmargin=1em,numbers=left} + +\begin{document} + +\title{Yosys Application Note 011: \\ Interactive Design Investigation} +\author{Clifford Wolf \\ November 2013} +\maketitle + +\begin{abstract} +Yosys \cite{yosys} can be a great environment for building custom synthesis +flows \cite{glaserwolf}. It can also be an excellent tool for teaching and +learning Verilog based RTL synthesis. In both applications it is of great +importance to be able to analyze the designs produces easily. + +This Yosys application note covers the generation of circuit diagrams with the +Yosys {\tt show} command and the selection of interesting parts of the circuit +using the {\tt select} command. +\end{abstract} + +\section{Installation and Prerequisites} + +This Application Note is based on GIT Rev. {\tt \FIXME} from \FIXME{} of +Yosys \cite{yosys}. The {\tt README} file covers how to install Yosys. The +{\tt show} command requires a working installation of GraphViz \cite{graphviz} +for generating the actual circuit diagrams. Yosys must be build with Qt +support in order to activate the built-in SVG viewer. Alternatively an +external viewer can be used. + +\section{Introduction to the {\tt show} command} + +The {\tt show} command generates a circuit diagram for the design in its +current state. Various options can be used to change the appearance of the +circuit diagram, set the name and format for the output file, and so forth. +When called without any special options, it saves the circuit diagram in +a temporary file and launches {\tt yosys-svgviewer} to display the diagram. +Subsequent calls to {\tt show} re-use the {\tt yosys-svgviewer} instance +(if still running). + +Fig.~\ref{example_src} shows a simple synthesis script and Verilog file that +demonstrates the usage of {\tt show} in a simple setting. Note that {\tt show} +is called with the {\tt -pause} option, that halts execution of the Yosys +script until the user presses the Enter key. The {\tt show -pause} command +also allows the user to enter an interactive shell to further investigate the +circuit before continuing synthesis. + +\begin{figure}[b] +\begin{lstlisting} +$ cat example.ys +read_verilog example.v +show -pause +proc +show -pause +opt +show -pause + +$ cat example.v +module example(input clk, a, b, c, + output reg [1:0] y); + always @(posedge clk) + if (c) + y <= c ? a + b : 2'd0; +endmodule +\end{lstlisting} +\caption{Yosys script with {\tt show} commands and example design} +\label{example_src} +\end{figure} + +So this script, when executed, will show the design after each of the three +synthesis commands. The generated circuit diagrams are shown in Fig.~\ref{example_out}. + +The first diagram (from top to bottom) shows the design directly after being +read by the Verilog front-end. Input and output ports are visualized using +octagonal shapes. Cells are visualized as rectangles with inputs on the left +and outputs on the right side. The cell labels are two lines long: The first line +contains the cell name (or a {\tt \_<number\_} placeholder for cells without +a name from the original Verilog, such as cells created from Verilog +expressions) and the second line contains the cell type. Internal cell types +are prefixed with a dollar sign. The Yosys manual contains a chapter on the +internal cell library used in Yosys. + +Constants are shown as ellipses with the constant value as label. The syntax +{\tt <bit\_width>'<bits>} is used for for constants that are not 32-bit wide +and/or contain bits that are not 0 or 1 (but {\tt x} or {\tt z}). Ordinary +32-bit constants are written using decimal numbers. + +Single-bit signals are shown as thin arrows pointing from the driver to the +load. Signals that are multiple bits wide are shown as think arrows. + +Finally {\it processes\/} are shown in boxes with round corners. Processes +are Yosys' internal representation of the decision-trees and synchronization +events modelled in a Verilog {\tt always}-block. The label reads {\tt PROC} in the +first line and contains the source code location of the original {\tt +always}-block in the 2nd line. Not how the multiplexer from the {\tt ?:}-expression +is represented as a {\tt \$mux} cell but the multiplexer from the {\tt if}-statement +is yet still hidden within the process. + +\medskip + +The {\tt proc} command transforms the process from the first diagram into a +multiplexer and a d-type flip-flip, which brings us to the 2nd diagram. + +Note that the auto-generated numbers for the cells have changed since the first +diagram, because they are just placeholders . We will cover how to avoid this +later in this document. + + +\begin{figure}[b!] +\includegraphics[width=\linewidth]{APPNOTE_011_Design_Investigation/example_00.pdf} +\includegraphics[width=\linewidth]{APPNOTE_011_Design_Investigation/example_01.pdf} +\includegraphics[width=\linewidth]{APPNOTE_011_Design_Investigation/example_02.pdf} +\caption{Output of the three {\tt show} commands from Fig.~\ref{example_src}} +\label{example_out} +\end{figure} + +Also note that the design now contains two instances of a {\tt BUF}-node. The +Rhombus shape to the right is a dangling wire. (Wire nodes are only shown if +they are dangling or have names assigned from the Verilog input.) This are +artefacts left behind by the {\tt proc}-command. It is quite usual to see such +artefacts after calling commands that perform changes in the design, as most +commands only care about doing the transformation in a foolproof way, not about +cleaning up after them. The next call to {\tt clean} (or {\tt opt}, which +includes {\tt clean} as one of its operations) will clean up this artefacts. +This operation is so common in Yosys scripts that it can simply be abbreviated +by using the {\tt ;;} token, which doubles as separator for commands. Unless +one wants to specifically analyze this artefacts left behind some operations, +it is therefore recommended to call {\tt clean} before calling {\tt show}. + +\medskip + +In this script we directly call {\tt opt} as next step, which finally leads us to +the 3rd diagram in Fig.~\ref{example_out}. Here we see that the {\tt opt} command +not only has removed the artifacts left behind by {\tt proc}, but also determined +correctly that it can remove the first {\tt \$mux} cell without changing the behavior +of the circuit. + +\begin{figure}[b!] +\includegraphics[width=\linewidth,trim=0 2cm 0 0]{APPNOTE_011_Design_Investigation/splice.pdf} +\caption{Output of {\tt yosys -p 'proc; opt; show' splice.v}} +\label{example_src} +\end{figure} + +\begin{figure}[b!] +\begin{lstlisting} +module splice_demo(a, b, c, d, e, f, x, y); + +input [1:0] a, b, c, d, e, f; +output [1:0] x = {a[0], a[1]}; + +output [11:0] y; +assign {y[11:4], y[1:0], y[3:2]} = + {a, b, -{c, d}, ~{e, f}}; + +endmodule +\end{lstlisting} +\caption{\tt splice.v} +\label{example_src} +\end{figure} + +\FIXME{} --- Splicing, Cell libraries + +\section{Navigating the design} + +\FIXME{} --- cd and ls, multi-page diagrams, select, cones and boolean operations + +\section{Advanced investigation techniques} + +\FIXME{} --- dump, eval, sat + +\begin{thebibliography}{9} + +\bibitem{yosys} +Clifford Wolf. The Yosys Open SYnthesis Suite. +\url{http://www.clifford.at/yosys/} + +\bibitem{glaserwolf} +Johann Glaser. Clifford Wolf. Methodology and Example-Driven Interconnect +Synthesis for Designing Heterogeneous Coarse-Grain Reconfigurable +Architectures. In: Jan Haase (Editor). {\it Models, Methods, and Tools for Complex Chip Design. +Lecture Notes in Electrical Engineering. Volume 265, 2014, pp 201-221.\/} +\href{http://dx.doi.org/10.1007/978-3-319-01418-0_12}{DOI 10.1007/978-3-319-01418-0\_12} + +\bibitem{graphviz} +Graphviz - Graph Visualization Software. +\url{http://www.graphviz.org/} + +\end{thebibliography} + +\end{document} diff --git a/manual/APPNOTE_011_Design_Investigation/.gitignore b/manual/APPNOTE_011_Design_Investigation/.gitignore new file mode 100644 index 000000000..b6fb30680 --- /dev/null +++ b/manual/APPNOTE_011_Design_Investigation/.gitignore @@ -0,0 +1,4 @@ +example_00.dot +example_01.dot +example_02.dot +splice.dot diff --git a/manual/APPNOTE_011_Design_Investigation/example.v b/manual/APPNOTE_011_Design_Investigation/example.v new file mode 100644 index 000000000..ec272011c --- /dev/null +++ b/manual/APPNOTE_011_Design_Investigation/example.v @@ -0,0 +1,5 @@ +module example(input clk, a, b, c, output reg [1:0] y); +always @(posedge clk) + if (c) + y <= c ? a + b : 2'd0; +endmodule diff --git a/manual/APPNOTE_011_Design_Investigation/example.ys b/manual/APPNOTE_011_Design_Investigation/example.ys new file mode 100644 index 000000000..6c9ff7983 --- /dev/null +++ b/manual/APPNOTE_011_Design_Investigation/example.ys @@ -0,0 +1,6 @@ +read_verilog example.v +show -format dot -prefix example_00 +proc +show -format dot -prefix example_01 +opt +show -format dot -prefix example_02 diff --git a/manual/APPNOTE_011_Design_Investigation/make.sh b/manual/APPNOTE_011_Design_Investigation/make.sh new file mode 100644 index 000000000..60c6c6be3 --- /dev/null +++ b/manual/APPNOTE_011_Design_Investigation/make.sh @@ -0,0 +1,8 @@ +#!/bin/bash +../../yosys example.ys +../../yosys -p 'proc; opt; show -format dot -prefix splice' splice.v +sed -i '/^label=/ d;' example_*.dot splice.dot +dot -Tpdf -o example_00.pdf example_00.dot +dot -Tpdf -o example_01.pdf example_01.dot +dot -Tpdf -o example_02.pdf example_02.dot +dot -Tpdf -o splice.pdf splice.dot diff --git a/manual/APPNOTE_011_Design_Investigation/splice.v b/manual/APPNOTE_011_Design_Investigation/splice.v new file mode 100644 index 000000000..b6796c516 --- /dev/null +++ b/manual/APPNOTE_011_Design_Investigation/splice.v @@ -0,0 +1,9 @@ +module splice_demo(a, b, c, d, e, f, x, y); + +input [1:0] a, b, c, d, e, f; +output [1:0] x = {a[0], a[1]}; + +output [11:0] y; +assign {y[11:4], y[1:0], y[3:2]} = {a, b, -{c, d}, ~{e, f}}; + +endmodule diff --git a/manual/make_appnotes.sh b/manual/make_appnotes.sh index 00f875760..478e4cf9e 100644 --- a/manual/make_appnotes.sh +++ b/manual/make_appnotes.sh @@ -1,10 +1,10 @@ #!/bin/bash set -ex -for job in APPNOTE_010_Verilog_to_BLIF +for job in APPNOTE_010_Verilog_to_BLIF APPNOTE_011_Design_Investigation do [ -f $job.ok -a $job.ok -nt $job.tex ] && continue - old_md5=$([ -f $job.aux ] && md5sum < $job.aux) + old_md5=$([ -f $job.aux ] && md5sum < $job.aux || true) while pdflatex -shell-escape -halt-on-error $job.tex new_md5=$(md5sum < $job.aux) diff --git a/passes/cmds/select.cc b/passes/cmds/select.cc index 1ab15c9a9..c424966ff 100644 --- a/passes/cmds/select.cc +++ b/passes/cmds/select.cc @@ -29,10 +29,20 @@ static std::vector<RTLIL::Selection> work_stack; static bool match_ids(RTLIL::IdString id, std::string pattern) { - if (!fnmatch(pattern.c_str(), id.c_str(), FNM_NOESCAPE)) + if (id == pattern) return true; - if (id.size() > 0 && id[0] == '\\' && !fnmatch(pattern.c_str(), id.substr(1).c_str(), FNM_NOESCAPE)) + if (id.size() > 0 && id[0] == '\\' && id.substr(1) == pattern) return true; + if (!fnmatch(pattern.c_str(), id.c_str(), 0)) + return true; + if (id.size() > 0 && id[0] == '\\' && !fnmatch(pattern.c_str(), id.substr(1).c_str(), 0)) + return true; + if (id.size() > 0 && id[0] == '$' && pattern.size() > 0 && pattern[0] == '$') { + const char *p = id.c_str(); + const char *q = strrchr(p, '$'); + if (pattern == q) + return true; + } return false; } @@ -993,6 +1003,24 @@ struct CdPass : public Pass { log_cmd_error("No such module `%s' found!\n", RTLIL::id2cstr(modname)); } } CdPass; + +template<typename T> +static int log_matches(const char *title, std::string pattern, T list) +{ + std::vector<std::string> matches; + + for (auto &it : list) + if (pattern.empty() || match_ids(it.first, pattern)) + matches.push_back(it.first); + + if (matches.empty()) + return 0; + + log("\n%d %s:\n", int(matches.size()), title); + for (auto &id : matches) + log(" %s\n", RTLIL::id2cstr(id)); + return matches.size(); +} struct LsPass : public Pass { LsPass() : Pass("ls", "list modules or objects in modules") { } @@ -1000,53 +1028,40 @@ struct LsPass : public Pass { { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" ls\n"); + log(" ls [pattern]\n"); log("\n"); - log("When no active module is selected, this prints a list of all module.\n"); + log("When no active module is selected, this prints a list of all modules.\n"); log("\n"); log("When an active module is selected, this prints a list of objects in the module.\n"); log("\n"); + log("If a pattern is given, the objects matching the pattern are printed\n"); + log("\n"); } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - if (args.size() != 1) + std::string pattern; + int counter = 0; + + if (args.size() != 1 && args.size() != 2) log_cmd_error("Invalid number of arguments.\n"); + if (args.size() == 2) + pattern = args.at(1); if (design->selected_active_module.empty()) { - log("\n%d modules:\n", int(design->modules.size())); - for (auto &it : design->modules) - log(" %s\n", RTLIL::id2cstr(it.first)); + counter += log_matches("modules", pattern, design->modules); } else if (design->modules.count(design->selected_active_module) > 0) { RTLIL::Module *module = design->modules.at(design->selected_active_module); - - if (module->wires.size()) { - log("\n%d wires:\n", int(module->wires.size())); - for (auto &it : module->wires) - log(" %s\n", RTLIL::id2cstr(it.first)); - } - - if (module->memories.size()) { - log("\n%d memories:\n", int(module->memories.size())); - for (auto &it : module->memories) - log(" %s\n", RTLIL::id2cstr(it.first)); - } - - if (module->cells.size()) { - log("\n%d cells:\n", int(module->cells.size())); - for (auto &it : module->cells) - log(" %s\n", RTLIL::id2cstr(it.first)); - } - - if (module->processes.size()) { - log("\n%d processes:\n", int(module->processes.size())); - for (auto &it : module->processes) - log(" %s\n", RTLIL::id2cstr(it.first)); - } + counter += log_matches("wires", pattern, module->wires); + counter += log_matches("memories", pattern, module->memories); + counter += log_matches("cells", pattern, module->cells); + counter += log_matches("processes", pattern, module->processes); } + + // log("\nfound %d item%s.\n", counter, counter == 1 ? "" : "s"); } } LsPass; diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc index adb925cb9..fc3575c62 100644 --- a/passes/cmds/show.cc +++ b/passes/cmds/show.cc @@ -22,6 +22,7 @@ #include "kernel/log.h" #include <string.h> #include <dirent.h> +#include <readline/readline.h> using RTLIL::id2cstr; @@ -45,6 +46,8 @@ struct ShowWorker uint32_t currentColor; bool genWidthLabels; bool stretchIO; + bool enumerateIds; + bool abbreviateIds; int page_counter; const std::vector<std::pair<std::string, RTLIL::Selection>> &color_selections; @@ -113,11 +116,17 @@ struct ShowWorker return ""; if (id[0] == '$' && is_name) { - if (autonames.count(id) == 0) { - autonames[id] = autonames.size() + 1; - log("Generated short name for internal identifier: _%d_ -> %s\n", autonames[id], id.c_str()); + if (enumerateIds) { + if (autonames.count(id) == 0) { + autonames[id] = autonames.size() + 1; + log("Generated short name for internal identifier: _%d_ -> %s\n", autonames[id], id.c_str()); + } + id = stringf("_%d_", autonames[id]); + } else if (abbreviateIds) { + const char *p = id.c_str(); + const char *q = strrchr(p, '$'); + id = std::string(q); } - id = stringf("_%d_", autonames[id]); } if (id[0] == '\\') @@ -376,6 +385,8 @@ struct ShowWorker code += gen_portbox("", sig, false, &node); fprintf(f, "%s", code.c_str()); net_conn_map[node].out.insert(stringf("p%d", pidx)); + net_conn_map[node].bits = sig.width; + net_conn_map[node].color = nextColor(sig, net_conn_map[node].color); } for (auto &sig : output_signals) { @@ -383,9 +394,14 @@ struct ShowWorker code += gen_portbox("", sig, true, &node); fprintf(f, "%s", code.c_str()); net_conn_map[node].in.insert(stringf("p%d", pidx)); + net_conn_map[node].bits = sig.width; + net_conn_map[node].color = nextColor(sig, net_conn_map[node].color); } - fprintf(f, "p%d [shape=box, style=rounded, label=\"PROC\\n%s\"];\n", pidx, RTLIL::id2cstr(proc->name)); + std::string proc_src = RTLIL::unescape_id(proc->name); + if (proc->attributes.count("\\src") > 0) + proc_src = proc->attributes.at("\\src").str; + fprintf(f, "p%d [shape=box, style=rounded, label=\"PROC %s\\n%s\"];\n", pidx, escape(proc->name, true), proc_src.c_str()); } for (auto &conn : module->connections) @@ -410,8 +426,8 @@ struct ShowWorker if (left_node[0] == 'x' && right_node[0] == 'x') { currentColor = xorshift32(currentColor); - fprintf(f, "%s:e -> %s:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, %s, %s];\n", left_node.c_str(), right_node.c_str(), nextColor(conn).c_str(), widthLabel(conn.first.width).c_str()); - } else { + fprintf(f, "%s:e -> %s:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, %s, %s];\n", left_node.c_str(), right_node.c_str(), nextColor(conn).c_str(), widthLabel(conn.first.width).c_str()); + } else { net_conn_map[right_node].bits = conn.first.width; net_conn_map[right_node].color = nextColor(conn, net_conn_map[right_node].color); net_conn_map[left_node].bits = conn.first.width; @@ -454,10 +470,12 @@ struct ShowWorker fprintf(f, "};\n"); } - ShowWorker(FILE *f, RTLIL::Design *design, std::vector<RTLIL::Design*> &libs, uint32_t colorSeed, bool genWidthLabels, bool stretchIO, + ShowWorker(FILE *f, RTLIL::Design *design, std::vector<RTLIL::Design*> &libs, uint32_t colorSeed, + bool genWidthLabels, bool stretchIO, bool enumerateIds, bool abbreviateIds, const std::vector<std::pair<std::string, RTLIL::Selection>> &color_selections, const std::vector<std::pair<std::string, RTLIL::Selection>> &label_selections) : - f(f), design(design), currentColor(colorSeed), genWidthLabels(genWidthLabels), stretchIO(stretchIO), + f(f), design(design), currentColor(colorSeed), genWidthLabels(genWidthLabels), + stretchIO(stretchIO), enumerateIds(enumerateIds), abbreviateIds(abbreviateIds), color_selections(color_selections), label_selections(label_selections) { ct.setup_internals(); @@ -536,6 +554,15 @@ struct ShowPass : public Pass { log(" stretch the graph so all inputs are on the left side and all outputs\n"); log(" (including inout ports) are on the right side.\n"); log("\n"); + log(" -pause\n"); + log(" wait for the use to press enter to before returning\n"); + log("\n"); + log(" -enum\n"); + log(" enumerate objects with internal ($-prefixed) names\n"); + log("\n"); + log(" -long\n"); + log(" do not abbeviate objects with internal ($-prefixed) names\n"); + log("\n"); log("When no <format> is specified, SVG is used. When no <format> and <viewer> is\n"); log("specified, 'yosys-svgviewer' is used to display the schematic.\n"); log("\n"); @@ -559,6 +586,9 @@ struct ShowPass : public Pass { uint32_t colorSeed = 0; bool flag_width = false; bool flag_stretch = false; + bool flag_pause = false; + bool flag_enum = false; + bool flag_abbeviate = true; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -610,6 +640,20 @@ struct ShowPass : public Pass { flag_stretch= true; continue; } + if (arg == "-pause") { + flag_pause= true; + continue; + } + if (arg == "-enum") { + flag_enum = true; + flag_abbeviate = false; + continue; + } + if (arg == "-long") { + flag_enum = false; + flag_abbeviate = false; + continue; + } break; } extra_args(args, argidx, design); @@ -651,7 +695,7 @@ struct ShowPass : public Pass { delete lib; log_cmd_error("Can't open dot file `%s' for writing.\n", dot_file.c_str()); } - ShowWorker worker(f, design, libs, colorSeed, flag_width, flag_stretch, color_selections, label_selections); + ShowWorker worker(f, design, libs, colorSeed, flag_width, flag_stretch, flag_enum, flag_abbeviate, color_selections, label_selections); fclose(f); for (auto lib : libs) @@ -660,24 +704,39 @@ struct ShowPass : public Pass { if (worker.page_counter == 0) log_cmd_error("Nothing there to show.\n"); - std::string cmd = stringf("dot -T%s -o '%s' '%s'", format.empty() ? "svg" : format.c_str(), out_file.c_str(), dot_file.c_str()); - log("Exec: %s\n", cmd.c_str()); - if (system(cmd.c_str()) != 0) - log_cmd_error("Shell command failed!\n"); + if (format != "dot") { + std::string cmd = stringf("dot -T%s -o '%s' '%s'", format.empty() ? "svg" : format.c_str(), out_file.c_str(), dot_file.c_str()); + log("Exec: %s\n", cmd.c_str()); + if (system(cmd.c_str()) != 0) + log_cmd_error("Shell command failed!\n"); + } if (!viewer_exe.empty()) { - cmd = stringf("%s '%s' &", viewer_exe.c_str(), out_file.c_str()); + std::string cmd = stringf("%s '%s' &", viewer_exe.c_str(), out_file.c_str()); log("Exec: %s\n", cmd.c_str()); if (system(cmd.c_str()) != 0) log_cmd_error("Shell command failed!\n"); } else if (format.empty()) { - cmd = stringf("fuser -s '%s' || '%s' '%s' &", out_file.c_str(), rewrite_yosys_exe("yosys-svgviewer").c_str(), out_file.c_str()); + std::string cmd = stringf("fuser -s '%s' || '%s' '%s' &", out_file.c_str(), rewrite_yosys_exe("yosys-svgviewer").c_str(), out_file.c_str()); log("Exec: %s\n", cmd.c_str()); if (system(cmd.c_str()) != 0) log_cmd_error("Shell command failed!\n"); } + if (flag_pause) { + char *input = NULL; + while ((input = readline("Press ENTER to continue (or type 'shell' to open a shell)> ")) != NULL) { + if (input[strspn(input, " \t\r\n")] == 0) + break; + char *p = input + strspn(input, " \t\r\n"); + if (!strcmp(p, "shell")) { + Pass::call(design, "shell"); + break; + } + } + } + log_pop(); } } ShowPass; |