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)"'
|
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)"'
|
||||||
|
|
|
@ -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]
|
// - 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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue