aboutsummaryrefslogtreecommitdiffstats
path: root/passes/proc
diff options
context:
space:
mode:
Diffstat (limited to 'passes/proc')
-rw-r--r--passes/proc/Makefile.inc1
-rw-r--r--passes/proc/proc.cc15
-rw-r--r--passes/proc/proc_arst.cc110
-rw-r--r--passes/proc/proc_clean.cc44
-rw-r--r--passes/proc/proc_dff.cc45
-rw-r--r--passes/proc/proc_dlatch.cc9
-rw-r--r--passes/proc/proc_init.cc16
-rw-r--r--passes/proc/proc_memwr.cc121
-rw-r--r--passes/proc/proc_mux.cc2
-rw-r--r--passes/proc/proc_prune.cc65
-rw-r--r--passes/proc/proc_rmdead.cc67
11 files changed, 345 insertions, 150 deletions
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..d7aac57b6 100644
--- a/passes/proc/proc.cc
+++ b/passes/proc/proc.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -43,7 +43,9 @@ 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(" opt_expr -keepdc\n");
log("\n");
log("This replaces the processes in the design with multiplexers,\n");
log("flip-flops and latches.\n");
@@ -60,12 +62,16 @@ struct ProcPass : public Pass {
log(" This option is passed through to proc_mux. proc_rmdead is not\n");
log(" executed in -ifx mode.\n");
log("\n");
+ log(" -noopt\n");
+ log(" Will omit the opt_expr pass.\n");
+ log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
std::string global_arst;
bool ifxmode = false;
bool nomux = false;
+ bool noopt = false;
log_header(design, "Executing PROC pass (convert processes to netlists).\n");
log_push();
@@ -85,6 +91,10 @@ struct ProcPass : public Pass {
ifxmode = true;
continue;
}
+ if (args[argidx] == "-noopt") {
+ noopt = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -102,7 +112,10 @@ 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");
+ if (!noopt)
+ Pass::call(design, "opt_expr -keepdc");
log_pop();
}
diff --git a/passes/proc/proc_arst.cc b/passes/proc/proc_arst.cc
index 16db461b2..f01682957 100644
--- a/passes/proc/proc_arst.cc
+++ b/passes/proc/proc_arst.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -153,51 +153,93 @@ 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:
- if (proc->root_case.switches.size() != 1)
- return;
-
- RTLIL::SigSpec root_sig = proc->root_case.switches[0]->signal;
+ std::vector<RTLIL::SyncRule *> arst_syncs;
+ std::vector<RTLIL::SyncRule *> edge_syncs;
+ std::vector<RTLIL::SyncRule *> other_syncs;
for (auto &sync : proc->syncs) {
- if (sync->type == RTLIL::SyncType::STp || sync->type == RTLIL::SyncType::STn) {
+ if (sync->type == RTLIL::SyncType::ST0 || sync->type == RTLIL::SyncType::ST1) {
+ arst_syncs.push_back(sync);
+ } else if (sync->type == RTLIL::SyncType::STp || sync->type == RTLIL::SyncType::STn) {
+ edge_syncs.push_back(sync);
+ } else {
+ other_syncs.push_back(sync);
+ }
+ }
+
+ bool did_something = false;
+
+ while (proc->root_case.switches.size() == 1) {
+ RTLIL::SigSpec root_sig = proc->root_case.switches[0]->signal;
+
+ bool found = false;
+ for (auto it = edge_syncs.begin(); it != edge_syncs.end(); ++it) {
+ auto sync = *it;
bool polarity = sync->type == RTLIL::SyncType::STp;
if (check_signal(mod, root_sig, sync->signal, polarity)) {
- if (proc->syncs.size() == 1) {
- log("Found VHDL-style edge-trigger %s in `%s.%s'.\n", log_signal(sync->signal), mod->name.c_str(), proc->name.c_str());
- } else {
+ if (edge_syncs.size() > 1) {
log("Found async reset %s in `%s.%s'.\n", log_signal(sync->signal), mod->name.c_str(), proc->name.c_str());
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;
+ arst_syncs.push_back(sync);
+ edge_syncs.erase(it);
+ for (auto &action : sync->actions) {
+ 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));
+ }
+ 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);
}
- 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;
+ sync->mem_write_actions.clear();
+ eliminate_const(mod, &proc->root_case, root_sig, polarity);
+ } else {
+ log("Found VHDL-style edge-trigger %s in `%s.%s'.\n", log_signal(sync->signal), mod->name.c_str(), proc->name.c_str());
+ eliminate_const(mod, &proc->root_case, root_sig, !polarity);
}
- eliminate_const(mod, &proc->root_case, root_sig, polarity);
- goto restart_proc_arst;
+ did_something = true;
+ found = true;
+ break;
}
}
+ if (!found)
+ break;
+ }
+
+ if (did_something) {
+ proc->syncs.clear();
+ proc->syncs.insert(proc->syncs.end(), arst_syncs.begin(), arst_syncs.end());
+ proc->syncs.insert(proc->syncs.end(), edge_syncs.begin(), edge_syncs.end());
+ proc->syncs.insert(proc->syncs.end(), other_syncs.begin(), other_syncs.end());
}
}
diff --git a/passes/proc/proc_clean.cc b/passes/proc/proc_clean.cc
index 5e78b7316..45872907b 100644
--- a/passes/proc/proc_clean.cc
+++ b/passes/proc/proc_clean.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -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--));
}
@@ -198,7 +209,7 @@ struct ProcCleanPass : public Pass {
extra_args(args, argidx, design);
for (auto mod : design->modules()) {
- std::vector<RTLIL::IdString> delme;
+ std::vector<RTLIL::Process *> delme;
if (!design->selected(mod))
continue;
for (auto &proc_it : mod->processes) {
@@ -209,12 +220,11 @@ struct ProcCleanPass : public Pass {
proc_it.second->root_case.actions.size() == 0) {
if (!quiet)
log("Removing empty process `%s.%s'.\n", log_id(mod), proc_it.second->name.c_str());
- delme.push_back(proc_it.first);
+ delme.push_back(proc_it.second);
}
}
- for (auto &id : delme) {
- delete mod->processes[id];
- mod->processes.erase(id);
+ for (auto proc : delme) {
+ mod->remove(proc);
}
}
diff --git a/passes/proc/proc_dff.cc b/passes/proc/proc_dff.cc
index e320a72a6..234671df5 100644
--- a/passes/proc/proc_dff.cc
+++ b/passes/proc/proc_dff.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -143,48 +143,23 @@ void gen_dffsr_complex(RTLIL::Module *mod, RTLIL::SigSpec sig_d, RTLIL::SigSpec
cell->type.c_str(), cell->name.c_str(), clk_polarity ? "positive" : "negative");
}
-void gen_dffsr(RTLIL::Module *mod, RTLIL::SigSpec sig_in, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_out,
+void gen_aldff(RTLIL::Module *mod, RTLIL::SigSpec sig_in, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_out,
bool clk_polarity, bool set_polarity, RTLIL::SigSpec clk, RTLIL::SigSpec set, RTLIL::Process *proc)
{
std::stringstream sstr;
sstr << "$procdff$" << (autoidx++);
- RTLIL::SigSpec sig_set_inv = mod->addWire(NEW_ID, sig_in.size());
- RTLIL::SigSpec sig_sr_set = mod->addWire(NEW_ID, sig_in.size());
- RTLIL::SigSpec sig_sr_clr = mod->addWire(NEW_ID, sig_in.size());
-
- RTLIL::Cell *inv_set = mod->addCell(NEW_ID, ID($not));
- inv_set->parameters[ID::A_SIGNED] = RTLIL::Const(0);
- inv_set->parameters[ID::A_WIDTH] = RTLIL::Const(sig_in.size());
- inv_set->parameters[ID::Y_WIDTH] = RTLIL::Const(sig_in.size());
- inv_set->setPort(ID::A, sig_set);
- inv_set->setPort(ID::Y, sig_set_inv);
-
- RTLIL::Cell *mux_sr_set = mod->addCell(NEW_ID, ID($mux));
- mux_sr_set->parameters[ID::WIDTH] = RTLIL::Const(sig_in.size());
- mux_sr_set->setPort(set_polarity ? ID::A : ID::B, RTLIL::Const(0, sig_in.size()));
- mux_sr_set->setPort(set_polarity ? ID::B : ID::A, sig_set);
- mux_sr_set->setPort(ID::Y, sig_sr_set);
- mux_sr_set->setPort(ID::S, set);
-
- RTLIL::Cell *mux_sr_clr = mod->addCell(NEW_ID, ID($mux));
- mux_sr_clr->parameters[ID::WIDTH] = RTLIL::Const(sig_in.size());
- mux_sr_clr->setPort(set_polarity ? ID::A : ID::B, RTLIL::Const(0, sig_in.size()));
- mux_sr_clr->setPort(set_polarity ? ID::B : ID::A, sig_set_inv);
- mux_sr_clr->setPort(ID::Y, sig_sr_clr);
- mux_sr_clr->setPort(ID::S, set);
-
- RTLIL::Cell *cell = mod->addCell(sstr.str(), ID($dffsr));
+ RTLIL::Cell *cell = mod->addCell(sstr.str(), ID($aldff));
cell->attributes = proc->attributes;
+
cell->parameters[ID::WIDTH] = RTLIL::Const(sig_in.size());
+ cell->parameters[ID::ALOAD_POLARITY] = RTLIL::Const(set_polarity, 1);
cell->parameters[ID::CLK_POLARITY] = RTLIL::Const(clk_polarity, 1);
- cell->parameters[ID::SET_POLARITY] = RTLIL::Const(true, 1);
- cell->parameters[ID::CLR_POLARITY] = RTLIL::Const(true, 1);
cell->setPort(ID::D, sig_in);
cell->setPort(ID::Q, sig_out);
+ cell->setPort(ID::AD, sig_set);
cell->setPort(ID::CLK, clk);
- cell->setPort(ID::SET, sig_sr_set);
- cell->setPort(ID::CLR, sig_sr_clr);
+ cell->setPort(ID::ALOAD, set);
log(" created %s cell `%s' with %s edge clock and %s level non-const reset.\n", cell->type.c_str(), cell->name.c_str(),
clk_polarity ? "positive" : "negative", set_polarity ? "positive" : "negative");
@@ -328,6 +303,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;
}
@@ -351,7 +330,7 @@ void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
else if (!rstval.is_fully_const() && !ce.eval(rstval))
{
log_warning("Async reset value `%s' is not constant!\n", log_signal(rstval));
- gen_dffsr(mod, insig, rstval, sig_q,
+ gen_aldff(mod, insig, rstval, sig_q,
sync_edge->type == RTLIL::SyncType::STp,
sync_level && sync_level->type == RTLIL::SyncType::ST1,
sync_edge->signal, sync_level->signal, proc);
diff --git a/passes/proc/proc_dlatch.cc b/passes/proc/proc_dlatch.cc
index 7b8c05b21..8340e1431 100644
--- a/passes/proc/proc_dlatch.cc
+++ b/passes/proc/proc_dlatch.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -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..4da20c395 100644
--- a/passes/proc/proc_init.cc
+++ b/passes/proc/proc_init.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -28,12 +28,9 @@ PRIVATE_NAMESPACE_BEGIN
void proc_init(RTLIL::Module *mod, SigMap &sigmap, RTLIL::Process *proc)
{
- bool found_init = false;
-
for (auto &sync : proc->syncs)
if (sync->type == RTLIL::SyncType::STi)
{
- found_init = true;
log("Found init rule in `%s.%s'.\n", mod->name.c_str(), proc->name.c_str());
for (auto &action : sync->actions)
@@ -71,17 +68,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..cf10bd4b2
--- /dev/null
+++ b/passes/proc/proc_memwr.cc
@@ -0,0 +1,121 @@
+/*
+ * 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_port_id)
+{
+ for (auto sr : proc->syncs)
+ {
+ std::vector<int> prev_port_ids;
+ for (auto memwr : sr->mem_write_actions) {
+ int port_id = next_port_id[memwr.memid]++;
+ Const priority_mask(State::S0, port_id);
+ for (int i = 0; i < GetSize(prev_port_ids); i++)
+ if (memwr.priority_mask[i] == State::S1)
+ priority_mask[prev_port_ids[i]] = State::S1;
+ prev_port_ids.push_back(port_id);
+
+ RTLIL::Cell *cell = mod->addCell(NEW_ID, ID($memwr_v2));
+ 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::PORTID, port_id);
+ cell->setParam(ID::PRIORITY_MASK, priority_mask);
+ 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_port_id;
+ for (auto cell : module->cells()) {
+ if (cell->type.in(ID($memwr), ID($memwr_v2))) {
+ bool is_compat = cell->type == ID($memwr);
+ IdString memid = cell->parameters.at(ID::MEMID).decode_string();
+ int port_id = cell->parameters.at(is_compat ? ID::PRIORITY : ID::PORTID).as_int();
+ if (port_id >= next_port_id[memid])
+ next_port_id[memid] = port_id + 1;
+ }
+ }
+ for (auto &proc_it : module->processes)
+ if (design->selected(module, proc_it.second))
+ proc_memwr(module, proc_it.second, next_port_id);
+ }
+ }
+} ProcMemWrPass;
+
+PRIVATE_NAMESPACE_END
+
diff --git a/passes/proc/proc_mux.cc b/passes/proc/proc_mux.cc
index d20f34534..b209057fe 100644
--- a/passes/proc/proc_mux.cc
+++ b/passes/proc/proc_mux.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
diff --git a/passes/proc/proc_prune.cc b/passes/proc/proc_prune.cc
index bd122b91f..9f1080ef6 100644
--- a/passes/proc/proc_prune.cc
+++ b/passes/proc/proc_prune.cc
@@ -67,51 +67,36 @@ struct PruneWorker
}
for (auto it = cs->actions.rbegin(); it != cs->actions.rend(); ) {
RTLIL::SigSpec lhs = sigmap(it->first);
- bool redundant = true;
- for (auto &bit : lhs) {
+ RTLIL::SigSpec rhs = sigmap(it->second);
+ SigSpec new_lhs, new_rhs;
+ SigSpec conn_lhs, conn_rhs;
+ for (int i = 0; i < GetSize(lhs); i++) {
+ SigBit bit = lhs[i];
if (bit.wire && !assigned[bit]) {
- redundant = false;
- break;
- }
- }
- bool remove = false;
- if (redundant) {
- removed_count++;
- remove = true;
- } else {
- if (root) {
- bool promotable = true;
- for (auto &bit : lhs) {
- if (bit.wire && affected[bit] && !assigned[bit]) {
- promotable = false;
- break;
- }
- }
- if (promotable) {
- RTLIL::SigSpec rhs = sigmap(it->second);
- RTLIL::SigSig conn;
- for (int i = 0; i < GetSize(lhs); i++) {
- RTLIL::SigBit lhs_bit = lhs[i];
- if (lhs_bit.wire && !assigned[lhs_bit]) {
- conn.first.append(lhs_bit);
- conn.second.append(rhs.extract(i));
- }
- }
- promoted_count++;
- module->connect(conn);
- remove = true;
+ if (!affected[bit] && root) {
+ conn_lhs.append(bit);
+ conn_rhs.append(rhs[i]);
+ } else {
+ new_lhs.append(bit);
+ new_rhs.append(rhs[i]);
}
+ assigned.insert(bit);
+ affected.insert(bit);
}
- for (auto &bit : lhs)
- if (bit.wire)
- assigned.insert(bit);
- for (auto &bit : lhs)
- if (bit.wire)
- affected.insert(bit);
}
- if (remove)
+ if (GetSize(conn_lhs)) {
+ promoted_count++;
+ module->connect(conn_lhs, conn_rhs);
+ }
+ if (GetSize(new_lhs) == 0) {
+ if (GetSize(conn_lhs) == 0)
+ removed_count++;
cs->actions.erase((it++).base() - 1);
- else it++;
+ } else {
+ it->first = new_lhs;
+ it->second = new_rhs;
+ it++;
+ }
}
return assigned;
}
diff --git a/passes/proc/proc_rmdead.cc b/passes/proc/proc_rmdead.cc
index ee91637ca..2ec11415a 100644
--- a/passes/proc/proc_rmdead.cc
+++ b/passes/proc/proc_rmdead.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -28,9 +28,62 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-void proc_rmdead(RTLIL::SwitchRule *sw, int &counter, int &full_case_counter)
+static bool can_use_fully_defined_pool(RTLIL::SwitchRule *sw)
+{
+ if (!GetSize(sw->signal))
+ return false;
+
+ for (const RTLIL::SigBit &bit : sw->signal)
+ if (bit.wire == NULL)
+ return false;
+
+ for (const RTLIL::CaseRule *cas : sw->cases)
+ for (const RTLIL::SigSpec &sig : cas->compare)
+ if (!sig.is_fully_def())
+ return false;
+
+ return true;
+}
+
+// This replicates the necessary parts of BitPatternPool's interface, but rather
+// than storing remaining patterns, this explicitly stores which fully-defined
+// constants have already been matched.
+struct FullyDefinedPool
+{
+ FullyDefinedPool(const RTLIL::SigSpec &signal)
+ : max_patterns{signal.size() >= 32 ? 0ul : 1ul << signal.size()}
+ {}
+
+ bool take(RTLIL::SigSpec sig)
+ {
+ if (default_reached || patterns.count(sig))
+ return false;
+ patterns.insert(sig);
+ return true;
+ }
+
+ void take_all()
+ {
+ default_reached = true;
+ }
+
+ bool empty()
+ {
+ return default_reached ||
+ (max_patterns && max_patterns == patterns.size());
+ }
+
+ pool<RTLIL::SigSpec> patterns;
+ bool default_reached = false;
+ size_t max_patterns;
+};
+
+void proc_rmdead(RTLIL::SwitchRule *sw, int &counter, int &full_case_counter);
+
+template <class Pool>
+static void proc_rmdead_impl(RTLIL::SwitchRule *sw, int &counter, int &full_case_counter)
{
- BitPatternPool pool(sw->signal);
+ Pool pool(sw->signal);
for (size_t i = 0; i < sw->cases.size(); i++)
{
@@ -68,6 +121,14 @@ void proc_rmdead(RTLIL::SwitchRule *sw, int &counter, int &full_case_counter)
}
}
+void proc_rmdead(RTLIL::SwitchRule *sw, int &counter, int &full_case_counter)
+{
+ if (can_use_fully_defined_pool(sw))
+ proc_rmdead_impl<FullyDefinedPool>(sw, counter, full_case_counter);
+ else
+ proc_rmdead_impl<BitPatternPool>(sw, counter, full_case_counter);
+}
+
struct ProcRmdeadPass : public Pass {
ProcRmdeadPass() : Pass("proc_rmdead", "eliminate dead trees in decision trees") { }
void help() override