From 4e70c3077562e511d6f840c91dd30ade87d66517 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Wed, 6 Oct 2021 22:16:55 +0200 Subject: FfData: some refactoring. - FfData now keeps track of the module and underlying cell, if any (so calling emit on FfData created from a cell will replace the existing cell) - FfData implementation is split off to its own .cc file for faster compilation - the "flip FF data sense by inserting inverters in front and after" functionality that zinit uses is moved onto FfData class and beefed up to have dffsr support, to support more use cases --- kernel/ff.h | 472 ++++-------------------------------------------------------- 1 file changed, 24 insertions(+), 448 deletions(-) (limited to 'kernel/ff.h') diff --git a/kernel/ff.h b/kernel/ff.h index 7f01b8a36..3125f67c6 100644 --- a/kernel/ff.h +++ b/kernel/ff.h @@ -76,7 +76,10 @@ YOSYS_NAMESPACE_BEGIN // - empty set [not a cell — will be emitted as a simple direct connection] struct FfData { + Module *module; FfInitVals *initvals; + Cell *cell; + IdString name; // The FF output. SigSpec sig_q; // The sync data input, present if has_clk or has_gclk. @@ -142,7 +145,7 @@ struct FfData { int width; dict attributes; - FfData(FfInitVals *initvals = nullptr, Cell *cell = nullptr) : initvals(initvals) { + FfData(Module *module = nullptr, FfInitVals *initvals = nullptr, IdString name = IdString()) : module(module), initvals(initvals), cell(nullptr), name(name) { width = 0; has_clk = false; has_gclk = false; @@ -160,464 +163,37 @@ struct FfData { pol_srst = false; pol_clr = false; pol_set = false; - - if (!cell) - return; - - sig_q = cell->getPort(ID::Q); - width = GetSize(sig_q); - attributes = cell->attributes; - - if (initvals) - val_init = (*initvals)(sig_q); - - std::string type_str = cell->type.str(); - - if (cell->type.in(ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($dffsre), ID($adff), ID($adffe), ID($aldff), ID($aldffe), ID($sdff), ID($sdffe), ID($sdffce), ID($dlatch), ID($adlatch), ID($dlatchsr), ID($sr))) { - if (cell->type == ID($ff)) { - has_gclk = true; - sig_d = cell->getPort(ID::D); - } else if (cell->type == ID($sr)) { - // No data input at all. - } else if (cell->type.in(ID($dlatch), ID($adlatch), ID($dlatchsr))) { - has_aload = true; - sig_aload = cell->getPort(ID::EN); - pol_aload = cell->getParam(ID::EN_POLARITY).as_bool(); - sig_ad = cell->getPort(ID::D); - } else { - has_clk = true; - sig_clk = cell->getPort(ID::CLK); - pol_clk = cell->getParam(ID::CLK_POLARITY).as_bool(); - sig_d = cell->getPort(ID::D); - } - if (cell->type.in(ID($dffe), ID($dffsre), ID($adffe), ID($aldffe), ID($sdffe), ID($sdffce))) { - has_ce = true; - sig_ce = cell->getPort(ID::EN); - pol_ce = cell->getParam(ID::EN_POLARITY).as_bool(); - } - if (cell->type.in(ID($dffsr), ID($dffsre), ID($dlatchsr), ID($sr))) { - has_sr = true; - sig_clr = cell->getPort(ID::CLR); - sig_set = cell->getPort(ID::SET); - pol_clr = cell->getParam(ID::CLR_POLARITY).as_bool(); - pol_set = cell->getParam(ID::SET_POLARITY).as_bool(); - } - if (cell->type.in(ID($aldff), ID($aldffe))) { - has_aload = true; - sig_aload = cell->getPort(ID::ALOAD); - pol_aload = cell->getParam(ID::ALOAD_POLARITY).as_bool(); - sig_ad = cell->getPort(ID::AD); - } - if (cell->type.in(ID($adff), ID($adffe), ID($adlatch))) { - has_arst = true; - sig_arst = cell->getPort(ID::ARST); - pol_arst = cell->getParam(ID::ARST_POLARITY).as_bool(); - val_arst = cell->getParam(ID::ARST_VALUE); - } - if (cell->type.in(ID($sdff), ID($sdffe), ID($sdffce))) { - has_srst = true; - sig_srst = cell->getPort(ID::SRST); - pol_srst = cell->getParam(ID::SRST_POLARITY).as_bool(); - val_srst = cell->getParam(ID::SRST_VALUE); - ce_over_srst = cell->type == ID($sdffce); - } - } else if (cell->type == ID($_FF_)) { - is_fine = true; - has_gclk = true; - sig_d = cell->getPort(ID::D); - } else if (type_str.substr(0, 5) == "$_SR_") { - is_fine = true; - has_sr = true; - pol_set = type_str[5] == 'P'; - pol_clr = type_str[6] == 'P'; - sig_set = cell->getPort(ID::S); - sig_clr = cell->getPort(ID::R); - } else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 8) { - is_fine = true; - sig_d = cell->getPort(ID::D); - has_clk = true; - pol_clk = type_str[6] == 'P'; - sig_clk = cell->getPort(ID::C); - } else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 10) { - is_fine = true; - sig_d = cell->getPort(ID::D); - has_clk = true; - pol_clk = type_str[7] == 'P'; - sig_clk = cell->getPort(ID::C); - has_ce = true; - pol_ce = type_str[8] == 'P'; - sig_ce = cell->getPort(ID::E); - } else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 10) { - is_fine = true; - sig_d = cell->getPort(ID::D); - has_clk = true; - pol_clk = type_str[6] == 'P'; - sig_clk = cell->getPort(ID::C); - has_arst = true; - pol_arst = type_str[7] == 'P'; - sig_arst = cell->getPort(ID::R); - val_arst = type_str[8] == '1' ? State::S1 : State::S0; - } else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 12) { - is_fine = true; - sig_d = cell->getPort(ID::D); - has_clk = true; - pol_clk = type_str[7] == 'P'; - sig_clk = cell->getPort(ID::C); - has_arst = true; - pol_arst = type_str[8] == 'P'; - sig_arst = cell->getPort(ID::R); - val_arst = type_str[9] == '1' ? State::S1 : State::S0; - has_ce = true; - pol_ce = type_str[10] == 'P'; - sig_ce = cell->getPort(ID::E); - } else if (type_str.substr(0, 8) == "$_ALDFF_" && type_str.size() == 11) { - is_fine = true; - sig_d = cell->getPort(ID::D); - has_clk = true; - pol_clk = type_str[8] == 'P'; - sig_clk = cell->getPort(ID::C); - has_aload = true; - pol_aload = type_str[9] == 'P'; - sig_aload = cell->getPort(ID::L); - sig_ad = cell->getPort(ID::AD); - } else if (type_str.substr(0, 9) == "$_ALDFFE_" && type_str.size() == 13) { - is_fine = true; - sig_d = cell->getPort(ID::D); - has_clk = true; - pol_clk = type_str[9] == 'P'; - sig_clk = cell->getPort(ID::C); - has_aload = true; - pol_aload = type_str[10] == 'P'; - sig_aload = cell->getPort(ID::L); - sig_ad = cell->getPort(ID::AD); - has_ce = true; - pol_ce = type_str[11] == 'P'; - sig_ce = cell->getPort(ID::E); - } else if (type_str.substr(0, 8) == "$_DFFSR_" && type_str.size() == 12) { - is_fine = true; - sig_d = cell->getPort(ID::D); - has_clk = true; - pol_clk = type_str[8] == 'P'; - sig_clk = cell->getPort(ID::C); - has_sr = true; - pol_set = type_str[9] == 'P'; - pol_clr = type_str[10] == 'P'; - sig_set = cell->getPort(ID::S); - sig_clr = cell->getPort(ID::R); - } else if (type_str.substr(0, 9) == "$_DFFSRE_" && type_str.size() == 14) { - is_fine = true; - sig_d = cell->getPort(ID::D); - has_clk = true; - pol_clk = type_str[9] == 'P'; - sig_clk = cell->getPort(ID::C); - has_sr = true; - pol_set = type_str[10] == 'P'; - pol_clr = type_str[11] == 'P'; - sig_set = cell->getPort(ID::S); - sig_clr = cell->getPort(ID::R); - has_ce = true; - pol_ce = type_str[12] == 'P'; - sig_ce = cell->getPort(ID::E); - } else if (type_str.substr(0, 7) == "$_SDFF_" && type_str.size() == 11) { - is_fine = true; - sig_d = cell->getPort(ID::D); - has_clk = true; - pol_clk = type_str[7] == 'P'; - sig_clk = cell->getPort(ID::C); - has_srst = true; - pol_srst = type_str[8] == 'P'; - sig_srst = cell->getPort(ID::R); - val_srst = type_str[9] == '1' ? State::S1 : State::S0; - } else if (type_str.substr(0, 8) == "$_SDFFE_" && type_str.size() == 13) { - is_fine = true; - sig_d = cell->getPort(ID::D); - has_clk = true; - pol_clk = type_str[8] == 'P'; - sig_clk = cell->getPort(ID::C); - has_srst = true; - pol_srst = type_str[9] == 'P'; - sig_srst = cell->getPort(ID::R); - val_srst = type_str[10] == '1' ? State::S1 : State::S0; - has_ce = true; - pol_ce = type_str[11] == 'P'; - sig_ce = cell->getPort(ID::E); - } else if (type_str.substr(0, 9) == "$_SDFFCE_" && type_str.size() == 14) { - is_fine = true; - sig_d = cell->getPort(ID::D); - has_clk = true; - pol_clk = type_str[9] == 'P'; - sig_clk = cell->getPort(ID::C); - has_srst = true; - pol_srst = type_str[10] == 'P'; - sig_srst = cell->getPort(ID::R); - val_srst = type_str[11] == '1' ? State::S1 : State::S0; - has_ce = true; - pol_ce = type_str[12] == 'P'; - sig_ce = cell->getPort(ID::E); - ce_over_srst = true; - } else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 11) { - is_fine = true; - has_aload = true; - sig_ad = cell->getPort(ID::D); - has_aload = true; - pol_aload = type_str[9] == 'P'; - sig_aload = cell->getPort(ID::E); - } else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 13) { - is_fine = true; - has_aload = true; - sig_ad = cell->getPort(ID::D); - has_aload = true; - pol_aload = type_str[9] == 'P'; - sig_aload = cell->getPort(ID::E); - has_arst = true; - pol_arst = type_str[10] == 'P'; - sig_arst = cell->getPort(ID::R); - val_arst = type_str[11] == '1' ? State::S1 : State::S0; - } else if (type_str.substr(0, 11) == "$_DLATCHSR_" && type_str.size() == 15) { - is_fine = true; - has_aload = true; - sig_ad = cell->getPort(ID::D); - has_aload = true; - pol_aload = type_str[11] == 'P'; - sig_aload = cell->getPort(ID::E); - has_sr = true; - pol_set = type_str[12] == 'P'; - pol_clr = type_str[13] == 'P'; - sig_set = cell->getPort(ID::S); - sig_clr = cell->getPort(ID::R); - } else { - log_assert(0); - } - if (has_aload && !has_clk && !has_sr && !has_arst && sig_ad.is_fully_const()) { - // Plain D latches with const D treated specially. - has_aload = false; - has_arst = true; - sig_arst = sig_aload; - pol_arst = pol_aload; - val_arst = sig_ad.as_const(); - } } - // Returns a FF identical to this one, but only keeping bit indices from the argument. - FfData slice(const std::vector &bits) { - FfData res(initvals); - res.sig_clk = sig_clk; - res.sig_ce = sig_ce; - res.sig_aload = sig_aload; - res.sig_arst = sig_arst; - res.sig_srst = sig_srst; - res.has_clk = has_clk; - res.has_gclk = has_gclk; - res.has_ce = has_ce; - res.has_aload = has_aload; - res.has_arst = has_arst; - res.has_srst = has_srst; - res.has_sr = has_sr; - res.ce_over_srst = ce_over_srst; - res.is_fine = is_fine; - res.pol_clk = pol_clk; - res.pol_ce = pol_ce; - res.pol_aload = pol_aload; - res.pol_arst = pol_arst; - res.pol_srst = pol_srst; - res.pol_clr = pol_clr; - res.pol_set = pol_set; - res.attributes = attributes; - for (int i : bits) { - res.sig_q.append(sig_q[i]); - if (has_clk || has_gclk) - res.sig_d.append(sig_d[i]); - if (has_aload) - res.sig_ad.append(sig_ad[i]); - if (has_sr) { - res.sig_clr.append(sig_clr[i]); - res.sig_set.append(sig_set[i]); - } - if (has_arst) - res.val_arst.bits.push_back(val_arst[i]); - if (has_srst) - res.val_srst.bits.push_back(val_srst[i]); - if (initvals) - res.val_init.bits.push_back(val_init[i]); - } - res.width = GetSize(res.sig_q); - return res; - } + FfData(FfInitVals *initvals, Cell *cell_); - void unmap_ce(Module *module) { - if (!has_ce) - return; - log_assert(has_clk); - if (has_srst && ce_over_srst) - unmap_srst(module); + // Returns a FF identical to this one, but only keeping bit indices from the argument. + FfData slice(const std::vector &bits); - if (!is_fine) { - if (pol_ce) - sig_d = module->Mux(NEW_ID, sig_q, sig_d, sig_ce); - else - sig_d = module->Mux(NEW_ID, sig_d, sig_q, sig_ce); - } else { - if (pol_ce) - sig_d = module->MuxGate(NEW_ID, sig_q, sig_d, sig_ce); - else - sig_d = module->MuxGate(NEW_ID, sig_d, sig_q, sig_ce); - } - has_ce = false; - } + void unmap_ce(); - void unmap_srst(Module *module) { - if (!has_srst) - return; - if (has_ce && !ce_over_srst) - unmap_ce(module); + void unmap_srst(); - if (!is_fine) { - if (pol_srst) - sig_d = module->Mux(NEW_ID, sig_d, val_srst, sig_srst); - else - sig_d = module->Mux(NEW_ID, val_srst, sig_d, sig_srst); - } else { - if (pol_srst) - sig_d = module->MuxGate(NEW_ID, sig_d, val_srst[0], sig_srst); - else - sig_d = module->MuxGate(NEW_ID, val_srst[0], sig_d, sig_srst); - } - has_srst = false; + void unmap_ce_srst() { + unmap_ce(); + unmap_srst(); } - void unmap_ce_srst(Module *module) { - unmap_ce(module); - unmap_srst(module); - } + Cell *emit(); - Cell *emit(Module *module, IdString name) { - if (!width) - return nullptr; - if (!has_aload && !has_clk && !has_gclk && !has_sr) { - if (has_arst) { - // Convert this case to a D latch. - has_aload = true; - has_arst = false; - sig_ad = val_arst; - sig_aload = sig_arst; - pol_aload = pol_arst; - } else { - // No control inputs left. Turn into a const driver. - if (initvals) - initvals->remove_init(sig_q); - module->connect(sig_q, val_init); - return nullptr; - } - } + // Removes init attribute from the Q output, but keeps val_init unchanged. + // It will be automatically reattached on emit. Use this before changing sig_q. + void remove_init() { if (initvals) - initvals->set_init(sig_q, val_init); - Cell *cell; - if (!is_fine) { - if (has_gclk) { - log_assert(!has_clk); - log_assert(!has_ce); - log_assert(!has_aload); - log_assert(!has_arst); - log_assert(!has_srst); - log_assert(!has_sr); - cell = module->addFf(name, sig_d, sig_q); - } else if (!has_aload && !has_clk) { - log_assert(has_sr); - cell = module->addSr(name, sig_set, sig_clr, sig_q, pol_set, pol_clr); - } else if (!has_clk) { - log_assert(!has_srst); - if (has_sr) - cell = module->addDlatchsr(name, sig_aload, sig_set, sig_clr, sig_ad, sig_q, pol_aload, pol_set, pol_clr); - else if (has_arst) - cell = module->addAdlatch(name, sig_aload, sig_arst, sig_ad, sig_q, val_arst, pol_aload, pol_arst); - else - cell = module->addDlatch(name, sig_aload, sig_ad, sig_q, pol_aload); - } else { - if (has_sr) { - if (has_ce) - cell = module->addDffsre(name, sig_clk, sig_ce, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_ce, pol_set, pol_clr); - else - cell = module->addDffsr(name, sig_clk, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_set, pol_clr); - } else if (has_arst) { - if (has_ce) - cell = module->addAdffe(name, sig_clk, sig_ce, sig_arst, sig_d, sig_q, val_arst, pol_clk, pol_ce, pol_arst); - else - cell = module->addAdff(name, sig_clk, sig_arst, sig_d, sig_q, val_arst, pol_clk, pol_arst); - } else if (has_aload) { - if (has_ce) - cell = module->addAldffe(name, sig_clk, sig_ce, sig_aload, sig_d, sig_q, sig_ad, pol_clk, pol_ce, pol_aload); - else - cell = module->addAldff(name, sig_clk, sig_aload, sig_d, sig_q, sig_ad, pol_clk, pol_aload); - } else if (has_srst) { - if (has_ce) - if (ce_over_srst) - cell = module->addSdffce(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_ce, pol_srst); - else - cell = module->addSdffe(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_ce, pol_srst); - else - cell = module->addSdff(name, sig_clk, sig_srst, sig_d, sig_q, val_srst, pol_clk, pol_srst); - } else { - if (has_ce) - cell = module->addDffe(name, sig_clk, sig_ce, sig_d, sig_q, pol_clk, pol_ce); - else - cell = module->addDff(name, sig_clk, sig_d, sig_q, pol_clk); - } - } - } else { - if (has_gclk) { - log_assert(!has_clk); - log_assert(!has_ce); - log_assert(!has_aload); - log_assert(!has_arst); - log_assert(!has_srst); - log_assert(!has_sr); - cell = module->addFfGate(name, sig_d, sig_q); - } else if (!has_aload && !has_clk) { - log_assert(has_sr); - cell = module->addSrGate(name, sig_set, sig_clr, sig_q, pol_set, pol_clr); - } else if (!has_clk) { - log_assert(!has_srst); - if (has_sr) - cell = module->addDlatchsrGate(name, sig_aload, sig_set, sig_clr, sig_ad, sig_q, pol_aload, pol_set, pol_clr); - else if (has_arst) - cell = module->addAdlatchGate(name, sig_aload, sig_arst, sig_ad, sig_q, val_arst.as_bool(), pol_aload, pol_arst); - else - cell = module->addDlatchGate(name, sig_aload, sig_ad, sig_q, pol_aload); - } else { - if (has_sr) { - if (has_ce) - cell = module->addDffsreGate(name, sig_clk, sig_ce, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_ce, pol_set, pol_clr); - else - cell = module->addDffsrGate(name, sig_clk, sig_set, sig_clr, sig_d, sig_q, pol_clk, pol_set, pol_clr); - } else if (has_arst) { - if (has_ce) - cell = module->addAdffeGate(name, sig_clk, sig_ce, sig_arst, sig_d, sig_q, val_arst.as_bool(), pol_clk, pol_ce, pol_arst); - else - cell = module->addAdffGate(name, sig_clk, sig_arst, sig_d, sig_q, val_arst.as_bool(), pol_clk, pol_arst); - } else if (has_aload) { - if (has_ce) - cell = module->addAldffeGate(name, sig_clk, sig_ce, sig_aload, sig_d, sig_q, sig_ad, pol_clk, pol_ce, pol_aload); - else - cell = module->addAldffGate(name, sig_clk, sig_aload, sig_d, sig_q, sig_ad, pol_clk, pol_aload); - } else if (has_srst) { - if (has_ce) - if (ce_over_srst) - cell = module->addSdffceGate(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_ce, pol_srst); - else - cell = module->addSdffeGate(name, sig_clk, sig_ce, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_ce, pol_srst); - else - cell = module->addSdffGate(name, sig_clk, sig_srst, sig_d, sig_q, val_srst.as_bool(), pol_clk, pol_srst); - } else { - if (has_ce) - cell = module->addDffeGate(name, sig_clk, sig_ce, sig_d, sig_q, pol_clk, pol_ce); - else - cell = module->addDffGate(name, sig_clk, sig_d, sig_q, pol_clk); - } - } - } - cell->attributes = attributes; - return cell; + initvals->remove_init(sig_q); } + + void remove(); + + // Flip the sense of the given bit slices of the FF: insert inverters on data + // inputs and output, flip the corresponding init/reset bits, swap clr/set + // inputs with proper priority fix. + void flip_bits(const pool &bits); }; YOSYS_NAMESPACE_END -- cgit v1.2.3