abc9_ops: add 'dff' label for auto handling of (* abc9_flop *) boxes

This commit is contained in:
Eddie Hung 2020-04-13 09:38:07 -07:00
parent accfc70fc2
commit 95763c8d18
9 changed files with 403 additions and 640 deletions

View File

@ -616,7 +616,6 @@ struct XAigerWriter
dict<SigBit, int> clk_to_mergeability;
bool nonzero_warned = false;
for (const auto &i : ff_bits) {
const SigBit &d = i.first;
const Cell *cell = i.second;
@ -633,15 +632,10 @@ struct XAigerWriter
write_r_buffer(mergeability);
else log_abort();
Const init = cell->attributes.at(ID::abc9_init, State::Sx);
Const init = cell->attributes.at(ID::abc9_init);
log_assert(GetSize(init) == 1);
if (init == State::S1) {
if (!nonzero_warned) {
log_warning("Module '%s' contains $_DFF_[NP]_ cell with non-zero initial state -- unsupported by ABC9.\n", log_id(module));
nonzero_warned = true;
}
if (init == State::S1)
write_s_buffer(1);
}
else if (init == State::S0)
write_s_buffer(0);
else {

View File

@ -389,7 +389,7 @@ struct SubmodPass : public Pass {
while (did_something) {
did_something = false;
std::vector<RTLIL::IdString> queued_modules;
for (auto mod : design->modules())
for (auto mod : design->selected_modules())
if (handled_modules.count(mod->name) == 0 && design->selected_whole_module(mod->name))
queued_modules.push_back(mod->name);
for (auto &modname : queued_modules)

View File

@ -151,8 +151,8 @@ struct Abc9Pass : public ScriptPass
log(" specified).\n");
log("\n");
log(" -dff\n");
log(" also pass $_ABC9_FF_ cells through to ABC. modules with many clock\n");
log(" domains are marked as such and automatically partitioned by ABC.\n");
log(" also pass $_DFF_[NP]_ cells through to ABC. modules with many clock\n");
log(" domains are supported and automatically partitioned by ABC.\n");
log("\n");
log(" -nocleanup\n");
log(" when this option is used, the temporary files created by this pass\n");
@ -274,26 +274,74 @@ struct Abc9Pass : public ScriptPass
void script() YS_OVERRIDE
{
if (check_label("pre")) {
if (check_label("check")) {
run("abc9_ops -check");
}
if (check_label("dff", "(only if -dff)")) {
if (dff_mode || help_mode) {
run("abc9_ops -prep_dff_hier"); // derive all used (* abc9_flop *) modules
run("design -stash $abc9");
run("design -copy-from $abc9 @$abc9_flops"); // copy derived modules in
run("proc");
run("wbflip");
run("techmap");
run("opt");
run("abc9_ops -prep_dff_map"); // rewrite specify
// TODO: Select fan-in cone $_DFF_[NP]_.Q
run("setattr -set submod \"$abc9_flop\" t:* t:$_DFF_N_ %d t:$_DFF_P_ %d");
run("submod");
run("design -copy-to $abc9 *_$abc9_flop"); // copy submod out
run("delete *_$abc9_flop");
if (help_mode) {
run("foreach module in design");
run(" cd <module-name>");
run(" rename <module-name>_$abc9_flop _TECHMAP_REPLACE_");
run(" cd");
}
else {
// Rename all submod-s to _TECHMAP_REPLACE_ to inherit name + attrs
for (auto module : active_design->selected_modules()) {
run(stringf("cd %s", log_id(module->name)));
run(stringf("rename %s_$abc9_flop _TECHMAP_REPLACE_", module->name.c_str()));
run("cd");
}
}
run("design -stash $abc9_map");
run("design -load $abc9");
run("abc9_ops -prep_dff_unmap"); // create $abc9_unmap design
run("techmap -map %$abc9_map"); // techmap user design into submod + $_DFF_[NP]_
run("setattr -mod -set whitebox 1 -set abc9_flop 1 -set abc9_box 1 *_$abc9_flop");
if (!help_mode) {
// TODO: Need a way to delete saved designs?
auto it = saved_designs.find("$abc9_map");
delete it->second;
saved_designs.erase(it);
// TODO: Need a way to delete selections
active_design->selection_vars.erase(ID($abc9_flops));
active_design->selection_vars.erase(ID($abc9_cells));
}
}
}
if (check_label("pre")) {
run("scc -set_attr abc9_scc_id {}");
if (help_mode)
run("abc9_ops -mark_scc -prep_delays -prep_xaiger [-dff]", "(option for -dff)");
else
run("abc9_ops -mark_scc -prep_delays -prep_xaiger" + std::string(dff_mode ? " -dff" : ""), "(option for -dff)");
run("abc9_ops -mark_scc -prep_delays -prep_xaiger" + std::string(dff_mode ? " -dff" : ""));
if (help_mode)
run("abc9_ops -prep_lut <maxlut>", "(skip if -lut or -luts)");
else if (!lut_mode)
run(stringf("abc9_ops -prep_lut %d", maxlut));
if (help_mode)
run("abc9_ops -prep_box [-dff]", "(skip if -box)");
else if (box_file.empty())
run(stringf("abc9_ops -prep_box %s", dff_mode ? "-dff" : ""));
run("abc9_ops -prep_box", "(skip if -box)");
else if (box_file.empty()) {
run("abc9_ops -prep_box");
}
run("select -set abc9_holes A:abc9_holes");
run("flatten -wb @abc9_holes");
run("techmap @abc9_holes");
if (dff_mode || help_mode)
run("abc9_ops -prep_dff", "(only if -dff)");
run("opt -purge @abc9_holes");
run("aigmap");
run("wbflip @abc9_holes");
@ -304,10 +352,10 @@ struct Abc9Pass : public ScriptPass
run("foreach module in selection");
run(" abc9_ops -write_lut <abc-temp-dir>/input.lut", "(skip if '-lut' or '-luts')");
run(" abc9_ops -write_box <abc-temp-dir>/input.box", "(skip if '-box')");
run(" write_xaiger -map <abc-temp-dir>/input.sym <abc-temp-dir>/input.xaig");
run(" abc9_exe [options] -cwd <abc-temp-dir> [-lut <abc-temp-dir>/input.lut] -box <abc-temp-dir>/input.box");
run(" write_xaiger -map <abc-temp-dir>/input.sym [-dff] <abc-temp-dir>/input.xaig");
run(" abc9_exe [options] -cwd <abc-temp-dir> -lut [<abc-temp-dir>/input.lut] -box [<abc-temp-dir>/input.box]");
run(" read_aiger -xaiger -wideports -module_name <module-name>$abc9 -map <abc-temp-dir>/input.sym <abc-temp-dir>/output.aig");
run(" abc9_ops -reintegrate");
run(" abc9_ops -reintegrate [-dff]");
}
else {
auto selected_modules = active_design->selected_modules();
@ -335,7 +383,7 @@ struct Abc9Pass : public ScriptPass
run_nocheck(stringf("abc9_ops -write_lut %s/input.lut", tempdir_name.c_str()));
if (box_file.empty())
run_nocheck(stringf("abc9_ops -write_box %s/input.box", tempdir_name.c_str()));
run_nocheck(stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str()));
run_nocheck(stringf("write_xaiger -map %s/input.sym %s %s/input.xaig", tempdir_name.c_str(), dff_mode ? "-dff" : "", tempdir_name.c_str()));
int num_outputs = active_design->scratchpad_get_int("write_xaiger.num_outputs");
@ -356,7 +404,7 @@ struct Abc9Pass : public ScriptPass
abc9_exe_cmd += stringf(" -box %s", box_file.c_str());
run_nocheck(abc9_exe_cmd);
run_nocheck(stringf("read_aiger -xaiger -wideports -module_name %s$abc9 -map %s/input.sym %s/output.aig", log_id(mod), tempdir_name.c_str(), tempdir_name.c_str()));
run_nocheck("abc9_ops -reintegrate");
run_nocheck(stringf("abc9_ops -reintegrate %s", dff_mode ? "-dff" : ""));
}
else
log("Don't call ABC as there is nothing to map.\n");
@ -373,6 +421,19 @@ struct Abc9Pass : public ScriptPass
active_design->selection_stack.pop_back();
}
}
if (check_label("post")) {
if (dff_mode || help_mode) {
run("techmap -wb -map %$abc9_unmap", "(only if -dff)"); // techmap user design from submod back to original cell
// ($_DFF_[NP]_ already shorted by -reintegrate)
if (!help_mode) {
// TODO: Need a way to delete saved designs?
auto it = saved_designs.find("$abc9_unmap");
delete it->second;
saved_designs.erase(it);
}
}
}
}
} Abc9Pass;

View File

@ -119,83 +119,129 @@ void mark_scc(RTLIL::Module *module)
}
}
void prep_dff(RTLIL::Module *module)
void prep_dff_hier(RTLIL::Design *design)
{
auto design = module->design;
log_assert(design);
pool<IdString> seen;
dict<RTLIL::IdString, RTLIL::Selection> selection_vars;
auto r YS_ATTRIBUTE(unused) = design->selection_vars.insert(std::make_pair(ID($abc9_flops), RTLIL::Selection(false)));
log_assert(r.second);
auto r2 YS_ATTRIBUTE(unused) = design->selection_vars.insert(std::make_pair(ID($abc9_cells), RTLIL::Selection(false)));
log_assert(r2.second);
auto &modules_sel = design->selection_vars.at(ID($abc9_flops));
auto &cells_sel = design->selection_vars.at(ID($abc9_cells));
SigMap assign_map(module);
typedef SigSpec clkdomain_t;
dict<clkdomain_t, int> clk_to_mergeability;
for (auto cell : module->cells()) {
if (cell->type != ID($__ABC9_FF_))
continue;
Wire *abc9_clock_wire = module->wire(stringf("%s.clock", cell->name.c_str()));
if (abc9_clock_wire == NULL)
log_error("'%s.clock' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module));
SigSpec abc9_clock = assign_map(abc9_clock_wire);
clkdomain_t key(abc9_clock);
auto r = clk_to_mergeability.insert(std::make_pair(abc9_clock, clk_to_mergeability.size() + 1));
auto r2 = cell->attributes.insert(ID::abc9_mergeability);
log_assert(r2.second);
r2.first->second = r.first->second;
}
RTLIL::Module *holes_module = design->module(stringf("%s$holes", module->name.c_str()));
if (holes_module) {
SigMap sigmap(holes_module);
dict<SigSpec, SigSpec> replace;
for (auto cell : holes_module->cells().to_vector()) {
if (!cell->type.in(ID($_DFF_N_), ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
ID($_DFF_P_), ID($_DFF_PN0_), ID($_DFF_PN1), ID($_DFF_PP0_), ID($_DFF_PP1_)))
continue;
SigBit D = cell->getPort(ID::D);
SigBit Q = cell->getPort(ID::Q);
// Emulate async control embedded inside $_DFF_* cell with mux in front of D
if (cell->type.in(ID($_DFF_NN0_), ID($_DFF_PN0_)))
D = holes_module->MuxGate(NEW_ID, State::S0, D, cell->getPort(ID::R));
else if (cell->type.in(ID($_DFF_NN1_), ID($_DFF_PN1_)))
D = holes_module->MuxGate(NEW_ID, State::S1, D, cell->getPort(ID::R));
else if (cell->type.in(ID($_DFF_NP0_), ID($_DFF_PP0_)))
D = holes_module->MuxGate(NEW_ID, D, State::S0, cell->getPort(ID::R));
else if (cell->type.in(ID($_DFF_NP1_), ID($_DFF_PP1_)))
D = holes_module->MuxGate(NEW_ID, D, State::S1, cell->getPort(ID::R));
// Remove the $_DFF_* cell from what needs to be a combinatorial box
holes_module->remove(cell);
Wire *port;
if (GetSize(Q.wire) == 1)
port = holes_module->wire(stringf("$abc%s", Q.wire->name.c_str()));
else
port = holes_module->wire(stringf("$abc%s[%d]", Q.wire->name.c_str(), Q.offset));
log_assert(port);
// Prepare to replace "assign <port> = $_DFF_*.Q;" with "assign <port> = $_DFF_*.D;"
// in order to extract just the combinatorial control logic that feeds the box
// (i.e. clock enable, synchronous reset, etc.)
replace.insert(std::make_pair(Q,D));
// Since `flatten` above would have created wires named "<cell>.Q",
// extract the pre-techmap cell name
auto pos = Q.wire->name.str().rfind(".");
log_assert(pos != std::string::npos);
IdString driver = Q.wire->name.substr(0, pos);
// And drive the signal that was previously driven by "DFF.Q" (typically
// used to implement clock-enable functionality) with the "<cell>.$abc9_currQ"
// wire (which itself is driven an by input port) we inserted above
Wire *currQ = holes_module->wire(stringf("%s.abc9_ff.Q", driver.c_str()));
log_assert(currQ);
holes_module->connect(Q, currQ);
for (auto module : design->selected_modules())
for (auto cell : module->cells()) {
auto inst_module = design->module(cell->type);
if (inst_module && inst_module->get_bool_attribute(ID::abc9_flop)) {
modules_sel.select(inst_module);
// Derive modules for all instantiations of (* abc9_flop *)
auto derived_type = inst_module->derive(design, cell->parameters);
// And remember one representative cell (for its parameters)
if (modules_sel.selected_modules.insert(derived_type).second)
cells_sel.select(module, cell);
}
}
}
for (auto &conn : holes_module->connections_)
conn.second = replace.at(sigmap(conn.second), conn.second);
void prep_dff_map(RTLIL::Design *design)
{
for (auto module : design->modules()) {
vector<Cell*> specify_cells;
SigBit D, Q;
for (auto cell : module->cells())
if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) {
if (D != SigBit())
log_error("More than one $_DFF_[NP]_ cell found in module '%s' marked (* abc9_flop *)\n", log_id(module));
D = cell->getPort(ID::D);
Q = cell->getPort(ID::Q);
// TODO: Can we avoid doing this?
// Convert (* init *) on $_DFF_[NP]_.Q to (* abc9_init *) attr on cell
log_assert(GetSize(Q.wire) == 1);
auto it = Q.wire->attributes.find(ID::init);
Const init;
if (it != Q.wire->attributes.end()) {
log_assert(GetSize(it->second) == 1);
init = it->second;
Q.wire->attributes.erase(it);
}
else
init = State::Sx;
auto r YS_ATTRIBUTE(unused) = cell->attributes.insert(std::make_pair(ID::abc9_init, init));
log_assert(r.second);
if (init == State::S1) {
log_warning("Module '%s' contains a %s cell with non-zero initial state -- this is not unsupported for ABC9 sequential synthesis. Treating as a blackbox.\n", log_id(module), log_id(cell->type));
module->makeblackbox();
auto wire = module->addWire(ID(_TECHMAP_FAIL_));
wire->set_bool_attribute(ID::keep);
module->connect(wire, State::S1);
goto continue_outer_loop;
}
}
else if (cell->type.in(ID($specify2), ID($specify3), ID($specrule)))
specify_cells.emplace_back(cell);
if (D == SigBit())
log_error("$_DFF_[NP]_ cell not found in module '%s' marked (* abc9_flop *)\n", log_id(module));
// Rewrite $specify cells that end with $_DFF_[NP]_.Q
// to $_DFF_[NP]_.D since it will be moved into
// the submodule
for (auto cell : specify_cells) {
auto DST = cell->getPort(ID::DST);
DST.replace(Q, D);
cell->setPort(ID::DST, DST);
}
continue_outer_loop: ;
}
}
void prep_dff_unmap(RTLIL::Design *design)
{
dict<IdString,Cell*> derived_to_cell;
const auto &cells_sel = design->selection_vars.at(ID($abc9_cells));
for (auto &i : cells_sel.selected_members) {
auto module = design->module(i.first);
for (auto cell_name : i.second) {
auto cell = module->cell(cell_name);
log_assert(cell);
auto inst_module = design->module(cell->type);
log_assert(inst_module);
auto derived_type = inst_module->derive(design, cell->parameters);
derived_to_cell.insert(std::make_pair(derived_type, cell));
}
}
Design *unmap_design = new Design;
// Create the reverse techmap rule -- (* abc9_box *) back to flop
for (const auto &i : derived_to_cell) {
auto module_name = i.first;
auto flop_module = design->module(module_name.str() + "_$abc9_flop");
if (!flop_module)
continue; // May not exist if init = 1'b1
auto unmap_module = unmap_design->addModule(flop_module->name);
for (auto port : flop_module->ports)
unmap_module->addWire(port, flop_module->wire(port));
unmap_module->ports = flop_module->ports;
unmap_module->check();
auto orig_cell = i.second;
auto unmap_cell = unmap_module->addCell(ID::_TECHMAP_REPLACE_, orig_cell->type);
for (const auto &conn : orig_cell->connections())
unmap_cell->setPort(conn.first, unmap_module->wire(conn.first));
unmap_cell->parameters = orig_cell->parameters;
}
auto r YS_ATTRIBUTE(unused) = saved_designs.emplace("$abc9_unmap", unmap_design);
log_assert(r.second);
}
void prep_xaiger(RTLIL::Module *module, bool dff)
{
auto design = module->design;
@ -208,17 +254,17 @@ void prep_xaiger(RTLIL::Module *module, bool dff)
dict<IdString, std::vector<IdString>> box_ports;
for (auto cell : module->cells()) {
if (cell->type == ID($__ABC9_FF_))
if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_)))
continue;
if (cell->has_keep_attr())
continue;
auto inst_module = module->design->module(cell->type);
auto inst_module = design->module(cell->type);
bool abc9_flop = inst_module && inst_module->get_bool_attribute(ID::abc9_flop);
if (abc9_flop && !dff)
continue;
if ((inst_module && inst_module->get_bool_attribute(ID::abc9_box)) || abc9_flop) {
if (inst_module && inst_module->get_bool_attribute(ID::abc9_box)) {
auto r = box_ports.insert(cell->type);
if (r.second) {
// Make carry in the last PI, and carry out the last PO
@ -305,15 +351,16 @@ void prep_xaiger(RTLIL::Module *module, bool dff)
cell->attributes[ID::abc9_box_seq] = box_count++;
IdString derived_type = box_module->derive(design, cell->parameters);
IdString derived_type;
if (cell->parameters.empty())
derived_type = cell->type;
else
derived_type = box_module->derive(design, cell->parameters);
box_module = design->module(derived_type);
auto r = cell_cache.insert(derived_type);
auto &holes_cell = r.first->second;
if (r.second) {
if (box_module->has_processes())
Pass::call_on_module(design, box_module, "proc");
if (box_module->get_bool_attribute(ID::whitebox)) {
holes_cell = holes_module->addCell(cell->name, derived_type);
@ -342,21 +389,6 @@ void prep_xaiger(RTLIL::Module *module, bool dff)
else if (w->port_output)
conn = holes_module->addWire(stringf("%s.%s", derived_type.c_str(), log_id(port_name)), GetSize(w));
}
// For flops only, create an extra 1-bit input that drives a new wire
// called "<cell>.abc9_ff.Q" that is used below
if (box_module->get_bool_attribute(ID::abc9_flop)) {
box_inputs++;
Wire *holes_wire = holes_module->wire(stringf("\\i%d", box_inputs));
if (!holes_wire) {
holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs));
holes_wire->port_input = true;
holes_wire->port_id = port_id++;
holes_module->ports.push_back(holes_wire->name);
}
Wire *Q = holes_module->addWire(stringf("%s.abc9_ff.Q", cell->name.c_str()));
holes_module->connect(Q, holes_wire);
}
}
else // box_module is a blackbox
log_assert(holes_cell == nullptr);
@ -394,7 +426,7 @@ void prep_delays(RTLIL::Design *design, bool dff_mode)
}
for (auto cell : module->cells()) {
if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_), ID($__ABC9_DELAY)))
if (cell->type.in(ID($_AND_), ID($_NOT_), ID($_DFF_N_), ID($_DFF_P_), ID($__ABC9_DELAY)))
continue;
RTLIL::Module* inst_module = module->design->module(cell->type);
@ -540,7 +572,7 @@ void write_lut(RTLIL::Module *module, const std::string &dst) {
ofs.close();
}
void prep_box(RTLIL::Design *design, bool dff_mode)
void prep_box(RTLIL::Design *design)
{
TimingInfo timing;
@ -555,165 +587,153 @@ void prep_box(RTLIL::Design *design, bool dff_mode)
dict<IdString,std::vector<IdString>> box_ports;
for (auto module : design->modules()) {
auto abc9_flop = module->get_bool_attribute(ID::abc9_flop);
if (abc9_flop) {
auto r = module->attributes.insert(ID::abc9_box_id);
if (!r.second)
continue;
r.first->second = abc9_box_id++;
if (!module->attributes.erase(ID::abc9_box))
continue;
if (dff_mode) {
int num_inputs = 0, num_outputs = 0;
for (auto port_name : module->ports) {
auto wire = module->wire(port_name);
log_assert(GetSize(wire) == 1);
if (wire->port_input) num_inputs++;
if (wire->port_output) num_outputs++;
}
log_assert(num_outputs == 1);
auto r = module->attributes.insert(ID::abc9_box_id);
if (!r.second)
continue;
r.first->second = abc9_box_id++;
ss << log_id(module) << " " << r.first->second.as_int();
ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0");
ss << " " << num_inputs+1 << " " << num_outputs << std::endl;
if (module->get_bool_attribute(ID::abc9_flop)) {
int num_inputs = 0, num_outputs = 0;
for (auto port_name : module->ports) {
auto wire = module->wire(port_name);
log_assert(GetSize(wire) == 1);
if (wire->port_input) num_inputs++;
if (wire->port_output) num_outputs++;
}
log_assert(num_outputs == 1);
ss << "#";
bool first = true;
for (auto port_name : module->ports) {
auto wire = module->wire(port_name);
if (!wire->port_input)
continue;
if (first)
first = false;
else
ss << " ";
ss << log_id(wire);
}
ss << " abc9_ff.Q" << std::endl;
ss << log_id(module) << " " << r.first->second.as_int();
ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0");
ss << " " << num_inputs << " " << num_outputs << std::endl;
auto &t = timing.setup_module(module).required;
first = true;
for (auto port_name : module->ports) {
auto wire = module->wire(port_name);
if (!wire->port_input)
continue;
if (first)
first = false;
else
ss << " ";
log_assert(GetSize(wire) == 1);
auto it = t.find(TimingInfo::NameBit(port_name,0));
if (it == t.end())
// Assume that no setup time means zero
ss << 0;
else {
ss << it->second;
ss << "#";
bool first = true;
for (auto port_name : module->ports) {
auto wire = module->wire(port_name);
if (!wire->port_input)
continue;
if (first)
first = false;
else
ss << " ";
ss << log_id(wire);
}
ss << std::endl;
auto &t = timing.setup_module(module).required;
first = true;
for (auto port_name : module->ports) {
auto wire = module->wire(port_name);
if (!wire->port_input)
continue;
if (first)
first = false;
else
ss << " ";
log_assert(GetSize(wire) == 1);
auto it = t.find(TimingInfo::NameBit(port_name,0));
if (it == t.end())
// Assume that no setup time means zero
ss << 0;
else {
ss << it->second;
#ifndef NDEBUG
if (ys_debug(1)) {
static std::set<std::pair<IdString,IdString>> seen;
if (seen.emplace(module->name, port_name).second) log("%s.%s abc9_required = %d\n", log_id(module),
log_id(port_name), it->second);
}
#endif
if (ys_debug(1)) {
static std::set<std::pair<IdString,IdString>> seen;
if (seen.emplace(module->name, port_name).second) log("%s.%s abc9_required = %d\n", log_id(module),
log_id(port_name), it->second);
}
#endif
}
// Last input is 'abc9_ff.Q'
ss << " 0" << std::endl << std::endl;
continue;
}
ss << " # $_DFF_[NP]_.D" << std::endl;
ss << std::endl;
}
else {
if (!module->attributes.erase(ID::abc9_box))
continue;
auto r = module->attributes.insert(ID::abc9_box_id);
if (!r.second)
continue;
r.first->second = abc9_box_id++;
}
auto r = box_ports.insert(module->name);
if (r.second) {
// Make carry in the last PI, and carry out the last PO
// since ABC requires it this way
IdString carry_in, carry_out;
for (const auto &port_name : module->ports) {
auto w = module->wire(port_name);
log_assert(w);
if (w->get_bool_attribute(ID::abc9_carry)) {
log_assert(w->port_input != w->port_output);
if (w->port_input)
carry_in = port_name;
else if (w->port_output)
carry_out = port_name;
auto r2 = box_ports.insert(module->name);
if (r2.second) {
// Make carry in the last PI, and carry out the last PO
// since ABC requires it this way
IdString carry_in, carry_out;
for (const auto &port_name : module->ports) {
auto w = module->wire(port_name);
log_assert(w);
if (w->get_bool_attribute(ID::abc9_carry)) {
log_assert(w->port_input != w->port_output);
if (w->port_input)
carry_in = port_name;
else if (w->port_output)
carry_out = port_name;
}
else
r2.first->second.push_back(port_name);
}
if (carry_in != IdString()) {
r2.first->second.push_back(carry_in);
r2.first->second.push_back(carry_out);
}
else
r.first->second.push_back(port_name);
}
if (carry_in != IdString()) {
r.first->second.push_back(carry_in);
r.first->second.push_back(carry_out);
std::vector<SigBit> inputs, outputs;
for (auto port_name : r2.first->second) {
auto wire = module->wire(port_name);
if (wire->port_input)
for (int i = 0; i < GetSize(wire); i++)
inputs.emplace_back(wire, i);
if (wire->port_output)
for (int i = 0; i < GetSize(wire); i++)
outputs.emplace_back(wire, i);
}
}
std::vector<SigBit> inputs;
std::vector<SigBit> outputs;
for (auto port_name : r.first->second) {
auto wire = module->wire(port_name);
if (wire->port_input)
for (int i = 0; i < GetSize(wire); i++)
inputs.emplace_back(wire, i);
if (wire->port_output)
for (int i = 0; i < GetSize(wire); i++)
outputs.emplace_back(wire, i);
}
ss << log_id(module) << " " << module->attributes.at(ID::abc9_box_id).as_int();
ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0");
ss << " " << GetSize(inputs) << " " << GetSize(outputs) << std::endl;
ss << log_id(module) << " " << module->attributes.at(ID::abc9_box_id).as_int();
ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0");
ss << " " << GetSize(inputs) << " " << GetSize(outputs) << std::endl;
bool first = true;
ss << "#";
for (const auto &i : inputs) {
if (first)
first = false;
else
ss << " ";
if (GetSize(i.wire) == 1)
ss << log_id(i.wire);
else
ss << log_id(i.wire) << "[" << i.offset << "]";
}
ss << std::endl;
auto &t = timing.setup_module(module).comb;
if (!abc9_flop && t.empty())
log_warning("(* abc9_box *) module '%s' has no timing (and thus no connectivity) information.\n", log_id(module));
for (const auto &o : outputs) {
first = true;
bool first = true;
ss << "#";
for (const auto &i : inputs) {
if (first)
first = false;
else
ss << " ";
auto jt = t.find(TimingInfo::BitBit(i,o));
if (jt == t.end())
ss << "-";
if (GetSize(i.wire) == 1)
ss << log_id(i.wire);
else
ss << jt->second;
ss << log_id(i.wire) << "[" << i.offset << "]";
}
ss << " # ";
if (GetSize(o.wire) == 1)
ss << log_id(o.wire);
else
ss << log_id(o.wire) << "[" << o.offset << "]";
ss << std::endl;
auto &t = timing.setup_module(module).comb;
if (t.empty())
log_warning("(* abc9_box *) module '%s' has no timing (and thus no connectivity) information.\n", log_id(module));
for (const auto &o : outputs) {
first = true;
for (const auto &i : inputs) {
if (first)
first = false;
else
ss << " ";
auto jt = t.find(TimingInfo::BitBit(i,o));
if (jt == t.end())
ss << "-";
else
ss << jt->second;
}
ss << " # ";
if (GetSize(o.wire) == 1)
ss << log_id(o.wire);
else
ss << log_id(o.wire) << "[" << o.offset << "]";
ss << std::endl;
}
ss << std::endl;
}
ss << std::endl;
}
// ABC expects at least one box
@ -730,7 +750,7 @@ void write_box(RTLIL::Module *module, const std::string &dst) {
ofs.close();
}
void reintegrate(RTLIL::Module *module)
void reintegrate(RTLIL::Module *module, bool dff_mode)
{
auto design = module->design;
log_assert(design);
@ -783,7 +803,12 @@ void reintegrate(RTLIL::Module *module)
for (auto cell : module->cells().to_vector()) {
if (cell->has_keep_attr())
continue;
if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_)))
if (dff_mode && cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) {
module->connect(cell->getPort(ID::Q), cell->getPort(ID::D));
module->remove(cell);
}
else if (cell->type.in(ID($_AND_), ID($_NOT_)))
module->remove(cell);
else if (cell->attributes.erase(ID::abc9_box_seq))
boxes.emplace_back(cell);
@ -797,6 +822,16 @@ void reintegrate(RTLIL::Module *module)
std::map<IdString, int> cell_stats;
for (auto mapped_cell : mapped_mod->cells())
{
if (dff_mode && mapped_cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) {
SigBit D = mapped_cell->getPort(ID::D);
SigBit Q = mapped_cell->getPort(ID::Q);
if (D.wire)
D.wire = module->wires_.at(remap_name(D.wire->name));
Q.wire = module->wires_.at(remap_name(Q.wire->name));
module->connect(Q, D);
continue;
}
// TODO: Speed up toposort -- we care about NOT ordering only
toposort.node(mapped_cell->name);
@ -846,7 +881,7 @@ void reintegrate(RTLIL::Module *module)
continue;
}
if (mapped_cell->type.in(ID($lut), ID($__ABC9_FF_))) {
if (mapped_cell->type == ID($lut)) {
RTLIL::Cell *cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type);
cell->parameters = mapped_cell->parameters;
cell->attributes = mapped_cell->attributes;
@ -893,7 +928,11 @@ void reintegrate(RTLIL::Module *module)
}
RTLIL::Module* box_module = design->module(existing_cell->type);
IdString derived_type = box_module->derive(design, existing_cell->parameters);
IdString derived_type;
if (existing_cell->parameters.empty())
derived_type = existing_cell->type;
else
derived_type = box_module->derive(design, existing_cell->parameters);
RTLIL::Module* derived_module = design->module(derived_type);
log_assert(derived_module);
log_assert(mapped_cell->type == stringf("$__boxid%d", derived_module->attributes.at(ID::abc9_box_id).as_int()));
@ -1116,6 +1155,21 @@ struct Abc9OpsPass : public Pass {
log(" check that the design is valid, e.g. (* abc9_box_id *) values are unique,\n");
log(" (* abc9_carry *) is only given for one input/output port, etc.\n");
log("\n");
log(" -prep_dff_hier\n");
log(" derive all cells with a type instantiating an (* abc9_flop *) module.\n");
log(" store such modules in named selection '$abc9_flops'.\n");
log("\n");
log(" -prep_dff_map\n");
log(" within (* abc9_flop *) modules, move all $specify{2,3}/$specrule cells\n");
log(" that share a 'DST' port with the $_DFF_[NP]_.Q port from this 'Q' port to\n");
log(" the DFF's 'D' port. this is to prepare such specify cells to be moved into\n");
log(" a submodule.\n");
log("\n");
log(" -prep_dff_unmap\n");
log(" create a new design '$abc9_unmap' containing techmap rules that map\n");
log(" *_$abc9_flop cells back into their original (* abc9_flop *) cells\n");
log(" (including their original parameters).\n");
log("\n");
log(" -prep_delays\n");
log(" insert `$__ABC9_DELAY' blackbox cells into the design to account for\n");
log(" certain required times.\n");
@ -1136,10 +1190,6 @@ struct Abc9OpsPass : public Pass {
log(" consider flop cells (those instantiating modules marked with (* abc9_flop *))\n");
log(" during -prep_{delays,xaiger,box}.\n");
log("\n");
log(" -prep_dff\n");
log(" compute the clock domain and initial value of each flop in the design.\n");
log(" process the '$holes' module to support clock-enable functionality.\n");
log("\n");
log(" -prep_lut <maxlut>\n");
log(" pre-compute the lut library by analysing all modules marked with\n");
log(" (* abc9_lut=<area> *).\n");
@ -1167,7 +1217,7 @@ struct Abc9OpsPass : public Pass {
bool check_mode = false;
bool prep_delays_mode = false;
bool mark_scc_mode = false;
bool prep_dff_mode = false;
bool prep_dff_hier_mode = false, prep_dff_map_mode = false, prep_dff_unmap_mode = false;
bool prep_xaiger_mode = false;
bool prep_lut_mode = false;
bool prep_box_mode = false;
@ -1177,53 +1227,71 @@ struct Abc9OpsPass : public Pass {
int maxlut = 0;
std::string write_box_dst;
bool valid = false;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
std::string arg = args[argidx];
if (arg == "-check") {
check_mode = true;
valid = true;
continue;
}
if (arg == "-mark_scc") {
mark_scc_mode = true;
valid = true;
continue;
}
if (arg == "-prep_dff") {
prep_dff_mode = true;
if (arg == "-prep_dff_hier") {
prep_dff_hier_mode = true;
valid = true;
continue;
}
if (arg == "-prep_dff_map") {
prep_dff_map_mode = true;
valid = true;
continue;
}
if (arg == "-prep_dff_unmap") {
prep_dff_unmap_mode = true;
valid = true;
continue;
}
if (arg == "-prep_xaiger") {
prep_xaiger_mode = true;
valid = true;
continue;
}
if (arg == "-prep_delays") {
prep_delays_mode = true;
valid = true;
continue;
}
if (arg == "-prep_lut" && argidx+1 < args.size()) {
prep_lut_mode = true;
maxlut = atoi(args[++argidx].c_str());
continue;
}
if (arg == "-maxlut" && argidx+1 < args.size()) {
valid = true;
continue;
}
if (arg == "-write_lut" && argidx+1 < args.size()) {
write_lut_dst = args[++argidx];
rewrite_filename(write_lut_dst);
valid = true;
continue;
}
if (arg == "-prep_box") {
prep_box_mode = true;
valid = true;
continue;
}
if (arg == "-write_box" && argidx+1 < args.size()) {
write_box_dst = args[++argidx];
rewrite_filename(write_box_dst);
valid = true;
continue;
}
if (arg == "-reintegrate") {
reintegrate_mode = true;
valid = true;
continue;
}
if (arg == "-dff") {
@ -1234,20 +1302,26 @@ struct Abc9OpsPass : public Pass {
}
extra_args(args, argidx, design);
if (!(check_mode || mark_scc_mode || prep_delays_mode || prep_xaiger_mode || prep_dff_mode || prep_lut_mode || prep_box_mode || !write_lut_dst.empty() || !write_box_dst.empty() || reintegrate_mode))
log_cmd_error("At least one of -check, -mark_scc, -prep_{delays,xaiger,dff,lut,box}, -write_{lut,box}, -reintegrate must be specified.\n");
if (!valid)
log_cmd_error("At least one of -check, -mark_scc, -prep_{delays,xaiger,dff[123],lut,box}, -write_{lut,box}, -reintegrate must be specified.\n");
if (dff_mode && !prep_delays_mode && !prep_xaiger_mode && !prep_box_mode)
log_cmd_error("'-dff' option is only relevant for -prep_{delay,xaiger,box}.\n");
if (dff_mode && !prep_delays_mode && !prep_xaiger_mode && !reintegrate_mode)
log_cmd_error("'-dff' option is only relevant for -prep_{delay,xaiger} or -reintegrate.\n");
if (check_mode)
check(design);
if (prep_dff_hier_mode)
prep_dff_hier(design);
if (prep_dff_map_mode)
prep_dff_map(design);
if (prep_dff_unmap_mode)
prep_dff_unmap(design);
if (prep_delays_mode)
prep_delays(design, dff_mode);
if (prep_lut_mode)
prep_lut(design, maxlut);
if (prep_box_mode)
prep_box(design, dff_mode);
prep_box(design);
for (auto mod : design->selected_modules()) {
if (mod->get_bool_attribute(ID::abc9_holes))
@ -1267,12 +1341,10 @@ struct Abc9OpsPass : public Pass {
write_box(mod, write_box_dst);
if (mark_scc_mode)
mark_scc(mod);
if (prep_dff_mode)
prep_dff(mod);
if (prep_xaiger_mode)
prep_xaiger(mod, dff_mode);
if (reintegrate_mode)
reintegrate(mod);
reintegrate(mod, dff_mode);
}
}
} Abc9OpsPass;

View File

@ -1,6 +1,3 @@
module \$__ABC9_FF_ (input D, output Q);
endmodule
(* abc9_box *)
module \$__ABC9_DELAY (input I, output O);
parameter DELAY = 0;

View File

@ -22,360 +22,6 @@
// before invoking the `abc9` pass in order to transform the design into
// a format that it understands.
`ifdef DFF_MODE
// For example, (complex) flip-flops are expected to be described as an
// combinatorial box (containing all control logic such as clock enable
// or synchronous resets) followed by a basic D-Q flop.
// Yosys will automatically analyse the simulation model (described in
// cells_sim.v) and detach any $_DFF_P_ or $_DFF_N_ cells present in
// order to extract the combinatorial control logic left behind.
// Specifically, a simulation model similar to the one below:
//
// ++===================================++
// || Sim model ||
// || /\/\/\/\ ||
// D -->>-----< > +------+ ||
// R -->>-----< Comb. > |$_DFF_| ||
// CE -->>-----< logic >-----| [NP]_|---+---->>-- Q
// || +--< > +------+ | ||
// || | \/\/\/\/ | ||
// || | | ||
// || +----------------------------+ ||
// || ||
// ++===================================++
//
// is transformed into:
//
// ++==================++
// || Comb box ||
// || ||
// || /\/\/\/\ ||
// D -->>-----< > ||
// R -->>-----< Comb. > || +-----------+
// CE -->>-----< logic >--->>-- $Q --|$__ABC9_FF_|--+-->> Q
// abc9_ff.Q +-->>-----< > || +-----------+ |
// | || \/\/\/\/ || |
// | || || |
// | ++==================++ |
// | |
// +-----------------------------------------------+
//
// The purpose of the following FD* rules are to wrap the flop with:
// (a) a special $__ABC9_FF_ in front of the FD*'s output, indicating to abc9
// the connectivity of its basic D-Q flop
// (b) an optional $__ABC9_ASYNC_ cell in front of $__ABC_FF_'s output to
// capture asynchronous behaviour
// (c) a special abc9_ff.clock wire to capture its clock domain and polarity
// (indicated to `abc9' so that it only performs sequential synthesis
// (with reachability analysis) correctly on one domain at a time)
// (d) an (* abc9_init *) attribute on the $__ABC9_FF_ cell capturing its
// initial state
// NOTE: in order to perform sequential synthesis, `abc9' requires that
// the initial value of all flops be zero
// (e) a special _TECHMAP_REPLACE_.abc9_ff.Q wire that will be used for feedback
// into the (combinatorial) FD* cell to facilitate clock-enable behaviour
module FDRE (output Q, (* techmap_autopurge *) input C, CE, D, R);
parameter [0:0] INIT = 1'b0;
parameter [0:0] IS_C_INVERTED = 1'b0;
parameter [0:0] IS_D_INVERTED = 1'b0;
parameter [0:0] IS_R_INVERTED = 1'b0;
wire QQ, $Q;
generate if (INIT == 1'b1) begin
assign Q = ~QQ;
FDSE #(
.INIT(1'b0),
.IS_C_INVERTED(IS_C_INVERTED),
.IS_D_INVERTED(IS_D_INVERTED),
.IS_S_INVERTED(IS_R_INVERTED)
) _TECHMAP_REPLACE_ (
.D(~D), .Q($Q), .C(C), .CE(CE), .S(R)
);
end
else begin
assign Q = QQ;
FDRE #(
.INIT(1'b0),
.IS_C_INVERTED(IS_C_INVERTED),
.IS_D_INVERTED(IS_D_INVERTED),
.IS_R_INVERTED(IS_R_INVERTED)
) _TECHMAP_REPLACE_ (
.D(D), .Q($Q), .C(C), .CE(CE), .R(R)
);
end
endgenerate
(* abc9_init = 1'b0 *)
$__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ));
// Special signals
wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED};
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ;
endmodule
module FDRE_1 (output Q, (* techmap_autopurge *) input C, CE, D, R);
parameter [0:0] INIT = 1'b0;
wire QQ, $Q;
generate if (INIT == 1'b1) begin
assign Q = ~QQ;
FDSE_1 #(
.INIT(1'b0)
) _TECHMAP_REPLACE_ (
.D(~D), .Q($Q), .C(C), .CE(CE), .S(R)
);
end
else begin
assign Q = QQ;
FDRE_1 #(
.INIT(1'b0)
) _TECHMAP_REPLACE_ (
.D(D), .Q($Q), .C(C), .CE(CE), .R(R)
);
end
endgenerate
(* abc9_init = 1'b0 *)
$__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ));
// Special signals
wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */};
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ;
endmodule
module FDSE (output Q, (* techmap_autopurge *) input C, CE, D, S);
parameter [0:0] INIT = 1'b1;
parameter [0:0] IS_C_INVERTED = 1'b0;
parameter [0:0] IS_D_INVERTED = 1'b0;
parameter [0:0] IS_S_INVERTED = 1'b0;
wire QQ, $Q;
generate if (INIT == 1'b1) begin
assign Q = ~QQ;
FDRE #(
.INIT(1'b0),
.IS_C_INVERTED(IS_C_INVERTED),
.IS_D_INVERTED(IS_D_INVERTED),
.IS_R_INVERTED(IS_S_INVERTED)
) _TECHMAP_REPLACE_ (
.D(~D), .Q($Q), .C(C), .CE(CE), .R(S)
);
end
else begin
assign Q = QQ;
FDSE #(
.INIT(1'b0),
.IS_C_INVERTED(IS_C_INVERTED),
.IS_D_INVERTED(IS_D_INVERTED),
.IS_S_INVERTED(IS_S_INVERTED)
) _TECHMAP_REPLACE_ (
.D(D), .Q($Q), .C(C), .CE(CE), .S(S)
);
end endgenerate
(* abc9_init = 1'b0 *)
$__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ));
// Special signals
wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED};
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ;
endmodule
module FDSE_1 (output Q, (* techmap_autopurge *) input C, CE, D, S);
parameter [0:0] INIT = 1'b1;
wire QQ, $Q;
generate if (INIT == 1'b1) begin
assign Q = ~QQ;
FDRE_1 #(
.INIT(1'b0)
) _TECHMAP_REPLACE_ (
.D(~D), .Q($Q), .C(C), .CE(CE), .R(S)
);
end
else begin
assign Q = QQ;
FDSE_1 #(
.INIT(1'b0)
) _TECHMAP_REPLACE_ (
.D(D), .Q($Q), .C(C), .CE(CE), .S(S)
);
end endgenerate
(* abc9_init = 1'b0 *)
$__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ));
// Special signals
wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */};
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ;
endmodule
module FDCE (output Q, (* techmap_autopurge *) input C, CE, D, CLR);
parameter [0:0] INIT = 1'b0;
parameter [0:0] IS_C_INVERTED = 1'b0;
parameter [0:0] IS_D_INVERTED = 1'b0;
parameter [0:0] IS_CLR_INVERTED = 1'b0;
wire QQ, $Q, $QQ;
generate if (INIT == 1'b1) begin
assign Q = ~QQ;
FDPE #(
.INIT(1'b0),
.IS_C_INVERTED(IS_C_INVERTED),
.IS_D_INVERTED(IS_D_INVERTED),
.IS_PRE_INVERTED(IS_CLR_INVERTED)
) _TECHMAP_REPLACE_ (
.D(~D), .Q($Q), .C(C), .CE(CE), .PRE(CLR)
// ^^^ Note that async
// control is not directly
// supported by abc9 but its
// behaviour is captured by
// $__ABC9_ASYNC1 below
);
// Since this is an async flop, async behaviour is dealt with here
$__ABC9_ASYNC1 abc_async (.A($QQ), .S(CLR ^ IS_CLR_INVERTED), .Y(QQ));
end
else begin
assign Q = QQ;
FDCE #(
.INIT(1'b0),
.IS_C_INVERTED(IS_C_INVERTED),
.IS_D_INVERTED(IS_D_INVERTED),
.IS_CLR_INVERTED(IS_CLR_INVERTED)
) _TECHMAP_REPLACE_ (
.D(D), .Q($Q), .C(C), .CE(CE), .CLR(CLR)
// ^^^ Note that async
// control is not directly
// supported by abc9 but its
// behaviour is captured by
// $__ABC9_ASYNC0 below
);
// Since this is an async flop, async behaviour is dealt with here
$__ABC9_ASYNC0 abc_async (.A($QQ), .S(CLR ^ IS_CLR_INVERTED), .Y(QQ));
end endgenerate
(* abc9_init = 1'b0 *)
$__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ));
// Special signals
wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED};
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ;
endmodule
module FDCE_1 (output Q, (* techmap_autopurge *) input C, CE, D, CLR);
parameter [0:0] INIT = 1'b0;
wire QQ, $Q, $QQ;
generate if (INIT == 1'b1) begin
assign Q = ~QQ;
FDPE_1 #(
.INIT(1'b0)
) _TECHMAP_REPLACE_ (
.D(~D), .Q($Q), .C(C), .CE(CE), .PRE(CLR)
// ^^^ Note that async
// control is not directly
// supported by abc9 but its
// behaviour is captured by
// $__ABC9_ASYNC1 below
);
$__ABC9_ASYNC1 abc_async (.A($QQ), .S(CLR), .Y(QQ));
end
else begin
assign Q = QQ;
FDCE_1 #(
.INIT(1'b0)
) _TECHMAP_REPLACE_ (
.D(D), .Q($Q), .C(C), .CE(CE), .CLR(CLR)
// ^^^ Note that async
// control is not directly
// supported by abc9 but its
// behaviour is captured by
// $__ABC9_ASYNC0 below
);
$__ABC9_ASYNC0 abc_async (.A($QQ), .S(CLR), .Y(QQ));
end endgenerate
(* abc9_init = 1'b0 *)
$__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ));
// Special signals
wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */};
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ;
endmodule
module FDPE (output Q, (* techmap_autopurge *) input C, CE, D, PRE);
parameter [0:0] INIT = 1'b1;
parameter [0:0] IS_C_INVERTED = 1'b0;
parameter [0:0] IS_D_INVERTED = 1'b0;
parameter [0:0] IS_PRE_INVERTED = 1'b0;
wire QQ, $Q, $QQ;
generate if (INIT == 1'b1) begin
assign Q = ~QQ;
FDCE #(
.INIT(1'b0),
.IS_C_INVERTED(IS_C_INVERTED),
.IS_D_INVERTED(IS_D_INVERTED),
.IS_CLR_INVERTED(IS_PRE_INVERTED),
) _TECHMAP_REPLACE_ (
.D(~D), .Q($Q), .C(C), .CE(CE), .CLR(PRE)
// ^^^ Note that async
// control is not directly
// supported by abc9 but its
// behaviour is captured by
// $__ABC9_ASYNC0 below
);
$__ABC9_ASYNC0 abc_async (.A($QQ), .S(PRE ^ IS_PRE_INVERTED), .Y(QQ));
end
else begin
assign Q = QQ;
FDPE #(
.INIT(1'b0),
.IS_C_INVERTED(IS_C_INVERTED),
.IS_D_INVERTED(IS_D_INVERTED),
.IS_PRE_INVERTED(IS_PRE_INVERTED),
) _TECHMAP_REPLACE_ (
.D(D), .Q($Q), .C(C), .CE(CE), .PRE(PRE)
// ^^^ Note that async
// control is not directly
// supported by abc9 but its
// behaviour is captured by
// $__ABC9_ASYNC1 below
);
$__ABC9_ASYNC1 abc_async (.A($QQ), .S(PRE ^ IS_PRE_INVERTED), .Y(QQ));
end endgenerate
(* abc9_init = 1'b0 *)
$__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ));
// Special signals
wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED};
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ;
endmodule
module FDPE_1 (output Q, (* techmap_autopurge *) input C, CE, D, PRE);
parameter [0:0] INIT = 1'b1;
wire QQ, $Q, $QQ;
generate if (INIT == 1'b1) begin
assign Q = ~QQ;
FDCE_1 #(
.INIT(1'b0)
) _TECHMAP_REPLACE_ (
.D(~D), .Q($Q), .C(C), .CE(CE), .CLR(PRE)
// ^^^ Note that async
// control is not directly
// supported by abc9 but its
// behaviour is captured by
// $__ABC9_ASYNC0 below
);
$__ABC9_ASYNC0 abc_async (.A($QQ), .S(PRE), .Y(QQ));
end
else begin
assign Q = QQ;
FDPE_1 #(
.INIT(1'b0)
) _TECHMAP_REPLACE_ (
.D(D), .Q($Q), .C(C), .CE(CE), .PRE(PRE)
// ^^^ Note that async
// control is not directly
// supported by abc9 but its
// behaviour is captured by
// $__ABC9_ASYNC1 below
);
$__ABC9_ASYNC1 abc_async (.A($QQ), .S(PRE), .Y(QQ));
end endgenerate
(* abc9_init = 1'b0 *)
$__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ));
// Special signals
wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */};
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ;
endmodule
`endif
// Attach a (combinatorial) black-box onto the output
// of thes LUTRAM primitives to capture their
// asynchronous read behaviour

View File

@ -25,10 +25,6 @@ module $__ABC9_ASYNC01(input A, S, output Y);
assign Y = A;
endmodule
module $__ABC9_FF_(input D, output Q);
assign Q = D;
endmodule
module $__ABC9_RAM6(input A, input [5:0] S, output Y);
assign Y = A;
endmodule

View File

@ -640,7 +640,7 @@ module FDRSE (
Q <= d;
endmodule
(* abc9_flop, lib_whitebox *)
(* lib_whitebox *)
module FDCE (
output reg Q,
(* clkbuf_sink *)
@ -683,7 +683,7 @@ module FDCE (
endspecify
endmodule
(* abc9_flop, lib_whitebox *)
(* lib_whitebox *)
module FDCE_1 (
output reg Q,
(* clkbuf_sink *)
@ -708,7 +708,7 @@ module FDCE_1 (
endspecify
endmodule
(* abc9_flop, lib_whitebox *)
(* lib_whitebox *)
module FDPE (
output reg Q,
(* clkbuf_sink *)
@ -750,7 +750,7 @@ module FDPE (
endspecify
endmodule
(* abc9_flop, lib_whitebox *)
(* lib_whitebox *)
module FDPE_1 (
output reg Q,
(* clkbuf_sink *)

View File

@ -613,10 +613,7 @@ struct SynthXilinxPass : public ScriptPass
if (family != "xc7")
log_warning("'synth_xilinx -abc9' not currently supported for the '%s' family, "
"will use timing for 'xc7' instead.\n", family.c_str());
std::string techmap_args = "-map +/xilinx/abc9_map.v -max_iter 1";
if (dff_mode)
techmap_args += " -D DFF_MODE";
run("techmap " + techmap_args);
run("techmap -map +/xilinx/abc9_map.v -max_iter 1");
run("read_verilog -icells -lib -specify +/abc9_model.v +/xilinx/abc9_model.v");
std::string abc9_opts;
std::string k = "synth_xilinx.abc9.W";