diff options
-rw-r--r-- | README.md | 8 | ||||
-rw-r--r-- | backends/aiger/xaiger.cc | 378 | ||||
-rw-r--r-- | frontends/aiger/aigerparse.cc | 74 | ||||
-rw-r--r-- | passes/techmap/abc9.cc | 234 | ||||
-rw-r--r-- | techlibs/xilinx/Makefile.inc | 3 | ||||
-rw-r--r-- | techlibs/xilinx/abc_map.v | 225 | ||||
-rw-r--r-- | techlibs/xilinx/abc_model.v | 179 | ||||
-rw-r--r-- | techlibs/xilinx/abc_unmap.v | 239 | ||||
-rw-r--r-- | techlibs/xilinx/abc_xc7.box | 68 | ||||
-rw-r--r-- | techlibs/xilinx/cells_map.v | 2 | ||||
-rw-r--r-- | techlibs/xilinx/cells_sim.v | 31 | ||||
-rw-r--r-- | techlibs/xilinx/synth_xilinx.cc | 14 | ||||
-rw-r--r-- | techlibs/xilinx/xc7_brams_bb.v | 18 |
13 files changed, 1276 insertions, 197 deletions
@@ -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; |