summaryrefslogtreecommitdiff
path: root/passes
diff options
context:
space:
mode:
authorRuben Undheim <ruben.undheim@gmail.com>2016-11-03 23:18:00 +0100
committerRuben Undheim <ruben.undheim@gmail.com>2016-11-03 23:18:00 +0100
commitfefe0fc0430f4f173a25e674708aa0f4f0854b31 (patch)
treeadb13b830212c269d58031f900d652f29013d2d7 /passes
parent4f096fe65b77435daba019248273e547fa18d167 (diff)
Imported yosys 0.7
Diffstat (limited to 'passes')
-rw-r--r--passes/cmds/setattr.cc16
-rw-r--r--passes/fsm/fsm.cc12
-rw-r--r--passes/fsm/fsm_expand.cc40
-rw-r--r--passes/fsm/fsm_map.cc3
-rw-r--r--passes/fsm/fsm_recode.cc6
-rw-r--r--passes/hierarchy/hierarchy.cc4
-rw-r--r--passes/opt/opt.cc10
-rw-r--r--passes/opt/opt_rmdff.cc35
-rw-r--r--passes/proc/proc_dff.cc26
-rw-r--r--passes/sat/Makefile.inc1
-rw-r--r--passes/sat/clk2fflogic.cc226
-rw-r--r--passes/sat/miter.cc38
-rw-r--r--passes/techmap/Makefile.inc1
-rw-r--r--passes/techmap/attrmap.cc23
-rw-r--r--passes/techmap/attrmvcp.cc2
-rw-r--r--passes/techmap/simplemap.cc20
-rw-r--r--passes/techmap/techmap.cc9
-rw-r--r--passes/techmap/zinit.cc151
18 files changed, 569 insertions, 54 deletions
diff --git a/passes/cmds/setattr.cc b/passes/cmds/setattr.cc
index 9b05ae32..689e3148 100644
--- a/passes/cmds/setattr.cc
+++ b/passes/cmds/setattr.cc
@@ -134,15 +134,18 @@ struct SetparamPass : public Pass {
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" setparam [ -set name value | -unset name ]... [selection]\n");
+ log(" setparam [ -type cell_type ] [ -set name value | -unset name ]... [selection]\n");
log("\n");
log("Set/unset the given parameters on the selected cells. String values must be\n");
log("passed in double quotes (\").\n");
log("\n");
+ log("The -type option can be used to change the cell type of the selected cells.\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- std::vector<setunset_t> setunset_list;
+ vector<setunset_t> setunset_list;
+ string new_cell_type;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -158,6 +161,10 @@ struct SetparamPass : public Pass {
setunset_list.push_back(setunset_t(args[++argidx]));
continue;
}
+ if (arg == "-type" && argidx+1 < args.size()) {
+ new_cell_type = RTLIL::escape_id(args[++argidx]);
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -170,8 +177,11 @@ struct SetparamPass : public Pass {
continue;
for (auto &it : module->cells_)
- if (design->selected(module, it.second))
+ if (design->selected(module, it.second)) {
+ if (!new_cell_type.empty())
+ it.second->type = new_cell_type;
do_setunset(it.second->parameters, setunset_list);
+ }
}
}
} SetparamPass;
diff --git a/passes/fsm/fsm.cc b/passes/fsm/fsm.cc
index 3b537ecd..997558b8 100644
--- a/passes/fsm/fsm.cc
+++ b/passes/fsm/fsm.cc
@@ -59,6 +59,9 @@ struct FsmPass : public Pass {
log(" -expand, -norecode, -export, -nomap\n");
log(" enable or disable passes as indicated above\n");
log("\n");
+ log(" -fullexpand\n");
+ log(" call expand with -full option\n");
+ log("\n");
log(" -encoding type\n");
log(" -fm_set_fsm_file file\n");
log(" -encfile file\n");
@@ -71,6 +74,7 @@ struct FsmPass : public Pass {
bool flag_norecode = false;
bool flag_nodetect = false;
bool flag_expand = false;
+ bool flag_fullexpand = false;
bool flag_export = false;
std::string fm_set_fsm_file_opt;
std::string encfile_opt;
@@ -110,6 +114,10 @@ struct FsmPass : public Pass {
flag_expand = true;
continue;
}
+ if (arg == "-fullexpand") {
+ flag_fullexpand = true;
+ continue;
+ }
if (arg == "-export") {
flag_export = true;
continue;
@@ -126,8 +134,8 @@ struct FsmPass : public Pass {
Pass::call(design, "opt_clean");
Pass::call(design, "fsm_opt");
- if (flag_expand) {
- Pass::call(design, "fsm_expand");
+ if (flag_expand || flag_fullexpand) {
+ Pass::call(design, flag_fullexpand ? "fsm_expand -full" : "fsm_expand");
Pass::call(design, "opt_clean");
Pass::call(design, "fsm_opt");
}
diff --git a/passes/fsm/fsm_expand.cc b/passes/fsm/fsm_expand.cc
index 3ded3f37..e7b9dcf9 100644
--- a/passes/fsm/fsm_expand.cc
+++ b/passes/fsm/fsm_expand.cc
@@ -32,6 +32,8 @@ struct FsmExpand
{
RTLIL::Module *module;
RTLIL::Cell *fsm_cell;
+ bool full_mode;
+
SigMap assign_map;
SigSet<RTLIL::Cell*, RTLIL::sort_by_name_id<RTLIL::Cell>> sig2driver, sig2user;
CellTypes ct;
@@ -45,6 +47,9 @@ struct FsmExpand
bool is_cell_merge_candidate(RTLIL::Cell *cell)
{
+ if (full_mode || cell->type == "$_MUX_")
+ return true;
+
if (cell->type == "$mux" || cell->type == "$pmux")
if (cell->getPort("\\A").size() < 2)
return true;
@@ -68,17 +73,6 @@ struct FsmExpand
if (new_signals.size() > 3)
return false;
- if (cell->hasPort("\\Y")) {
- new_signals.append(assign_map(cell->getPort("\\Y")));
- new_signals.sort_and_unify();
- new_signals.remove_const();
- new_signals.remove(assign_map(fsm_cell->getPort("\\CTRL_IN")));
- new_signals.remove(assign_map(fsm_cell->getPort("\\CTRL_OUT")));
- }
-
- if (new_signals.size() > 2)
- return false;
-
return true;
}
@@ -200,13 +194,15 @@ struct FsmExpand
fsm_data.copy_to_cell(fsm_cell);
}
- FsmExpand(RTLIL::Cell *cell, RTLIL::Design *design, RTLIL::Module *mod)
+ FsmExpand(RTLIL::Cell *cell, RTLIL::Design *design, RTLIL::Module *mod, bool full)
{
module = mod;
fsm_cell = cell;
+ full_mode = full;
assign_map.set(module);
ct.setup_internals();
+ ct.setup_stdcells();
for (auto &cell_it : module->cells_) {
RTLIL::Cell *c = cell_it.second;
@@ -249,17 +245,31 @@ struct FsmExpandPass : public Pass {
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" fsm_expand [selection]\n");
+ log(" fsm_expand [-full] [selection]\n");
log("\n");
log("The fsm_extract pass is conservative about the cells that belong to a finite\n");
log("state machine. This pass can be used to merge additional auxiliary gates into\n");
log("the finite state machine.\n");
log("\n");
+ log("By default, fsm_expand is still a bit conservative regarding merging larger\n");
+ log("word-wide cells. Call with -full to consider all cells for merging.\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
+ bool full_mode = false;
+
log_header(design, "Executing FSM_EXPAND pass (merging auxiliary logic into FSMs).\n");
- extra_args(args, 1, design);
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-full") {
+ full_mode = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
for (auto &mod_it : design->modules_) {
if (!design->selected(mod_it.second))
@@ -269,7 +279,7 @@ struct FsmExpandPass : public Pass {
if (cell_it.second->type == "$fsm" && design->selected(mod_it.second, cell_it.second))
fsm_cells.push_back(cell_it.second);
for (auto c : fsm_cells) {
- FsmExpand fsm_expand(c, design, mod_it.second);
+ FsmExpand fsm_expand(c, design, mod_it.second, full_mode);
fsm_expand.execute();
}
}
diff --git a/passes/fsm/fsm_map.cc b/passes/fsm/fsm_map.cc
index 5b32ed59..c4230375 100644
--- a/passes/fsm/fsm_map.cc
+++ b/passes/fsm/fsm_map.cc
@@ -272,7 +272,8 @@ static void map_fsm(RTLIL::Cell *fsm_cell, RTLIL::Module *module)
}
else
{
- RTLIL::SigSpec sig_a, sig_b, sig_s;
+ RTLIL::SigSpec sig_a(RTLIL::State::Sx, next_state_wire->width);
+ RTLIL::SigSpec sig_b, sig_s;
int reset_state = fsm_data.reset_state;
if (reset_state < 0)
reset_state = 0;
diff --git a/passes/fsm/fsm_recode.cc b/passes/fsm/fsm_recode.cc
index 5102d833..e1bde728 100644
--- a/passes/fsm/fsm_recode.cc
+++ b/passes/fsm/fsm_recode.cc
@@ -57,13 +57,13 @@ static void fsm_recode(RTLIL::Cell *cell, RTLIL::Module *module, FILE *fm_set_fs
log("Recoding FSM `%s' from module `%s' using `%s' encoding:\n", cell->name.c_str(), module->name.c_str(), encoding.c_str());
- if (encoding != "none" && encoding != "one-hot" && encoding != "binary" && encoding != "auto") {
+ if (encoding != "none" && encoding != "user" && encoding != "one-hot" && encoding != "binary" && encoding != "auto") {
log(" unknown encoding `%s': using auto instead.\n", encoding.c_str());
encoding = "auto";
}
- if (encoding == "none") {
- log(" nothing to do for encoding `none'.\n");
+ if (encoding == "none" || encoding == "user") {
+ log(" nothing to do for encoding `%s'.\n", encoding.c_str());
return;
}
diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index 4d1e3987..e21a7a4e 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -212,6 +212,10 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
} else if (mod->wire(conn.first) == nullptr || mod->wire(conn.first)->port_id == 0)
log_error("Module `%s' referenced in module `%s' in cell `%s' does not have a port named '%s'.\n",
log_id(cell->type), log_id(module), log_id(cell), log_id(conn.first));
+ for (auto &param : cell->parameters)
+ if (mod->avail_parameters.count(param.first) == 0 && param.first[0] != '$')
+ log_error("Module `%s' referenced in module `%s' in cell `%s' does not have a parameter named '%s'.\n",
+ log_id(cell->type), log_id(module), log_id(cell), log_id(param.first));
}
if (cell->parameters.size() == 0)
diff --git a/passes/opt/opt.cc b/passes/opt/opt.cc
index 13ea5469..021c1a03 100644
--- a/passes/opt/opt.cc
+++ b/passes/opt/opt.cc
@@ -44,7 +44,7 @@ struct OptPass : public Pass {
log(" opt_muxtree\n");
log(" opt_reduce [-fine] [-full]\n");
log(" opt_merge [-share_all]\n");
- log(" opt_rmdff\n");
+ log(" opt_rmdff [-keepdc]\n");
log(" opt_clean [-purge]\n");
log(" opt_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
log(" while <changed design>\n");
@@ -54,7 +54,7 @@ struct OptPass : public Pass {
log(" do\n");
log(" opt_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
log(" opt_merge [-share_all]\n");
- log(" opt_rmdff\n");
+ log(" opt_rmdff [-keepdc]\n");
log(" opt_clean [-purge]\n");
log(" while <changed design in opt_rmdff>\n");
log("\n");
@@ -69,6 +69,7 @@ struct OptPass : public Pass {
std::string opt_expr_args;
std::string opt_reduce_args;
std::string opt_merge_args;
+ std::string opt_rmdff_args;
bool fast_mode = false;
log_header(design, "Executing OPT pass (performing simple optimizations).\n");
@@ -108,6 +109,7 @@ struct OptPass : public Pass {
}
if (args[argidx] == "-keepdc") {
opt_expr_args += " -keepdc";
+ opt_rmdff_args += " -keepdc";
continue;
}
if (args[argidx] == "-share_all") {
@@ -128,7 +130,7 @@ struct OptPass : public Pass {
Pass::call(design, "opt_expr" + opt_expr_args);
Pass::call(design, "opt_merge" + opt_merge_args);
design->scratchpad_unset("opt.did_something");
- Pass::call(design, "opt_rmdff");
+ Pass::call(design, "opt_rmdff" + opt_rmdff_args);
if (design->scratchpad_get_bool("opt.did_something") == false)
break;
Pass::call(design, "opt_clean" + opt_clean_args);
@@ -145,7 +147,7 @@ struct OptPass : public Pass {
Pass::call(design, "opt_muxtree");
Pass::call(design, "opt_reduce" + opt_reduce_args);
Pass::call(design, "opt_merge" + opt_merge_args);
- Pass::call(design, "opt_rmdff");
+ Pass::call(design, "opt_rmdff" + opt_rmdff_args);
Pass::call(design, "opt_clean" + opt_clean_args);
Pass::call(design, "opt_expr" + opt_expr_args);
if (design->scratchpad_get_bool("opt.did_something") == false)
diff --git a/passes/opt/opt_rmdff.cc b/passes/opt/opt_rmdff.cc
index fa954afa..922f086f 100644
--- a/passes/opt/opt_rmdff.cc
+++ b/passes/opt/opt_rmdff.cc
@@ -29,6 +29,7 @@ PRIVATE_NAMESPACE_BEGIN
SigMap assign_map, dff_init_map;
SigSet<RTLIL::Cell*> mux_drivers;
dict<SigBit, pool<SigBit>> init_attributes;
+bool keepdc;
void remove_init_attr(SigSpec sig)
{
@@ -71,7 +72,11 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
RTLIL::SigSpec sig_d, sig_q, sig_c, sig_r;
RTLIL::Const val_cp, val_rp, val_rv;
- if (dff->type == "$_DFF_N_" || dff->type == "$_DFF_P_") {
+ if (dff->type == "$_FF_") {
+ sig_d = dff->getPort("\\D");
+ sig_q = dff->getPort("\\Q");
+ }
+ else if (dff->type == "$_DFF_N_" || dff->type == "$_DFF_P_") {
sig_d = dff->getPort("\\D");
sig_q = dff->getPort("\\Q");
sig_c = dff->getPort("\\C");
@@ -89,6 +94,10 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
val_rp = RTLIL::Const(dff->type[7] == 'P', 1);
val_rv = RTLIL::Const(dff->type[8] == '1', 1);
}
+ else if (dff->type == "$ff") {
+ sig_d = dff->getPort("\\D");
+ sig_q = dff->getPort("\\Q");
+ }
else if (dff->type == "$dff") {
sig_d = dff->getPort("\\D");
sig_q = dff->getPort("\\Q");
@@ -115,12 +124,12 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
bool has_init = false;
RTLIL::Const val_init;
for (auto bit : dff_init_map(sig_q).to_sigbit_vector()) {
- if (bit.wire == NULL)
+ if (bit.wire == NULL || keepdc)
has_init = true;
val_init.bits.push_back(bit.wire == NULL ? bit.data : RTLIL::State::Sx);
}
- if (dff->type == "$dff" && mux_drivers.has(sig_d)) {
+ if (dff->type.in("$ff", "$dff") && mux_drivers.has(sig_d)) {
std::set<RTLIL::Cell*> muxes;
mux_drivers.find(sig_d, muxes);
for (auto mux : muxes) {
@@ -137,7 +146,7 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
}
}
- if (sig_c.is_fully_const() && (!sig_r.size() || !has_init || val_init == val_rv)) {
+ if (!sig_c.empty() && sig_c.is_fully_const() && (!sig_r.size() || !has_init || val_init == val_rv)) {
if (val_rv.bits.size() == 0)
val_rv = val_init;
mod->connect(sig_q, val_rv);
@@ -182,7 +191,7 @@ struct OptRmdffPass : public Pass {
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" opt_rmdff [selection]\n");
+ log(" opt_rmdff [-keepdc] [selection]\n");
log("\n");
log("This pass identifies flip-flops with constant inputs and replaces them with\n");
log("a constant driver.\n");
@@ -193,7 +202,17 @@ struct OptRmdffPass : public Pass {
int total_count = 0, total_initdrv = 0;
log_header(design, "Executing OPT_RMDFF pass (remove dff with constant values).\n");
- extra_args(args, 1, design);
+ keepdc = false;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-keepdc") {
+ keepdc = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
for (auto module : design->selected_modules())
{
@@ -243,10 +262,10 @@ struct OptRmdffPass : public Pass {
if (!design->selected(module, cell))
continue;
- if (cell->type.in("$_DFF_N_", "$_DFF_P_",
+ if (cell->type.in("$_FF_", "$_DFF_N_", "$_DFF_P_",
"$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_",
"$_DFF_PN0_", "$_DFF_PN1_", "$_DFF_PP0_", "$_DFF_PP1_",
- "$dff", "$adff"))
+ "$ff", "$dff", "$adff"))
dff_list.push_back(cell->name);
if (cell->type == "$dlatch")
diff --git a/passes/proc/proc_dff.cc b/passes/proc/proc_dff.cc
index f532990c..98653dc6 100644
--- a/passes/proc/proc_dff.cc
+++ b/passes/proc/proc_dff.cc
@@ -196,7 +196,7 @@ void gen_dff(RTLIL::Module *mod, RTLIL::SigSpec sig_in, RTLIL::Const val_rst, RT
std::stringstream sstr;
sstr << "$procdff$" << (autoidx++);
- RTLIL::Cell *cell = mod->addCell(sstr.str(), arst ? "$adff" : "$dff");
+ RTLIL::Cell *cell = mod->addCell(sstr.str(), clk.empty() ? "$ff" : arst ? "$adff" : "$dff");
cell->attributes = proc->attributes;
cell->parameters["\\WIDTH"] = RTLIL::Const(sig_in.size());
@@ -204,15 +204,21 @@ void gen_dff(RTLIL::Module *mod, RTLIL::SigSpec sig_in, RTLIL::Const val_rst, RT
cell->parameters["\\ARST_POLARITY"] = RTLIL::Const(arst_polarity, 1);
cell->parameters["\\ARST_VALUE"] = val_rst;
}
- cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity, 1);
+ if (!clk.empty()) {
+ cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity, 1);
+ }
cell->setPort("\\D", sig_in);
cell->setPort("\\Q", sig_out);
if (arst)
cell->setPort("\\ARST", *arst);
- cell->setPort("\\CLK", clk);
+ if (!clk.empty())
+ cell->setPort("\\CLK", clk);
- log(" created %s cell `%s' with %s edge clock", cell->type.c_str(), cell->name.c_str(), clk_polarity ? "positive" : "negative");
+ if (!clk.empty())
+ log(" created %s cell `%s' with %s edge clock", cell->type.c_str(), cell->name.c_str(), clk_polarity ? "positive" : "negative");
+ else
+ log(" created %s cell `%s' with global clock", cell->type.c_str(), cell->name.c_str());
if (arst)
log(" and %s level reset", arst_polarity ? "positive" : "negative");
log(".\n");
@@ -236,6 +242,7 @@ void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
RTLIL::SyncRule *sync_level = NULL;
RTLIL::SyncRule *sync_edge = NULL;
RTLIL::SyncRule *sync_always = NULL;
+ bool global_clock = false;
std::map<RTLIL::SigSpec, std::set<RTLIL::SyncRule*>> many_async_rules;
@@ -267,6 +274,10 @@ void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
sig.replace(action.first, action.second, &insig);
sync_always = sync;
}
+ else if (sync->type == RTLIL::SyncType::STg) {
+ sig.replace(action.first, action.second, &insig);
+ global_clock = true;
+ }
else {
log_error("Event with any-edge sensitivity found for this signal!\n");
}
@@ -328,7 +339,7 @@ void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
continue;
}
- if (!sync_edge)
+ if (!sync_edge && !global_clock)
log_error("Missing edge-sensitive event for this signal!\n");
if (many_async_rules.size() > 0)
@@ -346,9 +357,10 @@ void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
}
else
gen_dff(mod, insig, rstval.as_const(), sig,
- sync_edge->type == RTLIL::SyncType::STp,
+ sync_edge && sync_edge->type == RTLIL::SyncType::STp,
sync_level && sync_level->type == RTLIL::SyncType::ST1,
- sync_edge->signal, sync_level ? &sync_level->signal : NULL, proc);
+ sync_edge ? sync_edge->signal : SigSpec(),
+ sync_level ? &sync_level->signal : NULL, proc);
if (free_sync_level)
delete sync_level;
diff --git a/passes/sat/Makefile.inc b/passes/sat/Makefile.inc
index 0c5f6fc6..6785b750 100644
--- a/passes/sat/Makefile.inc
+++ b/passes/sat/Makefile.inc
@@ -5,4 +5,5 @@ OBJS += passes/sat/eval.o
OBJS += passes/sat/miter.o
OBJS += passes/sat/expose.o
OBJS += passes/sat/assertpmux.o
+OBJS += passes/sat/clk2fflogic.o
diff --git a/passes/sat/clk2fflogic.cc b/passes/sat/clk2fflogic.cc
new file mode 100644
index 00000000..ef6d5dd7
--- /dev/null
+++ b/passes/sat/clk2fflogic.cc
@@ -0,0 +1,226 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct Clk2fflogicPass : public Pass {
+ Clk2fflogicPass() : Pass("clk2fflogic", "convert clocked FFs to generic $ff cells") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" clk2fflogic [options] [selection]\n");
+ log("\n");
+ log("This command replaces clocked flip-flops with generic $ff cells that use the\n");
+ log("implicit global clock. This is useful for formal verification of designs with\n");
+ log("multiple clocks.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ // bool flag_noinit = false;
+
+ log_header(design, "Executing CLK2FFLOGIC pass (convert clocked FFs to generic $ff cells).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ // if (args[argidx] == "-noinit") {
+ // flag_noinit = true;
+ // continue;
+ // }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ {
+ SigMap sigmap(module);
+ dict<SigBit, State> initbits;
+ pool<SigBit> del_initbits;
+
+ for (auto wire : module->wires())
+ if (wire->attributes.count("\\init") > 0)
+ {
+ Const initval = wire->attributes.at("\\init");
+ SigSpec initsig = sigmap(wire);
+
+ for (int i = 0; i < GetSize(initval) && i < GetSize(initsig); i++)
+ if (initval[i] == State::S0 || initval[i] == State::S1)
+ initbits[initsig[i]] = initval[i];
+ }
+
+ for (auto cell : vector<Cell*>(module->selected_cells()))
+ {
+ if (cell->type.in("$dlatch"))
+ {
+ bool enpol = cell->parameters["\\EN_POLARITY"].as_bool();
+
+ SigSpec sig_en = cell->getPort("\\EN");
+ SigSpec sig_d = cell->getPort("\\D");
+ SigSpec sig_q = cell->getPort("\\Q");
+
+ log("Replacing %s.%s (%s): EN=%s, D=%s, Q=%s\n",
+ log_id(module), log_id(cell), log_id(cell->type),
+ log_signal(sig_en), log_signal(sig_d), log_signal(sig_q));
+
+ Wire *past_q = module->addWire(NEW_ID, GetSize(sig_q));
+ module->addFf(NEW_ID, sig_q, past_q);
+
+ if (enpol)
+ module->addMux(NEW_ID, past_q, sig_d, sig_en, sig_q);
+ else
+ module->addMux(NEW_ID, sig_d, past_q, sig_en, sig_q);
+
+ Const initval;
+ bool assign_initval = false;
+ for (int i = 0; i < GetSize(sig_d); i++) {
+ SigBit qbit = sigmap(sig_q[i]);
+ if (initbits.count(qbit)) {
+ initval.bits.push_back(initbits.at(qbit));
+ del_initbits.insert(qbit);
+ } else
+ initval.bits.push_back(State::Sx);
+ if (initval.bits.back() != State::Sx)
+ assign_initval = true;
+ }
+
+ if (assign_initval)
+ past_q->attributes["\\init"] = initval;
+
+ module->remove(cell);
+ continue;
+ }
+
+ if (cell->type.in("$dff", "$adff", "$dffsr"))
+ {
+ bool clkpol = cell->parameters["\\CLK_POLARITY"].as_bool();
+
+ SigSpec clk = cell->getPort("\\CLK");
+ Wire *past_clk = module->addWire(NEW_ID);
+ past_clk->attributes["\\init"] = clkpol ? State::S1 : State::S0;
+ module->addFf(NEW_ID, clk, past_clk);
+
+ SigSpec sig_d = cell->getPort("\\D");
+ SigSpec sig_q = cell->getPort("\\Q");
+
+ log("Replacing %s.%s (%s): CLK=%s, D=%s, Q=%s\n",
+ log_id(module), log_id(cell), log_id(cell->type),
+ log_signal(clk), log_signal(sig_d), log_signal(sig_q));
+
+ SigSpec clock_edge_pattern;
+
+ if (clkpol) {
+ clock_edge_pattern.append_bit(State::S0);
+ clock_edge_pattern.append_bit(State::S1);
+ } else {
+ clock_edge_pattern.append_bit(State::S1);
+ clock_edge_pattern.append_bit(State::S0);
+ }
+
+ SigSpec clock_edge = module->Eqx(NEW_ID, {clk, SigSpec(past_clk)}, clock_edge_pattern);
+
+ Wire *past_d = module->addWire(NEW_ID, GetSize(sig_d));
+ Wire *past_q = module->addWire(NEW_ID, GetSize(sig_q));
+ module->addFf(NEW_ID, sig_d, past_d);
+ module->addFf(NEW_ID, sig_q, past_q);
+
+ if (cell->type == "$adff")
+ {
+ SigSpec arst = cell->getPort("\\ARST");
+ SigSpec qval = module->Mux(NEW_ID, past_q, past_d, clock_edge);
+ Const rstval = cell->parameters["\\ARST_VALUE"];
+
+ if (cell->parameters["\\ARST_POLARITY"].as_bool())
+ module->addMux(NEW_ID, qval, rstval, arst, sig_q);
+ else
+ module->addMux(NEW_ID, rstval, qval, arst, sig_q);
+ }
+ else
+ if (cell->type == "$dffsr")
+ {
+ SigSpec qval = module->Mux(NEW_ID, past_q, past_d, clock_edge);
+ SigSpec setval = cell->getPort("\\SET");
+ SigSpec clrval = cell->getPort("\\CLR");
+
+ if (!cell->parameters["\\SET_POLARITY"].as_bool())
+ setval = module->Not(NEW_ID, setval);
+
+ if (cell->parameters["\\CLR_POLARITY"].as_bool())
+ clrval = module->Not(NEW_ID, clrval);
+
+ qval = module->Or(NEW_ID, qval, setval);
+ module->addAnd(NEW_ID, qval, clrval, sig_q);
+ }
+ else
+ {
+ module->addMux(NEW_ID, past_q, past_d, clock_edge, sig_q);
+ }
+
+ Const initval;
+ bool assign_initval = false;
+ for (int i = 0; i < GetSize(sig_d); i++) {
+ SigBit qbit = sigmap(sig_q[i]);
+ if (initbits.count(qbit)) {
+ initval.bits.push_back(initbits.at(qbit));
+ del_initbits.insert(qbit);
+ } else
+ initval.bits.push_back(State::Sx);
+ if (initval.bits.back() != State::Sx)
+ assign_initval = true;
+ }
+
+ if (assign_initval) {
+ past_d->attributes["\\init"] = initval;
+ past_q->attributes["\\init"] = initval;
+ }
+
+ module->remove(cell);
+ continue;
+ }
+ }
+
+ for (auto wire : module->wires())
+ if (wire->attributes.count("\\init") > 0)
+ {
+ bool delete_initattr = true;
+ Const initval = wire->attributes.at("\\init");
+ SigSpec initsig = sigmap(wire);
+
+ for (int i = 0; i < GetSize(initval) && i < GetSize(initsig); i++)
+ if (del_initbits.count(initsig[i]) > 0)
+ initval[i] = State::Sx;
+ else if (initval[i] != State::Sx)
+ delete_initattr = false;
+
+ if (delete_initattr)
+ wire->attributes.erase("\\init");
+ else
+ wire->attributes.at("\\init") = initval;
+ }
+ }
+
+ }
+} Clk2fflogicPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/sat/miter.cc b/passes/sat/miter.cc
index 4854e19b..9e150b60 100644
--- a/passes/sat/miter.cc
+++ b/passes/sat/miter.cc
@@ -312,18 +312,42 @@ void create_miter_assert(struct Pass *that, std::vector<std::string> args, RTLIL
log_pop();
}
- SigSpec or_signals;
+ SigSpec assert_signals, assume_signals;
vector<Cell*> cell_list = module->cells();
- for (auto cell : cell_list) {
+ for (auto cell : cell_list)
+ {
+ if (!cell->type.in("$assert", "$assume"))
+ continue;
+
+ SigBit is_active = module->Nex(NEW_ID, cell->getPort("\\A"), State::S1);
+ SigBit is_enabled = module->Eqx(NEW_ID, cell->getPort("\\EN"), State::S1);
+
if (cell->type == "$assert") {
- SigBit is_active = module->Nex(NEW_ID, cell->getPort("\\A"), State::S1);
- SigBit is_enabled = module->Eqx(NEW_ID, cell->getPort("\\EN"), State::S1);
- or_signals.append(module->And(NEW_ID, is_active, is_enabled));
- module->remove(cell);
+ assert_signals.append(module->And(NEW_ID, is_active, is_enabled));
+ } else {
+ assume_signals.append(module->And(NEW_ID, is_active, is_enabled));
}
+
+ module->remove(cell);
}
- module->addReduceOr(NEW_ID, or_signals, trigger);
+ if (assume_signals.empty())
+ {
+ module->addReduceOr(NEW_ID, assert_signals, trigger);
+ }
+ else
+ {
+ Wire *assume_q = module->addWire(NEW_ID);
+ assume_q->attributes["\\init"] = State::S0;
+ assume_signals.append(assume_q);
+
+ SigSpec assume_nok = module->ReduceOr(NEW_ID, assume_signals);
+ SigSpec assume_ok = module->Not(NEW_ID, assume_nok);
+ module->addFf(NEW_ID, assume_nok, assume_q);
+
+ SigSpec assert_fail = module->ReduceOr(NEW_ID, assert_signals);
+ module->addAnd(NEW_ID, assert_fail, assume_ok, trigger);
+ }
if (flag_flatten) {
log_push();
diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc
index b5024fa9..311a1af9 100644
--- a/passes/techmap/Makefile.inc
+++ b/passes/techmap/Makefile.inc
@@ -31,6 +31,7 @@ OBJS += passes/techmap/deminout.o
OBJS += passes/techmap/insbuf.o
OBJS += passes/techmap/attrmvcp.o
OBJS += passes/techmap/attrmap.o
+OBJS += passes/techmap/zinit.o
endif
GENFILES += passes/techmap/techmap.inc
diff --git a/passes/techmap/attrmap.cc b/passes/techmap/attrmap.cc
index f715b63e..dec81d21 100644
--- a/passes/techmap/attrmap.cc
+++ b/passes/techmap/attrmap.cc
@@ -33,13 +33,32 @@ Const make_value(string &value)
return sig.as_const();
}
+bool string_compare_nocase(const string &str1, const string &str2)
+{
+ if (str1.size() != str2.size())
+ return false;
+
+ for (size_t i = 0; i < str1.size(); i++)
+ {
+ char ch1 = str1[i], ch2 = str2[i];
+ if ('a' <= ch1 && ch1 <= 'z')
+ ch1 -= 'a' - 'A';
+ if ('a' <= ch2 && ch2 <= 'z')
+ ch2 -= 'a' - 'A';
+ if (ch1 != ch2)
+ return false;
+ }
+
+ return true;
+}
+
bool match_name(string &name, IdString &id, bool ignore_case=false)
{
string str1 = RTLIL::escape_id(name);
string str2 = id.str();
if (ignore_case)
- return !strcasecmp(str1.c_str(), str2.c_str());
+ return string_compare_nocase(str1, str2);
return str1 == str2;
}
@@ -49,7 +68,7 @@ bool match_value(string &value, Const &val, bool ignore_case=false)
if (ignore_case && ((val.flags & RTLIL::CONST_FLAG_STRING) != 0) && GetSize(value) && value.front() == '"' && value.back() == '"') {
string str1 = value.substr(1, GetSize(value)-2);
string str2 = val.decode_string();
- return !strcasecmp(str1.c_str(), str2.c_str());
+ return string_compare_nocase(str1, str2);
}
return make_value(value) == val;
diff --git a/passes/techmap/attrmvcp.cc b/passes/techmap/attrmvcp.cc
index 50eaf61d..1537def0 100644
--- a/passes/techmap/attrmvcp.cc
+++ b/passes/techmap/attrmvcp.cc
@@ -93,6 +93,7 @@ struct AttrmvcpPass : public Pass {
for (auto cell : module->selected_cells())
for (auto &conn : cell->connections())
+ {
if (driven_mode) {
if (cell->input(conn.first))
for (auto bit : sigmap(conn.second))
@@ -102,6 +103,7 @@ struct AttrmvcpPass : public Pass {
for (auto bit : sigmap(conn.second))
net2cells[bit].insert(cell);
}
+ }
for (auto wire : module->selected_wires())
{
diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc
index 0fb64734..c6b932bd 100644
--- a/passes/techmap/simplemap.cc
+++ b/passes/techmap/simplemap.cc
@@ -388,6 +388,23 @@ void simplemap_sr(RTLIL::Module *module, RTLIL::Cell *cell)
}
}
+void simplemap_ff(RTLIL::Module *module, RTLIL::Cell *cell)
+{
+ int width = cell->parameters.at("\\WIDTH").as_int();
+
+ RTLIL::SigSpec sig_d = cell->getPort("\\D");
+ RTLIL::SigSpec sig_q = cell->getPort("\\Q");
+
+ std::string gate_type = "$_FF_";
+
+ for (int i = 0; i < width; i++) {
+ RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
+ gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src"));
+ gate->setPort("\\D", sig_d[i]);
+ gate->setPort("\\Q", sig_q[i]);
+ }
+}
+
void simplemap_dff(RTLIL::Module *module, RTLIL::Cell *cell)
{
int width = cell->parameters.at("\\WIDTH").as_int();
@@ -532,6 +549,7 @@ void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTL
mappers["$slice"] = simplemap_slice;
mappers["$concat"] = simplemap_concat;
mappers["$sr"] = simplemap_sr;
+ mappers["$ff"] = simplemap_ff;
mappers["$dff"] = simplemap_dff;
mappers["$dffe"] = simplemap_dffe;
mappers["$dffsr"] = simplemap_dffsr;
@@ -569,7 +587,7 @@ struct SimplemapPass : public Pass {
log(" $not, $pos, $and, $or, $xor, $xnor\n");
log(" $reduce_and, $reduce_or, $reduce_xor, $reduce_xnor, $reduce_bool\n");
log(" $logic_not, $logic_and, $logic_or, $mux, $tribuf\n");
- log(" $sr, $dff, $dffsr, $adff, $dlatch\n");
+ log(" $sr, $ff, $dff, $dffsr, $adff, $dlatch\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc
index b2cc492b..6784f48c 100644
--- a/passes/techmap/techmap.cc
+++ b/passes/techmap/techmap.cc
@@ -345,6 +345,12 @@ struct TechmapWorker
c->setParam("\\MEMID", Const(memory_renames[memid].str()));
}
+ if (c->type == "$mem") {
+ string memid = c->getParam("\\MEMID").decode_string();
+ apply_prefix(cell->name.str(), memid);
+ c->setParam("\\MEMID", Const(memid));
+ }
+
if (c->attributes.count("\\src"))
c->add_strpool_attribute("\\src", extra_src_attrs);
}
@@ -1164,8 +1170,9 @@ struct FlattenPass : public Pass {
worker.flatten_do_list.erase(mod->name);
}
} else {
- for (auto mod : vector<Module*>(design->modules()))
+ for (auto mod : vector<Module*>(design->modules())) {
while (worker.techmap_module(design, mod, design, handled_cells, celltypeMap, false)) { }
+ }
}
log("No more expansions possible.\n");
diff --git a/passes/techmap/zinit.cc b/passes/techmap/zinit.cc
new file mode 100644
index 00000000..a577e123
--- /dev/null
+++ b/passes/techmap/zinit.cc
@@ -0,0 +1,151 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct ZinitPass : public Pass {
+ ZinitPass() : Pass("zinit", "add inverters so all FF are zero-initialized") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" zinit [options] [selection]\n");
+ log("\n");
+ log("Add inverters as needed to make all FFs zero-initialized.\n");
+ log("\n");
+ log(" -all\n");
+ log(" also add zero initialization to uninitialized FFs\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ bool all_mode = false;
+
+ log_header(design, "Executing ZINIT pass (make all FFs zero-initialized).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-singleton") {
+ all_mode = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ {
+ SigMap sigmap(module);
+ dict<SigBit, State> initbits;
+ pool<SigBit> donebits;
+
+ for (auto wire : module->selected_wires())
+ {
+ if (wire->attributes.count("\\init") == 0)
+ continue;
+
+ SigSpec wirebits = sigmap(wire);
+ Const initval = wire->attributes.at("\\init");
+ wire->attributes.erase("\\init");
+
+ for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++)
+ {
+ SigBit bit = wirebits[i];
+ State val = initval[i];
+
+ if (val != State::S0 && val != State::S1 && bit.wire != nullptr)
+ continue;
+
+ if (initbits.count(bit)) {
+ if (initbits.at(bit) != val)
+ log_error("Conflicting init values for signal %s (%s = %s != %s).\n",
+ log_signal(bit), log_signal(SigBit(wire, i)),
+ log_signal(val), log_signal(initbits.at(bit)));
+ continue;
+ }
+
+ initbits[bit] = val;
+ }
+ }
+
+ pool<IdString> dff_types = {
+ "$ff", "$dff", "$dffe", "$dffsr", "$adff",
+ "$_FF_", "$_DFFE_NN_", "$_DFFE_NP_", "$_DFFE_PN_", "$_DFFE_PP_",
+ "$_DFFSR_NNN_", "$_DFFSR_NNP_", "$_DFFSR_NPN_", "$_DFFSR_NPP_",
+ "$_DFFSR_PNN_", "$_DFFSR_PNP_", "$_DFFSR_PPN_", "$_DFFSR_PPP_",
+ "$_DFF_N_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_",
+ "$_DFF_P_", "$_DFF_PN0_", "$_DFF_PN1_", "$_DFF_PP0_", "$_DFF_PP1_"
+ };
+
+ for (auto cell : module->selected_cells())
+ {
+ if (!dff_types.count(cell->type))
+ continue;
+
+ SigSpec sig_d = sigmap(cell->getPort("\\D"));
+ SigSpec sig_q = sigmap(cell->getPort("\\Q"));
+
+ if (GetSize(sig_d) < 1 || GetSize(sig_q) < 1)
+ continue;
+
+ Const initval;
+
+ for (int i = 0; i < GetSize(sig_q); i++) {
+ if (initbits.count(sig_q[i])) {
+ initval.bits.push_back(initbits.at(sig_q[i]));
+ donebits.insert(sig_q[i]);
+ } else
+ initval.bits.push_back(all_mode ? State::S0 : State::Sx);
+ }
+
+ Wire *initwire = module->addWire(NEW_ID, GetSize(initval));
+ initwire->attributes["\\init"] = initval;
+
+ for (int i = 0; i < GetSize(initwire); i++)
+ if (initval.bits.at(i) == State::S1)
+ {
+ sig_d[i] = module->NotGate(NEW_ID, sig_d[i]);
+ module->addNotGate(NEW_ID, SigSpec(initwire, i), sig_q[i]);
+ initwire->attributes["\\init"].bits.at(i) = State::S0;
+ }
+ else
+ {
+ module->connect(sig_q[i], SigSpec(initwire, i));
+ }
+
+ log("FF init value for cell %s (%s): %s = %s\n", log_id(cell), log_id(cell->type),
+ log_signal(sig_q), log_signal(initval));
+
+ cell->setPort("\\D", sig_d);
+ cell->setPort("\\Q", initwire);
+ }
+
+ for (auto &it : initbits)
+ if (donebits.count(it.first) == 0)
+ log_error("Failed to handle init bit %s = %s.\n", log_signal(it.first), log_signal(it.second));
+ }
+ }
+} ZinitPass;
+
+PRIVATE_NAMESPACE_END