Merge remote-tracking branch 'origin/xaig_dff' into eddie/abc9_refactor

This commit is contained in:
Eddie Hung 2019-12-30 16:20:58 -08:00
commit 7649ec72c9
18 changed files with 1429 additions and 769 deletions

View File

@ -57,6 +57,7 @@ Yosys 0.9 .. Yosys 0.9-dev
always_latch and always_ff) always_latch and always_ff)
- Added "xilinx_dffopt" pass - Added "xilinx_dffopt" pass
- Added "scratchpad" pass - Added "scratchpad" pass
- Added "synth_xilinx -dff"
Yosys 0.8 .. Yosys 0.9 Yosys 0.8 .. Yosys 0.9
---------------------- ----------------------

View File

@ -128,7 +128,7 @@ bumpversion:
# is just a symlink to your actual ABC working directory, as 'make mrproper' # is just a symlink to your actual ABC working directory, as 'make mrproper'
# will remove the 'abc' directory and you do not want to accidentally # will remove the 'abc' directory and you do not want to accidentally
# delete your work on ABC.. # delete your work on ABC..
ABCREV = 623b5e8 ABCREV = c4b12fa
ABCPULL = 1 ABCPULL = 1
ABCURL ?= https://github.com/berkeley-abc/abc ABCURL ?= https://github.com/berkeley-abc/abc
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1

View File

@ -378,6 +378,12 @@ Verilog Attributes and non-standard features
for example, to specify the clk-to-Q delay of a flip-flop for consideration for example, to specify the clk-to-Q delay of a flip-flop for consideration
during techmapping. during techmapping.
- The module attribute ``abc9_flop`` is a boolean marking the module as a
whitebox that describes the synchronous behaviour of a flip-flop.
- The cell attribute ``abc9_keep`` is a boolean indicating that this black/
white box should be preserved through `abc9` mapping.
- The frontend sets attributes ``always_comb``, ``always_latch`` and - The frontend sets attributes ``always_comb``, ``always_latch`` and
``always_ff`` on processes derived from SystemVerilog style always blocks ``always_ff`` on processes derived from SystemVerilog style always blocks
according to the type of the always. These are checked for correctness in according to the type of the always. These are checked for correctness in

View File

