aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEddie Hung <eddie@fpgeh.com>2020-01-14 12:57:56 -0800
committerEddie Hung <eddie@fpgeh.com>2020-01-14 12:57:56 -0800
commit915e7dde734094e21803f83e37f8827b8ff2fe32 (patch)
treef6d0a2fb338c92f865e6c6c1f2e43716d90716c8
parentf9aae90e7a9d238f5063d980e2b1e85a94cff4c7 (diff)
parent654247abe9078566f93960a135ce08b0cfc96442 (diff)
downloadyosys-915e7dde734094e21803f83e37f8827b8ff2fe32.tar.gz
yosys-915e7dde734094e21803f83e37f8827b8ff2fe32.tar.bz2
yosys-915e7dde734094e21803f83e37f8827b8ff2fe32.zip
Merge remote-tracking branch 'origin/eddie/abc9_refactor' into eddie/abc9_required
-rw-r--r--backends/aiger/xaiger.cc177
-rw-r--r--backends/edif/edif.cc62
-rw-r--r--frontends/aiger/aigerparse.cc31
-rw-r--r--frontends/aiger/aigerparse.h3
-rw-r--r--kernel/rtlil.cc1
-rw-r--r--kernel/rtlil.h2
-rw-r--r--passes/cmds/autoname.cc2
-rw-r--r--passes/cmds/scratchpad.cc25
-rw-r--r--passes/techmap/abc9.cc98
-rw-r--r--passes/techmap/abc9_exe.cc113
-rw-r--r--passes/techmap/abc9_ops.cc288
-rw-r--r--techlibs/ice40/synth_ice40.cc20
-rw-r--r--techlibs/xilinx/abc9_map.v16
-rw-r--r--techlibs/xilinx/synth_xilinx.cc17
-rw-r--r--tests/arch/ecp5/bug1630.il.gzbin0 -> 8527 bytes
-rw-r--r--tests/arch/ecp5/bug1630.ys2
-rw-r--r--tests/arch/ice40/bug1626.ys217
-rw-r--r--tests/arch/xilinx/add_sub.ys8
-rw-r--r--tests/arch/xilinx/counter.ys7
-rw-r--r--tests/arch/xilinx/fsm.ys2
-rw-r--r--tests/techmap/abc9.ys68
-rw-r--r--tests/various/autoname.ys19
22 files changed, 789 insertions, 389 deletions
diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc
index d934a9aa9..d3415e45d 100644
--- a/backends/aiger/xaiger.cc
+++ b/backends/aiger/xaiger.cc
@@ -156,7 +156,6 @@ struct XAigerWriter
if (wire->get_bool_attribute(ID::keep))
sigmap.add(wire);
-
for (auto wire : module->wires())
for (int i = 0; i < GetSize(wire); i++)
{
@@ -174,93 +173,101 @@ struct XAigerWriter
undriven_bits.insert(bit);
unused_bits.insert(bit);
- if (wire->port_input)
+ bool keep = wire->get_bool_attribute(ID::keep);
+ if (wire->port_input || keep)
input_bits.insert(bit);
- if (wire->port_output) {
+ if (wire->port_output || keep) {
if (bit != wirebit)
alias_map[wirebit] = bit;
output_bits.insert(wirebit);
}
}
- std::vector<int> arrivals;
+ dict<IdString,dict<IdString,std::vector<int>>> arrivals_cache;
for (auto cell : module->cells()) {
- if (cell->type == "$_NOT_")
- {
- SigBit A = sigmap(cell->getPort("\\A").as_bit());
- SigBit Y = sigmap(cell->getPort("\\Y").as_bit());
- unused_bits.erase(A);
- undriven_bits.erase(Y);
- not_map[Y] = A;
- continue;
- }
-
- if (cell->type == "$_AND_")
- {
- SigBit A = sigmap(cell->getPort("\\A").as_bit());
- SigBit B = sigmap(cell->getPort("\\B").as_bit());
- SigBit Y = sigmap(cell->getPort("\\Y").as_bit());
- unused_bits.erase(A);
- unused_bits.erase(B);
- undriven_bits.erase(Y);
- and_map[Y] = make_pair(A, B);
- continue;
- }
+ RTLIL::Module* inst_module = module->design->module(cell->type);
+ if (!cell->has_keep_attr()) {
+ if (cell->type == "$_NOT_")
+ {
+ SigBit A = sigmap(cell->getPort("\\A").as_bit());
+ SigBit Y = sigmap(cell->getPort("\\Y").as_bit());
+ unused_bits.erase(A);
+ undriven_bits.erase(Y);
+ not_map[Y] = A;
+ continue;
+ }
- if (cell->type == "$__ABC9_FF_" &&
- // The presence of an abc9_mergeability attribute indicates
- // that we do want to pass this flop to ABC
- cell->attributes.count("\\abc9_mergeability"))
- {
- 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;
- auto r YS_ATTRIBUTE(unused) = ff_bits.insert(std::make_pair(D, cell));
- log_assert(r.second);
- continue;
- }
+ if (cell->type == "$_AND_")
+ {
+ SigBit A = sigmap(cell->getPort("\\A").as_bit());
+ SigBit B = sigmap(cell->getPort("\\B").as_bit());
+ SigBit Y = sigmap(cell->getPort("\\Y").as_bit());
+ unused_bits.erase(A);
+ unused_bits.erase(B);
+ undriven_bits.erase(Y);
+ and_map[Y] = make_pair(A, B);
+ continue;
+ }
- RTLIL::Module* inst_module = module->design->module(cell->type);
- if (inst_module && inst_module->get_blackbox_attribute()) {
- auto it = cell->attributes.find("\\abc9_box_seq");
- if (it != cell->attributes.end()) {
- int abc9_box_seq = it->second.as_int();
- if (GetSize(box_list) <= abc9_box_seq)
- box_list.resize(abc9_box_seq+1);
- box_list[abc9_box_seq] = cell;
- // Only flop boxes may have arrival times
- // (all others are combinatorial)
- if (!inst_module->get_bool_attribute("\\abc9_flop"))
- continue;
+ if (cell->type == "$__ABC9_FF_" &&
+ // The presence of an abc9_mergeability attribute indicates
+ // that we do want to pass this flop to ABC
+ cell->attributes.count("\\abc9_mergeability"))
+ {
+ 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;
+ auto r YS_ATTRIBUTE(unused) = ff_bits.insert(std::make_pair(D, cell));
+ log_assert(r.second);
+ continue;
}
- for (const auto &conn : cell->connections()) {
- auto port_wire = inst_module->wire(conn.first);
- if (port_wire->port_output) {
- arrivals.clear();
- auto it = port_wire->attributes.find("\\abc9_arrival");
- if (it == port_wire->attributes.end())
+ if (inst_module) {
+ auto it = cell->attributes.find("\\abc9_box_seq");
+ if (it != cell->attributes.end()) {
+ int abc9_box_seq = it->second.as_int();
+ if (GetSize(box_list) <= abc9_box_seq)
+ box_list.resize(abc9_box_seq+1);
+ box_list[abc9_box_seq] = cell;
+ // Only flop boxes may have arrival times
+ // (all others are combinatorial)
+ if (!inst_module->get_bool_attribute("\\abc9_flop"))
continue;
- if (it->second.flags == 0)
- arrivals.emplace_back(it->second.as_int());
- else
- for (const auto &tok : split_tokens(it->second.decode_string()))
- arrivals.push_back(atoi(tok.c_str()));
+ }
+
+ auto &cell_arrivals = arrivals_cache[cell->type];
+ for (const auto &conn : cell->connections()) {
+ auto port_wire = inst_module->wire(conn.first);
+ if (!port_wire->port_output)
+ continue;
+
+ auto r = cell_arrivals.insert(conn.first);
+ auto &arrivals = r.first->second;
+ if (r.second) {
+ auto it = port_wire->attributes.find("\\abc9_arrival");
+ if (it == port_wire->attributes.end())
+ continue;
+ if (it->second.flags == 0)
+ arrivals.emplace_back(it->second.as_int());
+ else
+ for (const auto &tok : split_tokens(it->second.decode_string()))
+ arrivals.push_back(atoi(tok.c_str()));
+ }
+
if (GetSize(arrivals) > 1 && GetSize(arrivals) != GetSize(port_wire))
log_error("%s.%s is %d bits wide but abc9_arrival = %s has %d value(s)!\n", log_id(cell->type), log_id(conn.first),
GetSize(port_wire), log_signal(it->second), GetSize(arrivals));
- auto jt = arrivals.begin();
+ auto jt = arrivals.begin();
#ifndef NDEBUG
if (ys_debug(1)) {
static std::set<std::pair<IdString,IdString>> seen;
if (seen.emplace(cell->type, conn.first).second) log("%s.%s abc9_arrival = %d\n", log_id(cell->type), log_id(conn.first), *jt);
}
#endif
-
for (auto bit : sigmap(conn.second)) {
arrival_times[bit] = *jt;
if (arrivals.size() > 1)
@@ -283,6 +290,9 @@ struct XAigerWriter
for (auto b : c.second) {
Wire *w = b.wire;
if (!w) continue;
+ // Do not add as PO if bit is already a PI
+ if (input_bits.count(b))
+ continue;
if (!w->port_output || !cell_known) {
SigBit I = sigmap(b);
if (I != b)
@@ -337,12 +347,11 @@ struct XAigerWriter
}
}
- // Fully pad all unused input connections of this box cell with S0
- // Fully pad all undriven output connections of this box cell with anonymous wires
for (auto port_name : r.first->second) {
auto w = box_module->wire(port_name);
log_assert(w);
- auto rhs = cell->getPort(port_name);
+ auto rhs = cell->connections_.at(port_name, SigSpec());
+ rhs.append(Const(State::Sx, GetSize(w)-GetSize(rhs)));
if (w->port_input)
for (auto b : rhs) {
SigBit I = sigmap(b);
@@ -364,6 +373,11 @@ struct XAigerWriter
alias_map[O] = b;
ci_bits.emplace_back(b);
undriven_bits.erase(O);
+ // If PI and CI, then must be a (* keep *) wire
+ if (input_bits.erase(O)) {
+ log_assert(output_bits.count(O));
+ log_assert(O.wire->get_bool_attribute(ID::keep));
+ }
}
}
@@ -432,6 +446,10 @@ struct XAigerWriter
for (auto &bit : ci_bits) {
aig_m++, aig_i++;
+ // 1'bx may exist here due to a box output
+ // that has been padded to its full width
+ if (bit == State::Sx)
+ continue;
log_assert(!aig_map.count(bit));
aig_map[bit] = 2*aig_m;
}
@@ -443,7 +461,27 @@ struct XAigerWriter
for (const auto &bit : output_bits) {
ordered_outputs[bit] = aig_o++;
- aig_outputs.push_back(bit2aig(bit));
+ int aig;
+ // Unlike bit2aig() which checks aig_map first, for
+ // inout/keep bits, since aig_map will point to
+ // the PI, first attempt to find the NOT/AND driver
+ // before resorting to an aig_map lookup (which
+ // could be another PO)
+ if (input_bits.count(bit)) {
+ if (not_map.count(bit)) {
+ aig = bit2aig(not_map.at(bit)) ^ 1;
+ } else if (and_map.count(bit)) {
+ auto args = and_map.at(bit);
+ int a0 = bit2aig(args.first);
+ int a1 = bit2aig(args.second);
+ aig = mkgate(a0, a1);
+ }
+ else
+ aig = aig_map.at(bit);
+ }
+ else
+ aig = bit2aig(bit);
+ aig_outputs.push_back(aig);
}
for (auto &i : ff_bits) {
@@ -720,7 +758,8 @@ struct XAigerBackend : public Backend {
log("Write the top module (according to the (* top *) attribute or if only one module\n");
log("is currently selected) to an XAIGER file. Any non $_NOT_, $_AND_, $_ABC9_FF_, or");
log("non (* abc9_box_id *) cells will be converted into psuedo-inputs and\n");
- log("pseudo-outputs.\n");
+ log("pseudo-outputs. Whitebox contents will be taken from the '<module-name>$holes'\n");
+ log("module, if it exists.\n");
log("\n");
log(" -ascii\n");
log(" write ASCII version of AIGER format\n");
diff --git a/backends/edif/edif.cc b/backends/edif/edif.cc
index 6d9469538..6735d670f 100644
--- a/backends/edif/edif.cc
+++ b/backends/edif/edif.cc
@@ -300,6 +300,26 @@ struct EdifBackend : public Backend {
*f << stringf(" (library DESIGN\n");
*f << stringf(" (edifLevel 0)\n");
*f << stringf(" (technology (numberDefinition))\n");
+
+ auto add_prop = [&](IdString name, Const val) {
+ if ((val.flags & RTLIL::CONST_FLAG_STRING) != 0)
+ *f << stringf("\n (property %s (string \"%s\"))", EDIF_DEF(name), val.decode_string().c_str());
+ else if (val.bits.size() <= 32 && RTLIL::SigSpec(val).is_fully_def())
+ *f << stringf("\n (property %s (integer %u))", EDIF_DEF(name), val.as_int());
+ else {
+ std::string hex_string = "";
+ for (size_t i = 0; i < val.bits.size(); i += 4) {
+ int digit_value = 0;
+ if (i+0 < val.bits.size() && val.bits.at(i+0) == RTLIL::State::S1) digit_value |= 1;
+ if (i+1 < val.bits.size() && val.bits.at(i+1) == RTLIL::State::S1) digit_value |= 2;
+ if (i+2 < val.bits.size() && val.bits.at(i+2) == RTLIL::State::S1) digit_value |= 4;
+ if (i+3 < val.bits.size() && val.bits.at(i+3) == RTLIL::State::S1) digit_value |= 8;
+ char digit_str[2] = { "0123456789abcdef"[digit_value], 0 };
+ hex_string = std::string(digit_str) + hex_string;
+ }
+ *f << stringf("\n (property %s (string \"%d'h%s\"))", EDIF_DEF(name), GetSize(val.bits), hex_string.c_str());
+ }
+ };
for (auto module : sorted_modules)
{
if (module->get_blackbox_attribute())
@@ -323,14 +343,23 @@ struct EdifBackend : public Backend {
else if (!wire->port_input)
dir = "OUTPUT";
if (wire->width == 1) {
- *f << stringf(" (port %s (direction %s))\n", EDIF_DEF(wire->name), dir);
+ *f << stringf(" (port %s (direction %s)", EDIF_DEF(wire->name), dir);
+ if (attr_properties)
+ for (auto &p : wire->attributes)
+ add_prop(p.first, p.second);
+ *f << ")\n";
RTLIL::SigSpec sig = sigmap(RTLIL::SigSpec(wire));
net_join_db[sig].insert(stringf("(portRef %s)", EDIF_REF(wire->name)));
} else {
int b[2];
b[wire->upto ? 0 : 1] = wire->start_offset;
b[wire->upto ? 1 : 0] = wire->start_offset + GetSize(wire) - 1;
- *f << stringf(" (port (array %s %d) (direction %s))\n", EDIF_DEFR(wire->name, port_rename, b[0], b[1]), wire->width, dir);
+ *f << stringf(" (port (array %s %d) (direction %s)", EDIF_DEFR(wire->name, port_rename, b[0], b[1]), wire->width, dir);
+ if (attr_properties)
+ for (auto &p : wire->attributes)
+ add_prop(p.first, p.second);
+
+ *f << ")\n";
for (int i = 0; i < wire->width; i++) {
RTLIL::SigSpec sig = sigmap(RTLIL::SigSpec(wire, i));
net_join_db[sig].insert(stringf("(portRef (member %s %d))", EDIF_REF(wire->name), GetSize(wire)-i-1));
@@ -348,27 +377,6 @@ struct EdifBackend : public Backend {
*f << stringf(" (instance %s\n", EDIF_DEF(cell->name));
*f << stringf(" (viewRef VIEW_NETLIST (cellRef %s%s))", EDIF_REF(cell->type),
lib_cell_ports.count(cell->type) > 0 ? " (libraryRef LIB)" : "");
-
- auto add_prop = [&](IdString name, Const val) {
- if ((val.flags & RTLIL::CONST_FLAG_STRING) != 0)
- *f << stringf("\n (property %s (string \"%s\"))", EDIF_DEF(name), val.decode_string().c_str());
- else if (val.bits.size() <= 32 && RTLIL::SigSpec(val).is_fully_def())
- *f << stringf("\n (property %s (integer %u))", EDIF_DEF(name), val.as_int());
- else {
- std::string hex_string = "";
- for (size_t i = 0; i < val.bits.size(); i += 4) {
- int digit_value = 0;
- if (i+0 < val.bits.size() && val.bits.at(i+0) == RTLIL::State::S1) digit_value |= 1;
- if (i+1 < val.bits.size() && val.bits.at(i+1) == RTLIL::State::S1) digit_value |= 2;
- if (i+2 < val.bits.size() && val.bits.at(i+2) == RTLIL::State::S1) digit_value |= 4;
- if (i+3 < val.bits.size() && val.bits.at(i+3) == RTLIL::State::S1) digit_value |= 8;
- char digit_str[2] = { "0123456789abcdef"[digit_value], 0 };
- hex_string = std::string(digit_str) + hex_string;
- }
- *f << stringf("\n (property %s (string \"%d'h%s\"))", EDIF_DEF(name), GetSize(val.bits), hex_string.c_str());
- }
- };
-
for (auto &p : cell->parameters)
add_prop(p.first, p.second);
if (attr_properties)
@@ -431,8 +439,12 @@ struct EdifBackend : public Backend {
*f << stringf(" (portRef %c (instanceRef GND))\n", gndvccy ? 'Y' : 'G');
if (sig == RTLIL::State::S1)
*f << stringf(" (portRef %c (instanceRef VCC))\n", gndvccy ? 'Y' : 'P');
- }
- *f << stringf(" ))\n");
+ }
+ *f << stringf(" )");
+ if (attr_properties && sig.wire != NULL)
+ for (auto &p : sig.wire->attributes)
+ add_prop(p.first, p.second);
+ *f << stringf("\n )\n");
}
*f << stringf(" )\n");
*f << stringf(" )\n");
diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc
index b4304a581..cf9b33b3c 100644
--- a/frontends/aiger/aigerparse.cc
+++ b/frontends/aiger/aigerparse.cc
@@ -206,7 +206,7 @@ eval_end:
};
AigerReader::AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name, std::string map_filename, bool wideports)
- : design(design), f(f), clk_name(clk_name), map_filename(map_filename), wideports(wideports)
+ : design(design), f(f), clk_name(clk_name), map_filename(map_filename), wideports(wideports), aiger_autoidx(autoidx++)
{
module = new RTLIL::Module;
module->name = module_name;
@@ -255,7 +255,7 @@ end_of_header:
else
log_abort();
- RTLIL::Wire* n0 = module->wire("$0");
+ RTLIL::Wire* n0 = module->wire(stringf("$aiger%d$0", aiger_autoidx));
if (n0)
module->connect(n0, State::S0);
@@ -323,18 +323,18 @@ static uint32_t parse_xaiger_literal(std::istream &f)
return from_big_endian(l);
}
-static RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned literal)
+RTLIL::Wire* AigerReader::createWireIfNotExists(RTLIL::Module *module, unsigned literal)
{
const unsigned variable = literal >> 1;
const bool invert = literal & 1;
- RTLIL::IdString wire_name(stringf("$%d%s", variable, invert ? "b" : ""));
+ RTLIL::IdString wire_name(stringf("$aiger%d$%d%s", aiger_autoidx, variable, invert ? "b" : ""));
RTLIL::Wire *wire = module->wire(wire_name);
if (wire) return wire;
log_debug2("Creating %s\n", wire_name.c_str());
wire = module->addWire(wire_name);
wire->port_input = wire->port_output = false;
if (!invert) return wire;
- RTLIL::IdString wire_inv_name(stringf("$%d", variable));
+ RTLIL::IdString wire_inv_name(stringf("$aiger%d$%d", aiger_autoidx, variable));
RTLIL::Wire *wire_inv = module->wire(wire_inv_name);
if (wire_inv) {
if (module->cell(wire_inv_name)) return wire;
@@ -346,7 +346,7 @@ static RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned litera
}
log_debug2("Creating %s = ~%s\n", wire_name.c_str(), wire_inv_name.c_str());
- module->addNotGate(stringf("$%d$not", variable), wire_inv, wire);
+ module->addNotGate(stringf("$not$aiger%d$%d", aiger_autoidx, variable), wire_inv, wire);
return wire;
}
@@ -383,7 +383,7 @@ void AigerReader::parse_xaiger()
else
log_abort();
- RTLIL::Wire* n0 = module->wire("$0");
+ RTLIL::Wire* n0 = module->wire(stringf("$aiger%d$0", aiger_autoidx));
if (n0)
module->connect(n0, State::S0);
@@ -407,13 +407,14 @@ void AigerReader::parse_xaiger()
uint32_t rootNodeID = parse_xaiger_literal(f);
uint32_t cutLeavesM = parse_xaiger_literal(f);
log_debug2("rootNodeID=%d cutLeavesM=%d\n", rootNodeID, cutLeavesM);
- RTLIL::Wire *output_sig = module->wire(stringf("$%d", rootNodeID));
+ RTLIL::Wire *output_sig = module->wire(stringf("$aiger%d$%d", aiger_autoidx, rootNodeID));
+ log_assert(output_sig);
uint32_t nodeID;
RTLIL::SigSpec input_sig;
for (unsigned j = 0; j < cutLeavesM; ++j) {
nodeID = parse_xaiger_literal(f);
log_debug2("\t%u\n", nodeID);
- RTLIL::Wire *wire = module->wire(stringf("$%d", nodeID));
+ RTLIL::Wire *wire = module->wire(stringf("$aiger%d$%d", aiger_autoidx, nodeID));
log_assert(wire);
input_sig.append(wire);
}
@@ -430,10 +431,10 @@ void AigerReader::parse_xaiger()
log_assert(o.wire == nullptr);
lut_mask[gray] = o.data;
}
- RTLIL::Cell *output_cell = module->cell(stringf("$%d$and", rootNodeID));
+ RTLIL::Cell *output_cell = module->cell(stringf("$and$aiger%d$%d", aiger_autoidx, rootNodeID));
log_assert(output_cell);
module->remove(output_cell);
- module->addLut(stringf("$%d$lut", rootNodeID), input_sig, output_sig, std::move(lut_mask));
+ module->addLut(stringf("$lut$aiger%d$%d", aiger_autoidx, rootNodeID), input_sig, output_sig, std::move(lut_mask));
}
}
else if (c == 'r') {
@@ -603,7 +604,7 @@ void AigerReader::parse_aiger_ascii()
RTLIL::Wire *o_wire = createWireIfNotExists(module, l1);
RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2);
RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3);
- module->addAndGate(o_wire->name.str() + "$and", i1_wire, i2_wire, o_wire);
+ module->addAndGate("$and" + o_wire->name.str(), i1_wire, i2_wire, o_wire);
}
std::getline(f, line); // Ignore up to start of next line
}
@@ -729,7 +730,7 @@ void AigerReader::parse_aiger_binary()
RTLIL::Wire *o_wire = createWireIfNotExists(module, l1);
RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2);
RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3);
- module->addAndGate(o_wire->name.str() + "$and", i1_wire, i2_wire, o_wire);
+ module->addAndGate("$and" + o_wire->name.str(), i1_wire, i2_wire, o_wire);
}
}
@@ -831,6 +832,7 @@ void AigerReader::post_process()
}
else {
wire->port_output = false;
+ existing->port_output = true;
module->connect(wire, existing);
wire = existing;
}
@@ -845,8 +847,9 @@ void AigerReader::post_process()
wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index);
}
else {
- module->connect(wire, existing);
wire->port_output = false;
+ existing->port_output = true;
+ module->connect(wire, existing);
}
log_debug(" -> %s\n", log_id(indexed_name));
}
diff --git a/frontends/aiger/aigerparse.h b/frontends/aiger/aigerparse.h
index de3c3efbc..722f1e472 100644
--- a/frontends/aiger/aigerparse.h
+++ b/frontends/aiger/aigerparse.h
@@ -33,6 +33,7 @@ struct AigerReader
RTLIL::Module *module;
std::string map_filename;
bool wideports;
+ const int aiger_autoidx;
unsigned M, I, L, O, A;
unsigned B, C, J, F; // Optional in AIGER 1.9
@@ -51,6 +52,8 @@ struct AigerReader
void parse_aiger_ascii();
void parse_aiger_binary();
void post_process();
+
+ RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned literal);
};
YOSYS_NAMESPACE_END
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index ab4f4f377..f286d139f 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -46,6 +46,7 @@ IdString RTLIL::ID::Y;
IdString RTLIL::ID::keep;
IdString RTLIL::ID::whitebox;
IdString RTLIL::ID::blackbox;
+dict<std::string, std::string> RTLIL::constpad;
RTLIL::Const::Const()
{
diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index e5b24cc02..6251d265d 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -377,6 +377,8 @@ namespace RTLIL
extern IdString blackbox;
};
+ extern dict<std::string, std::string> constpad;
+
static inline std::string escape_id(std::string str) {
if (str.size() > 0 && str[0] != '\\' && str[0] != '$')
return "\\" + str;
diff --git a/passes/cmds/autoname.cc b/passes/cmds/autoname.cc
index 4614a8153..50632201e 100644
--- a/passes/cmds/autoname.cc
+++ b/passes/cmds/autoname.cc
@@ -56,7 +56,7 @@ int autoname_worker(Module *module)
for (auto &conn : cell->connections()) {
string suffix = stringf("_%s", log_id(conn.first));
for (auto bit : conn.second)
- if (bit.wire != nullptr && bit.wire->name[0] == '$') {
+ if (bit.wire != nullptr && bit.wire->name[0] == '$' && !bit.wire->port_id) {
IdString new_name(cell->name.str() + suffix);
int score = wire_score.at(bit.wire);
if (cell->output(conn.first)) score = 0;
diff --git a/passes/cmds/scratchpad.cc b/passes/cmds/scratchpad.cc
index 7ec55b78e..34ec0863a 100644
--- a/passes/cmds/scratchpad.cc
+++ b/passes/cmds/scratchpad.cc
@@ -70,8 +70,10 @@ struct ScratchpadPass : public Pass {
{
if (args[argidx] == "-get" && argidx+1 < args.size()) {
string identifier = args[++argidx];
- if (design->scratchpad.count(identifier)){
+ if (design->scratchpad.count(identifier)) {
log("%s\n", design->scratchpad_get_string(identifier).c_str());
+ } else if (RTLIL::constpad.count(identifier)) {
+ log("%s\n", RTLIL::constpad.at(identifier).c_str());
} else {
log("\"%s\" not set\n", identifier.c_str());
}
@@ -79,6 +81,8 @@ struct ScratchpadPass : public Pass {
}
if (args[argidx] == "-set" && argidx+2 < args.size()) {
string identifier = args[++argidx];
+ if (RTLIL::constpad.count(identifier))
+ log_error("scratchpad entry \"%s\" is a global constant\n", identifier.c_str());
string value = args[++argidx];
if (value.front() == '\"' && value.back() == '\"') value = value.substr(1, value.size() - 2);
design->scratchpad_set_string(identifier, value);
@@ -92,8 +96,15 @@ struct ScratchpadPass : public Pass {
if (args[argidx] == "-copy" && argidx+2 < args.size()) {
string identifier_from = args[++argidx];
string identifier_to = args[++argidx];
- if (design->scratchpad.count(identifier_from) == 0) log_error("\"%s\" not set\n", identifier_from.c_str());
- string value = design->scratchpad_get_string(identifier_from);
+ string value;
+ if (design->scratchpad.count(identifier_from))
+ value = design->scratchpad_get_string(identifier_from);
+ else if (RTLIL::constpad.count(identifier_from))
+ value = RTLIL::constpad.at(identifier_from);
+ else
+ log_error("\"%s\" not set\n", identifier_from.c_str());
+ if (RTLIL::constpad.count(identifier_to))
+ log_error("scratchpad entry \"%s\" is a global constant\n", identifier_to.c_str());
design->scratchpad_set_string(identifier_to, value);
continue;
}
@@ -102,10 +113,10 @@ struct ScratchpadPass : public Pass {
string expected = args[++argidx];
if (expected.front() == '\"' && expected.back() == '\"') expected = expected.substr(1, expected.size() - 2);
if (design->scratchpad.count(identifier) == 0)
- log_error("Assertion failed: scratchpad entry '%s' is not defined\n", identifier.c_str());
+ log_error("scratchpad entry '%s' is not defined\n", identifier.c_str());
string value = design->scratchpad_get_string(identifier);
if (value != expected) {
- log_error("Assertion failed: scratchpad entry '%s' is set to '%s' instead of the asserted '%s'\n",
+ log_error("scratchpad entry '%s' is set to '%s' instead of the asserted '%s'\n",
identifier.c_str(), value.c_str(), expected.c_str());
}
continue;
@@ -113,13 +124,13 @@ struct ScratchpadPass : public Pass {
if (args[argidx] == "-assert-set" && argidx+1 < args.size()) {
string identifier = args[++argidx];
if (design->scratchpad.count(identifier) == 0)
- log_error("Assertion failed: scratchpad entry '%s' is not defined\n", identifier.c_str());
+ log_error("scratchpad entry '%s' is not defined\n", identifier.c_str());
continue;
}
if (args[argidx] == "-assert-unset" && argidx+1 < args.size()) {
string identifier = args[++argidx];
if (design->scratchpad.count(identifier) > 0)
- log_error("Assertion failed: scratchpad entry '%s' is defined\n", identifier.c_str());
+ log_error("scratchpad entry '%s' is defined\n", identifier.c_str());
continue;
}
break;
diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc
index 1be7519b7..5ba87fa88 100644
--- a/passes/techmap/abc9.cc
+++ b/passes/techmap/abc9.cc
@@ -18,18 +18,69 @@
*
*/
+// [[CITE]] ABC
+// Berkeley Logic Synthesis and Verification Group, ABC: A System for Sequential Synthesis and Verification
+// http://www.eecs.berkeley.edu/~alanmi/abc/
+
#include "kernel/register.h"
#include "kernel/celltypes.h"
#include "kernel/rtlil.h"
#include "kernel/log.h"
+// abc9_exe.cc
+std::string fold_abc9_cmd(std::string str);
+
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct Abc9Pass : public ScriptPass
{
Abc9Pass() : ScriptPass("abc9", "use ABC9 for technology mapping") { }
-
+ void on_register() YS_OVERRIDE
+ {
+ RTLIL::constpad["abc9.script.default"] = "+&scorr; &sweep; &dc2; &dch -f; &ps; &if {C} {W} {D} {R} -v; &mfs";
+ RTLIL::constpad["abc9.script.default.area"] = "+&scorr; &sweep; &dc2; &dch -f; &ps; &if {C} {W} {D} {R} -a -v; &mfs";
+ RTLIL::constpad["abc9.script.default.fast"] = "+&if {C} {W} {D} {R} -v";
+ // Based on ABC's &flow
+ RTLIL::constpad["abc9.script.flow"] = "+&scorr; &sweep;" \
+ "&dch -C 500;" \
+ /* Round 1 */ \
+ /* Map 1 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
+ "&st; &dsdb;" \
+ /* Map 2 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
+ "&st; &syn2 -m -R 10; &dsdb;" \
+ "&blut -a -K 6;" \
+ /* Map 3 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
+ /* Round 2 */ \
+ "&st; &sopb;" \
+ /* Map 1 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
+ "&st; &dsdb;" \
+ /* Map 2 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
+ "&st; &syn2 -m -R 10; &dsdb;" \
+ "&blut -a -K 6;" \
+ /* Map 3 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
+ /* Round 3 */ \
+ /* Map 1 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
+ "&st; &dsdb;" \
+ /* Map 2 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
+ "&st; &syn2 -m -R 10; &dsdb;" \
+ "&blut -a -K 6;" \
+ /* Map 3 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;";
+ // Based on ABC's &flow2
+ RTLIL::constpad["abc9.script.flow2"] = "+&scorr; &sweep;" \
+ /* Comm1 */ "&synch2 -K 6 -C 500; &if -m {C} {W} {D} {R} -v; &mfs "/*"-W 4 -M 500 -C 7000"*/"; &save;"\
+ /* Comm2 */ "&dch -C 500; &if -m {C} {W} {D} {R} -v; &mfs "/*"-W 4 -M 500 -C 7000"*/"; &save;"\
+ "&load; &st; &sopb -R 10 -C 4; " \
+ /* Comm3 */ "&synch2 -K 6 -C 500; &if -m "/*"-E 5"*/" {C} {W} {D} {R} -v; &mfs "/*"-W 4 -M 500 -C 7000"*/"; &save;"\
+ /* Comm2 */ "&dch -C 500; &if -m {C} {W} {D} {R} -v; &mfs "/*"-W 4 -M 500 -C 7000"*/"; &save; "\
+ "&load";
+ // Based on ABC's &flow3
+ RTLIL::constpad["abc9.script.flow3"] = "+&scorr; &sweep;" \
+ "&if {C} {W} {D}; &save; &st; &syn2; &if {C} {W} {D} {R} -v; &save; &load;"\
+ "&st; &if {C} -g -K 6; &dch -f; &if {C} {W} {D} {R} -v; &save; &load;"\
+ "&st; &if {C} -g -K 6; &synch2; &if {C} {W} {D} {R} -v; &save; &load;"\
+ "&mfs";
+ }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
@@ -40,6 +91,11 @@ struct Abc9Pass : public ScriptPass
log("tool [1] for technology mapping of the current design to a target FPGA\n");
log("architecture. Only fully-selected modules are supported.\n");
log("\n");
+ log(" -run <from_label>:<to_label>\n");
+ log(" only run the commands between the labels (see below). an empty\n");
+ log(" from label is synonymous to 'begin', and empty to label is\n");
+ log(" synonymous to the end of the command list.\n");
+ log("\n");
log(" -exe <command>\n");
#ifdef ABCEXTERNAL
log(" use the specified command instead of \"" ABCEXTERNAL "\" to execute ABC.\n");
@@ -57,14 +113,12 @@ struct Abc9Pass : public ScriptPass
log(" replaced with blanks before the string is passed to ABC.\n");
log("\n");
log(" if no -script parameter is given, the following scripts are used:\n");
- //FIXME:
- //log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT).c_str());
+ log("%s\n", fold_abc9_cmd(RTLIL::constpad.at("abc9.script.default").substr(1,std::string::npos)).c_str());
log("\n");
log(" -fast\n");
log(" use different default scripts that are slightly faster (at the cost\n");
log(" of output quality):\n");
- //FIXME:
- //log("%s\n", fold_abc9_cmd(ABC_FAST_COMMAND_LUT).c_str());
+ log("%s\n", fold_abc9_cmd(RTLIL::constpad.at("abc9.script.default.fast").substr(1,std::string::npos)).c_str());
log("\n");
log(" -D <picoseconds>\n");
log(" set delay target. the string {D} in the default scripts above is\n");
@@ -104,7 +158,7 @@ struct Abc9Pass : public ScriptPass
log(" command output is identical across runs.\n");
log("\n");
log(" -box <file>\n");
- log(" pass this file with box library to ABC. Use with -lut.\n");
+ log(" pass this file with box library to ABC.\n");
log("\n");
log("Note that this is a logic optimization pass within Yosys that is calling ABC\n");
log("internally. This is not going to \"run ABC on your design\". It will instead run\n");
@@ -141,6 +195,11 @@ struct Abc9Pass : public ScriptPass
dff_mode = design->scratchpad_get_bool("abc9.dff", dff_mode);
cleanup = !design->scratchpad_get_bool("abc9.nocleanup", !cleanup);
+ if (design->scratchpad_get_bool("abc9.debug")) {
+ cleanup = false;
+ exe_cmd << " -showtmp";
+ }
+
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
std::string arg = args[argidx];
@@ -152,13 +211,13 @@ struct Abc9Pass : public ScriptPass
continue;
}
if (arg == "-fast" || /* arg == "-dff" || */
- /* arg == "-nocleanup" || */ arg == "-showtmp" ||
- arg == "-nomfs") {
+ /* arg == "-nocleanup" || */ arg == "-showtmp") {
exe_cmd << " " << arg;
continue;
}
if (arg == "-dff") {
dff_mode = true;
+ exe_cmd << " " << arg;
continue;
}
if (arg == "-nocleanup") {
@@ -169,6 +228,14 @@ struct Abc9Pass : public ScriptPass
box_file = args[++argidx];
continue;
}
+ if (arg == "-run" && argidx+1 < args.size()) {
+ size_t pos = args[argidx+1].find(':');
+ if (pos == std::string::npos)
+ break;
+ run_from = args[++argidx].substr(0, pos);
+ run_to = args[argidx].substr(pos+1);
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -184,9 +251,9 @@ struct Abc9Pass : public ScriptPass
run("abc9_ops -check");
run("scc -set_attr abc9_scc_id {}");
if (help_mode)
- run("abc9_ops -break_scc -prep_times -prep_holes [-dff]", "(option for -dff)");
+ run("abc9_ops -mark_scc -prep_times -prep_xaiger [-dff]", "(option for -dff)");
else
- run("abc9_ops -break_scc -prep_times -prep_holes" + std::string(dff_mode ? " -dff" : ""), "(option for -dff)");
+ run("abc9_ops -mark_scc -prep_times -prep_xaiger" + std::string(dff_mode ? " -dff" : ""), "(option for -dff)");
run("select -set abc9_holes A:abc9_holes");
run("flatten -wb @abc9_holes");
run("techmap @abc9_holes");
@@ -200,7 +267,7 @@ struct Abc9Pass : public ScriptPass
if (check_label("map")) {
if (help_mode) {
run("foreach module in selection");
- run(" abc9_ops -write_box [(-box value)|(null)] <abc-temp-dir>/input.box");
+ run(" abc9_ops -write_box [(-box <path>)|(null)] <abc-temp-dir>/input.box");
run(" write_xaiger -map <abc-temp-dir>/input.sym <abc-temp-dir>/input.xaig");
run(" abc9_exe [options] -cwd <abc-temp-dir> -box <abc-temp-dir>/input.box");
run(" read_aiger -xaiger -wideports -module_name <module-name>$abc9 -map <abc-temp-dir>/input.sym <abc-temp-dir>/output.aig");
@@ -234,14 +301,16 @@ struct Abc9Pass : public ScriptPass
run(stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str()));
int num_outputs = active_design->scratchpad_get_int("write_xaiger.num_outputs");
- log("Extracted %d AND gates and %d wires to a netlist network with %d inputs and %d outputs.\n",
+
+ log("Extracted %d AND gates and %d wires from module `%s' to a netlist network with %d inputs and %d outputs.\n",
active_design->scratchpad_get_int("write_xaiger.num_ands"),
active_design->scratchpad_get_int("write_xaiger.num_wires"),
+ log_id(mod),
active_design->scratchpad_get_int("write_xaiger.num_inputs"),
num_outputs);
if (num_outputs) {
run(stringf("%s -cwd %s -box %s/input.box", exe_cmd.str().c_str(), tempdir_name.c_str(), tempdir_name.c_str()));
- run(stringf("read_aiger -xaiger -wideports -module_name %s$abc9 -map %s/input.sym %s/output.aig", log_id(mod->name), tempdir_name.c_str(), tempdir_name.c_str()));
+ run(stringf("read_aiger -xaiger -wideports -module_name %s$abc9 -map %s/input.sym %s/output.aig", log_id(mod), tempdir_name.c_str(), tempdir_name.c_str()));
run("abc9_ops -reintegrate");
}
else
@@ -258,9 +327,6 @@ struct Abc9Pass : public ScriptPass
active_design->selection_stack.pop_back();
}
}
-
- if (check_label("post"))
- run("abc9_ops -unbreak_scc");
}
} Abc9Pass;
diff --git a/passes/techmap/abc9_exe.cc b/passes/techmap/abc9_exe.cc
index d92285a51..a2acfac91 100644
--- a/passes/techmap/abc9_exe.cc
+++ b/passes/techmap/abc9_exe.cc
@@ -22,20 +22,6 @@
// Berkeley Logic Synthesis and Verification Group, ABC: A System for Sequential Synthesis and Verification
// http://www.eecs.berkeley.edu/~alanmi/abc/
-#if 0
-// Based on &flow3 - better QoR but more experimental
-#define ABC_COMMAND_LUT "&st; &ps -l; &sweep -v; &scorr; " \
- "&st; &if {W}; &save; &st; &syn2; &if {W} -v; &save; &load; "\
- "&st; &if -g -K 6; &dch -f; &if {W} -v; &save; &load; "\
- "&st; &if -g -K 6; &synch2; &if {W} -v; &save; &load; "\
- "&mfs; &ps -l"
-#else
-#define ABC_COMMAND_LUT "&st; &scorr; &sweep; &dc2; &st; &dch -f; &ps; &if {W} {D} -v; &mfs; &ps -l"
-#endif
-
-
-#define ABC_FAST_COMMAND_LUT "&st; &if {W} {D}"
-
#include "kernel/register.h"
#include "kernel/log.h"
@@ -48,6 +34,25 @@
extern "C" int Abc_RealMain(int argc, char *argv[]);
#endif
+std::string fold_abc9_cmd(std::string str)
+{
+ std::string token, new_str = " ";
+ int char_counter = 10;
+
+ for (size_t i = 0; i <= str.size(); i++) {
+ if (i < str.size())
+ token += str[i];
+ if (i == str.size() || str[i] == ';') {
+ if (char_counter + token.size() > 75)
+ new_str += "\n ", char_counter = 14;
+ new_str += token, char_counter += token.size();
+ token.clear();
+ }
+ }
+
+ return new_str;
+}
+
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@@ -73,25 +78,6 @@ std::string add_echos_to_abc9_cmd(std::string str)
return new_str;
}
-std::string fold_abc9_cmd(std::string str)
-{
- std::string token, new_str = " ";
- int char_counter = 10;
-
- for (size_t i = 0; i <= str.size(); i++) {
- if (i < str.size())
- token += str[i];
- if (i == str.size() || str[i] == ';') {
- if (char_counter + token.size() > 75)
- new_str += "\n ", char_counter = 14;
- new_str += token, char_counter += token.size();
- token.clear();
- }
- }
-
- return new_str;
-}
-
std::string replace_tempdir(std::string text, std::string tempdir_name, bool show_tempdir)
{
if (show_tempdir)
@@ -177,25 +163,21 @@ struct abc9_output_filter
};
void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe_file,
- vector<int> lut_costs, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode,
+ vector<int> lut_costs, bool dff_mode, 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, bool nomfs, std::string tempdir_name
+ std::string wire_delay, std::string tempdir_name
)
{
- //FIXME:
- //log_header(design, "Extracting gate netlist of module `%s' to `%s/input.xaig'..\n",
- // module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str());
-
std::string abc9_script;
if (!lut_costs.empty())
abc9_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str());
- else
- if (!lut_file.empty())
+ else if (!lut_file.empty())
abc9_script += stringf("read_lut %s; ", lut_file.c_str());
else
log_abort();
+ log_assert(!box_file.empty());
abc9_script += stringf("read_box %s; ", box_file.c_str());
abc9_script += stringf("&read %s/input.xaig; &ps; ", tempdir_name.c_str());
@@ -211,7 +193,8 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe
} else
abc9_script += stringf("source %s", script_file.c_str());
} else if (!lut_costs.empty() || !lut_file.empty()) {
- abc9_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT;
+ abc9_script += fast_mode ? RTLIL::constpad.at("abc9.script.default.fast").substr(1,std::string::npos)
+ : RTLIL::constpad.at("abc9.script.default").substr(1,std::string::npos);
} else
log_abort();
@@ -224,11 +207,26 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe
for (size_t pos = abc9_script.find("{W}"); pos != std::string::npos; pos = abc9_script.find("{W}", pos))
abc9_script = abc9_script.substr(0, pos) + wire_delay + abc9_script.substr(pos+3);
- if (nomfs)
- for (size_t pos = abc9_script.find("&mfs"); pos != std::string::npos; pos = abc9_script.find("&mfs", pos))
- abc9_script = abc9_script.erase(pos, strlen("&mfs"));
-
- abc9_script += stringf("; &write -n %s/output.aig", tempdir_name.c_str());
+ std::string C;
+ if (design->scratchpad.count("abc9.if.C"))
+ C = "-C " + design->scratchpad_get_string("abc9.if.C");
+ for (size_t pos = abc9_script.find("{C}"); pos != std::string::npos; pos = abc9_script.find("{C}", pos))
+ abc9_script = abc9_script.substr(0, pos) + C + abc9_script.substr(pos+3);
+
+ std::string R;
+ if (design->scratchpad.count("abc9.if.R"))
+ R = "-R " + design->scratchpad_get_string("abc9.if.R");
+ for (size_t pos = abc9_script.find("{R}"); pos != std::string::npos; pos = abc9_script.find("{R}", pos))
+ abc9_script = abc9_script.substr(0, pos) + R + abc9_script.substr(pos+3);
+
+ abc9_script += stringf("; &ps -l; &write -n %s/output.aig;", tempdir_name.c_str());
+ if (design->scratchpad_get_bool("abc9.verify")) {
+ if (dff_mode)
+ abc9_script += "verify -s;";
+ else
+ abc9_script += "verify;";
+ }
+ abc9_script += "time";
abc9_script = add_echos_to_abc9_cmd(abc9_script);
for (size_t i = 0; i+1 < abc9_script.size(); i++)
@@ -308,12 +306,12 @@ struct Abc9ExePass : public Pass {
log(" replaced with blanks before the string is passed to ABC.\n");
log("\n");
log(" if no -script parameter is given, the following scripts are used:\n");
- log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT).c_str());
+ log("%s\n", fold_abc9_cmd(RTLIL::constpad.at("abc9.script.default").substr(1,std::string::npos)).c_str());
log("\n");
log(" -fast\n");
log(" use different default scripts that are slightly faster (at the cost\n");
log(" of output quality):\n");
- log("%s\n", fold_abc9_cmd(ABC_FAST_COMMAND_LUT).c_str());
+ log("%s\n", fold_abc9_cmd(RTLIL::constpad.at("abc9.script.default.fast").substr(1,std::string::npos)).c_str());
log("\n");
log(" -D <picoseconds>\n");
log(" set delay target. the string {D} in the default scripts above is\n");
@@ -374,9 +372,8 @@ struct Abc9ExePass : public Pass {
std::string script_file, clk_str, box_file, lut_file;
std::string delay_target, lutin_shared = "-S 1", wire_delay;
std::string tempdir_name;
- bool fast_mode = false;
+ bool fast_mode = false, dff_mode = false;
bool show_tempdir = false;
- bool nomfs = false;
vector<int> lut_costs;
#if 0
@@ -400,12 +397,12 @@ struct Abc9ExePass : public Pass {
lut_arg = design->scratchpad_get_string("abc9.lut", lut_arg);
luts_arg = design->scratchpad_get_string("abc9.luts", luts_arg);
fast_mode = design->scratchpad_get_bool("abc9.fast", fast_mode);
+ dff_mode = design->scratchpad_get_bool("abc9.dff", dff_mode);
show_tempdir = design->scratchpad_get_bool("abc9.showtmp", show_tempdir);
box_file = design->scratchpad_get_string("abc9.box", box_file);
if (design->scratchpad.count("abc9.W")) {
wire_delay = "-W " + design->scratchpad_get_string("abc9.W");
}
- nomfs = design->scratchpad_get_bool("abc9.nomfs", nomfs);
size_t argidx;
char pwd [PATH_MAX];
@@ -443,6 +440,10 @@ struct Abc9ExePass : public Pass {
fast_mode = true;
continue;
}
+ if (arg == "-dff") {
+ dff_mode = true;
+ continue;
+ }
if (arg == "-showtmp") {
show_tempdir = true;
continue;
@@ -455,10 +456,6 @@ struct Abc9ExePass : public Pass {
wire_delay = "-W " + args[++argidx];
continue;
}
- if (arg == "-nomfs") {
- nomfs = true;
- continue;
- }
if (arg == "-cwd" && argidx+1 < args.size()) {
tempdir_name = args[++argidx];
continue;
@@ -525,9 +522,9 @@ struct Abc9ExePass : public Pass {
log_cmd_error("abc9_exe '-cwd' option is mandatory.\n");
- abc9_module(design, script_file, exe_file, lut_costs,
+ abc9_module(design, script_file, exe_file, lut_costs, dff_mode,
delay_target, lutin_shared, fast_mode, show_tempdir,
- box_file, lut_file, wire_delay, nomfs, tempdir_name);
+ box_file, lut_file, wire_delay, tempdir_name);
}
} Abc9ExePass;
diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc
index 7f3bbc7ad..04a54fd63 100644
--- a/passes/techmap/abc9_ops.cc
+++ b/passes/techmap/abc9_ops.cc
@@ -91,7 +91,7 @@ void check(RTLIL::Design *design)
}
}
-void break_scc(RTLIL::Module *module)
+void mark_scc(RTLIL::Module *module)
{
// For every unique SCC found, (arbitrarily) find the first
// cell in the component, and convert all wires driven by
@@ -102,7 +102,8 @@ void break_scc(RTLIL::Module *module)
auto it = cell->attributes.find(ID(abc9_scc_id));
if (it == cell->attributes.end())
continue;
- auto r = ids_seen.insert(it->second);
+ auto id = it->second;
+ auto r = ids_seen.insert(id);
cell->attributes.erase(it);
if (!r.second)
continue;
@@ -111,30 +112,8 @@ void break_scc(RTLIL::Module *module)
if (cell->output(c.first)) {
SigBit b = c.second.as_bit();
Wire *w = b.wire;
- if (w->port_input) {
- // In this case, hopefully the loop break has been already created
- // Get the non-prefixed wire
- Wire *wo = module->wire(stringf("%s.abco", b.wire->name.c_str()));
- log_assert(wo != nullptr);
- log_assert(wo->port_output);
- log_assert(b.offset < GetSize(wo));
- c.second = RTLIL::SigBit(wo, b.offset);
- }
- else {
- // Create a new output/input loop break
- w->port_input = true;
- w = module->wire(stringf("%s.abco", w->name.c_str()));
- if (!w) {
- w = module->addWire(stringf("%s.abco", b.wire->name.c_str()), GetSize(b.wire));
- w->port_output = true;
- }
- else {
- log_assert(w->port_input);
- log_assert(b.offset < GetSize(w));
- }
- w->set_bool_attribute(ID(abc9_scc_break));
- c.second = RTLIL::SigBit(w, b.offset);
- }
+ w->set_bool_attribute(ID::keep);
+ w->attributes[ID(abc9_scc_id)] = id.as_int();
}
}
}
@@ -142,28 +121,6 @@ void break_scc(RTLIL::Module *module)
module->fixup_ports();
}
-void unbreak_scc(RTLIL::Module *module)
-{
- // Now 'unexpose' those wires by undoing
- // the expose operation -- remove them from PO/PI
- // and re-connecting them back together
- for (auto wire : module->wires()) {
- auto it = wire->attributes.find(ID(abc9_scc_break));
- if (it != wire->attributes.end()) {
- wire->attributes.erase(it);
- log_assert(wire->port_output);
- wire->port_output = false;
- std::string name = wire->name.str();
- RTLIL::Wire *i_wire = module->wire(name.substr(0, GetSize(name) - 5));
- log_assert(i_wire);
- log_assert(i_wire->port_input);
- i_wire->port_input = false;
- module->connect(i_wire, wire);
- }
- }
- module->fixup_ports();
-}
-
void prep_dff(RTLIL::Module *module)
{
auto design = module->design;
@@ -244,7 +201,7 @@ void prep_dff(RTLIL::Module *module)
}
}
-void prep_holes(RTLIL::Module *module, bool dff)
+void prep_xaiger(RTLIL::Module *module, bool dff)
{
auto design = module->design;
log_assert(design);
@@ -253,7 +210,7 @@ void prep_holes(RTLIL::Module *module, bool dff)
dict<SigBit, pool<IdString>> bit_drivers, bit_users;
TopoSort<IdString, RTLIL::sort_by_id_str> toposort;
- bool abc9_box_seen = false;
+ dict<IdString, std::vector<IdString>> box_ports;
for (auto cell : module->cells()) {
if (cell->type == "$__ABC9_FF_")
@@ -266,7 +223,40 @@ void prep_holes(RTLIL::Module *module, bool dff)
abc9_flop = inst_module->get_bool_attribute("\\abc9_flop");
if (abc9_flop && !dff)
continue;
- abc9_box_seen = abc9_box;
+
+ auto r = box_ports.insert(cell->type);
+ if (r.second) {
+ // Make carry in the last PI, and carry out the last PO
+ // since ABC requires it this way
+ IdString carry_in, carry_out;
+ for (const auto &port_name : inst_module->ports) {
+ auto w = inst_module->wire(port_name);
+ log_assert(w);
+ if (w->get_bool_attribute("\\abc9_carry")) {
+ if (w->port_input) {
+ if (carry_in != IdString())
+ log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(inst_module));
+ carry_in = port_name;
+ }
+ if (w->port_output) {
+ if (carry_out != IdString())
+ log_error("Module '%s' contains more than one 'abc9_carry' output port.\n", log_id(inst_module));
+ carry_out = port_name;
+ }
+ }
+ else
+ r.first->second.push_back(port_name);
+ }
+
+ if (carry_in != IdString() && carry_out == IdString())
+ log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", log_id(inst_module));
+ if (carry_in == IdString() && carry_out != IdString())
+ log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(inst_module));
+ if (carry_in != IdString()) {
+ r.first->second.push_back(carry_in);
+ r.first->second.push_back(carry_out);
+ }
+ }
}
else if (!yosys_celltypes.cell_known(cell->type))
continue;
@@ -284,7 +274,7 @@ void prep_holes(RTLIL::Module *module, bool dff)
toposort.node(cell->name);
}
- if (!abc9_box_seen)
+ if (box_ports.empty())
return;
for (auto &it : bit_users)
@@ -312,7 +302,13 @@ void prep_holes(RTLIL::Module *module, bool dff)
log_assert(no_loops);
- vector<Cell*> box_list;
+ RTLIL::Module *holes_module = design->addModule(stringf("%s$holes", module->name.c_str()));
+ log_assert(holes_module);
+ holes_module->set_bool_attribute("\\abc9_holes");
+
+ dict<IdString, Cell*> cell_cache;
+
+ int port_id = 1, box_count = 0;
for (auto cell_name : toposort.sorted) {
RTLIL::Cell *cell = module->cell(cell_name);
log_assert(cell);
@@ -321,92 +317,16 @@ void prep_holes(RTLIL::Module *module, bool dff)
if (!box_module || !box_module->attributes.count("\\abc9_box_id"))
continue;
- bool blackbox = box_module->get_blackbox_attribute(true /* ignore_wb */);
-
- // Fully pad all unused input connections of this box cell with S0
- // Fully pad all undriven output connections of this box cell with anonymous wires
- for (const auto &port_name : box_module->ports) {
- RTLIL::Wire* w = box_module->wire(port_name);
- log_assert(w);
- auto it = cell->connections_.find(port_name);
- if (w->port_input) {
- RTLIL::SigSpec rhs;
- if (it != cell->connections_.end()) {
- if (GetSize(it->second) < GetSize(w))
- it->second.append(RTLIL::SigSpec(State::S0, GetSize(w)-GetSize(it->second)));
- rhs = it->second;
- }
- else {
- rhs = RTLIL::SigSpec(State::S0, GetSize(w));
- cell->setPort(port_name, rhs);
- }
- }
- if (w->port_output) {
- RTLIL::SigSpec rhs;
- auto it = cell->connections_.find(w->name);
- if (it != cell->connections_.end()) {
- if (GetSize(it->second) < GetSize(w))
- it->second.append(module->addWire(NEW_ID, GetSize(w)-GetSize(it->second)));
- rhs = it->second;
- }
- else {
- Wire *wire = module->addWire(NEW_ID, GetSize(w));
- if (blackbox)
- wire->set_bool_attribute(ID(abc9_padding));
- rhs = wire;
- cell->setPort(port_name, rhs);
- }
- }
- }
-
- cell->attributes["\\abc9_box_seq"] = box_list.size();
- //log_debug("%s.%s is box %d\n", log_id(module), log_id(cell), box_list.size());
- box_list.emplace_back(cell);
- }
- log_assert(!box_list.empty());
-
- RTLIL::Module *holes_module = design->addModule(stringf("%s$holes", module->name.c_str()));
- log_assert(holes_module);
- holes_module->set_bool_attribute("\\abc9_holes");
-
- dict<IdString, Cell*> cell_cache;
- dict<IdString, std::vector<IdString>> box_ports;
+ cell->attributes["\\abc9_box_seq"] = box_count++;
- int port_id = 1;
- for (auto cell : box_list) {
- RTLIL::Module* orig_box_module = design->module(cell->type);
- log_assert(orig_box_module);
- IdString derived_name = orig_box_module->derive(design, cell->parameters);
- RTLIL::Module* box_module = design->module(derived_name);
- //cell->type = derived_name;
- //cell->parameters.clear();
+ IdString derived_name = box_module->derive(design, cell->parameters);
+ box_module = design->module(derived_name);
auto r = cell_cache.insert(derived_name);
auto &holes_cell = r.first->second;
if (r.second) {
- auto r2 = box_ports.insert(cell->type);
- if (r2.second) {
- // Make carry in the last PI, and carry out the last PO
- // since ABC requires it this way
- IdString carry_in, carry_out;
- for (const auto &port_name : box_module->ports) {
- auto w = box_module->wire(port_name);
- log_assert(w);
- if (w->get_bool_attribute("\\abc9_carry")) {
- if (w->port_input)
- carry_in = port_name;
- if (w->port_output)
- carry_out = port_name;
- }
- else
- r2.first->second.push_back(port_name);
- }
-
- if (carry_in != IdString()) {
- r2.first->second.push_back(carry_in);
- r2.first->second.push_back(carry_out);
- }
- }
+ if (box_module->has_processes())
+ Pass::call_on_module(design, box_module, "proc");
if (box_module->get_bool_attribute("\\whitebox")) {
holes_cell = holes_module->addCell(cell->name, derived_name);
@@ -655,6 +575,8 @@ void reintegrate(RTLIL::Module *module)
pool<IdString> delay_boxes;
std::vector<Cell*> boxes;
for (auto cell : module->cells().to_vector()) {
+ if (cell->has_keep_attr())
+ continue;
if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_)))
module->remove(cell);
else if (cell->type.begins_with("$paramod$__ABC9_DELAY\\DELAY=")) {
@@ -680,7 +602,9 @@ void reintegrate(RTLIL::Module *module)
RTLIL::SigBit a_bit = mapped_cell->getPort(ID::A);
RTLIL::SigBit y_bit = mapped_cell->getPort(ID::Y);
bit_users[a_bit].insert(mapped_cell->name);
- bit_drivers[y_bit].insert(mapped_cell->name);
+ // Ignore inouts for topo ordering
+ if (y_bit.wire && !(y_bit.wire->port_input && y_bit.wire->port_output))
+ bit_drivers[y_bit].insert(mapped_cell->name);
if (!a_bit.wire) {
mapped_cell->setPort(ID::Y, module->addWire(NEW_ID));
@@ -698,16 +622,16 @@ void reintegrate(RTLIL::Module *module)
// (TODO: Optimise by not cloning unless will increase depth)
RTLIL::IdString driver_name;
if (GetSize(a_bit.wire) == 1)
- driver_name = stringf("%s$lut", a_bit.wire->name.c_str());
+ driver_name = stringf("$lut%s", a_bit.wire->name.c_str());
else
- driver_name = stringf("%s[%d]$lut", a_bit.wire->name.c_str(), a_bit.offset);
+ driver_name = stringf("$lut%s[%d]", a_bit.wire->name.c_str(), a_bit.offset);
driver_lut = mapped_mod->cell(driver_name);
}
if (!driver_lut) {
// If a driver couldn't be found (could be from PI or box CI)
// then implement using a LUT
- RTLIL::Cell *cell = module->addLut(remap_name(stringf("%s$lut", mapped_cell->name.c_str())),
+ RTLIL::Cell *cell = module->addLut(remap_name(stringf("$lut%s", mapped_cell->name.c_str())),
RTLIL::SigBit(module->wires_.at(remap_name(a_bit.wire->name)), a_bit.offset),
RTLIL::SigBit(module->wires_.at(remap_name(y_bit.wire->name)), y_bit.offset),
RTLIL::Const::from_string("01"));
@@ -745,7 +669,9 @@ void reintegrate(RTLIL::Module *module)
}
if (cell->output(mapped_conn.first))
for (auto i : mapped_conn.second)
- bit_drivers[i].insert(mapped_cell->name);
+ // Ignore inouts for topo ordering
+ if (i.wire && !(i.wire->port_input && i.wire->port_output))
+ bit_drivers[i].insert(mapped_cell->name);
}
}
else if (delay_boxes.count(mapped_cell->name)) {
@@ -788,7 +714,9 @@ void reintegrate(RTLIL::Module *module)
for (const auto &i : inputs)
bit_users[i].insert(mapped_cell->name);
for (const auto &i : outputs)
- bit_drivers[i].insert(mapped_cell->name);
+ // Ignore inouts for topo ordering
+ if (i.wire && !(i.wire->port_input && i.wire->port_output))
+ bit_drivers[i].insert(mapped_cell->name);
}
auto r2 = box_ports.insert(cell->type);
@@ -886,21 +814,25 @@ void reintegrate(RTLIL::Module *module)
// Stitch in mapped_mod's inputs/outputs into module
for (auto port : mapped_mod->ports) {
- RTLIL::Wire *w = mapped_mod->wire(port);
+ RTLIL::Wire *mapped_wire = mapped_mod->wire(port);
RTLIL::Wire *wire = module->wire(port);
log_assert(wire);
+ if (wire->attributes.erase(ID(abc9_scc_id))) {
+ auto r YS_ATTRIBUTE(unused) = wire->attributes.erase(ID::keep);
+ log_assert(r);
+ }
RTLIL::Wire *remap_wire = module->wire(remap_name(port));
RTLIL::SigSpec signal(wire, 0, GetSize(remap_wire));
log_assert(GetSize(signal) >= GetSize(remap_wire));
RTLIL::SigSig conn;
- if (w->port_output) {
+ if (mapped_wire->port_output) {
conn.first = signal;
conn.second = remap_wire;
out_wires++;
module->connect(conn);
}
- else if (w->port_input) {
+ else if (mapped_wire->port_input) {
conn.first = remap_wire;
conn.second = signal;
in_wires++;
@@ -996,6 +928,35 @@ struct Abc9OpsPass : public Pass {
log("\n");
log(" abc9_ops [options] [selection]\n");
log("\n");
+ log("This pass contains a set of supporting operations for use during ABC technology\n");
+ log("mapping, and is expected to be called in conjunction with other operations from\n");
+ log("the `abc9' script pass. Only fully-selected modules are supported.\n");
+ log("\n");
+ log(" -mark_scc\n");
+ log(" for an arbitrarily chosen cell in each unique SCC of each selected module\n");
+ log(" (tagged with an (* abc9_scc_id = <int> *) attribute), temporarily mark all\n");
+ log(" wires driven by this cell's outputs with a (* keep *) attribute in order\n");
+ log(" to break the SCC. this temporary attribute will be removed on -reintegrate.\n");
+ log("\n");
+ log(" -prep_xaiger\n");
+ log(" prepare the design for XAIGER output. this includes computing the\n");
+ log(" topological ordering of ABC9 boxes, as well as preparing the\n");
+ log(" '<module-name>$holes' module that contains the logic behaviour of ABC9\n");
+ log(" whiteboxes.\n");
+ log("\n");
+ log(" -dff\n");
+ log(" consider flop cells (those instantiating modules marked with (* abc9_flop *)\n");
+ log(" during -prep_xaiger.\n");
+ log("\n");
+ log(" -prep_dff\n");
+ log(" compute the clock domain and initial value of each flop in the design.\n");
+ log(" process the '$holes' module to support clock-enable functionality.\n");
+ log("\n");
+ log(" -reintegrate\n");
+ log(" for each selected module, re-intergrate the module '<module-name>$abc9'\n");
+ log(" by first recovering ABC9 boxes, and then stitching in the remaining primary\n");
+ log(" inputs and outputs.\n");
+ log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
@@ -1003,13 +964,12 @@ struct Abc9OpsPass : public Pass {
bool check_mode = false;
bool prep_times_mode = false;
- bool break_scc_mode = false;
- bool unbreak_scc_mode = false;
- bool prep_holes_mode = false;
+ bool mark_scc_mode = false;
bool prep_dff_mode = false;
- std::string write_box_src, write_box_dst;
+ bool prep_xaiger_mode = false;
bool reintegrate_mode = false;
bool dff_mode = false;
+ std::string write_box_src, write_box_dst;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
@@ -1018,20 +978,16 @@ struct Abc9OpsPass : public Pass {
check_mode = true;
continue;
}
- if (arg == "-break_scc") {
- break_scc_mode = true;
- continue;
- }
- if (arg == "-unbreak_scc") {
- unbreak_scc_mode = true;
+ if (arg == "-mark_scc") {
+ mark_scc_mode = true;
continue;
}
if (arg == "-prep_dff") {
prep_dff_mode = true;
continue;
}
- if (arg == "-prep_holes") {
- prep_holes_mode = true;
+ if (arg == "-prep_xaiger") {
+ prep_xaiger_mode = true;
continue;
}
if (arg == "-prep_times") {
@@ -1057,11 +1013,11 @@ struct Abc9OpsPass : public Pass {
}
extra_args(args, argidx, design);
- if (!(check_mode || break_scc_mode || unbreak_scc_mode || prep_times_mode || prep_holes_mode || prep_dff_mode || !write_box_src.empty() || reintegrate_mode))
- log_cmd_error("At least one of -check, -{,un}break_scc, -prep_{times,holes,dff}, -write_box, -reintegrate must be specified.\n");
+ if (!(check_mode || mark_scc_mode || prep_times_mode || prep_xaiger_mode || prep_dff_mode || !write_box_src.empty() || reintegrate_mode))
+ log_cmd_error("At least one of -check, -mark_scc, -prep_{times,xaiger,dff}, -write_box, -reintegrate must be specified.\n");
- if (dff_mode && !prep_holes_mode)
- log_cmd_error("'-dff' option is only relevant for -prep_holes.\n");
+ if (dff_mode && !prep_xaiger_mode)
+ log_cmd_error("'-dff' option is only relevant for -prep_xaiger.\n");
if (check_mode)
check(design);
@@ -1080,16 +1036,14 @@ struct Abc9OpsPass : public Pass {
if (!design->selected_whole_module(mod))
log_error("Can't handle partially selected module %s!\n", log_id(mod));
- if (break_scc_mode)
- break_scc(mod);
- if (unbreak_scc_mode)
- unbreak_scc(mod);
- if (prep_holes_mode)
- prep_holes(mod, dff_mode);
- if (prep_dff_mode)
- prep_dff(mod);
if (!write_box_src.empty())
write_box(mod, write_box_src, write_box_dst);
+ if (mark_scc_mode)
+ mark_scc(mod);
+ if (prep_dff_mode)
+ prep_dff(mod);
+ if (prep_xaiger_mode)
+ prep_xaiger(mod, dff_mode);
if (reintegrate_mode)
reintegrate(mod);
}
diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc
index 463c2063a..121bcff1f 100644
--- a/techlibs/ice40/synth_ice40.cc
+++ b/techlibs/ice40/synth_ice40.cc
@@ -102,8 +102,8 @@ struct SynthIce40Pass : public ScriptPass
log("\n");
}
- string top_opt, blif_file, edif_file, json_file, abc, device_opt;
- bool nocarry, nodffe, nobram, dsp, flatten, retime, noabc, abc2, vpr;
+ string top_opt, blif_file, edif_file, json_file, device_opt;
+ bool nocarry, nodffe, nobram, dsp, flatten, retime, noabc, abc2, vpr, abc9;
int min_ce_use;
void clear_flags() YS_OVERRIDE
@@ -122,7 +122,7 @@ struct SynthIce40Pass : public ScriptPass
noabc = false;
abc2 = false;
vpr = false;
- abc = "abc";
+ abc9 = false;
device_opt = "hx";
}
@@ -207,7 +207,7 @@ struct SynthIce40Pass : public ScriptPass
continue;
}
if (args[argidx] == "-abc9") {
- abc = "abc9";
+ abc9 = true;
continue;
}
if (args[argidx] == "-device" && argidx+1 < args.size()) {
@@ -223,7 +223,7 @@ struct SynthIce40Pass : public ScriptPass
if (device_opt != "hx" && device_opt != "lp" && device_opt !="u")
log_cmd_error("Invalid or no device specified: '%s'\n", device_opt.c_str());
- if (abc == "abc9" && retime)
+ if (abc9 && retime)
log_cmd_error("-retime option not currently compatible with -abc9!\n");
log_header(design, "Executing SYNTH_ICE40 pass.\n");
@@ -316,7 +316,7 @@ struct SynthIce40Pass : public ScriptPass
run("techmap -map +/techmap.v -map +/ice40/arith_map.v");
}
if (retime || help_mode)
- run(abc + " -dff -D 1", "(only if -retime)");
+ run("abc -dff -D 1", "(only if -retime)");
run("ice40_opt");
}
@@ -340,7 +340,7 @@ struct SynthIce40Pass : public ScriptPass
if (check_label("map_luts"))
{
if (abc2 || help_mode) {
- run(abc, " (only if -abc2)");
+ run("abc", " (only if -abc2)");
run("ice40_opt", "(only if -abc2)");
}
run("techmap -map +/ice40/latches_map.v");
@@ -349,7 +349,7 @@ struct SynthIce40Pass : public ScriptPass
run("techmap -map +/gate2lut.v -D LUT_WIDTH=4", "(only if -noabc)");
}
if (!noabc) {
- if (abc == "abc9") {
+ if (abc9) {
run("read_verilog -icells -lib +/ice40/abc9_model.v");
int wire_delay;
if (device_opt == "lp")
@@ -358,10 +358,10 @@ struct SynthIce40Pass : public ScriptPass
wire_delay = 750;
else
wire_delay = 250;
- run(abc + stringf(" -W %d -lut +/ice40/abc9_%s.lut -box +/ice40/abc9_%s.box", wire_delay, device_opt.c_str(), device_opt.c_str()), "(skip if -noabc)");
+ run(stringf("abc9 -W %d -lut +/ice40/abc9_%s.lut -box +/ice40/abc9_%s.box", wire_delay, device_opt.c_str(), device_opt.c_str()));
}
else
- run(abc + " -dress -lut 4", "(skip if -noabc)");
+ run("abc -dress -lut 4", "(skip if -noabc)");
}
run("ice40_wrapcarry -unwrap");
run("techmap -D NO_LUT -map +/ice40/cells_map.v");
diff --git a/techlibs/xilinx/abc9_map.v b/techlibs/xilinx/abc9_map.v
index 0652064cb..7dc027176 100644
--- a/techlibs/xilinx/abc9_map.v
+++ b/techlibs/xilinx/abc9_map.v
@@ -74,7 +74,7 @@
// (e) a special _TECHMAP_REPLACE_.abc9_ff.Q wire that will be used for feedback
// into the (combinatorial) FD* cell to facilitate clock-enable behaviour
-module FDRE (output Q, input C, CE, D, R);
+module FDRE (output Q, (* techmap_autopurge *) 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;
@@ -110,7 +110,7 @@ module FDRE (output Q, input C, CE, D, R);
wire [0:0] abc9_ff.init = 1'b0;
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ;
endmodule
-module FDRE_1 (output Q, input C, CE, D, R);
+module FDRE_1 (output Q, (* techmap_autopurge *) input C, CE, D, R);
parameter [0:0] INIT = 1'b0;
wire QQ, $Q;
generate if (INIT == 1'b1) begin
@@ -138,7 +138,7 @@ module FDRE_1 (output Q, input C, CE, D, R);
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ;
endmodule
-module FDSE (output Q, input C, CE, D, S);
+module FDSE (output Q, (* techmap_autopurge *) input C, CE, D, S);
parameter [0:0] INIT = 1'b1;
parameter [0:0] IS_C_INVERTED = 1'b0;
parameter [0:0] IS_D_INVERTED = 1'b0;
@@ -173,7 +173,7 @@ module FDSE (output Q, input C, CE, D, S);
wire [0:0] abc9_ff.init = 1'b0;
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ;
endmodule
-module FDSE_1 (output Q, input C, CE, D, S);
+module FDSE_1 (output Q, (* techmap_autopurge *) input C, CE, D, S);
parameter [0:0] INIT = 1'b1;
wire QQ, $Q;
generate if (INIT == 1'b1) begin
@@ -200,7 +200,7 @@ module FDSE_1 (output Q, input C, CE, D, S);
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ;
endmodule
-module FDCE (output Q, input C, CE, D, CLR);
+module FDCE (output Q, (* techmap_autopurge *) 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;
@@ -249,7 +249,7 @@ module FDCE (output Q, input C, CE, D, CLR);
wire [0:0] abc9_ff.init = 1'b0;
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ;
endmodule
-module FDCE_1 (output Q, input C, CE, D, CLR);
+module FDCE_1 (output Q, (* techmap_autopurge *) input C, CE, D, CLR);
parameter [0:0] INIT = 1'b0;
wire QQ, $Q, $QQ;
generate if (INIT == 1'b1) begin
@@ -288,7 +288,7 @@ module FDCE_1 (output Q, input C, CE, D, CLR);
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ;
endmodule
-module FDPE (output Q, input C, CE, D, PRE);
+module FDPE (output Q, (* techmap_autopurge *) input C, CE, D, PRE);
parameter [0:0] INIT = 1'b1;
parameter [0:0] IS_C_INVERTED = 1'b0;
parameter [0:0] IS_D_INVERTED = 1'b0;
@@ -335,7 +335,7 @@ module FDPE (output Q, input C, CE, D, PRE);
wire [0:0] abc9_ff.init = 1'b0;
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ;
endmodule
-module FDPE_1 (output Q, input C, CE, D, PRE);
+module FDPE_1 (output Q, (* techmap_autopurge *) input C, CE, D, PRE);
parameter [0:0] INIT = 1'b1;
wire QQ, $Q, $QQ;
generate if (INIT == 1'b1) begin
diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc
index 63d00027a..77be8299c 100644
--- a/techlibs/xilinx/synth_xilinx.cc
+++ b/techlibs/xilinx/synth_xilinx.cc
@@ -26,13 +26,16 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-#define XC7_WIRE_DELAY 300 // Number with which ABC will map a 6-input gate
- // to one LUT6 (instead of a LUT5 + LUT2)
-
struct SynthXilinxPass : public ScriptPass
{
SynthXilinxPass() : ScriptPass("synth_xilinx", "synthesis for Xilinx FPGAs") { }
+ void on_register() YS_OVERRIDE
+ {
+ RTLIL::constpad["synth_xilinx.abc9.xc7.W"] = "300"; // Number with which ABC will map a 6-input gate
+ // to one LUT6 (instead of a LUT5 + LUT2)
+ }
+
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
@@ -515,7 +518,7 @@ struct SynthXilinxPass : public ScriptPass
techmap_args += " -map +/xilinx/arith_map.v";
if (vpr)
techmap_args += " -D _EXPLICIT_CARRY";
- else if (abc9)
+ else
techmap_args += " -D _CLB_CARRY";
}
run("techmap " + techmap_args);
@@ -555,7 +558,11 @@ struct SynthXilinxPass : public ScriptPass
run("techmap " + techmap_args);
run("read_verilog -icells -lib +/xilinx/abc9_model.v");
std::string abc9_opts = " -box +/xilinx/abc9_xc7.box";
- abc9_opts += stringf(" -W %d", XC7_WIRE_DELAY);
+ auto k = stringf("synth_xilinx.abc9.%s.W", family.c_str());
+ if (active_design->scratchpad.count(k))
+ abc9_opts += stringf(" -W %s", active_design->scratchpad_get_string(k).c_str());
+ else
+ abc9_opts += stringf(" -W %s", RTLIL::constpad.at(k).c_str());
if (nowidelut)
abc9_opts += " -lut +/xilinx/abc9_xc7_nowide.lut";
else
diff --git a/tests/arch/ecp5/bug1630.il.gz b/tests/arch/ecp5/bug1630.il.gz
new file mode 100644
index 000000000..37bcf2be2
--- /dev/null
+++ b/tests/arch/ecp5/bug1630.il.gz
Binary files differ
diff --git a/tests/arch/ecp5/bug1630.ys b/tests/arch/ecp5/bug1630.ys
new file mode 100644
index 000000000..b419fb9bb
--- /dev/null
+++ b/tests/arch/ecp5/bug1630.ys
@@ -0,0 +1,2 @@
+read_ilang bug1630.il.gz
+abc9 -lut +/ecp5/abc9_5g.lut
diff --git a/tests/arch/ice40/bug1626.ys b/tests/arch/ice40/bug1626.ys
new file mode 100644
index 000000000..27b6fb5e8
--- /dev/null
+++ b/tests/arch/ice40/bug1626.ys
@@ -0,0 +1,217 @@
+read_ilang <<EOT
+# Generated by Yosys 0.9+1706 (git sha1 58ab9f60, clang 6.0.0-1ubuntu2 -fPIC -Os)
+autoidx 2815
+attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:9"
+attribute \cells_not_processed 1
+attribute \dynports 1
+module \ahb_async_sram_halfwidth
+ parameter \DEPTH
+ parameter \W_ADDR
+ parameter \W_BYTEADDR
+ parameter \W_DATA
+ parameter \W_SRAM_ADDR
+ parameter \W_SRAM_DATA
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:71"
+ wire $0\addr_lsb[0:0]
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:71"
+ wire $0\hready_r[0:0]
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:71"
+ wire $0\long_dphase[0:0]
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:71"
+ wire width 16 $0\rdata_buf[15:0]
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:71"
+ wire $0\read_dph[0:0]
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:71"
+ wire $0\write_dph[0:0]
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:63"
+ wire width 32 $add$../hdl/mem/ahb_async_sram_halfwidth.v:63$2433_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:62"
+ wire width 16 $and$../hdl/mem/ahb_async_sram_halfwidth.v:62$2431_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:56"
+ wire $eq$../hdl/mem/ahb_async_sram_halfwidth.v:56$2424_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:112"
+ wire $logic_and$../hdl/mem/ahb_async_sram_halfwidth.v:112$2450_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:112"
+ wire $logic_and$../hdl/mem/ahb_async_sram_halfwidth.v:112$2451_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:112"
+ wire $logic_and$../hdl/mem/ahb_async_sram_halfwidth.v:112$2452_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:112"
+ wire $logic_and$../hdl/mem/ahb_async_sram_halfwidth.v:112$2453_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:112"
+ wire $logic_and$../hdl/mem/ahb_async_sram_halfwidth.v:112$2454_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:112"
+ wire $logic_and$../hdl/mem/ahb_async_sram_halfwidth.v:112$2455_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:112"
+ wire $logic_and$../hdl/mem/ahb_async_sram_halfwidth.v:112$2456_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:112"
+ wire $logic_and$../hdl/mem/ahb_async_sram_halfwidth.v:112$2457_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:112"
+ wire $logic_and$../hdl/mem/ahb_async_sram_halfwidth.v:112$2458_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:112"
+ wire $logic_and$../hdl/mem/ahb_async_sram_halfwidth.v:112$2459_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:118"
+ wire $logic_and$../hdl/mem/ahb_async_sram_halfwidth.v:118$2444_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:133"
+ wire $logic_and$../hdl/mem/ahb_async_sram_halfwidth.v:133$2449_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:140"
+ wire $logic_and$../hdl/mem/ahb_async_sram_halfwidth.v:140$2461_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:140"
+ wire $logic_and$../hdl/mem/ahb_async_sram_halfwidth.v:140$2463_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:58"
+ wire $logic_and$../hdl/mem/ahb_async_sram_halfwidth.v:58$2425_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:59"
+ wire $logic_and$../hdl/mem/ahb_async_sram_halfwidth.v:59$2426_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:59"
+ wire $logic_and$../hdl/mem/ahb_async_sram_halfwidth.v:59$2427_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:59"
+ wire $logic_and$../hdl/mem/ahb_async_sram_halfwidth.v:59$2429_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:91"
+ wire $logic_and$../hdl/mem/ahb_async_sram_halfwidth.v:91$2441_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:104"
+ wire $logic_not$../hdl/mem/ahb_async_sram_halfwidth.v:104$2442_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:118"
+ wire $logic_not$../hdl/mem/ahb_async_sram_halfwidth.v:118$2443_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:125"
+ wire $logic_not$../hdl/mem/ahb_async_sram_halfwidth.v:125$2446_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:132"
+ wire $logic_not$../hdl/mem/ahb_async_sram_halfwidth.v:132$2447_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:59"
+ wire $logic_not$../hdl/mem/ahb_async_sram_halfwidth.v:59$2428_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:72"
+ wire $logic_not$../hdl/mem/ahb_async_sram_halfwidth.v:72$2437_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:81"
+ wire $logic_not$../hdl/mem/ahb_async_sram_halfwidth.v:81$2438_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:83"
+ wire $logic_not$../hdl/mem/ahb_async_sram_halfwidth.v:83$2439_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:91"
+ wire $logic_not$../hdl/mem/ahb_async_sram_halfwidth.v:91$2440_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:118"
+ wire $logic_or$../hdl/mem/ahb_async_sram_halfwidth.v:118$2445_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:132"
+ wire $logic_or$../hdl/mem/ahb_async_sram_halfwidth.v:132$2448_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:59"
+ wire $logic_or$../hdl/mem/ahb_async_sram_halfwidth.v:59$2430_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:139"
+ wire width 2 $not$../hdl/mem/ahb_async_sram_halfwidth.v:139$2460_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:139"
+ wire width 2 $not$../hdl/mem/ahb_async_sram_halfwidth.v:139$2462_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:54"
+ wire width 2 $not$../hdl/mem/ahb_async_sram_halfwidth.v:54$2421_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:63"
+ wire width 16 $shiftx$../hdl/mem/ahb_async_sram_halfwidth.v:63$2434_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:54"
+ wire width 8 $shl$../hdl/mem/ahb_async_sram_halfwidth.v:54$2419_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:54"
+ wire width 2 $shl$../hdl/mem/ahb_async_sram_halfwidth.v:54$2420_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:55"
+ wire width 2 $shl$../hdl/mem/ahb_async_sram_halfwidth.v:55$2422_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:56"
+ wire width 32 $shl$../hdl/mem/ahb_async_sram_halfwidth.v:56$2423_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:63"
+ wire width 32 $ternary$../hdl/mem/ahb_async_sram_halfwidth.v:63$2432_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:65"
+ wire width 16 $ternary$../hdl/mem/ahb_async_sram_halfwidth.v:65$2435_Y
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:50"
+ wire \addr_lsb
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:24"
+ wire width 32 \ahbls_haddr
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:28"
+ wire width 3 \ahbls_hburst
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:30"
+ wire \ahbls_hmastlock
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:29"
+ wire width 4 \ahbls_hprot
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:32"
+ wire width 32 \ahbls_hrdata
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:22"
+ wire \ahbls_hready
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:21"
+ wire \ahbls_hready_resp
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:23"
+ wire \ahbls_hresp
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:27"
+ wire width 3 \ahbls_hsize
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:26"
+ wire width 2 \ahbls_htrans
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:31"
+ wire width 32 \ahbls_hwdata
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:25"
+ wire \ahbls_hwrite
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:56"
+ wire \aphase_full_width
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:55"
+ wire width 2 \bytemask
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:54"
+ wire width 2 \bytemask_noshift
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:17"
+ wire \clk
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:46"
+ wire \hready_r
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:47"
+ wire \long_dphase
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:64"
+ wire width 16 \rdata_buf
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:49"
+ wire \read_dph
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:18"
+ wire \rst_n
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:34"
+ wire width 11 \sram_addr
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:39"
+ wire width 2 \sram_byte_n
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:36"
+ wire \sram_ce_n
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:35"
+ wire width 16 \sram_dq
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:38"
+ wire \sram_oe_n
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:61"
+ wire width 16 \sram_q
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:62"
+ wire width 16 \sram_rdata
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:63"
+ wire width 16 \sram_wdata
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:37"
+ wire \sram_we_n
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:58"
+ wire \we_next
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:48"
+ wire \write_dph
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:71"
+ process $proc$../hdl/mem/ahb_async_sram_halfwidth.v:71$2436
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:72"
+ switch $logic_not$../hdl/mem/ahb_async_sram_halfwidth.v:72$2437_Y
+ case 1'1
+ case
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:78"
+ switch \ahbls_hready
+ case 1'1
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:79"
+ switch \ahbls_htrans [1]
+ case 1'1
+ case
+ end
+ case
+ attribute \src "../hdl/mem/ahb_async_sram_halfwidth.v:91"
+ switch $logic_and$../hdl/mem/ahb_async_sram_halfwidth.v:91$2441_Y
+ case 1'1
+ case
+ end
+ end
+ end
+ sync posedge \clk
+ sync negedge \rst_n
+ end
+ connect \ahbls_hresp 1'0
+ connect \bytemask_noshift $not$../hdl/mem/ahb_async_sram_halfwidth.v:54$2421_Y
+ connect \bytemask $shl$../hdl/mem/ahb_async_sram_halfwidth.v:55$2422_Y
+ connect \aphase_full_width $eq$../hdl/mem/ahb_async_sram_halfwidth.v:56$2424_Y
+ connect \we_next $logic_or$../hdl/mem/ahb_async_sram_halfwidth.v:59$2430_Y
+ connect \sram_rdata $and$../hdl/mem/ahb_async_sram_halfwidth.v:62$2431_Y
+ connect \sram_wdata $shiftx$../hdl/mem/ahb_async_sram_halfwidth.v:63$2434_Y
+ connect \ahbls_hrdata { \sram_rdata $ternary$../hdl/mem/ahb_async_sram_halfwidth.v:65$2435_Y }
+ connect \ahbls_hready_resp \hready_r
+end
+EOT
+
+synth_ice40 -abc2 -abc9
diff --git a/tests/arch/xilinx/add_sub.ys b/tests/arch/xilinx/add_sub.ys
index 313948cc5..70cfe81a3 100644
--- a/tests/arch/xilinx/add_sub.ys
+++ b/tests/arch/xilinx/add_sub.ys
@@ -4,8 +4,8 @@ proc
equiv_opt -assert -map +/xilinx/cells_sim.v synth_xilinx -noiopad # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd top # Constrain all select calls below inside the top module
-select -assert-count 14 t:LUT2
-select -assert-count 6 t:MUXCY
-select -assert-count 8 t:XORCY
-select -assert-none t:LUT2 t:MUXCY t:XORCY %% t:* %D
+stat
+select -assert-count 16 t:LUT2
+select -assert-count 2 t:CARRY4
+select -assert-none t:LUT2 t:CARRY4 %% t:* %D
diff --git a/tests/arch/xilinx/counter.ys b/tests/arch/xilinx/counter.ys
index 11c29922e..064519ce7 100644
--- a/tests/arch/xilinx/counter.ys
+++ b/tests/arch/xilinx/counter.ys
@@ -5,10 +5,9 @@ flatten
equiv_opt -async2sync -assert -map +/xilinx/cells_sim.v synth_xilinx -noiopad # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd top # Constrain all select calls below inside the top module
-
+stat
select -assert-count 1 t:BUFG
select -assert-count 8 t:FDCE
select -assert-count 1 t:INV
-select -assert-count 7 t:MUXCY
-select -assert-count 8 t:XORCY
-select -assert-none t:BUFG t:FDCE t:INV t:MUXCY t:XORCY %% t:* %D
+select -assert-count 2 t:CARRY4
+select -assert-none t:BUFG t:FDCE t:INV t:CARRY4 %% t:* %D
diff --git a/tests/arch/xilinx/fsm.ys b/tests/arch/xilinx/fsm.ys
index 3235d5af3..a464fcfdb 100644
--- a/tests/arch/xilinx/fsm.ys
+++ b/tests/arch/xilinx/fsm.ys
@@ -9,7 +9,7 @@ sat -verify -prove-asserts -show-public -set-at 1 in_reset 1 -seq 20 -prove-skip
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd fsm # Constrain all select calls below inside the top module
-
+stat
select -assert-count 1 t:BUFG
select -assert-count 4 t:FDRE
select -assert-count 1 t:FDSE
diff --git a/tests/techmap/abc9.ys b/tests/techmap/abc9.ys
new file mode 100644
index 000000000..d5a63e1cb
--- /dev/null
+++ b/tests/techmap/abc9.ys
@@ -0,0 +1,68 @@
+read_verilog <<EOT
+`define N 256
+module top(input [`N-1:0] a, output o);
+wire [`N-2:0] w;
+assign w[0] = a[0] & a[1];
+genvar i;
+generate for (i = 1; i < `N-1; i++)
+assign w[i] = w[i-1] & a[i+1];
+endgenerate
+assign o = w[`N-2];
+endmodule
+EOT
+simplemap
+dump
+design -save gold
+
+abc9 -lut 4
+
+design -load gold
+abc9 -lut 4 -fast
+
+design -load gold
+scratchpad -copy abc9.script.default.area abc9.script
+abc9 -lut 4
+
+design -load gold
+scratchpad -copy abc9.script.default.fast abc9.script
+abc9 -lut 4
+
+design -load gold
+scratchpad -copy abc9.script.flow abc9.script
+abc9 -lut 4
+
+design -load gold
+scratchpad -copy abc9.script.flow2 abc9.script
+abc9 -lut 4
+
+design -load gold
+scratchpad -copy abc9.script.flow3 abc9.script
+abc9 -lut 4
+
+design -reset
+read_verilog <<EOT
+module top(input a, b, output o);
+(* keep *) wire w = a & b;
+assign o = ~w;
+endmodule
+EOT
+
+simplemap
+equiv_opt -assert abc9 -lut 4
+design -load postopt
+select -assert-count 2 t:$lut
+
+design -reset
+read_verilog -icells <<EOT
+module top(input a, b, output o);
+wire w;
+(* keep *) $_AND_ gate (.Y(w), .A(a), .B(b));
+assign o = ~w;
+endmodule
+EOT
+
+simplemap
+equiv_opt -assert abc9 -lut 4
+design -load postopt
+select -assert-count 1 t:$lut
+select -assert-count 1 t:$_AND_
diff --git a/tests/various/autoname.ys b/tests/various/autoname.ys
new file mode 100644
index 000000000..830962e81
--- /dev/null
+++ b/tests/various/autoname.ys
@@ -0,0 +1,19 @@
+read_ilang <<EOT
+autoidx 2
+module \top
+ wire output 3 $y
+ wire input 1 \a
+ wire input 2 \b
+ cell $and \b_$and_B
+ parameter \A_SIGNED 0
+ parameter \A_WIDTH 1
+ parameter \B_SIGNED 0
+ parameter \B_WIDTH 1
+ parameter \Y_WIDTH 1
+ connect \A \a
+ connect \B \b
+ connect \Y $y
+ end
+end
+EOT
+autoname