aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--backends/aiger/xaiger.cc156
-rw-r--r--kernel/register.cc15
-rw-r--r--kernel/register.h3
-rw-r--r--kernel/rtlil.cc1
-rw-r--r--kernel/rtlil.h2
-rw-r--r--kernel/yosys.cc3
-rw-r--r--passes/cmds/scratchpad.cc25
-rw-r--r--passes/techmap/abc9.cc120
-rw-r--r--techlibs/ecp5/synth_ecp5.cc4
-rw-r--r--techlibs/ice40/synth_ice40.cc20
-rw-r--r--techlibs/xilinx/synth_xilinx.cc16
-rw-r--r--tests/arch/ecp5/bug1459.ys25
-rw-r--r--tests/arch/ice40/bug1626.ys217
-rw-r--r--tests/techmap/abc9.ys40
15 files changed, 512 insertions, 137 deletions
diff --git a/Makefile b/Makefile
index 374d42f6f..43c4d0890 100644
--- a/Makefile
+++ b/Makefile
@@ -128,7 +128,7 @@ bumpversion:
# is just a symlink to your actual ABC working directory, as 'make mrproper'
# will remove the 'abc' directory and you do not want to accidentally
# delete your work on ABC..
-ABCREV = 144c5be
+ABCREV = 71f2b40
ABCPULL = 1
ABCURL ?= https://github.com/berkeley-abc/abc
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1
diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc
index 05e9678ee..a6c87159d 100644
--- a/backends/aiger/xaiger.cc
+++ b/backends/aiger/xaiger.cc
@@ -407,7 +407,7 @@ struct XAigerWriter
}
if (w->port_output) {
RTLIL::SigSpec rhs;
- auto it = cell->connections_.find(w->name);
+ auto it = cell->connections_.find(port_name);
if (it != cell->connections_.end()) {
if (GetSize(it->second) < GetSize(w))
it->second.append(module->addWire(NEW_ID, GetSize(w)-GetSize(it->second)));
@@ -474,7 +474,8 @@ struct XAigerWriter
if (holes_mode) {
struct sort_by_port_id {
bool operator()(const RTLIL::SigBit& a, const RTLIL::SigBit& b) const {
- return a.wire->port_id < b.wire->port_id;
+ return a.wire->port_id < b.wire->port_id ||
+ (a.wire->port_id == b.wire->port_id && a.offset < b.offset);
}
};
input_bits.sort(sort_by_port_id());
@@ -614,7 +615,7 @@ struct XAigerWriter
RTLIL::Module *holes_module = module->design->addModule("$__holes__");
log_assert(holes_module);
- dict<IdString, Cell*> cell_cache;
+ dict<IdString, std::tuple<Cell*,int,int,int>> cell_cache;
int port_id = 1;
int box_count = 0;
@@ -623,81 +624,94 @@ struct XAigerWriter
log_assert(orig_box_module);
IdString derived_name = orig_box_module->derive(module->design, cell->parameters);
RTLIL::Module* box_module = module->design->module(derived_name);
- if (box_module->has_processes())
- Pass::call_on_module(module->design, box_module, "proc");
-
- auto r = cell_cache.insert(std::make_pair(derived_name, nullptr));
- Cell *holes_cell = r.first->second;
- if (r.second && box_module->get_bool_attribute("\\whitebox")) {
- holes_cell = holes_module->addCell(cell->name, cell->type);
- holes_cell->parameters = cell->parameters;
- r.first->second = holes_cell;
- }
- int box_inputs = 0, box_outputs = 0;
- for (auto port_name : box_ports.at(cell->type)) {
- RTLIL::Wire *w = box_module->wire(port_name);
- log_assert(w);
- RTLIL::Wire *holes_wire;
- RTLIL::SigSpec port_sig;
+ auto r = cell_cache.insert(derived_name);
+ auto &v = r.first->second;
+ if (r.second) {
+ if (box_module->has_processes())
+ Pass::call_on_module(module->design, box_module, "proc");
+
+ int box_inputs = 0, box_outputs = 0;
+ if (box_module->get_bool_attribute("\\whitebox")) {
+ auto holes_cell = holes_module->addCell(cell->name, derived_name);
+ for (auto port_name : box_ports.at(cell->type)) {
+ RTLIL::Wire *w = box_module->wire(port_name);
+ log_assert(w);
+ log_assert(!w->port_input || !w->port_output);
+ auto &conn = holes_cell->connections_[port_name];
+ if (w->port_input) {
+ for (int i = 0; i < GetSize(w); i++) {
+ box_inputs++;
+ RTLIL::Wire *holes_wire = holes_module->wire(stringf("\\i%d", box_inputs));
+ if (!holes_wire) {
+ holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs));
+ holes_wire->port_input = true;
+ holes_wire->port_id = port_id++;
+ holes_module->ports.push_back(holes_wire->name);
+ }
+ conn.append(holes_wire);
+ }
+ }
+ else if (w->port_output) {
+ box_outputs += GetSize(w);
+ conn = holes_module->addWire(stringf("%s.%s", derived_name.c_str(), log_id(port_name)), GetSize(w));
+ }
+ }
- if (w->port_input)
- for (int i = 0; i < GetSize(w); i++) {
+ // For flops only, create an extra 1-bit input that drives a new wire
+ // called "<cell>.abc9_ff.Q" that is used below
+ if (box_module->get_bool_attribute("\\abc9_flop")) {
box_inputs++;
- holes_wire = holes_module->wire(stringf("\\i%d", box_inputs));
+ Wire *holes_wire = holes_module->wire(stringf("\\i%d", box_inputs));
if (!holes_wire) {
holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs));
holes_wire->port_input = true;
holes_wire->port_id = port_id++;
holes_module->ports.push_back(holes_wire->name);
}
- if (holes_cell)
- port_sig.append(holes_wire);
- }
- if (w->port_output) {
- box_outputs += GetSize(w);
- for (int i = 0; i < GetSize(w); i++) {
- if (GetSize(w) == 1)
- holes_wire = holes_module->addWire(stringf("$abc%s.%s", cell->name.c_str(), log_id(w->name)));
- else
- holes_wire = holes_module->addWire(stringf("$abc%s.%s[%d]", cell->name.c_str(), log_id(w->name), i));
- holes_wire->port_output = true;
- holes_wire->port_id = port_id++;
- holes_module->ports.push_back(holes_wire->name);
- if (holes_cell)
- port_sig.append(holes_wire);
- else
- holes_module->connect(holes_wire, State::S0);
+ Wire *Q = holes_module->addWire(stringf("%s.abc9_ff.Q", cell->name.c_str()));
+ holes_module->connect(Q, holes_wire);
}
+
+ std::get<0>(v) = holes_cell;
}
- if (!port_sig.empty()) {
- if (r.second)
- holes_cell->setPort(w->name, port_sig);
- else
- holes_module->connect(holes_cell->getPort(w->name), port_sig);
+ else {
+ for (auto port_name : box_ports.at(cell->type)) {
+ RTLIL::Wire *w = box_module->wire(port_name);
+ log_assert(w);
+ log_assert(!w->port_input || !w->port_output);
+ if (w->port_input)
+ box_inputs += GetSize(w);
+ else if (w->port_output)
+ box_outputs += GetSize(w);
+ }
+ log_assert(std::get<0>(v) == nullptr);
}
+
+ std::get<1>(v) = box_inputs;
+ std::get<2>(v) = box_outputs;
+ std::get<3>(v) = box_module->attributes.at("\\abc9_box_id").as_int();
}
- // For flops only, create an extra 1-bit input that drives a new wire
- // called "<cell>.abc9_ff.Q" that is used below
- if (box_module->get_bool_attribute("\\abc9_flop")) {
- log_assert(holes_cell);
-
- box_inputs++;
- Wire *holes_wire = holes_module->wire(stringf("\\i%d", box_inputs));
- if (!holes_wire) {
- holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs));
- holes_wire->port_input = true;
- holes_wire->port_id = port_id++;
- holes_module->ports.push_back(holes_wire->name);
- }
- Wire *w = holes_module->addWire(stringf("%s.abc9_ff.Q", cell->name.c_str()));
- holes_module->connect(w, holes_wire);
+ auto holes_cell = std::get<0>(v);
+ for (auto port_name : box_ports.at(cell->type)) {
+ RTLIL::Wire *w = box_module->wire(port_name);
+ log_assert(w);
+ if (!w->port_output)
+ continue;
+ Wire *holes_wire = holes_module->addWire(stringf("$abc%s.%s", cell->name.c_str(), log_id(port_name)), GetSize(w));
+ holes_wire->port_output = true;
+ holes_wire->port_id = port_id++;
+ holes_module->ports.push_back(holes_wire->name);
+ if (holes_cell) // whitebox
+ holes_module->connect(holes_wire, holes_cell->getPort(port_name));
+ else // blackbox
+ holes_module->connect(holes_wire, Const(State::S0, GetSize(w)));
}
- write_h_buffer(box_inputs);
- write_h_buffer(box_outputs);
- write_h_buffer(box_module->attributes.at("\\abc9_box_id").as_int());
+ write_h_buffer(std::get<1>(v));
+ write_h_buffer(std::get<2>(v));
+ write_h_buffer(std::get<3>(v));
write_h_buffer(box_count++);
}
@@ -757,14 +771,16 @@ struct XAigerWriter
// created a new $paramod ...
Pass::call_on_module(holes_module->design, holes_module, "flatten -wb; techmap; aigmap");
- dict<SigSig, SigSig> replace;
+ SigMap holes_sigmap(holes_module);
+
+ dict<SigSpec, SigSpec> 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
+ // 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)
@@ -772,10 +788,10 @@ struct XAigerWriter
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
+ // Prepare to replace "assign <port> = $_DFF_*.Q;" with "assign <port> = $_DFF_*.D;"
+ // in order to extract just 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)));
+ replace.insert(std::make_pair(Q,D));
// Since `flatten` above would have created wires named "<cell>.Q",
// extract the pre-techmap cell name
auto pos = Q.wire->name.str().rfind(".");
@@ -783,7 +799,7 @@ struct XAigerWriter
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_ff.Q"
- // wire (which itself is driven an input port) we inserted above
+ // wire (which itself is driven by an input port) we inserted above
Wire *currQ = holes_module->wire(stringf("%s.abc9_ff.Q", driver.c_str()));
log_assert(currQ);
holes_module->connect(Q, currQ);
@@ -795,9 +811,9 @@ struct XAigerWriter
}
for (auto &conn : holes_module->connections_) {
- auto it = replace.find(conn);
+ auto it = replace.find(sigmap(conn.second));
if (it != replace.end())
- conn = it->second;
+ conn.second = it->second;
}
// Move into a new (temporary) design so that "clean" will only
diff --git a/kernel/register.cc b/kernel/register.cc
index 37f2e5e1b..5d0fb3c8c 100644
--- a/kernel/register.cc
+++ b/kernel/register.cc
@@ -114,20 +114,35 @@ void Pass::run_register()
void Pass::init_register()
{
+ vector<Pass*> added_passes;
while (first_queued_pass) {
+ added_passes.push_back(first_queued_pass);
first_queued_pass->run_register();
first_queued_pass = first_queued_pass->next_queued_pass;
}
+ for (auto added_pass : added_passes)
+ added_pass->on_register();
}
void Pass::done_register()
{
+ for (auto &it : pass_register)
+ it.second->on_shutdown();
+
frontend_register.clear();
pass_register.clear();
backend_register.clear();
log_assert(first_queued_pass == NULL);
}
+void Pass::on_register()
+{
+}
+
+void Pass::on_shutdown()
+{
+}
+
Pass::~Pass()
{
}
diff --git a/kernel/register.h b/kernel/register.h
index 85d552f0d..821faff3e 100644
--- a/kernel/register.h
+++ b/kernel/register.h
@@ -62,6 +62,9 @@ struct Pass
virtual void run_register();
static void init_register();
static void done_register();
+
+ virtual void on_register();
+ virtual void on_shutdown();
};
struct ScriptPass : Pass
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/kernel/yosys.cc b/kernel/yosys.cc
index 5018a4888..8190d8902 100644
--- a/kernel/yosys.cc
+++ b/kernel/yosys.cc
@@ -544,6 +544,8 @@ void yosys_shutdown()
already_shutdown = true;
log_pop();
+ Pass::done_register();
+
delete yosys_design;
yosys_design = NULL;
@@ -553,7 +555,6 @@ void yosys_shutdown()
log_errfile = NULL;
log_files.clear();
- Pass::done_register();
yosys_celltypes.clear();
#ifdef YOSYS_ENABLE_TCL
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 8cb34e523..8a6195741 100644
--- a/passes/techmap/abc9.cc
+++ b/passes/techmap/abc9.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/sigtools.h"
#include "kernel/celltypes.h"
@@ -250,7 +236,7 @@ struct abc9_output_filter
void abc9_module(RTLIL::Design *design, RTLIL::Module *module, std::string script_file, std::string exe_file,
bool cleanup, 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 wire_delay
)
{
map_autoidx = autoidx++;
@@ -292,7 +278,8 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *module, std::string scrip
} 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();
@@ -305,11 +292,26 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *module, std::string scrip
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++)
@@ -416,13 +418,11 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *module, std::string scrip
dict<IdString, bool> abc9_box;
vector<RTLIL::Cell*> boxes;
- for (auto it = module->cells_.begin(); it != module->cells_.end(); ) {
- auto cell = it->second;
+ for (auto cell : module->cells().to_vector()) {
if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_))) {
- it = module->cells_.erase(it);
+ module->remove(cell);
continue;
}
- ++it;
RTLIL::Module* box_module = design->module(cell->type);
auto jt = abc9_box.find(cell->type);
if (jt == abc9_box.end())
@@ -731,6 +731,51 @@ clone_lut:
struct Abc9Pass : public Pass {
Abc9Pass() : Pass("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---|
@@ -758,18 +803,15 @@ struct Abc9Pass : public Pass {
log("\n");
log(" if no -script parameter is given, the following scripts are used:\n");
log("\n");
- log(" for -lut/-luts (only one LUT size):\n");
- log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT).c_str());
- log("\n");
- log(" for -lut/-luts (different LUT sizes):\n");
- log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT).c_str());
+ log(" for -lut/-luts:\n");
+ 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("\n");
log(" for -lut/-luts:\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");
@@ -835,7 +877,6 @@ struct Abc9Pass : public Pass {
std::string delay_target, lutin_shared = "-S 1", wire_delay;
bool fast_mode = false, dff_mode = false, cleanup = true;
bool show_tempdir = false;
- bool nomfs = false;
vector<int> lut_costs;
#if 0
@@ -867,7 +908,11 @@ struct Abc9Pass : public Pass {
if (design->scratchpad.count("abc9.W")) {
wire_delay = "-W " + design->scratchpad_get_string("abc9.W");
}
- nomfs = design->scratchpad_get_bool("abc9.nomfs", nomfs);
+
+ if (design->scratchpad_get_bool("abc9.debug")) {
+ cleanup = false;
+ show_tempdir = true;
+ }
size_t argidx;
char pwd [PATH_MAX];
@@ -883,9 +928,6 @@ struct Abc9Pass : public Pass {
}
if (arg == "-script" && argidx+1 < args.size()) {
script_file = args[++argidx];
- rewrite_filename(script_file);
- if (!script_file.empty() && !is_absolute_path(script_file) && script_file[0] != '+')
- script_file = std::string(pwd) + "/" + script_file;
continue;
}
if (arg == "-D" && argidx+1 < args.size()) {
@@ -928,10 +970,6 @@ struct Abc9Pass : public Pass {
wire_delay = "-W " + args[++argidx];
continue;
}
- if (arg == "-nomfs") {
- nomfs = true;
- continue;
- }
break;
}
extra_args(args, argidx, design);
@@ -1045,7 +1083,7 @@ struct Abc9Pass : public Pass {
design->selected_active_module = module->name.str();
abc9_module(design, module, script_file, exe_file, cleanup, lut_costs, dff_mode,
delay_target, lutin_shared, fast_mode, show_tempdir,
- box_file, lut_file, wire_delay, nomfs);
+ box_file, lut_file, wire_delay);
design->selected_active_module.clear();
}
diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc
index d616391b2..6583f43fd 100644
--- a/techlibs/ecp5/synth_ecp5.cc
+++ b/techlibs/ecp5/synth_ecp5.cc
@@ -323,9 +323,9 @@ struct SynthEcp5Pass : public ScriptPass
if (abc9) {
run("read_verilog -icells -lib +/ecp5/abc9_model.v");
if (nowidelut)
- run("abc9 -lut +/ecp5/abc9_5g_nowide.lut -box +/ecp5/abc9_5g.box -W 200 -nomfs");
+ run("abc9 -lut +/ecp5/abc9_5g_nowide.lut -box +/ecp5/abc9_5g.box -W 200");
else
- run("abc9 -lut +/ecp5/abc9_5g.lut -box +/ecp5/abc9_5g.box -W 200 -nomfs");
+ run("abc9 -lut +/ecp5/abc9_5g.lut -box +/ecp5/abc9_5g.box -W 200");
run("techmap -map +/ecp5/abc9_unmap.v");
} else {
if (nowidelut)
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/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc
index 7ff09a437..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---|
@@ -555,8 +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);
- abc9_opts += " -nomfs";
+ 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/bug1459.ys b/tests/arch/ecp5/bug1459.ys
new file mode 100644
index 000000000..1142ae0b5
--- /dev/null
+++ b/tests/arch/ecp5/bug1459.ys
@@ -0,0 +1,25 @@
+read_verilog <<EOT
+module register_file(
+ input wire clk,
+ input wire write_enable,
+ input wire [63:0] write_data,
+ input wire [4:0] write_reg,
+ input wire [4:0] read1_reg,
+ output reg [63:0] read1_data,
+ );
+
+ reg [63:0] registers[0:31];
+
+ always @(posedge clk) begin
+ if (write_enable == 1'b1) begin
+ registers[write_reg] <= write_data;
+ end
+ end
+
+ always @(all) begin
+ read1_data <= registers[read1_reg];
+ end
+endmodule
+EOT
+
+synth_ecp5 -abc9
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/techmap/abc9.ys b/tests/techmap/abc9.ys
new file mode 100644
index 000000000..20f263da8
--- /dev/null
+++ b/tests/techmap/abc9.ys
@@ -0,0 +1,40 @@
+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