@ -78,10 +78,11 @@ struct XAigerWriter
Module *module; Module *module;
SigMap sigmap; SigMap sigmap;
pool<SigBit> input_bits, output_bits; pool<SigBit> input_bits, output_bits, external_bits;
dict<SigBit, SigBit> not_map, alias_map; dict<SigBit, SigBit> not_map, alias_map;
dict<SigBit, pair<SigBit, SigBit>> and_map; dict<SigBit, pair<SigBit, SigBit>> and_map;
vector<SigBit> ci_bits, co_bits; vector<SigBit> ci_bits, co_bits;
dict<SigBit, std::pair<int,int>> ff_bits;
dict<SigBit, float> arrival_times; dict<SigBit, float> arrival_times;
vector<pair<int, int>> aig_gates; vector<pair<int, int>> aig_gates;
@ -92,7 +93,6 @@ struct XAigerWriter
dict<SigBit, int> ordered_outputs; dict<SigBit, int> ordered_outputs;
vector<Cell*> box_list; vector<Cell*> box_list;
bool omode = false;
int mkgate(int a0, int a1) int mkgate(int a0, int a1)
{ {
@ -140,7 +140,7 @@ struct XAigerWriter
{ {
pool<SigBit> undriven_bits; pool<SigBit> undriven_bits;
pool<SigBit> unused_bits; pool<SigBit> unused_bits;
pool<SigBit> keep_bits; pool<SigBit> inout_bits;
// promote public wires // promote public wires
for (auto wire : module->wires()) for (auto wire : module->wires())
@ -152,52 +152,52 @@ struct XAigerWriter
if (wire->port_input) if (wire->port_input)
sigmap.add(wire); sigmap.add(wire);
// promote keep wires
for (auto wire : module->wires()) for (auto wire : module->wires())
{ if (wire->get_bool_attribute(ID::keep))
bool keep = wire->attributes.count("\\keep"); sigmap.add(wire);
for (auto wire : module->wires())
for (int i = 0; i < GetSize(wire); i++) for (int i = 0; i < GetSize(wire); i++)
{ {
SigBit wirebit(wire, i); SigBit wirebit(wire, i);
SigBit bit = sigmap(wirebit); SigBit bit = sigmap(wirebit);
if (bit.wire) { if (bit.wire == nullptr) {
if (wire->port_output) {
aig_map[wirebit] = (bit == State::S1) ? 1 : 0;
if (holes_mode)
output_bits.insert(wirebit);
//external_bits.insert(wirebit);
}
continue;
}
undriven_bits.insert(bit); undriven_bits.insert(bit);
unused_bits.insert(bit); unused_bits.insert(bit);
}
if (keep) if (wire->port_input)
keep_bits.insert(wirebit); input_bits.insert(bit);
if (wire->port_input || keep) { if (wire->port_output) {
if (bit != wirebit)
alias_map[bit] = wirebit;
input_bits.insert(wirebit);
}
if (wire->port_output || keep) {
if (bit != RTLIL::Sx) {
if (bit != wirebit) if (bit != wirebit)
alias_map[wirebit] = bit; alias_map[wirebit] = bit;
if (holes_mode)
output_bits.insert(wirebit); output_bits.insert(wirebit);
}
else else
log_debug("Skipping PO '%s' driven by 1'bx\n", log_signal(wirebit)); external_bits.insert(wirebit);
}
}
} }
for (auto bit : input_bits) if (wire->port_input && wire->port_output)
undriven_bits.erase(sigmap(bit)); inout_bits.insert(wirebit);
for (auto bit : output_bits) }
if (!bit.wire->port_input)
unused_bits.erase(bit);
// TODO: Speed up toposort -- ultimately we care about // TODO: Speed up toposort -- ultimately we care about
// box ordering, but not individual AIG cells // box ordering, but not individual AIG cells
dict<SigBit, pool<IdString>> bit_drivers, bit_users; dict<SigBit, pool<IdString>> bit_drivers, bit_users;
TopoSort<IdString, RTLIL::sort_by_id_str> toposort; TopoSort<IdString, RTLIL::sort_by_id_str> toposort;
bool abc9_box_seen = false; bool abc9_box_seen = false;
std::vector<Cell*> flop_boxes;
for (auto cell : module->selected_cells()) { for (auto cell : module->selected_cells()) {
if (cell->type == "$_NOT_") if (cell->type == "$_NOT_")
@ -235,28 +235,60 @@ struct XAigerWriter
log_assert(!holes_mode); log_assert(!holes_mode);
RTLIL::Module* inst_module = module->design->module(cell->type); if (cell->type == "$__ABC9_FF_")
if (inst_module && inst_module->attributes.count("\\abc9_box_id")) { {
abc9_box_seen = true; SigBit D = sigmap(cell->getPort("\\D").as_bit());
SigBit Q = sigmap(cell->getPort("\\Q").as_bit());
if (!holes_mode) { unused_bits.erase(D);
toposort.node(cell->name); undriven_bits.erase(Q);
for (const auto &conn : cell->connections()) { alias_map[Q] = D;
auto port_wire = inst_module->wire(conn.first); auto r = ff_bits.insert(std::make_pair(D, std::make_pair(0, 2)));
if (port_wire->port_input) { log_assert(r.second);
// Ignore inout for the sake of topographical ordering continue;
if (port_wire->port_output) continue;
for (auto bit : sigmap(conn.second))
bit_users[bit].insert(cell->name);
} }
RTLIL::Module* inst_module = module->design->module(cell->type);
if (inst_module) {
bool abc9_box = inst_module->attributes.count("\\abc9_box_id") && !cell->get_bool_attribute("\\abc9_keep");
for (const auto &conn : cell->connections()) {
auto port_wire = inst_module->wire(conn.first);
if (port_wire->port_output) {
int arrival = 0;
auto it = port_wire->attributes.find("\\abc9_arrival");
if (it != port_wire->attributes.end()) {
if (it->second.flags != 0)
log_error("Attribute 'abc9_arrival' on port '%s' of module '%s' is not an integer.\n", log_id(port_wire), log_id(cell->type));
arrival = it->second.as_int();
}
if (arrival)
for (auto bit : sigmap(conn.second))
arrival_times[bit] = arrival;
}
if (abc9_box) {
// Ignore inout for the sake of topographical ordering
if (port_wire->port_input && !port_wire->port_output)
for (auto bit : sigmap(conn.second))
bit_users[bit].insert(cell->name);
if (port_wire->port_output) if (port_wire->port_output)
for (auto bit : sigmap(conn.second)) for (auto bit : sigmap(conn.second))
bit_drivers[bit].insert(cell->name); bit_drivers[bit].insert(cell->name);
} }
} }
if (abc9_box) {
abc9_box_seen = true;
toposort.node(cell->name);
if (inst_module->attributes.count("\\abc9_flop"))
flop_boxes.push_back(cell);
continue;
} }
else { }
bool cell_known = inst_module || cell->known(); bool cell_known = inst_module || cell->known();
for (const auto &c : cell->connections()) { for (const auto &c : cell->connections()) {
if (c.second.is_fully_const()) continue; if (c.second.is_fully_const()) continue;
@ -274,36 +306,10 @@ struct XAigerWriter
SigBit I = sigmap(b); SigBit I = sigmap(b);
if (I != b) if (I != b)
alias_map[b] = I; alias_map[b] = I;
if (holes_mode)
output_bits.insert(b); output_bits.insert(b);
unused_bits.erase(b); else
external_bits.insert(b);
if (!cell_known)
keep_bits.insert(b);
}
}
}
if (is_output) {
int arrival = 0;
if (port_wire) {
auto it = port_wire->attributes.find("\\abc9_arrival");
if (it != port_wire->attributes.end()) {
if (it->second.flags != 0)
log_error("Attribute 'abc9_arrival' on port '%s' of module '%s' is not an integer.\n", log_id(port_wire), log_id(cell->type));
arrival = it->second.as_int();
}
}
for (auto b : c.second) {
Wire *w = b.wire;
if (!w) continue;
input_bits.insert(b);
SigBit O = sigmap(b);
if (O != b)
alias_map[O] = b;
undriven_bits.erase(O);
if (arrival)
arrival_times[b] = arrival;
} }
} }
} }
@ -313,6 +319,60 @@ struct XAigerWriter
} }
if (abc9_box_seen) { if (abc9_box_seen) {
dict<IdString, std::pair<IdString,int>> flop_q;
for (auto cell : flop_boxes) {
auto r = flop_q.insert(std::make_pair(cell->type, std::make_pair(IdString(), 0)));
SigBit d;
if (r.second) {
for (const auto &conn : cell->connections()) {
const SigSpec &rhs = conn.second;
if (!rhs.is_bit())
continue;
if (!ff_bits.count(rhs))
continue;
r.first->second.first = conn.first;
Module *inst_module = module->design->module(cell->type);
Wire *wire = inst_module->wire(conn.first);
log_assert(wire);
auto jt = wire->attributes.find("\\abc9_arrival");
if (jt != wire->attributes.end()) {
if (jt->second.flags != 0)
log_error("Attribute 'abc9_arrival' on port '%s' of module '%s' is not an integer.\n", log_id(wire), log_id(cell->type));
r.first->second.second = jt->second.as_int();
}
d = rhs;
log_assert(d == sigmap(d));
break;
}
}
else
d = cell->getPort(r.first->second.first);
auto &rhs = ff_bits.at(d);
auto it = cell->attributes.find(ID(abc9_mergeability));
log_assert(it != cell->attributes.end());
rhs.first = it->second.as_int();
cell->attributes.erase(it);
it = cell->attributes.find(ID(abc9_init));
log_assert(it != cell->attributes.end());
log_assert(GetSize(it->second) == 1);
if (it->second[0] == State::S1)
rhs.second = 1;
else if (it->second[0] == State::S0)
rhs.second = 0;
else {
log_assert(it->second[0] == State::Sx);
rhs.second = 0;
}
cell->attributes.erase(it);
auto arrival = r.first->second.second;
if (arrival)
arrival_times[d] = arrival;
}
for (auto &it : bit_users) for (auto &it : bit_users)
if (bit_drivers.count(it.first)) if (bit_drivers.count(it.first))
for (auto driver_cell : bit_drivers.at(it.first)) for (auto driver_cell : bit_drivers.at(it.first))
@ -341,7 +401,8 @@ struct XAigerWriter
log_assert(cell); log_assert(cell);
RTLIL::Module* box_module = module->design->module(cell->type); RTLIL::Module* box_module = module->design->module(cell->type);
if (!box_module || !box_module->attributes.count("\\abc9_box_id")) if (!box_module || !box_module->attributes.count("\\abc9_box_id")
|| cell->get_bool_attribute("\\abc9_keep"))
continue; continue;
bool blackbox = box_module->get_blackbox_attribute(true /* ignore_wb */); bool blackbox = box_module->get_blackbox_attribute(true /* ignore_wb */);
@ -377,7 +438,7 @@ struct XAigerWriter
alias_map[b] = I; alias_map[b] = I;
} }
co_bits.emplace_back(b); co_bits.emplace_back(b);
unused_bits.erase(b); unused_bits.erase(I);
} }
} }
if (w->port_output) { if (w->port_output) {
@ -401,61 +462,74 @@ struct XAigerWriter
SigBit O = sigmap(b); SigBit O = sigmap(b);
if (O != b) if (O != b)
alias_map[O] = b; alias_map[O] = b;
input_bits.erase(O);
undriven_bits.erase(O); undriven_bits.erase(O);
input_bits.erase(b);
} }
} }
} }
// Connect <cell>.$abc9_currQ (inserted by abc9_map.v) as an input to the flop box
if (box_module->get_bool_attribute("\\abc9_flop")) {
SigSpec rhs = module->wire(stringf("%s.$abc9_currQ", cell->name.c_str()));
if (rhs.empty())
log_error("'%s.$abc9_currQ' is not a wire present in module '%s'.\n", log_id(cell), log_id(module));
for (auto b : rhs) {
SigBit I = sigmap(b);
if (b == RTLIL::Sx)
b = State::S0;
else if (I != b) {
if (I == RTLIL::Sx)
alias_map[b] = State::S0;
else
alias_map[b] = I;
}
co_bits.emplace_back(b);
unused_bits.erase(I);
}
}
box_list.emplace_back(cell); box_list.emplace_back(cell);
} }
// TODO: Free memory from toposort, bit_drivers, bit_users // TODO: Free memory from toposort, bit_drivers, bit_users
} }
for (auto bit : input_bits) { if (!holes_mode)
if (!output_bits.count(bit)) for (auto cell : module->cells())
if (!module->selected(cell))
for (auto &conn : cell->connections())
if (cell->input(conn.first))
for (auto wirebit : conn.second)
if (sigmap(wirebit).wire)
external_bits.insert(wirebit);
// For all bits consumed outside of the selected cells,
// but driven from a selected cell, then add it as
// a primary output
for (auto wirebit : external_bits) {
SigBit bit = sigmap(wirebit);
if (!bit.wire)
continue; continue;
RTLIL::Wire *wire = bit.wire; if (!undriven_bits.count(bit)) {
// If encountering an inout port, or a keep-ed wire, then create a new wire if (bit != wirebit)
// with $inout.out suffix, make it a PO driven by the existing inout, and alias_map[wirebit] = bit;
// inherit existing inout's drivers output_bits.insert(wirebit);
if ((wire->port_input && wire->port_output && !undriven_bits.count(bit))
|| keep_bits.count(bit)) {
RTLIL::IdString wire_name = stringf("$%s$inout.out", wire->name.c_str());
RTLIL::Wire *new_wire = module->wire(wire_name);
if (!new_wire)
new_wire = module->addWire(wire_name, GetSize(wire));
SigBit new_bit(new_wire, bit.offset);
module->connect(new_bit, bit);
if (not_map.count(bit)) {
auto a = not_map.at(bit);
not_map[new_bit] = a;
}
else if (and_map.count(bit)) {
auto a = and_map.at(bit);
and_map[new_bit] = a;
}
else if (alias_map.count(bit)) {
auto a = alias_map.at(bit);
alias_map[new_bit] = a;
}
else
alias_map[new_bit] = bit;
output_bits.erase(bit);
output_bits.insert(new_bit);
} }
} }
for (auto bit : input_bits)
undriven_bits.erase(sigmap(bit));
for (auto bit : output_bits)
unused_bits.erase(sigmap(bit));
for (auto bit : unused_bits) for (auto bit : unused_bits)
undriven_bits.erase(bit); undriven_bits.erase(bit);
if (!undriven_bits.empty() && !holes_mode) { // Make all undriven bits a primary input
undriven_bits.sort(); if (!holes_mode)
for (auto bit : undriven_bits) { for (auto bit : undriven_bits) {
log_warning("Treating undriven bit %s.%s like $anyseq.\n", log_id(module), log_signal(bit));
input_bits.insert(bit); input_bits.insert(bit);
} undriven_bits.erase(bit);
log_warning("Treating a total of %d undriven bits in %s like $anyseq.\n", GetSize(undriven_bits), log_id(module));
} }
if (holes_mode) { if (holes_mode) {
@ -484,25 +558,36 @@ struct XAigerWriter
aig_map[bit] = 2*aig_m; aig_map[bit] = 2*aig_m;
} }
for (auto bit : ci_bits) { for (const auto &i : ff_bits) {
const SigBit &bit = i.first;
aig_m++, aig_i++; aig_m++, aig_i++;
log_assert(!aig_map.count(bit));
aig_map[bit] = 2*aig_m; aig_map[bit] = 2*aig_m;
} }
dict<SigBit, int> ff_aig_map;
for (auto &bit : ci_bits) {
aig_m++, aig_i++;
auto r = aig_map.insert(std::make_pair(bit, 2*aig_m));
if (!r.second)
ff_aig_map[bit] = 2*aig_m;
}
for (auto bit : co_bits) { for (auto bit : co_bits) {
ordered_outputs[bit] = aig_o++; ordered_outputs[bit] = aig_o++;
aig_outputs.push_back(bit2aig(bit)); aig_outputs.push_back(bit2aig(bit));
} }
if (output_bits.empty()) {
output_bits.insert(State::S0);
omode = true;
}
for (auto bit : output_bits) { for (auto bit : output_bits) {
ordered_outputs[bit] = aig_o++; ordered_outputs[bit] = aig_o++;
aig_outputs.push_back(bit2aig(bit)); aig_outputs.push_back(bit2aig(bit));
} }
for (auto &i : ff_bits) {
const SigBit &bit = i.first;
aig_o++;
aig_outputs.push_back(ff_aig_map.at(bit));
}
} }
void write_aiger(std::ostream &f, bool ascii_mode) void write_aiger(std::ostream &f, bool ascii_mode)
@ -564,7 +649,6 @@ struct XAigerWriter
f << "c"; f << "c";
log_assert(!output_bits.empty());
auto write_buffer = [](std::stringstream &buffer, int i32) { auto write_buffer = [](std::stringstream &buffer, int i32) {
int32_t i32_be = to_big_endian(i32); int32_t i32_be = to_big_endian(i32);
buffer.write(reinterpret_cast<const char*>(&i32_be), sizeof(i32_be)); buffer.write(reinterpret_cast<const char*>(&i32_be), sizeof(i32_be));
@ -572,14 +656,14 @@ struct XAigerWriter
std::stringstream h_buffer; std::stringstream h_buffer;
auto write_h_buffer = std::bind(write_buffer, std::ref(h_buffer), std::placeholders::_1); auto write_h_buffer = std::bind(write_buffer, std::ref(h_buffer), std::placeholders::_1);
write_h_buffer(1); write_h_buffer(1);
log_debug("ciNum = %d\n", GetSize(input_bits) + GetSize(ci_bits)); log_debug("ciNum = %d\n", GetSize(input_bits) + GetSize(ff_bits) + GetSize(ci_bits));
write_h_buffer(input_bits.size() + ci_bits.size()); write_h_buffer(input_bits.size() + ff_bits.size() + ci_bits.size());
log_debug("coNum = %d\n", GetSize(output_bits) + GetSize(co_bits)); log_debug("coNum = %d\n", GetSize(output_bits) + GetSize(ff_bits) + GetSize(co_bits));
write_h_buffer(output_bits.size() + GetSize(co_bits)); write_h_buffer(output_bits.size() + GetSize(ff_bits) + GetSize(co_bits));
log_debug("piNum = %d\n", GetSize(input_bits)); log_debug("piNum = %d\n", GetSize(input_bits) + GetSize(ff_bits));
write_h_buffer(input_bits.size()); write_h_buffer(input_bits.size() + ff_bits.size());
log_debug("poNum = %d\n", GetSize(output_bits)); log_debug("poNum = %d\n", GetSize(output_bits) + GetSize(ff_bits));
write_h_buffer(output_bits.size()); write_h_buffer(output_bits.size() + ff_bits.size());
log_debug("boxNum = %d\n", GetSize(box_list)); log_debug("boxNum = %d\n", GetSize(box_list));
write_h_buffer(box_list.size()); write_h_buffer(box_list.size());
@ -595,7 +679,7 @@ struct XAigerWriter
//for (auto bit : output_bits) //for (auto bit : output_bits)
// write_o_buffer(0); // write_o_buffer(0);
if (!box_list.empty()) { if (!box_list.empty() || !ff_bits.empty()) {
RTLIL::Module *holes_module = module->design->addModule("$__holes__"); RTLIL::Module *holes_module = module->design->addModule("$__holes__");
log_assert(holes_module); log_assert(holes_module);
@ -609,7 +693,7 @@ struct XAigerWriter
IdString derived_name = orig_box_module->derive(module->design, cell->parameters); IdString derived_name = orig_box_module->derive(module->design, cell->parameters);
RTLIL::Module* box_module = module->design->module(derived_name); RTLIL::Module* box_module = module->design->module(derived_name);
if (box_module->has_processes()) if (box_module->has_processes())
log_error("ABC9 box '%s' contains processes!\n", box_module->name.c_str()); Pass::call_on_module(module->design, box_module, "proc");
int box_inputs = 0, box_outputs = 0; int box_inputs = 0, box_outputs = 0;
auto r = cell_cache.insert(std::make_pair(derived_name, nullptr)); auto r = cell_cache.insert(std::make_pair(derived_name, nullptr));
@ -655,9 +739,9 @@ struct XAigerWriter
box_outputs += GetSize(w); box_outputs += GetSize(w);
for (int i = 0; i < GetSize(w); i++) { for (int i = 0; i < GetSize(w); i++) {
if (GetSize(w) == 1) if (GetSize(w) == 1)
holes_wire = holes_module->addWire(stringf("%s.%s", cell->name.c_str(), log_id(w->name))); holes_wire = holes_module->addWire(stringf("$abc%s.%s", cell->name.c_str(), log_id(w->name)));
else else
holes_wire = holes_module->addWire(stringf("%s.%s[%d]", cell->name.c_str(), log_id(w->name), i)); holes_wire = holes_module->addWire(stringf("$abc%s.%s[%d]", cell->name.c_str(), log_id(w->name), i));
holes_wire->port_output = true; holes_wire->port_output = true;
holes_wire->port_id = port_id++; holes_wire->port_id = port_id++;
holes_module->ports.push_back(holes_wire->name); holes_module->ports.push_back(holes_wire->name);
@ -675,6 +759,23 @@ struct XAigerWriter
} }
} }
// For flops only, create an extra 1-bit input that drives a new wire
// called "<cell>.$abc9_currQ" that is used below
if (box_module->get_bool_attribute("\\abc9_flop")) {
log_assert(holes_cell);
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 *w = holes_module->addWire(stringf("%s.$abc9_currQ", cell->name.c_str()));
holes_module->connect(w, holes_wire);
}
write_h_buffer(box_inputs); write_h_buffer(box_inputs);
write_h_buffer(box_outputs); write_h_buffer(box_outputs);
write_h_buffer(box_module->attributes.at("\\abc9_box_id").as_int()); write_h_buffer(box_module->attributes.at("\\abc9_box_id").as_int());
@ -683,13 +784,36 @@ struct XAigerWriter
std::stringstream r_buffer; std::stringstream r_buffer;
auto write_r_buffer = std::bind(write_buffer, std::ref(r_buffer), std::placeholders::_1); auto write_r_buffer = std::bind(write_buffer, std::ref(r_buffer), std::placeholders::_1);
write_r_buffer(0); log_debug("flopNum = %d\n", GetSize(ff_bits));
write_r_buffer(ff_bits.size());
std::stringstream s_buffer;
auto write_s_buffer = std::bind(write_buffer, std::ref(s_buffer), std::placeholders::_1);
write_s_buffer(ff_bits.size());
for (const auto &i : ff_bits) {
const SigBit &bit = i.first;
int mergeability = i.second.first;
log_assert(mergeability > 0);
write_r_buffer(mergeability);
int init = i.second.second;
write_s_buffer(init);
write_i_buffer(arrival_times.at(bit, 0));
//write_o_buffer(0);
}
f << "r"; f << "r";
std::string buffer_str = r_buffer.str(); std::string buffer_str = r_buffer.str();
int32_t buffer_size_be = to_big_endian(buffer_str.size()); int32_t buffer_size_be = to_big_endian(buffer_str.size());
f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be)); f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be));
f.write(buffer_str.data(), buffer_str.size()); f.write(buffer_str.data(), buffer_str.size());
f << "s";
buffer_str = s_buffer.str();
buffer_size_be = to_big_endian(buffer_str.size());
f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be));
f.write(buffer_str.data(), buffer_str.size());
if (holes_module) { if (holes_module) {
log_push(); log_push();
@ -697,34 +821,64 @@ struct XAigerWriter
//holes_module->fixup_ports(); //holes_module->fixup_ports();
holes_module->check(); holes_module->check();
holes_module->design->selection_stack.emplace_back(false);
RTLIL::Selection& sel = holes_module->design->selection_stack.back();
sel.select(holes_module);
Pass::call(holes_module->design, "flatten -wb");
// Cannot techmap/aigmap/check all lib_whitebox-es outside of write_xaiger // Cannot techmap/aigmap/check all lib_whitebox-es outside of write_xaiger
// since boxes may contain parameters in which case `flatten` would have // since boxes may contain parameters in which case `flatten` would have
// created a new $paramod ... // created a new $paramod ...
Pass::call(holes_module->design, "techmap"); Pass::call_on_module(holes_module->design, holes_module, "flatten -wb; techmap; aigmap");
Pass::call(holes_module->design, "aigmap");
for (auto cell : holes_module->cells())
if (!cell->type.in("$_NOT_", "$_AND_"))
log_error("Whitebox contents cannot be represented as AIG. Please verify whiteboxes are synthesisable.\n");
holes_module->design->selection_stack.pop_back(); dict<SigSig, SigSig> replace;
for (auto it = holes_module->cells_.begin(); it != holes_module->cells_.end(); ) {
auto cell = it->second;
if (cell->type.in("$_DFF_N_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_",
"$_DFF_P_", "$_DFF_PN0_", "$_DFF_PN1", "$_DFF_PP0_", "$_DFF_PP1_")) {
SigBit D = cell->getPort("\\D");
SigBit Q = cell->getPort("\\Q");
// Remove the DFF cell from what needs to be a combinatorial box
it = holes_module->cells_.erase(it);
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 the combinatorial control logic that feeds the box
// (i.e. clock enable, synchronous reset, etc.)
replace.insert(std::make_pair(SigSig(port,Q), SigSig(port,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 input port) we inserted above
Wire *currQ = holes_module->wire(stringf("%s.$abc9_currQ", driver.c_str()));
log_assert(currQ);
holes_module->connect(Q, currQ);
continue;
}
else if (!cell->type.in("$_NOT_", "$_AND_"))
log_error("Whitebox contents cannot be represented as AIG. Please verify whiteboxes are synthesisable.\n");
++it;
}
for (auto &conn : holes_module->connections_) {
auto it = replace.find(conn);
if (it != replace.end())
conn = it->second;
}
// Move into a new (temporary) design so that "clean" will only // Move into a new (temporary) design so that "clean" will only
// operate (and run checks on) this one module // operate (and run checks on) this one module
RTLIL::Design *holes_design = new RTLIL::Design; RTLIL::Design *holes_design = new RTLIL::Design;
holes_module->design->modules_.erase(holes_module->name); module->design->modules_.erase(holes_module->name);
holes_design->add(holes_module); holes_design->add(holes_module);
Pass::call(holes_design, "clean -purge"); Pass::call(holes_design, "opt -purge");
std::stringstream a_buffer; std::stringstream a_buffer;
XAigerWriter writer(holes_module, true /* holes_mode */); XAigerWriter writer(holes_module, true /* holes_mode */);
writer.write_aiger(a_buffer, false /*ascii_mode*/); writer.write_aiger(a_buffer, false /*ascii_mode*/);
delete holes_design; delete holes_design;
f << "a"; f << "a";
@ -755,6 +909,11 @@ struct XAigerWriter
//f.write(buffer_str.data(), buffer_str.size()); //f.write(buffer_str.data(), buffer_str.size());
f << stringf("Generated by %s\n", yosys_version_str); f << stringf("Generated by %s\n", yosys_version_str);
module->design->scratchpad_set_int("write_xaiger.num_ands", and_map.size());
module->design->scratchpad_set_int("write_xaiger.num_wires", aig_map.size());
module->design->scratchpad_set_int("write_xaiger.num_inputs", input_bits.size());
module->design->scratchpad_set_int("write_xaiger.num_outputs", output_bits.size());
} }
void write_map(std::ostream &f, bool verbose_map) void write_map(std::ostream &f, bool verbose_map)
@ -781,7 +940,8 @@ struct XAigerWriter
if (output_bits.count(b)) { if (output_bits.count(b)) {
int o = ordered_outputs.at(b); int o = ordered_outputs.at(b);
output_lines[o] += stringf("output %d %d %s\n", o - GetSize(co_bits), i, log_id(wire)); int init = 2;
output_lines[o] += stringf("output %d %d %s %d\n", o - GetSize(co_bits), i, log_id(wire), init);
continue; continue;
} }
@ -805,8 +965,6 @@ struct XAigerWriter
f << stringf("box %d %d %s\n", box_count++, 0, log_id(cell->name)); f << stringf("box %d %d %s\n", box_count++, 0, log_id(cell->name));
output_lines.sort(); output_lines.sort();
if (omode)
output_lines[State::S0] = "output 0 0 $__dummy__\n";
for (auto &it : output_lines) for (auto &it : output_lines)
f << it.second; f << it.second;
log_assert(output_lines.size() == output_bits.size()); log_assert(output_lines.size() == output_bits.size());

View File

@ -255,7 +255,7 @@ end_of_header:
else else
log_abort(); log_abort();
RTLIL::Wire* n0 = module->wire("\\__0__"); RTLIL::Wire* n0 = module->wire("$0");
if (n0) if (n0)
module->connect(n0, State::S0); module->connect(n0, State::S0);
@ -316,14 +316,14 @@ static RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned litera
{ {
const unsigned variable = literal >> 1; const unsigned variable = literal >> 1;
const bool invert = literal & 1; const bool invert = literal & 1;
RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : "")); RTLIL::IdString wire_name(stringf("$%d%s", variable, invert ? "b" : ""));
RTLIL::Wire *wire = module->wire(wire_name); RTLIL::Wire *wire = module->wire(wire_name);
if (wire) return wire; if (wire) return wire;
log_debug2("Creating %s\n", wire_name.c_str()); log_debug2("Creating %s\n", wire_name.c_str());
wire = module->addWire(wire_name); wire = module->addWire(wire_name);
wire->port_input = wire->port_output = false; wire->port_input = wire->port_output = false;
if (!invert) return wire; if (!invert) return wire;
RTLIL::IdString wire_inv_name(stringf("\\__%d__", variable)); RTLIL::IdString wire_inv_name(stringf("$%d", variable));
RTLIL::Wire *wire_inv = module->wire(wire_inv_name); RTLIL::Wire *wire_inv = module->wire(wire_inv_name);
if (wire_inv) { if (wire_inv) {
if (module->cell(wire_inv_name)) return wire; if (module->cell(wire_inv_name)) return wire;
@ -335,7 +335,7 @@ static RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned litera
} }
log_debug2("Creating %s = ~%s\n", wire_name.c_str(), wire_inv_name.c_str()); log_debug2("Creating %s = ~%s\n", wire_name.c_str(), wire_inv_name.c_str());
module->addNotGate(stringf("\\__%d__$not", variable), wire_inv, wire); module->addNotGate(stringf("$%d$not", variable), wire_inv, wire);
return wire; return wire;
} }
@ -372,23 +372,19 @@ void AigerReader::parse_xaiger(const dict<int,IdString> &box_lookup)
else else
log_abort(); log_abort();
RTLIL::Wire* n0 = module->wire("\\__0__"); RTLIL::Wire* n0 = module->wire("$0");
if (n0) if (n0)
module->connect(n0, State::S0); module->connect(n0, State::S0);
int c = f.get();
if (c != 'c')
log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c);
if (f.peek() == '\n')
f.get();
// Parse footer (symbol table, comments, etc.) // Parse footer (symbol table, comments, etc.)
std::string s; std::string s;
bool comment_seen = false; for (int c = f.get(); c != EOF; c = f.get()) {
for (int c = f.peek(); c != EOF; c = f.peek()) {
if (comment_seen || c == 'c') {
if (!comment_seen) {
f.ignore(1);
c = f.peek();
comment_seen = true;
}
if (c == '\n')
break;
f.ignore(1);
// XAIGER extensions // XAIGER extensions
if (c == 'm') { if (c == 'm') {
uint32_t dataSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f); uint32_t dataSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
@ -400,13 +396,13 @@ void AigerReader::parse_xaiger(const dict<int,IdString> &box_lookup)
uint32_t rootNodeID = parse_xaiger_literal(f); uint32_t rootNodeID = parse_xaiger_literal(f);
uint32_t cutLeavesM = parse_xaiger_literal(f); uint32_t cutLeavesM = parse_xaiger_literal(f);
log_debug2("rootNodeID=%d cutLeavesM=%d\n", rootNodeID, cutLeavesM); log_debug2("rootNodeID=%d cutLeavesM=%d\n", rootNodeID, cutLeavesM);
RTLIL::Wire *output_sig = module->wire(stringf("\\__%d__", rootNodeID)); RTLIL::Wire *output_sig = module->wire(stringf("$%d", rootNodeID));
uint32_t nodeID; uint32_t nodeID;
RTLIL::SigSpec input_sig; RTLIL::SigSpec input_sig;
for (unsigned j = 0; j < cutLeavesM; ++j) { for (unsigned j = 0; j < cutLeavesM; ++j) {
nodeID = parse_xaiger_literal(f); nodeID = parse_xaiger_literal(f);
log_debug2("\t%u\n", nodeID); log_debug2("\t%u\n", nodeID);
RTLIL::Wire *wire = module->wire(stringf("\\__%d__", nodeID)); RTLIL::Wire *wire = module->wire(stringf("$%d", nodeID));
log_assert(wire); log_assert(wire);
input_sig.append(wire); input_sig.append(wire);
} }
@ -423,16 +419,16 @@ void AigerReader::parse_xaiger(const dict<int,IdString> &box_lookup)
log_assert(o.wire == nullptr); log_assert(o.wire == nullptr);
lut_mask[gray] = o.data; lut_mask[gray] = o.data;
} }
RTLIL::Cell *output_cell = module->cell(stringf("\\__%d__$and", rootNodeID)); RTLIL::Cell *output_cell = module->cell(stringf("$%d$and", rootNodeID));
log_assert(output_cell); log_assert(output_cell);
module->remove(output_cell); module->remove(output_cell);
module->addLut(stringf("\\__%d__$lut", rootNodeID), input_sig, output_sig, std::move(lut_mask)); module->addLut(stringf("$%d$lut", rootNodeID), input_sig, output_sig, std::move(lut_mask));
} }
} }
else if (c == 'r') { else if (c == 'r') {
uint32_t dataSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f); uint32_t dataSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
flopNum = parse_xaiger_literal(f); flopNum = parse_xaiger_literal(f);
log_debug("flopNum: %u\n", flopNum); log_debug("flopNum = %u\n", flopNum);
log_assert(dataSize == (flopNum+1) * sizeof(uint32_t)); log_assert(dataSize == (flopNum+1) * sizeof(uint32_t));
f.ignore(flopNum * sizeof(uint32_t)); f.ignore(flopNum * sizeof(uint32_t));
} }
@ -460,21 +456,19 @@ void AigerReader::parse_xaiger(const dict<int,IdString> &box_lookup)
uint32_t boxUniqueId = parse_xaiger_literal(f); uint32_t boxUniqueId = parse_xaiger_literal(f);
log_assert(boxUniqueId > 0); log_assert(boxUniqueId > 0);
uint32_t oldBoxNum = parse_xaiger_literal(f); uint32_t oldBoxNum = parse_xaiger_literal(f);
RTLIL::Cell* cell = module->addCell(stringf("$__box%u__", oldBoxNum), box_lookup.at(boxUniqueId)); RTLIL::Cell* cell = module->addCell(stringf("$__box%u", oldBoxNum), box_lookup.at(boxUniqueId));
boxes.emplace_back(cell); boxes.emplace_back(cell);
} }
} }
else if (c == 'a' || c == 'i' || c == 'o') { else if (c == 'a' || c == 'i' || c == 'o' || c == 's') {
uint32_t dataSize = parse_xaiger_literal(f); uint32_t dataSize = parse_xaiger_literal(f);
f.ignore(dataSize); f.ignore(dataSize);
log_debug("ignoring '%c'\n", c);
} }
else { else {
break; break;
} }
} }
else
log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c);
}
post_process(); post_process();
} }
@ -550,7 +544,7 @@ void AigerReader::parse_aiger_ascii()
log_debug2("%d is an output\n", l1); log_debug2("%d is an output\n", l1);
const unsigned variable = l1 >> 1; const unsigned variable = l1 >> 1;
const bool invert = l1 & 1; const bool invert = l1 & 1;
RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : "")); // FIXME: is "b" the right suffix? RTLIL::IdString wire_name(stringf("$%d%s", variable, invert ? "b" : "")); // FIXME: is "b" the right suffix?
RTLIL::Wire *wire = module->wire(wire_name); RTLIL::Wire *wire = module->wire(wire_name);
if (!wire) if (!wire)
wire = createWireIfNotExists(module, l1); wire = createWireIfNotExists(module, l1);
@ -616,11 +610,12 @@ void AigerReader::parse_aiger_binary()
std::string line; std::string line;
// Parse inputs // Parse inputs
int digits = ceil(log10(I));
for (unsigned i = 1; i <= I; ++i) { for (unsigned i = 1; i <= I; ++i) {
log_debug2("%d is an input\n", i); log_debug2("%d is an input\n", i);
RTLIL::Wire *wire = createWireIfNotExists(module, i << 1); RTLIL::Wire *wire = module->addWire(stringf("$i%0*d", digits, i));
wire->port_input = true; wire->port_input = true;
log_assert(!wire->port_output); module->connect(createWireIfNotExists(module, i << 1), wire);
inputs.push_back(wire); inputs.push_back(wire);
} }
@ -670,23 +665,15 @@ void AigerReader::parse_aiger_binary()
} }
// Parse outputs // Parse outputs
digits = ceil(log10(O));
for (unsigned i = 0; i < O; ++i, ++line_count) { for (unsigned i = 0; i < O; ++i, ++line_count) {
if (!(f >> l1)) if (!(f >> l1))
log_error("Line %u cannot be interpreted as an output!\n", line_count); log_error("Line %u cannot be interpreted as an output!\n", line_count);
log_debug2("%d is an output\n", l1); log_debug2("%d is an output\n", l1);
const unsigned variable = l1 >> 1; RTLIL::Wire *wire = module->addWire(stringf("$o%0*d", digits, i));
const bool invert = l1 & 1;
RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : "")); // FIXME: is "_b" the right suffix?
RTLIL::Wire *wire = module->wire(wire_name);
if (!wire)
wire = createWireIfNotExists(module, l1);
else if (wire->port_input || wire->port_output) {
RTLIL::Wire *new_wire = module->addWire(NEW_ID);
module->connect(new_wire, wire);
wire = new_wire;
}
wire->port_output = true; wire->port_output = true;
module->connect(wire, createWireIfNotExists(module, l1));
outputs.push_back(wire); outputs.push_back(wire);
} }
std::getline(f, line); // Ignore up to start of next line std::getline(f, line); // Ignore up to start of next line
@ -734,12 +721,19 @@ void AigerReader::parse_aiger_binary()
void AigerReader::post_process() void AigerReader::post_process()
{ {
pool<IdString> seen_boxes; pool<IdString> seen_boxes;
unsigned ci_count = 0, co_count = 0; pool<IdString> flops;
unsigned ci_count = 0, co_count = 0, flop_count = 0;
for (auto cell : boxes) { for (auto cell : boxes) {
RTLIL::Module* box_module = design->module(cell->type); RTLIL::Module* box_module = design->module(cell->type);
log_assert(box_module); log_assert(box_module);
bool is_flop = false;
if (seen_boxes.insert(cell->type).second) { if (seen_boxes.insert(cell->type).second) {
if (box_module->attributes.count("\\abc9_flop")) {
log_assert(flop_count < flopNum);
flops.insert(cell->type);
is_flop = true;
}
auto it = box_module->attributes.find("\\abc9_carry"); auto it = box_module->attributes.find("\\abc9_carry");
if (it != box_module->attributes.end()) { if (it != box_module->attributes.end()) {
RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr; RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr;
@ -779,6 +773,8 @@ void AigerReader::post_process()
carry_out->port_id = ports.size(); carry_out->port_id = ports.size();
} }
} }
else
is_flop = flops.count(cell->type);
// NB: Assume box_module->ports are sorted alphabetically // NB: Assume box_module->ports are sorted alphabetically
// (as RTLIL::Module::fixup_ports() would do) // (as RTLIL::Module::fixup_ports() would do)
@ -804,9 +800,32 @@ void AigerReader::post_process()
} }
rhs.append(wire); rhs.append(wire);
} }
cell->setPort(port_name, rhs); cell->setPort(port_name, rhs);
} }
if (is_flop) {
log_assert(co_count < outputs.size());
Wire *wire = outputs[co_count++];
log_assert(wire);
log_assert(wire->port_output);
wire->port_output = false;
RTLIL::Wire *d = outputs[outputs.size() - flopNum + flop_count];
log_assert(d);
log_assert(d->port_output);
d->port_output = false;
RTLIL::Wire *q = inputs[piNum - flopNum + flop_count];
log_assert(q);
log_assert(q->port_input);
q->port_input = false;
auto ff = module->addCell(NEW_ID, "$__ABC9_FF_");
ff->setPort("\\D", d);
ff->setPort("\\Q", q);
flop_count++;
continue;
}
} }
dict<RTLIL::IdString, int> wideports_cache; dict<RTLIL::IdString, int> wideports_cache;
@ -868,15 +887,6 @@ void AigerReader::post_process()
// simply connect the latter to the former // simply connect the latter to the former
RTLIL::Wire* existing = module->wire(escaped_s); RTLIL::Wire* existing = module->wire(escaped_s);
if (!existing) { if (!existing) {
if (escaped_s.ends_with("$inout.out")) {
wire->port_output = false;
RTLIL::Wire *in_wire = module->wire(escaped_s.substr(1, escaped_s.size()-11));
log_assert(in_wire);
log_assert(in_wire->port_input && !in_wire->port_output);
in_wire->port_output = true;
module->connect(in_wire, wire);
}
else
module->rename(wire, escaped_s); module->rename(wire, escaped_s);
} }
else { else {
@ -889,29 +899,23 @@ void AigerReader::post_process()
std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index); std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index);
RTLIL::Wire* existing = module->wire(indexed_name); RTLIL::Wire* existing = module->wire(indexed_name);
if (!existing) { if (!existing) {
if (escaped_s.ends_with("$inout.out")) {
wire->port_output = false;
RTLIL::Wire *in_wire = module->wire(stringf("%s[%d]", escaped_s.substr(1, escaped_s.size()-11).c_str(), index));
log_assert(in_wire);
log_assert(in_wire->port_input && !in_wire->port_output);
in_wire->port_output = true;
module->connect(in_wire, wire);
}
else {
module->rename(wire, indexed_name); module->rename(wire, indexed_name);
if (wideports) if (wideports)
wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index); wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index);
} }
}
else { else {
module->connect(wire, existing); module->connect(wire, existing);
wire->port_output = false; wire->port_output = false;
} }
} }
log_debug(" -> %s\n", log_id(wire)); log_debug(" -> %s\n", log_id(wire));
int init;
mf >> init;
if (init < 2)
wire->attributes["\\init"] = init;
} }
else if (type == "box") { else if (type == "box") {
RTLIL::Cell* cell = module->cell(stringf("$__box%d__", variable)); RTLIL::Cell* cell = module->cell(stringf("$__box%d", variable));
if (cell) { // ABC could have optimised this box away if (cell) { // ABC could have optimised this box away
module->rename(cell, escaped_s); module->rename(cell, escaped_s);
for (const auto &i : cell->connections()) { for (const auto &i : cell->connections()) {
@ -968,15 +972,10 @@ void AigerReader::post_process()
if (other_wire) { if (other_wire) {
other_wire->port_input = false; other_wire->port_input = false;
other_wire->port_output = false; other_wire->port_output = false;
} if (wire->port_input)
if (wire->port_input) {
if (other_wire)
module->connect(other_wire, SigSpec(wire, i)); module->connect(other_wire, SigSpec(wire, i));
} else
else { module->connect(SigSpec(wire, i), other_wire);
// Since we skip POs that are connected to Sx,
// re-connect them here
module->connect(SigSpec(wire, i), other_wire ? other_wire : SigSpec(RTLIL::Sx));
} }
} }
} }

View File

@ -80,8 +80,6 @@ struct Abc9Pass : public ScriptPass
log(" set delay target. the string {D} in the default scripts above is\n"); log(" set delay target. the string {D} in the default scripts above is\n");
log(" replaced by this option when used, and an empty string otherwise\n"); log(" replaced by this option when used, and an empty string otherwise\n");
log(" (indicating best possible delay).\n"); log(" (indicating best possible delay).\n");
// log(" This also replaces 'dretime' with 'dretime; retime -o {D}' in the\n");
// log(" default scripts above.\n");
log("\n"); log("\n");
// log(" -S <num>\n"); // log(" -S <num>\n");
// log(" maximum number of LUT inputs shared.\n"); // log(" maximum number of LUT inputs shared.\n");
@ -103,19 +101,6 @@ struct Abc9Pass : public ScriptPass
log(" generate netlist using luts. Use the specified costs for luts with 1,\n"); log(" generate netlist using luts. Use the specified costs for luts with 1,\n");
log(" 2, 3, .. inputs.\n"); log(" 2, 3, .. inputs.\n");
log("\n"); log("\n");
// log(" -dff\n");
// log(" also pass $_DFF_?_ and $_DFFE_??_ cells through ABC. modules with many\n");
// log(" clock domains are automatically partitioned in clock domains and each\n");
// log(" domain is passed through ABC independently.\n");
// log("\n");
// log(" -clk [!]<clock-signal-name>[,[!]<enable-signal-name>]\n");
// log(" use only the specified clock domain. this is like -dff, but only FF\n");
// log(" cells that belong to the specified clock domain are used.\n");
// log("\n");
// log(" -keepff\n");
// log(" set the \"keep\" attribute on flip-flop output wires. (and thus preserve\n");
// log(" them, for example for equivalence checking.)\n");
// log("\n");
log(" -nocleanup\n"); log(" -nocleanup\n");
log(" when this option is used, the temporary files created by this pass\n"); log(" when this option is used, the temporary files created by this pass\n");
log(" are not removed. this is useful for debugging.\n"); log(" are not removed. this is useful for debugging.\n");
@ -136,8 +121,17 @@ struct Abc9Pass : public ScriptPass
log("internally. This is not going to \"run ABC on your design\". It will instead run\n"); log("internally. This is not going to \"run ABC on your design\". It will instead run\n");
log("ABC on logic snippets extracted from your design. You will not get any useful\n"); log("ABC on logic snippets extracted from your design. You will not get any useful\n");
log("output when passing an ABC script that writes a file. Instead write your full\n"); log("output when passing an ABC script that writes a file. Instead write your full\n");
log("design as BLIF file with write_blif and then load that into ABC externally if\n"); log("design as an XAIGER file with write_xaiger and then load that into ABC externally\n");
log("you want to use ABC to convert your design into another format.\n"); log("if you want to use ABC to convert your design into another format.\n");
log("\n");
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("Delay targets can also be specified on a per clock basis by attaching a\n");
log("'(* abc9_period = <int> *)' attribute onto clock wires (specifically, onto wires\n");
log("that appear inside any special '$abc9_clock' wires inserted by abc9_map.v). This\n");
log("can be achieved by modifying the source directly, or through a `setattr`\n");
log("invocation. Since such attributes cannot yet be propagated through a\n");
log("hierarchical design (whether or not it has been uniquified) it is recommended\n");
log("that the design be flattened when using this feature.\n");
log("\n"); log("\n");
log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n"); log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n");
log("\n"); log("\n");

