aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--backends/aiger/xaiger.cc259
-rw-r--r--frontends/aiger/aigerparse.cc88
-rw-r--r--passes/techmap/abc9.cc49
-rw-r--r--techlibs/xilinx/Makefile.inc1
-rw-r--r--techlibs/xilinx/abc_ff.v33
-rw-r--r--techlibs/xilinx/abc_xc7.box20
-rw-r--r--techlibs/xilinx/ff_map.v20
-rw-r--r--techlibs/xilinx/synth_xilinx.cc6
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");