diff --git a/Makefile b/Makefile index eec70dfaa..a2cad5dce 100644 --- a/Makefile +++ b/Makefile @@ -608,7 +608,7 @@ ifneq ($(ABCEXTERNAL),) kernel/yosys.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"' endif endif -OBJS += kernel/cellaigs.o kernel/celledges.o kernel/satgen.o kernel/qcsat.o kernel/mem.o kernel/ffmerge.o +OBJS += kernel/cellaigs.o kernel/celledges.o kernel/satgen.o kernel/qcsat.o kernel/mem.o kernel/ffmerge.o kernel/ff.o kernel/log.o: CXXFLAGS += -DYOSYS_SRC='"$(YOSYS_SRC)"' kernel/yosys.o: CXXFLAGS += -DYOSYS_DATDIR='"$(DATDIR)"' -DYOSYS_PROGRAM_PREFIX='"$(PROGRAM_PREFIX)"' diff --git a/kernel/ff.cc b/kernel/ff.cc new file mode 100644 index 000000000..c2f1a75a0 --- /dev/null +++ b/kernel/ff.cc @@ -0,0 +1,575 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2020 Marcelina Kościelnicka + * + * 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/ff.h" + +USING_YOSYS_NAMESPACE + +FfData::FfData(FfInitVals *initvals, Cell *cell_) : FfData(cell_->module, initvals, cell_->name) +{ + cell = cell_; + 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(); + } +} + +FfData FfData::slice(const std::vector &bits) { + FfData res(module, initvals, NEW_ID); + 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; +} + +void FfData::unmap_ce() { + if (!has_ce) + return; + log_assert(has_clk); + if (has_srst && ce_over_srst) + unmap_srst(); + + 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 FfData::unmap_srst() { + if (!has_srst) + return; + if (has_ce && !ce_over_srst) + unmap_ce(); + + 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; +} + +Cell *FfData::emit() { + remove(); + 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. + module->connect(sig_q, val_init); + return nullptr; + } + } + if (initvals) + initvals->set_init(sig_q, val_init); + 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; +} + +void FfData::remove() { + if (cell) { + remove_init(); + module->remove(cell); + cell = nullptr; + } +} + +namespace { + State invert(State s) { + switch (s) { + case State::S0: return State::S1; + case State::S1: return State::S0; + default: return s; + } + } +} + +void FfData::flip_bits(const pool &bits) { + if (!bits.size()) + return; + + remove_init(); + + Wire *new_q = module->addWire(NEW_ID, width); + + for (auto bit: bits) { + if (has_arst) + val_arst[bit] = invert(val_arst[bit]); + if (has_srst) + val_srst[bit] = invert(val_srst[bit]); + val_init[bit] = invert(val_init[bit]); + } + + if (has_sr && cell) { + log_warning("Flipping D/Q/init and inserting priority fixup to legalize %s.%s [%s].", log_id(module->name), log_id(cell->name), log_id(cell->type)); + } + + if (is_fine) { + if (has_sr) { + bool new_pol_clr = pol_set; + SigSpec new_sig_clr; + if (pol_set) { + if (pol_clr) { + new_sig_clr = module->AndnotGate(NEW_ID, sig_set, sig_clr); + } else { + new_sig_clr = module->AndGate(NEW_ID, sig_set, sig_clr); + } + } else { + if (pol_clr) { + new_sig_clr = module->OrGate(NEW_ID, sig_set, sig_clr); + } else { + new_sig_clr = module->OrnotGate(NEW_ID, sig_set, sig_clr); + } + } + pol_set = pol_clr; + sig_set = sig_clr; + pol_clr = new_pol_clr; + sig_clr = new_sig_clr; + } + if (has_clk || has_gclk) + sig_d = module->NotGate(NEW_ID, sig_d); + if (has_aload) + sig_ad = module->NotGate(NEW_ID, sig_ad); + module->addNotGate(NEW_ID, new_q, sig_q); + } + else + { + if (has_sr) { + SigSpec not_clr; + if (!pol_clr) { + not_clr = sig_clr; + sig_clr = module->Not(NEW_ID, sig_clr); + pol_clr = true; + } else { + not_clr = module->Not(NEW_ID, sig_clr); + } + if (!pol_set) { + sig_set = module->Not(NEW_ID, sig_set); + pol_set = true; + } + + SigSpec masked_set = module->And(NEW_ID, sig_set, not_clr); + for (auto bit: bits) { + sig_set[bit] = sig_clr[bit]; + sig_clr[bit] = masked_set[bit]; + } + } + + Const mask = Const(State::S0, width); + for (auto bit: bits) + mask.bits[bit] = State::S1; + + if (has_clk || has_gclk) + sig_d = module->Xor(NEW_ID, sig_d, mask); + if (has_aload) + sig_ad = module->Xor(NEW_ID, sig_ad, mask); + module->addXor(NEW_ID, new_q, mask, sig_q); + } + + sig_q = new_q; +} 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(); - } } + FfData(FfInitVals *initvals, Cell *cell_); + // 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 slice(const std::vector &bits); + + void unmap_ce(); + + void unmap_srst(); + + void unmap_ce_srst() { + unmap_ce(); + unmap_srst(); } - void unmap_ce(Module *module) { - if (!has_ce) - return; - log_assert(has_clk); - if (has_srst && ce_over_srst) - unmap_srst(module); + Cell *emit(); - 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_srst(Module *module) { - if (!has_srst) - return; - if (has_ce && !ce_over_srst) - unmap_ce(module); - - 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(Module *module) { - unmap_ce(module); - unmap_srst(module); - } - - 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 diff --git a/kernel/ffmerge.cc b/kernel/ffmerge.cc index 7d62a88cf..4ca5bcbb4 100644 --- a/kernel/ffmerge.cc +++ b/kernel/ffmerge.cc @@ -29,7 +29,7 @@ bool FfMergeHelper::is_output_unused(RTLIL::SigSpec sig) { } bool FfMergeHelper::find_output_ff(RTLIL::SigSpec sig, FfData &ff, pool> &bits) { - ff = FfData(); + ff = FfData(module, initvals, NEW_ID); sigmap->apply(sig); bool found = false; diff --git a/kernel/mem.cc b/kernel/mem.cc index 40659b15b..746f667ea 100644 --- a/kernel/mem.cc +++ b/kernel/mem.cc @@ -955,7 +955,7 @@ Cell *Mem::extract_rdff(int idx, FfInitVals *initvals) { } IdString name = stringf("$%s$rdreg[%d]", memid.c_str(), idx); - FfData ff(initvals); + FfData ff(module, initvals, name); ff.width = GetSize(port.data); ff.has_clk = true; ff.sig_clk = port.clk; @@ -982,7 +982,7 @@ Cell *Mem::extract_rdff(int idx, FfInitVals *initvals) { ff.sig_q = port.data; ff.val_init = port.init_value; port.data = async_d; - c = ff.emit(module, name); + c = ff.emit(); } log("Extracted %s FF from read port %d of %s.%s: %s\n", trans_use_addr ? "addr" : "data", @@ -1160,7 +1160,7 @@ void Mem::emulate_transparency(int widx, int ridx, FfInitVals *initvals) { // The FF for storing the bypass enable signal must be carefully // constructed to preserve the overall init/reset/enable behavior // of the whole port. - FfData ff(initvals); + FfData ff(module, initvals, NEW_ID); ff.width = 1; ff.sig_q = cond_q; ff.sig_d = cond; @@ -1189,7 +1189,7 @@ void Mem::emulate_transparency(int widx, int ridx, FfInitVals *initvals) { ff.val_init = State::S0; else ff.val_init = State::Sx; - ff.emit(module, NEW_ID); + ff.emit(); // And the final bypass mux. SigSpec cur = rdata_a.extract(pos, epos-pos); SigSpec other = wdata_q.extract(pos + wsub * width, epos-pos); diff --git a/passes/memory/memory_dff.cc b/passes/memory/memory_dff.cc index b87ecdd99..91209d428 100644 --- a/passes/memory/memory_dff.cc +++ b/passes/memory/memory_dff.cc @@ -581,7 +581,7 @@ struct MemoryDffWorker // Now we're commited to merge it. merger.mark_input_ff(bits); // If the address FF has enable and/or sync reset, unmap it. - ff.unmap_ce_srst(module); + ff.unmap_ce_srst(); port.clk = ff.sig_clk; port.en = State::S1; port.addr = ff.sig_d; diff --git a/passes/opt/opt_dff.cc b/passes/opt/opt_dff.cc index 0e25484b8..38faba15a 100644 --- a/passes/opt/opt_dff.cc +++ b/passes/opt/opt_dff.cc @@ -275,7 +275,7 @@ struct OptDffWorker bool changed = false; if (!ff.width) { - module->remove(cell); + ff.remove(); did_something = true; continue; } @@ -316,6 +316,7 @@ struct OptDffWorker continue; } ff = ff.slice(keep_bits); + ff.cell = cell; changed = true; } @@ -393,8 +394,7 @@ struct OptDffWorker // Always-active enable. Make a comb circuit, nuke the FF/latch. log("Handling always-active async load on %s (%s) from module %s (changing to combinatorial circuit).\n", log_id(cell), log_id(cell->type), log_id(module)); - initvals.remove_init(ff.sig_q); - module->remove(cell); + ff.remove(); if (ff.has_sr) { SigSpec tmp; if (ff.is_fine) { @@ -456,8 +456,7 @@ struct OptDffWorker // Always-active async reset — change to const driver. log("Handling always-active ARST on %s (%s) from module %s (changing to const driver).\n", log_id(cell), log_id(cell->type), log_id(module)); - initvals.remove_init(ff.sig_q); - module->remove(cell); + ff.remove(); module->connect(ff.sig_q, ff.val_arst); did_something = true; continue; @@ -660,6 +659,7 @@ struct OptDffWorker continue; } ff = ff.slice(keep_bits); + ff.cell = cell; changed = true; } @@ -728,7 +728,7 @@ struct OptDffWorker new_ff.pol_srst = srst.second; if (new_ff.has_ce) new_ff.ce_over_srst = true; - Cell *new_cell = new_ff.emit(module, NEW_ID); + Cell *new_cell = new_ff.emit(); if (new_cell) dff_cells.push_back(new_cell); log("Adding SRST signal on %s (%s) from module %s (D = %s, Q = %s, rval = %s).\n", @@ -741,6 +741,7 @@ struct OptDffWorker continue; } else if (GetSize(remaining_indices) != ff.width) { ff = ff.slice(remaining_indices); + ff.cell = cell; changed = true; } } @@ -790,7 +791,7 @@ struct OptDffWorker new_ff.sig_ce = en.first; new_ff.pol_ce = en.second; new_ff.ce_over_srst = false; - Cell *new_cell = new_ff.emit(module, NEW_ID); + Cell *new_cell = new_ff.emit(); if (new_cell) dff_cells.push_back(new_cell); log("Adding EN signal on %s (%s) from module %s (D = %s, Q = %s).\n", @@ -803,6 +804,7 @@ struct OptDffWorker continue; } else if (GetSize(remaining_indices) != ff.width) { ff = ff.slice(remaining_indices); + ff.cell = cell; changed = true; } } @@ -810,9 +812,7 @@ struct OptDffWorker if (changed) { // Rebuild the FF. - IdString name = cell->name; - module->remove(cell); - ff.emit(module, name); + ff.emit(); did_something = true; } } diff --git a/passes/sat/async2sync.cc b/passes/sat/async2sync.cc index f1b93d084..46c76eba9 100644 --- a/passes/sat/async2sync.cc +++ b/passes/sat/async2sync.cc @@ -78,7 +78,7 @@ struct Async2syncPass : public Pass { if (ff.has_clk) { if (ff.has_sr) { - ff.unmap_ce_srst(module); + ff.unmap_ce_srst(); log("Replacing %s.%s (%s): SET=%s, CLR=%s, D=%s, Q=%s\n", log_id(module), log_id(cell), log_id(cell->type), @@ -124,7 +124,7 @@ struct Async2syncPass : public Pass { ff.sig_q = new_q; ff.has_sr = false; } else if (ff.has_aload) { - ff.unmap_ce_srst(module); + ff.unmap_ce_srst(); log("Replacing %s.%s (%s): ALOAD=%s, AD=%s, D=%s, Q=%s\n", log_id(module), log_id(cell), log_id(cell->type), @@ -157,7 +157,7 @@ struct Async2syncPass : public Pass { ff.sig_q = new_q; ff.has_aload = false; } else if (ff.has_arst) { - ff.unmap_srst(module); + ff.unmap_srst(); log("Replacing %s.%s (%s): ARST=%s, D=%s, Q=%s\n", log_id(module), log_id(cell), log_id(cell->type), @@ -267,10 +267,7 @@ struct Async2syncPass : public Pass { ff.has_sr = false; ff.has_gclk = true; } - - IdString name = cell->name; - module->remove(cell); - ff.emit(module, name); + ff.emit(); } } } diff --git a/passes/sat/clk2fflogic.cc b/passes/sat/clk2fflogic.cc index d90206b46..a292941c8 100644 --- a/passes/sat/clk2fflogic.cc +++ b/passes/sat/clk2fflogic.cc @@ -153,6 +153,23 @@ struct Clk2fflogicPass : public Pass { continue; } + if (ff.has_clk) { + log("Replacing %s.%s (%s): CLK=%s, D=%s, Q=%s\n", + log_id(module), log_id(cell), log_id(cell->type), + log_signal(ff.sig_clk), log_signal(ff.sig_d), log_signal(ff.sig_q)); + } else if (ff.has_aload) { + log("Replacing %s.%s (%s): EN=%s, D=%s, Q=%s\n", + log_id(module), log_id(cell), log_id(cell->type), + log_signal(ff.sig_aload), log_signal(ff.sig_ad), log_signal(ff.sig_q)); + } else { + // $sr. + log("Replacing %s.%s (%s): SET=%s, CLR=%s, Q=%s\n", + log_id(module), log_id(cell), log_id(cell->type), + log_signal(ff.sig_set), log_signal(ff.sig_clr), log_signal(ff.sig_q)); + } + + ff.remove(); + Wire *past_q = module->addWire(NEW_ID, ff.width); if (!ff.is_fine) { module->addFf(NEW_ID, ff.sig_q, past_q); @@ -163,7 +180,7 @@ struct Clk2fflogicPass : public Pass { initvals.set_init(past_q, ff.val_init); if (ff.has_clk) { - ff.unmap_ce_srst(module); + ff.unmap_ce_srst(); Wire *past_clk = module->addWire(NEW_ID); initvals.set_init(past_clk, ff.pol_clk ? State::S1 : State::S0); @@ -173,10 +190,6 @@ struct Clk2fflogicPass : public Pass { else module->addFfGate(NEW_ID, ff.sig_clk, past_clk); - log("Replacing %s.%s (%s): CLK=%s, D=%s, Q=%s\n", - log_id(module), log_id(cell), log_id(cell->type), - log_signal(ff.sig_clk), log_signal(ff.sig_d), log_signal(ff.sig_q)); - SigSpec clock_edge_pattern; if (ff.pol_clk) { @@ -203,16 +216,6 @@ struct Clk2fflogicPass : public Pass { else qval = module->MuxGate(NEW_ID, past_q, past_d, clock_edge); } else { - if (ff.has_aload) { - log("Replacing %s.%s (%s): EN=%s, D=%s, Q=%s\n", - log_id(module), log_id(cell), log_id(cell->type), - log_signal(ff.sig_aload), log_signal(ff.sig_ad), log_signal(ff.sig_q)); - } else { - // $sr. - log("Replacing %s.%s (%s): SET=%s, CLR=%s, Q=%s\n", - log_id(module), log_id(cell), log_id(cell->type), - log_signal(ff.sig_set), log_signal(ff.sig_clr), log_signal(ff.sig_q)); - } qval = past_q; } @@ -246,10 +249,6 @@ struct Clk2fflogicPass : public Pass { } else { module->connect(ff.sig_q, qval); } - - initvals.remove_init(ff.sig_q); - module->remove(cell); - continue; } } } diff --git a/passes/techmap/dffunmap.cc b/passes/techmap/dffunmap.cc index 583185e75..7312015f1 100644 --- a/passes/techmap/dffunmap.cc +++ b/passes/techmap/dffunmap.cc @@ -86,19 +86,18 @@ struct DffunmapPass : public Pass { if (ce_only) { if (!ff.has_ce) continue; - ff.unmap_ce(mod); + ff.unmap_ce(); } else if (srst_only) { if (!ff.has_srst) continue; - ff.unmap_srst(mod); + ff.unmap_srst(); } else { if (!ff.has_ce && !ff.has_srst) continue; - ff.unmap_ce_srst(mod); + ff.unmap_ce_srst(); } - mod->remove(cell); - ff.emit(mod, name); + ff.emit(); } } } diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc index 04d7ec874..68f44cf6d 100644 --- a/passes/techmap/simplemap.cc +++ b/passes/techmap/simplemap.cc @@ -368,13 +368,13 @@ void simplemap_concat(RTLIL::Module *module, RTLIL::Cell *cell) module->connect(RTLIL::SigSig(sig_y, sig_ab)); } -void simplemap_ff(RTLIL::Module *module, RTLIL::Cell *cell) +void simplemap_ff(RTLIL::Module *, RTLIL::Cell *cell) { FfData ff(nullptr, cell); for (int i = 0; i < ff.width; i++) { FfData fff = ff.slice({i}); fff.is_fine = true; - fff.emit(module, NEW_ID); + fff.emit(); } } diff --git a/passes/techmap/zinit.cc b/passes/techmap/zinit.cc index 8fcc47570..cc208c516 100644 --- a/passes/techmap/zinit.cc +++ b/passes/techmap/zinit.cc @@ -25,14 +25,6 @@ USING_YOSYS_NAMESPACE 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 { ZinitPass() : Pass("zinit", "add inverters so all FF are zero-initialized") { } void help() override @@ -75,45 +67,19 @@ struct ZinitPass : public Pass { continue; FfData ff(&initvals, cell); - if (!ff.width) - continue; - - // Supporting those would require a new cell type where S has priority over R. - if (ff.has_sr) - continue; - - Wire *new_q = module->addWire(NEW_ID, ff.width); log("FF init value for cell %s (%s): %s = %s\n", log_id(cell), log_id(cell->type), 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) - { - if (ff.has_clk || ff.has_gclk) - ff.sig_d[i] = module->NotGate(NEW_ID, ff.sig_d[i]); - 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 - { - module->connect(ff.sig_q[i], SigSpec(new_q, i)); - if (all_mode) - ff.val_init[i] = State::S0; - } - - ff.sig_q = new_q; - ff.emit(module, name); + pool bits; + for (int i = 0; i < ff.width; i++) { + if (ff.val_init.bits[i] == State::S1) + bits.insert(i); + else if (ff.val_init.bits[i] != State::S0 && all_mode) + ff.val_init.bits[i] = State::S0; + } + ff.flip_bits(bits); + ff.emit(); } } } diff --git a/tests/arch/xilinx/fsm.ys b/tests/arch/xilinx/fsm.ys index ace646af4..3b1919627 100644 --- a/tests/arch/xilinx/fsm.ys +++ b/tests/arch/xilinx/fsm.ys @@ -31,6 +31,7 @@ stat select -assert-count 1 t:BUFG select -assert-count 6 t:FDRE select -assert-count 1 t:LUT1 -select -assert-count 8 t:LUT4 +select -assert-max 1 t:LUT3 +select -assert-max 8 t:LUT4 select -assert-count 5 t:MUXF5 -select -assert-none t:BUFG t:FDRE t:LUT1 t:LUT4 t:MUXF5 %% t:* %D +select -assert-none t:BUFG t:FDRE t:LUT1 t:LUT3 t:LUT4 t:MUXF5 %% t:* %D diff --git a/tests/techmap/zinit.ys b/tests/techmap/zinit.ys index 1670573dd..bc07f40e6 100644 --- a/tests/techmap/zinit.ys +++ b/tests/techmap/zinit.ys @@ -20,7 +20,8 @@ EOT equiv_opt -assert -multiclock zinit design -load postopt -select -assert-count 20 t:$_NOT_ +select -assert-count 16 t:$_NOT_ +select -assert-count 4 t:$xor select -assert-count 1 w:unused a:init %i select -assert-count 1 w:Q a:init=13'bxxxx1xxxxxxxx %i select -assert-count 4 c:dff0 c:dff2 c:dff4 c:dff6 %% t:$_DFF_??1_ %i @@ -52,7 +53,7 @@ design -load postopt select -assert-count 0 t:$_NOT_ select -assert-count 1 w:unused a:init %i -select -assert-count 1 w:Q a:init=13'bxxxx1xxxxxxxx %i +select -assert-count 1 w:Q a:init=13'bx00x100000000 %i select -assert-count 4 c:dff0 c:dff2 c:dff4 c:dff6 %% t:$_DFF_??0_ %i select -assert-count 4 c:dff1 c:dff3 c:dff5 c:dff7 %% t:$_DFF_??1_ %i @@ -142,7 +143,7 @@ EOT zinit select -assert-count 0 t:$_NOT_ -select -assert-count 0 w:Q a:init %i +select -assert-count 1 w:Q a:init=24'b0 %i select -assert-count 4 c:dff0 c:dff2 c:dff4 c:dff6 %% t:$_DFFE_??0P_ %i select -assert-count 4 c:dff1 c:dff3 c:dff5 c:dff7 %% t:$_DFFE_??1P_ %i select -assert-count 4 c:dff8 c:dff10 c:dff12 c:dff14 %% t:$_SDFF_??0_ %i