diff options
-rw-r--r-- | backends/aiger/xaiger.cc | 277 | ||||
-rw-r--r-- | frontends/aiger/aigerparse.cc | 98 | ||||
-rw-r--r-- | passes/techmap/abc9.cc | 156 | ||||
-rw-r--r-- | techlibs/xilinx/Makefile.inc | 1 | ||||
-rw-r--r-- | techlibs/xilinx/abc_ff.v | 208 | ||||
-rw-r--r-- | techlibs/xilinx/abc_xc7.box | 40 | ||||
-rw-r--r-- | techlibs/xilinx/synth_xilinx.cc | 8 |
7 files changed, 696 insertions, 92 deletions
diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc index 41a79d9dd..5d3677ab3 100644 --- a/backends/aiger/xaiger.cc +++ b/backends/aiger/xaiger.cc @@ -76,24 +76,31 @@ 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; 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 +143,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 +166,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 +217,7 @@ 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; + dict<IdString, std::pair<IdString,IdString>> flop_data; bool abc_box_seen = false; for (auto cell : module->selected_cells()) { @@ -240,24 +256,74 @@ 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, std::make_pair(IdString(), IdString()))); + if (r.second && inst_module->attributes.count("\\abc_flop")) { + IdString abc_flop_d, abc_flop_q; + 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; + } + } + 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)); + r.first->second = std::make_pair(abc_flop_d, abc_flop_q); + } + + auto abc_flop_d = r.first->second.first; + 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.second; + 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); + } - if (cell->output(conn.first)) - for (auto bit : sigmap(conn.second)) - bit_drivers[bit].insert(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); } + + if (cell->output(conn.first)) + for (auto bit : sigmap(conn.second)) + bit_drivers[bit].insert(cell->name); } } else { @@ -450,6 +516,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 +532,7 @@ struct XAigerWriter } not_map.sort(); + ff_map.sort(); and_map.sort(); aig_map[State::S0] = 0; @@ -476,12 +544,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 +626,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 +645,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 +657,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 +683,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,7 +717,7 @@ struct XAigerWriter f << "c"; - if (!box_list.empty()) { + if (!box_list.empty() || !ff_bits.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)); @@ -568,14 +726,14 @@ struct XAigerWriter 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("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()); @@ -650,7 +808,11 @@ struct XAigerWriter 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 = %zu\n", ff_bits.size()); + write_r_buffer(ff_bits.size()); + int mergeability_class = 1; + for (auto cell : ff_bits) + write_r_buffer(mergeability_class++); f << "r"; buffer_str = r_buffer.str(); @@ -658,6 +820,26 @@ struct XAigerWriter 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()); + if (holes_module) { log_push(); @@ -693,7 +875,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; @@ -714,7 +896,9 @@ struct XAigerWriter 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 +919,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 +958,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 +973,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 +997,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 +1011,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 +1024,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 +1046,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 bd0596cc0..f2b38da67 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 = 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)); } @@ -451,7 +452,7 @@ void AigerReader::parse_xaiger(const dict<int,IdString> &box_lookup) uint32_t poNum = parse_xaiger_literal(f); log_debug("poNum = %u\n", poNum); uint32_t boxNum = parse_xaiger_literal(f); - log_debug("boxNum = %u\n", poNum); + log_debug("boxNum = %u\n", boxNum); for (unsigned i = 0; i < boxNum; i++) { f.ignore(2*sizeof(uint32_t)); uint32_t boxUniqueId = parse_xaiger_literal(f); @@ -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() == ' ') { @@ -726,14 +731,28 @@ void AigerReader::parse_aiger_binary() void AigerReader::post_process() { + const RTLIL::Wire* n0 = module->wire("\\__0__"); + const RTLIL::Wire* n1 = module->wire("\\__1__"); + pool<IdString> seen_boxes; - unsigned ci_count = 0, co_count = 0; + dict<IdString, RTLIL::Module*> flop_data; + 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); + RTLIL::Module* flop_module = nullptr; if (seen_boxes.insert(cell->type).second) { - auto it = box_module->attributes.find("\\abc_carry"); + auto it = box_module->attributes.find("\\abc_flop"); + if (it != box_module->attributes.end()) { + log_assert(flop_count < flopNum); + auto abc_flop = it->second.decode_string(); + flop_module = design->module(RTLIL::escape_id(abc_flop)); + if (!flop_module) + log_error("'abc_flop' attribute value '%s' on module '%s' is not a valid module.\n", abc_flop.c_str(), log_id(cell->type)); + flop_data[cell->type] = flop_module; + } + it = box_module->attributes.find("\\abc_carry"); if (it != box_module->attributes.end()) { RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr; auto carry_in_out = it->second.decode_string(); @@ -772,23 +791,28 @@ void AigerReader::post_process() carry_out->port_id = ports.size(); } } + else { + auto it = flop_data.find(cell->type); + if (it != flop_data.end()) + flop_module = it->second; + } // 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 +821,36 @@ void AigerReader::post_process() } rhs.append(wire); } - cell->setPort(port_name, rhs); + + if (!flop_module || port_name != "\\$pastQ") + cell->setPort(port_name, rhs); + } + + if (flop_module) { + 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++; + cell->type = flop_module->name; + module->connect(q, d); + continue; + } + + // Remove the async mux by shorting out its input and output + if (cell->type == "$__ABC_ASYNC") { + RTLIL::Wire* A = cell->getPort("\\A").as_wire(); + if (A == n0 || A == n1) A = nullptr; + auto it = cell->connections_.find("\\Y"); + log_assert(it != cell->connections_.end()); + module->connect(it->second, A); + cell->connections_.erase(it); } } @@ -814,6 +867,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 +894,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 +905,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 +927,7 @@ void AigerReader::post_process() else { wire->port_output = false; module->connect(wire, existing); + wire = existing; } } else if (index > 0) { @@ -896,6 +953,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)); @@ -1007,8 +1069,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 4cdd392b5..50a6e0fe5 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; @@ -440,8 +443,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri design->remove(design->module(ID($__abc9__))); #endif - design->selection_stack.pop_back(); - // Now 'unexpose' those wires by undoing // the expose operation -- remove them from PO/PI // and re-connecting them back together @@ -528,6 +529,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 +548,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; } @@ -579,8 +585,8 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri 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,10 +598,10 @@ 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())), @@ -606,11 +612,9 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri cell_stats[ID($lut)]++; } else - not2drivers[c] = driver_lut; + not2drivers[c] = driving_lut; continue; } - else - log_abort(); if (cell && markgroups) cell->attributes[ID(abcgroup)] = map_autoidx; continue; } @@ -639,6 +643,13 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri if (existing_cell) { cell->parameters = existing_cell->parameters; cell->attributes = existing_cell->attributes; + + auto it = cell->parameters.find("\\$abc_flop_clk_pol"); + if (it != cell->parameters.end()) + cell->parameters.erase(it); + it = cell->parameters.find("\\$abc_flop_en_pol"); + if (it != cell->parameters.end()) + cell->parameters.erase(it); } else { cell->parameters = c->parameters; @@ -694,25 +705,23 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri 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++; @@ -935,7 +944,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 +1035,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 +1075,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 +1156,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 +1185,10 @@ 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; + dict<IdString, std::pair<RTLIL::IdString,RTLIL::IdString>> flop_data; + + for (auto cell : all_cells) { clkdomain_t key; for (auto &conn : cell->connections()) @@ -1188,19 +1208,54 @@ 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, std::make_pair(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; + + auto jt = cell->parameters.find("\\$abc_flop_clk_pol"); + if (jt == cell->parameters.end()) + log_error("'$abc_flop_clk_pol' parameter not found on module '%s'.\n", log_id(cell->type)); + bool this_clk_pol = jt->second.as_bool(); + jt = cell->parameters.find("\\$abc_flop_en_pol"); + if (jt == cell->parameters.end()) + log_error("'$abc_flop_en_pol' parameter not found on module '%s'.\n", log_id(cell->type)); + bool this_en_pol = jt->second.as_bool(); + + const auto &data = it->second; + key = clkdomain_t(this_clk_pol, assign_map(cell->getPort(data.first)), this_en_pol, assign_map(cell->getPort(data.second))); unassigned_cells.erase(cell); expand_queue.insert(cell); @@ -1286,16 +1341,27 @@ 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); + RTLIL::Selection& sel = design->selection_stack.back(); + for (auto &it : assigned_cells) { clk_polarity = std::get<0>(it.first); clk_sig = assign_map(std::get<1>(it.first)); en_polarity = std::get<2>(it.first); en_sig = assign_map(std::get<3>(it.first)); + + pool<RTLIL::IdString> assigned_names; + for (auto i : it.second) + assigned_names.insert(i->name); + 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 2c6e7432e..a9e0c5c7b 100644 --- a/techlibs/xilinx/Makefile.inc +++ b/techlibs/xilinx/Makefile.inc @@ -39,6 +39,7 @@ $(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_ff.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_ff.v b/techlibs/xilinx/abc_ff.v new file mode 100644 index 000000000..19f86365a --- /dev/null +++ b/techlibs/xilinx/abc_ff.v @@ -0,0 +1,208 @@ +/* + * 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 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), + .\$abc_flop_clk_pol (!IS_C_INVERTED), + .\$abc_flop_en_pol (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), + .\$abc_flop_clk_pol (1'b1), + .\$abc_flop_en_pol (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), + .\$abc_flop_clk_pol (!IS_C_INVERTED), + .\$abc_flop_en_pol (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), + .\$abc_flop_clk_pol (1'b1), + .\$abc_flop_en_pol (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), + .\$abc_flop_clk_pol (!IS_C_INVERTED), + .\$abc_flop_en_pol (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), + .\$abc_flop_clk_pol (1'b1), + .\$abc_flop_en_pol (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 + +`ifndef _ABC +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 = "FDRE" *) +module \$__ABC_FDRE ((* abc_flop_q *) 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 \$abc_flop_clk_pol = ~IS_C_INVERTED; + parameter \$abc_flop_en_pol = 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 = "FDRE_1" *) +module \$__ABC_FDRE_1 ((* abc_flop_q *) 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 \$abc_flop_clk_pol = 1'b0; + parameter \$abc_flop_en_pol = 1'b1; + assign Q = R ? 1'b0 : (CE ? D : \$pastQ ); +endmodule + +(* abc_box_id = 1003, lib_whitebox, abc_flop = "FDCE" *) +module \$__ABC_FDCE ((* abc_flop_q *) 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 \$abc_flop_clk_pol = ~IS_C_INVERTED; + parameter \$abc_flop_en_pol = 1'b1; + assign Q = (CE && !(CLR ^ IS_CLR_INVERTED)) ? (D ^ IS_D_INVERTED) : \$pastQ ; +endmodule + +(* abc_box_id = 1004, lib_whitebox, abc_flop = "FDCE_1" *) +module \$__ABC_FDCE_1 ((* abc_flop_q *) 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 \$abc_flop_clk_pol = 1'b0; + parameter \$abc_flop_en_inv = 1'b1; + assign Q = (CE && !CLR) ? D : \$pastQ ; +endmodule + +(* abc_box_id = 1005, lib_whitebox, abc_flop = "FDPE" *) +module \$__ABC_FDPE ((* abc_flop_q *) 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 \$abc_flop_clk_pol = ~IS_C_INVERTED; + parameter \$abc_flop_en_pol = 1'b1; + assign Q = (CE && !(PRE ^ IS_PRE_INVERTED)) ? (D ^ IS_D_INVERTED) : \$pastQ ; +endmodule + +(* abc_box_id = 1006, lib_whitebox, abc_flop = "FDPE_1" *) +module \$__ABC_FDPE_1 ((* abc_flop_q *) 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 \$abc_flop_clk_pol = 1'b0; + parameter \$abc_flop_en_pol = 1'b1; + assign Q = (CE && !PRE) ? D : \$pastQ ; +endmodule + +`endif diff --git a/techlibs/xilinx/abc_xc7.box b/techlibs/xilinx/abc_xc7.box index 3789ff350..044ed1bff 100644 --- a/techlibs/xilinx/abc_xc7.box +++ b/techlibs/xilinx/abc_xc7.box @@ -14,6 +14,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 @@ -56,3 +57,42 @@ RAM64X1D 6 0 15 2 RAM128X1D 7 0 17 2 - - - - - - - - 1009 998 839 774 605 494 450 - - 1047 1036 877 812 643 532 478 - - - - - - - - - - + +# 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 + +# Inputs: C CE D R \$pastQ +# Outputs: Q +FDRE 1001 1 5 1 +0 155 0 404 0 + +# Inputs: C CE D R \$pastQ +# Outputs: Q +FDRE_1 1002 1 5 1 +0 155 0 404 0 + +# Inputs: C CE CLR D \$pastQ +# Outputs: Q +FDCE 1003 1 5 1 +0 155 810 0 0 + +# Inputs: C CE CLR D \$pastQ +# Outputs: Q +FDCE_1 1004 1 5 1 +0 155 810 0 0 + +# Inputs: C CE D PRE \$pastQ +# Outputs: Q +FDPE 1005 1 5 1 +0 155 0 810 0 + +# Inputs: C CE D PRE \$pastQ +# Outputs: Q +FDPE_1 1006 1 5 1 +0 155 0 810 0 diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index d143c6823..6456dbdf4 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -376,6 +376,8 @@ struct SynthXilinxPass : public ScriptPass std::string techmap_args = "-map +/techmap.v -D _ABC -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 -D _ABC -map +/xilinx/abc_ff.v"; run("techmap " + techmap_args); run("clean"); } @@ -387,6 +389,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_ff.v"); if (nowidelut) run("abc9 -lut +/xilinx/abc_xc7_nowide.lut -box +/xilinx/abc_xc7.box -W " + std::to_string(XC7_WIRE_DELAY)); else @@ -404,7 +407,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/cells_map.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"); |