3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-06-11 00:23:26 +00:00
This commit is contained in:
Andrew Zonenberg 2016-04-01 00:03:00 -07:00
commit f277267916
21 changed files with 439 additions and 366 deletions

View file

@ -22,7 +22,7 @@ hierarchy -top $3;
hierarchy -libdir $DIR; hierarchy -libdir $DIR;
hierarchy -check; hierarchy -check;
proc; proc;
opt; opt_const -mux_undef; opt; opt; opt_expr -mux_undef; opt;
rename -hide;;; rename -hide;;;
#techmap -map +/pmux2mux.v;; #techmap -map +/pmux2mux.v;;
splice; opt; splice; opt;

View file

@ -230,6 +230,32 @@ static inline void log_dump_args_worker(const char *p YS_ATTRIBUTE(unused)) { lo
void log_dump_val_worker(RTLIL::IdString v); void log_dump_val_worker(RTLIL::IdString v);
void log_dump_val_worker(RTLIL::SigSpec v); void log_dump_val_worker(RTLIL::SigSpec v);
template<typename K, typename T, typename OPS>
static inline void log_dump_val_worker(dict<K, T, OPS> &v) {
log("{");
bool first = true;
for (auto &it : v) {
log(first ? " " : ", ");
log_dump_val_worker(it.first);
log(": ");
log_dump_val_worker(it.second);
first = false;
}
log(" }");
}
template<typename K, typename OPS>
static inline void log_dump_val_worker(pool<K, OPS> &v) {
log("{");
bool first = true;
for (auto &it : v) {
log(first ? " " : ", ");
log_dump_val_worker(it);
first = false;
}
log(" }");
}
template<typename T> template<typename T>
static inline void log_dump_val_worker(T *ptr) { log("%p", ptr); } static inline void log_dump_val_worker(T *ptr) { log("%p", ptr); }

View file

@ -80,6 +80,7 @@ Pass::pre_post_exec_state_t Pass::pre_execute()
state.begin_ns = PerformanceTimer::query(); state.begin_ns = PerformanceTimer::query();
state.parent_pass = current_pass; state.parent_pass = current_pass;
current_pass = this; current_pass = this;
clear_flags();
return state; return state;
} }
@ -99,6 +100,10 @@ void Pass::help()
log("\n"); log("\n");
} }
void Pass::clear_flags()
{
}
void Pass::cmd_log_args(const std::vector<std::string> &args) void Pass::cmd_log_args(const std::vector<std::string> &args)
{ {
if (args.size() <= 1) if (args.size() <= 1)
@ -282,6 +287,60 @@ void Pass::call_on_module(RTLIL::Design *design, RTLIL::Module *module, std::vec
design->selected_active_module = backup_selected_active_module; design->selected_active_module = backup_selected_active_module;
} }
bool ScriptPass::check_label(std::string label, std::string info)
{
if (active_design == nullptr) {
log("\n");
if (info.empty())
log(" %s:\n", label.c_str());
else
log(" %s: %s\n", label.c_str(), info.c_str());
return true;
} else {
if (!active_run_from.empty() && active_run_from == active_run_to) {
block_active = (label == active_run_from);
} else {
if (label == active_run_from)
block_active = true;
if (label == active_run_to)
block_active = false;
}
return block_active;
}
}
void ScriptPass::run(std::string command, std::string info)
{
if (active_design == nullptr) {
if (info.empty())
log(" %s\n", command.c_str());
else
log(" %s %s\n", command.c_str(), info.c_str());
} else
Pass::call(active_design, command);
}
void ScriptPass::run_script(RTLIL::Design *design, std::string run_from, std::string run_to)
{
help_mode = false;
active_design = design;
block_active = run_from.empty();
active_run_from = run_from;
active_run_to = run_to;
script();
}
void ScriptPass::help_script()
{
clear_flags();
help_mode = true;
active_design = nullptr;
block_active = true;
active_run_from.clear();
active_run_to.clear();
script();
}
Frontend::Frontend(std::string name, std::string short_help) : Frontend::Frontend(std::string name, std::string short_help) :
Pass(name.rfind("=", 0) == 0 ? name.substr(1) : "read_" + name, short_help), Pass(name.rfind("=", 0) == 0 ? name.substr(1) : "read_" + name, short_help),
frontend_name(name.rfind("=", 0) == 0 ? name.substr(1) : name) frontend_name(name.rfind("=", 0) == 0 ? name.substr(1) : name)

View file

@ -31,6 +31,7 @@ struct Pass
virtual ~Pass(); virtual ~Pass();
virtual void help(); virtual void help();
virtual void clear_flags();
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) = 0; virtual void execute(std::vector<std::string> args, RTLIL::Design *design) = 0;
int call_counter; int call_counter;
@ -63,6 +64,22 @@ struct Pass
static void done_register(); static void done_register();
}; };
struct ScriptPass : Pass
{
bool block_active, help_mode;
RTLIL::Design *active_design;
std::string active_run_from, active_run_to;
ScriptPass(std::string name, std::string short_help = "** document me **") : Pass(name, short_help) { }
virtual void script() = 0;
bool check_label(std::string label, std::string info = std::string());
void run(std::string command, std::string info = std::string());
void run_script(RTLIL::Design *design, std::string run_from = std::string(), std::string run_to = std::string());
void help_script();
};
struct Frontend : Pass struct Frontend : Pass
{ {
// for reading of here documents // for reading of here documents

View file

@ -1100,8 +1100,8 @@ struct HistoryPass : public Pass {
} HistoryPass; } HistoryPass;
#endif #endif
struct ScriptPass : public Pass { struct ScriptCmdPass : public Pass {
ScriptPass() : Pass("script", "execute commands from script file") { } ScriptCmdPass() : Pass("script", "execute commands from script file") { }
virtual void help() { virtual void help() {
log("\n"); log("\n");
log(" script <filename> [<from_label>:<to_label>]\n"); log(" script <filename> [<from_label>:<to_label>]\n");
@ -1127,7 +1127,7 @@ struct ScriptPass : public Pass {
else else
extra_args(args, 2, design, false); extra_args(args, 2, design, false);
} }
} ScriptPass; } ScriptCmdPass;
YOSYS_NAMESPACE_END YOSYS_NAMESPACE_END

View file

@ -208,7 +208,7 @@ read_verilog -sv $1;
hierarchy -top $3; hierarchy -libdir $DIR; hierarchy -top $3; hierarchy -libdir $DIR;
hierarchy -check; hierarchy -check;
proc; opt; proc; opt;
opt_const -mux_undef; opt; opt_expr -mux_undef; opt;
rename -hide;;; rename -hide;;;
splice; opt; splice; opt;
memory_dff -wr_only; memory_collect;; memory_dff -wr_only; memory_collect;;
@ -263,7 +263,7 @@ read_verilog -sv $1;
hierarchy -top $3; hierarchy -libdir $DIR; hierarchy -top $3; hierarchy -libdir $DIR;
hierarchy -check; hierarchy -check;
proc; opt; proc; opt;
opt_const -mux_undef; opt; opt_expr -mux_undef; opt;
rename -hide;;; rename -hide;;;
splice; opt; splice; opt;
memory;; memory;;

View file

@ -15,23 +15,23 @@ passes that each perform a simple optimization:
\begin{itemize} \begin{itemize}
\item Once at the beginning of {\tt opt}: \item Once at the beginning of {\tt opt}:
\begin{itemize} \begin{itemize}
\item {\tt opt\_const} \item {\tt opt\_expr}
\item {\tt opt\_share -nomux} \item {\tt opt\_merge -nomux}
\end{itemize} \end{itemize}
\item Repeat until result is stable: \item Repeat until result is stable:
\begin{itemize} \begin{itemize}
\item {\tt opt\_muxtree} \item {\tt opt\_muxtree}
\item {\tt opt\_reduce} \item {\tt opt\_reduce}
\item {\tt opt\_share} \item {\tt opt\_merge}
\item {\tt opt\_rmdff} \item {\tt opt\_rmdff}
\item {\tt opt\_clean} \item {\tt opt\_clean}
\item {\tt opt\_const} \item {\tt opt\_expr}
\end{itemize} \end{itemize}
\end{itemize} \end{itemize}
The following section describes each of the {\tt opt\_*} passes. The following section describes each of the {\tt opt\_*} passes.
\subsection{The opt\_const pass} \subsection{The opt\_expr pass}
This pass performs const folding on the internal combinational cell types This pass performs const folding on the internal combinational cell types
described in Chap.~\ref{chapter:celllib}. This means a cell with all constant described in Chap.~\ref{chapter:celllib}. This means a cell with all constant
@ -57,11 +57,11 @@ this pass can also optimize cells with some constant inputs.
$a$ & 1 & $a$ \\ $a$ & 1 & $a$ \\
1 & $b$ & $b$ \\ 1 & $b$ & $b$ \\
\end{tabular} \end{tabular}
\caption{Const folding rules for {\tt\$\_AND\_} cells as used in {\tt opt\_const}.} \caption{Const folding rules for {\tt\$\_AND\_} cells as used in {\tt opt\_expr}.}
\label{tab:opt_const_and} \label{tab:opt_expr_and}
\end{table} \end{table}
Table~\ref{tab:opt_const_and} shows the replacement rules used for optimizing Table~\ref{tab:opt_expr_and} shows the replacement rules used for optimizing
an {\tt\$\_AND\_} gate. The first three rules implement the obvious const folding an {\tt\$\_AND\_} gate. The first three rules implement the obvious const folding
rules. Note that `any' might include dynamic values calculated by other parts rules. Note that `any' might include dynamic values calculated by other parts
of the circuit. The following three lines propagate undef (X) states. of the circuit. The following three lines propagate undef (X) states.
@ -76,10 +76,10 @@ an undef value or a 1 and therefore the output can be set to undef.
The last two lines simply replace an {\tt\$\_AND\_} gate with one constant-1 The last two lines simply replace an {\tt\$\_AND\_} gate with one constant-1
input with a buffer. input with a buffer.
Besides this basic const folding the {\tt opt\_const} pass can replace 1-bit wide Besides this basic const folding the {\tt opt\_expr} pass can replace 1-bit wide
{\tt \$eq} and {\tt \$ne} cells with buffers or not-gates if one input is constant. {\tt \$eq} and {\tt \$ne} cells with buffers or not-gates if one input is constant.
The {\tt opt\_const} pass is very conservative regarding optimizing {\tt \$mux} cells, The {\tt opt\_expr} pass is very conservative regarding optimizing {\tt \$mux} cells,
as these cells are often used to model decision-trees and breaking these trees can as these cells are often used to model decision-trees and breaking these trees can
interfere with other optimizations. interfere with other optimizations.
@ -130,7 +130,7 @@ This pass identifies unused signals and cells and removes them from the design.
creates an \B{unused\_bits} attribute on wires with unused bits. This attribute can be creates an \B{unused\_bits} attribute on wires with unused bits. This attribute can be
used for debugging or by other optimization passes. used for debugging or by other optimization passes.
\subsection{The opt\_share pass} \subsection{The opt\_merge pass}
This pass performs trivial resource sharing. This means that this pass identifies cells This pass performs trivial resource sharing. This means that this pass identifies cells
with identical inputs and replaces them with a single instance of the cell. with identical inputs and replaces them with a single instance of the cell.

View file

@ -488,8 +488,8 @@ select.cc}, {\tt show.cc}, \dots) and a couple of other small utility libraries.
\item {\tt passes/} \\ \item {\tt passes/} \\
This directory contains a subdirectory for each pass or group of passes. For example as This directory contains a subdirectory for each pass or group of passes. For example as
of this writing the directory {\tt passes/opt/} contains the code for seven of this writing the directory {\tt passes/opt/} contains the code for seven
passes: {\tt opt}, {\tt opt\_const}, {\tt opt\_muxtree}, {\tt opt\_reduce}, passes: {\tt opt}, {\tt opt\_expr}, {\tt opt\_muxtree}, {\tt opt\_reduce},
{\tt opt\_rmdff}, {\tt opt\_rmunused} and {\tt opt\_share}. {\tt opt\_rmdff}, {\tt opt\_rmunused} and {\tt opt\_merge}.
\item {\tt techlibs/} \\ \item {\tt techlibs/} \\
This directory contains simulation models and standard implementations for the This directory contains simulation models and standard implementations for the
@ -513,7 +513,7 @@ Yosys. So it is not needed to add additional commands to a central list of comma
\end{sloppypar} \end{sloppypar}
Good starting points for reading example source code to learn how to write passes Good starting points for reading example source code to learn how to write passes
are {\tt passes/opt/opt\_rmdff.cc} and {\tt passes/opt/opt\_share.cc}. are {\tt passes/opt/opt\_rmdff.cc} and {\tt passes/opt/opt\_merge.cc}.
See the top-level README file for a quick {\it Getting Started} guide and build See the top-level README file for a quick {\it Getting Started} guide and build
instructions. The Yosys build is based solely on Makefiles. instructions. The Yosys build is based solely on Makefiles.

