zinit: Refactor to use FfData.

This commit is contained in:
Marcelina Kościelnicka 2021-10-02 00:05:22 +02:00
parent 63b9df8693
commit ba0723cad7
1 changed files with 39 additions and 102 deletions

View File

@ -20,10 +20,19 @@
#include "kernel/yosys.h" #include "kernel/yosys.h"
#include "kernel/sigtools.h" #include "kernel/sigtools.h"
#include "kernel/ffinit.h" #include "kernel/ffinit.h"
#include "kernel/ff.h"
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN PRIVATE_NAMESPACE_BEGIN
State invert(State s) {
switch (s) {
case State::S0: return State::S1;
case State::S1: return State::S0;
default: return s;
}
}
struct ZinitPass : public Pass { struct ZinitPass : public Pass {
ZinitPass() : Pass("zinit", "add inverters so all FF are zero-initialized") { } ZinitPass() : Pass("zinit", "add inverters so all FF are zero-initialized") { }
void help() override void help() override
@ -60,123 +69,51 @@ struct ZinitPass : public Pass {
SigMap sigmap(module); SigMap sigmap(module);
FfInitVals initvals(&sigmap, module); FfInitVals initvals(&sigmap, module);
pool<IdString> dff_types = {
// FIXME: It would appear that supporting
// $dffsr/$_DFFSR_* would require a new
// cell type where S has priority over R
ID($ff), ID($dff), ID($dffe), /*ID($dffsr),*/ ID($adff), ID($adffe),
ID($sdff), ID($sdffe), ID($sdffce),
ID($_FF_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_),
/*ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_),
ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_),*/
ID($_DFF_N_), ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
ID($_DFF_P_), ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_),
// Async set/reset
ID($_DFFE_NN0P_), ID($_DFFE_NN1P_), ID($_DFFE_NP0P_), ID($_DFFE_NP1P_),
ID($_DFFE_PN0P_), ID($_DFFE_PN1P_), ID($_DFFE_PP0P_), ID($_DFFE_PP1P_),
ID($_DFFE_NN0N_), ID($_DFFE_NN1N_), ID($_DFFE_NP0N_), ID($_DFFE_NP1N_),
ID($_DFFE_PN0N_), ID($_DFFE_PN1N_), ID($_DFFE_PP0N_), ID($_DFFE_PP1N_),
// Sync set/reset
ID($_SDFF_NN0_), ID($_SDFF_NN1_), ID($_SDFF_NP0_), ID($_SDFF_NP1_),
ID($_SDFF_PN0_), ID($_SDFF_PN1_), ID($_SDFF_PP0_), ID($_SDFF_PP1_),
ID($_SDFFE_NN0P_), ID($_SDFFE_NN1P_), ID($_SDFFE_NP0P_), ID($_SDFFE_NP1P_),
ID($_SDFFE_PN0P_), ID($_SDFFE_PN1P_), ID($_SDFFE_PP0P_), ID($_SDFFE_PP1P_),
ID($_SDFFE_NN0N_), ID($_SDFFE_NN1N_), ID($_SDFFE_NP0N_), ID($_SDFFE_NP1N_),
ID($_SDFFE_PN0N_), ID($_SDFFE_PN1N_), ID($_SDFFE_PP0N_), ID($_SDFFE_PP1N_),
ID($_SDFFCE_NN0P_), ID($_SDFFCE_NN1P_), ID($_SDFFCE_NP0P_), ID($_SDFFCE_NP1P_),
ID($_SDFFCE_PN0P_), ID($_SDFFCE_PN1P_), ID($_SDFFCE_PP0P_), ID($_SDFFCE_PP1P_),
ID($_SDFFCE_NN0N_), ID($_SDFFCE_NN1N_), ID($_SDFFCE_NP0N_), ID($_SDFFCE_NP1N_),
ID($_SDFFCE_PN0N_), ID($_SDFFCE_PN1N_), ID($_SDFFCE_PP0N_), ID($_SDFFCE_PP1N_)
};
for (auto cell : module->selected_cells()) for (auto cell : module->selected_cells())
{ {
if (!dff_types.count(cell->type)) if (!RTLIL::builtin_ff_cell_types().count(cell->type))
continue; continue;
SigSpec sig_d = sigmap(cell->getPort(ID::D)); FfData ff(&initvals, cell);
SigSpec sig_q = sigmap(cell->getPort(ID::Q)); if (!ff.width)
if (GetSize(sig_d) < 1 || GetSize(sig_q) < 1)
continue; continue;
Const initval = initvals(sig_q); // Supporting those would require a new cell type where S has priority over R.
Const newval = initval; if (ff.has_sr)
initvals.remove_init(sig_q); continue;
Wire *initwire = module->addWire(NEW_ID, GetSize(sig_q)); Wire *new_q = module->addWire(NEW_ID, ff.width);
for (int i = 0; i < GetSize(initwire); i++) log("FF init value for cell %s (%s): %s = %s\n", log_id(cell), log_id(cell->type),
if (initval[i] == State::S1) log_signal(ff.sig_q), log_signal(ff.val_init));
IdString name = cell->name;
module->remove(cell);
initvals.remove_init(ff.sig_q);
for (int i = 0; i < ff.width; i++)
if (ff.val_init[i] == State::S1)
{ {
sig_d[i] = module->NotGate(NEW_ID, sig_d[i]); if (ff.has_clk || ff.has_gclk)
module->addNotGate(NEW_ID, SigSpec(initwire, i), sig_q[i]); ff.sig_d[i] = module->NotGate(NEW_ID, ff.sig_d[i]);
newval[i] = State::S0; if (ff.has_aload)
ff.sig_ad[i] = module->NotGate(NEW_ID, ff.sig_ad[i]);
if (ff.has_arst)
ff.val_arst[i] = invert(ff.val_arst[i]);
if (ff.has_srst)
ff.val_srst[i] = invert(ff.val_srst[i]);
module->addNotGate(NEW_ID, SigSpec(new_q, i), ff.sig_q[i]);
ff.val_init[i] = State::S0;
} }
else else
{ {
module->connect(sig_q[i], SigSpec(initwire, i)); module->connect(ff.sig_q[i], SigSpec(new_q, i));
if (all_mode) if (all_mode)
newval[i] = State::S0; ff.val_init[i] = State::S0;
} }
initvals.set_init(initwire, newval); ff.sig_q = new_q;
ff.emit(module, name);
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(ID::D, sig_d);
cell->setPort(ID::Q, initwire);
if (cell->type.in(ID($adff), ID($adffe))) {
auto val = cell->getParam(ID::ARST_VALUE);
for (int i = 0; i < GetSize(initwire); i++)
if (initval[i] == State::S1)
val[i] = (val[i] == State::S1 ? State::S0 : State::S1);
cell->setParam(ID::ARST_VALUE, std::move(val));
}
else if (cell->type.in(ID($sdff), ID($sdffe), ID($sdffce))) {
auto val = cell->getParam(ID::SRST_VALUE);
for (int i = 0; i < GetSize(initwire); i++)
if (initval[i] == State::S1)
val[i] = (val[i] == State::S1 ? State::S0 : State::S1);
cell->setParam(ID::SRST_VALUE, std::move(val));
}
else if (initval == State::S1) {
std::string t = cell->type.str();
if (cell->type.in(ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_)))
{
t[8] = (t[8] == '0' ? '1' : '0');
}
else if (cell->type.in(ID($_SDFF_NN0_), ID($_SDFF_NN1_), ID($_SDFF_NP0_), ID($_SDFF_NP1_),
ID($_SDFF_PN0_), ID($_SDFF_PN1_), ID($_SDFF_PP0_), ID($_SDFF_PP1_)))
{
t[9] = (t[9] == '0' ? '1' : '0');
}
else if (cell->type.in(ID($_DFFE_NN0P_), ID($_DFFE_NN1P_), ID($_DFFE_NP0P_), ID($_DFFE_NP1P_),
ID($_DFFE_PN0P_), ID($_DFFE_PN1P_), ID($_DFFE_PP0P_), ID($_DFFE_PP1P_),
ID($_DFFE_NN0N_), ID($_DFFE_NN1N_), ID($_DFFE_NP0N_), ID($_DFFE_NP1N_),
ID($_DFFE_PN0N_), ID($_DFFE_PN1N_), ID($_DFFE_PP0N_), ID($_DFFE_PP1N_)))
{
t[9] = (t[9] == '0' ? '1' : '0');
}
else if (cell->type.in(ID($_SDFFE_NN0P_), ID($_SDFFE_NN1P_), ID($_SDFFE_NP0P_), ID($_SDFFE_NP1P_),
ID($_SDFFE_PN0P_), ID($_SDFFE_PN1P_), ID($_SDFFE_PP0P_), ID($_SDFFE_PP1P_),
ID($_SDFFE_NN0N_), ID($_SDFFE_NN1N_), ID($_SDFFE_NP0N_), ID($_SDFFE_NP1N_),
ID($_SDFFE_PN0N_), ID($_SDFFE_PN1N_), ID($_SDFFE_PP0N_), ID($_SDFFE_PP1N_)))
{
t[10] = (t[10] == '0' ? '1' : '0');
}
else if (cell->type.in(ID($_SDFFCE_NN0P_), ID($_SDFFCE_NN1P_), ID($_SDFFCE_NP0P_), ID($_SDFFCE_NP1P_),
ID($_SDFFCE_PN0P_), ID($_SDFFCE_PN1P_), ID($_SDFFCE_PP0P_), ID($_SDFFCE_PP1P_),
ID($_SDFFCE_NN0N_), ID($_SDFFCE_NN1N_), ID($_SDFFCE_NP0N_), ID($_SDFFCE_NP1N_),
ID($_SDFFCE_PN0N_), ID($_SDFFCE_PN1N_), ID($_SDFFCE_PP0N_), ID($_SDFFCE_PP1N_)))
{
t[11] = (t[11] == '0' ? '1' : '0');
}
cell->type = t;
}
} }
} }
} }