Module *module;
SigMap sigmap;
- pool<SigBit> input_bits, output_bits;
+ pool<SigBit> input_bits, output_bits, external_bits;
dict<SigBit, SigBit> not_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> ci_bits, co_bits;
+ dict<SigBit, std::pair<int,int>> ff_bits;
dict<SigBit, float> arrival_times;
vector<pair<int, int>> aig_gates;
else
alias_map[b] = I;
}
- co_bits.emplace_back(b, cell, port_name, offset++, 0);
+ co_bits.emplace_back(b);
- unused_bits.erase(b);
+ unused_bits.erase(I);
}
}
if (w->port_output) {
}
}
}
- int offset = 0;
+
+ // Connect <cell>.$abc9_currQ (inserted by abc9_map.v) as an input to the flop box
+ if (box_module->get_bool_attribute("\\abc9_flop")) {
+ SigSpec rhs = module->wire(stringf("%s.$abc9_currQ", cell->name.c_str()));
+ if (rhs.empty())
+ log_error("'%s.$abc9_currQ' is not a wire present in module '%s'.\n", log_id(cell), log_id(module));
+
- co_bits.emplace_back(b, cell, "\\$abc9_currQ", offset++, 0);
+ for (auto b : rhs) {
+ SigBit I = sigmap(b);
+ if (b == RTLIL::Sx)
+ b = State::S0;
+ else if (I != b) {
+ if (I == RTLIL::Sx)
+ alias_map[b] = State::S0;
+ else
+ alias_map[b] = I;
+ }
++ co_bits.emplace_back(b);
+ unused_bits.erase(I);
+ }
+ }
+
box_list.emplace_back(cell);
}
aig_map[bit] = 2*aig_m;
}
- for (auto &c : ci_bits) {
- RTLIL::SigBit bit = std::get<0>(c);
+ dict<SigBit, int> ff_aig_map;
- for (auto &c : co_bits) {
- RTLIL::SigBit bit = std::get<0>(c);
- std::get<4>(c) = ordered_outputs[bit] = aig_o++;
++ for (auto &bit : ci_bits) {
+ aig_m++, aig_i++;
+ auto r = aig_map.insert(std::make_pair(bit, 2*aig_m));
+ if (!r.second)
+ ff_aig_map[bit] = 2*aig_m;
+ }
+
+ for (auto bit : co_bits) {
+ ordered_outputs[bit] = aig_o++;
aig_outputs.push_back(bit2aig(bit));
}
//holes_module->fixup_ports();
holes_module->check();
- // TODO: Should techmap/aigmap/check all lib_whitebox-es just once,
- // instead of per write_xaiger call
- holes_module->design->selection_stack.emplace_back(false);
- RTLIL::Selection& sel = holes_module->design->selection_stack.back();
- sel.select(holes_module);
-
- Pass::call(holes_module->design, "flatten -wb");
-
+ // Cannot techmap/aigmap/check all lib_whitebox-es outside of write_xaiger
+ // since boxes may contain parameters in which case `flatten` would have
+ // created a new $paramod ...
- Pass::call(holes_module->design, "techmap");
- Pass::call(holes_module->design, "aigmap");
- for (auto cell : holes_module->cells())
- if (!cell->type.in("$_NOT_", "$_AND_"))
+ Pass::call_on_module(holes_module->design, holes_module, "flatten -wb; techmap; aigmap");
+
+ dict<SigSig, SigSig> replace;
+ for (auto it = holes_module->cells_.begin(); it != holes_module->cells_.end(); ) {
+ auto cell = it->second;
+ if (cell->type.in("$_DFF_N_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_",
+ "$_DFF_P_", "$_DFF_PN0_", "$_DFF_PN1", "$_DFF_PP0_", "$_DFF_PP1_")) {
+ SigBit D = cell->getPort("\\D");
+ SigBit Q = cell->getPort("\\Q");
+ // Remove the DFF cell from what needs to be a combinatorial box
+ it = holes_module->cells_.erase(it);
+ Wire *port;
+ if (GetSize(Q.wire) == 1)
+ port = holes_module->wire(stringf("$abc%s", Q.wire->name.c_str()));
+ else
+ port = holes_module->wire(stringf("$abc%s[%d]", Q.wire->name.c_str(), Q.offset));
+ log_assert(port);
+ // Prepare to replace "assign <port> = DFF.Q;" with "assign <port> = DFF.D;"
+ // in order to extract the combinatorial control logic that feeds the box
+ // (i.e. clock enable, synchronous reset, etc.)
+ replace.insert(std::make_pair(SigSig(port,Q), SigSig(port,D)));
+ // Since `flatten` above would have created wires named "<cell>.Q",
+ // extract the pre-techmap cell name
+ auto pos = Q.wire->name.str().rfind(".");
+ log_assert(pos != std::string::npos);
+ IdString driver = Q.wire->name.substr(0, pos);
+ // And drive the signal that was previously driven by "DFF.Q" (typically
+ // used to implement clock-enable functionality) with the "<cell>.$abc9_currQ"
+ // wire (which itself is driven an input port) we inserted above
+ Wire *currQ = holes_module->wire(stringf("%s.$abc9_currQ", driver.c_str()));
+ log_assert(currQ);
+ holes_module->connect(Q, currQ);
+ continue;
+ }
+ else if (!cell->type.in("$_NOT_", "$_AND_"))
log_error("Whitebox contents cannot be represented as AIG. Please verify whiteboxes are synthesisable.\n");
+ ++it;
+ }
- holes_module->design->selection_stack.pop_back();
+ for (auto &conn : holes_module->connections_) {
+ auto it = replace.find(conn);
+ if (it != replace.end())
+ conn = it->second;
+ }
// Move into a new (temporary) design so that "clean" will only
// operate (and run checks on) this one module