View file

@ -144,16 +144,16 @@ The {\tt opt} command implements a series of simple optimizations. It also
is a macro command that calls other commands: is a macro command that calls other commands:
\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] \begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys]
opt_const # const folding opt_expr # const folding and simple expression rewriting
opt_share -nomux # merging identical cells opt_merge -nomux # merging identical cells
do do
opt_muxtree # remove never-active branches from multiplexer tree opt_muxtree # remove never-active branches from multiplexer tree
opt_reduce # consolidate trees of boolean ops to reduce functions opt_reduce # consolidate trees of boolean ops to reduce functions
opt_share # merging identical cells opt_merge # merging identical cells
opt_rmdff # remove/simplify registers with constant inputs opt_rmdff # remove/simplify registers with constant inputs
opt_clean # remove unused objects (cells, wires) from design opt_clean # remove unused objects (cells, wires) from design
opt_const # const folding opt_expr # const folding and simple expression rewriting
while [changed design] while [changed design]
\end{lstlisting} \end{lstlisting}
@ -161,7 +161,7 @@ The command {\tt clean} can be used as alias for {\tt opt\_clean}. And {\tt ;;}
can be used as shortcut for {\tt clean}. For example: can be used as shortcut for {\tt clean}. For example:
\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys] \begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys]
proc; opt; memory; opt_const;; fsm;; proc; opt; memory; opt_expr;; fsm;;
\end{lstlisting} \end{lstlisting}
\end{frame} \end{frame}

View file

