diff options
-rw-r--r-- | backends/aiger/xaiger.cc | 259 | ||||
-rw-r--r-- | frontends/aiger/aigerparse.cc | 88 | ||||
-rw-r--r-- | passes/techmap/abc9.cc | 49 | ||||
-rw-r--r-- | techlibs/xilinx/Makefile.inc | 1 | ||||
-rw-r--r-- | techlibs/xilinx/abc_ff.v | 33 | ||||
-rw-r--r-- | techlibs/xilinx/abc_xc7.box | 20 | ||||
-rw-r--r-- | techlibs/xilinx/ff_map.v | 20 | ||||
-rw-r--r-- | techlibs/xilinx/synth_xilinx.cc | 6 |
8 files changed, 414 insertions, 62 deletions
diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc index 69f63486c..a1085addf 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,12 +256,60 @@ 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); + toposort.node(cell->name); + + auto r = flop_data.insert(std::make_pair(cell->type, std::make_pair(IdString(), IdString()))); + if (r.second) { + auto it = inst_module->attributes.find("\\abc_flop"); + if (it != inst_module->attributes.end()) { + std::string abc_flop = it->second.decode_string(); + size_t start, end; + end = abc_flop.find(','); // Ignore original module + log_assert(end != std::string::npos); + start = end + 1; + end = abc_flop.find(',', start + 1); + log_assert(start != std::string::npos && end != std::string::npos); + auto abc_flop_d = RTLIL::escape_id(abc_flop.substr(start, end-start)); + start = end + 1; + end = abc_flop.find(',', start + 1); + log_assert(start != std::string::npos && end != std::string::npos); + auto abc_flop_q = RTLIL::escape_id(abc_flop.substr(start, end-start)); + 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); + + } + else { for (const auto &conn : cell->connections()) { if (cell->input(conn.first)) { // Ignore inout for the sake of topographical ordering @@ -492,6 +556,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 { @@ -507,6 +572,7 @@ struct XAigerWriter } not_map.sort(); + ff_map.sort(); and_map.sort(); aig_map[State::S0] = 0; @@ -518,12 +584,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++; @@ -535,11 +666,16 @@ 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); omode = true; - } + } } void write_aiger(std::ostream &f, bool ascii_mode) @@ -549,6 +685,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); @@ -559,6 +697,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)); @@ -576,6 +723,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)); @@ -601,7 +757,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)); @@ -610,14 +766,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 = %zu\n", input_bits.size() + ci_bits.size()); - write_h_buffer(input_bits.size() + ci_bits.size()); - log_debug("coNum = %zu\n", output_bits.size() + co_bits.size()); - write_h_buffer(output_bits.size() + co_bits.size()); - log_debug("piNum = %zu\n", input_bits.size()); - write_h_buffer(input_bits.size()); - log_debug("poNum = %zu\n", output_bits.size()); - write_h_buffer(output_bits.size()); + log_debug("ciNum = %zu\n", input_bits.size() + ff_bits.size() + ci_bits.size()); + write_h_buffer(input_bits.size() + ff_bits.size() + ci_bits.size()); + log_debug("coNum = %zu\n", output_bits.size() + ff_bits.size() + co_bits.size()); + write_h_buffer(output_bits.size() + ff_bits.size() + co_bits.size()); + log_debug("piNum = %zu\n", input_bits.size() + ff_bits.size()); + write_h_buffer(input_bits.size()+ ff_bits.size()); + log_debug("poNum = %zu\n", output_bits.size() + ff_bits.size()); + write_h_buffer(output_bits.size() + ff_bits.size()); log_debug("boxNum = %zu\n", box_list.size()); write_h_buffer(box_list.size()); @@ -693,7 +849,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(); @@ -701,6 +861,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(); @@ -729,7 +909,7 @@ struct XAigerWriter Pass::call(holes_module->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*/); holes_module->design->selection_stack.pop_back(); @@ -751,7 +931,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()) @@ -772,10 +954,30 @@ struct XAigerWriter if (output_bits.count(b)) { int o = ordered_outputs.at(b); - output_lines[o] += stringf("output %lu %d %s\n", o - co_bits.size(), 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 %lu %d %s %d\n", o - co_bits.size(), 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; @@ -791,6 +993,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)); @@ -802,6 +1008,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; @@ -822,6 +1032,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"); @@ -832,6 +1046,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; @@ -844,6 +1059,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; @@ -862,7 +1081,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 1ac0f7ba4..30e35da01 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -440,6 +440,7 @@ void AigerReader::parse_xaiger() 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)); } @@ -461,7 +462,7 @@ void AigerReader::parse_xaiger() 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); @@ -506,8 +507,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()); @@ -523,7 +523,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() == ' ') { @@ -631,8 +634,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()); @@ -648,7 +650,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() == ' ') { @@ -737,13 +742,29 @@ void AigerReader::parse_aiger_binary() void AigerReader::post_process() { pool<IdString> seen_boxes; - unsigned ci_count = 0, co_count = 0; + dict<IdString, std::pair<RTLIL::Module*,IdString>> 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; + RTLIL::IdString flop_past_q; 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); + std::string abc_flop = it->second.decode_string(); + auto pos = abc_flop.find(','); + log_assert(pos != std::string::npos); + flop_module = design->module(RTLIL::escape_id(abc_flop.substr(0, pos))); + log_assert(flop_module); + pos = abc_flop.rfind(','); + log_assert(pos != std::string::npos); + flop_past_q = RTLIL::escape_id(abc_flop.substr(pos+1)); + flop_data[cell->type] = std::make_pair(flop_module, flop_past_q); + } + 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(); @@ -782,23 +803,28 @@ void AigerReader::post_process() carry_out->port_id = ports.size(); } } + else { + auto it = flop_data.find(cell->type); + if (it != flop_data.end()) + std::tie(flop_module,flop_past_q) = 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); @@ -807,7 +833,25 @@ void AigerReader::post_process() } rhs.append(wire); } - cell->setPort(port_name, rhs); + + if (!flop_module || port_name != flop_past_q) + 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); } } @@ -824,6 +868,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 @@ -850,6 +895,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()); @@ -881,6 +927,7 @@ void AigerReader::post_process() else { wire->port_output = false; module->connect(wire, existing); + wire = existing; } } else if (index > 0) { @@ -906,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)); @@ -1016,8 +1068,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 f107f9947..30df8e3ef 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -285,7 +285,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) @@ -323,7 +323,7 @@ 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()) + 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"; @@ -397,7 +397,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"); @@ -434,6 +434,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.xaig", 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; @@ -542,6 +545,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_) { @@ -557,7 +566,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri vector<RTLIL::Cell*> boxes; for (const auto &it : module->cells_) { auto cell = it.second; - if (cell->type.in("$_AND_", "$_NOT_")) { + if (cell->type.in("$_AND_", "$_NOT_", "$__ABC_FF_")) { module->remove(cell); continue; } @@ -699,25 +708,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++; @@ -867,7 +874,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; @@ -958,13 +965,13 @@ struct Abc9Pass : public Pass { fast_mode = true; continue; } - //if (arg == "-dff") { - // dff_mode = true; - // continue; - //} + 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") { @@ -1010,8 +1017,8 @@ 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 (!retime_mode || !clk_str.empty()) { + abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, retime_mode, clk_str, keepff, delay_target, lutin_shared, fast_mode, show_tempdir, box_file, lut_file, wire_delay); continue; diff --git a/techlibs/xilinx/Makefile.inc b/techlibs/xilinx/Makefile.inc index 17c5df37d..c9a3a49fb 100644 --- a/techlibs/xilinx/Makefile.inc +++ b/techlibs/xilinx/Makefile.inc @@ -32,6 +32,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..a91720260 --- /dev/null +++ b/techlibs/xilinx/abc_ff.v @@ -0,0 +1,33 @@ +/* + * 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_FF_ (input C, D, output Q); +endmodule + +(* abc_box_id = 7, lib_whitebox, abc_flop = "FDRE,D,Q,\\$pastQ" *) +module \$__ABC_FDRE (output Q, input C, CE, D, 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; + assign Q = (R ^ IS_R_INVERTED) ? 1'b0 : (CE ? (D ^ IS_D_INVERTED) : \$pastQ ); +endmodule diff --git a/techlibs/xilinx/abc_xc7.box b/techlibs/xilinx/abc_xc7.box index 3789ff350..69ff9aeab 100644 --- a/techlibs/xilinx/abc_xc7.box +++ b/techlibs/xilinx/abc_xc7.box @@ -56,3 +56,23 @@ RAM64X1D 6 0 15 2 RAM128X1D 7 0 17 2 - - - - - - - - 1009 998 839 774 605 494 450 - - 1047 1036 877 812 643 532 478 - - - - - - - - - - + +# Inputs: C CE D R \$pastQ +# Outputs: Q +FDRE 7 1 5 1 +- 109 -46 358 0 + +# Inputs: C CE D S \$pastQ +# Outputs: Q +FDSE 8 0 5 1 +- 109 -46 358 0 + +# Inputs: C CE CLR D \$pastQ +# Outputs: Q +FDCE 9 0 5 1 +- 109 - -46 0 + +# Inputs: C CE D PRE \$pastQ +# Outputs: Q +FDPE 10 0 5 1 +- 109 -46 - 0 diff --git a/techlibs/xilinx/ff_map.v b/techlibs/xilinx/ff_map.v index 13beaa6ae..5ad73aa63 100644 --- a/techlibs/xilinx/ff_map.v +++ b/techlibs/xilinx/ff_map.v @@ -23,10 +23,26 @@ `ifndef _NO_FFS module \$_DFF_N_ (input D, C, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule -module \$_DFF_P_ (input D, C, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule +module \$_DFF_P_ (input D, C, output Q); +`ifndef _ABC + FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); +`else + wire \$nextQ ; + \$__ABC_FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(\$nextQ ), .\$pastQ (Q), .C(C), .CE(1'b1), .R(1'b0)); + \$__ABC_FF_ abc_dff (.D(\$nextQ ), .Q(Q)); +`endif +endmodule module \$_DFFE_NP_ (input D, C, E, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule -module \$_DFFE_PP_ (input D, C, E, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule +module \$_DFFE_PP_ (input D, C, E, output Q); +`ifndef _ABC + FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); +`else + wire \$nextQ ; + \$__ABC_FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(\$nextQ ), .\$pastQ (Q), .C(C), .CE(E), .R(1'b0)); + \$__ABC_FF_ abc_dff (.D(\$nextQ ), .Q(Q)); +`endif +endmodule module \$_DFF_NN0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); endmodule module \$_DFF_NP0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 77daa745c..2455c2885 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -372,6 +372,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 @@ -389,7 +390,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"); |