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
This commit is contained in:
Marcelina Kościelnicka 2021-10-06 22:16:55 +02:00
parent 356ec7bb39
commit 4e70c30775
14 changed files with 663 additions and 549 deletions

View File

@ -608,7 +608,7 @@ ifneq ($(ABCEXTERNAL),)
kernel/yosys.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"' kernel/yosys.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"'
endif endif
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/log.o: CXXFLAGS += -DYOSYS_SRC='"$(YOSYS_SRC)"'
kernel/yosys.o: CXXFLAGS += -DYOSYS_DATDIR='"$(DATDIR)"' -DYOSYS_PROGRAM_PREFIX='"$(PROGRAM_PREFIX)"' kernel/yosys.o: CXXFLAGS += -DYOSYS_DATDIR='"$(DATDIR)"' -DYOSYS_PROGRAM_PREFIX='"$(PROGRAM_PREFIX)"'

575
kernel/ff.cc Normal file
View File

@ -0,0 +1,575 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2020 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/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<int> &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<int> &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;
}

View File

@ -76,7 +76,10 @@ YOSYS_NAMESPACE_BEGIN
// - empty set [not a cell — will be emitted as a simple direct connection] // - empty set [not a cell — will be emitted as a simple direct connection]
struct FfData { struct FfData {
Module *module;
FfInitVals *initvals; FfInitVals *initvals;
Cell *cell;
IdString name;
// The FF output. // The FF output.
SigSpec sig_q; SigSpec sig_q;
// The sync data input, present if has_clk or has_gclk. // The sync data input, present if has_clk or has_gclk.
@ -142,7 +145,7 @@ struct FfData {
int width; int width;
dict<IdString, Const> attributes; dict<IdString, Const> 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; width = 0;
has_clk = false; has_clk = false;
has_gclk = false; has_gclk = false;
@ -160,464 +163,37 @@ struct FfData {
pol_srst = false; pol_srst = false;
pol_clr = false; pol_clr = false;
pol_set = 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. // Returns a FF identical to this one, but only keeping bit indices from the argument.
FfData slice(const std::vector<int> &bits) { FfData slice(const std::vector<int> &bits);
FfData res(initvals);
res.sig_clk = sig_clk; void unmap_ce();
res.sig_ce = sig_ce;
res.sig_aload = sig_aload; void unmap_srst();
res.sig_arst = sig_arst;
res.sig_srst = sig_srst; void unmap_ce_srst() {
res.has_clk = has_clk; unmap_ce();
res.has_gclk = has_gclk; unmap_srst();
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 unmap_ce(Module *module) { Cell *emit();
if (!has_ce)
return;
log_assert(has_clk);
if (has_srst && ce_over_srst)
unmap_srst(module);
if (!is_fine) { // Removes init attribute from the Q output, but keeps val_init unchanged.
if (pol_ce) // It will be automatically reattached on emit. Use this before changing sig_q.
sig_d = module->Mux(NEW_ID, sig_q, sig_d, sig_ce); void remove_init() {
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;
}
}
if (initvals) if (initvals)
initvals->set_init(sig_q, val_init); initvals->remove_init(sig_q);
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;
} }
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<int> &bits);
}; };
YOSYS_NAMESPACE_END YOSYS_NAMESPACE_END

View File

@ -29,7 +29,7 @@ bool FfMergeHelper::is_output_unused(RTLIL::SigSpec sig) {
} }
bool FfMergeHelper::find_output_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pair<Cell *, int>> &bits) { bool FfMergeHelper::find_output_ff(RTLIL::SigSpec sig, FfData &ff, pool<std::pair<Cell *, int>> &bits) {
ff = FfData(); ff = FfData(module, initvals, NEW_ID);
sigmap->apply(sig); sigmap->apply(sig);
bool found = false; bool found = false;

View File

@ -955,7 +955,7 @@ Cell *Mem::extract_rdff(int idx, FfInitVals *initvals) {
} }
IdString name = stringf("$%s$rdreg[%d]", memid.c_str(), idx); IdString name = stringf("$%s$rdreg[%d]", memid.c_str(), idx);
FfData ff(initvals); FfData ff(module, initvals, name);
ff.width = GetSize(port.data); ff.width = GetSize(port.data);
ff.has_clk = true; ff.has_clk = true;
ff.sig_clk = port.clk; ff.sig_clk = port.clk;
@ -982,7 +982,7 @@ Cell *Mem::extract_rdff(int idx, FfInitVals *initvals) {
ff.sig_q = port.data; ff.sig_q = port.data;
ff.val_init = port.init_value; ff.val_init = port.init_value;
port.data = async_d; 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", 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 // The FF for storing the bypass enable signal must be carefully
// constructed to preserve the overall init/reset/enable behavior // constructed to preserve the overall init/reset/enable behavior
// of the whole port. // of the whole port.
FfData ff(initvals); FfData ff(module, initvals, NEW_ID);
ff.width = 1; ff.width = 1;
ff.sig_q = cond_q; ff.sig_q = cond_q;
ff.sig_d = cond; ff.sig_d = cond;
@ -1189,7 +1189,7 @@ void Mem::emulate_transparency(int widx, int ridx, FfInitVals *initvals) {
ff.val_init = State::S0; ff.val_init = State::S0;
else else
ff.val_init = State::Sx; ff.val_init = State::Sx;
ff.emit(module, NEW_ID); ff.emit();
// And the final bypass mux. // And the final bypass mux.
SigSpec cur = rdata_a.extract(pos, epos-pos); SigSpec cur = rdata_a.extract(pos, epos-pos);
SigSpec other = wdata_q.extract(pos + wsub * width, epos-pos); SigSpec other = wdata_q.extract(pos + wsub * width, epos-pos);

View File

@ -581,7 +581,7 @@ struct MemoryDffWorker
// Now we're commited to merge it. // Now we're commited to merge it.
merger.mark_input_ff(bits); merger.mark_input_ff(bits);
// If the address FF has enable and/or sync reset, unmap it. // 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.clk = ff.sig_clk;
port.en = State::S1; port.en = State::S1;
port.addr = ff.sig_d; port.addr = ff.sig_d;

View File

@ -275,7 +275,7 @@ struct OptDffWorker
bool changed = false; bool changed = false;
if (!ff.width) { if (!ff.width) {
module->remove(cell); ff.remove();
did_something = true; did_something = true;
continue; continue;
} }
@ -316,6 +316,7 @@ struct OptDffWorker
continue; continue;
} }
ff = ff.slice(keep_bits); ff = ff.slice(keep_bits);
ff.cell = cell;
changed = true; changed = true;
} }
@ -393,8 +394,7 @@ struct OptDffWorker
// Always-active enable. Make a comb circuit, nuke the FF/latch. // 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("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)); log_id(cell), log_id(cell->type), log_id(module));
initvals.remove_init(ff.sig_q); ff.remove();
module->remove(cell);
if (ff.has_sr) { if (ff.has_sr) {
SigSpec tmp; SigSpec tmp;
if (ff.is_fine) { if (ff.is_fine) {
@ -456,8 +456,7 @@ struct OptDffWorker
// Always-active async reset — change to const driver. // 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("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)); log_id(cell), log_id(cell->type), log_id(module));
initvals.remove_init(ff.sig_q); ff.remove();
module->remove(cell);
module->connect(ff.sig_q, ff.val_arst); module->connect(ff.sig_q, ff.val_arst);
did_something = true; did_something = true;
continue; continue;
@ -660,6 +659,7 @@ struct OptDffWorker
continue; continue;
} }
ff = ff.slice(keep_bits); ff = ff.slice(keep_bits);
ff.cell = cell;
changed = true; changed = true;
} }
@ -728,7 +728,7 @@ struct OptDffWorker
new_ff.pol_srst = srst.second; new_ff.pol_srst = srst.second;
if (new_ff.has_ce) if (new_ff.has_ce)
new_ff.ce_over_srst = true; new_ff.ce_over_srst = true;
Cell *new_cell = new_ff.emit(module, NEW_ID); Cell *new_cell = new_ff.emit();
if (new_cell) if (new_cell)
dff_cells.push_back(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", log("Adding SRST signal on %s (%s) from module %s (D = %s, Q = %s, rval = %s).\n",
@ -741,6 +741,7 @@ struct OptDffWorker
continue; continue;
} else if (GetSize(remaining_indices) != ff.width) { } else if (GetSize(remaining_indices) != ff.width) {
ff = ff.slice(remaining_indices); ff = ff.slice(remaining_indices);
ff.cell = cell;
changed = true; changed = true;
} }
} }
@ -790,7 +791,7 @@ struct OptDffWorker
new_ff.sig_ce = en.first; new_ff.sig_ce = en.first;
new_ff.pol_ce = en.second; new_ff.pol_ce = en.second;
new_ff.ce_over_srst = false; new_ff.ce_over_srst = false;
Cell *new_cell = new_ff.emit(module, NEW_ID); Cell *new_cell = new_ff.emit();
if (new_cell) if (new_cell)
dff_cells.push_back(new_cell); dff_cells.push_back(new_cell);
log("Adding EN signal on %s (%s) from module %s (D = %s, Q = %s).\n", log("Adding EN signal on %s (%s) from module %s (D = %s, Q = %s).\n",
@ -803,6 +804,7 @@ struct OptDffWorker
continue; continue;
} else if (GetSize(remaining_indices) != ff.width) { } else if (GetSize(remaining_indices) != ff.width) {
ff = ff.slice(remaining_indices); ff = ff.slice(remaining_indices);
ff.cell = cell;
changed = true; changed = true;
} }
} }
@ -810,9 +812,7 @@ struct OptDffWorker
if (changed) { if (changed) {
// Rebuild the FF. // Rebuild the FF.
IdString name = cell->name; ff.emit();
module->remove(cell);
ff.emit(module, name);
did_something = true; did_something = true;
} }
} }