@ -746,7 +746,7 @@ struct MemorySharePass : public Pass {
log("\n"); log("\n");
log("Note that in addition to the algorithms implemented in this pass, the $memrd\n"); log("Note that in addition to the algorithms implemented in this pass, the $memrd\n");
log("and $memwr cells are also subject to generic resource sharing passes (and other\n"); log("and $memwr cells are also subject to generic resource sharing passes (and other\n");
log("optimizations) such as opt_share.\n"); log("optimizations) such as \"share\" and \"opt_merge\".\n");
log("\n"); log("\n");
} }
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {

View file

@ -1,11 +1,11 @@
OBJS += passes/opt/opt.o OBJS += passes/opt/opt.o
OBJS += passes/opt/opt_share.o OBJS += passes/opt/opt_merge.o
OBJS += passes/opt/opt_muxtree.o OBJS += passes/opt/opt_muxtree.o
OBJS += passes/opt/opt_reduce.o OBJS += passes/opt/opt_reduce.o
OBJS += passes/opt/opt_rmdff.o OBJS += passes/opt/opt_rmdff.o
OBJS += passes/opt/opt_clean.o OBJS += passes/opt/opt_clean.o
OBJS += passes/opt/opt_const.o OBJS += passes/opt/opt_expr.o
ifneq ($(SMALL),1) ifneq ($(SMALL),1)
OBJS += passes/opt/share.o OBJS += passes/opt/share.o

View file

@ -37,23 +37,23 @@ struct OptPass : public Pass {
log("a series of trivial optimizations and cleanups. This pass executes the other\n"); log("a series of trivial optimizations and cleanups. This pass executes the other\n");
log("passes in the following order:\n"); log("passes in the following order:\n");
log("\n"); log("\n");
log(" opt_const [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n"); log(" opt_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
log(" opt_share [-share_all] -nomux\n"); log(" opt_merge [-share_all] -nomux\n");
log("\n"); log("\n");
log(" do\n"); log(" do\n");
log(" opt_muxtree\n"); log(" opt_muxtree\n");
log(" opt_reduce [-fine] [-full]\n"); log(" opt_reduce [-fine] [-full]\n");
log(" opt_share [-share_all]\n"); log(" opt_merge [-share_all]\n");
log(" opt_rmdff\n"); log(" opt_rmdff\n");
log(" opt_clean [-purge]\n"); log(" opt_clean [-purge]\n");
log(" opt_const [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n"); log(" opt_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
log(" while <changed design>\n"); log(" while <changed design>\n");
log("\n"); log("\n");
log("When called with -fast the following script is used instead:\n"); log("When called with -fast the following script is used instead:\n");
log("\n"); log("\n");
log(" do\n"); log(" do\n");
log(" opt_const [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n"); log(" opt_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
log(" opt_share [-share_all]\n"); log(" opt_merge [-share_all]\n");
log(" opt_rmdff\n"); log(" opt_rmdff\n");
log(" opt_clean [-purge]\n"); log(" opt_clean [-purge]\n");
log(" while <changed design in opt_rmdff>\n"); log(" while <changed design in opt_rmdff>\n");
@ -66,9 +66,9 @@ struct OptPass : public Pass {
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{ {
std::string opt_clean_args; std::string opt_clean_args;
std::string opt_const_args; std::string opt_expr_args;
std::string opt_reduce_args; std::string opt_reduce_args;
std::string opt_share_args; std::string opt_merge_args;
bool fast_mode = false; bool fast_mode = false;
log_header("Executing OPT pass (performing simple optimizations).\n"); log_header("Executing OPT pass (performing simple optimizations).\n");
@ -81,37 +81,37 @@ struct OptPass : public Pass {
continue; continue;
} }
if (args[argidx] == "-mux_undef") { if (args[argidx] == "-mux_undef") {
opt_const_args += " -mux_undef"; opt_expr_args += " -mux_undef";
continue; continue;
} }
if (args[argidx] == "-mux_bool") { if (args[argidx] == "-mux_bool") {
opt_const_args += " -mux_bool"; opt_expr_args += " -mux_bool";
continue; continue;
} }
if (args[argidx] == "-undriven") { if (args[argidx] == "-undriven") {
opt_const_args += " -undriven"; opt_expr_args += " -undriven";
continue; continue;
} }
if (args[argidx] == "-clkinv") { if (args[argidx] == "-clkinv") {
opt_const_args += " -clkinv"; opt_expr_args += " -clkinv";
continue; continue;
} }
if (args[argidx] == "-fine") { if (args[argidx] == "-fine") {
opt_const_args += " -fine"; opt_expr_args += " -fine";
opt_reduce_args += " -fine"; opt_reduce_args += " -fine";
continue; continue;
} }
if (args[argidx] == "-full") { if (args[argidx] == "-full") {
opt_const_args += " -full"; opt_expr_args += " -full";
opt_reduce_args += " -full"; opt_reduce_args += " -full";
continue; continue;
} }
if (args[argidx] == "-keepdc") { if (args[argidx] == "-keepdc") {
opt_const_args += " -keepdc"; opt_expr_args += " -keepdc";
continue; continue;
} }
if (args[argidx] == "-share_all") { if (args[argidx] == "-share_all") {
opt_share_args += " -share_all"; opt_merge_args += " -share_all";
continue; continue;
} }
if (args[argidx] == "-fast") { if (args[argidx] == "-fast") {
@ -125,8 +125,8 @@ struct OptPass : public Pass {
if (fast_mode) if (fast_mode)
{ {
while (1) { while (1) {
Pass::call(design, "opt_const" + opt_const_args); Pass::call(design, "opt_expr" + opt_expr_args);
Pass::call(design, "opt_share" + opt_share_args); Pass::call(design, "opt_merge" + opt_merge_args);
design->scratchpad_unset("opt.did_something"); design->scratchpad_unset("opt.did_something");
Pass::call(design, "opt_rmdff"); Pass::call(design, "opt_rmdff");
if (design->scratchpad_get_bool("opt.did_something") == false) if (design->scratchpad_get_bool("opt.did_something") == false)
@ -138,16 +138,16 @@ struct OptPass : public Pass {
} }
else else
{ {
Pass::call(design, "opt_const" + opt_const_args); Pass::call(design, "opt_expr" + opt_expr_args);
Pass::call(design, "opt_share -nomux" + opt_share_args); Pass::call(design, "opt_merge -nomux" + opt_merge_args);
while (1) { while (1) {
design->scratchpad_unset("opt.did_something"); design->scratchpad_unset("opt.did_something");
Pass::call(design, "opt_muxtree"); Pass::call(design, "opt_muxtree");
Pass::call(design, "opt_reduce" + opt_reduce_args); Pass::call(design, "opt_reduce" + opt_reduce_args);
Pass::call(design, "opt_share" + opt_share_args); Pass::call(design, "opt_merge" + opt_merge_args);
Pass::call(design, "opt_rmdff"); Pass::call(design, "opt_rmdff");
Pass::call(design, "opt_clean" + opt_clean_args); Pass::call(design, "opt_clean" + opt_clean_args);
Pass::call(design, "opt_const" + opt_const_args); Pass::call(design, "opt_expr" + opt_expr_args);
if (design->scratchpad_get_bool("opt.did_something") == false) if (design->scratchpad_get_bool("opt.did_something") == false)
break; break;
log_header("Rerunning OPT passes. (Maybe there is more to do..)\n"); log_header("Rerunning OPT passes. (Maybe there is more to do..)\n");

View file

@ -179,7 +179,7 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ
log("\n"); log("\n");
} }
cover_list("opt.opt_const.fine.group", "$not", "$pos", "$and", "$or", "$xor", "$xnor", cell->type.str()); cover_list("opt.opt_expr.fine.group", "$not", "$pos", "$and", "$or", "$xor", "$xnor", cell->type.str());
module->remove(cell); module->remove(cell);
did_something = true; did_something = true;
@ -304,7 +304,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
for (auto cell : cells.sorted) for (auto cell : cells.sorted)
{ {
#define ACTION_DO(_p_, _s_) do { cover("opt.opt_const.action_" S__LINE__); replace_cell(assign_map, module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0) #define ACTION_DO(_p_, _s_) do { cover("opt.opt_expr.action_" S__LINE__); replace_cell(assign_map, module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0)
#define ACTION_DO_Y(_v_) ACTION_DO("\\Y", RTLIL::SigSpec(RTLIL::State::S ## _v_)) #define ACTION_DO_Y(_v_) ACTION_DO("\\Y", RTLIL::SigSpec(RTLIL::State::S ## _v_))
if (clkinv) if (clkinv)
@ -366,7 +366,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
} }
if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) { if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) {
cover("opt.opt_const.fine.$reduce_and"); cover("opt.opt_expr.fine.$reduce_and");
log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a)); cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a));
cell->setPort("\\A", sig_a = new_a); cell->setPort("\\A", sig_a = new_a);
@ -392,7 +392,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
} }
if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) { if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) {
cover_list("opt.opt_const.fine.A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_bool", cell->type.str()); cover_list("opt.opt_expr.fine.A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_bool", cell->type.str());
log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a)); cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a));
cell->setPort("\\A", sig_a = new_a); cell->setPort("\\A", sig_a = new_a);
@ -418,7 +418,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
} }
if (new_b != RTLIL::State::Sm && RTLIL::SigSpec(new_b) != sig_b) { if (new_b != RTLIL::State::Sm && RTLIL::SigSpec(new_b) != sig_b) {
cover_list("opt.opt_const.fine.B", "$logic_and", "$logic_or", cell->type.str()); cover_list("opt.opt_expr.fine.B", "$logic_and", "$logic_or", cell->type.str());
log("Replacing port B of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", log("Replacing port B of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_b)); cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_b));
cell->setPort("\\B", sig_b = new_b); cell->setPort("\\B", sig_b = new_b);
@ -429,13 +429,13 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
} }
if (cell->type == "$logic_or" && (assign_map(cell->getPort("\\A")) == RTLIL::State::S1 || assign_map(cell->getPort("\\B")) == RTLIL::State::S1)) { if (cell->type == "$logic_or" && (assign_map(cell->getPort("\\A")) == RTLIL::State::S1 || assign_map(cell->getPort("\\B")) == RTLIL::State::S1)) {
cover("opt.opt_const.one_high"); cover("opt.opt_expr.one_high");
replace_cell(assign_map, module, cell, "one high", "\\Y", RTLIL::State::S1); replace_cell(assign_map, module, cell, "one high", "\\Y", RTLIL::State::S1);
goto next_cell; goto next_cell;
} }
if (cell->type == "$logic_and" && (assign_map(cell->getPort("\\A")) == RTLIL::State::S0 || assign_map(cell->getPort("\\B")) == RTLIL::State::S0)) { if (cell->type == "$logic_and" && (assign_map(cell->getPort("\\A")) == RTLIL::State::S0 || assign_map(cell->getPort("\\B")) == RTLIL::State::S0)) {
cover("opt.opt_const.one_low"); cover("opt.opt_expr.one_low");
replace_cell(assign_map, module, cell, "one low", "\\Y", RTLIL::State::S0); replace_cell(assign_map, module, cell, "one low", "\\Y", RTLIL::State::S0);
goto next_cell; goto next_cell;
} }
@ -462,7 +462,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (0) { if (0) {
found_the_x_bit: found_the_x_bit:
cover_list("opt.opt_const.xbit", "$reduce_xor", "$reduce_xnor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cover_list("opt.opt_expr.xbit", "$reduce_xor", "$reduce_xnor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
"$lt", "$le", "$ge", "$gt", "$neg", "$add", "$sub", "$mul", "$div", "$mod", "$pow", cell->type.str()); "$lt", "$le", "$ge", "$gt", "$neg", "$add", "$sub", "$mul", "$div", "$mod", "$pow", cell->type.str());
if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor" || if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor" ||
cell->type == "$lt" || cell->type == "$le" || cell->type == "$ge" || cell->type == "$gt") cell->type == "$lt" || cell->type == "$le" || cell->type == "$ge" || cell->type == "$gt")
@ -475,13 +475,13 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if ((cell->type == "$_NOT_" || cell->type == "$not" || cell->type == "$logic_not") && cell->getPort("\\Y").size() == 1 && if ((cell->type == "$_NOT_" || cell->type == "$not" || cell->type == "$logic_not") && cell->getPort("\\Y").size() == 1 &&
invert_map.count(assign_map(cell->getPort("\\A"))) != 0) { invert_map.count(assign_map(cell->getPort("\\A"))) != 0) {
cover_list("opt.opt_const.invert.double", "$_NOT_", "$not", "$logic_not", cell->type.str()); cover_list("opt.opt_expr.invert.double", "$_NOT_", "$not", "$logic_not", cell->type.str());
replace_cell(assign_map, module, cell, "double_invert", "\\Y", invert_map.at(assign_map(cell->getPort("\\A")))); replace_cell(assign_map, module, cell, "double_invert", "\\Y", invert_map.at(assign_map(cell->getPort("\\A"))));
goto next_cell; goto next_cell;
} }
if ((cell->type == "$_MUX_" || cell->type == "$mux") && invert_map.count(assign_map(cell->getPort("\\S"))) != 0) { if ((cell->type == "$_MUX_" || cell->type == "$mux") && invert_map.count(assign_map(cell->getPort("\\S"))) != 0) {
cover_list("opt.opt_const.invert.muxsel", "$_MUX_", "$mux", cell->type.str()); cover_list("opt.opt_expr.invert.muxsel", "$_MUX_", "$mux", cell->type.str());
log("Optimizing away select inverter for %s cell `%s' in module `%s'.\n", log_id(cell->type), log_id(cell), log_id(module)); log("Optimizing away select inverter for %s cell `%s' in module `%s'.\n", log_id(cell->type), log_id(cell), log_id(module));
RTLIL::SigSpec tmp = cell->getPort("\\A"); RTLIL::SigSpec tmp = cell->getPort("\\A");
cell->setPort("\\A", cell->getPort("\\B")); cell->setPort("\\A", cell->getPort("\\B"));
@ -564,7 +564,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (input.match(" 1")) ACTION_DO("\\Y", input.extract(1, 1)); if (input.match(" 1")) ACTION_DO("\\Y", input.extract(1, 1));
if (input.match("01 ")) ACTION_DO("\\Y", input.extract(0, 1)); if (input.match("01 ")) ACTION_DO("\\Y", input.extract(0, 1));
if (input.match("10 ")) { if (input.match("10 ")) {
cover("opt.opt_const.mux_to_inv"); cover("opt.opt_expr.mux_to_inv");
cell->type = "$_NOT_"; cell->type = "$_NOT_";
cell->setPort("\\A", input.extract(0, 1)); cell->setPort("\\A", input.extract(0, 1));
cell->unsetPort("\\B"); cell->unsetPort("\\B");
@ -599,7 +599,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
log_assert(GetSize(a) == GetSize(b)); log_assert(GetSize(a) == GetSize(b));
for (int i = 0; i < GetSize(a); i++) { for (int i = 0; i < GetSize(a); i++) {
if (a[i].wire == NULL && b[i].wire == NULL && a[i] != b[i] && a[i].data <= RTLIL::State::S1 && b[i].data <= RTLIL::State::S1) { if (a[i].wire == NULL && b[i].wire == NULL && a[i] != b[i] && a[i].data <= RTLIL::State::S1 && b[i].data <= RTLIL::State::S1) {
cover_list("opt.opt_const.eqneq.isneq", "$eq", "$ne", "$eqx", "$nex", cell->type.str()); cover_list("opt.opt_expr.eqneq.isneq", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
RTLIL::SigSpec new_y = RTLIL::SigSpec((cell->type == "$eq" || cell->type == "$eqx") ? RTLIL::State::S0 : RTLIL::State::S1); RTLIL::SigSpec new_y = RTLIL::SigSpec((cell->type == "$eq" || cell->type == "$eqx") ? RTLIL::State::S0 : RTLIL::State::S1);
new_y.extend_u0(cell->parameters["\\Y_WIDTH"].as_int(), false); new_y.extend_u0(cell->parameters["\\Y_WIDTH"].as_int(), false);
replace_cell(assign_map, module, cell, "isneq", "\\Y", new_y); replace_cell(assign_map, module, cell, "isneq", "\\Y", new_y);
@ -612,7 +612,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
} }
if (new_a.size() == 0) { if (new_a.size() == 0) {
cover_list("opt.opt_const.eqneq.empty", "$eq", "$ne", "$eqx", "$nex", cell->type.str()); cover_list("opt.opt_expr.eqneq.empty", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
RTLIL::SigSpec new_y = RTLIL::SigSpec((cell->type == "$eq" || cell->type == "$eqx") ? RTLIL::State::S1 : RTLIL::State::S0); RTLIL::SigSpec new_y = RTLIL::SigSpec((cell->type == "$eq" || cell->type == "$eqx") ? RTLIL::State::S1 : RTLIL::State::S0);
new_y.extend_u0(cell->parameters["\\Y_WIDTH"].as_int(), false); new_y.extend_u0(cell->parameters["\\Y_WIDTH"].as_int(), false);
replace_cell(assign_map, module, cell, "empty", "\\Y", new_y); replace_cell(assign_map, module, cell, "empty", "\\Y", new_y);
@ -620,7 +620,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
} }
if (new_a.size() < a.size() || new_b.size() < b.size()) { if (new_a.size() < a.size() || new_b.size() < b.size()) {
cover_list("opt.opt_const.eqneq.resize", "$eq", "$ne", "$eqx", "$nex", cell->type.str()); cover_list("opt.opt_expr.eqneq.resize", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
cell->setPort("\\A", new_a); cell->setPort("\\A", new_a);
cell->setPort("\\B", new_b); cell->setPort("\\B", new_b);
cell->parameters["\\A_WIDTH"] = new_a.size(); cell->parameters["\\A_WIDTH"] = new_a.size();
@ -635,7 +635,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
RTLIL::SigSpec b = assign_map(cell->getPort("\\B")); RTLIL::SigSpec b = assign_map(cell->getPort("\\B"));
if (a.is_fully_const() && !b.is_fully_const()) { if (a.is_fully_const() && !b.is_fully_const()) {
cover_list("opt.opt_const.eqneq.swapconst", "$eq", "$ne", cell->type.str()); cover_list("opt.opt_expr.eqneq.swapconst", "$eq", "$ne", cell->type.str());
cell->setPort("\\A", b); cell->setPort("\\A", b);
cell->setPort("\\B", a); cell->setPort("\\B", a);
std::swap(a, b); std::swap(a, b);
@ -646,7 +646,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
RTLIL::SigSpec input = b; RTLIL::SigSpec input = b;
ACTION_DO("\\Y", cell->getPort("\\A")); ACTION_DO("\\Y", cell->getPort("\\A"));
} else { } else {
cover_list("opt.opt_const.eqneq.isnot", "$eq", "$ne", cell->type.str()); cover_list("opt.opt_expr.eqneq.isnot", "$eq", "$ne", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module)); log("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module));
cell->type = "$not"; cell->type = "$not";
cell->parameters.erase("\\B_WIDTH"); cell->parameters.erase("\\B_WIDTH");
@ -661,7 +661,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if ((cell->type == "$eq" || cell->type == "$ne") && if ((cell->type == "$eq" || cell->type == "$ne") &&
(assign_map(cell->getPort("\\A")).is_fully_zero() || assign_map(cell->getPort("\\B")).is_fully_zero())) (assign_map(cell->getPort("\\A")).is_fully_zero() || assign_map(cell->getPort("\\B")).is_fully_zero()))
{ {
cover_list("opt.opt_const.eqneq.cmpzero", "$eq", "$ne", cell->type.str()); cover_list("opt.opt_expr.eqneq.cmpzero", "$eq", "$ne", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell->type), log_id(cell), log("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell->type), log_id(cell),
log_id(module), "$eq" ? "$logic_not" : "$reduce_bool"); log_id(module), "$eq" ? "$logic_not" : "$reduce_bool");
cell->type = cell->type == "$eq" ? "$logic_not" : "$reduce_bool"; cell->type = cell->type == "$eq" ? "$logic_not" : "$reduce_bool";
@ -699,7 +699,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
sig_y[i] = sig_a[GetSize(sig_a)-1]; sig_y[i] = sig_a[GetSize(sig_a)-1];
} }
cover_list("opt.opt_const.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell->type.str()); cover_list("opt.opt_expr.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell->type.str());
log("Replacing %s cell `%s' (B=%s, SHR=%d) in module `%s' with fixed wiring: %s\n", log("Replacing %s cell `%s' (B=%s, SHR=%d) in module `%s' with fixed wiring: %s\n",
log_id(cell->type), log_id(cell), log_signal(assign_map(cell->getPort("\\B"))), shift_bits, log_id(module), log_signal(sig_y)); log_id(cell->type), log_id(cell), log_signal(assign_map(cell->getPort("\\B"))), shift_bits, log_id(module), log_signal(sig_y));
@ -760,9 +760,9 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (identity_wrt_a || identity_wrt_b) if (identity_wrt_a || identity_wrt_b)
{ {
if (identity_wrt_a) if (identity_wrt_a)
cover_list("opt.opt_const.identwrt.a", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str()); cover_list("opt.opt_expr.identwrt.a", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str());
if (identity_wrt_b) if (identity_wrt_b)
cover_list("opt.opt_const.identwrt.b", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str()); cover_list("opt.opt_expr.identwrt.b", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with identity for port %c.\n", log("Replacing %s cell `%s' in module `%s' with identity for port %c.\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), identity_wrt_a ? 'A' : 'B'); cell->type.c_str(), cell->name.c_str(), module->name.c_str(), identity_wrt_a ? 'A' : 'B');
@ -786,14 +786,14 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && if (mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") &&
cell->getPort("\\A") == RTLIL::SigSpec(0, 1) && cell->getPort("\\B") == RTLIL::SigSpec(1, 1)) { cell->getPort("\\A") == RTLIL::SigSpec(0, 1) && cell->getPort("\\B") == RTLIL::SigSpec(1, 1)) {
cover_list("opt.opt_const.mux_bool", "$mux", "$_MUX_", cell->type.str()); cover_list("opt.opt_expr.mux_bool", "$mux", "$_MUX_", cell->type.str());
replace_cell(assign_map, module, cell, "mux_bool", "\\Y", cell->getPort("\\S")); replace_cell(assign_map, module, cell, "mux_bool", "\\Y", cell->getPort("\\S"));
goto next_cell; goto next_cell;
} }
if (mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && if (mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") &&
cell->getPort("\\A") == RTLIL::SigSpec(1, 1) && cell->getPort("\\B") == RTLIL::SigSpec(0, 1)) { cell->getPort("\\A") == RTLIL::SigSpec(1, 1) && cell->getPort("\\B") == RTLIL::SigSpec(0, 1)) {
cover_list("opt.opt_const.mux_invert", "$mux", "$_MUX_", cell->type.str()); cover_list("opt.opt_expr.mux_invert", "$mux", "$_MUX_", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module)); log("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module));
cell->setPort("\\A", cell->getPort("\\S")); cell->setPort("\\A", cell->getPort("\\S"));
cell->unsetPort("\\B"); cell->unsetPort("\\B");
@ -812,7 +812,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
} }
if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\A") == RTLIL::SigSpec(0, 1)) { if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\A") == RTLIL::SigSpec(0, 1)) {
cover_list("opt.opt_const.mux_and", "$mux", "$_MUX_", cell->type.str()); cover_list("opt.opt_expr.mux_and", "$mux", "$_MUX_", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with and-gate.\n", log_id(cell->type), log_id(cell), log_id(module)); log("Replacing %s cell `%s' in module `%s' with and-gate.\n", log_id(cell->type), log_id(cell), log_id(module));
cell->setPort("\\A", cell->getPort("\\S")); cell->setPort("\\A", cell->getPort("\\S"));
cell->unsetPort("\\S"); cell->unsetPort("\\S");
@ -832,7 +832,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
} }
if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\B") == RTLIL::SigSpec(1, 1)) { if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\B") == RTLIL::SigSpec(1, 1)) {
cover_list("opt.opt_const.mux_or", "$mux", "$_MUX_", cell->type.str()); cover_list("opt.opt_expr.mux_or", "$mux", "$_MUX_", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with or-gate.\n", log_id(cell->type), log_id(cell), log_id(module)); log("Replacing %s cell `%s' in module `%s' with or-gate.\n", log_id(cell->type), log_id(cell), log_id(module));
cell->setPort("\\B", cell->getPort("\\S")); cell->setPort("\\B", cell->getPort("\\S"));
cell->unsetPort("\\S"); cell->unsetPort("\\S");
@ -856,7 +856,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
int width = cell->getPort("\\A").size(); int width = cell->getPort("\\A").size();
if ((cell->getPort("\\A").is_fully_undef() && cell->getPort("\\B").is_fully_undef()) || if ((cell->getPort("\\A").is_fully_undef() && cell->getPort("\\B").is_fully_undef()) ||
cell->getPort("\\S").is_fully_undef()) { cell->getPort("\\S").is_fully_undef()) {
cover_list("opt.opt_const.mux_undef", "$mux", "$pmux", cell->type.str()); cover_list("opt.opt_expr.mux_undef", "$mux", "$pmux", cell->type.str());
replace_cell(assign_map, module, cell, "mux_undef", "\\Y", cell->getPort("\\A")); replace_cell(assign_map, module, cell, "mux_undef", "\\Y", cell->getPort("\\A"));
goto next_cell; goto next_cell;
} }
@ -875,17 +875,17 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
new_s = new_s.extract(0, new_s.size()-1); new_s = new_s.extract(0, new_s.size()-1);
} }
if (new_s.size() == 0) { if (new_s.size() == 0) {
cover_list("opt.opt_const.mux_empty", "$mux", "$pmux", cell->type.str()); cover_list("opt.opt_expr.mux_empty", "$mux", "$pmux", cell->type.str());
replace_cell(assign_map, module, cell, "mux_empty", "\\Y", new_a); replace_cell(assign_map, module, cell, "mux_empty", "\\Y", new_a);
goto next_cell; goto next_cell;
} }
if (new_a == RTLIL::SigSpec(RTLIL::State::S0) && new_b == RTLIL::SigSpec(RTLIL::State::S1)) { if (new_a == RTLIL::SigSpec(RTLIL::State::S0) && new_b == RTLIL::SigSpec(RTLIL::State::S1)) {
cover_list("opt.opt_const.mux_sel01", "$mux", "$pmux", cell->type.str()); cover_list("opt.opt_expr.mux_sel01", "$mux", "$pmux", cell->type.str());
replace_cell(assign_map, module, cell, "mux_sel01", "\\Y", new_s); replace_cell(assign_map, module, cell, "mux_sel01", "\\Y", new_s);
goto next_cell; goto next_cell;
} }
if (cell->getPort("\\S").size() != new_s.size()) { if (cell->getPort("\\S").size() != new_s.size()) {
cover_list("opt.opt_const.mux_reduce", "$mux", "$pmux", cell->type.str()); cover_list("opt.opt_expr.mux_reduce", "$mux", "$pmux", cell->type.str());
log("Optimized away %d select inputs of %s cell `%s' in module `%s'.\n", log("Optimized away %d select inputs of %s cell `%s' in module `%s'.\n",
GetSize(cell->getPort("\\S")) - GetSize(new_s), log_id(cell->type), log_id(cell), log_id(module)); GetSize(cell->getPort("\\S")) - GetSize(new_s), log_id(cell->type), log_id(cell), log_id(module));
cell->setPort("\\A", new_a); cell->setPort("\\A", new_a);
@ -911,7 +911,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), dummy_arg, \ RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), dummy_arg, \
cell->parameters["\\A_SIGNED"].as_bool(), false, \ cell->parameters["\\A_SIGNED"].as_bool(), false, \
cell->parameters["\\Y_WIDTH"].as_int())); \ cell->parameters["\\Y_WIDTH"].as_int())); \
cover("opt.opt_const.const.$" #_t); \ cover("opt.opt_expr.const.$" #_t); \
replace_cell(assign_map, module, cell, stringf("%s", log_signal(a)), "\\Y", y); \ replace_cell(assign_map, module, cell, stringf("%s", log_signal(a)), "\\Y", y); \
goto next_cell; \ goto next_cell; \
} \ } \
@ -926,7 +926,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
cell->parameters["\\A_SIGNED"].as_bool(), \ cell->parameters["\\A_SIGNED"].as_bool(), \
cell->parameters["\\B_SIGNED"].as_bool(), \ cell->parameters["\\B_SIGNED"].as_bool(), \
cell->parameters["\\Y_WIDTH"].as_int())); \ cell->parameters["\\Y_WIDTH"].as_int())); \
cover("opt.opt_const.const.$" #_t); \ cover("opt.opt_expr.const.$" #_t); \
replace_cell(assign_map, module, cell, stringf("%s, %s", log_signal(a), log_signal(b)), "\\Y", y); \ replace_cell(assign_map, module, cell, stringf("%s, %s", log_signal(a), log_signal(b)), "\\Y", y); \
goto next_cell; \ goto next_cell; \
} \ } \
@ -1002,7 +1002,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (a_val == 0) if (a_val == 0)
{ {
cover("opt.opt_const.mul_shift.zero"); cover("opt.opt_expr.mul_shift.zero");
log("Replacing multiply-by-zero cell `%s' in module `%s' with zero-driver.\n", log("Replacing multiply-by-zero cell `%s' in module `%s' with zero-driver.\n",
cell->name.c_str(), module->name.c_str()); cell->name.c_str(), module->name.c_str());
@ -1018,9 +1018,9 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (a_val == (1 << i)) if (a_val == (1 << i))
{ {
if (swapped_ab) if (swapped_ab)
cover("opt.opt_const.mul_shift.swapped"); cover("opt.opt_expr.mul_shift.swapped");
else else
cover("opt.opt_const.mul_shift.unswapped"); cover("opt.opt_expr.mul_shift.unswapped");
log("Replacing multiply-by-%d cell `%s' in module `%s' with shift-by-%d.\n", log("Replacing multiply-by-%d cell `%s' in module `%s' with shift-by-%d.\n",
a_val, cell->name.c_str(), module->name.c_str(), i); a_val, cell->name.c_str(), module->name.c_str(), i);
@ -1056,15 +1056,16 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
} }
} }
struct OptConstPass : public Pass { struct OptExprPass : public Pass {
OptConstPass() : Pass("opt_const", "perform const folding") { } OptExprPass() : Pass("opt_expr", "perform const folding and simple expression rewriting") { }
virtual void help() virtual void help()
{ {
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n"); log("\n");
log(" opt_const [options] [selection]\n"); log(" opt_expr [options] [selection]\n");
log("\n"); log("\n");
log("This pass performs const folding on internal cell types with constant inputs.\n"); log("This pass performs const folding on internal cell types with constant inputs.\n");
log("It also performs some simple expression rewritring.\n");
log("\n"); log("\n");
log(" -mux_undef\n"); log(" -mux_undef\n");
log(" remove 'undef' inputs from $mux, $pmux and $_MUX_ cells\n"); log(" remove 'undef' inputs from $mux, $pmux and $_MUX_ cells\n");
@ -1100,7 +1101,7 @@ struct OptConstPass : public Pass {
bool do_fine = false; bool do_fine = false;
bool keepdc = false; bool keepdc = false;
log_header("Executing OPT_CONST pass (perform const folding).\n"); log_header("Executing OPT_EXPR pass (perform const folding).\n");
log_push(); log_push();
size_t argidx; size_t argidx;
@ -1158,6 +1159,6 @@ struct OptConstPass : public Pass {
log_pop(); log_pop();
} }
} OptConstPass; } OptExprPass;
PRIVATE_NAMESPACE_END PRIVATE_NAMESPACE_END

View file

@ -31,7 +31,7 @@
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN PRIVATE_NAMESPACE_BEGIN
struct OptShareWorker struct OptMergeWorker
{ {
RTLIL::Design *design; RTLIL::Design *design;
RTLIL::Module *module; RTLIL::Module *module;
@ -45,6 +45,29 @@ struct OptShareWorker
dict<const RTLIL::Cell*, std::string> cell_hash_cache; dict<const RTLIL::Cell*, std::string> cell_hash_cache;
#endif #endif
static void sort_pmux_conn(dict<RTLIL::IdString, RTLIL::SigSpec> &conn)
{
SigSpec sig_s = conn.at("\\S");
SigSpec sig_b = conn.at("\\B");
int s_width = GetSize(sig_s);
int width = GetSize(sig_b) / s_width;
vector<pair<SigBit, SigSpec>> sb_pairs;
for (int i = 0; i < s_width; i++)
sb_pairs.push_back(pair<SigBit, SigSpec>(sig_s[i], sig_b.extract(i*width, width)));
std::sort(sb_pairs.begin(), sb_pairs.end());
conn["\\S"] = SigSpec();
conn["\\B"] = SigSpec();
for (auto &it : sb_pairs) {
conn["\\S"].append(it.first);
conn["\\B"].append(it.second);
}
}
#ifdef USE_CELL_HASH_CACHE #ifdef USE_CELL_HASH_CACHE
std::string int_to_hash_string(unsigned int v) std::string int_to_hash_string(unsigned int v)
{ {
@ -91,25 +114,40 @@ struct OptShareWorker
assign_map.apply(alt_conn.at("\\A")); assign_map.apply(alt_conn.at("\\A"));
alt_conn.at("\\A").sort_and_unify(); alt_conn.at("\\A").sort_and_unify();
conn = &alt_conn; conn = &alt_conn;
} else
if (cell->type == "$pmux") {
alt_conn = *conn;
assign_map.apply(alt_conn.at("\\A"));
assign_map.apply(alt_conn.at("\\B"));
assign_map.apply(alt_conn.at("\\S"));
sort_pmux_conn(alt_conn);
conn = &alt_conn;
} }
vector<string> hash_conn_strings;
for (auto &it : *conn) { for (auto &it : *conn) {
if (cell->output(it.first)) if (cell->output(it.first))
continue; continue;
RTLIL::SigSpec sig = it.second; RTLIL::SigSpec sig = it.second;
assign_map.apply(sig); assign_map.apply(sig);
hash_string += "C " + it.first.str() + "="; string s = "C " + it.first.str() + "=";
for (auto &chunk : sig.chunks()) { for (auto &chunk : sig.chunks()) {
if (chunk.wire) if (chunk.wire)
hash_string += "{" + chunk.wire->name.str() + " " + s += "{" + chunk.wire->name.str() + " " +
int_to_hash_string(chunk.offset) + " " + int_to_hash_string(chunk.offset) + " " +
int_to_hash_string(chunk.width) + "}"; int_to_hash_string(chunk.width) + "}";
else else
hash_string += RTLIL::Const(chunk.data).as_string(); s += RTLIL::Const(chunk.data).as_string();
} }
hash_string += "\n"; hash_conn_strings.push_back(s + "\n");
} }
std::sort(hash_conn_strings.begin(), hash_conn_strings.end());
for (auto it : hash_conn_strings)
hash_string += it;
cell_hash_cache[cell] = sha1(hash_string); cell_hash_cache[cell] = sha1(hash_string);
return cell_hash_cache[cell]; return cell_hash_cache[cell];
} }
@ -171,6 +209,10 @@ struct OptShareWorker
if (cell1->type == "$reduce_and" || cell1->type == "$reduce_or" || cell1->type == "$reduce_bool") { if (cell1->type == "$reduce_and" || cell1->type == "$reduce_or" || cell1->type == "$reduce_bool") {
conn1["\\A"].sort_and_unify(); conn1["\\A"].sort_and_unify();
conn2["\\A"].sort_and_unify(); conn2["\\A"].sort_and_unify();
} else
if (cell1->type == "$pmux") {
sort_pmux_conn(conn1);
sort_pmux_conn(conn2);
} }
if (conn1 != conn2) { if (conn1 != conn2) {
@ -212,14 +254,14 @@ struct OptShareWorker
} }
struct CompareCells { struct CompareCells {
OptShareWorker *that; OptMergeWorker *that;
CompareCells(OptShareWorker *that) : that(that) {} CompareCells(OptMergeWorker *that) : that(that) {}
bool operator()(const RTLIL::Cell *cell1, const RTLIL::Cell *cell2) const { bool operator()(const RTLIL::Cell *cell1, const RTLIL::Cell *cell2) const {
return that->compare_cells(cell1, cell2); return that->compare_cells(cell1, cell2);
} }
}; };
OptShareWorker(RTLIL::Design *design, RTLIL::Module *module, bool mode_nomux, bool mode_share_all) : OptMergeWorker(RTLIL::Design *design, RTLIL::Module *module, bool mode_nomux, bool mode_share_all) :
design(design), module(module), assign_map(module), mode_share_all(mode_share_all) design(design), module(module), assign_map(module), mode_share_all(mode_share_all)
{ {
total_count = 0; total_count = 0;
@ -286,13 +328,13 @@ struct OptShareWorker
} }
}; };
struct OptSharePass : public Pass { struct OptMergePass : public Pass {
OptSharePass() : Pass("opt_share", "consolidate identical cells") { } OptMergePass() : Pass("opt_merge", "consolidate identical cells") { }
virtual void help() virtual void help()
{ {
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n"); log("\n");
log(" opt_share [options] [selection]\n"); log(" opt_merge [options] [selection]\n");
log("\n"); log("\n");
log("This pass identifies cells with identical type and input signals. Such cells\n"); log("This pass identifies cells with identical type and input signals. Such cells\n");
log("are then merged to one cell.\n"); log("are then merged to one cell.\n");
@ -306,7 +348,7 @@ struct OptSharePass : public Pass {
} }
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{ {
log_header("Executing OPT_SHARE pass (detect identical cells).\n"); log_header("Executing OPT_MERGE pass (detect identical cells).\n");
bool mode_nomux = false; bool mode_nomux = false;
bool mode_share_all = false; bool mode_share_all = false;
@ -328,7 +370,7 @@ struct OptSharePass : public Pass {
int total_count = 0; int total_count = 0;
for (auto module : design->selected_modules()) { for (auto module : design->selected_modules()) {
OptShareWorker worker(design, module, mode_nomux, mode_share_all); OptMergeWorker worker(design, module, mode_nomux, mode_share_all);
total_count += worker.total_count; total_count += worker.total_count;
} }
@ -336,6 +378,6 @@ struct OptSharePass : public Pass {
design->scratchpad_set_bool("opt.did_something", true); design->scratchpad_set_bool("opt.did_something", true);
log("Removed a total of %d cells.\n", total_count); log("Removed a total of %d cells.\n", total_count);
} }
} OptSharePass; } OptMergePass;
PRIVATE_NAMESPACE_END PRIVATE_NAMESPACE_END

View file

@ -51,8 +51,8 @@ void proc_rmdead(RTLIL::SwitchRule *sw, int &counter)
counter++; counter++;
continue; continue;
} }
if (pool.empty()) // if (pool.empty())
sw->cases[i]->compare.clear(); // sw->cases[i]->compare.clear();
} }
for (auto switch_it : sw->cases[i]->switches) for (auto switch_it : sw->cases[i]->switches)

View file

@ -254,7 +254,7 @@ void create_miter_equiv(struct Pass *that, std::vector<std::string> args, RTLIL:
if (flag_flatten) { if (flag_flatten) {
log_push(); log_push();
Pass::call_on_module(design, miter_module, "flatten; opt_const -keepdc -undriven;;"); Pass::call_on_module(design, miter_module, "flatten; opt_expr -keepdc -undriven;;");
log_pop(); log_pop();
} }
} }
@ -327,7 +327,7 @@ void create_miter_assert(struct Pass *that, std::vector<std::string> args, RTLIL
if (flag_flatten) { if (flag_flatten) {
log_push(); log_push();
Pass::call_on_module(design, module, "opt_const -keepdc -undriven;;"); Pass::call_on_module(design, module, "opt_expr -keepdc -undriven;;");
log_pop(); log_pop();
} }
} }
@ -361,7 +361,7 @@ struct MiterPass : public Pass {
log(" also create an 'assert' cell that checks if trigger is always low.\n"); log(" also create an 'assert' cell that checks if trigger is always low.\n");
log("\n"); log("\n");
log(" -flatten\n"); log(" -flatten\n");
log(" call 'flatten; opt_const -keepdc -undriven;;' on the miter circuit.\n"); log(" call 'flatten; opt_expr -keepdc -undriven;;' on the miter circuit.\n");
log("\n"); log("\n");
log("\n"); log("\n");
log(" miter -assert [options] module [miter_name]\n"); log(" miter -assert [options] module [miter_name]\n");
@ -375,7 +375,7 @@ struct MiterPass : public Pass {
log(" keep module output ports.\n"); log(" keep module output ports.\n");
log("\n"); log("\n");
log(" -flatten\n"); log(" -flatten\n");
log(" call 'flatten; opt_const -keepdc -undriven;;' on the miter circuit.\n"); log(" call 'flatten; opt_expr -keepdc -undriven;;' on the miter circuit.\n");
log("\n"); log("\n");
} }
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) virtual void execute(std::vector<std::string> args, RTLIL::Design *design)