View File

@ -65,11 +65,6 @@ PRIVATE_NAMESPACE_BEGIN
bool markgroups; bool markgroups;
int map_autoidx; int map_autoidx;
SigMap assign_map;
RTLIL::Module *module;
bool clk_polarity, en_polarity;
RTLIL::SigSpec clk_sig, en_sig;
inline std::string remap_name(RTLIL::IdString abc9_name) inline std::string remap_name(RTLIL::IdString abc9_name)
{ {
@ -201,64 +196,30 @@ struct abc9_output_filter
} }
}; };
void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, void abc9_module(RTLIL::Design *design, RTLIL::Module *module, std::string script_file, std::string exe_file,
/*bool cleanup,*/ vector<int> lut_costs, bool dff_mode, std::string clk_str, vector<int> lut_costs, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode,
bool /*keepff*/, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode, const std::vector<RTLIL::Cell*> &/*cells*/, bool show_tempdir, std::string box_file, std::string lut_file,
bool show_tempdir, std::string box_file, std::string lut_file,
std::string wire_delay, const dict<int,IdString> &box_lookup, bool nomfs, std::string tempdir_name std::string wire_delay, const dict<int,IdString> &box_lookup, bool nomfs, std::string tempdir_name
) )
{ {
module = current_module;
map_autoidx = autoidx++; map_autoidx = autoidx++;
if (clk_str != "$") //FIXME:
{ //log_header(design, "Extracting gate netlist of module `%s' to `%s/input.xaig'..\n",
clk_polarity = true; // module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str());
clk_sig = RTLIL::SigSpec();
en_polarity = true;
en_sig = RTLIL::SigSpec();
}
if (!clk_str.empty() && clk_str != "$")
{
if (clk_str.find(',') != std::string::npos) {
int pos = clk_str.find(',');
std::string 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->wires_.count(RTLIL::escape_id(en_str)) != 0)
en_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(en_str)), 0));
}
if (clk_str[0] == '!') {
clk_polarity = false;
clk_str = clk_str.substr(1);
}
if (module->wires_.count(RTLIL::escape_id(clk_str)) != 0)
clk_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(clk_str)), 0));
}
if (dff_mode && clk_sig.empty())
log_cmd_error("Clock domain %s not found.\n", clk_str.c_str());
log_header(design, "Extracting gate netlist of module `%s' to `%s/input.xaig'..\n",
module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str());
std::string abc9_script; std::string abc9_script;
if (!lut_costs.empty()) { if (!lut_costs.empty()) {
abc9_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str()); abc9_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str());
if (!box_file.empty()) if (!box_file.empty())
abc9_script += stringf("read_box -v %s; ", box_file.c_str()); abc9_script += stringf("read_box %s; ", box_file.c_str());
} }
else else
if (!lut_file.empty()) { if (!lut_file.empty()) {
abc9_script += stringf("read_lut %s; ", lut_file.c_str()); abc9_script += stringf("read_lut %s; ", lut_file.c_str());
if (!box_file.empty()) if (!box_file.empty())
abc9_script += stringf("read_box -v %s; ", box_file.c_str()); abc9_script += stringf("read_box %s; ", box_file.c_str());
} }
else else
log_abort(); log_abort();
@ -277,20 +238,10 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
} else } else
abc9_script += stringf("source %s", script_file.c_str()); abc9_script += stringf("source %s", script_file.c_str());
} else if (!lut_costs.empty() || !lut_file.empty()) { } else if (!lut_costs.empty() || !lut_file.empty()) {
//bool all_luts_cost_same = true;
//for (int this_cost : lut_costs)
// if (this_cost != lut_costs.front())
// all_luts_cost_same = false;
abc9_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT; abc9_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT;
//if (all_luts_cost_same && !fast_mode)
// abc9_script += "; lutpack {S}";
} else } else
log_abort(); log_abort();
//if (script_file.empty() && !delay_target.empty())
// for (size_t pos = abc9_script.find("dretime;"); pos != std::string::npos; pos = abc9_script.find("dretime;", pos+1))
// abc9_script = abc9_script.substr(0, pos) + "dretime; retime -o {D};" + abc9_script.substr(pos+8);
for (size_t pos = abc9_script.find("{D}"); pos != std::string::npos; pos = abc9_script.find("{D}", pos)) for (size_t pos = abc9_script.find("{D}"); pos != std::string::npos; pos = abc9_script.find("{D}", pos))
abc9_script = abc9_script.substr(0, pos) + delay_target + abc9_script.substr(pos+3); abc9_script = abc9_script.substr(0, pos) + delay_target + abc9_script.substr(pos+3);
@ -304,7 +255,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
for (size_t pos = abc9_script.find("&mfs"); pos != std::string::npos; pos = abc9_script.find("&mfs", pos)) for (size_t pos = abc9_script.find("&mfs"); pos != std::string::npos; pos = abc9_script.find("&mfs", pos))
abc9_script = abc9_script.erase(pos, strlen("&mfs")); abc9_script = abc9_script.erase(pos, strlen("&mfs"));
abc9_script += stringf("; &write %s/output.aig", tempdir_name.c_str()); abc9_script += stringf("; &write -n %s/output.aig", tempdir_name.c_str());
abc9_script = add_echos_to_abc9_cmd(abc9_script); abc9_script = add_echos_to_abc9_cmd(abc9_script);
for (size_t i = 0; i+1 < abc9_script.size(); i++) for (size_t i = 0; i+1 < abc9_script.size(); i++)
@ -315,22 +266,17 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
fprintf(f, "%s\n", abc9_script.c_str()); fprintf(f, "%s\n", abc9_script.c_str());
fclose(f); fclose(f);
if (dff_mode || !clk_str.empty())
{
if (clk_sig.size() == 0)
log("No%s clock domain found. Not extracting any FF cells.\n", clk_str.empty() ? "" : " matching");
else {
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));
log("\n");
}
}
log_push(); log_push();
//if (count_output) // FIXME:
{ /*int count_outputs = design->scratchpad_get_int("write_xaiger.num_outputs");
log("Extracted %d AND gates and %d wires to a netlist network with %d inputs and %d outputs.\n",
design->scratchpad_get_int("write_xaiger.num_ands"),
design->scratchpad_get_int("write_xaiger.num_wires"),
design->scratchpad_get_int("write_xaiger.num_inputs"),
count_outputs);
if (count_outputs > 0)*/ {
std::string buffer; std::string buffer;
std::ifstream ifs; std::ifstream ifs;
#if 0 #if 0
@ -342,14 +288,14 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
log_assert(!design->module(ID($__abc9__))); log_assert(!design->module(ID($__abc9__)));
{ {
AigerReader reader(design, ifs, ID($__abc9__), "" /* clk_name */, buffer.c_str() /* map_filename */, true /* wideports */); AigerReader reader(design, ifs, ID($__abc9__), "" /* clk_name */, buffer.c_str() /* map_filename */, true /* wideports */);
reader.parse_xaiger(); reader.parse_xaiger(box_lookup);
} }
ifs.close(); ifs.close();
Pass::call(design, stringf("write_verilog -noexpr -norename")); Pass::call_on_module(design, design->module(ID($__abc9__)), stringf("write_verilog -noexpr -norename -selected"));
design->remove(design->module(ID($__abc9__))); design->remove(design->module(ID($__abc9__)));
#endif #endif
log_header(design, "Executing ABC9_MAP.\n"); log_header(design, "Executing ABC9.\n");
if (!lut_costs.empty()) { if (!lut_costs.empty()) {
buffer = stringf("%s/lutdefs.txt", tempdir_name.c_str()); buffer = stringf("%s/lutdefs.txt", tempdir_name.c_str());
@ -398,7 +344,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
ifs.close(); ifs.close();
#if 0 #if 0
Pass::call(design, stringf("write_verilog -noexpr -norename")); Pass::call_on_module(design, design->module(ID($__abc9__)), stringf("write_verilog -noexpr -norename -selected"));
#endif #endif
log_header(design, "Re-integrating ABC9 results.\n"); log_header(design, "Re-integrating ABC9 results.\n");
@ -406,33 +352,16 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
if (mapped_mod == NULL) if (mapped_mod == NULL)
log_error("ABC output file does not contain a module `$__abc9__'.\n"); log_error("ABC output file does not contain a module `$__abc9__'.\n");
pool<RTLIL::SigBit> output_bits;
for (auto &it : mapped_mod->wires_) { for (auto &it : mapped_mod->wires_) {
RTLIL::Wire *w = it.second; RTLIL::Wire *w = it.second;
RTLIL::Wire *remap_wire = module->addWire(remap_name(w->name), GetSize(w)); RTLIL::Wire *remap_wire = module->addWire(remap_name(w->name), GetSize(w));
if (markgroups) remap_wire->attributes[ID(abcgroup)] = map_autoidx; if (markgroups) remap_wire->attributes[ID(abcgroup)] = map_autoidx;
if (w->port_output) {
RTLIL::Wire *wire = module->wire(w->name);
log_assert(wire);
for (int i = 0; i < GetSize(w); i++)
output_bits.insert({wire, i});
}
}
for (auto &it : module->connections_) {
auto &signal = it.first;
auto bits = signal.bits();
for (auto &b : bits)
if (output_bits.count(b))
b = module->addWire(NEW_ID);
signal = std::move(bits);
} }
dict<IdString, bool> abc9_box; dict<IdString, bool> abc9_box;
vector<RTLIL::Cell*> boxes; vector<RTLIL::Cell*> boxes;
for (const auto &it : module->cells_) { for (auto cell : module->selected_cells()) {
auto cell = it.second; if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_))) {
if (cell->type.in(ID($_AND_), ID($_NOT_))) {
module->remove(cell); module->remove(cell);
continue; continue;
} }
@ -441,9 +370,17 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
RTLIL::Module* box_module = design->module(cell->type); RTLIL::Module* box_module = design->module(cell->type);
jt = abc9_box.insert(std::make_pair(cell->type, box_module && box_module->attributes.count(ID(abc9_box_id)))).first; jt = abc9_box.insert(std::make_pair(cell->type, box_module && box_module->attributes.count(ID(abc9_box_id)))).first;
} }
if (jt->second) if (jt->second) {
auto kt = cell->attributes.find("\\abc9_keep");
bool abc9_keep = false;
if (kt != cell->attributes.end()) {
abc9_keep = kt->second.as_bool();
cell->attributes.erase(kt);
}
if (!abc9_keep)
boxes.emplace_back(cell); boxes.emplace_back(cell);
} }
}
dict<SigBit, pool<IdString>> bit_drivers, bit_users; dict<SigBit, pool<IdString>> bit_drivers, bit_users;
TopoSort<IdString, RTLIL::sort_by_id_str> toposort; TopoSort<IdString, RTLIL::sort_by_id_str> toposort;
@ -451,19 +388,19 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
dict<SigBit, std::vector<RTLIL::Cell*>> bit2sinks; dict<SigBit, std::vector<RTLIL::Cell*>> bit2sinks;
std::map<IdString, int> cell_stats; std::map<IdString, int> cell_stats;
for (auto c : mapped_mod->cells()) for (auto mapped_cell : mapped_mod->cells())
{ {
toposort.node(c->name); toposort.node(mapped_cell->name);
RTLIL::Cell *cell = nullptr; RTLIL::Cell *cell = nullptr;
if (c->type == ID($_NOT_)) { if (mapped_cell->type == ID($_NOT_)) {
RTLIL::SigBit a_bit = c->getPort(ID::A); RTLIL::SigBit a_bit = mapped_cell->getPort(ID::A);
RTLIL::SigBit y_bit = c->getPort(ID::Y); RTLIL::SigBit y_bit = mapped_cell->getPort(ID::Y);
bit_users[a_bit].insert(c->name); bit_users[a_bit].insert(mapped_cell->name);
bit_drivers[y_bit].insert(c->name); bit_drivers[y_bit].insert(mapped_cell->name);
if (!a_bit.wire) { if (!a_bit.wire) {
c->setPort(ID::Y, module->addWire(NEW_ID)); mapped_cell->setPort(ID::Y, module->addWire(NEW_ID));
RTLIL::Wire *wire = module->wire(remap_name(y_bit.wire->name)); RTLIL::Wire *wire = module->wire(remap_name(y_bit.wire->name));
log_assert(wire); log_assert(wire);
module->connect(RTLIL::SigBit(wire, y_bit.offset), State::S1); module->connect(RTLIL::SigBit(wire, y_bit.offset), State::S1);
@ -487,7 +424,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
if (!driver_lut) { if (!driver_lut) {
// If a driver couldn't be found (could be from PI or box CI) // If a driver couldn't be found (could be from PI or box CI)
// then implement using a LUT // then implement using a LUT
cell = module->addLut(remap_name(stringf("%s$lut", c->name.c_str())), cell = module->addLut(remap_name(stringf("%s$lut", mapped_cell->name.c_str())),
RTLIL::SigBit(module->wires_.at(remap_name(a_bit.wire->name)), a_bit.offset), RTLIL::SigBit(module->wires_.at(remap_name(a_bit.wire->name)), a_bit.offset),
RTLIL::SigBit(module->wires_.at(remap_name(y_bit.wire->name)), y_bit.offset), RTLIL::SigBit(module->wires_.at(remap_name(y_bit.wire->name)), y_bit.offset),
RTLIL::Const::from_string("01")); RTLIL::Const::from_string("01"));
@ -495,7 +432,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
cell_stats[ID($lut)]++; cell_stats[ID($lut)]++;
} }
else else
not2drivers[c] = driver_lut; not2drivers[mapped_cell] = driver_lut;
continue; continue;
} }
else else
@ -503,24 +440,26 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
if (cell && markgroups) cell->attributes[ID(abcgroup)] = map_autoidx; if (cell && markgroups) cell->attributes[ID(abcgroup)] = map_autoidx;
continue; continue;
} }
cell_stats[c->type]++; cell_stats[mapped_cell->type]++;
RTLIL::Cell *existing_cell = nullptr; RTLIL::Cell *existing_cell = nullptr;
if (c->type == ID($lut)) { if (mapped_cell->type.in(ID($lut), ID($__ABC9_FF_))) {
if (GetSize(c->getPort(ID::A)) == 1 && c->getParam(ID(LUT)) == RTLIL::Const::from_string("01")) { if (mapped_cell->type == ID($lut) &&
SigSpec my_a = module->wires_.at(remap_name(c->getPort(ID::A).as_wire()->name)); GetSize(mapped_cell->getPort(ID::A)) == 1 &&
SigSpec my_y = module->wires_.at(remap_name(c->getPort(ID::Y).as_wire()->name)); mapped_cell->getParam(ID(LUT)) == RTLIL::Const::from_string("01")) {
SigSpec my_a = module->wires_.at(remap_name(mapped_cell->getPort(ID::A).as_wire()->name));
SigSpec my_y = module->wires_.at(remap_name(mapped_cell->getPort(ID::Y).as_wire()->name));
module->connect(my_y, my_a); module->connect(my_y, my_a);
if (markgroups) c->attributes[ID(abcgroup)] = map_autoidx; if (markgroups) mapped_cell->attributes[ID(abcgroup)] = map_autoidx;
log_abort(); log_abort();
continue; continue;
} }
cell = module->addCell(remap_name(c->name), c->type); cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type);
} }
else { else {
existing_cell = module->cell(c->name); existing_cell = module->cell(mapped_cell->name);
log_assert(existing_cell); log_assert(existing_cell);
cell = module->addCell(remap_name(c->name), c->type); cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type);
} }
if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx; if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx;
@ -529,10 +468,13 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
cell->attributes = existing_cell->attributes; cell->attributes = existing_cell->attributes;
} }
else { else {
cell->parameters = c->parameters; cell->parameters = mapped_cell->parameters;
cell->attributes = c->attributes; cell->attributes = mapped_cell->attributes;
} }
for (auto &conn : c->connections()) {
RTLIL::Module* box_module = design->module(mapped_cell->type);
auto abc9_flop = box_module && box_module->attributes.count("\\abc9_flop");
for (auto &conn : mapped_cell->connections()) {
RTLIL::SigSpec newsig; RTLIL::SigSpec newsig;
for (auto c : conn.second.chunks()) { for (auto c : conn.second.chunks()) {
if (c.width == 0) if (c.width == 0)
@ -544,15 +486,17 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
} }
cell->setPort(conn.first, newsig); cell->setPort(conn.first, newsig);
if (!abc9_flop) {
if (cell->input(conn.first)) { if (cell->input(conn.first)) {
for (auto i : newsig) for (auto i : newsig)
bit2sinks[i].push_back(cell); bit2sinks[i].push_back(cell);
for (auto i : conn.second) for (auto i : conn.second)
bit_users[i].insert(c->name); bit_users[i].insert(mapped_cell->name);
} }
if (cell->output(conn.first)) if (cell->output(conn.first))
for (auto i : conn.second) for (auto i : conn.second)
bit_drivers[i].insert(c->name); bit_drivers[i].insert(mapped_cell->name);
}
} }
} }
@ -787,10 +731,6 @@ struct Abc9TechmapPass : public Pass {
// log(" -keepff\n"); // log(" -keepff\n");
// log(" set the \"keep\" attribute on flip-flop output wires. (and thus preserve\n"); // log(" set the \"keep\" attribute on flip-flop output wires. (and thus preserve\n");
// log(" them, for example for equivalence checking.)\n"); // log(" them, for example for equivalence checking.)\n");
// log("\n");
// log(" -nocleanup\n");
// log(" when this option is used, the temporary files created by this pass\n");
// log(" are not removed. this is useful for debugging.\n");
// log("\n"); // log("\n");
log(" -showtmp\n"); log(" -showtmp\n");
log(" print the temp dir name in log. usually this is suppressed so that the\n"); log(" print the temp dir name in log. usually this is suppressed so that the\n");
@ -822,8 +762,6 @@ struct Abc9TechmapPass : public Pass {
log_header(design, "Executing ABC9_MAP pass (technology mapping using ABC9).\n"); log_header(design, "Executing ABC9_MAP pass (technology mapping using ABC9).\n");
log_push(); log_push();
assign_map.clear();
#ifdef ABCEXTERNAL #ifdef ABCEXTERNAL
std::string exe_file = ABCEXTERNAL; std::string exe_file = ABCEXTERNAL;
#else #else
@ -832,7 +770,7 @@ struct Abc9TechmapPass : public Pass {
std::string script_file, clk_str, box_file, lut_file; std::string script_file, clk_str, box_file, lut_file;
std::string delay_target, lutin_shared = "-S 1", wire_delay; std::string delay_target, lutin_shared = "-S 1", wire_delay;
std::string tempdir_name; std::string tempdir_name;
bool fast_mode = false, dff_mode = false, keepff = false /*, cleanup = true*/; bool fast_mode = false;
bool show_tempdir = false; bool show_tempdir = false;
bool nomfs = false; bool nomfs = false;
vector<int> lut_costs; vector<int> lut_costs;
@ -923,23 +861,6 @@ struct Abc9TechmapPass : public Pass {
fast_mode = true; fast_mode = true;
continue; continue;
} }
//if (arg == "-dff") {
// dff_mode = true;
// continue;
//}
//if (arg == "-clk" && argidx+1 < args.size()) {
// clk_str = args[++argidx];
// dff_mode = true;
// continue;
//}
//if (arg == "-keepff") {
// keepff = true;
// continue;
//}
//if (arg == "-nocleanup") {
// cleanup = false;
// continue;
//}
if (arg == "-showtmp") { if (arg == "-showtmp") {
show_tempdir = true; show_tempdir = true;
continue; continue;
@ -1040,173 +961,59 @@ struct Abc9TechmapPass : public Pass {
} }
} }
for (auto mod : design->selected_modules()) SigMap assign_map;
{
if (mod->attributes.count(ID(abc9_box_id)))
continue;
if (mod->processes.size() > 0) {
log("Skipping module %s as it contains processes.\n", log_id(mod));
continue;
}
assign_map.set(mod);
if (!dff_mode || !clk_str.empty()) {
abc9_module(design, mod, script_file, exe_file, /*cleanup,*/ lut_costs, dff_mode, clk_str, keepff,
delay_target, lutin_shared, fast_mode, show_tempdir,
box_file, lut_file, wire_delay, box_lookup, nomfs, tempdir_name);
continue;
}
CellTypes ct(design); CellTypes ct(design);
for (auto module : design->selected_modules())
std::vector<RTLIL::Cell*> all_cells = mod->selected_cells();
std::set<RTLIL::Cell*> unassigned_cells(all_cells.begin(), all_cells.end());
std::set<RTLIL::Cell*> expand_queue, next_expand_queue;
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;
std::map<clkdomain_t, std::vector<RTLIL::Cell*>> assigned_cells;
std::map<RTLIL::Cell*, clkdomain_t> assigned_cells_reverse;
std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_bit, cell_to_bit_up, cell_to_bit_down;
std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> bit_to_cell, bit_to_cell_up, bit_to_cell_down;
for (auto cell : all_cells)
{ {
clkdomain_t key; if (module->attributes.count(ID(abc9_box_id)))
for (auto &conn : cell->connections())
for (auto bit : conn.second) {
bit = assign_map(bit);
if (bit.wire != nullptr) {
cell_to_bit[cell].insert(bit);
bit_to_cell[bit].insert(cell);
if (ct.cell_input(cell->type, conn.first)) {
cell_to_bit_up[cell].insert(bit);
bit_to_cell_down[bit].insert(cell);
}
if (ct.cell_output(cell->type, conn.first)) {
cell_to_bit_down[cell].insert(bit);
bit_to_cell_up[bit].insert(cell);
}
}
}
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
continue; continue;
unassigned_cells.erase(cell); if (module->processes.size() > 0) {
expand_queue.insert(cell); log("Skipping module %s as it contains processes.\n", log_id(module));
expand_queue_up.insert(cell); continue;
expand_queue_down.insert(cell);
assigned_cells[key].push_back(cell);
assigned_cells_reverse[cell] = key;
} }
while (!expand_queue_up.empty() || !expand_queue_down.empty()) assign_map.set(module);
{
if (!expand_queue_up.empty())
{
RTLIL::Cell *cell = *expand_queue_up.begin();
clkdomain_t key = assigned_cells_reverse.at(cell);
expand_queue_up.erase(cell);
for (auto bit : cell_to_bit_up[cell]) typedef SigSpec clkdomain_t;
for (auto c : bit_to_cell_up[bit]) dict<clkdomain_t, int> clk_to_mergeability;
if (unassigned_cells.count(c)) {
unassigned_cells.erase(c); const std::vector<RTLIL::Cell*> all_cells = module->selected_cells();
next_expand_queue_up.insert(c);
assigned_cells[key].push_back(c); for (auto cell : all_cells) {
assigned_cells_reverse[c] = key; auto inst_module = design->module(cell->type);
expand_queue.insert(c); if (!inst_module || !inst_module->attributes.count("\\abc9_flop")
} || cell->get_bool_attribute("\\abc9_keep"))
continue;
Wire *abc9_clock_wire = module->wire(stringf("%s.$abc9_clock", cell->name.c_str()));
if (abc9_clock_wire == NULL)
log_error("'%s$abc9_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 YS_ATTRIBUTE(unused) = cell->attributes.insert(std::make_pair(ID(abc9_mergeability), r.first->second));
log_assert(r2.second);
Wire *abc9_init_wire = module->wire(stringf("%s.$abc9_init", cell->name.c_str()));
if (abc9_init_wire == NULL)
log_error("'%s.$abc9_init' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module));
log_assert(GetSize(abc9_init_wire) == 1);
SigSpec abc9_init = assign_map(abc9_init_wire);
if (!abc9_init.is_fully_const())
log_error("'%s.$abc9_init' is not a constant wire present in module '%s'.\n", cell->name.c_str(), log_id(module));
r2 = cell->attributes.insert(std::make_pair(ID(abc9_init), abc9_init.as_const()));
log_assert(r2.second);
} }
if (!expand_queue_down.empty()) design->selected_active_module = module->name.str();
{ abc9_module(design, module, script_file, exe_file, lut_costs,
RTLIL::Cell *cell = *expand_queue_down.begin(); delay_target, lutin_shared, fast_mode, all_cells, show_tempdir,
clkdomain_t key = assigned_cells_reverse.at(cell);
expand_queue_down.erase(cell);
for (auto bit : cell_to_bit_down[cell])
for (auto c : bit_to_cell_down[bit])
if (unassigned_cells.count(c)) {
unassigned_cells.erase(c);
next_expand_queue_up.insert(c);
assigned_cells[key].push_back(c);
assigned_cells_reverse[c] = key;
expand_queue.insert(c);
}
}
if (expand_queue_up.empty() && expand_queue_down.empty()) {
expand_queue_up.swap(next_expand_queue_up);
expand_queue_down.swap(next_expand_queue_down);
}
}
while (!expand_queue.empty())
{
RTLIL::Cell *cell = *expand_queue.begin();
clkdomain_t key = assigned_cells_reverse.at(cell);
expand_queue.erase(cell);
for (auto bit : cell_to_bit.at(cell)) {
for (auto c : bit_to_cell[bit])
if (unassigned_cells.count(c)) {
unassigned_cells.erase(c);
next_expand_queue.insert(c);
assigned_cells[key].push_back(c);
assigned_cells_reverse[c] = key;
}
bit_to_cell[bit].clear();
}
if (expand_queue.empty())
expand_queue.swap(next_expand_queue);
}
clkdomain_t key(true, RTLIL::SigSpec(), true, RTLIL::SigSpec());
for (auto cell : unassigned_cells) {
assigned_cells[key].push_back(cell);
assigned_cells_reverse[cell] = key;
}
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),
std::get<0>(it.first) ? "" : "!", log_signal(std::get<1>(it.first)),
std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(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));
abc9_module(design, mod, script_file, exe_file, /*cleanup,*/ lut_costs, !clk_sig.empty(), "$",
keepff, delay_target, lutin_shared, fast_mode, show_tempdir,
box_file, lut_file, wire_delay, box_lookup, nomfs, tempdir_name); box_file, lut_file, wire_delay, box_lookup, nomfs, tempdir_name);
assign_map.set(mod); design->selected_active_module.clear();
} }
}
assign_map.clear();
log_pop(); log_pop();
} }

View File

@ -18,7 +18,449 @@
* *
*/ */
// ============================================================================ // The following techmapping rules are intended to be run (with -max_iter 1)
// before invoking the `abc9` pass in order to transform the design into
// a format that it understands.
//
// 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 --|$__ABC_FF_|--+-->> Q
// $abc9_currQ +-->>-----< > || +----------+ |
// | || \/\/\/\/ || |
// | || || |
// | ++==================++ |
// | |
// +----------------------------------------------+
//
// 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 _TECHMAP_REPLACE_.$abc9_clock wire to capture its clock
// domain and polarity (used when partitioning the module so that `abc9' only
// performs sequential synthesis (with reachability analysis) correctly on
// one domain at a time) and also used to infer the optional delay target
// from the (* abc9_clock_period = %d *) attribute attached to any wire
// within
// (d) a special _TECHMAP_REPLACE_.$abc9_init wire to encode the flop's initial
// state
// (e) a special _TECHMAP_REPLACE_.$abc9_currQ wire that will be used for feedback
// into the (combinatorial) FD* cell to facilitate clock-enable behaviour
//
// In order to perform sequential synthesis, `abc9' also requires that
// the initial value of all flops be zero.
module FDRE (output Q, 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;
`ifdef DFF_MODE
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_FF_ abc_dff (.D($Q), .Q(QQ));
// Special signals
wire [1:0] _TECHMAP_REPLACE_.$abc9_clock = {C, IS_C_INVERTED};
wire [0:0] _TECHMAP_REPLACE_.$abc9_init = 1'b0;
wire [0:0] _TECHMAP_REPLACE_.$abc9_currQ = QQ;
`else
(* abc9_keep *)
FDRE #(
.INIT(INIT),
.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)
);
`endif
endmodule
module FDRE_1 (output Q, input C, CE, D, R);
parameter [0:0] INIT = 1'b0;
`ifdef DFF_MODE
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_FF_ abc_dff (.D($Q), .Q(QQ));
// Special signals
wire [1:0] _TECHMAP_REPLACE_.$abc9_clock = {C, 1'b1 /* IS_C_INVERTED */};
wire [0:0] _TECHMAP_REPLACE_.$abc9_init = 1'b0;
wire [0:0] _TECHMAP_REPLACE_.$abc9_currQ = QQ;
`else
(* abc9_keep *)
FDRE_1 #(
.INIT(INIT)
) _TECHMAP_REPLACE_ (
.D(D), .Q(Q), .C(C), .CE(CE), .R(R)
);
`endif
endmodule
module FDCE (output Q, 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;
`ifdef DFF_MODE
wire QQ, $Q, $abc9_currQ;
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_ASYNC0 abc_async (.A($abc9_currQ), .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_ASYNC1 abc_async (.A($abc9_currQ), .S(CLR ^ IS_CLR_INVERTED), .Y(QQ));
end endgenerate
$__ABC9_FF_ abc_dff (.D($Q), .Q($abc9_currQ));
// Special signals
wire [1:0] _TECHMAP_REPLACE_.$abc9_clock = {C, IS_C_INVERTED};
wire [0:0] _TECHMAP_REPLACE_.$abc9_init = 1'b0;
wire [0:0] _TECHMAP_REPLACE_.$abc9_currQ = $abc9_currQ;
`else
(* abc9_keep *)
FDCE #(
.INIT(INIT),
.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)
);
`endif
endmodule
module FDCE_1 (output Q, input C, CE, D, CLR);
parameter [0:0] INIT = 1'b0;
`ifdef DFF_MODE
wire QQ, $Q, $abc9_currQ;
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($abc9_currQ), .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($abc9_currQ), .S(CLR), .Y(QQ));
end endgenerate
$__ABC9_FF_ abc_dff (.D($Q), .Q($abc9_currQ));
// Special signals
wire [1:0] _TECHMAP_REPLACE_.$abc9_clock = {C, 1'b1 /* IS_C_INVERTED */};
wire [0:0] _TECHMAP_REPLACE_.$abc9_init = 1'b0;
wire [0:0] _TECHMAP_REPLACE_.$abc9_currQ = $abc9_currQ;
`else
(* abc9_keep *)
FDCE_1 #(
.INIT(INIT)
) _TECHMAP_REPLACE_ (
.D(D), .Q(Q), .C(C), .CE(CE), .CLR(CLR)
);
`endif
endmodule
module FDPE (output Q, 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;
`ifdef DFF_MODE
wire QQ, $Q, $abc9_currQ;
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($abc9_currQ), .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($abc9_currQ), .S(PRE ^ IS_PRE_INVERTED), .Y(QQ));
end endgenerate
$__ABC9_FF_ abc_dff (.D($Q), .Q($abc9_currQ));
// Special signals
wire [1:0] _TECHMAP_REPLACE_.$abc9_clock = {C, IS_C_INVERTED};
wire [0:0] _TECHMAP_REPLACE_.$abc9_init = 1'b0;
wire [0:0] _TECHMAP_REPLACE_.$abc9_currQ = $abc9_currQ;
`else
(* abc9_keep *)
FDPE #(
.INIT(INIT),
.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)
);
`endif
endmodule
module FDPE_1 (output Q, input C, CE, D, PRE);
parameter [0:0] INIT = 1'b1;
`ifdef DFF_MODE
wire QQ, $Q, $abc9_currQ;
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($abc9_currQ), .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($abc9_currQ), .S(PRE), .Y(QQ));
end endgenerate
$__ABC9_FF_ abc_dff (.D($Q), .Q($abc9_currQ));
// Special signals
wire [1:0] _TECHMAP_REPLACE_.$abc9_clock = {C, 1'b1 /* IS_C_INVERTED */};
wire [0:0] _TECHMAP_REPLACE_.$abc9_init = 1'b0;
wire [0:0] _TECHMAP_REPLACE_.$abc9_currQ = $abc9_currQ;
`else
(* abc9_keep *)
FDPE_1 #(
.INIT(INIT)
) _TECHMAP_REPLACE_ (
.D(D), .Q(Q), .C(C), .CE(CE), .PRE(PRE)
);
`endif
endmodule
module FDSE (output Q, 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;
`ifdef DFF_MODE
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_FF_ abc_dff (.D($Q), .Q(QQ));
// Special signals
wire [1:0] _TECHMAP_REPLACE_.$abc9_clock = {C, IS_C_INVERTED};
wire [0:0] _TECHMAP_REPLACE_.$abc9_init = 1'b0;
wire [0:0] _TECHMAP_REPLACE_.$abc9_currQ = QQ;
`else
(* abc9_keep *)
FDSE #(
.INIT(INIT),
.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)
);
`endif
endmodule
module FDSE_1 (output Q, input C, CE, D, S);
parameter [0:0] INIT = 1'b1;
`ifdef DFF_MODE
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_FF_ abc_dff (.D($Q), .Q(QQ));
// Special signals
wire [1:0] _TECHMAP_REPLACE_.$abc9_clock = {C, 1'b1 /* IS_C_INVERTED */};
wire [0:0] _TECHMAP_REPLACE_.$abc9_init = 1'b0;
wire [0:0] _TECHMAP_REPLACE_.$abc9_currQ = QQ;
`else
(* abc9_keep *)
FDSE_1 #(
.INIT(INIT)
) _TECHMAP_REPLACE_ (
.D(D), .Q(Q), .C(C), .CE(CE), .S(S)
);
`endif
endmodule
module RAM32X1D ( module RAM32X1D (
output DPO, SPO, output DPO, SPO,
@ -30,17 +472,17 @@ module RAM32X1D (
); );
parameter INIT = 32'h0; parameter INIT = 32'h0;
parameter IS_WCLK_INVERTED = 1'b0; parameter IS_WCLK_INVERTED = 1'b0;
wire \$DPO , \$SPO ; wire $DPO, $SPO;
RAM32X1D #( RAM32X1D #(
.INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED) .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED)
) _TECHMAP_REPLACE_ ( ) _TECHMAP_REPLACE_ (
.DPO(\$DPO ), .SPO(\$SPO ), .DPO($DPO), .SPO($SPO),
.D(D), .WCLK(WCLK), .WE(WE), .D(D), .WCLK(WCLK), .WE(WE),
.A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4), .A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4),
.DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4) .DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4)
); );
\$__ABC9_LUT6 spo (.A(\$SPO ), .S({1'b1, A4, A3, A2, A1, A0}), .Y(SPO)); $__ABC9_LUT6 spo (.A($SPO), .S({1'b1, A4, A3, A2, A1, A0}), .Y(SPO));
\$__ABC9_LUT6 dpo (.A(\$DPO ), .S({1'b1, DPRA4, DPRA3, DPRA2, DPRA1, DPRA0}), .Y(DPO)); $__ABC9_LUT6 dpo (.A($DPO), .S({1'b1, DPRA4, DPRA3, DPRA2, DPRA1, DPRA0}), .Y(DPO));
endmodule endmodule
module RAM64X1D ( module RAM64X1D (
@ -53,17 +495,17 @@ module RAM64X1D (
); );
parameter INIT = 64'h0; parameter INIT = 64'h0;
parameter IS_WCLK_INVERTED = 1'b0; parameter IS_WCLK_INVERTED = 1'b0;
wire \$DPO , \$SPO ; wire $DPO, $SPO;
RAM64X1D #( RAM64X1D #(
.INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED) .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED)
) _TECHMAP_REPLACE_ ( ) _TECHMAP_REPLACE_ (
.DPO(\$DPO ), .SPO(\$SPO ), .DPO($DPO), .SPO($SPO),
.D(D), .WCLK(WCLK), .WE(WE), .D(D), .WCLK(WCLK), .WE(WE),
.A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4), .A5(A5), .A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4), .A5(A5),
.DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4), .DPRA5(DPRA5) .DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4), .DPRA5(DPRA5)
); );
\$__ABC9_LUT6 spo (.A(\$SPO ), .S({A5, A4, A3, A2, A1, A0}), .Y(SPO)); $__ABC9_LUT6 spo (.A($SPO), .S({A5, A4, A3, A2, A1, A0}), .Y(SPO));
\$__ABC9_LUT6 dpo (.A(\$DPO ), .S({DPRA5, DPRA4, DPRA3, DPRA2, DPRA1, DPRA0}), .Y(DPO)); $__ABC9_LUT6 dpo (.A($DPO), .S({DPRA5, DPRA4, DPRA3, DPRA2, DPRA1, DPRA0}), .Y(DPO));
endmodule endmodule
module RAM128X1D ( module RAM128X1D (
@ -75,17 +517,17 @@ module RAM128X1D (
); );
parameter INIT = 128'h0; parameter INIT = 128'h0;
parameter IS_WCLK_INVERTED = 1'b0; parameter IS_WCLK_INVERTED = 1'b0;
wire \$DPO , \$SPO ; wire $DPO, $SPO;
RAM128X1D #( RAM128X1D #(
.INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED) .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED)
) _TECHMAP_REPLACE_ ( ) _TECHMAP_REPLACE_ (
.DPO(\$DPO ), .SPO(\$SPO ), .DPO($DPO), .SPO($SPO),
.D(D), .WCLK(WCLK), .WE(WE), .D(D), .WCLK(WCLK), .WE(WE),
.A(A), .A(A),
.DPRA(DPRA) .DPRA(DPRA)
); );
\$__ABC9_LUT7 spo (.A(\$SPO ), .S(A), .Y(SPO)); $__ABC9_LUT7 spo (.A($SPO), .S(A), .Y(SPO));
\$__ABC9_LUT7 dpo (.A(\$DPO ), .S(DPRA), .Y(DPO)); $__ABC9_LUT7 dpo (.A($DPO), .S(DPRA), .Y(DPO));
endmodule endmodule
module RAM32M ( module RAM32M (
@ -109,24 +551,24 @@ module RAM32M (
parameter [63:0] INIT_C = 64'h0000000000000000; parameter [63:0] INIT_C = 64'h0000000000000000;
parameter [63:0] INIT_D = 64'h0000000000000000; parameter [63:0] INIT_D = 64'h0000000000000000;
parameter [0:0] IS_WCLK_INVERTED = 1'b0; parameter [0:0] IS_WCLK_INVERTED = 1'b0;
wire [1:0] \$DOA , \$DOB , \$DOC , \$DOD ; wire [1:0] $DOA, $DOB, $DOC, $DOD;
RAM32M #( RAM32M #(
.INIT_A(INIT_A), .INIT_B(INIT_B), .INIT_C(INIT_C), .INIT_D(INIT_D), .INIT_A(INIT_A), .INIT_B(INIT_B), .INIT_C(INIT_C), .INIT_D(INIT_D),
.IS_WCLK_INVERTED(IS_WCLK_INVERTED) .IS_WCLK_INVERTED(IS_WCLK_INVERTED)
) _TECHMAP_REPLACE_ ( ) _TECHMAP_REPLACE_ (
.DOA(\$DOA ), .DOB(\$DOB ), .DOC(\$DOC ), .DOD(\$DOD ), .DOA($DOA), .DOB($DOB), .DOC($DOC), .DOD($DOD),
.WCLK(WCLK), .WE(WE), .WCLK(WCLK), .WE(WE),
.ADDRA(ADDRA), .ADDRB(ADDRB), .ADDRC(ADDRC), .ADDRD(ADDRD), .ADDRA(ADDRA), .ADDRB(ADDRB), .ADDRC(ADDRC), .ADDRD(ADDRD),
.DIA(DIA), .DIB(DIB), .DIC(DIC), .DID(DID) .DIA(DIA), .DIB(DIB), .DIC(DIC), .DID(DID)
); );
\$__ABC9_LUT6 doa0 (.A(\$DOA [0]), .S({1'b1, ADDRA}), .Y(DOA[0])); $__ABC9_LUT6 doa0 (.A($DOA[0]), .S({1'b1, ADDRA}), .Y(DOA[0]));
\$__ABC9_LUT6 doa1 (.A(\$DOA [1]), .S({1'b1, ADDRA}), .Y(DOA[1])); $__ABC9_LUT6 doa1 (.A($DOA[1]), .S({1'b1, ADDRA}), .Y(DOA[1]));
\$__ABC9_LUT6 dob0 (.A(\$DOB [0]), .S({1'b1, ADDRB}), .Y(DOB[0])); $__ABC9_LUT6 dob0 (.A($DOB[0]), .S({1'b1, ADDRB}), .Y(DOB[0]));
\$__ABC9_LUT6 dob1 (.A(\$DOB [1]), .S({1'b1, ADDRB}), .Y(DOB[1])); $__ABC9_LUT6 dob1 (.A($DOB[1]), .S({1'b1, ADDRB}), .Y(DOB[1]));
\$__ABC9_LUT6 doc0 (.A(\$DOC [0]), .S({1'b1, ADDRC}), .Y(DOC[0])); $__ABC9_LUT6 doc0 (.A($DOC[0]), .S({1'b1, ADDRC}), .Y(DOC[0]));
\$__ABC9_LUT6 doc1 (.A(\$DOC [1]), .S({1'b1, ADDRC}), .Y(DOC[1])); $__ABC9_LUT6 doc1 (.A($DOC[1]), .S({1'b1, ADDRC}), .Y(DOC[1]));
\$__ABC9_LUT6 dod0 (.A(\$DOD [0]), .S({1'b1, ADDRD}), .Y(DOD[0])); $__ABC9_LUT6 dod0 (.A($DOD[0]), .S({1'b1, ADDRD}), .Y(DOD[0]));
\$__ABC9_LUT6 dod1 (.A(\$DOD [1]), .S({1'b1, ADDRD}), .Y(DOD[1])); $__ABC9_LUT6 dod1 (.A($DOD[1]), .S({1'b1, ADDRD}), .Y(DOD[1]));
endmodule endmodule
module RAM64M ( module RAM64M (
@ -150,20 +592,20 @@ module RAM64M (
parameter [63:0] INIT_C = 64'h0000000000000000; parameter [63:0] INIT_C = 64'h0000000000000000;
parameter [63:0] INIT_D = 64'h0000000000000000; parameter [63:0] INIT_D = 64'h0000000000000000;
parameter [0:0] IS_WCLK_INVERTED = 1'b0; parameter [0:0] IS_WCLK_INVERTED = 1'b0;
wire \$DOA , \$DOB , \$DOC , \$DOD ; wire $DOA, $DOB, $DOC, $DOD;
RAM64M #( RAM64M #(
.INIT_A(INIT_A), .INIT_B(INIT_B), .INIT_C(INIT_C), .INIT_D(INIT_D), .INIT_A(INIT_A), .INIT_B(INIT_B), .INIT_C(INIT_C), .INIT_D(INIT_D),
.IS_WCLK_INVERTED(IS_WCLK_INVERTED) .IS_WCLK_INVERTED(IS_WCLK_INVERTED)
) _TECHMAP_REPLACE_ ( ) _TECHMAP_REPLACE_ (
.DOA(\$DOA ), .DOB(\$DOB ), .DOC(\$DOC ), .DOD(\$DOD ), .DOA($DOA), .DOB($DOB), .DOC($DOC), .DOD($DOD),
.WCLK(WCLK), .WE(WE), .WCLK(WCLK), .WE(WE),
.ADDRA(ADDRA), .ADDRB(ADDRB), .ADDRC(ADDRC), .ADDRD(ADDRD), .ADDRA(ADDRA), .ADDRB(ADDRB), .ADDRC(ADDRC), .ADDRD(ADDRD),
.DIA(DIA), .DIB(DIB), .DIC(DIC), .DID(DID) .DIA(DIA), .DIB(DIB), .DIC(DIC), .DID(DID)
); );
\$__ABC9_LUT6 doa (.A(\$DOA ), .S(ADDRA), .Y(DOA)); $__ABC9_LUT6 doa (.A($DOA), .S(ADDRA), .Y(DOA));
\$__ABC9_LUT6 dob (.A(\$DOB ), .S(ADDRB), .Y(DOB)); $__ABC9_LUT6 dob (.A($DOB), .S(ADDRB), .Y(DOB));
\$__ABC9_LUT6 doc (.A(\$DOC ), .S(ADDRC), .Y(DOC)); $__ABC9_LUT6 doc (.A($DOC), .S(ADDRC), .Y(DOC));
\$__ABC9_LUT6 dod (.A(\$DOD ), .S(ADDRD), .Y(DOD)); $__ABC9_LUT6 dod (.A($DOD), .S(ADDRD), .Y(DOD));
endmodule endmodule
module SRL16E ( module SRL16E (
@ -172,14 +614,14 @@ module SRL16E (
); );
parameter [15:0] INIT = 16'h0000; parameter [15:0] INIT = 16'h0000;
parameter [0:0] IS_CLK_INVERTED = 1'b0; parameter [0:0] IS_CLK_INVERTED = 1'b0;
wire \$Q ; wire $Q;
SRL16E #( SRL16E #(
.INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED) .INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED)
) _TECHMAP_REPLACE_ ( ) _TECHMAP_REPLACE_ (
.Q(\$Q ), .Q($Q),
.A0(A0), .A1(A1), .A2(A2), .A3(A3), .CE(CE), .CLK(CLK), .D(D) .A0(A0), .A1(A1), .A2(A2), .A3(A3), .CE(CE), .CLK(CLK), .D(D)
); );
\$__ABC9_LUT6 q (.A(\$Q ), .S({1'b1, A3, A2, A1, A0, 1'b1}), .Y(Q)); $__ABC9_LUT6 q (.A($Q), .S({1'b1, A3, A2, A1, A0, 1'b1}), .Y(Q));
endmodule endmodule
module SRLC32E ( module SRLC32E (
@ -190,14 +632,14 @@ module SRLC32E (
); );
parameter [31:0] INIT = 32'h00000000; parameter [31:0] INIT = 32'h00000000;
parameter [0:0] IS_CLK_INVERTED = 1'b0; parameter [0:0] IS_CLK_INVERTED = 1'b0;
wire \$Q ; wire $Q;
SRLC32E #( SRLC32E #(
.INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED) .INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED)
) _TECHMAP_REPLACE_ ( ) _TECHMAP_REPLACE_ (
.Q(\$Q ), .Q31(Q31), .Q($Q), .Q31(Q31),
.A(A), .CE(CE), .CLK(CLK), .D(D) .A(A), .CE(CE), .CLK(CLK), .D(D)
); );
\$__ABC9_LUT6 q (.A(\$Q ), .S({1'b1, A}), .Y(Q)); $__ABC9_LUT6 q (.A($Q), .S({1'b1, A}), .Y(Q));
endmodule endmodule
module DSP48E1 ( module DSP48E1 (
@ -386,15 +828,15 @@ __CELL__ #(
if (AREG == 0 && MREG == 0 && PREG == 0) if (AREG == 0 && MREG == 0 && PREG == 0)
assign iA = A, pA = 1'bx; assign iA = A, pA = 1'bx;
else else
\$__ABC9_REG #(.WIDTH(30)) rA (.I(A), .O(iA), .Q(pA)); $__ABC9_REG #(.WIDTH(30)) rA (.I(A), .O(iA), .Q(pA));
if (BREG == 0 && MREG == 0 && PREG == 0) if (BREG == 0 && MREG == 0 && PREG == 0)
assign iB = B, pB = 1'bx; assign iB = B, pB = 1'bx;
else else
\$__ABC9_REG #(.WIDTH(18)) rB (.I(B), .O(iB), .Q(pB)); $__ABC9_REG #(.WIDTH(18)) rB (.I(B), .O(iB), .Q(pB));
if (CREG == 0 && PREG == 0) if (CREG == 0 && PREG == 0)
assign iC = C, pC = 1'bx; assign iC = C, pC = 1'bx;
else else
\$__ABC9_REG #(.WIDTH(48)) rC (.I(C), .O(iC), .Q(pC)); $__ABC9_REG #(.WIDTH(48)) rC (.I(C), .O(iC), .Q(pC));
if (DREG == 0) if (DREG == 0)
assign iD = D; assign iD = D;
else if (techmap_guard) else if (techmap_guard)
@ -405,27 +847,27 @@ __CELL__ #(
assign pAD = 1'bx; assign pAD = 1'bx;
if (PREG == 0) begin if (PREG == 0) begin
if (MREG == 1) if (MREG == 1)
\$__ABC9_REG rM (.Q(pM)); $__ABC9_REG rM (.Q(pM));
else else
assign pM = 1'bx; assign pM = 1'bx;
assign pP = 1'bx; assign pP = 1'bx;
end else begin end else begin
assign pM = 1'bx; assign pM = 1'bx;
\$__ABC9_REG rP (.Q(pP)); $__ABC9_REG rP (.Q(pP));
end end
if (MREG == 0 && PREG == 0) if (MREG == 0 && PREG == 0)
assign mP = oP, mPCOUT = oPCOUT; assign mP = oP, mPCOUT = oPCOUT;
else else
assign mP = 1'bx, mPCOUT = 1'bx; assign mP = 1'bx, mPCOUT = 1'bx;
\$__ABC9_DSP48E1_MULT_P_MUX muxP ( $__ABC9_DSP48E1_MULT_P_MUX muxP (
.Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oP), .Mq(pM), .P(mP), .Pq(pP), .O(P) .Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oP), .Mq(pM), .P(mP), .Pq(pP), .O(P)
); );
\$__ABC9_DSP48E1_MULT_PCOUT_MUX muxPCOUT ( $__ABC9_DSP48E1_MULT_PCOUT_MUX muxPCOUT (
.Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oPCOUT), .Mq(pM), .P(mPCOUT), .Pq(pP), .O(PCOUT) .Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oPCOUT), .Mq(pM), .P(mPCOUT), .Pq(pP), .O(PCOUT)
); );
`DSP48E1_INST(\$__ABC9_DSP48E1_MULT ) `DSP48E1_INST($__ABC9_DSP48E1_MULT )
end end
else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") begin else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") begin
// Disconnect the A-input if MREG is enabled, since // Disconnect the A-input if MREG is enabled, since
@ -433,26 +875,26 @@ __CELL__ #(
if (AREG == 0 && ADREG == 0 && MREG == 0 && PREG == 0) if (AREG == 0 && ADREG == 0 && MREG == 0 && PREG == 0)
assign iA = A, pA = 1'bx; assign iA = A, pA = 1'bx;
else else
\$__ABC9_REG #(.WIDTH(30)) rA (.I(A), .O(iA), .Q(pA)); $__ABC9_REG #(.WIDTH(30)) rA (.I(A), .O(iA), .Q(pA));
if (BREG == 0 && MREG == 0 && PREG == 0) if (BREG == 0 && MREG == 0 && PREG == 0)
assign iB = B, pB = 1'bx; assign iB = B, pB = 1'bx;
else else
\$__ABC9_REG #(.WIDTH(18)) rB (.I(B), .O(iB), .Q(pB)); $__ABC9_REG #(.WIDTH(18)) rB (.I(B), .O(iB), .Q(pB));
if (CREG == 0 && PREG == 0) if (CREG == 0 && PREG == 0)
assign iC = C, pC = 1'bx; assign iC = C, pC = 1'bx;
else else
\$__ABC9_REG #(.WIDTH(48)) rC (.I(C), .O(iC), .Q(pC)); $__ABC9_REG #(.WIDTH(48)) rC (.I(C), .O(iC), .Q(pC));
if (DREG == 0 && ADREG == 0) if (DREG == 0 && ADREG == 0)
assign iD = D, pD = 1'bx; assign iD = D, pD = 1'bx;
else else
\$__ABC9_REG #(.WIDTH(25)) rD (.I(D), .O(iD), .Q(pD)); $__ABC9_REG #(.WIDTH(25)) rD (.I(D), .O(iD), .Q(pD));
if (PREG == 0) begin if (PREG == 0) begin
if (MREG == 1) begin if (MREG == 1) begin
assign pAD = 1'bx; assign pAD = 1'bx;
\$__ABC9_REG rM (.Q(pM)); $__ABC9_REG rM (.Q(pM));
end else begin end else begin
if (ADREG == 1) if (ADREG == 1)
\$__ABC9_REG rAD (.Q(pAD)); $__ABC9_REG rAD (.Q(pAD));
else else
assign pAD = 1'bx; assign pAD = 1'bx;
assign pM = 1'bx; assign pM = 1'bx;
@ -460,21 +902,21 @@ __CELL__ #(
assign pP = 1'bx; assign pP = 1'bx;
end else begin end else begin
assign pAD = 1'bx, pM = 1'bx; assign pAD = 1'bx, pM = 1'bx;
\$__ABC9_REG rP (.Q(pP)); $__ABC9_REG rP (.Q(pP));
end end
if (MREG == 0 && PREG == 0) if (MREG == 0 && PREG == 0)
assign mP = oP, mPCOUT = oPCOUT; assign mP = oP, mPCOUT = oPCOUT;
else else
assign mP = 1'bx, mPCOUT = 1'bx; assign mP = 1'bx, mPCOUT = 1'bx;
\$__ABC9_DSP48E1_MULT_DPORT_P_MUX muxP ( $__ABC9_DSP48E1_MULT_DPORT_P_MUX muxP (
.Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oP), .Mq(pM), .P(mP), .Pq(pP), .O(P) .Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oP), .Mq(pM), .P(mP), .Pq(pP), .O(P)
); );
\$__ABC9_DSP48E1_MULT_DPORT_PCOUT_MUX muxPCOUT ( $__ABC9_DSP48E1_MULT_DPORT_PCOUT_MUX muxPCOUT (
.Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oPCOUT), .Mq(pM), .P(mPCOUT), .Pq(pP), .O(PCOUT) .Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oPCOUT), .Mq(pM), .P(mPCOUT), .Pq(pP), .O(PCOUT)
); );
`DSP48E1_INST(\$__ABC9_DSP48E1_MULT_DPORT ) `DSP48E1_INST($__ABC9_DSP48E1_MULT_DPORT )
end end
else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") begin else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") begin
// Disconnect the A-input if MREG is enabled, since // Disconnect the A-input if MREG is enabled, since
@ -482,15 +924,15 @@ __CELL__ #(
if (AREG == 0 && PREG == 0) if (AREG == 0 && PREG == 0)
assign iA = A, pA = 1'bx; assign iA = A, pA = 1'bx;
else else
\$__ABC9_REG #(.WIDTH(30)) rA (.I(A), .O(iA), .Q(pA)); $__ABC9_REG #(.WIDTH(30)) rA (.I(A), .O(iA), .Q(pA));
if (BREG == 0 && PREG == 0) if (BREG == 0 && PREG == 0)
assign iB = B, pB = 1'bx; assign iB = B, pB = 1'bx;
else else
\$__ABC9_REG #(.WIDTH(18)) rB (.I(B), .O(iB), .Q(pB)); $__ABC9_REG #(.WIDTH(18)) rB (.I(B), .O(iB), .Q(pB));
if (CREG == 0 && PREG == 0) if (CREG == 0 && PREG == 0)
assign iC = C, pC = 1'bx; assign iC = C, pC = 1'bx;
else else
\$__ABC9_REG #(.WIDTH(48)) rC (.I(C), .O(iC), .Q(pC)); $__ABC9_REG #(.WIDTH(48)) rC (.I(C), .O(iC), .Q(pC));
if (DREG == 1 && techmap_guard) if (DREG == 1 && techmap_guard)
$error("Invalid DSP48E1 configuration: DREG enabled but USE_DPORT == \"FALSE\""); $error("Invalid DSP48E1 configuration: DREG enabled but USE_DPORT == \"FALSE\"");
assign pD = 1'bx; assign pD = 1'bx;
@ -501,7 +943,7 @@ __CELL__ #(
$error("Invalid DSP48E1 configuration: MREG enabled but USE_MULT == \"NONE\""); $error("Invalid DSP48E1 configuration: MREG enabled but USE_MULT == \"NONE\"");
assign pM = 1'bx; assign pM = 1'bx;
if (PREG == 1) if (PREG == 1)
\$__ABC9_REG rP (.Q(pP)); $__ABC9_REG rP (.Q(pP));
else else
assign pP = 1'bx; assign pP = 1'bx;
@ -509,14 +951,14 @@ __CELL__ #(
assign mP = oP, mPCOUT = oPCOUT; assign mP = oP, mPCOUT = oPCOUT;
else else
assign mP = 1'bx, mPCOUT = 1'bx; assign mP = 1'bx, mPCOUT = 1'bx;
\$__ABC9_DSP48E1_P_MUX muxP ( $__ABC9_DSP48E1_P_MUX muxP (
.Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oP), .Mq(pM), .P(mP), .Pq(pP), .O(P) .Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oP), .Mq(pM), .P(mP), .Pq(pP), .O(P)
); );
\$__ABC9_DSP48E1_PCOUT_MUX muxPCOUT ( $__ABC9_DSP48E1_PCOUT_MUX muxPCOUT (
.Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oPCOUT), .Mq(pM), .P(mPCOUT), .Pq(pP), .O(PCOUT) .Aq(pA), .Bq(pB), .Cq(pC), .Dq(pD), .ADq(pAD), .I(oPCOUT), .Mq(pM), .P(mPCOUT), .Pq(pP), .O(PCOUT)
); );
`DSP48E1_INST(\$__ABC9_DSP48E1 ) `DSP48E1_INST($__ABC9_DSP48E1 )
end end
else else
$error("Invalid DSP48E1 configuration"); $error("Invalid DSP48E1 configuration");

View File

@ -30,7 +30,22 @@ module \$__XILINX_MUXF78 (output O, input I0, I1, I2, I3, S0, S1);
: (S0 ? I1 : I0); : (S0 ? I1 : I0);
endmodule endmodule
// Box to emulate comb/seq behaviour of RAMD{32,64} and SRL{16,32} module \$__ABC9_FF_ (input D, output Q);
endmodule
// Box to emulate async behaviour of FDC*
(* abc_box_id = 1000 *)
module \$__ABC9_ASYNC0 (input A, S, output Y);
assign Y = S ? 1'b0 : A;
endmodule
// Box to emulate async behaviour of FDP*
(* abc_box_id = 1001 *)
module \$__ABC9_ASYNC1 (input A, S, output Y);
assign Y = S ? 1'b0 : A;
endmodule
// Box to emulate comb/seq behaviour of RAM{32,64} and SRL{16,32}
// Necessary since RAMD* and SRL* have both combinatorial (i.e. // Necessary since RAMD* and SRL* have both combinatorial (i.e.
// same-cycle read operation) and sequential (write operation // same-cycle read operation) and sequential (write operation
// is only committed on the next clock edge). // is only committed on the next clock edge).
@ -39,7 +54,7 @@ endmodule
(* abc9_box_id=2000 *) (* abc9_box_id=2000 *)
module \$__ABC9_LUT6 (input A, input [5:0] S, output Y); module \$__ABC9_LUT6 (input A, input [5:0] S, output Y);
endmodule endmodule
// Box to emulate comb/seq behaviour of RAMD128 // Box to emulate comb/seq behaviour of RAM128
(* abc9_box_id=2001 *) (* abc9_box_id=2001 *)
module \$__ABC9_LUT7 (input A, input [6:0] S, output Y); module \$__ABC9_LUT7 (input A, input [6:0] S, output Y);
endmodule endmodule