View File

@ -78,7 +78,7 @@ struct Async2syncPass : public Pass {
if (ff.has_clk) if (ff.has_clk)
{ {
if (ff.has_sr) { 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("Replacing %s.%s (%s): SET=%s, CLR=%s, D=%s, Q=%s\n",
log_id(module), log_id(cell), log_id(cell->type), log_id(module), log_id(cell), log_id(cell->type),
@ -124,7 +124,7 @@ struct Async2syncPass : public Pass {
ff.sig_q = new_q; ff.sig_q = new_q;
ff.has_sr = false; ff.has_sr = false;
} else if (ff.has_aload) { } 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("Replacing %s.%s (%s): ALOAD=%s, AD=%s, D=%s, Q=%s\n",
log_id(module), log_id(cell), log_id(cell->type), log_id(module), log_id(cell), log_id(cell->type),
@ -157,7 +157,7 @@ struct Async2syncPass : public Pass {
ff.sig_q = new_q; ff.sig_q = new_q;
ff.has_aload = false; ff.has_aload = false;
} else if (ff.has_arst) { } 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("Replacing %s.%s (%s): ARST=%s, D=%s, Q=%s\n",
log_id(module), log_id(cell), log_id(cell->type), log_id(module), log_id(cell), log_id(cell->type),
@ -267,10 +267,7 @@ struct Async2syncPass : public Pass {
ff.has_sr = false; ff.has_sr = false;
ff.has_gclk = true; ff.has_gclk = true;
} }
ff.emit();
IdString name = cell->name;
module->remove(cell);
ff.emit(module, name);
} }
} }
} }