View file

@ -69,7 +69,7 @@ struct PrepPass : public Pass {
log("\n"); log("\n");
log(" prep:\n"); log(" prep:\n");
log(" proc\n"); log(" proc\n");
log(" opt_const\n"); log(" opt_expr -keepdc\n");
log(" opt_clean\n"); log(" opt_clean\n");
log(" check\n"); log(" check\n");
log(" opt -keepdc\n"); log(" opt -keepdc\n");
@ -134,7 +134,7 @@ struct PrepPass : public Pass {
if (check_label(active, run_from, run_to, "coarse")) if (check_label(active, run_from, run_to, "coarse"))
{ {
Pass::call(design, "proc"); Pass::call(design, "proc");
Pass::call(design, "opt_const"); Pass::call(design, "opt_expr -keepdc");
Pass::call(design, "opt_clean"); Pass::call(design, "opt_clean");
Pass::call(design, "check"); Pass::call(design, "check");
Pass::call(design, "opt -keepdc"); Pass::call(design, "opt -keepdc");

View file

@ -25,22 +25,11 @@
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN PRIVATE_NAMESPACE_BEGIN
bool check_label(bool &active, std::string run_from, std::string run_to, std::string label) struct SynthPass : public ScriptPass
{ {
if (!run_from.empty() && run_from == run_to) { SynthPass() : ScriptPass("synth", "generic synthesis script") { }
active = (label == run_from);
} else {
if (label == run_from)
active = true;
if (label == run_to)
active = false;
}
return active;
}
struct SynthPass : public Pass { virtual void help() YS_OVERRIDE
SynthPass() : Pass("synth", "generic synthesis script") { }
virtual void help()
{ {
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n"); log("\n");
@ -75,49 +64,28 @@ struct SynthPass : public Pass {
log("\n"); log("\n");
log("\n"); log("\n");
log("The following commands are executed by this synthesis command:\n"); log("The following commands are executed by this synthesis command:\n");
log("\n"); help_script();
log(" begin:\n");
log(" hierarchy -check [-top <top>]\n");
log("\n");
log(" coarse:\n");
log(" proc\n");
log(" opt_const\n");
log(" opt_clean\n");
log(" check\n");
log(" opt\n");
log(" wreduce\n");
log(" alumacc\n");
log(" share\n");
log(" opt\n");
log(" fsm\n");
log(" opt -fast\n");
log(" memory -nomap\n");
log(" opt_clean\n");
log("\n");
log(" fine:\n");
log(" opt -fast -full\n");
log(" memory_map\n");
log(" opt -full\n");
log(" techmap\n");
log(" opt -fast\n");
#ifdef YOSYS_ENABLE_ABC
log(" abc -fast\n");
log(" opt -fast\n");
#endif
log("\n");
log(" check:\n");
log(" hierarchy -check\n");
log(" stat\n");
log(" check\n");
log("\n"); log("\n");
} }
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
std::string top_module, fsm_opts, memory_opts;
bool noalumacc, nofsm, noabc;
virtual void clear_flags() YS_OVERRIDE
{ {
std::string top_module, fsm_opts, memory_opts; top_module.clear();
std::string run_from, run_to; fsm_opts.clear();
bool noalumacc = false; memory_opts.clear();
bool nofsm = false;
bool noabc = false; noalumacc = false;
nofsm = false;
noabc = false;
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
string run_from, run_to;
clear_flags();
size_t argidx; size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) for (argidx = 1; argidx < args.size(); argidx++)
@ -164,62 +132,69 @@ struct SynthPass : public Pass {
if (!design->full_selection()) if (!design->full_selection())
log_cmd_error("This comannd only operates on fully selected designs!\n"); log_cmd_error("This comannd only operates on fully selected designs!\n");
bool active = run_from.empty();
log_header("Executing SYNTH pass.\n"); log_header("Executing SYNTH pass.\n");
log_push(); log_push();
if (check_label(active, run_from, run_to, "begin")) run_script(design, run_from, run_to);
log_pop();
}
virtual void script() YS_OVERRIDE
{
if (check_label("begin"))
{ {
if (top_module.empty()) if (help_mode) {
Pass::call(design, stringf("hierarchy -check")); run("hierarchy -check [-top <top>]");
else } else {
Pass::call(design, stringf("hierarchy -check -top %s", top_module.c_str())); if (top_module.empty())
run(stringf("hierarchy -check"));
else
run(stringf("hierarchy -check -top %s", top_module.c_str()));
}
} }
if (check_label(active, run_from, run_to, "coarse")) if (check_label("coarse"))
{ {
Pass::call(design, "proc"); run("proc");
Pass::call(design, "opt_const"); run("opt_expr");
Pass::call(design, "opt_clean"); run("opt_clean");
Pass::call(design, "check"); run("check");
Pass::call(design, "opt"); run("opt");
Pass::call(design, "wreduce"); run("wreduce");
if (!noalumacc) if (!noalumacc)
Pass::call(design, "alumacc"); run("alumacc");
Pass::call(design, "share"); run("share");
Pass::call(design, "opt"); run("opt");
if (!nofsm) if (!nofsm)
Pass::call(design, "fsm" + fsm_opts); run("fsm" + fsm_opts);
Pass::call(design, "opt -fast"); run("opt -fast");
Pass::call(design, "memory -nomap" + memory_opts); run("memory -nomap" + memory_opts);
Pass::call(design, "opt_clean"); run("opt_clean");
} }
if (check_label(active, run_from, run_to, "fine")) if (check_label("fine"))
{ {
Pass::call(design, "opt -fast -full"); run("opt -fast -full");
Pass::call(design, "memory_map"); run("memory_map");
Pass::call(design, "opt -full"); run("opt -full");
Pass::call(design, "techmap"); run("techmap");
Pass::call(design, "opt -fast"); run("opt -fast");
if (!noabc) { if (!noabc) {
#ifdef YOSYS_ENABLE_ABC #ifdef YOSYS_ENABLE_ABC
Pass::call(design, "abc -fast"); run("abc -fast");
Pass::call(design, "opt -fast"); run("opt -fast");
#endif #endif
} }
} }
if (check_label(active, run_from, run_to, "check")) if (check_label("check"))
{ {
Pass::call(design, "hierarchy -check"); run("hierarchy -check");
Pass::call(design, "stat"); run("stat");
Pass::call(design, "check"); run("check");
} }
log_pop();
} }
} SynthPass; } SynthPass;

View file

@ -93,7 +93,7 @@ module _90_shift_ops_shr_shl_sshl_sshr (A, B, Y);
localparam BB_WIDTH = `MIN($clog2(shift_left ? Y_WIDTH : A_SIGNED ? WIDTH : A_WIDTH) + 1, B_WIDTH); localparam BB_WIDTH = `MIN($clog2(shift_left ? Y_WIDTH : A_SIGNED ? WIDTH : A_WIDTH) + 1, B_WIDTH);
wire [1023:0] _TECHMAP_DO_00_ = "proc;;"; wire [1023:0] _TECHMAP_DO_00_ = "proc;;";
wire [1023:0] _TECHMAP_DO_01_ = "RECURSION; CONSTMAP; opt_muxtree; opt_const -mux_undef -mux_bool -fine;;;"; wire [1023:0] _TECHMAP_DO_01_ = "RECURSION; CONSTMAP; opt_muxtree; opt_expr -mux_undef -mux_bool -fine;;;";
integer i; integer i;
reg [WIDTH-1:0] buffer; reg [WIDTH-1:0] buffer;
@ -136,7 +136,7 @@ module _90_shift_shiftx (A, B, Y);
localparam extbit = _TECHMAP_CELLTYPE_ == "$shift" ? 1'b0 : 1'bx; localparam extbit = _TECHMAP_CELLTYPE_ == "$shift" ? 1'b0 : 1'bx;
wire [1023:0] _TECHMAP_DO_00_ = "proc;;"; wire [1023:0] _TECHMAP_DO_00_ = "proc;;";
wire [1023:0] _TECHMAP_DO_01_ = "CONSTMAP; opt_muxtree; opt_const -mux_undef -mux_bool -fine;;;"; wire [1023:0] _TECHMAP_DO_01_ = "CONSTMAP; opt_muxtree; opt_expr -mux_undef -mux_bool -fine;;;";
integer i; integer i;
reg [WIDTH-1:0] buffer; reg [WIDTH-1:0] buffer;

View file

@ -127,8 +127,8 @@ struct Ice40OptPass : public Pass {
log("\n"); log("\n");
log(" do\n"); log(" do\n");
log(" <ice40 specific optimizations>\n"); log(" <ice40 specific optimizations>\n");
log(" opt_const -mux_undef -undriven [-full]\n"); log(" opt_expr -mux_undef -undriven [-full]\n");
log(" opt_share\n"); log(" opt_merge\n");
log(" opt_rmdff\n"); log(" opt_rmdff\n");
log(" opt_clean\n"); log(" opt_clean\n");
log(" while <changed design>\n"); log(" while <changed design>\n");
@ -136,14 +136,14 @@ struct Ice40OptPass : public Pass {
} }
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{ {
string opt_const_args = "-mux_undef -undriven"; string opt_expr_args = "-mux_undef -undriven";
log_header("Executing ICE40_OPT pass (performing simple optimizations).\n"); log_header("Executing ICE40_OPT pass (performing simple optimizations).\n");
log_push(); log_push();
size_t argidx; size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) { for (argidx = 1; argidx < args.size(); argidx++) {
if (args[argidx] == "-full") { if (args[argidx] == "-full") {
opt_const_args += " -full"; opt_expr_args += " -full";
continue; continue;
} }
break; break;
@ -158,8 +158,8 @@ struct Ice40OptPass : public Pass {
for (auto module : design->selected_modules()) for (auto module : design->selected_modules())
run_ice40_opts(module); run_ice40_opts(module);
Pass::call(design, "opt_const " + opt_const_args); Pass::call(design, "opt_expr " + opt_expr_args);
Pass::call(design, "opt_share"); Pass::call(design, "opt_merge");
Pass::call(design, "opt_rmdff"); Pass::call(design, "opt_rmdff");
Pass::call(design, "opt_clean"); Pass::call(design, "opt_clean");

View file

@ -25,18 +25,11 @@
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN PRIVATE_NAMESPACE_BEGIN
bool check_label(bool &active, std::string run_from, std::string run_to, std::string label) struct SynthIce40Pass : public ScriptPass
{ {
if (label == run_from) SynthIce40Pass() : ScriptPass("synth_ice40", "synthesis for iCE40 FPGAs") { }
active = true;
if (label == run_to)
active = false;
return active;
}
struct SynthIce40Pass : public Pass { virtual void help() YS_OVERRIDE
SynthIce40Pass() : Pass("synth_ice40", "synthesis for iCE40 FPGAs") { }
virtual void help()
{ {
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n"); log("\n");
@ -77,73 +70,30 @@ struct SynthIce40Pass : public Pass {
log("\n"); log("\n");
log("\n"); log("\n");
log("The following commands are executed by this synthesis command:\n"); log("The following commands are executed by this synthesis command:\n");
log("\n"); help_script();
log(" begin:\n");
log(" read_verilog -lib +/ice40/cells_sim.v\n");
log(" hierarchy -check -top <top>\n");
log("\n");
log(" flatten: (unless -noflatten)\n");
log(" proc\n");
log(" flatten\n");
log(" tribuf -logic\n");
log("\n");
log(" coarse:\n");
log(" synth -run coarse\n");
log("\n");
log(" bram: (skip if -nobram)\n");
log(" memory_bram -rules +/ice40/brams.txt\n");
log(" techmap -map +/ice40/brams_map.v\n");
log("\n");
log(" fine:\n");
log(" opt -fast -mux_undef -undriven -fine\n");
log(" memory_map\n");
log(" opt -undriven -fine\n");
log(" techmap -map +/techmap.v [-map +/ice40/arith_map.v]\n");
log(" abc -dff (only if -retime)\n");
log(" ice40_opt\n");
log("\n");
log(" map_ffs:\n");
log(" dffsr2dff\n");
log(" dff2dffe -direct-match $_DFF_*\n");
log(" techmap -map +/ice40/cells_map.v\n");
log(" opt_const -mux_undef\n");
log(" simplemap\n");
log(" ice40_ffinit\n");
log(" ice40_ffssr\n");
log(" ice40_opt -full\n");
log("\n");
log(" map_luts:\n");
log(" abc (only if -abc2)\n");
log(" ice40_opt (only if -abc2)\n");
log(" abc -lut 4\n");
log(" clean\n");
log("\n");
log(" map_cells:\n");
log(" techmap -map +/ice40/cells_map.v\n");
log(" clean\n");
log("\n");
log(" check:\n");
log(" hierarchy -check\n");
log(" stat\n");
log(" check -noinit\n");
log("\n");
log(" blif:\n");
log(" write_blif -gates -attr -param <file-name>\n");
log("\n");
log(" edif:\n");
log(" write_edif <file-name>\n");
log("\n"); log("\n");
} }
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
string top_opt = "-auto-top";
string blif_file, edif_file;
bool nocarry, nobram, flatten, retime, abc2;
virtual void clear_flags() YS_OVERRIDE
{
top_opt = "-auto-top";
blif_file = "";
edif_file = "";
nocarry = false;
nobram = false;
flatten = true;
retime = false;
abc2 = false;
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{ {
std::string top_opt = "-auto-top";
std::string run_from, run_to; std::string run_from, run_to;
std::string blif_file, edif_file; clear_flags();
bool nocarry = false;
bool nobram = false;
bool flatten = true;
bool retime = false;
bool abc2 = false;
size_t argidx; size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) for (argidx = 1; argidx < args.size(); argidx++)
@ -199,98 +149,101 @@ struct SynthIce40Pass : public Pass {
if (!design->full_selection()) if (!design->full_selection())
log_cmd_error("This comannd only operates on fully selected designs!\n"); log_cmd_error("This comannd only operates on fully selected designs!\n");
bool active = run_from.empty();
log_header("Executing SYNTH_ICE40 pass.\n"); log_header("Executing SYNTH_ICE40 pass.\n");
log_push(); log_push();
if (check_label(active, run_from, run_to, "begin")) run_script(design, run_from, run_to);
{
Pass::call(design, "read_verilog -lib +/ice40/cells_sim.v");
Pass::call(design, stringf("hierarchy -check %s", top_opt.c_str()));
}
if (flatten && check_label(active, run_from, run_to, "flatten"))
{
Pass::call(design, "proc");
Pass::call(design, "flatten");
Pass::call(design, "tribuf -logic");
}
if (check_label(active, run_from, run_to, "coarse"))
{
Pass::call(design, "synth -run coarse");
}
if (!nobram && check_label(active, run_from, run_to, "bram"))
{
Pass::call(design, "memory_bram -rules +/ice40/brams.txt");
Pass::call(design, "techmap -map +/ice40/brams_map.v");
}
if (check_label(active, run_from, run_to, "fine"))
{
Pass::call(design, "opt -fast -mux_undef -undriven -fine");
Pass::call(design, "memory_map");
Pass::call(design, "opt -undriven -fine");
if (nocarry)
Pass::call(design, "techmap");
else
Pass::call(design, "techmap -map +/techmap.v -map +/ice40/arith_map.v");
if (retime)
Pass::call(design, "abc -dff");
Pass::call(design, "ice40_opt");
}
if (check_label(active, run_from, run_to, "map_ffs"))
{
Pass::call(design, "dffsr2dff");
Pass::call(design, "dff2dffe -direct-match $_DFF_*");
Pass::call(design, "techmap -map +/ice40/cells_map.v");
Pass::call(design, "opt_const -mux_undef");
Pass::call(design, "simplemap");
Pass::call(design, "ice40_ffinit");
Pass::call(design, "ice40_ffssr");
Pass::call(design, "ice40_opt -full");
}
if (check_label(active, run_from, run_to, "map_luts"))
{
if (abc2) {
Pass::call(design, "abc");
Pass::call(design, "ice40_opt");
}
Pass::call(design, "abc -lut 4");
Pass::call(design, "clean");
}
if (check_label(active, run_from, run_to, "map_cells"))
{
Pass::call(design, "techmap -map +/ice40/cells_map.v");
Pass::call(design, "clean");
}
if (check_label(active, run_from, run_to, "check"))
{
Pass::call(design, "hierarchy -check");
Pass::call(design, "stat");
Pass::call(design, "check -noinit");
}
if (check_label(active, run_from, run_to, "blif"))
{
if (!blif_file.empty())
Pass::call(design, stringf("write_blif -gates -attr -param %s", blif_file.c_str()));
}
if (check_label(active, run_from, run_to, "edif"))
{
if (!edif_file.empty())
Pass::call(design, stringf("write_edif %s", edif_file.c_str()));
}
log_pop(); log_pop();
} }
virtual void script() YS_OVERRIDE
{
if (check_label("begin"))
{
run("read_verilog -lib +/ice40/cells_sim.v");
run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
}
if (flatten && check_label("flatten", "(unless -noflatten)"))
{
run("proc");
run("flatten");
run("tribuf -logic");
}
if (check_label("coarse"))
{
run("synth -run coarse");
}
if (!nobram && check_label("bram", "(skip if -nobram)"))
{
run("memory_bram -rules +/ice40/brams.txt");
run("techmap -map +/ice40/brams_map.v");
}
if (check_label("fine"))
{
run("opt -fast -mux_undef -undriven -fine");
run("memory_map");
run("opt -undriven -fine");
if (nocarry)
run("techmap");
else
run("techmap -map +/techmap.v -map +/ice40/arith_map.v");
if (retime || help_mode)
run("abc -dff", "(only if -retime)");
run("ice40_opt");
}
if (check_label("map_ffs"))
{
run("dffsr2dff");
run("dff2dffe -direct-match $_DFF_*");
run("techmap -map +/ice40/cells_map.v");
run("opt_expr -mux_undef");
run("simplemap");
run("ice40_ffinit");
run("ice40_ffssr");
run("ice40_opt -full");
}
if (check_label("map_luts"))
{
if (abc2 || help_mode) {
run("abc", " (only if -abc2)");
run("ice40_opt", "(only if -abc2)");
}
run("abc -lut 4");
run("clean");
}
if (check_label("map_cells"))
{
run("techmap -map +/ice40/cells_map.v");
run("clean");
}
if (check_label("check"))
{
run("hierarchy -check");
run("stat");
run("check -noinit");
}
if (check_label("blif"))
{
if (!blif_file.empty() || help_mode)
run(stringf("write_blif -gates -attr -param %s", help_mode ? "<file-name>" : blif_file.c_str()));
}
if (check_label("edif"))
{
if (!edif_file.empty() || help_mode)
run(stringf("write_edif %s", help_mode ? "<file-name>" : edif_file.c_str()));
}
}
} SynthIce40Pass; } SynthIce40Pass;
PRIVATE_NAMESPACE_END PRIVATE_NAMESPACE_END