View File

@ -20,6 +20,15 @@
// ============================================================================ // ============================================================================
(* techmap_celltype = "$__ABC9_ASYNC0 $__ABC9_ASYNC1" *)
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_LUT6 (input A, input [5:0] S, output Y); module \$__ABC9_LUT6 (input A, input [5:0] S, output Y);
assign Y = A; assign Y = A;
endmodule endmodule

View File

@ -41,6 +41,72 @@ CARRY4 4 1 10 8
592 540 520 356 - 512 548 292 - 228 592 540 520 356 - 512 548 292 - 228
580 526 507 398 385 508 528 378 380 114 580 526 507 398 385 508 528 378 380 114
# Box to emulate async behaviour of FDC*
# Inputs: A S
# Outputs: Y
$__ABC9_ASYNC0 1000 1 2 1
0 764
# Box to emulate async behaviour of FDP*
# Inputs: A S
# Outputs: Y
$__ABC9_ASYNC1 1001 1 2 1
0 764
# Max delays from https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L237-L251
# https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L265-L277
# NB: Inputs/Outputs must be ordered alphabetically
# (with exception for \$currQ)
# Inputs: C CE D R \$currQ
# Outputs: Q
FDRE 1100 1 5 1
#0 109 -46 404 0
0 109 0 404 0 # Clamp -46ps Tsu
# Inputs: C CE D R \$currQ
# Outputs: Q
FDRE_1 1101 1 5 1
#0 109 0 -46 404
0 109 0 0 404 # Clamp -46ps Tsu
# Inputs: C CE CLR D \$currQ
# Outputs: Q
FDCE 1102 1 5 1
#0 109 764 -46 0
0 109 764 0 0 # Clamp -46ps Tsu
# Inputs: C CE CLR D \$currQ
# Outputs: Q
FDCE_1 1103 1 5 1
#0 109 764 -46 0
0 109 764 0 0 # Clamp -46ps Tsu
# Inputs: C CE D PRE \$currQ
# Outputs: Q
FDPE 1104 1 5 1
#0 109 -46 764 0
0 109 0 764 0 # Clamp -46ps Tsu
# Inputs: C CE D PRE \$currQ
# Outputs: Q
FDPE_1 1105 1 5 1
#0 109 -46 764 0
0 109 0 764 0 # Clamp -46ps Tsu
# Inputs: C CE D S \$currQ
# Outputs: Q
FDSE 1106 1 5 1
#0 109 -46 446 0
0 109 0 446 0 # Clamp -46ps Tsu
# Inputs: C CE D S \$currQ
# Outputs: Q
FDSE_1 1107 1 5 1
#0 109 -46 446 0
0 109 0 446 0 # Clamp -46ps Tsu
# SLICEM/A6LUT # SLICEM/A6LUT
# Box to emulate comb/seq behaviour of RAMD{32,64} and SRL{16,32} # Box to emulate comb/seq behaviour of RAMD{32,64} and SRL{16,32}
# Necessary since RAMD* and SRL* have both combinatorial (i.e. # Necessary since RAMD* and SRL* have both combinatorial (i.e.
@ -56,7 +122,7 @@ $__ABC9_LUT6 2000 0 7 1
# SLICEM/A6LUT + F7BMUX # SLICEM/A6LUT + F7BMUX
# Box to emulate comb/seq behaviour of RAMD128 # Box to emulate comb/seq behaviour of RAMD128
# Inputs: A S0 S1 S2 S3 S4 S5 S6 # Inputs: A S0 S1 S2 S3 S4 S5 S6
# Outputs: DPO SPO # Outputs: Y
$__ABC9_LUT7 2001 0 8 1 $__ABC9_LUT7 2001 0 8 1
0 1047 1036 877 812 643 532 478 0 1047 1036 877 812 643 532 478

