mirror of https://github.com/YosysHQ/yosys.git
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:
parent
356ec7bb39
commit
4e70c30775
2
Makefile
2
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)"'
|
||||
|
|
|
@ -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;
|
||||
}
|
478
kernel/ff.h
478
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<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;
|
||||
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<int> &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<int> &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<int> &bits);
|
||||
};
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
|
|
@ -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) {
|
||||
ff = FfData();
|
||||
ff = FfData(module, initvals, NEW_ID);
|
||||
sigmap->apply(sig);
|
||||
|
||||
bool found = false;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<int> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue