aboutsummaryrefslogtreecommitdiffstats
path: root/passes
diff options
context:
space:
mode:
Diffstat (limited to 'passes')
-rw-r--r--passes/cmds/bugpoint.cc17
-rw-r--r--passes/cmds/check.cc8
-rw-r--r--passes/cmds/show.cc5
-rw-r--r--passes/memory/memory.cc5
-rw-r--r--passes/memory/memory_dff.cc146
-rw-r--r--passes/memory/memory_nordff.cc2
-rw-r--r--passes/pmgen/Makefile.inc9
-rw-r--r--passes/proc/Makefile.inc1
-rw-r--r--passes/proc/proc.cc2
-rw-r--r--passes/proc/proc_arst.cc54
-rw-r--r--passes/proc/proc_clean.cc33
-rw-r--r--passes/proc/proc_dff.cc4
-rw-r--r--passes/proc/proc_dlatch.cc7
-rw-r--r--passes/proc/proc_init.cc11
-rw-r--r--passes/proc/proc_memwr.cc111
-rw-r--r--passes/sat/sim.cc2
-rw-r--r--passes/techmap/abc9_ops.cc10
17 files changed, 248 insertions, 179 deletions
diff --git a/passes/cmds/bugpoint.cc b/passes/cmds/bugpoint.cc
index da81e7f09..40207b1fc 100644
--- a/passes/cmds/bugpoint.cc
+++ b/passes/cmds/bugpoint.cc
@@ -339,6 +339,23 @@ struct BugpointPass : public Pass {
return design_copy;
}
}
+ int i = 0;
+ for (auto it = sy->mem_write_actions.begin(); it != sy->mem_write_actions.end(); ++it, ++i)
+ {
+ if (index++ == seed)
+ {
+ log_header(design, "Trying to remove sync %s memwr %s %s %s %s in %s.%s.\n", log_signal(sy->signal), log_id(it->memid), log_signal(it->address), log_signal(it->data), log_signal(it->enable), log_id(mod), log_id(pr.first));
+ sy->mem_write_actions.erase(it);
+ // Remove the bit for removed action from other actions' priority masks.
+ for (auto it2 = sy->mem_write_actions.begin(); it2 != sy->mem_write_actions.end(); ++it2) {
+ auto &mask = it2->priority_mask;
+ if (GetSize(mask) > i) {
+ mask.bits.erase(mask.bits.begin() + i);
+ }
+ }
+ return design_copy;
+ }
+ }
}
}
}
diff --git a/passes/cmds/check.cc b/passes/cmds/check.cc
index 36febb98a..b502b0788 100644
--- a/passes/cmds/check.cc
+++ b/passes/cmds/check.cc
@@ -141,6 +141,14 @@ struct CheckPass : public Pass {
for (auto bit : sigmap(action.second))
if (bit.wire) used_wires.insert(bit);
}
+ for (auto memwr : sync->mem_write_actions) {
+ for (auto bit : sigmap(memwr.address))
+ if (bit.wire) used_wires.insert(bit);
+ for (auto bit : sigmap(memwr.data))
+ if (bit.wire) used_wires.insert(bit);
+ for (auto bit : sigmap(memwr.enable))
+ if (bit.wire) used_wires.insert(bit);
+ }
}
}
diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc
index 0c96f8c5d..a389c3179 100644
--- a/passes/cmds/show.cc
+++ b/passes/cmds/show.cc
@@ -339,6 +339,11 @@ struct ShowWorker
{
input_signals.insert(obj->signal);
collect_proc_signals(obj->actions, input_signals, output_signals);
+ for (auto it : obj->mem_write_actions) {
+ input_signals.insert(it.address);
+ input_signals.insert(it.data);
+ input_signals.insert(it.enable);
+ }
}
void collect_proc_signals(RTLIL::Process *obj, std::set<RTLIL::SigSpec> &input_signals, std::set<RTLIL::SigSpec> &output_signals)
diff --git a/passes/memory/memory.cc b/passes/memory/memory.cc
index 282517992..9dec05db8 100644
--- a/passes/memory/memory.cc
+++ b/passes/memory/memory.cc
@@ -36,7 +36,7 @@ struct MemoryPass : public Pass {
log("This pass calls all the other memory_* passes in a useful order:\n");
log("\n");
log(" opt_mem\n");
- log(" memory_dff [-nordff] (-memx implies -nordff)\n");
+ log(" memory_dff (skipped if called with -nordff or -memx)\n");
log(" opt_clean\n");
log(" memory_share\n");
log(" opt_clean\n");
@@ -83,7 +83,8 @@ struct MemoryPass : public Pass {
extra_args(args, argidx, design);
Pass::call(design, "opt_mem");
- Pass::call(design, flag_nordff ? "memory_dff -nordff" : "memory_dff");
+ if (!flag_nordff)
+ Pass::call(design, "memory_dff");
Pass::call(design, "opt_clean");
Pass::call(design, "memory_share");
if (flag_memx)
diff --git a/passes/memory/memory_dff.cc b/passes/memory/memory_dff.cc
index 4adcb462e..83c9d7631 100644
--- a/passes/memory/memory_dff.cc
+++ b/passes/memory/memory_dff.cc
@@ -33,8 +33,6 @@ struct MemoryDffWorker
vector<Cell*> dff_cells;
dict<SigBit, SigBit> invbits;
dict<SigBit, int> sigbit_users_count;
- dict<SigSpec, Cell*> mux_cells_a, mux_cells_b;
- pool<Cell*> forward_merged_dffs, candidate_dffs;
FfInitVals initvals;
MemoryDffWorker(Module *module) : module(module), sigmap(module)
@@ -114,7 +112,6 @@ struct MemoryDffWorker
bit = d;
clk = this_clk;
clk_polarity = this_clk_polarity;
- candidate_dffs.insert(cell);
goto replaced_this_bit;
}
@@ -136,8 +133,6 @@ struct MemoryDffWorker
for (auto cell : dff_cells)
{
- if (forward_merged_dffs.count(cell))
- continue;
if (!cell->type.in(ID($dff), ID($dffe)))
continue;
@@ -187,7 +182,6 @@ struct MemoryDffWorker
clk_polarity = this_clk_polarity;
en = this_en;
en_polarity = this_en_polarity;
- candidate_dffs.insert(cell);
goto replaced_this_bit;
}
@@ -198,51 +192,6 @@ struct MemoryDffWorker
return true;
}
- void handle_wr_cell(RTLIL::Cell *cell)
- {
- log("Checking cell `%s' in module `%s': ", cell->name.c_str(), module->name.c_str());
-
- RTLIL::SigSpec clk = RTLIL::SigSpec(RTLIL::State::Sx);
- bool clk_polarity = 0;
- candidate_dffs.clear();
-
- RTLIL::SigSpec sig_addr = cell->getPort(ID::ADDR);
- if (!find_sig_before_dff(sig_addr, clk, clk_polarity)) {
- log("no (compatible) $dff for address input found.\n");
- return;
- }
-
- RTLIL::SigSpec sig_data = cell->getPort(ID::DATA);
- if (!find_sig_before_dff(sig_data, clk, clk_polarity)) {
- log("no (compatible) $dff for data input found.\n");
- return;
- }
-
- RTLIL::SigSpec sig_en = cell->getPort(ID::EN);
- if (!find_sig_before_dff(sig_en, clk, clk_polarity)) {
- log("no (compatible) $dff for enable input found.\n");
- return;
- }
-
- if (clk != RTLIL::SigSpec(RTLIL::State::Sx))
- {
- for (auto cell : candidate_dffs)
- forward_merged_dffs.insert(cell);
-
- cell->setPort(ID::CLK, clk);
- cell->setPort(ID::ADDR, sig_addr);
- cell->setPort(ID::DATA, sig_data);
- cell->setPort(ID::EN, sig_en);
- cell->parameters[ID::CLK_ENABLE] = RTLIL::Const(1);
- cell->parameters[ID::CLK_POLARITY] = RTLIL::Const(clk_polarity);
-
- log("merged $dff to cell.\n");
- return;
- }
-
- log("no (compatible) $dff found.\n");
- }
-
void disconnect_dff(RTLIL::SigSpec sig)
{
sigmap.apply(sig);
@@ -276,58 +225,19 @@ struct MemoryDffWorker
if (sigbit_users_count[bit] > 1)
goto skip_ff_after_read_merging;
- if (mux_cells_a.count(sig_data) || mux_cells_b.count(sig_data))
+ if (find_sig_after_dffe(sig_data, clk_data, clk_polarity, en_data, en_polarity) && clk_data != RTLIL::SigSpec(RTLIL::State::Sx))
{
- RTLIL::SigSpec en;
- std::vector<RTLIL::SigSpec> check_q;
-
- do {
- bool enable_invert = mux_cells_a.count(sig_data) != 0;
- Cell *mux = enable_invert ? mux_cells_a.at(sig_data) : mux_cells_b.at(sig_data);
- check_q.push_back(sigmap(mux->getPort(enable_invert ? ID::B : ID::A)));
- sig_data = sigmap(mux->getPort(ID::Y));
- en.append(enable_invert ? module->LogicNot(NEW_ID, mux->getPort(ID::S)) : mux->getPort(ID::S));
- } while (mux_cells_a.count(sig_data) || mux_cells_b.count(sig_data));
-
- for (auto bit : sig_data)
- if (sigbit_users_count[bit] > 1)
- goto skip_ff_after_read_merging;
-
- if (find_sig_after_dffe(sig_data, clk_data, clk_polarity, en_data, en_polarity) && clk_data != RTLIL::SigSpec(RTLIL::State::Sx) &&
- std::all_of(check_q.begin(), check_q.end(), [&](const SigSpec &cq) {return cq == sig_data; }))
- {
- if (en_data != State::S1 || !en_polarity) {
- if (!en_polarity)
- en_data = module->LogicNot(NEW_ID, en_data);
- en.append(en_data);
- }
- disconnect_dff(sig_data);
- cell->setPort(ID::CLK, clk_data);
- cell->setPort(ID::EN, en.size() > 1 ? module->ReduceAnd(NEW_ID, en) : en);
- cell->setPort(ID::DATA, sig_data);
- cell->parameters[ID::CLK_ENABLE] = RTLIL::Const(1);
- cell->parameters[ID::CLK_POLARITY] = RTLIL::Const(clk_polarity);
- cell->parameters[ID::TRANSPARENT] = RTLIL::Const(0);
- log("merged data $dff with rd enable to cell.\n");
- return;
- }
- }
- else
- {
- if (find_sig_after_dffe(sig_data, clk_data, clk_polarity, en_data, en_polarity) && clk_data != RTLIL::SigSpec(RTLIL::State::Sx))
- {
- if (!en_polarity)
- en_data = module->LogicNot(NEW_ID, en_data);
- disconnect_dff(sig_data);
- cell->setPort(ID::CLK, clk_data);
- cell->setPort(ID::EN, en_data);
- cell->setPort(ID::DATA, sig_data);
- cell->parameters[ID::CLK_ENABLE] = RTLIL::Const(1);
- cell->parameters[ID::CLK_POLARITY] = RTLIL::Const(clk_polarity);
- cell->parameters[ID::TRANSPARENT] = RTLIL::Const(0);
- log("merged data $dff to cell.\n");
- return;
- }
+ if (!en_polarity)
+ en_data = module->LogicNot(NEW_ID, en_data);
+ disconnect_dff(sig_data);
+ cell->setPort(ID::CLK, clk_data);
+ cell->setPort(ID::EN, en_data);
+ cell->setPort(ID::DATA, sig_data);
+ cell->parameters[ID::CLK_ENABLE] = RTLIL::Const(1);
+ cell->parameters[ID::CLK_POLARITY] = RTLIL::Const(clk_polarity);
+ cell->parameters[ID::TRANSPARENT] = RTLIL::Const(0);
+ log("merged data $dff to cell.\n");
+ return;
}
skip_ff_after_read_merging:;
@@ -349,7 +259,7 @@ struct MemoryDffWorker
log("no (compatible) $dff found.\n");
}
- void run(bool flag_wr_only)
+ void run()
{
for (auto wire : module->wires()) {
if (wire->port_output)
@@ -360,10 +270,6 @@ struct MemoryDffWorker
for (auto cell : module->cells()) {
if (cell->type.in(ID($dff), ID($dffe), ID($sdff), ID($sdffe), ID($sdffce)))
dff_cells.push_back(cell);
- if (cell->type == ID($mux)) {
- mux_cells_a[sigmap(cell->getPort(ID::A))] = cell;
- mux_cells_b[sigmap(cell->getPort(ID::B))] = cell;
- }
if (cell->type.in(ID($not), ID($_NOT_)) || (cell->type == ID($logic_not) && GetSize(cell->getPort(ID::A)) == 1)) {
SigSpec sig_a = cell->getPort(ID::A);
SigSpec sig_y = cell->getPort(ID::Y);
@@ -381,51 +287,37 @@ struct MemoryDffWorker
}
for (auto cell : module->selected_cells())
- if (cell->type == ID($memwr) && !cell->parameters[ID::CLK_ENABLE].as_bool())
- handle_wr_cell(cell);
-
- if (!flag_wr_only)
- for (auto cell : module->selected_cells())
- if (cell->type == ID($memrd) && !cell->parameters[ID::CLK_ENABLE].as_bool())
- handle_rd_cell(cell);
+ if (cell->type == ID($memrd) && !cell->parameters[ID::CLK_ENABLE].as_bool())
+ handle_rd_cell(cell);
}
};
struct MemoryDffPass : public Pass {
- MemoryDffPass() : Pass("memory_dff", "merge input/output DFFs into memories") { }
+ MemoryDffPass() : Pass("memory_dff", "merge input/output DFFs into memory read ports") { }
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" memory_dff [options] [selection]\n");
log("\n");
- log("This pass detects DFFs at memory ports and merges them into the memory port.\n");
+ log("This pass detects DFFs at memory read ports and merges them into the memory port.\n");
log("I.e. it consumes an asynchronous memory port and the flip-flops at its\n");
log("interface and yields a synchronous memory port.\n");
log("\n");
- log(" -nordfff\n");
- log(" do not merge registers on read ports\n");
- log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
- bool flag_wr_only = false;
-
- log_header(design, "Executing MEMORY_DFF pass (merging $dff cells to $memrd and $memwr).\n");
+ log_header(design, "Executing MEMORY_DFF pass (merging $dff cells to $memrd).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
- if (args[argidx] == "-nordff" || args[argidx] == "-wr_only") {
- flag_wr_only = true;
- continue;
- }
break;
}
extra_args(args, argidx, design);
for (auto mod : design->selected_modules()) {
MemoryDffWorker worker(mod);
- worker.run(flag_wr_only);
+ worker.run();
}
}
} MemoryDffPass;
diff --git a/passes/memory/memory_nordff.cc b/passes/memory/memory_nordff.cc
index a4fdcfc38..bb853c483 100644
--- a/passes/memory/memory_nordff.cc
+++ b/passes/memory/memory_nordff.cc
@@ -33,7 +33,7 @@ struct MemoryNordffPass : public Pass {
log(" memory_nordff [options] [selection]\n");
log("\n");
log("This pass extracts FFs from memory read ports. This results in a netlist\n");
- log("similar to what one would get from calling memory_dff with -nordff.\n");
+ log("similar to what one would get from not calling memory_dff.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc
index c6bbc386a..a7ef64282 100644
--- a/passes/pmgen/Makefile.inc
+++ b/passes/pmgen/Makefile.inc
@@ -4,24 +4,31 @@
# --------------------------------------
OBJS += passes/pmgen/test_pmgen.o
+GENFILES += passes/pmgen/test_pmgen_pm.h
passes/pmgen/test_pmgen.o: passes/pmgen/test_pmgen_pm.h passes/pmgen/ice40_dsp_pm.h passes/pmgen/peepopt_pm.h passes/pmgen/xilinx_srl_pm.h
$(eval $(call add_extra_objs,passes/pmgen/test_pmgen_pm.h))
# --------------------------------------
OBJS += passes/pmgen/ice40_dsp.o
+GENFILES += passes/pmgen/ice40_dsp_pm.h
passes/pmgen/ice40_dsp.o: passes/pmgen/ice40_dsp_pm.h
$(eval $(call add_extra_objs,passes/pmgen/ice40_dsp_pm.h))
# --------------------------------------
OBJS += passes/pmgen/ice40_wrapcarry.o
+GENFILES += passes/pmgen/ice40_wrapcarry_pm.h
passes/pmgen/ice40_wrapcarry.o: passes/pmgen/ice40_wrapcarry_pm.h
$(eval $(call add_extra_objs,passes/pmgen/ice40_wrapcarry_pm.h))
# --------------------------------------
OBJS += passes/pmgen/xilinx_dsp.o
+GENFILES += passes/pmgen/xilinx_dsp_pm.h
+GENFILES += passes/pmgen/xilinx_dsp48a_pm.h
+GENFILES += passes/pmgen/xilinx_dsp_CREG_pm.h
+GENFILES += passes/pmgen/xilinx_dsp_cascade_pm.h
passes/pmgen/xilinx_dsp.o: passes/pmgen/xilinx_dsp_pm.h passes/pmgen/xilinx_dsp48a_pm.h passes/pmgen/xilinx_dsp_CREG_pm.h passes/pmgen/xilinx_dsp_cascade_pm.h
$(eval $(call add_extra_objs,passes/pmgen/xilinx_dsp_pm.h))
$(eval $(call add_extra_objs,passes/pmgen/xilinx_dsp48a_pm.h))
@@ -31,6 +38,7 @@ $(eval $(call add_extra_objs,passes/pmgen/xilinx_dsp_cascade_pm.h))
# --------------------------------------
OBJS += passes/pmgen/peepopt.o
+GENFILES += passes/pmgen/peepopt_pm.h
passes/pmgen/peepopt.o: passes/pmgen/peepopt_pm.h
$(eval $(call add_extra_objs,passes/pmgen/peepopt_pm.h))
@@ -43,5 +51,6 @@ passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN)
# --------------------------------------
OBJS += passes/pmgen/xilinx_srl.o
+GENFILES += passes/pmgen/xilinx_srl_pm.h
passes/pmgen/xilinx_srl.o: passes/pmgen/xilinx_srl_pm.h
$(eval $(call add_extra_objs,passes/pmgen/xilinx_srl_pm.h))
diff --git a/passes/proc/Makefile.inc b/passes/proc/Makefile.inc
index 4b56979f8..50244bf33 100644
--- a/passes/proc/Makefile.inc
+++ b/passes/proc/Makefile.inc
@@ -8,3 +8,4 @@ OBJS += passes/proc/proc_arst.o
OBJS += passes/proc/proc_mux.o
OBJS += passes/proc/proc_dlatch.o
OBJS += passes/proc/proc_dff.o
+OBJS += passes/proc/proc_memwr.o
diff --git a/passes/proc/proc.cc b/passes/proc/proc.cc
index 09cf0af82..2151b0ce7 100644
--- a/passes/proc/proc.cc
+++ b/passes/proc/proc.cc
@@ -43,6 +43,7 @@ struct ProcPass : public Pass {
log(" proc_mux\n");
log(" proc_dlatch\n");
log(" proc_dff\n");
+ log(" proc_memwr\n");
log(" proc_clean\n");
log("\n");
log("This replaces the processes in the design with multiplexers,\n");
@@ -102,6 +103,7 @@ struct ProcPass : public Pass {
Pass::call(design, ifxmode ? "proc_mux -ifx" : "proc_mux");
Pass::call(design, "proc_dlatch");
Pass::call(design, "proc_dff");
+ Pass::call(design, "proc_memwr");
Pass::call(design, "proc_clean");
log_pop();
diff --git a/passes/proc/proc_arst.cc b/passes/proc/proc_arst.cc
index 16db461b2..4351321e0 100644
--- a/passes/proc/proc_arst.cc
+++ b/passes/proc/proc_arst.cc
@@ -153,6 +153,30 @@ void eliminate_const(RTLIL::Module *mod, RTLIL::CaseRule *cs, RTLIL::SigSpec con
}
}
+RTLIL::SigSpec apply_reset(RTLIL::Module *mod, RTLIL::Process *proc, RTLIL::SyncRule *sync, SigMap &assign_map, RTLIL::SigSpec root_sig, bool polarity, RTLIL::SigSpec sig, RTLIL::SigSpec log_sig) {
+ RTLIL::SigSpec rspec = assign_map(sig);
+ RTLIL::SigSpec rval = RTLIL::SigSpec(RTLIL::State::Sm, rspec.size());
+ for (int i = 0; i < GetSize(rspec); i++)
+ if (rspec[i].wire == NULL)
+ rval[i] = rspec[i];
+ RTLIL::SigSpec last_rval;
+ for (int count = 0; rval != last_rval; count++) {
+ last_rval = rval;
+ apply_const(mod, rspec, rval, &proc->root_case, root_sig, polarity, false);
+ assign_map.apply(rval);
+ if (rval.is_fully_const())
+ break;
+ if (count > 100)
+ log_error("Async reset %s yields endless loop at value %s for signal %s.\n",
+ log_signal(sync->signal), log_signal(rval), log_signal(log_sig));
+ rspec = rval;
+ }
+ if (rval.has_marked_bits())
+ log_error("Async reset %s yields non-constant value %s for signal %s.\n",
+ log_signal(sync->signal), log_signal(rval), log_signal(log_sig));
+ return rval;
+}
+
void proc_arst(RTLIL::Module *mod, RTLIL::Process *proc, SigMap &assign_map)
{
restart_proc_arst:
@@ -172,28 +196,18 @@ restart_proc_arst:
sync->type = sync->type == RTLIL::SyncType::STp ? RTLIL::SyncType::ST1 : RTLIL::SyncType::ST0;
}
for (auto &action : sync->actions) {
- RTLIL::SigSpec rspec = assign_map(action.second);
- RTLIL::SigSpec rval = RTLIL::SigSpec(RTLIL::State::Sm, rspec.size());
- for (int i = 0; i < GetSize(rspec); i++)
- if (rspec[i].wire == NULL)
- rval[i] = rspec[i];
- RTLIL::SigSpec last_rval;
- for (int count = 0; rval != last_rval; count++) {
- last_rval = rval;
- apply_const(mod, rspec, rval, &proc->root_case, root_sig, polarity, false);
- assign_map.apply(rval);
- if (rval.is_fully_const())
- break;
- if (count > 100)
- log_error("Async reset %s yields endless loop at value %s for signal %s.\n",
- log_signal(sync->signal), log_signal(rval), log_signal(action.first));
- rspec = rval;
+ action.second = apply_reset(mod, proc, sync, assign_map, root_sig, polarity, action.second, action.first);
+ }
+ for (auto &memwr : sync->mem_write_actions) {
+ RTLIL::SigSpec en = apply_reset(mod, proc, sync, assign_map, root_sig, polarity, memwr.enable, memwr.enable);
+ if (!en.is_fully_zero()) {
+ log_error("Async reset %s causes memory write to %s.\n",
+ log_signal(sync->signal), log_id(memwr.memid));
}
- if (rval.has_marked_bits())
- log_error("Async reset %s yields non-constant value %s for signal %s.\n",
- log_signal(sync->signal), log_signal(rval), log_signal(action.first));
- action.second = rval;
+ apply_reset(mod, proc, sync, assign_map, root_sig, polarity, memwr.address, memwr.address);
+ apply_reset(mod, proc, sync, assign_map, root_sig, polarity, memwr.data, memwr.data);
}
+ sync->mem_write_actions.clear();
eliminate_const(mod, &proc->root_case, root_sig, polarity);
goto restart_proc_arst;
}
diff --git a/passes/proc/proc_clean.cc b/passes/proc/proc_clean.cc
index 5e78b7316..9e0b671f4 100644
--- a/passes/proc/proc_clean.cc
+++ b/passes/proc/proc_clean.cc
@@ -76,22 +76,33 @@ void proc_clean_switch(RTLIL::SwitchRule *sw, RTLIL::CaseRule *parent, bool &did
}
else
{
- bool all_fully_def = true;
for (auto cs : sw->cases)
- {
if (max_depth != 0)
proc_clean_case(cs, did_something, count, max_depth-1);
- int size = 0;
- for (auto cmp : cs->compare)
+
+ bool is_parallel_case = sw->get_bool_attribute(ID::parallel_case);
+ bool is_full_case = sw->get_bool_attribute(ID::full_case);
+
+ // Empty case removal. The rules are:
+ //
+ // - for full_case: only remove cases if *all* cases are empty
+ // - for parallel_case but not full_case: remove any empty case
+ // - for non-parallel and non-full case: remove the final case if it's empty
+
+ if (is_full_case)
+ {
+ bool all_empty = true;
+ for (auto cs : sw->cases)
+ if (!cs->empty())
+ all_empty = false;
+ if (all_empty)
{
- size += cmp.size();
- if (!cmp.is_fully_def())
- all_fully_def = false;
+ for (auto cs : sw->cases)
+ delete cs;
+ sw->cases.clear();
}
- if (sw->signal.size() != size)
- all_fully_def = false;
}
- if (all_fully_def)
+ else if (is_parallel_case)
{
for (auto cs = sw->cases.begin(); cs != sw->cases.end();)
{
@@ -150,7 +161,7 @@ void proc_clean(RTLIL::Module *mod, RTLIL::Process *proc, int &total_count, bool
for (size_t j = 0; j < proc->syncs[i]->actions.size(); j++)
if (proc->syncs[i]->actions[j].first.size() == 0)
proc->syncs[i]->actions.erase(proc->syncs[i]->actions.begin() + (j--));
- if (proc->syncs[i]->actions.size() == 0) {
+ if (proc->syncs[i]->actions.size() == 0 && proc->syncs[i]->mem_write_actions.size() == 0) {
delete proc->syncs[i];
proc->syncs.erase(proc->syncs.begin() + (i--));
}
diff --git a/passes/proc/proc_dff.cc b/passes/proc/proc_dff.cc
index e320a72a6..2b6ca8449 100644
--- a/passes/proc/proc_dff.cc
+++ b/passes/proc/proc_dff.cc
@@ -328,6 +328,10 @@ void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
ce.assign_map.apply(sig);
if (rstval == sig) {
+ if (sync_level->type == RTLIL::SyncType::ST1)
+ insig = mod->Mux(NEW_ID, insig, sig, sync_level->signal);
+ else
+ insig = mod->Mux(NEW_ID, sig, insig, sync_level->signal);
rstval = RTLIL::SigSpec(RTLIL::State::Sz, sig.size());
sync_level = NULL;
}
diff --git a/passes/proc/proc_dlatch.cc b/passes/proc/proc_dlatch.cc
index 7b8c05b21..03d072cf4 100644
--- a/passes/proc/proc_dlatch.cc
+++ b/passes/proc/proc_dlatch.cc
@@ -342,7 +342,6 @@ struct proc_dlatch_db_t
void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc)
{
- std::vector<RTLIL::SyncRule*> new_syncs;
RTLIL::SigSig latches_bits, nolatches_bits;
dict<SigBit, SigBit> latches_out_in;
dict<SigBit, int> latches_hold;
@@ -351,7 +350,6 @@ void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc)
for (auto sr : proc->syncs)
{
if (sr->type != RTLIL::SyncType::STa) {
- new_syncs.push_back(sr);
continue;
}
@@ -373,8 +371,7 @@ void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc)
for (int i = 0; i < GetSize(ss.first); i++)
latches_out_in[ss.first[i]] = ss.second[i];
}
-
- delete sr;
+ sr->actions.clear();
}
latches_out_in.sort();
@@ -441,8 +438,6 @@ void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc)
offset += width;
}
-
- new_syncs.swap(proc->syncs);
}
struct ProcDlatchPass : public Pass {
diff --git a/passes/proc/proc_init.cc b/passes/proc/proc_init.cc
index eb323038d..b705251dd 100644
--- a/passes/proc/proc_init.cc
+++ b/passes/proc/proc_init.cc
@@ -71,17 +71,8 @@ void proc_init(RTLIL::Module *mod, SigMap &sigmap, RTLIL::Process *proc)
offset += lhs_c.width;
}
}
+ sync->actions.clear();
}
-
- if (found_init) {
- std::vector<RTLIL::SyncRule*> new_syncs;
- for (auto &sync : proc->syncs)
- if (sync->type == RTLIL::SyncType::STi)
- delete sync;
- else
- new_syncs.push_back(sync);
- proc->syncs.swap(new_syncs);
- }
}
struct ProcInitPass : public Pass {
diff --git a/passes/proc/proc_memwr.cc b/passes/proc/proc_memwr.cc
new file mode 100644
index 000000000..f898979d8
--- /dev/null
+++ b/passes/proc/proc_memwr.cc
@@ -0,0 +1,111 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2021 Marcelina Koƛcielnicka <mwk@0x04.net>
+ *
+ * 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/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/ffinit.h"
+#include "kernel/consteval.h"
+#include "kernel/log.h"
+#include <sstream>
+#include <stdlib.h>
+#include <stdio.h>
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+void proc_memwr(RTLIL::Module *mod, RTLIL::Process *proc, dict<IdString, int> &next_priority)
+{
+ for (auto sr : proc->syncs)
+ {
+ for (auto memwr : sr->mem_write_actions) {
+ RTLIL::Cell *cell = mod->addCell(NEW_ID, ID($memwr));
+ cell->attributes = memwr.attributes;
+ cell->setParam(ID::MEMID, Const(memwr.memid.str()));
+ cell->setParam(ID::ABITS, GetSize(memwr.address));
+ cell->setParam(ID::WIDTH, GetSize(memwr.data));
+ cell->setParam(ID::PRIORITY, next_priority[memwr.memid]++);
+ cell->setPort(ID::ADDR, memwr.address);
+ cell->setPort(ID::DATA, memwr.data);
+ SigSpec enable = memwr.enable;
+ for (auto sr2 : proc->syncs) {
+ if (sr2->type == RTLIL::SyncType::ST0) {
+ log_assert(sr2->mem_write_actions.empty());
+ enable = mod->Mux(NEW_ID, Const(State::S0, GetSize(enable)), enable, sr2->signal);
+ } else if (sr2->type == RTLIL::SyncType::ST1) {
+ log_assert(sr2->mem_write_actions.empty());
+ enable = mod->Mux(NEW_ID, enable, Const(State::S0, GetSize(enable)), sr2->signal);
+ }
+ }
+ cell->setPort(ID::EN, enable);
+ if (sr->type == RTLIL::SyncType::STa) {
+ cell->setPort(ID::CLK, State::Sx);
+ cell->setParam(ID::CLK_ENABLE, State::S0);
+ cell->setParam(ID::CLK_POLARITY, State::Sx);
+ } else if (sr->type == RTLIL::SyncType::STp) {
+ cell->setPort(ID::CLK, sr->signal);
+ cell->setParam(ID::CLK_ENABLE, State::S1);
+ cell->setParam(ID::CLK_POLARITY, State::S1);
+ } else if (sr->type == RTLIL::SyncType::STn) {
+ cell->setPort(ID::CLK, sr->signal);
+ cell->setParam(ID::CLK_ENABLE, State::S1);
+ cell->setParam(ID::CLK_POLARITY, State::S0);
+ } else {
+ log_error("process memory write with unsupported sync type in %s.%s", log_id(mod), log_id(proc));
+ }
+ }
+ sr->mem_write_actions.clear();
+ }
+}
+
+struct ProcMemWrPass : public Pass {
+ ProcMemWrPass() : Pass("proc_memwr", "extract memory writes from processes") { }
+ void help() override
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" proc_memwr [selection]\n");
+ log("\n");
+ log("This pass converts memory writes in processes into $memwr cells.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
+ {
+ log_header(design, "Executing PROC_MEMWR pass (convert process memory writes to cells).\n");
+
+ extra_args(args, 1, design);
+
+ for (auto module : design->selected_modules()) {
+ dict<IdString, int> next_priority;
+ for (auto cell : module->cells()) {
+ if (cell->type == ID($memwr)) {
+ IdString memid = cell->parameters.at(ID::MEMID).decode_string();
+ int priority = cell->parameters.at(ID::PRIORITY).as_int();
+ if (priority >= next_priority[memid])
+ next_priority[memid] = priority + 1;
+ }
+ }
+ for (auto &proc_it : module->processes)
+ if (design->selected(module, proc_it.second))
+ proc_memwr(module, proc_it.second, next_priority);
+ }
+ }
+} ProcMemWrPass;
+
+PRIVATE_NAMESPACE_END
+
diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc
index 3ba66bd33..922be886c 100644
--- a/passes/sat/sim.cc
+++ b/passes/sat/sim.cc
@@ -271,7 +271,7 @@ struct SimInstance
{
auto child = children.at(cell);
for (auto &conn: cell->connections())
- if (cell->input(conn.first)) {
+ if (cell->input(conn.first) && GetSize(conn.second)) {
Const value = get_state(conn.second);
child->set_state(child->module->wire(conn.first), value);
}
diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc
index 98d0207c4..3f3e667de 100644
--- a/passes/techmap/abc9_ops.cc
+++ b/passes/techmap/abc9_ops.cc
@@ -778,7 +778,15 @@ void prep_xaiger(RTLIL::Module *module, bool dff)
continue;
if (!box_module->get_bool_attribute(ID::abc9_box))
continue;
- log_assert(cell->parameters.empty());
+ if (!cell->parameters.empty())
+ // At this stage of the ABC9 flow, all modules must be nonparametric, because ABC itself requires concrete netlists, and the presence of
+ // parameters implies a non-concrete netlist. This error needs some explaining, because there are (at least) two ways to get this:
+ // 1) You have an (* abc9_box *) parametric whitebox but due to a bug somewhere this hasn't been monomorphised into a concrete blackbox.
+ // This is a bug, and a bug report would be welcomed.
+ // 2) You have an (* abc9_box *) parametric blackbox (e.g. to store associated cell data) but want to provide timing data for ABC9.
+ // This is not supported due to the presence of parameters. If you want to store associated cell data for a box, one approach could be
+ // to techmap the parameters to constant module inputs, and then after ABC9 use _TECHMAP_CONSTVAL_XX_ to retrieve the values again.
+ log_error("Black box '%s' is marked (* abc9_box *) and has parameters, which is forbidden in prep_xaiger\n", log_id(cell_name));
log_assert(box_module->get_blackbox_attribute());
cell->attributes[ID::abc9_box_seq] = box_count++;