View File

@ -325,6 +325,7 @@ endmodule
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf#L238-L250 // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf#L238-L250
(* abc9_box_id=1100, lib_whitebox, abc9_flop *)
module FDRE ( module FDRE (
(* abc9_arrival=303 *) (* abc9_arrival=303 *)
output reg Q, output reg Q,
@ -348,27 +349,17 @@ module FDRE (
endcase endgenerate endcase endgenerate
endmodule endmodule
module FDSE ( (* abc9_box_id=1101, lib_whitebox, abc9_flop *)
module FDRE_1 (
(* abc9_arrival=303 *) (* abc9_arrival=303 *)
output reg Q, output reg Q,
(* clkbuf_sink *) (* clkbuf_sink *)
(* invertible_pin = "IS_C_INVERTED" *)
input C, input C,
input CE, input CE, D, R
(* invertible_pin = "IS_D_INVERTED" *)
input D,
(* invertible_pin = "IS_S_INVERTED" *)
input S
); );
parameter [0:0] INIT = 1'b1; 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_S_INVERTED = 1'b0;
initial Q <= INIT; initial Q <= INIT;
generate case (|IS_C_INVERTED) always @(negedge C) if (R) Q <= 1'b0; else if (CE) Q <= D;
1'b0: always @(posedge C) if (S == !IS_S_INVERTED) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
1'b1: always @(negedge C) if (S == !IS_S_INVERTED) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
endcase endgenerate
endmodule endmodule
module FDRSE ( module FDRSE (
@ -406,6 +397,7 @@ module FDRSE (
Q <= d; Q <= d;
endmodule endmodule
(* abc9_box_id=1102, lib_whitebox, abc9_flop *)
module FDCE ( module FDCE (
(* abc9_arrival=303 *) (* abc9_arrival=303 *)
output reg Q, output reg Q,
@ -431,29 +423,17 @@ module FDCE (
endcase endgenerate endcase endgenerate
endmodule endmodule
module FDPE ( (* abc9_box_id=1103, lib_whitebox, abc9_flop *)
module FDCE_1 (
(* abc9_arrival=303 *) (* abc9_arrival=303 *)
output reg Q, output reg Q,
(* clkbuf_sink *) (* clkbuf_sink *)
(* invertible_pin = "IS_C_INVERTED" *)
input C, input C,
input CE, input CE, D, CLR
(* invertible_pin = "IS_D_INVERTED" *)
input D,
(* invertible_pin = "IS_PRE_INVERTED" *)
input PRE
); );
parameter [0:0] INIT = 1'b1; 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_PRE_INVERTED = 1'b0;
initial Q <= INIT; initial Q <= INIT;
generate case ({|IS_C_INVERTED, |IS_PRE_INVERTED}) always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D;
2'b00: always @(posedge C, posedge PRE) if ( PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
2'b01: always @(posedge C, negedge PRE) if (!PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
2'b10: always @(negedge C, posedge PRE) if ( PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
2'b11: always @(negedge C, negedge PRE) if (!PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
endcase endgenerate
endmodule endmodule
module FDCPE ( module FDCPE (
@ -501,42 +481,33 @@ module FDCPE (
assign Q = qs ? qp : qc; assign Q = qs ? qp : qc;
endmodule endmodule
module FDRE_1 ( (* abc9_box_id=1104, lib_whitebox, abc9_flop *)
module FDPE (
(* abc9_arrival=303 *) (* abc9_arrival=303 *)
output reg Q, output reg Q,
(* clkbuf_sink *) (* clkbuf_sink *)
(* invertible_pin = "IS_C_INVERTED" *)
input C, input C,
input CE, D, R input CE,
); (* invertible_pin = "IS_D_INVERTED" *)
parameter [0:0] INIT = 1'b0; input D,
initial Q <= INIT; (* invertible_pin = "IS_PRE_INVERTED" *)
always @(negedge C) if (R) Q <= 1'b0; else if(CE) Q <= D; input PRE
endmodule
module FDSE_1 (
(* abc9_arrival=303 *)
output reg Q,
(* clkbuf_sink *)
input C,
input CE, D, S
); );
parameter [0:0] INIT = 1'b1; 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;
initial Q <= INIT; initial Q <= INIT;
always @(negedge C) if (S) Q <= 1'b1; else if(CE) Q <= D; generate case ({|IS_C_INVERTED, |IS_PRE_INVERTED})
endmodule 2'b00: always @(posedge C, posedge PRE) if ( PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
2'b01: always @(posedge C, negedge PRE) if (!PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
module FDCE_1 ( 2'b10: always @(negedge C, posedge PRE) if ( PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
(* abc9_arrival=303 *) 2'b11: always @(negedge C, negedge PRE) if (!PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
output reg Q, endcase endgenerate
(* clkbuf_sink *)
input C,
input CE, D, CLR
);
parameter [0:0] INIT = 1'b0;
initial Q <= INIT;
always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D;
endmodule endmodule
(* abc9_box_id=1105, lib_whitebox, abc9_flop *)
module FDPE_1 ( module FDPE_1 (
(* abc9_arrival=303 *) (* abc9_arrival=303 *)
output reg Q, output reg Q,
@ -549,6 +520,43 @@ module FDPE_1 (
always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D; always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D;
endmodule endmodule
(* abc9_box_id=1106, lib_whitebox, abc9_flop *)
module FDSE (
(* abc9_arrival=303 *)
output reg Q,
(* clkbuf_sink *)
(* invertible_pin = "IS_C_INVERTED" *)
input C,
input CE,
(* invertible_pin = "IS_D_INVERTED" *)
input D,
(* invertible_pin = "IS_S_INVERTED" *)
input 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;
initial Q <= INIT;
generate case (|IS_C_INVERTED)
1'b0: always @(posedge C) if (S == !IS_S_INVERTED) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
1'b1: always @(negedge C) if (S == !IS_S_INVERTED) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
endcase endgenerate
endmodule
(* abc9_box_id=1107, lib_whitebox, abc9_flop *)
module FDSE_1 (
(* abc9_arrival=303 *)
output reg Q,
(* clkbuf_sink *)
input C,
input CE, D, S
);
parameter [0:0] INIT = 1'b1;
initial Q <= INIT;
always @(negedge C) if (S) Q <= 1'b1; else if (CE) Q <= D;
endmodule
module LDCE ( module LDCE (
output reg Q, output reg Q,
(* invertible_pin = "IS_CLR_INVERTED" *) (* invertible_pin = "IS_CLR_INVERTED" *)

View File

@ -107,6 +107,9 @@ struct SynthXilinxPass : public ScriptPass
log(" -flatten\n"); log(" -flatten\n");
log(" flatten design before synthesis\n"); log(" flatten design before synthesis\n");
log("\n"); log("\n");
log(" -dff\n");
log(" run 'abc9' with -dff option\n");
log("\n");
log(" -retime\n"); log(" -retime\n");
log(" run 'abc' with -dff option\n"); log(" run 'abc' with -dff option\n");
log("\n"); log("\n");
@ -120,7 +123,8 @@ struct SynthXilinxPass : public ScriptPass
} }
std::string top_opt, edif_file, blif_file, family; std::string top_opt, edif_file, blif_file, family;
bool flatten, retime, vpr, ise, noiopad, noclkbuf, nobram, nolutram, nosrl, nocarry, nowidelut, nodsp, uram, abc9; bool flatten, retime, vpr, ise, noiopad, noclkbuf, nobram, nolutram, nosrl, nocarry, nowidelut, nodsp, uram;
bool abc9, dff_mode;
bool flatten_before_abc; bool flatten_before_abc;
int widemux; int widemux;
@ -145,6 +149,7 @@ struct SynthXilinxPass : public ScriptPass
nodsp = false; nodsp = false;
uram = false; uram = false;
abc9 = false; abc9 = false;
dff_mode = false;
flatten_before_abc = false; flatten_before_abc = false;
widemux = 0; widemux = 0;
} }
@ -252,6 +257,10 @@ struct SynthXilinxPass : public ScriptPass
uram = true; uram = true;
continue; continue;
} }
if (args[argidx] == "-dff") {
dff_mode = true;
continue;
}
break; break;
} }
extra_args(args, argidx, design); extra_args(args, argidx, design);
@ -287,10 +296,11 @@ struct SynthXilinxPass : public ScriptPass
ff_map_file = "+/xilinx/xc7_ff_map.v"; ff_map_file = "+/xilinx/xc7_ff_map.v";
if (check_label("begin")) { if (check_label("begin")) {
std::string read_args;
if (vpr) if (vpr)
run("read_verilog -lib -D_EXPLICIT_CARRY +/xilinx/cells_sim.v"); read_args += " -D_EXPLICIT_CARRY";
else read_args += " -lib +/xilinx/cells_sim.v";
run("read_verilog -lib +/xilinx/cells_sim.v"); run("read_verilog" + read_args);
run("read_verilog -lib +/xilinx/cells_xtra.v"); run("read_verilog -lib +/xilinx/cells_xtra.v");
@ -537,7 +547,10 @@ struct SynthXilinxPass : public ScriptPass
if (family != "xc7") if (family != "xc7")
log_warning("'synth_xilinx -abc9' not currently supported for the '%s' family, " log_warning("'synth_xilinx -abc9' not currently supported for the '%s' family, "
"will use timing for 'xc7' instead.\n", family.c_str()); "will use timing for 'xc7' instead.\n", family.c_str());
run("techmap -map +/xilinx/abc9_map.v -max_iter 1"); 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("read_verilog -icells -lib +/xilinx/abc9_model.v"); run("read_verilog -icells -lib +/xilinx/abc9_model.v");
std::string abc9_opts = " -box +/xilinx/abc9_xc7.box"; std::string abc9_opts = " -box +/xilinx/abc9_xc7.box";
abc9_opts += stringf(" -W %d", XC7_WIRE_DELAY); abc9_opts += stringf(" -W %d", XC7_WIRE_DELAY);
@ -547,6 +560,7 @@ struct SynthXilinxPass : public ScriptPass
else else
abc9_opts += " -lut +/xilinx/abc9_xc7.lut"; abc9_opts += " -lut +/xilinx/abc9_xc7.lut";
run("abc9" + abc9_opts); run("abc9" + abc9_opts);
run("techmap -map +/xilinx/abc9_unmap.v");
} }
else { else {
if (nowidelut) if (nowidelut)
@ -562,14 +576,11 @@ struct SynthXilinxPass : public ScriptPass
run("xilinx_srl -fixed -minlen 3", "(skip if '-nosrl')"); run("xilinx_srl -fixed -minlen 3", "(skip if '-nosrl')");
std::string techmap_args = "-map +/xilinx/lut_map.v -map +/xilinx/cells_map.v"; std::string techmap_args = "-map +/xilinx/lut_map.v -map +/xilinx/cells_map.v";
if (help_mode) if (help_mode)
techmap_args += " [-map " + ff_map_file + "]"; techmap_args += stringf("[-map %s]", ff_map_file.c_str());
else if (abc9) else if (!abc9)
techmap_args += " -map +/xilinx/abc9_unmap.v"; techmap_args += stringf(" -map %s", ff_map_file.c_str());
else run("techmap " + techmap_args, "(option without '-abc9')");
techmap_args += " -map " + ff_map_file;
run("techmap " + techmap_args);
run("xilinx_dffopt"); run("xilinx_dffopt");
run("clean");
} }
if (check_label("finalize")) { if (check_label("finalize")) {
@ -577,6 +588,7 @@ struct SynthXilinxPass : public ScriptPass
run("clkbufmap -buf BUFG O:I ", "(skip if '-noclkbuf')"); run("clkbufmap -buf BUFG O:I ", "(skip if '-noclkbuf')");
if (help_mode || ise) if (help_mode || ise)
run("extractinv -inv INV O:I", "(only if '-ise')"); run("extractinv -inv INV O:I", "(only if '-ise')");
run("clean");
} }
if (check_label("check")) { if (check_label("check")) {

View File

@ -0,0 +1,91 @@
read_verilog <<EOT
module top(input C, CE, D, R, output [1:0] Q);
FDRE #(.INIT(1'b1)) ff1 (.C(C), .CE(CE), .D(D), .R(R), .Q(Q[0]));
FDRE_1 #(.INIT(1'b1)) ff2 (.C(C), .CE(CE), .D(D), .R(R), .Q(Q[1]));
endmodule
EOT
design -save gold
techmap -map +/xilinx/abc9_map.v -max_iter 1
techmap -map +/xilinx/abc9_unmap.v
select -assert-count 1 t:FDSE
select -assert-count 1 t:FDSE_1
techmap -autoproc -map +/xilinx/cells_sim.v
design -stash gate
design -import gold -as gold
design -import gate -as gate
techmap -autoproc -map +/xilinx/cells_sim.v
miter -equiv -flatten -make_assert -make_outputs gold gate miter
sat -seq 2 -verify -prove-asserts -show-ports miter
design -reset
read_verilog <<EOT
module top(input C, CE, D, S, output [1:0] Q);
FDSE #(.INIT(1'b1)) ff1 (.C(C), .CE(CE), .D(D), .S(S), .Q(Q[0]));
FDSE_1 #(.INIT(1'b1)) ff2 (.C(C), .CE(CE), .D(D), .S(S), .Q(Q[1]));
endmodule
EOT
design -save gold
techmap -map +/xilinx/abc9_map.v -max_iter 1
techmap -map +/xilinx/abc9_unmap.v
select -assert-count 1 t:FDRE
select -assert-count 1 t:FDRE_1
techmap -autoproc -map +/xilinx/cells_sim.v
design -stash gate
design -import gold -as gold
design -import gate -as gate
techmap -autoproc -map +/xilinx/cells_sim.v
miter -equiv -flatten -make_assert -make_outputs gold gate miter
sat -seq 2 -set-init-zero -verify -prove-asserts -show-ports miter
design -reset
read_verilog <<EOT
module top(input C, CE, D, PRE, output [1:0] Q);
FDPE #(.INIT(1'b1)) ff1 (.C(C), .CE(CE), .D(D), .PRE(PRE), .Q(Q[0]));
FDPE_1 #(.INIT(1'b1)) ff2 (.C(C), .CE(CE), .D(D), .PRE(PRE), .Q(Q[1]));
endmodule
EOT
design -save gold
techmap -map +/xilinx/abc9_map.v -max_iter 1
techmap -map +/xilinx/abc9_unmap.v
select -assert-count 1 t:FDCE
select -assert-count 1 t:FDCE_1
techmap -autoproc -map +/xilinx/cells_sim.v
design -stash gate
design -import gold -as gold
design -import gate -as gate
techmap -autoproc -map +/xilinx/cells_sim.v
clk2fflogic
miter -equiv -flatten -make_assert -make_outputs gold gate miter
sat -seq 2 -set-init-zero -verify -prove-asserts -show-ports miter
design -reset
read_verilog <<EOT
module top(input C, CE, D, CLR, output [1:0] Q);
FDCE #(.INIT(1'b1)) ff1 (.C(C), .CE(CE), .D(D), .CLR(CLR), .Q(Q[0]));
FDCE_1 #(.INIT(1'b1)) ff2 (.C(C), .CE(CE), .D(D), .CLR(CLR), .Q(Q[1]));
endmodule
EOT
design -save gold
techmap -map +/xilinx/abc9_map.v -max_iter 1
techmap -map +/xilinx/abc9_unmap.v
select -assert-count 1 t:FDPE
techmap -autoproc -map +/xilinx/cells_sim.v
design -stash gate
design -import gold -as gold
design -import gate -as gate
techmap -autoproc -map +/xilinx/cells_sim.v
clk2fflogic
miter -equiv -flatten -make_assert -make_outputs gold gate miter
sat -seq 2 -set-init-zero -verify -prove-asserts -show-ports miter

View File

@ -264,3 +264,30 @@ always @*
if (en) if (en)
q <= d; q <= d;
endmodule endmodule
module abc9_test031(input clk1, clk2, d, output reg q1, q2);
always @(posedge clk1) q1 <= d;
always @(negedge clk2) q2 <= q1;
endmodule
module abc9_test032(input clk, d, r, output reg q);
always @(posedge clk or posedge r)
if (r) q <= 1'b0;
else q <= d;
endmodule
module abc9_test033(input clk, d, r, output reg q);
always @(negedge clk or posedge r)
if (r) q <= 1'b1;
else q <= d;
endmodule
module abc9_test034(input clk, d, output reg q1, q2);
always @(posedge clk) q1 <= d;
always @(posedge clk) q2 <= q1;
endmodule
module abc9_test035(input clk, d, output reg [1:0] q);
always @(posedge clk) q[0] <= d;
always @(negedge clk) q[1] <= q[0];
endmodule

View File

@ -20,10 +20,12 @@ fi
cp ../simple/*.v . cp ../simple/*.v .
cp ../simple/*.sv . cp ../simple/*.sv .
DOLLAR='?' DOLLAR='?'
exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.v EXTRA_FLAGS="-n 300 -p '\ exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.v *.sv EXTRA_FLAGS="-n 300 -p '\
hierarchy; \ hierarchy; \
synth -run coarse; \ synth -run coarse; \
opt -full; \ opt -full; \
techmap; abc9 -lut 4 -box ../abc.box; \ techmap; \
abc9 -lut 4 -box ../abc.box; \
clean; \
check -assert; \ check -assert; \
select -assert-none t:${DOLLAR}_NOT_ t:${DOLLAR}_AND_ %%'" select -assert-none t:${DOLLAR}_NOT_ t:${DOLLAR}_AND_ %%'"

View File

@ -9,3 +9,10 @@ wire w;
unknown u(~i, w); unknown u(~i, w);
unknown2 u2(w, o); unknown2 u2(w, o);
endmodule endmodule
module abc9_test032(input clk, d, r, output reg q);
initial q = 1'b0;
always @(negedge clk or negedge r)
if (!r) q <= 1'b0;
else q <= d;
endmodule

View File

@ -22,3 +22,19 @@ abc9 -lut 4
select -assert-count 1 t:$lut r:LUT=2'b01 r:WIDTH=1 %i %i select -assert-count 1 t:$lut r:LUT=2'b01 r:WIDTH=1 %i %i
select -assert-count 1 t:unknown select -assert-count 1 t:unknown
select -assert-none t:$lut t:unknown %% t: %D select -assert-none t:$lut t:unknown %% t: %D
design -load read
hierarchy -top abc9_test032
proc
clk2fflogic
design -save gold
abc9 -lut 4
check
design -stash gate
design -import gold -as gold
design -import gate -as gate
miter -equiv -flatten -make_assert -make_outputs gold gate miter
sat -seq 10 -verify -prove-asserts -show-ports miter