aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md8
-rw-r--r--backends/aiger/xaiger.cc378
-rw-r--r--frontends/aiger/aigerparse.cc74
-rw-r--r--passes/techmap/abc9.cc234
-rw-r--r--techlibs/xilinx/Makefile.inc3
-rw-r--r--techlibs/xilinx/abc_map.v225
-rw-r--r--techlibs/xilinx/abc_model.v179
-rw-r--r--techlibs/xilinx/abc_unmap.v239
-rw-r--r--techlibs/xilinx/abc_xc7.box68
-rw-r--r--techlibs/xilinx/cells_map.v2
-rw-r--r--techlibs/xilinx/cells_sim.v31
-rw-r--r--techlibs/xilinx/synth_xilinx.cc14
-rw-r--r--techlibs/xilinx/xc7_brams_bb.v18
13 files changed, 1276 insertions, 197 deletions
diff --git a/README.md b/README.md
index 56f428548..fe30348eb 100644
--- a/README.md
+++ b/README.md
@@ -409,14 +409,6 @@ Verilog Attributes and non-standard features
blackbox or whitebox definition to a corresponding entry in a `abc9`
box-file.
-- The port attribute ``abc_scc_break`` indicates a module input port that will
- be treated as a primary output during `abc9` techmapping. Doing so eliminates
- the possibility of a strongly-connected component (i.e. a combinatorial loop)
- existing. Typically, this is specified for sequential inputs on otherwise
- combinatorial boxes -- for example, applying ``abc_scc_break`` onto the `D`
- port of a LUTRAM cell prevents `abc9` from interpreting any `Q` -> `D` paths
- as a combinatorial loop.
-
- The port attribute ``abc_carry`` marks the carry-in (if an input port) and
carry-out (if output port) ports of a box. This information is necessary for
`abc9` to preserve the integrity of carry-chains. Specifying this attribute
diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc
index 77d0e94c2..d02997da4 100644
--- a/backends/aiger/xaiger.cc
+++ b/backends/aiger/xaiger.cc
@@ -76,24 +76,32 @@ void aiger_encode(std::ostream &f, int x)
struct XAigerWriter
{
Module *module;
+ bool zinit_mode;
SigMap sigmap;
+ dict<SigBit, bool> init_map;
pool<SigBit> input_bits, output_bits;
- dict<SigBit, SigBit> not_map, alias_map;
+ dict<SigBit, SigBit> not_map, ff_map, alias_map;
dict<SigBit, pair<SigBit, SigBit>> and_map;
vector<std::tuple<SigBit,RTLIL::Cell*,RTLIL::IdString,int>> ci_bits;
vector<std::tuple<SigBit,RTLIL::Cell*,RTLIL::IdString,int,int>> co_bits;
+ vector<SigBit> ff_bits;
+ dict<SigBit, float> arrival_times;
vector<pair<int, int>> aig_gates;
- vector<int> aig_outputs;
+ vector<int> aig_latchin, aig_latchinit, aig_outputs;
int aig_m = 0, aig_i = 0, aig_l = 0, aig_o = 0, aig_a = 0;
dict<SigBit, int> aig_map;
dict<SigBit, int> ordered_outputs;
+ dict<SigBit, int> ordered_latches;
vector<Cell*> box_list;
bool omode = false;
+ //dict<SigBit, int> init_inputs;
+ //int initstate_ff = 0;
+
int mkgate(int a0, int a1)
{
aig_m++, aig_a++;
@@ -136,7 +144,7 @@ struct XAigerWriter
return a;
}
- XAigerWriter(Module *module, bool holes_mode=false) : module(module), sigmap(module)
+ XAigerWriter(Module *module, bool zinit_mode, bool holes_mode=false) : module(module), zinit_mode(zinit_mode), sigmap(module)
{
pool<SigBit> undriven_bits;
pool<SigBit> unused_bits;
@@ -159,6 +167,14 @@ struct XAigerWriter
for (auto wire : module->wires())
{
+ if (wire->attributes.count("\\init")) {
+ SigSpec initsig = sigmap(wire);
+ Const initval = wire->attributes.at("\\init");
+ for (int i = 0; i < GetSize(wire) && i < GetSize(initval); i++)
+ if (initval[i] == State::S0 || initval[i] == State::S1)
+ init_map[initsig[i]] = initval[i] == State::S1;
+ }
+
bool keep = wire->attributes.count("\\keep");
for (int i = 0; i < GetSize(wire); i++)
@@ -202,6 +218,12 @@ struct XAigerWriter
// box ordering, but not individual AIG cells
dict<SigBit, pool<IdString>> bit_drivers, bit_users;
TopoSort<IdString, RTLIL::sort_by_id_str> toposort;
+ struct flop_data_t {
+ IdString d_port;
+ IdString q_port;
+ int q_arrival;
+ };
+ dict<IdString, flop_data_t> flop_data;
bool abc_box_seen = false;
for (auto cell : module->selected_cells()) {
@@ -240,37 +262,100 @@ struct XAigerWriter
log_assert(!holes_mode);
+ if (cell->type == "$__ABC_FF_")
+ {
+ SigBit D = sigmap(cell->getPort("\\D").as_bit());
+ SigBit Q = sigmap(cell->getPort("\\Q").as_bit());
+ unused_bits.erase(D);
+ undriven_bits.erase(Q);
+ alias_map[Q] = D;
+ continue;
+ }
+
RTLIL::Module* inst_module = module->design->module(cell->type);
if (inst_module && inst_module->attributes.count("\\abc_box_id")) {
abc_box_seen = true;
- if (!holes_mode) {
- toposort.node(cell->name);
- for (const auto &conn : cell->connections()) {
- if (cell->input(conn.first)) {
- // Ignore inout for the sake of topographical ordering
- if (cell->output(conn.first)) continue;
- for (auto bit : sigmap(conn.second))
- bit_users[bit].insert(cell->name);
+ toposort.node(cell->name);
+
+ auto r = flop_data.insert(std::make_pair(cell->type, flop_data_t{IdString(), IdString(), 0}));
+ if (r.second && inst_module->attributes.count("\\abc_flop")) {
+ IdString &abc_flop_d = r.first->second.d_port;
+ IdString &abc_flop_q = r.first->second.q_port;
+ for (auto port_name : inst_module->ports) {
+ auto wire = inst_module->wire(port_name);
+ log_assert(wire);
+ if (wire->attributes.count("\\abc_flop_d")) {
+ if (abc_flop_d != IdString())
+ log_error("More than one port has the 'abc_flop_d' attribute set on module '%s'.\n", log_id(cell->type));
+ abc_flop_d = port_name;
+ }
+ if (wire->attributes.count("\\abc_flop_q")) {
+ if (abc_flop_q != IdString())
+ log_error("More than one port has the 'abc_flop_q' attribute set on module '%s'.\n", log_id(cell->type));
+ abc_flop_q = port_name;
+
+ auto it = wire->attributes.find("\\abc_arrival");
+ if (it != wire->attributes.end()) {
+ if (it->second.flags != 0)
+ log_error("Attribute 'abc_arrival' on port '%s' of module '%s' is not an integer.\n", log_id(wire), log_id(cell->type));
+ r.first->second.q_arrival = it->second.as_int();
+ }
}
+ }
+ if (abc_flop_d == IdString())
+ log_error("'abc_flop_d' attribute not found on any ports on module '%s'.\n", log_id(cell->type));
+ if (abc_flop_q == IdString())
+ log_error("'abc_flop_q' attribute not found on any ports on module '%s'.\n", log_id(cell->type));
+ }
+
+ auto abc_flop_d = r.first->second.d_port;
+ if (abc_flop_d != IdString()) {
+ SigBit d = cell->getPort(abc_flop_d);
+ SigBit I = sigmap(d);
+ if (I != d)
+ alias_map[I] = d;
+ unused_bits.erase(d);
+
+ auto abc_flop_q = r.first->second.q_port;
+ SigBit q = cell->getPort(abc_flop_q);
+ SigBit O = sigmap(q);
+ if (O != q)
+ alias_map[O] = q;
+ undriven_bits.erase(O);
+ ff_bits.emplace_back(q);
+
+ auto arrival = r.first->second.q_arrival;
+ if (arrival)
+ arrival_times[q] = arrival;
+ }
- if (cell->output(conn.first))
- for (auto bit : sigmap(conn.second))
- bit_drivers[bit].insert(cell->name);
+ for (const auto &conn : cell->connections()) {
+ auto port_wire = inst_module->wire(conn.first);
+ if (port_wire->port_input) {
+ // Ignore inout for the sake of topographical ordering
+ if (port_wire->port_output) continue;
+ for (auto bit : sigmap(conn.second))
+ bit_users[bit].insert(cell->name);
}
+
+ if (port_wire->port_output)
+ for (auto bit : sigmap(conn.second))
+ bit_drivers[bit].insert(cell->name);
}
}
else {
- bool cell_known = cell->known();
+ bool cell_known = inst_module;
for (const auto &c : cell->connections()) {
if (c.second.is_fully_const()) continue;
- auto is_input = !cell_known || cell->input(c.first);
- auto is_output = !cell_known || cell->output(c.first);
+ auto port_wire = inst_module ? inst_module->wire(c.first) : nullptr;
+ auto is_input = !cell_known || port_wire->port_input;
+ auto is_output = !cell_known || port_wire->port_output;
if (!is_input && !is_output)
log_error("Connection '%s' on cell '%s' (type '%s') not recognised!\n", log_id(c.first), log_id(cell), log_id(cell->type));
if (is_input) {
- for (auto b : c.second.bits()) {
+ for (auto b : c.second) {
Wire *w = b.wire;
if (!w) continue;
if (!w->port_output || !cell_known) {
@@ -286,7 +371,17 @@ struct XAigerWriter
}
}
if (is_output) {
- for (auto b : c.second.bits()) {
+ int arrival = 0;
+ if (port_wire) {
+ auto it = port_wire->attributes.find("\\abc_arrival");
+ if (it != port_wire->attributes.end()) {
+ if (it->second.flags != 0)
+ log_error("Attribute 'abc_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);
@@ -294,6 +389,9 @@ struct XAigerWriter
if (O != b)
alias_map[O] = b;
undriven_bits.erase(O);
+
+ if (arrival)
+ arrival_times[b] = arrival;
}
}
}
@@ -450,6 +548,7 @@ struct XAigerWriter
log_warning("Treating a total of %d undriven bits in %s like $anyseq.\n", GetSize(undriven_bits), log_id(module));
}
+ init_map.sort();
if (holes_mode) {
struct sort_by_port_id {
bool operator()(const RTLIL::SigBit& a, const RTLIL::SigBit& b) const {
@@ -465,6 +564,7 @@ struct XAigerWriter
}
not_map.sort();
+ ff_map.sort();
and_map.sort();
aig_map[State::S0] = 0;
@@ -476,12 +576,77 @@ struct XAigerWriter
aig_map[bit] = 2*aig_m;
}
+ for (auto bit : ff_bits) {
+ aig_m++, aig_i++;
+ log_assert(!aig_map.count(bit));
+ aig_map[bit] = 2*aig_m;
+ }
+
+ dict<SigBit, int> ff_aig_map;
for (auto &c : ci_bits) {
RTLIL::SigBit bit = std::get<0>(c);
aig_m++, aig_i++;
- aig_map[bit] = 2*aig_m;
+ auto r = aig_map.insert(std::make_pair(bit, 2*aig_m));
+ if (!r.second)
+ ff_aig_map[bit] = 2*aig_m;
}
+ //if (zinit_mode)
+ //{
+ // for (auto it : ff_map) {
+ // if (init_map.count(it.first))
+ // continue;
+ // aig_m++, aig_i++;
+ // init_inputs[it.first] = 2*aig_m;
+ // }
+ //}
+
+ //for (auto it : ff_map) {
+ // aig_m++, aig_l++;
+ // aig_map[it.first] = 2*aig_m;
+ // ordered_latches[it.first] = aig_l-1;
+ // if (init_map.count(it.first) == 0)
+ // aig_latchinit.push_back(2);
+ // else
+ // aig_latchinit.push_back(init_map.at(it.first) ? 1 : 0);
+ //}
+
+ //if (!init_inputs.empty()) {
+ // aig_m++, aig_l++;
+ // initstate_ff = 2*aig_m+1;
+ // aig_latchinit.push_back(0);
+ //}
+
+ //if (zinit_mode)
+ //{
+ // for (auto it : ff_map)
+ // {
+ // int l = ordered_latches[it.first];
+
+ // if (aig_latchinit.at(l) == 1)
+ // aig_map[it.first] ^= 1;
+
+ // if (aig_latchinit.at(l) == 2)
+ // {
+ // int gated_ffout = mkgate(aig_map[it.first], initstate_ff^1);
+ // int gated_initin = mkgate(init_inputs[it.first], initstate_ff);
+ // aig_map[it.first] = mkgate(gated_ffout^1, gated_initin^1)^1;
+ // }
+ // }
+ //}
+
+ //for (auto it : ff_map) {
+ // int a = bit2aig(it.second);
+ // int l = ordered_latches[it.first];
+ // if (zinit_mode && aig_latchinit.at(l) == 1)
+ // aig_latchin.push_back(a ^ 1);
+ // else
+ // aig_latchin.push_back(a);
+ //}
+
+ //if (!init_inputs.empty())
+ // aig_latchin.push_back(1);
+
for (auto &c : co_bits) {
RTLIL::SigBit bit = std::get<0>(c);
std::get<4>(c) = ordered_outputs[bit] = aig_o++;
@@ -493,6 +658,11 @@ struct XAigerWriter
aig_outputs.push_back(bit2aig(bit));
}
+ for (auto bit : ff_bits) {
+ aig_o++;
+ aig_outputs.push_back(ff_aig_map.at(bit));
+ }
+
if (output_bits.empty()) {
aig_o++;
aig_outputs.push_back(0);
@@ -507,6 +677,8 @@ struct XAigerWriter
int aig_obcjf = aig_obcj;
log_assert(aig_m == aig_i + aig_l + aig_a);
+ log_assert(aig_l == GetSize(aig_latchin));
+ log_assert(aig_l == GetSize(aig_latchinit));
log_assert(aig_obcjf == GetSize(aig_outputs));
f << stringf("%s %d %d %d %d %d", ascii_mode ? "aag" : "aig", aig_m, aig_i, aig_l, aig_o, aig_a);
@@ -517,6 +689,15 @@ struct XAigerWriter
for (int i = 0; i < aig_i; i++)
f << stringf("%d\n", 2*i+2);
+ //for (int i = 0; i < aig_l; i++) {
+ // if (zinit_mode || aig_latchinit.at(i) == 0)
+ // f << stringf("%d %d\n", 2*(aig_i+i)+2, aig_latchin.at(i));
+ // else if (aig_latchinit.at(i) == 1)
+ // f << stringf("%d %d 1\n", 2*(aig_i+i)+2, aig_latchin.at(i));
+ // else if (aig_latchinit.at(i) == 2)
+ // f << stringf("%d %d %d\n", 2*(aig_i+i)+2, aig_latchin.at(i), 2*(aig_i+i)+2);
+ //}
+
for (int i = 0; i < aig_obc; i++)
f << stringf("%d\n", aig_outputs.at(i));
@@ -534,6 +715,15 @@ struct XAigerWriter
}
else
{
+ //for (int i = 0; i < aig_l; i++) {
+ // if (zinit_mode || aig_latchinit.at(i) == 0)
+ // f << stringf("%d\n", aig_latchin.at(i));
+ // else if (aig_latchinit.at(i) == 1)
+ // f << stringf("%d 1\n", aig_latchin.at(i));
+ // else if (aig_latchinit.at(i) == 2)
+ // f << stringf("%d %d\n", aig_latchin.at(i), 2*(aig_i+i)+2);
+ //}
+
for (int i = 0; i < aig_obc; i++)
f << stringf("%d\n", aig_outputs.at(i));
@@ -559,26 +749,37 @@ struct XAigerWriter
f << "c";
- if (!box_list.empty()) {
- auto write_buffer = [](std::stringstream &buffer, int i32) {
- int32_t i32_be = to_big_endian(i32);
- buffer.write(reinterpret_cast<const char*>(&i32_be), sizeof(i32_be));
- };
-
- std::stringstream h_buffer;
- auto write_h_buffer = std::bind(write_buffer, std::ref(h_buffer), std::placeholders::_1);
- write_h_buffer(1);
- log_debug("ciNum = %d\n", GetSize(input_bits) + GetSize(ci_bits));
- write_h_buffer(input_bits.size() + ci_bits.size());
- log_debug("coNum = %d\n", GetSize(output_bits) + GetSize(co_bits));
- write_h_buffer(output_bits.size() + co_bits.size());
- log_debug("piNum = %d\n", GetSize(input_bits));
- write_h_buffer(input_bits.size());
- log_debug("poNum = %d\n", GetSize(output_bits));
- write_h_buffer(output_bits.size());
- log_debug("boxNum = %d\n", GetSize(box_list));
- write_h_buffer(box_list.size());
+ auto write_buffer = [](std::stringstream &buffer, int i32) {
+ int32_t i32_be = to_big_endian(i32);
+ buffer.write(reinterpret_cast<const char*>(&i32_be), sizeof(i32_be));
+ };
+ std::stringstream h_buffer;
+ auto write_h_buffer = std::bind(write_buffer, std::ref(h_buffer), std::placeholders::_1);
+ write_h_buffer(1);
+ log_debug("ciNum = %d\n", GetSize(input_bits) + GetSize(ff_bits) + GetSize(ci_bits));
+ write_h_buffer(input_bits.size() + ff_bits.size() + ci_bits.size());
+ log_debug("coNum = %d\n", GetSize(output_bits) + GetSize(ff_bits) + GetSize(co_bits));
+ write_h_buffer(output_bits.size() + GetSize(ff_bits) + GetSize(co_bits));
+ log_debug("piNum = %d\n", GetSize(input_bits) + GetSize(ff_bits));
+ write_h_buffer(input_bits.size() + ff_bits.size());
+ log_debug("poNum = %d\n", GetSize(output_bits) + GetSize(ff_bits));
+ write_h_buffer(output_bits.size() + ff_bits.size());
+ log_debug("boxNum = %d\n", GetSize(box_list));
+ write_h_buffer(box_list.size());
+
+ auto write_buffer_float = [](std::stringstream &buffer, float f32) {
+ buffer.write(reinterpret_cast<const char*>(&f32), sizeof(f32));
+ };
+ std::stringstream i_buffer;
+ auto write_i_buffer = std::bind(write_buffer_float, std::ref(i_buffer), std::placeholders::_1);
+ for (auto bit : input_bits)
+ write_i_buffer(arrival_times.at(bit, 0));
+ //std::stringstream o_buffer;
+ //auto write_o_buffer = std::bind(write_buffer_float, std::ref(o_buffer), std::placeholders::_1);
+ //for (auto bit : output_bits)
+ // write_o_buffer(0);
+ if (!box_list.empty() || !ff_bits.empty()) {
RTLIL::Module *holes_module = module->design->addModule("$__holes__");
log_assert(holes_module);
@@ -642,18 +843,39 @@ struct XAigerWriter
write_h_buffer(box_count++);
}
- f << "h";
- std::string buffer_str = h_buffer.str();
- 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(buffer_str.data(), buffer_str.size());
-
std::stringstream r_buffer;
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());
+ int mergeability_class = 1;
+ for (auto bit : ff_bits) {
+ write_r_buffer(mergeability_class++);
+ write_i_buffer(arrival_times.at(bit, 0));
+ //write_o_buffer(0);
+ }
f << "r";
- buffer_str = r_buffer.str();
+ std::string buffer_str = r_buffer.str();
+ 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(buffer_str.data(), buffer_str.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 (auto bit : ff_bits) {
+ auto it = bit.wire->attributes.find("\\init");
+ if (it != bit.wire->attributes.end()) {
+ auto init = it->second[bit.offset];
+ if (init == RTLIL::S1) {
+ write_s_buffer(1);
+ continue;
+ }
+ }
+ write_s_buffer(0);
+ }
+ 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());
@@ -693,7 +915,7 @@ struct XAigerWriter
Pass::call(holes_design, "clean -purge");
std::stringstream a_buffer;
- XAigerWriter writer(holes_module, true /* holes_mode */);
+ XAigerWriter writer(holes_module, false /*zinit_mode*/, true /* holes_mode */);
writer.write_aiger(a_buffer, false /*ascii_mode*/);
delete holes_design;
@@ -708,13 +930,32 @@ struct XAigerWriter
}
}
+ f << "h";
+ std::string buffer_str = h_buffer.str();
+ 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(buffer_str.data(), buffer_str.size());
+
+ f << "i";
+ buffer_str = i_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());
+ //f << "o";
+ //buffer_str = o_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());
+
f << stringf("Generated by %s\n", yosys_version_str);
}
void write_map(std::ostream &f, bool verbose_map)
{
dict<int, string> input_lines;
+ dict<int, string> init_lines;
dict<int, string> output_lines;
+ dict<int, string> latch_lines;
dict<int, string> wire_lines;
for (auto wire : module->wires())
@@ -735,10 +976,30 @@ struct XAigerWriter
if (output_bits.count(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;
+ auto it = init_map.find(b);
+ if (it != init_map.end())
+ init = it->second ? 1 : 0;
+ output_lines[o] += stringf("output %d %d %s %d\n", o - GetSize(co_bits), i, log_id(wire), init);
continue;
}
+ //if (init_inputs.count(sig[i])) {
+ // int a = init_inputs.at(sig[i]);
+ // log_assert((a & 1) == 0);
+ // init_lines[a] += stringf("init %d %d %s\n", (a >> 1)-1, i, log_id(wire));
+ // continue;
+ //}
+
+ //if (ordered_latches.count(sig[i])) {
+ // int l = ordered_latches.at(sig[i]);
+ // if (zinit_mode && (aig_latchinit.at(l) == 1))
+ // latch_lines[l] += stringf("invlatch %d %d %s\n", l, i, log_id(wire));
+ // else
+ // latch_lines[l] += stringf("latch %d %d %s\n", l, i, log_id(wire));
+ // continue;
+ //}
+
if (verbose_map) {
if (aig_map.count(sig[i]) == 0)
continue;
@@ -754,6 +1015,10 @@ struct XAigerWriter
f << it.second;
log_assert(input_lines.size() == input_bits.size());
+ init_lines.sort();
+ for (auto &it : init_lines)
+ f << it.second;
+
int box_count = 0;
for (auto cell : box_list)
f << stringf("box %d %d %s\n", box_count++, 0, log_id(cell->name));
@@ -765,6 +1030,10 @@ struct XAigerWriter
if (omode && output_bits.empty())
f << "output " << output_lines.size() << " 0 $__dummy__\n";
+ latch_lines.sort();
+ for (auto &it : latch_lines)
+ f << it.second;
+
wire_lines.sort();
for (auto &it : wire_lines)
f << it.second;
@@ -785,6 +1054,10 @@ struct XAigerBackend : public Backend {
log(" -ascii\n");
log(" write ASCII version of AIGER format\n");
log("\n");
+ log(" -zinit\n");
+ log(" convert FFs to zero-initialized FFs, adding additional inputs for\n");
+ log(" uninitialized FFs.\n");
+ log("\n");
log(" -map <filename>\n");
log(" write an extra file with port and latch symbols\n");
log("\n");
@@ -795,6 +1068,7 @@ struct XAigerBackend : public Backend {
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool ascii_mode = false;
+ bool zinit_mode = false;
bool verbose_map = false;
std::string map_filename;
@@ -807,6 +1081,10 @@ struct XAigerBackend : public Backend {
ascii_mode = true;
continue;
}
+ if (args[argidx] == "-zinit") {
+ zinit_mode = true;
+ continue;
+ }
if (map_filename.empty() && args[argidx] == "-map" && argidx+1 < args.size()) {
map_filename = args[++argidx];
continue;
@@ -825,7 +1103,7 @@ struct XAigerBackend : public Backend {
if (top_module == nullptr)
log_error("Can't find top module in current design!\n");
- XAigerWriter writer(top_module);
+ XAigerWriter writer(top_module, zinit_mode);
writer.write_aiger(*f, ascii_mode);
if (!map_filename.empty()) {
diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc
index 06522939f..7a467b91e 100644
--- a/frontends/aiger/aigerparse.cc
+++ b/frontends/aiger/aigerparse.cc
@@ -430,6 +430,7 @@ void AigerReader::parse_xaiger(const dict<int,IdString> &box_lookup)
else if (c == 'r') {
uint32_t dataSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
flopNum = parse_xaiger_literal(f);
+ log_debug("flopNum: %u\n", flopNum);
log_assert(dataSize == (flopNum+1) * sizeof(uint32_t));
f.ignore(flopNum * sizeof(uint32_t));
}
@@ -496,8 +497,7 @@ void AigerReader::parse_aiger_ascii()
// Parse latches
RTLIL::Wire *clk_wire = nullptr;
- if (L > 0) {
- log_assert(clk_name != "");
+ if (L > 0 && !clk_name.empty()) {
clk_wire = module->wire(clk_name);
log_assert(!clk_wire);
log_debug2("Creating %s\n", clk_name.c_str());
@@ -513,7 +513,10 @@ void AigerReader::parse_aiger_ascii()
RTLIL::Wire *q_wire = createWireIfNotExists(module, l1);
RTLIL::Wire *d_wire = createWireIfNotExists(module, l2);
- module->addDffGate(NEW_ID, clk_wire, d_wire, q_wire);
+ if (clk_wire)
+ module->addDffGate(NEW_ID, clk_wire, d_wire, q_wire);
+ else
+ module->addFfGate(NEW_ID, d_wire, q_wire);
// Reset logic is optional in AIGER 1.9
if (f.peek() == ' ') {
@@ -621,8 +624,7 @@ void AigerReader::parse_aiger_binary()
// Parse latches
RTLIL::Wire *clk_wire = nullptr;
- if (L > 0) {
- log_assert(clk_name != "");
+ if (L > 0 && !clk_name.empty()) {
clk_wire = module->wire(clk_name);
log_assert(!clk_wire);
log_debug2("Creating %s\n", clk_name.c_str());
@@ -638,7 +640,10 @@ void AigerReader::parse_aiger_binary()
RTLIL::Wire *q_wire = createWireIfNotExists(module, l1);
RTLIL::Wire *d_wire = createWireIfNotExists(module, l2);
- module->addDff(NEW_ID, clk_wire, d_wire, q_wire);
+ if (clk_wire)
+ module->addDff(NEW_ID, clk_wire, d_wire, q_wire);
+ else
+ module->addFf(NEW_ID, d_wire, q_wire);
// Reset logic is optional in AIGER 1.9
if (f.peek() == ' ') {
@@ -727,12 +732,19 @@ void AigerReader::parse_aiger_binary()
void AigerReader::post_process()
{
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) {
RTLIL::Module* box_module = design->module(cell->type);
log_assert(box_module);
+ bool is_flop = false;
if (seen_boxes.insert(cell->type).second) {
+ if (box_module->attributes.count("\\abc_flop")) {
+ log_assert(flop_count < flopNum);
+ flops.insert(cell->type);
+ is_flop = true;
+ }
auto it = box_module->attributes.find("\\abc_carry");
if (it != box_module->attributes.end()) {
RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr;
@@ -772,23 +784,25 @@ void AigerReader::post_process()
carry_out->port_id = ports.size();
}
}
+ else
+ is_flop = flops.count(cell->type);
// NB: Assume box_module->ports are sorted alphabetically
// (as RTLIL::Module::fixup_ports() would do)
for (auto port_name : box_module->ports) {
- RTLIL::Wire* w = box_module->wire(port_name);
- log_assert(w);
+ RTLIL::Wire* port = box_module->wire(port_name);
+ log_assert(port);
RTLIL::SigSpec rhs;
- RTLIL::Wire* wire = nullptr;
- for (int i = 0; i < GetSize(w); i++) {
- if (w->port_input) {
+ for (int i = 0; i < GetSize(port); i++) {
+ RTLIL::Wire* wire = nullptr;
+ if (port->port_input) {
log_assert(co_count < outputs.size());
wire = outputs[co_count++];
log_assert(wire);
log_assert(wire->port_output);
wire->port_output = false;
}
- if (w->port_output) {
+ if (port->port_output) {
log_assert((piNum + ci_count) < inputs.size());
wire = inputs[piNum + ci_count++];
log_assert(wire);
@@ -797,7 +811,26 @@ void AigerReader::post_process()
}
rhs.append(wire);
}
- cell->setPort(port_name, rhs);
+
+ if (!is_flop || port_name != "\\$pastQ")
+ cell->setPort(port_name, rhs);
+ }
+
+ if (is_flop) {
+ 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;
+
+ flop_count++;
+ module->connect(q, d);
+ cell->set_bool_attribute("\\abc_flop");
+ continue;
}
}
@@ -814,6 +847,7 @@ void AigerReader::post_process()
RTLIL::Wire* wire = inputs[variable];
log_assert(wire);
log_assert(wire->port_input);
+ log_debug("Renaming input %s", log_id(wire));
if (index == 0) {
// Cope with the fact that a CI might be identical
@@ -840,6 +874,7 @@ void AigerReader::post_process()
wire->port_input = false;
}
}
+ log_debug(" -> %s\n", log_id(wire));
}
else if (type == "output") {
log_assert(static_cast<unsigned>(variable + co_count) < outputs.size());
@@ -850,6 +885,7 @@ void AigerReader::post_process()
wire->port_output = false;
continue;
}
+ log_debug("Renaming output %s", log_id(wire));
if (index == 0) {
// Cope with the fact that a CO might be identical
@@ -871,6 +907,7 @@ void AigerReader::post_process()
else {
wire->port_output = false;
module->connect(wire, existing);
+ wire = existing;
}
}
else if (index > 0) {
@@ -896,6 +933,11 @@ void AigerReader::post_process()
wire->port_output = false;
}
}
+ log_debug(" -> %s\n", log_id(wire));
+ int init;
+ mf >> init;
+ if (init < 2)
+ wire->attributes["\\init"] = init;
}
else if (type == "box") {
RTLIL::Cell* cell = module->cell(stringf("$__box%d__", variable));
@@ -1004,8 +1046,8 @@ struct AigerFrontend : public Frontend {
log(" Name of module to be created (default: <filename>)\n");
log("\n");
log(" -clk_name <wire_name>\n");
- log(" AIGER latches to be transformed into posedge DFFs clocked by wire of");
- log(" this name (default: clk)\n");
+ log(" If specified, AIGER latches to be transformed into $_DFF_P_ cells\n");
+ log(" clocked by wire of this name. Otherwise, $_FF_ cells will be used.\n");
log("\n");
log(" -map <filename>\n");
log(" read file with port and latch symbols\n");
diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc
index 84cb2c04f..c7dc67c62 100644
--- a/passes/techmap/abc9.cc
+++ b/passes/techmap/abc9.cc
@@ -85,7 +85,7 @@ void handle_loops(RTLIL::Design *design,
// cell in the component, and select (and mark) all its output
// wires
pool<RTLIL::Const> ids_seen;
- for (auto cell : module->cells()) {
+ for (auto cell : module->selected_cells()) {
auto it = cell->attributes.find(ID(abc_scc_id));
if (it != cell->attributes.end()) {
auto r = ids_seen.insert(it->second);
@@ -269,7 +269,7 @@ struct abc_output_filter
};
void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file,
- bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str,
+ bool cleanup, vector<int> lut_costs, bool /*retime_mode*/, std::string clk_str,
bool /*keepff*/, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode,
bool show_tempdir, std::string box_file, std::string lut_file,
std::string wire_delay, const dict<int,IdString> &box_lookup,
@@ -309,8 +309,8 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
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());
+ //if (retime_mode && clk_sig.empty())
+ // log_cmd_error("Clock domain %s not found.\n", clk_str.c_str());
std::string tempdir_name = "/tmp/yosys-abc-XXXXXX";
if (!cleanup)
@@ -383,7 +383,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
fprintf(f, "%s\n", abc_script.c_str());
fclose(f);
- if (dff_mode || !clk_str.empty())
+ if (/*retime_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");
@@ -420,6 +420,9 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
//log("Extracted %d gates and %d wires to a netlist network with %d inputs and %d outputs.\n",
// count_gates, GetSize(signal_list), count_input, count_output);
+#if 0
+ Pass::call(design, stringf("write_verilog -noexpr -norename %s/before.v", tempdir_name.c_str()));
+#endif
Pass::call(design, stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str()));
std::string buffer;
@@ -528,6 +531,12 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
for (int i = 0; i < GetSize(w); i++)
output_bits.insert({wire, i});
}
+
+ auto jt = w->attributes.find("\\init");
+ if (jt != w->attributes.end()) {
+ auto r = remap_wire->attributes.insert(std::make_pair("\\init", jt->second));
+ log_assert(r.second);
+ }
}
for (auto &it : module->connections_) {
@@ -541,9 +550,8 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
dict<IdString, bool> abc_box;
vector<RTLIL::Cell*> boxes;
- for (const auto &it : module->cells_) {
- auto cell = it.second;
- if (cell->type.in(ID($_AND_), ID($_NOT_))) {
+ for (auto cell : module->selected_cells()) {
+ if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC_FF_))) {
module->remove(cell);
continue;
}
@@ -562,25 +570,23 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
dict<SigBit, std::vector<RTLIL::Cell*>> bit2sinks;
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;
- if (c->type == ID($_NOT_)) {
- RTLIL::SigBit a_bit = c->getPort(ID::A);
- RTLIL::SigBit y_bit = c->getPort(ID::Y);
- bit_users[a_bit].insert(c->name);
- bit_drivers[y_bit].insert(c->name);
+ if (mapped_cell->type == ID($_NOT_)) {
+ RTLIL::SigBit a_bit = mapped_cell->getPort(ID::A);
+ RTLIL::SigBit y_bit = mapped_cell->getPort(ID::Y);
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));
log_assert(wire);
module->connect(RTLIL::SigBit(wire, y_bit.offset), State::S1);
}
- else if (!lut_costs.empty() || !lut_file.empty()) {
- RTLIL::Cell* driver_lut = nullptr;
+ else {
+ RTLIL::Cell* driving_lut = nullptr;
// ABC can return NOT gates that drive POs
if (!a_bit.wire->port_input) {
// If it's not a NOT gate that that comes from a PI directly,
@@ -592,46 +598,46 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
driver_name = stringf("%s$lut", a_bit.wire->name.c_str());
else
driver_name = stringf("%s[%d]$lut", a_bit.wire->name.c_str(), a_bit.offset);
- driver_lut = mapped_mod->cell(driver_name);
+ driving_lut = mapped_mod->cell(driver_name);
}
- if (!driver_lut) {
+ if (!driving_lut) {
// If a driver couldn't be found (could be from PI or box CI)
// 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(y_bit.wire->name)), y_bit.offset),
RTLIL::Const::from_string("01"));
bit2sinks[cell->getPort(ID::A)].push_back(cell);
cell_stats[ID($lut)]++;
+ bit_users[a_bit].insert(mapped_cell->name);
+ bit_drivers[y_bit].insert(mapped_cell->name);
}
else
- not2drivers[c] = driver_lut;
+ not2drivers[mapped_cell] = driving_lut;
continue;
}
- else
- log_abort();
if (cell && markgroups) cell->attributes[ID(abcgroup)] = map_autoidx;
continue;
}
- cell_stats[c->type]++;
+ cell_stats[mapped_cell->type]++;
RTLIL::Cell *existing_cell = nullptr;
- if (c->type == ID($lut)) {
- if (GetSize(c->getPort(ID::A)) == 1 && c->getParam(ID(LUT)) == RTLIL::Const::from_string("01")) {
- SigSpec my_a = module->wires_.at(remap_name(c->getPort(ID::A).as_wire()->name));
- SigSpec my_y = module->wires_.at(remap_name(c->getPort(ID::Y).as_wire()->name));
+ if (mapped_cell->type == ID($lut)) {
+ if (GetSize(mapped_cell->getPort(ID::A)) == 1 && 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);
- if (markgroups) c->attributes[ID(abcgroup)] = map_autoidx;
+ if (markgroups) mapped_cell->attributes[ID(abcgroup)] = map_autoidx;
log_abort();
continue;
}
- cell = module->addCell(remap_name(c->name), c->type);
+ cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type);
}
else {
- existing_cell = module->cell(c->name);
+ existing_cell = module->cell(mapped_cell->name);
log_assert(existing_cell);
- cell = module->addCell(remap_name(c->name), c->type);
+ cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type);
module->swap_names(cell, existing_cell);
}
@@ -641,10 +647,12 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
cell->attributes = existing_cell->attributes;
}
else {
- cell->parameters = c->parameters;
- cell->attributes = c->attributes;
+ cell->parameters = mapped_cell->parameters;
+ cell->attributes = mapped_cell->attributes;
}
- for (auto &conn : c->connections()) {
+
+ auto abc_flop = mapped_cell->attributes.count("\\abc_flop");
+ for (auto &conn : mapped_cell->connections()) {
RTLIL::SigSpec newsig;
for (auto c : conn.second.chunks()) {
if (c.width == 0)
@@ -656,15 +664,17 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
}
cell->setPort(conn.first, newsig);
- if (cell->input(conn.first)) {
- for (auto i : newsig)
- bit2sinks[i].push_back(cell);
- for (auto i : conn.second)
- bit_users[i].insert(c->name);
+ if (!abc_flop) {
+ if (cell->input(conn.first)) {
+ for (auto i : newsig)
+ bit2sinks[i].push_back(cell);
+ for (auto i : conn.second)
+ bit_users[i].insert(mapped_cell->name);
+ }
+ if (cell->output(conn.first))
+ for (auto i : conn.second)
+ bit_drivers[i].insert(mapped_cell->name);
}
- if (cell->output(conn.first))
- for (auto i : conn.second)
- bit_drivers[i].insert(c->name);
}
}
@@ -690,29 +700,27 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
}
for (auto &it : cell_stats)
- log("ABC RESULTS: %15s cells: %8d\n", it.first.c_str(), it.second);
+ log("ABC RESULTS: %15s cells: %8d\n", log_id(it.first), it.second);
int in_wires = 0, out_wires = 0;
// Stitch in mapped_mod's inputs/outputs into module
- for (auto &it : mapped_mod->wires_) {
- RTLIL::Wire *w = it.second;
- if (!w->port_input && !w->port_output)
- continue;
- RTLIL::Wire *wire = module->wire(w->name);
+ for (auto port_name : mapped_mod->ports) {
+ RTLIL::Wire *port = mapped_mod->wire(port_name);
+ log_assert(port);
+ RTLIL::Wire *wire = module->wire(port->name);
log_assert(wire);
- RTLIL::Wire *remap_wire = module->wire(remap_name(w->name));
+ RTLIL::Wire *remap_wire = module->wire(remap_name(port->name));
RTLIL::SigSpec signal = RTLIL::SigSpec(wire, 0, GetSize(remap_wire));
log_assert(GetSize(signal) >= GetSize(remap_wire));
- log_assert(w->port_input || w->port_output);
RTLIL::SigSig conn;
- if (w->port_input) {
+ if (port->port_input) {
conn.first = remap_wire;
conn.second = signal;
in_wires++;
module->connect(conn);
}
- if (w->port_output) {
+ if (port->port_output) {
conn.first = signal;
conn.second = remap_wire;
out_wires++;
@@ -725,7 +733,21 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
for (auto driver_cell : bit_drivers.at(it.first))
for (auto user_cell : it.second)
toposort.edge(driver_cell, user_cell);
+#if 0
+ toposort.analyze_loops = true;
+#endif
bool no_loops YS_ATTRIBUTE(unused) = toposort.sort();
+#if 0
+ unsigned i = 0;
+ for (auto &it : toposort.loops) {
+ log(" loop %d\n", i++);
+ for (auto cell_name : it) {
+ auto cell = mapped_mod->cell(cell_name);
+ log_assert(cell);
+ log("\t%s (%s @ %s)\n", log_id(cell), log_id(cell->type), cell->get_src_attribute().c_str());
+ }
+ }
+#endif
log_assert(no_loops);
for (auto ii = toposort.sorted.rbegin(); ii != toposort.sorted.rend(); ii++) {
@@ -935,7 +957,7 @@ struct Abc9Pass : public Pass {
#endif
std::string script_file, clk_str, box_file, lut_file;
std::string delay_target, lutin_shared = "-S 1", wire_delay;
- bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true;
+ bool fast_mode = false, /*retime_mode = false,*/ keepff = false, cleanup = true;
bool show_tempdir = false;
vector<int> lut_costs;
markgroups = false;
@@ -1026,13 +1048,13 @@ struct Abc9Pass : public Pass {
fast_mode = true;
continue;
}
- //if (arg == "-dff") {
- // dff_mode = true;
+ //if (arg == "-retime") {
+ // retime_mode = true;
// continue;
//}
//if (arg == "-clk" && argidx+1 < args.size()) {
// clk_str = args[++argidx];
- // dff_mode = true;
+ // retime_mode = true;
// continue;
//}
//if (arg == "-keepff") {
@@ -1066,6 +1088,9 @@ struct Abc9Pass : public Pass {
}
extra_args(args, argidx, design);
+ if (lut_costs.empty() && lut_file.empty())
+ log_cmd_error("abc9 must be called with '-lut' or '-luts'\n");
+
dict<int,IdString> box_lookup;
dict<IdString,pool<IdString>> scc_break_inputs;
for (auto m : design->modules()) {
@@ -1144,10 +1169,16 @@ struct Abc9Pass : public Pass {
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,
+ if (true || /*!dff_mode ||*/ !clk_str.empty()) {
+
+ design->selection_stack.emplace_back(false);
+ RTLIL::Selection& sel = design->selection_stack.back();
+ sel.select(mod);
+
+ abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, false, clk_str, keepff,
delay_target, lutin_shared, fast_mode, show_tempdir,
box_file, lut_file, wire_delay, box_lookup, scc_break_inputs);
+ design->selection_stack.pop_back();
continue;
}
@@ -1167,8 +1198,14 @@ struct Abc9Pass : public Pass {
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)
- {
+ pool<IdString> seen_cells;
+ struct flop_data_t {
+ IdString clk_port;
+ IdString en_port;
+ };
+ dict<IdString, flop_data_t> flop_data;
+
+ for (auto cell : all_cells) {
clkdomain_t key;
for (auto &conn : cell->connections())
@@ -1188,19 +1225,57 @@ struct Abc9Pass : public Pass {
}
}
- if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_)))
- {
- key = clkdomain_t(cell->type == ID($_DFF_P_), assign_map(cell->getPort(ID(C))), true, RTLIL::SigSpec());
+ decltype(flop_data)::iterator it;
+ if (seen_cells.insert(cell->type).second) {
+ RTLIL::Module* inst_module = design->module(cell->type);
+ if (!inst_module)
+ continue;
+
+ if (!inst_module->attributes.count("\\abc_flop"))
+ continue;
+
+ IdString abc_flop_clk, abc_flop_en;
+ for (auto port_name : inst_module->ports) {
+ auto wire = inst_module->wire(port_name);
+ log_assert(wire);
+ if (wire->attributes.count("\\abc_flop_clk")) {
+ if (abc_flop_clk != IdString())
+ log_error("More than one port has the 'abc_flop_clk' attribute set on module '%s'.\n", log_id(cell->type));
+ abc_flop_clk = port_name;
+ }
+ if (wire->attributes.count("\\abc_flop_en")) {
+ if (abc_flop_en != IdString())
+ log_error("More than one port has the 'abc_flop_en' attribute set on module '%s'.\n", log_id(cell->type));
+ abc_flop_en = port_name;
+ }
+ }
+
+ if (abc_flop_clk == IdString())
+ log_error("'abc_flop_clk' attribute not found on any ports on module '%s'.\n", log_id(cell->type));
+ if (abc_flop_en == IdString())
+ log_error("'abc_flop_en' attribute not found on any ports on module '%s'.\n", log_id(cell->type));
+
+ it = flop_data.insert(std::make_pair(cell->type, flop_data_t{abc_flop_clk, abc_flop_en})).first;
}
- 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 {
+ it = flop_data.find(cell->type);
+ if (it == flop_data.end())
+ continue;
}
- else
- continue;
+
+ const auto &data = it->second;
+
+ auto jt = cell->parameters.find("\\CLK_POLARITY");
+ if (jt == cell->parameters.end())
+ log_error("'CLK_POLARITY' is not a parameter on module '%s'.\n", log_id(cell->type));
+ bool this_clk_pol = jt->second.as_bool();
+
+ jt = cell->parameters.find("\\EN_POLARITY");
+ if (jt == cell->parameters.end())
+ log_error("'EN_POLARITY' is not a parameter on module '%s'.\n", log_id(cell->type));
+ bool this_en_pol = jt->second.as_bool();
+
+ key = clkdomain_t(this_clk_pol, assign_map(cell->getPort(data.clk_port)), this_en_pol, assign_map(cell->getPort(data.en_port)));
unassigned_cells.erase(cell);
expand_queue.insert(cell);
@@ -1286,16 +1361,29 @@ struct Abc9Pass : public Pass {
std::get<0>(it.first) ? "" : "!", log_signal(std::get<1>(it.first)),
std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(it.first)));
+ design->selection_stack.emplace_back(false);
+
for (auto &it : assigned_cells) {
+ // FIXME: abc9_module calls below can delete cells,
+ // leaving a dangling pointer here...
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));
+
+ pool<RTLIL::IdString> assigned_names;
+ for (auto i : it.second)
+ assigned_names.insert(i->name);
+ RTLIL::Selection& sel = design->selection_stack.back();
+ sel.selected_members[mod->name] = std::move(assigned_names);
+
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, scc_break_inputs);
assign_map.set(mod);
}
+
+ design->selection_stack.pop_back();
}
assign_map.clear();
diff --git a/techlibs/xilinx/Makefile.inc b/techlibs/xilinx/Makefile.inc
index 2b1af289c..2efcf7d90 100644
--- a/techlibs/xilinx/Makefile.inc
+++ b/techlibs/xilinx/Makefile.inc
@@ -39,6 +39,9 @@ $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/ff_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/mux_map.v))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_map.v))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_unmap.v))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_model.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_xc7.box))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_xc7.lut))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_xc7_nowide.lut))
diff --git a/techlibs/xilinx/abc_map.v b/techlibs/xilinx/abc_map.v
new file mode 100644
index 000000000..56b4fe7f9
--- /dev/null
+++ b/techlibs/xilinx/abc_map.v
@@ -0,0 +1,225 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * 2019 Eddie Hung <eddie@fpgeh.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+// ============================================================================
+
+// Max delays from https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L237-L251
+
+module FDRE (output reg 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;
+ wire \$nextQ ;
+ \$__ABC_FDRE #(
+ .INIT(INIT),
+ .IS_C_INVERTED(IS_C_INVERTED),
+ .IS_D_INVERTED(IS_D_INVERTED),
+ .IS_R_INVERTED(IS_R_INVERTED),
+ .CLK_POLARITY(!IS_C_INVERTED),
+ .EN_POLARITY(1'b1)
+ ) _TECHMAP_REPLACE_ (
+ .D(D), .Q(\$nextQ ), .\$pastQ (Q), .C(C), .CE(CE), .R(R)
+ );
+ \$__ABC_FF_ abc_dff (.D(\$nextQ ), .Q(Q));
+endmodule
+module FDRE_1 (output reg Q, input C, CE, D, R);
+ parameter [0:0] INIT = 1'b0;
+ wire \$nextQ ;
+ \$__ABC_FDRE_1 #(
+ .INIT(|0),
+ .CLK_POLARITY(1'b0),
+ .EN_POLARITY(1'b1)
+ ) _TECHMAP_REPLACE_ (
+ .D(D), .Q(\$nextQ ), .\$pastQ (Q), .C(C), .CE(CE), .R(R)
+ );
+ \$__ABC_FF_ abc_dff (.D(\$nextQ ), .Q(Q));
+endmodule
+
+module FDCE (output reg 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;
+ wire \$nextQ , \$currQ ;
+ \$__ABC_FDCE #(
+ .INIT(INIT),
+ .IS_C_INVERTED(IS_C_INVERTED),
+ .IS_D_INVERTED(IS_D_INVERTED),
+ .IS_CLR_INVERTED(IS_CLR_INVERTED),
+ .CLK_POLARITY(!IS_C_INVERTED),
+ .EN_POLARITY(1'b1)
+ ) _TECHMAP_REPLACE_ (
+ .D(D), .Q(\$nextQ ), .\$pastQ (Q), .C(C), .CE(CE), .CLR(CLR)
+ );
+ \$__ABC_FF_ abc_dff (.D(\$nextQ ), .Q(\$currQ ));
+ \$__ABC_ASYNC abc_async (.A(\$currQ ), .S(CLR), .Y(Q));
+endmodule
+module FDCE_1 (output reg Q, input C, CE, D, CLR);
+ parameter [0:0] INIT = 1'b0;
+ wire \$nextQ , \$currQ ;
+ \$__ABC_FDCE_1 #(
+ .INIT(INIT),
+ .CLK_POLARITY(1'b0),
+ .EN_POLARITY(1'b1)
+ ) _TECHMAP_REPLACE_ (
+ .D(D), .Q(\$nextQ ), .\$pastQ (Q), .C(C), .CE(CE), .CLR(CLR)
+ );
+ \$__ABC_FF_ abc_dff (.D(\$nextQ ), .Q(\$currQ ));
+ \$__ABC_ASYNC abc_async (.A(\$currQ ), .S(CLR), .Y(Q));
+endmodule
+
+module FDPE (output reg Q, input C, CE, D, PRE);
+ 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;
+ wire \$nextQ , \$currQ ;
+ \$__ABC_FDPE #(
+ .INIT(INIT),
+ .IS_C_INVERTED(IS_C_INVERTED),
+ .IS_D_INVERTED(IS_D_INVERTED),
+ .IS_PRE_INVERTED(IS_PRE_INVERTED),
+ .CLK_POLARITY(!IS_C_INVERTED),
+ .EN_POLARITY(1'b1)
+ ) _TECHMAP_REPLACE_ (
+ .D(D), .Q(\$nextQ ), .\$pastQ (Q), .C(C), .CE(CE), .PRE(PRE)
+ );
+ \$__ABC_FF_ abc_dff (.D(\$nextQ ), .Q(\$currQ ));
+ \$__ABC_ASYNC abc_async (.A(\$currQ ), .S(PRE), .Y(Q));
+endmodule
+module FDPE_1 (output reg Q, input C, CE, D, PRE);
+ parameter [0:0] INIT = 1'b0;
+ wire \$nextQ , \$currQ ;
+ \$__ABC_FDPE_1 #(
+ .INIT(INIT),
+ .CLK_POLARITY(1'b0),
+ .EN_POLARITY(1'b1)
+ ) _TECHMAP_REPLACE_ (
+ .D(D), .Q(\$nextQ ), .\$pastQ (Q), .C(C), .CE(CE), .PRE(PRE)
+ );
+ \$__ABC_FF_ abc_dff (.D(\$nextQ ), .Q(\$currQ ));
+ \$__ABC_ASYNC abc_async (.A(\$currQ ), .S(PRE), .Y(Q));
+endmodule
+
+module RAM32X1D (
+ output DPO, SPO,
+ input D,
+ input WCLK,
+ input WE,
+ input A0, A1, A2, A3, A4,
+ input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4
+);
+ parameter INIT = 32'h0;
+ parameter IS_WCLK_INVERTED = 1'b0;
+ wire \$DPO , \$SPO ;
+ \$__ABC_RAM32X1D #(
+ .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED)
+ ) _TECHMAP_REPLACE_ (
+ .DPO(\$DPO ), .SPO(\$SPO ),
+ .D(D), .WCLK(WCLK), .WE(WE),
+ .A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4),
+ .DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4)
+ );
+ \$__ABC_LUTMUX dpo (.A(\$DPO ), .S({1'b0, A0, A1, A2, A3, A4}), .Y(DPO));
+ \$__ABC_LUTMUX spo (.A(\$SPO ), .S({1'b0, A0, A1, A2, A3, A4}), .Y(SPO));
+endmodule
+
+module RAM64X1D (
+ output DPO, SPO,
+ input D,
+ input WCLK,
+ input WE,
+ input A0, A1, A2, A3, A4, A5,
+ input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5
+);
+ parameter INIT = 64'h0;
+ parameter IS_WCLK_INVERTED = 1'b0;
+ wire \$DPO , \$SPO ;
+ \$__ABC_RAM64X1D #(
+ .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED)
+ ) _TECHMAP_REPLACE_ (
+ .DPO(\$DPO ), .SPO(\$SPO ),
+ .D(D), .WCLK(WCLK), .WE(WE),
+ .A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4), .A5(A5),
+ .DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4), .DPRA5(DPRA5)
+ );
+ \$__ABC_LUTMUX6 dpo (.A(\$DPO ), .S({A0, A1, A2, A3, A4, A5}), .Y(DPO));
+ \$__ABC_LUTMUX6 spo (.A(\$SPO ), .S({A0, A1, A2, A3, A4, A5}), .Y(SPO));
+endmodule
+
+module \$__ABC_RAM128X1D (
+ output DPO, SPO,
+ input D,
+ input WCLK,
+ input WE,
+ input [6:0] A, DPRA
+);
+ parameter INIT = 128'h0;
+ parameter IS_WCLK_INVERTED = 1'b0;
+ wire \$DPO , \$SPO ;
+ \$__ABC_RAM128X1D #(
+ .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED)
+ ) _TECHMAP_REPLACE_ (
+ .DPO(\$DPO ), .SPO(\$SPO ),
+ .D(D), .WCLK(WCLK), .WE(WE),
+ .A(A),
+ .DPRA(DPRA)
+ );
+ \$__ABC_LUTMUX7 dpo (.A(\$DPO ), .S(A), .Y(DPO));
+ \$__ABC_LUTMUX7 spo (.A(\$SPO ), .S(A), .Y(SPO));
+endmodule
+
+module SRL16E (
+ output Q,
+ input A0, A1, A2, A3, CE, CLK, D
+);
+ parameter [15:0] INIT = 16'h0000;
+ parameter [0:0] IS_CLK_INVERTED = 1'b0;
+ wire \$Q ;
+ \$__ABC_SRL16E #(
+ .INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED)
+ ) _TECHMAP_REPLACE_ (
+ .Q(\$Q ),
+ .A0(A0), .A1(A1), .A2(A2), .A3(A3), .CE(CE), .CLK(CLK), .D(D)
+ );
+ // TODO: Check if SRL uses fast inputs or slow inputs
+ \$__ABC_LUTMUX6 q (.A(\$Q ), .S({A0, A1, A2, A3, 1'b0, 1'b0}), .Y(Q));
+endmodule
+
+module SRLC32E (
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904-L905
+ (* abc_arrival=1472 *) output Q,
+ (* abc_arrival=1114 *) output Q31,
+ input [4:0] A,
+ input CE, CLK, D
+);
+ parameter [31:0] INIT = 32'h00000000;
+ parameter [0:0] IS_CLK_INVERTED = 1'b0;
+ wire \$Q ;
+ \$__ABC_SRLC32E #(
+ .INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED)
+ ) _TECHMAP_REPLACE_ (
+ .Q(\$Q ), .Q31(Q31),
+ .A(A), .CE(CE), .CLK(CLK), .D(D)
+ );
+ // TODO: Check if SRL uses fast inputs or slow inputs
+ \$__ABC_LUTMUX6 q (.A(\$Q ), .S({A, 1'b0}), .Y(Q));
+endmodule
diff --git a/techlibs/xilinx/abc_model.v b/techlibs/xilinx/abc_model.v
new file mode 100644
index 000000000..7162bd213
--- /dev/null
+++ b/techlibs/xilinx/abc_model.v
@@ -0,0 +1,179 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * 2019 Eddie Hung <eddie@fpgeh.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+// ============================================================================
+
+(* abc_box_id = 3, lib_whitebox *)
+module \$__XILINX_MUXF78 (output O, input I0, I1, I2, I3, S0, S1);
+ assign O = S1 ? (S0 ? I3 : I2)
+ : (S0 ? I1 : I0);
+endmodule
+
+module \$__ABC_FF_ (input C, D, output Q);
+endmodule
+
+(* abc_box_id = 1000 *)
+module \$__ABC_ASYNC (input A, S, output Y);
+endmodule
+
+(* abc_box_id=1001, lib_whitebox, abc_flop *)
+module \$__ABC_FDRE ((* abc_flop_q, abc_arrival=303 *) output Q,
+ (* abc_flop_clk *) input C,
+ (* abc_flop_en *) input CE,
+ (* abc_flop_d *) input D,
+ input R, \$pastQ );
+ 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;
+ parameter CLK_POLARITY = !IS_C_INVERTED;
+ parameter EN_POLARITY = 1'b1;
+ assign Q = (R ^ IS_R_INVERTED) ? 1'b0 : (CE ? (D ^ IS_D_INVERTED) : \$pastQ );
+endmodule
+
+(* abc_box_id=1002, lib_whitebox, abc_flop *)
+module \$__ABC_FDRE_1 ((* abc_flop_q, abc_arrival=303 *) output Q,
+ (* abc_flop_clk *) input C,
+ (* abc_flop_en *) input CE,
+ (* abc_flop_d *) input D,
+ input R, \$pastQ );
+ parameter [0:0] INIT = 1'b0;
+ parameter CLK_POLARITY = 1'b0;
+ parameter EN_POLARITY = 1'b1;
+ assign Q = R ? 1'b0 : (CE ? D : \$pastQ );
+endmodule
+
+(* abc_box_id=1003, lib_whitebox, abc_flop *)
+module \$__ABC_FDCE ((* abc_flop_q, abc_arrival=303 *) output Q,
+ (* abc_flop_clk *) input C,
+ (* abc_flop_en *) input CE,
+ (* abc_flop_d *) input D,
+ input CLR, \$pastQ );
+ 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;
+ parameter CLK_POLARITY = !IS_C_INVERTED;
+ parameter EN_POLARITY = 1'b1;
+ assign Q = (CE && !(CLR ^ IS_CLR_INVERTED)) ? (D ^ IS_D_INVERTED) : \$pastQ ;
+endmodule
+
+(* abc_box_id=1004, lib_whitebox, abc_flop *)
+module \$__ABC_FDCE_1 ((* abc_flop_q, abc_arrival=303 *) output Q,
+ (* abc_flop_clk *) input C,
+ (* abc_flop_en *) input CE,
+ (* abc_flop_d *) input D,
+ input CLR, \$pastQ );
+ parameter [0:0] INIT = 1'b0;
+ parameter CLK_POLARITY = 1'b0;
+ parameter EN_POLARITY = 1'b1;
+ assign Q = (CE && !CLR) ? D : \$pastQ ;
+endmodule
+
+(* abc_box_id=1005, lib_whitebox, abc_flop *)
+module \$__ABC_FDPE ((* abc_flop_q, abc_arrival=303 *) output Q,
+ (* abc_flop_clk *) input C,
+ (* abc_flop_en *) input CE,
+ (* abc_flop_d *) input D,
+ input PRE, \$pastQ );
+ 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;
+ parameter CLK_POLARITY = !IS_C_INVERTED;
+ parameter EN_POLARITY = 1'b1;
+ assign Q = (CE && !(PRE ^ IS_PRE_INVERTED)) ? (D ^ IS_D_INVERTED) : \$pastQ ;
+endmodule
+
+(* abc_box_id=1006, lib_whitebox, abc_flop *)
+module \$__ABC_FDPE_1 ((* abc_flop_q, abc_arrival=303 *) output Q,
+ (* abc_flop_clk *) input C,
+ (* abc_flop_en *) input CE,
+ (* abc_flop_d *) input D,
+ input PRE, \$pastQ );
+ parameter [0:0] INIT = 1'b0;
+ parameter CLK_POLARITY = 1'b0;
+ parameter EN_POLARITY = 1'b1;
+ assign Q = (CE && !PRE) ? D : \$pastQ ;
+endmodule
+
+(* abc_box_id=2000 *)
+module \$__ABC_LUTMUX6 (input A, input [5:0] S, output Y);
+endmodule
+(* abc_box_id=2001 *)
+module \$__ABC_LUTMUX7 (input A, input [6:0] S, output Y);
+endmodule
+
+
+module \$__ABC_RAM32X1D (
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
+ (* abc_arrival=1153 *) output DPO, SPO,
+ input D,
+ input WCLK,
+ input WE,
+ input A0, A1, A2, A3, A4,
+ input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4
+);
+endmodule
+
+module \$__ABC_RAM64X1D (
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
+ (* abc_arrival=1153 *) output DPO, SPO,
+ input D,
+ input WCLK,
+ input WE,
+ input A0, A1, A2, A3, A4, A5,
+ input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5
+);
+ parameter INIT = 64'h0;
+ parameter IS_WCLK_INVERTED = 1'b0;
+endmodule
+
+module \$__ABC_RAM128X1D (
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
+ (* abc_arrival=1153 *) output DPO, SPO,
+ input D,
+ input WCLK,
+ input WE,
+ input [6:0] A, DPRA
+);
+ parameter INIT = 128'h0;
+ parameter IS_WCLK_INVERTED = 1'b0;
+endmodule
+
+module SRL16E (
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904-L905
+ (* abc_arrival=1472 *) output Q,
+ input A0, A1, A2, A3, CE, CLK, D
+);
+ parameter [15:0] INIT = 16'h0000;
+ parameter [0:0] IS_CLK_INVERTED = 1'b0;
+endmodule
+
+module SRLC32E (
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904-L905
+ (* abc_arrival=1472 *) output Q,
+ (* abc_arrival=1114 *) output Q31,
+ input [4:0] A,
+ input CE, CLK, D
+);
+ parameter [31:0] INIT = 32'h00000000;
+ parameter [0:0] IS_CLK_INVERTED = 1'b0;
+endmodule
diff --git a/techlibs/xilinx/abc_unmap.v b/techlibs/xilinx/abc_unmap.v
new file mode 100644
index 000000000..d00d27e2e
--- /dev/null
+++ b/techlibs/xilinx/abc_unmap.v
@@ -0,0 +1,239 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * 2019 Eddie Hung <eddie@fpgeh.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+// ============================================================================
+
+module \$__ABC_ASYNC (input A, S, output Y);
+ assign Y = A;
+endmodule
+
+module \$__ABC_FDRE (output Q,
+ input C,
+ input CE,
+ input D,
+ input R, \$pastQ );
+ 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;
+ parameter CLK_POLARITY = !IS_C_INVERTED;
+ parameter EN_POLARITY = 1'b1;
+
+ 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)
+ );
+endmodule
+
+module \$__ABC_FDRE_1 (output Q,
+ input C,
+ input CE,
+ input D,
+ input R, \$pastQ );
+ parameter [0:0] INIT = 1'b0;
+ parameter CLK_POLARITY = 1'b0;
+ parameter EN_POLARITY = 1'b1;
+ assign Q = R ? 1'b0 : (CE ? D : \$pastQ );
+
+ FDRE_1 #(
+ .INIT(INIT),
+ ) _TECHMAP_REPLACE_ (
+ .D(D), .Q(Q), .C(C), .CE(CE), .R(R)
+ );
+endmodule
+
+module \$__ABC_FDCE (output Q,
+ input C,
+ input CE,
+ input D,
+ input CLR, \$pastQ );
+ 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;
+ parameter CLK_POLARITY = !IS_C_INVERTED;
+ parameter EN_POLARITY = 1'b1;
+
+ 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)
+ );
+endmodule
+
+module \$__ABC_FDCE_1 (output Q,
+ input C,
+ input CE,
+ input D,
+ input CLR, \$pastQ );
+ parameter [0:0] INIT = 1'b0;
+ parameter CLK_POLARITY = 1'b0;
+ parameter EN_POLARITY = 1'b1;
+
+ FDCE_1 #(
+ .INIT(INIT),
+ ) _TECHMAP_REPLACE_ (
+ .D(D), .Q(Q), .C(C), .CE(CE), .CLR(CLR)
+ );
+endmodule
+
+module \$__ABC_FDPE (output Q,
+ input C,
+ input CE,
+ input D,
+ input PRE, \$pastQ );
+ 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;
+ parameter CLK_POLARITY = !IS_C_INVERTED;
+ parameter EN_POLARITY = 1'b1;
+
+ 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)
+ );
+endmodule
+
+module \$__ABC_FDPE_1 (output Q,
+ input C,
+ input CE,
+ input D,
+ input PRE, \$pastQ );
+ parameter [0:0] INIT = 1'b0;
+ parameter CLK_POLARITY = 1'b0;
+ parameter EN_POLARITY = 1'b1;
+
+ FDPE_1 #(
+ .INIT(INIT),
+ ) _TECHMAP_REPLACE_ (
+ .D(D), .Q(Q), .C(C), .CE(CE), .PRE(PRE)
+ );
+endmodule
+
+module \$__ABC_LUTMUX6 (input A, input [5:0] S, output Y);
+ assign Y = A;
+endmodule
+module \$__ABC_LUTMUX7 (input A, input [6:0] S, output Y);
+ assign Y = A;
+endmodule
+
+module \$__ABC_RAM32X1D (
+ output DPO, SPO,
+ input D,
+ input WCLK,
+ input WE,
+ input A0, A1, A2, A3, A4,
+ input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4
+);
+ parameter INIT = 32'h0;
+ parameter IS_WCLK_INVERTED = 1'b0;
+ RAM32X1D #(
+ .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED)
+ ) _TECHMAP_REPLACE_ (
+ .DPO(DPO), .SPO(SPO),
+ .D(D), .WCLK(WCLK), .WE(WE),
+ .A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4),
+ .DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4)
+ );
+endmodule
+
+module \$__ABC_RAM64X1D (
+ output DPO, SPO,
+ input D,
+ input WCLK,
+ input WE,
+ input A0, A1, A2, A3, A4, A5,
+ input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5
+);
+ parameter INIT = 64'h0;
+ parameter IS_WCLK_INVERTED = 1'b0;
+ RAM64X1D #(
+ .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED)
+ ) _TECHMAP_REPLACE_ (
+ .DPO(DPO), .SPO(SPO),
+ .D(D), .WCLK(WCLK), .WE(WE),
+ .A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4), .A5(A5),
+ .DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4), .DPRA5(DPRA5)
+ );
+endmodule
+
+module \$__ABC_RAM128X1D (
+ output DPO, SPO,
+ input D,
+ input WCLK,
+ input WE,
+ input A,
+ input DPRA,
+);
+ parameter INIT = 128'h0;
+ parameter IS_WCLK_INVERTED = 1'b0;
+ RAM128X1D #(
+ .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED)
+ ) _TECHMAP_REPLACE_ (
+ .DPO(DPO), .SPO(SPO),
+ .D(D), .WCLK(WCLK), .WE(WE),
+ .A(A),
+ .DPRA(DPRA)
+ );
+endmodule
+
+module \$__ABC_SRL16E (
+ output Q,
+ input A0, A1, A2, A3, CE, CLK, D
+);
+ parameter [15:0] INIT = 16'h0000;
+ parameter [0:0] IS_CLK_INVERTED = 1'b0;
+
+ SRL16E #(
+ .INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED)
+ ) _TECHMAP_REPLACE_ (
+ .Q(Q),
+ .A0(A0), .A1(A1), .A2(A2), .A3(A3), .CE(CE), .CLK(CLK), .D(D)
+ );
+endmodule
+
+module \$__ABC_SRLC32E (
+ output Q,
+ output Q31,
+ input [4:0] A,
+ input CE, CLK, D
+);
+ parameter [31:0] INIT = 32'h00000000;
+ parameter [0:0] IS_CLK_INVERTED = 1'b0;
+
+ SRLC32E #(
+ .INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED)
+ ) _TECHMAP_REPLACE_ (
+ .Q(Q), .Q31(Q31),
+ .A(A), .CE(CE), .CLK(CLK), .D(D)
+ );
+endmodule
diff --git a/techlibs/xilinx/abc_xc7.box b/techlibs/xilinx/abc_xc7.box
index 3789ff350..c08af6320 100644
--- a/techlibs/xilinx/abc_xc7.box
+++ b/techlibs/xilinx/abc_xc7.box
@@ -1,4 +1,5 @@
# Max delays from https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf
+# https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf
# NB: Inputs/Outputs must be ordered alphabetically
# (with exceptions for carry in/out)
@@ -14,6 +15,7 @@ F7MUX 1 1 3 1
MUXF8 2 1 3 1
104 94 273
+# Box containing MUXF7.[AB] + MUXF8
# Inputs: I0 I1 I2 I3 S0 S1
# Outputs: O
$__MUXF78 3 1 6 1
@@ -36,23 +38,57 @@ CARRY4 4 1 10 8
592 540 520 356 - 512 548 292 - 228
580 526 507 398 385 508 528 378 380 114
-# SLICEM/A6LUT
-# Inputs: A0 A1 A2 A3 A4 D DPRA0 DPRA1 DPRA2 DPRA3 DPRA4 WCLK WE
-# Outputs: DPO SPO
-RAM32X1D 5 0 13 2
-- - - - - - 631 472 407 238 127 - -
-631 472 407 238 127 - - - - - - - -
+# Box to emulate async behaviour of FD[CP]*
+# Inputs: A S
+# Outputs: Y
+$__ABC_ASYNC 1000 0 2 1
+0 764
+
+# The following FD*.{CE,R,CLR,PRE) are offset by 46ps to
+# reflect the -46ps Tsu
+# 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
+
+# Inputs: C CE D R \$pastQ
+# Outputs: Q
+FDRE 1001 1 5 1
+0 151 0 446 0
+
+# Inputs: C CE D R \$pastQ
+# Outputs: Q
+FDRE_1 1002 1 5 1
+0 151 0 446 0
+
+# Inputs: C CE CLR D \$pastQ
+# Outputs: Q
+FDCE 1003 1 5 1
+0 151 806 0 0
+
+# Inputs: C CE CLR D \$pastQ
+# Outputs: Q
+FDCE_1 1004 1 5 1
+0 151 806 0 0
+
+# Inputs: C CE D PRE \$pastQ
+# Outputs: Q
+FDPE 1005 1 5 1
+0 151 0 806 0
+
+# Inputs: C CE D PRE \$pastQ
+# Outputs: Q
+FDPE_1 1006 1 5 1
+0 151 0 806 0
# SLICEM/A6LUT
-# Inputs: A0 A1 A2 A3 A4 A5 D DPRA0 DPRA1 DPRA2 DPRA3 DPRA4 DPRA5 WCLK WE
-# Outputs: DPO SPO
-RAM64X1D 6 0 15 2
-- - - - - - - 642 631 472 407 238 127 - -
-642 631 472 407 238 127 - - - - - - - - -
+# Box to emulate comb/seq behaviour of RAMD{32,64} and SRL{16,32}
+# Inputs: A S0 S1 S2 S3 S4 S5
+# Outputs: Y
+$__ABC_LUTRAM6 2000 0 7 1
+0 642 631 472 407 238 127
-# SLICEM/A6LUT + F7[AB]MUX
-# Inputs: A0 A1 A2 A3 A4 A5 A6 D DPRA0 DPRA1 DPRA2 DPRA3 DPRA4 DPRA5 DPRA6 WCLK WE
+# SLICEM/A6LUT + F7BMUX
+# Box to emulate comb/seq behaviour of RAMD128
+# Inputs: A S0 S1 S2 S3 S4 S5 S6
# Outputs: DPO SPO
-RAM128X1D 7 0 17 2
-- - - - - - - - 1009 998 839 774 605 494 450 - -
-1047 1036 877 812 643 532 478 - - - - - - - - - -
+$__ABC_LUTRAM7 2001 0 8 1
+0 1047 1036 877 812 643 532 478
diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v
index b8e5bafc7..a15884ec4 100644
--- a/techlibs/xilinx/cells_map.v
+++ b/techlibs/xilinx/cells_map.v
@@ -331,7 +331,6 @@ module \$_MUX16_ (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, S, T, U, V, Y)
endmodule
`endif
-`ifndef _ABC
module \$__XILINX_MUXF78 (O, I0, I1, I2, I3, S0, S1);
output O;
input I0, I1, I2, I3, S0, S1;
@@ -364,4 +363,3 @@ module \$__XILINX_MUXF78 (O, I0, I1, I2, I3, S0, S1);
else
MUXF8 mux8 (.I0(T0), .I1(T1), .S(S1), .O(O));
endmodule
-`endif
diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v
index bec9ea1a0..e5261de1c 100644
--- a/techlibs/xilinx/cells_sim.v
+++ b/techlibs/xilinx/cells_sim.v
@@ -169,14 +169,6 @@ module MUXF8(output O, input I0, I1, S);
assign O = S ? I1 : I0;
endmodule
-`ifdef _ABC
-(* abc_box_id = 3, lib_whitebox *)
-module \$__XILINX_MUXF78 (output O, input I0, I1, I2, I3, S0, S1);
- assign O = S1 ? (S0 ? I3 : I2)
- : (S0 ? I1 : I0);
-endmodule
-`endif
-
module XORCY(output O, input CI, LI);
assign O = CI ^ LI;
endmodule
@@ -295,12 +287,11 @@ module FDPE_1 (output reg Q, input C, CE, D, PRE);
always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D;
endmodule
-(* abc_box_id = 5 *)
module RAM32X1D (
output DPO, SPO,
- (* abc_scc_break *) input D,
+ input D,
input WCLK,
- (* abc_scc_break *) input WE,
+ input WE,
input A0, A1, A2, A3, A4,
input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4
);
@@ -315,12 +306,11 @@ module RAM32X1D (
always @(posedge clk) if (WE) mem[a] <= D;
endmodule
-(* abc_box_id = 6 *)
module RAM64X1D (
output DPO, SPO,
- (* abc_scc_break *) input D,
+ input D,
input WCLK,
- (* abc_scc_break *) input WE,
+ input WE,
input A0, A1, A2, A3, A4, A5,
input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5
);
@@ -335,12 +325,11 @@ module RAM64X1D (
always @(posedge clk) if (WE) mem[a] <= D;
endmodule
-(* abc_box_id = 7 *)
module RAM128X1D (
output DPO, SPO,
- (* abc_scc_break *) input D,
+ input D,
input WCLK,
- (* abc_scc_break *) input WE,
+ input WE,
input [6:0] A, DPRA
);
parameter INIT = 128'h0;
@@ -353,7 +342,8 @@ module RAM128X1D (
endmodule
module SRL16E (
- output Q,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904-L905
+ (* abc_arrival=1472 *) output Q,
input A0, A1, A2, A3, CE, CLK, D
);
parameter [15:0] INIT = 16'h0000;
@@ -371,8 +361,9 @@ module SRL16E (
endmodule
module SRLC32E (
- output Q,
- output Q31,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904-L905
+ (* abc_arrival=1472 *) output Q,
+ (* abc_arrival=1114 *) output Q31,
input [4:0] A,
input CE, CLK, D
);
diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc
index 7ba67409b..d6ff91e13 100644
--- a/techlibs/xilinx/synth_xilinx.cc
+++ b/techlibs/xilinx/synth_xilinx.cc
@@ -230,9 +230,9 @@ struct SynthXilinxPass : public ScriptPass
{
if (check_label("begin")) {
if (vpr)
- run("read_verilog -lib -icells -D _ABC -D_EXPLICIT_CARRY +/xilinx/cells_sim.v");
+ run("read_verilog -lib -D_EXPLICIT_CARRY +/xilinx/cells_sim.v");
else
- run("read_verilog -lib -icells -D _ABC +/xilinx/cells_sim.v");
+ run("read_verilog -lib +/xilinx/cells_sim.v");
run("read_verilog -lib +/xilinx/cells_xtra.v");
@@ -376,9 +376,11 @@ struct SynthXilinxPass : public ScriptPass
}
if (check_label("map_cells")) {
- std::string techmap_args = "-map +/techmap.v -D _ABC -map +/xilinx/cells_map.v";
+ std::string techmap_args = "-map +/techmap.v -map +/xilinx/cells_map.v";
if (widemux > 0)
techmap_args += stringf(" -D MIN_MUX_INPUTS=%d", widemux);
+ if (abc9)
+ techmap_args += " -map +/xilinx/ff_map.v -map +/xilinx/abc_map.v";
run("techmap " + techmap_args);
run("clean");
}
@@ -390,6 +392,7 @@ struct SynthXilinxPass : public ScriptPass
else if (abc9) {
if (family != "xc7")
log_warning("'synth_xilinx -abc9' currently supports '-family xc7' only.\n");
+ run("read_verilog -icells -lib +/xilinx/abc_model.v");
if (nowidelut)
run("abc9 -lut +/xilinx/abc_xc7_nowide.lut -box +/xilinx/abc_xc7.box -W " + std::to_string(XC7_WIRE_DELAY));
else
@@ -407,7 +410,10 @@ struct SynthXilinxPass : public ScriptPass
// has performed any necessary retiming
if (!nosrl || help_mode)
run("shregmap -minlen 3 -init -params -enpol any_or_none", "(skip if '-nosrl')");
- run("techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v");
+ if (abc9)
+ run("techmap -map +/xilinx/lut_map.v -map +/xilinx/abc_unmap.v");
+ else
+ run("techmap -map +/xilinx/lut_map.v -map +/xilinx/cells_map.v -map +/xilinx/ff_map.v");
run("dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT "
"-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT");
run("clean");
diff --git a/techlibs/xilinx/xc7_brams_bb.v b/techlibs/xilinx/xc7_brams_bb.v
index a682ba4a7..0e8cb406c 100644
--- a/techlibs/xilinx/xc7_brams_bb.v
+++ b/techlibs/xilinx/xc7_brams_bb.v
@@ -1,3 +1,5 @@
+// Max delays from https://github.com/SymbiFlow/prjxray-db/blob/f8e0364116b2983ac72a3dc8c509ea1cc79e2e3d/artix7/timings/BRAM_L.sdf#L138-L147
+
module RAMB18E1 (
input CLKARDCLK,
input CLKBWRCLK,
@@ -19,10 +21,10 @@ module RAMB18E1 (
input [1:0] WEA,
input [3:0] WEBWE,
- output [15:0] DOADO,
- output [15:0] DOBDO,
- output [1:0] DOPADOP,
- output [1:0] DOPBDOP
+ (* abc_arrival=2454 *) output [15:0] DOADO,
+ (* abc_arrival=2454 *) output [15:0] DOBDO,
+ (* abc_arrival=2454 *) output [1:0] DOPADOP,
+ (* abc_arrival=2454 *) output [1:0] DOPBDOP
);
parameter INITP_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INITP_01 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
@@ -143,10 +145,10 @@ module RAMB36E1 (
input [3:0] WEA,
input [7:0] WEBWE,
- output [31:0] DOADO,
- output [31:0] DOBDO,
- output [3:0] DOPADOP,
- output [3:0] DOPBDOP
+ (* abc_arrival=2454 *) output [31:0] DOADO,
+ (* abc_arrival=2454 *) output [31:0] DOBDO,
+ (* abc_arrival=2454 *) output [3:0] DOPADOP,
+ (* abc_arrival=2454 *) output [3:0] DOPBDOP
);
parameter INITP_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INITP_01 = 256'h0000000000000000000000000000000000000000000000000000000000000000;