View File

@ -153,6 +153,23 @@ struct Clk2fflogicPass : public Pass {
continue; 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); Wire *past_q = module->addWire(NEW_ID, ff.width);
if (!ff.is_fine) { if (!ff.is_fine) {
module->addFf(NEW_ID, ff.sig_q, past_q); 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); initvals.set_init(past_q, ff.val_init);
if (ff.has_clk) { if (ff.has_clk) {
ff.unmap_ce_srst(module); ff.unmap_ce_srst();
Wire *past_clk = module->addWire(NEW_ID); Wire *past_clk = module->addWire(NEW_ID);
initvals.set_init(past_clk, ff.pol_clk ? State::S1 : State::S0); initvals.set_init(past_clk, ff.pol_clk ? State::S1 : State::S0);
@ -173,10 +190,6 @@ struct Clk2fflogicPass : public Pass {
else else
module->addFfGate(NEW_ID, ff.sig_clk, past_clk); 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; SigSpec clock_edge_pattern;
if (ff.pol_clk) { if (ff.pol_clk) {
@ -203,16 +216,6 @@ struct Clk2fflogicPass : public Pass {
else else
qval = module->MuxGate(NEW_ID, past_q, past_d, clock_edge); qval = module->MuxGate(NEW_ID, past_q, past_d, clock_edge);
} else { } 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; qval = past_q;
} }
@ -246,10 +249,6 @@ struct Clk2fflogicPass : public Pass {
} else { } else {
module->connect(ff.sig_q, qval); module->connect(ff.sig_q, qval);
} }
initvals.remove_init(ff.sig_q);
module->remove(cell);
continue;
} }
} }
} }

