abc: Add support for FFs with reset in -dff

This commit is contained in:
Marcelina Kościelnicka 2022-04-07 03:25:35 +02:00
parent 4da3f2878b
commit 376d8cb26f
1 changed files with 230 additions and 91 deletions

View File

@ -45,6 +45,7 @@
#include "kernel/sigtools.h"
#include "kernel/celltypes.h"
#include "kernel/ffinit.h"
#include "kernel/ff.h"
#include "kernel/cost.h"
#include "kernel/log.h"
#include <stdlib.h>
@ -73,6 +74,8 @@ PRIVATE_NAMESPACE_BEGIN
enum class gate_type_t {
G_NONE,
G_FF,
G_FF0,
G_FF1,
G_BUF,
G_NOT,
G_AND,
@ -115,10 +118,11 @@ std::vector<gate_t> signal_list;
std::map<RTLIL::SigBit, int> signal_map;
FfInitVals initvals;
pool<std::string> enabled_gates;
bool recover_init, cmos_cost;
bool cmos_cost;
bool had_init;
bool clk_polarity, en_polarity;
RTLIL::SigSpec clk_sig, en_sig;
bool clk_polarity, en_polarity, arst_polarity, srst_polarity;
RTLIL::SigSpec clk_sig, en_sig, arst_sig, srst_sig;
dict<int, std::string> pi_map, po_map;
int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1)
@ -165,46 +169,84 @@ void mark_port(RTLIL::SigSpec sig)
void extract_cell(RTLIL::Cell *cell, bool keepff)
{
if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_)))
{
if (clk_polarity != (cell->type == ID($_DFF_P_)))
if (RTLIL::builtin_ff_cell_types().count(cell->type)) {
FfData ff(&initvals, cell);
gate_type_t type = G(FF);
if (!ff.has_clk)
return;
if (clk_sig != assign_map(cell->getPort(ID::C)))
if (ff.has_gclk)
return;
if (GetSize(en_sig) != 0)
if (ff.has_aload)
return;
goto matching_dff;
}
if (cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
{
if (clk_polarity != cell->type.in(ID($_DFFE_PN_), ID($_DFFE_PP_)))
if (ff.has_sr)
return;
if (en_polarity != cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_)))
if (!ff.is_fine)
return;
if (clk_sig != assign_map(cell->getPort(ID::C)))
if (clk_polarity != ff.pol_clk)
return;
if (en_sig != assign_map(cell->getPort(ID::E)))
if (clk_sig != assign_map(ff.sig_clk))
return;
goto matching_dff;
}
if (0) {
matching_dff:
RTLIL::SigSpec sig_d = cell->getPort(ID::D);
RTLIL::SigSpec sig_q = cell->getPort(ID::Q);
if (ff.has_ce) {
if (en_polarity != ff.pol_ce)
return;
if (en_sig != assign_map(ff.sig_ce))
return;
} else {
if (GetSize(en_sig) != 0)
return;
}
if (ff.val_init == State::S1) {
type = G(FF1);
had_init = true;
} else if (ff.val_init == State::S0) {
type = G(FF0);
had_init = true;
}
if (ff.has_arst) {
if (arst_polarity != ff.pol_arst)
return;
if (arst_sig != assign_map(ff.sig_arst))
return;
if (ff.val_arst == State::S1) {
if (type == G(FF0))
return;
type = G(FF1);
} else if (ff.val_arst == State::S0) {
if (type == G(FF1))
return;
type = G(FF0);
}
} else {
if (GetSize(arst_sig) != 0)
return;
}
if (ff.has_srst) {
if (srst_polarity != ff.pol_srst)
return;
if (srst_sig != assign_map(ff.sig_srst))
return;
if (ff.val_srst == State::S1) {
if (type == G(FF0))
return;
type = G(FF1);
} else if (ff.val_srst == State::S0) {
if (type == G(FF1))
return;
type = G(FF0);
}
} else {
if (GetSize(srst_sig) != 0)
return;
}
if (keepff)
for (auto &c : sig_q.chunks())
for (auto &c : ff.sig_q.chunks())
if (c.wire != nullptr)
c.wire->attributes[ID::keep] = 1;
assign_map.apply(sig_d);
assign_map.apply(sig_q);
map_signal(ff.sig_q, type, map_signal(ff.sig_d));
map_signal(sig_q, G(FF), map_signal(sig_d));
module->remove(cell);
ff.remove();
return;
}
@ -412,7 +454,7 @@ void handle_loops()
// dot_f = fopen("test.dot", "w");
for (auto &g : signal_list) {
if (g.type == G(NONE) || g.type == G(FF)) {
if (g.type == G(NONE) || g.type == G(FF) || g.type == G(FF0) || g.type == G(FF1)) {
workpool.insert(g.id);
} else {
if (g.in1 >= 0) {
@ -667,7 +709,6 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
signal_list.clear();
pi_map.clear();
po_map.clear();
recover_init = false;
if (clk_str != "$")
{
@ -676,20 +717,33 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
en_polarity = true;
en_sig = RTLIL::SigSpec();
arst_polarity = true;
arst_sig = RTLIL::SigSpec();
srst_polarity = true;
srst_sig = RTLIL::SigSpec();
}
if (!clk_str.empty() && clk_str != "$")
{
std::string en_str;
std::string arst_str;
std::string srst_str;
if (clk_str.find(',') != std::string::npos) {
int pos = clk_str.find(',');
std::string en_str = clk_str.substr(pos+1);
en_str = clk_str.substr(pos+1);
clk_str = clk_str.substr(0, pos);
if (en_str[0] == '!') {
en_polarity = false;
en_str = en_str.substr(1);
}
if (module->wire(RTLIL::escape_id(en_str)) != nullptr)
en_sig = assign_map(module->wire(RTLIL::escape_id(en_str)));
}
if (en_str.find(',') != std::string::npos) {
int pos = en_str.find(',');
arst_str = en_str.substr(pos+1);
arst_str = en_str.substr(0, pos);
}
if (arst_str.find(',') != std::string::npos) {
int pos = arst_str.find(',');
srst_str = arst_str.substr(pos+1);
srst_str = arst_str.substr(0, pos);
}
if (clk_str[0] == '!') {
clk_polarity = false;
@ -697,6 +751,30 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
}
if (module->wire(RTLIL::escape_id(clk_str)) != nullptr)
clk_sig = assign_map(module->wire(RTLIL::escape_id(clk_str)));
if (en_str != "") {
if (en_str[0] == '!') {
en_polarity = false;
en_str = en_str.substr(1);
}
if (module->wire(RTLIL::escape_id(en_str)) != nullptr)
en_sig = assign_map(module->wire(RTLIL::escape_id(en_str)));
}
if (arst_str != "") {
if (arst_str[0] == '!') {
arst_polarity = false;
arst_str = arst_str.substr(1);
}
if (module->wire(RTLIL::escape_id(arst_str)) != nullptr)
arst_sig = assign_map(module->wire(RTLIL::escape_id(arst_str)));
}
if (srst_str != "") {
if (srst_str[0] == '!') {
srst_polarity = false;
srst_str = srst_str.substr(1);
}
if (module->wire(RTLIL::escape_id(srst_str)) != nullptr)
srst_sig = assign_map(module->wire(RTLIL::escape_id(srst_str)));
}
}
if (dff_mode && clk_sig.empty())
@ -789,10 +867,15 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
log("Found%s %s clock domain: %s", clk_str.empty() ? "" : " matching", clk_polarity ? "posedge" : "negedge", log_signal(clk_sig));
if (en_sig.size() != 0)
log(", enabled by %s%s", en_polarity ? "" : "!", log_signal(en_sig));
if (arst_sig.size() != 0)
log(", asynchronously reset by %s%s", arst_polarity ? "" : "!", log_signal(arst_sig));
if (srst_sig.size() != 0)
log(", synchronously reset by %s%s", srst_polarity ? "" : "!", log_signal(srst_sig));
log("\n");
}
}
had_init = false;
for (auto c : cells)
extract_cell(c, keepff);
@ -811,6 +894,12 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
if (en_sig.size() != 0)
mark_port(en_sig);
if (arst_sig.size() != 0)
mark_port(arst_sig);
if (srst_sig.size() != 0)
mark_port(srst_sig);
handle_loops();
buffer = stringf("%s/input.blif", tempdir_name.c_str());
@ -917,11 +1006,11 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
fprintf(f, "00-- 1\n");
fprintf(f, "--00 1\n");
} else if (si.type == G(FF)) {
if (si.init == State::S0 || si.init == State::S1) {
fprintf(f, ".latch ys__n%d ys__n%d %d\n", si.in1, si.id, si.init == State::S1 ? 1 : 0);
recover_init = true;
} else
fprintf(f, ".latch ys__n%d ys__n%d 2\n", si.in1, si.id);
fprintf(f, ".latch ys__n%d ys__n%d 2\n", si.in1, si.id);
} else if (si.type == G(FF0)) {
fprintf(f, ".latch ys__n%d ys__n%d 0\n", si.in1, si.id);
} else if (si.type == G(FF1)) {
fprintf(f, ".latch ys__n%d ys__n%d 1\n", si.in1, si.id);
} else if (si.type != G(NONE))
log_abort();
if (si.type != G(NONE))
@ -1043,6 +1132,9 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
design->select(module, wire);
}
SigMap mapped_sigmap(mapped_mod);
FfInitVals mapped_initvals(&mapped_sigmap, mapped_mod);
std::map<std::string, int> cell_stats;
for (auto c : mapped_mod->cells())
{
@ -1149,20 +1241,41 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
}
if (c->type == ID(DFF)) {
log_assert(clk_sig.size() == 1);
RTLIL::Cell *cell;
if (en_sig.size() == 0) {
cell = module->addCell(remap_name(c->name), clk_polarity ? ID($_DFF_P_) : ID($_DFF_N_));
} else {
FfData ff(module, &initvals, remap_name(c->name));
ff.width = 1;
ff.is_fine = true;
ff.has_clk = true;
ff.pol_clk = clk_polarity;
ff.sig_clk = clk_sig;
if (en_sig.size() != 0) {
log_assert(en_sig.size() == 1);
cell = module->addCell(remap_name(c->name), stringf("$_DFFE_%c%c_", clk_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N'));
cell->setPort(ID::E, en_sig);
ff.has_ce = true;
ff.pol_ce = en_polarity;
ff.sig_ce = en_sig;
}
RTLIL::Const init = mapped_initvals(c->getPort(ID::Q));
if (had_init)
ff.val_init = init;
else
ff.val_init = State::Sx;
if (arst_sig.size() != 0) {
log_assert(arst_sig.size() == 1);
ff.has_arst = true;
ff.pol_arst = arst_polarity;
ff.sig_arst = arst_sig;
ff.val_arst = init;
}
if (srst_sig.size() != 0) {
log_assert(srst_sig.size() == 1);
ff.has_srst = true;
ff.pol_srst = srst_polarity;
ff.sig_srst = srst_sig;
ff.val_srst = init;
}
ff.sig_d = module->wire(remap_name(c->getPort(ID::D).as_wire()->name));
ff.sig_q = module->wire(remap_name(c->getPort(ID::Q).as_wire()->name));
RTLIL::Cell *cell = ff.emit();
if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx;
for (auto name : {ID::D, ID::Q}) {
RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name);
cell->setPort(name, module->wire(remapped_name));
}
cell->setPort(ID::C, clk_sig);
design->select(module, cell);
continue;
}
@ -1180,20 +1293,38 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
if (c->type == ID(_dff_)) {
log_assert(clk_sig.size() == 1);
RTLIL::Cell *cell;
if (en_sig.size() == 0) {
cell = module->addCell(remap_name(c->name), clk_polarity ? ID($_DFF_P_) : ID($_DFF_N_));
} else {
FfData ff(module, &initvals, remap_name(c->name));
ff.width = 1;
ff.is_fine = true;
ff.has_clk = true;
ff.pol_clk = clk_polarity;
ff.sig_clk = clk_sig;
if (en_sig.size() != 0) {
log_assert(en_sig.size() == 1);
cell = module->addCell(remap_name(c->name), stringf("$_DFFE_%c%c_", clk_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N'));
cell->setPort(ID::E, en_sig);
ff.pol_ce = en_polarity;
ff.sig_ce = en_sig;
}
RTLIL::Const init = mapped_initvals(c->getPort(ID::Q));
if (had_init)
ff.val_init = init;
else
ff.val_init = State::Sx;
if (arst_sig.size() != 0) {
log_assert(arst_sig.size() == 1);
ff.pol_arst = arst_polarity;
ff.sig_arst = arst_sig;
ff.val_arst = init;
}
if (srst_sig.size() != 0) {
log_assert(srst_sig.size() == 1);
ff.pol_srst = srst_polarity;
ff.sig_srst = srst_sig;
ff.val_srst = init;
}
ff.sig_d = module->wire(remap_name(c->getPort(ID::D).as_wire()->name));
ff.sig_q = module->wire(remap_name(c->getPort(ID::Q).as_wire()->name));
RTLIL::Cell *cell = ff.emit();
if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx;
for (auto name : {ID::D, ID::Q}) {
RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name);
cell->setPort(name, module->wire(remapped_name));
}
cell->setPort(ID::C, clk_sig);
design->select(module, cell);
continue;
}
@ -1229,15 +1360,6 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
module->connect(conn);
}
if (recover_init)
for (auto wire : mapped_mod->wires()) {
if (wire->attributes.count(ID::init)) {
Wire *w = module->wire(remap_name(wire->name));
log_assert(w->attributes.count(ID::init) == 0);
w->attributes[ID::init] = wire->attributes.at(ID::init);
}
}
for (auto &it : cell_stats)
log("ABC RESULTS: %15s cells: %8d\n", it.first.c_str(), it.second);
int in_wires = 0, out_wires = 0;
@ -1884,7 +2006,7 @@ struct AbcPass : public Pass {
std::set<RTLIL::Cell*> expand_queue_up, next_expand_queue_up;
std::set<RTLIL::Cell*> expand_queue_down, next_expand_queue_down;
typedef tuple<bool, RTLIL::SigSpec, bool, RTLIL::SigSpec> clkdomain_t;
typedef tuple<bool, RTLIL::SigSpec, bool, RTLIL::SigSpec, bool, RTLIL::SigSpec, bool, RTLIL::SigSpec> clkdomain_t;
std::map<clkdomain_t, std::vector<RTLIL::Cell*>> assigned_cells;
std::map<RTLIL::Cell*, clkdomain_t> assigned_cells_reverse;
@ -1912,20 +2034,31 @@ struct AbcPass : public Pass {
}
}
if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_)))
{
key = clkdomain_t(cell->type == ID($_DFF_P_), assign_map(cell->getPort(ID::C)), true, RTLIL::SigSpec());
}
else
if (cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
{
bool this_clk_pol = cell->type.in(ID($_DFFE_PN_), ID($_DFFE_PP_));
bool this_en_pol = cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_));
key = clkdomain_t(this_clk_pol, assign_map(cell->getPort(ID::C)), this_en_pol, assign_map(cell->getPort(ID::E)));
}
else
if (!RTLIL::builtin_ff_cell_types().count(cell->type))
continue;
FfData ff(&initvals, cell);
if (!ff.has_clk)
continue;
if (ff.has_gclk)
continue;
if (ff.has_aload)
continue;
if (ff.has_sr)
continue;
if (!ff.is_fine)
continue;
key = clkdomain_t(
ff.pol_clk,
ff.sig_clk,
ff.has_ce ? ff.pol_ce : true,
ff.has_ce ? assign_map(ff.sig_ce) : RTLIL::SigSpec(),
ff.has_arst ? ff.pol_arst : true,
ff.has_arst ? assign_map(ff.sig_arst) : RTLIL::SigSpec(),
ff.has_srst ? ff.pol_srst : true,
ff.has_srst ? assign_map(ff.sig_srst) : RTLIL::SigSpec()
);
unassigned_cells.erase(cell);
expand_queue.insert(cell);
expand_queue_up.insert(cell);
@ -1998,7 +2131,7 @@ struct AbcPass : public Pass {
expand_queue.swap(next_expand_queue);
}
clkdomain_t key(true, RTLIL::SigSpec(), true, RTLIL::SigSpec());
clkdomain_t key(true, RTLIL::SigSpec(), true, RTLIL::SigSpec(), true, RTLIL::SigSpec(), true, RTLIL::SigSpec());
for (auto cell : unassigned_cells) {
assigned_cells[key].push_back(cell);
assigned_cells_reverse[cell] = key;
@ -2006,15 +2139,21 @@ struct AbcPass : public Pass {
log_header(design, "Summary of detected clock domains:\n");
for (auto &it : assigned_cells)
log(" %d cells in clk=%s%s, en=%s%s\n", GetSize(it.second),
log(" %d cells in clk=%s%s, en=%s%s, arst=%s%s, srst=%s%s\n", GetSize(it.second),
std::get<0>(it.first) ? "" : "!", log_signal(std::get<1>(it.first)),
std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(it.first)));
std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(it.first)),
std::get<4>(it.first) ? "" : "!", log_signal(std::get<5>(it.first)),
std::get<6>(it.first) ? "" : "!", log_signal(std::get<7>(it.first)));
for (auto &it : assigned_cells) {
clk_polarity = std::get<0>(it.first);
clk_sig = assign_map(std::get<1>(it.first));
en_polarity = std::get<2>(it.first);
en_sig = assign_map(std::get<3>(it.first));
arst_polarity = std::get<4>(it.first);
arst_sig = assign_map(std::get<5>(it.first));
srst_polarity = std::get<6>(it.first);
srst_sig = assign_map(std::get<7>(it.first));
abc_module(design, mod, script_file, exe_file, liberty_files, genlib_files, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$",
keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode, abc_dress);
assign_map.set(mod);