View File

@ -86,19 +86,18 @@ struct DffunmapPass : public Pass {
if (ce_only) { if (ce_only) {
if (!ff.has_ce) if (!ff.has_ce)
continue; continue;
ff.unmap_ce(mod); ff.unmap_ce();
} else if (srst_only) { } else if (srst_only) {
if (!ff.has_srst) if (!ff.has_srst)
continue; continue;
ff.unmap_srst(mod); ff.unmap_srst();
} else { } else {
if (!ff.has_ce && !ff.has_srst) if (!ff.has_ce && !ff.has_srst)
continue; continue;
ff.unmap_ce_srst(mod); ff.unmap_ce_srst();
} }
mod->remove(cell); ff.emit();
ff.emit(mod, name);
} }
} }
} }

View File

@ -368,13 +368,13 @@ void simplemap_concat(RTLIL::Module *module, RTLIL::Cell *cell)
module->connect(RTLIL::SigSig(sig_y, sig_ab)); 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); FfData ff(nullptr, cell);
for (int i = 0; i < ff.width; i++) { for (int i = 0; i < ff.width; i++) {
FfData fff = ff.slice({i}); FfData fff = ff.slice({i});
fff.is_fine = true; fff.is_fine = true;
fff.emit(module, NEW_ID); fff.emit();
} }
} }

View File

@ -25,14 +25,6 @@
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
@ -75,45 +67,19 @@ struct ZinitPass : public Pass {
continue; continue;
FfData ff(&initvals, cell); 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("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)); log_signal(ff.sig_q), log_signal(ff.val_init));
IdString name = cell->name; pool<int> bits;
module->remove(cell); for (int i = 0; i < ff.width; i++) {
initvals.remove_init(ff.sig_q); if (ff.val_init.bits[i] == State::S1)
bits.insert(i);
for (int i = 0; i < ff.width; i++) else if (ff.val_init.bits[i] != State::S0 && all_mode)
if (ff.val_init[i] == State::S1) ff.val_init.bits[i] = State::S0;
{ }
if (ff.has_clk || ff.has_gclk) ff.flip_bits(bits);
ff.sig_d[i] = module->NotGate(NEW_ID, ff.sig_d[i]); ff.emit();
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);
} }
} }
} }

View File

@ -31,6 +31,7 @@ stat
select -assert-count 1 t:BUFG select -assert-count 1 t:BUFG
select -assert-count 6 t:FDRE select -assert-count 6 t:FDRE
select -assert-count 1 t:LUT1 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-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

View File

@ -20,7 +20,8 @@ EOT
equiv_opt -assert -multiclock zinit equiv_opt -assert -multiclock zinit
design -load postopt 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:unused a:init %i
select -assert-count 1 w:Q a:init=13'bxxxx1xxxxxxxx %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 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 0 t:$_NOT_
select -assert-count 1 w:unused a:init %i 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: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 select -assert-count 4 c:dff1 c:dff3 c:dff5 c:dff7 %% t:$_DFF_??1_ %i
@ -142,7 +143,7 @@ EOT
zinit zinit
select -assert-count 0 t:$_NOT_ 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: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: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 select -assert-count 4 c:dff8 c:dff10 c:dff12 c:dff14 %% t:$_SDFF_??0_ %i