aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG1
-rw-r--r--backends/btor/btor.cc30
-rw-r--r--backends/smt2/smtio.py5
-rw-r--r--frontends/aiger/aigerparse.cc3
-rw-r--r--frontends/verilog/const2ast.cc2
-rw-r--r--kernel/rtlil.cc13
-rw-r--r--kernel/rtlil.h1
-rw-r--r--passes/opt/opt_clean.cc6
-rw-r--r--passes/techmap/abc9.cc13
-rw-r--r--passes/techmap/muxcover.cc52
-rw-r--r--techlibs/ecp5/cells_map.v40
-rw-r--r--techlibs/ecp5/cells_sim.v94
-rw-r--r--techlibs/xilinx/Makefile.inc1
-rw-r--r--techlibs/xilinx/abc_xc7.box19
-rw-r--r--techlibs/xilinx/cells_map.v162
-rw-r--r--techlibs/xilinx/cells_sim.v18
-rw-r--r--techlibs/xilinx/mux_map.v71
-rw-r--r--techlibs/xilinx/synth_xilinx.cc92
-rw-r--r--tests/various/muxcover.ys320
19 files changed, 817 insertions, 126 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 73115600c..82576e842 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -28,6 +28,7 @@ Yosys 0.8 .. Yosys 0.8-dev
- Added "synth_ice40 -abc9" (experimental)
- Added "synth -abc9" (experimental)
- "synth_xilinx" to now infer hard shift registers (-nosrl to disable)
+ - "synth_xilinx" to now infer wide multiplexers (-nomux to disable)
- Fixed sign extension of unsized constants with 'bx and 'bz MSB
diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc
index 511a11942..a507b120b 100644
--- a/backends/btor/btor.cc
+++ b/backends/btor/btor.cc
@@ -17,6 +17,11 @@
*
*/
+// [[CITE]] Btor2 , BtorMC and Boolector 3.0
+// Aina Niemetz, Mathias Preiner, Clifford Wolf, Armin Biere
+// Computer Aided Verification - 30th International Conference, CAV 2018
+// https://cs.stanford.edu/people/niemetz/publication/2018/niemetzpreinerwolfbiere-cav18/
+
#include "kernel/rtlil.h"
#include "kernel/register.h"
#include "kernel/sigtools.h"
@@ -875,9 +880,28 @@ struct BtorWorker
else
{
if (bit_cell.count(bit) == 0)
- log_error("No driver for signal bit %s.\n", log_signal(bit));
- export_cell(bit_cell.at(bit));
- log_assert(bit_nid.count(bit));
+ {
+ SigSpec s = bit;
+
+ while (i+GetSize(s) < GetSize(sig) && sig[i+GetSize(s)].wire != nullptr &&
+ bit_cell.count(sig[i+GetSize(s)]) == 0)
+ s.append(sig[i+GetSize(s)]);
+
+ log_warning("No driver for signal %s.\n", log_signal(s));
+
+ int sid = get_bv_sid(GetSize(s));
+ int nid = next_nid++;
+ btorf("%d input %d %s\n", nid, sid);
+ nid_width[nid] = GetSize(s);
+
+ i += GetSize(s)-1;
+ continue;
+ }
+ else
+ {
+ export_cell(bit_cell.at(bit));
+ log_assert(bit_nid.count(bit));
+ }
}
}
diff --git a/backends/smt2/smtio.py b/backends/smt2/smtio.py
index cea0fc56c..ae7968a1b 100644
--- a/backends/smt2/smtio.py
+++ b/backends/smt2/smtio.py
@@ -1043,7 +1043,10 @@ class MkVcd:
scope = scope[:-1]
while uipath[:-1] != scope:
- print("$scope module %s $end" % uipath[len(scope)], file=self.f)
+ scopename = uipath[len(scope)]
+ if scopename.startswith("$"):
+ scopename = "\\" + scopename
+ print("$scope module %s $end" % scopename, file=self.f)
scope.append(uipath[len(scope)])
if path in self.clocks and self.clocks[path][1] == "event":
diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc
index efd265464..43337f4c2 100644
--- a/frontends/aiger/aigerparse.cc
+++ b/frontends/aiger/aigerparse.cc
@@ -22,9 +22,6 @@
// Armin Biere. The AIGER And-Inverter Graph (AIG) Format Version 20071012. Technical Report 07/1, October 2011, FMV Reports Series, Institute for Formal Models and Verification, Johannes Kepler University, Altenbergerstr. 69, 4040 Linz, Austria.
// http://fmv.jku.at/papers/Biere-FMV-TR-07-1.pdf
-#ifdef _WIN32
-#include <libgen.h>
-#endif
// https://stackoverflow.com/a/46137633
#ifdef _MSC_VER
#include <stdlib.h>
diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc
index 3a3634d34..f6a17b242 100644
--- a/frontends/verilog/const2ast.cc
+++ b/frontends/verilog/const2ast.cc
@@ -153,7 +153,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
{
if (warn_z) {
AstNode *ret = const2ast(code, case_type);
- if (std::find(ret->bits.begin(), ret->bits.end(), RTLIL::State::Sz) != ret->bits.end())
+ if (ret != nullptr && std::find(ret->bits.begin(), ret->bits.end(), RTLIL::State::Sz) != ret->bits.end())
log_warning("Yosys has only limited support for tri-state logic at the moment. (%s:%d)\n",
current_filename.c_str(), get_line_num());
return ret;
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index 502b45cfd..94dbf31c0 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -1592,21 +1592,14 @@ void RTLIL::Module::remove(const pool<RTLIL::Wire*> &wires)
void RTLIL::Module::remove(RTLIL::Cell *cell)
{
- auto it = cells_.find(cell->name);
- log_assert(it != cells_.end());
- remove(it);
-}
-
-dict<RTLIL::IdString, RTLIL::Cell*>::iterator RTLIL::Module::remove(dict<RTLIL::IdString, RTLIL::Cell*>::iterator it)
-{
- RTLIL::Cell *cell = it->second;
while (!cell->connections_.empty())
cell->unsetPort(cell->connections_.begin()->first);
+ auto it = cells_.find(cell->name);
+ log_assert(it != cells_.end());
log_assert(refcount_cells_ == 0);
- it = cells_.erase(it);
+ cells_.erase(it);
delete cell;
- return it;
}
void RTLIL::Module::rename(RTLIL::Wire *wire, RTLIL::IdString new_name)
diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index 4a0f8b4f8..f4fcf5dcf 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -1040,7 +1040,6 @@ public:
// Removing wires is expensive. If you have to remove wires, remove them all at once.
void remove(const pool<RTLIL::Wire*> &wires);
void remove(RTLIL::Cell *cell);
- dict<RTLIL::IdString, RTLIL::Cell*>::iterator remove(dict<RTLIL::IdString, RTLIL::Cell*>::iterator it);
void rename(RTLIL::Wire *wire, RTLIL::IdString new_name);
void rename(RTLIL::Cell *cell, RTLIL::IdString new_name);
diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc
index cfb0f788a..a8a8e0bc7 100644
--- a/passes/opt/opt_clean.cc
+++ b/passes/opt/opt_clean.cc
@@ -326,8 +326,8 @@ bool rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
if (wire->port_id != 0 || wire->get_bool_attribute("\\keep") || !initval.is_fully_undef()) {
// do not delete anything with "keep" or module ports or initialized wires
} else
- if (!purge_mode && check_public_name(wire->name)) {
- // do not get rid of public names unless in purge mode
+ if (!purge_mode && check_public_name(wire->name) && (raw_used_signals.check_any(s1) || used_signals.check_any(s2) || s1 != s2)) {
+ // do not get rid of public names unless in purge mode or if the wire is entirely unused, not even aliased
} else
if (!raw_used_signals.check_any(s1)) {
// delete wires that aren't used by anything directly
@@ -480,7 +480,7 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool
std::vector<RTLIL::Cell*> delcells;
for (auto cell : module->cells())
- if (cell->type.in("$pos", "$_BUF_")) {
+ if (cell->type.in("$pos", "$_BUF_") && !cell->has_keep_attr()) {
bool is_signed = cell->type == "$pos" && cell->getParam("\\A_SIGNED").as_bool();
RTLIL::SigSpec a = cell->getPort("\\A");
RTLIL::SigSpec y = cell->getPort("\\Y");
diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc
index b4f15d6a1..dbdd775f8 100644
--- a/passes/techmap/abc9.cc
+++ b/passes/techmap/abc9.cc
@@ -555,16 +555,15 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
}
vector<RTLIL::Cell*> boxes;
- for (auto it = module->cells_.begin(); it != module->cells_.end(); ) {
- RTLIL::Cell* cell = it->second;
+ for (auto it = module->cells_.begin(); it != module->cells_.end(); ++it) {
+ RTLIL::Cell *cell = it->second;
if (cell->type.in("$_AND_", "$_NOT_", "$__ABC_FF_")) {
- it = module->remove(it);
+ module->remove(cell);
continue;
}
RTLIL::Module* box_module = design->module(cell->type);
if (box_module && box_module->attributes.count("\\abc_box_id"))
- boxes.emplace_back(it->second);
- ++it;
+ boxes.emplace_back(cell);
}
std::map<std::string, int> cell_stats;
@@ -670,8 +669,8 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
}
}
- for (auto cell : boxes)
- module->remove(cell);
+ for (auto cell : boxes)
+ module->remove(cell);
// Copy connections (and rename) from mapped_mod to module
for (auto conn : mapped_mod->connections()) {
diff --git a/passes/techmap/muxcover.cc b/passes/techmap/muxcover.cc
index b0722134e..5642aeafc 100644
--- a/passes/techmap/muxcover.cc
+++ b/passes/techmap/muxcover.cc
@@ -330,13 +330,15 @@ struct MuxcoverWorker
ok = ok && follow_muxtree(S4, tree, bit, "BBS");
if (nodecode)
- ok = ok && S1 == S2 && S2 == S3 && S3 == S4;
+ ok = ok && (S1 == S2 || S1 == State::Sx || S2 == State::Sx) &&
+ /*S2 == S3 && */
+ (S3 == S4 || S3 == State::Sx || S4 == State::Sx);
ok = ok && follow_muxtree(T1, tree, bit, "AS");
ok = ok && follow_muxtree(T2, tree, bit, "BS");
if (nodecode)
- ok = ok && T1 == T2;
+ ok = ok && (T1 == T2 || T1 == State::Sx || T2 == State::Sx);
ok = ok && follow_muxtree(U1, tree, bit, "S");
@@ -353,11 +355,12 @@ struct MuxcoverWorker
mux.inputs.push_back(G);
mux.inputs.push_back(H);
+ mux.cost += prepare_decode_mux(T1, T2, U1, bit);
+
mux.cost += prepare_decode_mux(S1, S2, T1, bit);
mux.cost += prepare_decode_mux(S3, S4, T2, bit);
- mux.cost += prepare_decode_mux(S1, S3, U1, bit);
-
- mux.cost += prepare_decode_mux(T1, T2, U1, bit);
+ if (T1 != T2 && T1 != State::Sx && T2 != State::Sx)
+ mux.cost += prepare_decode_mux(S1, S3, U1, bit);
mux.selects.push_back(S1);
mux.selects.push_back(T1);
@@ -407,7 +410,13 @@ struct MuxcoverWorker
ok = ok && follow_muxtree(S8, tree, bit, "BBBS");
if (nodecode)
- ok = ok && S1 == S2 && S2 == S3 && S3 == S4 && S4 == S5 && S5 == S6 && S6 == S7 && S7 == S8;
+ ok = ok && (S1 == S2 || S1 == State::Sx || S2 == State::Sx) &&
+ /*S2 == S3 &&*/
+ (S3 == S4 || S3 == State::Sx || S4 == State::Sx) &&
+ /*S4 == S5 &&*/
+ (S5 == S6 || S5 == State::Sx || S6 == State::Sx) &&
+ /*S6 == S7 &&*/
+ (S7 == S8 || S7 == State::Sx || S8 == State::Sx);
ok = ok && follow_muxtree(T1, tree, bit, "AAS");
ok = ok && follow_muxtree(T2, tree, bit, "ABS");
@@ -415,13 +424,15 @@ struct MuxcoverWorker
ok = ok && follow_muxtree(T4, tree, bit, "BBS");
if (nodecode)
- ok = ok && T1 == T2 && T2 == T3 && T3 == T4;
+ ok = ok && (T1 == T2 || T1 == State::Sx || T2 == State::Sx) &&
+ /*T2 == T3 &&*/
+ (T3 == T4 || T3 == State::Sx || T4 == State::Sx);
ok = ok && follow_muxtree(U1, tree, bit, "AS");
ok = ok && follow_muxtree(U2, tree, bit, "BS");
if (nodecode)
- ok = ok && U1 == U2;
+ ok = ok && (U1 == U2 || U1 == State::Sx || U2 == State::Sx);
ok = ok && follow_muxtree(V1, tree, bit, "S");
@@ -446,19 +457,26 @@ struct MuxcoverWorker
mux.inputs.push_back(O);
mux.inputs.push_back(P);
- mux.cost += prepare_decode_mux(S1, S2, T1, bit);
- mux.cost += prepare_decode_mux(S3, S4, T2, bit);
- mux.cost += prepare_decode_mux(S5, S6, T3, bit);
- mux.cost += prepare_decode_mux(S7, S8, T4, bit);
- mux.cost += prepare_decode_mux(S1, S3, U1, bit);
- mux.cost += prepare_decode_mux(S5, S7, U2, bit);
- mux.cost += prepare_decode_mux(S1, S5, V1, bit);
+ mux.cost += prepare_decode_mux(U1, U2, V1, bit);
mux.cost += prepare_decode_mux(T1, T2, U1, bit);
mux.cost += prepare_decode_mux(T3, T4, U2, bit);
- mux.cost += prepare_decode_mux(T1, T3, V1, bit);
+ if (U1 != U2 && U1 != State::Sx && U2 != State::Sx) {
+ mux.cost += prepare_decode_mux(T1, T3, V1, bit);
- mux.cost += prepare_decode_mux(U1, U2, V1, bit);
+ mux.cost += prepare_decode_mux(S1, S2, T1, bit);
+ mux.cost += prepare_decode_mux(S3, S4, T2, bit);
+ if (T1 != T2 && T1 != State::Sx && T2 != State::Sx)
+ mux.cost += prepare_decode_mux(S1, S3, U1, bit);
+
+ mux.cost += prepare_decode_mux(S5, S6, T3, bit);
+ mux.cost += prepare_decode_mux(S7, S8, T4, bit);
+ if (T3 != T4 && T3 != State::Sx && T4 != State::Sx)
+ mux.cost += prepare_decode_mux(S5, S7, U2, bit);
+
+ if (T1 != T3 && T1 != State::Sx && T3 != State::Sx)
+ mux.cost += prepare_decode_mux(S1, S5, V1, bit);
+ }
mux.selects.push_back(S1);
mux.selects.push_back(T1);
diff --git a/techlibs/ecp5/cells_map.v b/techlibs/ecp5/cells_map.v
index b504d51e2..6985fbbc8 100644
--- a/techlibs/ecp5/cells_map.v
+++ b/techlibs/ecp5/cells_map.v
@@ -47,6 +47,28 @@ module \$__DFFSE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"
module \$__DFFSE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
module \$__DFFSE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+// TODO: Diamond flip-flops
+// module FD1P3AX(); endmodule
+// module FD1P3AY(); endmodule
+// module FD1P3BX(); endmodule
+// module FD1P3DX(); endmodule
+// module FD1P3IX(); endmodule
+// module FD1P3JX(); endmodule
+// module FD1S3AX(); endmodule
+// module FD1S3AY(); endmodule
+module FD1S3BX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
+module FD1S3DX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule
+module FD1S3IX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule
+module FD1S3JX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
+// module FL1P3AY(); endmodule
+// module FL1P3AZ(); endmodule
+// module FL1P3BX(); endmodule
+// module FL1P3DX(); endmodule
+// module FL1P3IY(); endmodule
+// module FL1P3JY(); endmodule
+// module FL1S3AX(); endmodule
+// module FL1S3AY(); endmodule
+
// Diamond I/O buffers
module IB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
module IBPU (input I, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule
@@ -62,8 +84,22 @@ module BBPD (input I, T, output O, inout B); (* PULLMODE="DOWN" *) TRELLIS_IO #(
module ILVDS(input A, AN, output Z); TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(A), .O(Z)); endmodule
module OLVDS(input A, output Z, ZN); TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(Z), .I(A)); endmodule
-// For Diamond compatibility, FIXME: add all Diamond flipflop mappings
-module FD1S3BX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
+// Diamond I/O registers
+module IFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module IFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module IFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module IFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
+
+module OFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module OFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module OFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module OFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
+
+// TODO: Diamond I/O latches
+// module IFS1S1B(input PD, D, SCLK, output Q); endmodule
+// module IFS1S1D(input CD, D, SCLK, output Q); endmodule
+// module IFS1S1I(input PD, D, SCLK, output Q); endmodule
+// module IFS1S1J(input CD, D, SCLK, output Q); endmodule
`ifndef NO_LUT
module \$lut (A, Y);
diff --git a/techlibs/ecp5/cells_sim.v b/techlibs/ecp5/cells_sim.v
index b678a14da..08ae0a112 100644
--- a/techlibs/ecp5/cells_sim.v
+++ b/techlibs/ecp5/cells_sim.v
@@ -261,18 +261,6 @@ module TRELLIS_FF(input CLK, LSR, CE, DI, M, output reg Q);
endmodule
// ---------------------------------------
-
-module OBZ(input I, T, output O);
-assign O = T ? 1'bz : I;
-endmodule
-
-// ---------------------------------------
-
-module IB(input I, output O);
-assign O = I;
-endmodule
-
-// ---------------------------------------
(* keep *)
module TRELLIS_IO(
inout B,
@@ -303,19 +291,6 @@ endmodule
// ---------------------------------------
-module OB(input I, output O);
-assign O = I;
-endmodule
-
-// ---------------------------------------
-
-module BB(input I, T, output O, inout B);
-assign B = T ? 1'bz : I;
-assign O = B;
-endmodule
-
-// ---------------------------------------
-
module INV(input A, output Z);
assign Z = !A;
endmodule
@@ -568,19 +543,56 @@ module DP16KD(
parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
endmodule
-// For Diamond compatibility, FIXME: add all Diamond flipflop mappings
-module FD1S3BX(input PD, D, CK, output Q);
- TRELLIS_FF #(
- .GSR("DISABLED"),
- .CEMUX("1"),
- .CLKMUX("CLK"),
- .LSRMUX("LSR"),
- .REGSET("SET"),
- .SRMODE("ASYNC")
- ) tff_i (
- .CLK(CK),
- .LSR(PD),
- .DI(D),
- .Q(Q)
- );
-endmodule
+// TODO: Diamond flip-flops
+// module FD1P3AX(); endmodule
+// module FD1P3AY(); endmodule
+// module FD1P3BX(); endmodule
+// module FD1P3DX(); endmodule
+// module FD1P3IX(); endmodule
+// module FD1P3JX(); endmodule
+// module FD1S3AX(); endmodule
+// module FD1S3AY(); endmodule
+module FD1S3BX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) tff (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
+module FD1S3DX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) tff (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule
+module FD1S3IX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule
+module FD1S3JX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule
+// module FL1P3AY(); endmodule
+// module FL1P3AZ(); endmodule
+// module FL1P3BX(); endmodule
+// module FL1P3DX(); endmodule
+// module FL1P3IY(); endmodule
+// module FL1P3JY(); endmodule
+// module FL1S3AX(); endmodule
+// module FL1S3AY(); endmodule
+
+// Diamond I/O buffers
+module IB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("INPUT")) tio (.B(I), .O(O)); endmodule
+module IBPU (input I, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("INPUT")) tio (.B(I), .O(O)); endmodule
+module IBPD (input I, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("INPUT")) tio (.B(I), .O(O)); endmodule
+module OB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I)); endmodule
+module OBZ (input I, T, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I), .T(T)); endmodule
+module OBZPU(input I, T, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I), .T(T)); endmodule
+module OBZPD(input I, T, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I), .T(T)); endmodule
+module OBCO (input I, output OT, OC); OLVDS olvds (.A(I), .Z(OT), .ZN(OC)); endmodule
+module BB (input I, T, output O, inout B); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("BIDIR")) tio (.B(B), .I(I), .O(O), .T(T)); endmodule
+module BBPU (input I, T, output O, inout B); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("BIDIR")) tio (.B(B), .I(I), .O(O), .T(T)); endmodule
+module BBPD (input I, T, output O, inout B); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("BIDIR")) tio (.B(B), .I(I), .O(O), .T(T)); endmodule
+module ILVDS(input A, AN, output Z); TRELLIS_IO #(.DIR("INPUT")) tio (.B(A), .O(Z)); endmodule
+module OLVDS(input A, output Z, ZN); TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(Z), .I(A)); endmodule
+
+// Diamond I/O registers
+module IFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module IFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module IFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module IFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
+
+module OFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module OFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module OFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule
+module OFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule
+
+// TODO: Diamond I/O latches
+// module IFS1S1B(input PD, D, SCLK, output Q); endmodule
+// module IFS1S1D(input CD, D, SCLK, output Q); endmodule
+// module IFS1S1I(input PD, D, SCLK, output Q); endmodule
+// module IFS1S1J(input CD, D, SCLK, output Q); endmodule
diff --git a/techlibs/xilinx/Makefile.inc b/techlibs/xilinx/Makefile.inc
index 1a652eb27..59fd61cf0 100644
--- a/techlibs/xilinx/Makefile.inc
+++ b/techlibs/xilinx/Makefile.inc
@@ -30,6 +30,7 @@ $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/arith_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/ff_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut_map.v))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/mux_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_xc7.box))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_xc7.lut))
diff --git a/techlibs/xilinx/abc_xc7.box b/techlibs/xilinx/abc_xc7.box
index 6dd71d758..7fe8a7236 100644
--- a/techlibs/xilinx/abc_xc7.box
+++ b/techlibs/xilinx/abc_xc7.box
@@ -3,17 +3,22 @@
# NB: Inputs/Outputs must be ordered alphabetically
# (with exceptions for carry in/out)
-# F7BMUX slower than F7AMUX
+# Average across F7[AB]MUX
# Inputs: I0 I1 S0
# Outputs: O
-F7BMUX 1 1 3 1
-217 223 296
+F7MUX 1 1 3 1
+204 208 286
# Inputs: I0 I1 S0
# Outputs: O
MUXF8 2 1 3 1
104 94 273
+# Inputs: I0 I1 I2 I3 S0 S1
+# Outputs: O
+MUXF78 3 1 6 1
+190 193 217 223 296 273
+
# CARRY4 + CARRY4_[ABCD]X
# Inputs: CYINIT DI0 DI1 DI2 DI3 S0 S1 S2 S3 CI
# Outputs: O0 O1 O2 O3 CO0 CO1 CO2 CO3
@@ -21,7 +26,7 @@ MUXF8 2 1 3 1
# input/output and the entire bus has been
# moved there overriding the otherwise
# alphabetical ordering)
-CARRY4 3 1 10 8
+CARRY4 4 1 10 8
482 - - - - 223 - - - 222
598 407 - - - 400 205 - - 334
584 556 537 - - 523 558 226 - 239
@@ -34,20 +39,20 @@ CARRY4 3 1 10 8
# SLICEM/A6LUT
# Inputs: A0 A1 A2 A3 A4 D DPRA0 DPRA1 DPRA2 DPRA3 DPRA4 WCLK WE
# Outputs: DPO SPO
-RAM32X1D 4 0 13 2
+RAM32X1D 5 0 13 2
- - - - - - 631 472 407 238 127 - -
631 472 407 238 127 - - - - - - - -
# SLICEM/A6LUT
# Inputs: A0 A1 A2 A3 A4 A5 D DPRA0 DPRA1 DPRA2 DPRA3 DPRA4 DPRA5 WCLK WE
# Outputs: DPO SPO
-RAM64X1D 5 0 15 2
+RAM64X1D 6 0 15 2
- - - - - - - 642 631 472 407 238 127 - -
642 631 472 407 238 127 - - - - - - - - -
# SLICEM/A6LUT + F7[AB]MUX
# Inputs: A0 A1 A2 A3 A4 A5 A6 D DPRA0 DPRA1 DPRA2 DPRA3 DPRA4 DPRA5 DPRA6 WCLK WE
# Outputs: DPO SPO
-RAM128X1D 6 0 17 2
+RAM128X1D 7 0 17 2
- - - - - - - - 1009 998 839 774 605 494 450 - -
1047 1036 877 812 643 532 478 - - - - - - - - - -
diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v
index b5114758c..61c2c8f94 100644
--- a/techlibs/xilinx/cells_map.v
+++ b/techlibs/xilinx/cells_map.v
@@ -154,3 +154,165 @@ module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, o
end
endgenerate
endmodule
+
+`ifdef MIN_MUX_INPUTS
+module \$__XILINX_SHIFTX (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ input [A_WIDTH-1:0] A;
+ input [B_WIDTH-1:0] B;
+ output [Y_WIDTH-1:0] Y;
+
+ parameter [A_WIDTH-1:0] _TECHMAP_CONSTMSK_A_ = 0;
+ parameter [A_WIDTH-1:0] _TECHMAP_CONSTVAL_A_ = 0;
+ parameter [B_WIDTH-1:0] _TECHMAP_CONSTMSK_B_ = 0;
+ parameter [B_WIDTH-1:0] _TECHMAP_CONSTVAL_B_ = 0;
+
+ function integer compute_num_leading_X_in_A;
+ integer i, c;
+ begin
+ compute_num_leading_X_in_A = 0;
+ c = 1;
+ for (i = A_WIDTH-1; i >= 0; i=i-1) begin
+ if (!_TECHMAP_CONSTMSK_A_[i] || _TECHMAP_CONSTVAL_A_[i] !== 1'bx)
+ c = 0;
+ compute_num_leading_X_in_A = compute_num_leading_X_in_A + c;
+ end
+ end
+ endfunction
+ localparam num_leading_X_in_A = compute_num_leading_X_in_A();
+
+ generate
+ genvar i, j;
+ // Bit-blast
+ if (Y_WIDTH > 1) begin
+ for (i = 0; i < Y_WIDTH; i++)
+ \$__XILINX_SHIFTX #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(A_WIDTH-Y_WIDTH+1), .B_WIDTH(B_WIDTH), .Y_WIDTH(1'd1)) bitblast (.A(A[A_WIDTH-Y_WIDTH+i:i]), .B(B), .Y(Y[i]));
+ end
+ // If the LSB of B is constant zero (and Y_WIDTH is 1) then
+ // we can optimise by removing every other entry from A
+ // and popping the constant zero from B
+ else if (_TECHMAP_CONSTMSK_B_[0] && !_TECHMAP_CONSTVAL_B_[0]) begin
+ wire [(A_WIDTH+1)/2-1:0] A_i;
+ for (i = 0; i < (A_WIDTH+1)/2; i++)
+ assign A_i[i] = A[i*2];
+ \$__XILINX_SHIFTX #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH((A_WIDTH+1'd1)/2'd2), .B_WIDTH(B_WIDTH-1'd1), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A_i), .B(B[B_WIDTH-1:1]), .Y(Y));
+ end
+ // Trim off any leading 1'bx -es in A, and resize B accordingly
+ else if (num_leading_X_in_A > 0) begin
+ localparam A_WIDTH_new = A_WIDTH - num_leading_X_in_A;
+ localparam B_WIDTH_new = $clog2(A_WIDTH_new);
+ \$__XILINX_SHIFTX #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(A_WIDTH_new), .B_WIDTH(B_WIDTH_new), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A[A_WIDTH_new-1:0]), .B(B[B_WIDTH_new-1:0]), .Y(Y));
+ end
+ else if (A_WIDTH < `MIN_MUX_INPUTS) begin
+ wire _TECHMAP_FAIL_ = 1;
+ end
+ else if (A_WIDTH <= 2 ** 3) begin
+ localparam a_width0 = 2 ** 2;
+ localparam a_widthN = A_WIDTH - a_width0;
+ wire T0, T1;
+ \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_width0), .B_WIDTH(2), .Y_WIDTH(Y_WIDTH)) fpga_soft_mux (.A(A[a_width0-1:0]), .B(B[2-1:0]), .Y(T0));
+ if (a_widthN > 1)
+ \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_widthN), .B_WIDTH($clog2(a_widthN)), .Y_WIDTH(Y_WIDTH)) fpga_soft_mux_last (.A(A[A_WIDTH-1:a_width0]), .B(B[$clog2(a_widthN)-1:0]), .Y(T1));
+ else
+ assign T1 = A[A_WIDTH-1];
+ MUXF7 fpga_hard_mux (.I0(T0), .I1(T1), .S(B[2]), .O(Y));
+ end
+ else if (A_WIDTH <= 2 ** 4) begin
+ localparam a_width0 = 2 ** 2;
+ localparam num_mux8 = A_WIDTH / a_width0;
+ localparam a_widthN = A_WIDTH % a_width0;
+ wire [a_width0-1:0] T;
+ for (i = 0; i < a_width0; i++)
+ if (i < num_mux8)
+ \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_width0), .B_WIDTH(2), .Y_WIDTH(Y_WIDTH)) fpga_mux (.A(A[i*a_width0+:a_width0]), .B(B[2-1:0]), .Y(T[i]));
+ else if (i == num_mux8 && a_widthN > 1)
+ \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_widthN), .B_WIDTH($clog2(a_widthN)), .Y_WIDTH(Y_WIDTH)) fpga_mux_last (.A(A[A_WIDTH-1-:a_widthN]), .B(B[$clog2(a_widthN)-1:0]), .Y(T[i]));
+ else
+ assign T[i] = A[A_WIDTH-1];
+ \$__XILINX_MUXF78 fpga_hard_mux (.I0(T[0]), .I1(T[1]), .I2(T[2]), .I3(T[3]), .S0(B[2]), .S1(B[3]), .O(Y));
+ end
+ else begin
+ localparam a_width0 = 2 ** 4;
+ localparam num_mux16 = A_WIDTH / a_width0;
+ localparam a_widthN = A_WIDTH % a_width0;
+ wire [num_mux16 + (a_widthN > 0 ? 1 : 0) - 1:0] T;
+ for (i = 0; i < num_mux16; i++)
+ \$__XILINX_SHIFTX #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_width0), .B_WIDTH(4), .Y_WIDTH(Y_WIDTH)) fpga_soft_mux (.A(A[i*a_width0+:a_width0]), .B(B[4-1:0]), .Y(T[i]));
+ if (a_widthN > 0) begin
+ if (a_widthN > 1)
+ \$__XILINX_SHIFTX #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_widthN), .B_WIDTH($clog2(a_widthN)), .Y_WIDTH(Y_WIDTH)) fpga_soft_mux_last (.A(A[A_WIDTH-1-:a_widthN]), .B(B[$clog2(a_widthN)-1:0]), .Y(T[num_mux16]));
+ else
+ assign T[num_mux16] = A[A_WIDTH-1];
+ end
+ \$__XILINX_SHIFTX #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(num_mux16 + (a_widthN > 0 ? 1 : 0)), .B_WIDTH(B_WIDTH-4), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(T), .B(B[B_WIDTH-1:4]), .Y(Y));
+ end
+ endgenerate
+endmodule
+
+(* techmap_celltype = "$__XILINX_SHIFTX" *)
+module _90__XILINX_SHIFTX (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ input [A_WIDTH-1:0] A;
+ input [B_WIDTH-1:0] B;
+ output [Y_WIDTH-1:0] Y;
+
+ \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(A_WIDTH), .B_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A), .B(B), .Y(Y));
+endmodule
+
+module \$_MUX8_ (A, B, C, D, E, F, G, H, S, T, U, Y);
+input A, B, C, D, E, F, G, H, S, T, U;
+output Y;
+ \$__XILINX_SHIFTX #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(8), .B_WIDTH(3), .Y_WIDTH(1)) _TECHMAP_REPLACE_ (.A({H,G,F,E,D,C,B,A}), .B({U,T,S}), .Y(Y));
+endmodule
+
+module \$_MUX16_ (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, S, T, U, V, Y);
+input A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, S, T, U, V;
+output Y;
+ \$__XILINX_SHIFTX #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(16), .B_WIDTH(4), .Y_WIDTH(1)) _TECHMAP_REPLACE_ (.A({P,O,N,M,L,K,J,I,H,G,F,E,D,C,B,A}), .B({V,U,T,S}), .Y(Y));
+endmodule
+`endif
+
+`ifndef _ABC
+module \$__XILINX_MUXF78 (O, I0, I1, I2, I3, S0, S1);
+ output O;
+ input I0, I1, I2, I3, S0, S1;
+ wire T0, T1;
+// parameter _TECHMAP_BITS_CONNMAP_ = 0;
+// parameter [_TECHMAP_BITS_CONNMAP_-1:0] _TECHMAP_CONNMAP_I0_ = 0;
+// parameter [_TECHMAP_BITS_CONNMAP_-1:0] _TECHMAP_CONNMAP_I1_ = 0;
+// parameter [_TECHMAP_BITS_CONNMAP_-1:0] _TECHMAP_CONNMAP_I2_ = 0;
+// parameter [_TECHMAP_BITS_CONNMAP_-1:0] _TECHMAP_CONNMAP_I3_ = 0;
+// parameter _TECHMAP_CONSTMSK_S0_ = 0;
+// parameter _TECHMAP_CONSTVAL_S0_ = 0;
+// parameter _TECHMAP_CONSTMSK_S1_ = 0;
+// parameter _TECHMAP_CONSTVAL_S1_ = 0;
+// if (_TECHMAP_CONSTMSK_S0_ && _TECHMAP_CONSTVAL_S0_ === 1'b1)
+// assign T0 = I1;
+// else if (_TECHMAP_CONSTMSK_S0_ || _TECHMAP_CONNMAP_I0_ === _TECHMAP_CONNMAP_I1_)
+// assign T0 = I0;
+// else
+ MUXF7 mux7a (.I0(I0), .I1(I1), .S(S0), .O(T0));
+// if (_TECHMAP_CONSTMSK_S0_ && _TECHMAP_CONSTVAL_S0_ === 1'b1)
+// assign T1 = I3;
+// else if (_TECHMAP_CONSTMSK_S0_ || _TECHMAP_CONNMAP_I2_ === _TECHMAP_CONNMAP_I3_)
+// assign T1 = I2;
+// else
+ MUXF7 mux7b (.I0(I2), .I1(I3), .S(S0), .O(T1));
+// if (_TECHMAP_CONSTMSK_S1_ && _TECHMAP_CONSTVAL_S1_ === 1'b1)
+// assign O = T1;
+// else if (_TECHMAP_CONSTMSK_S1_ || (_TECHMAP_CONNMAP_I0_ === _TECHMAP_CONNMAP_I1_ && _TECHMAP_CONNMAP_I1_ === _TECHMAP_CONNMAP_I2_ && _TECHMAP_CONNMAP_I2_ === _TECHMAP_CONNMAP_I3_))
+// assign O = T0;
+// else
+ MUXF8 mux8 (.I0(T0), .I1(T1), .S(S1), .O(O));
+endmodule
+`endif
diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v
index 4ecf8277b..4a1e334d6 100644
--- a/techlibs/xilinx/cells_sim.v
+++ b/techlibs/xilinx/cells_sim.v
@@ -169,11 +169,19 @@ module MUXF8(output O, input I0, I1, S);
assign O = S ? I1 : I0;
endmodule
+`ifdef _ABC
+(* abc_box_id = 3, lib_whitebox *)
+module \$__XILINX_MUXF78 (output O, input I0, I1, I2, I3, S0, S1);
+ assign O = S1 ? (S0 ? I3 : I2)
+ : (S0 ? I1 : I0);
+endmodule
+`endif
+
module XORCY(output O, input CI, LI);
assign O = CI ^ LI;
endmodule
-(* abc_box_id = 3, abc_carry, lib_whitebox *)
+(* abc_box_id = 4, abc_carry, lib_whitebox *)
module CARRY4((* abc_carry_out *) output [3:0] CO, output [3:0] O, (* abc_carry_in *) input CI, input CYINIT, input [3:0] DI, S);
assign O = S ^ {CO[2:0], CI | CYINIT};
assign CO[0] = S[0] ? CI | CYINIT : DI[0];
@@ -281,12 +289,12 @@ module FDPE_1 (output reg Q, input C, CE, D, PRE);
always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D;
endmodule
-(* abc_box_id = 4, abc_scc_break="D,WE" *)
+(* abc_box_id = 5, abc_scc_break="D,WE" *)
module RAM32X1D (
output DPO, SPO,
input D, WCLK, WE,
input A0, A1, A2, A3, A4,
- input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4,
+ input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4
);
parameter INIT = 32'h0;
parameter IS_WCLK_INVERTED = 1'b0;
@@ -299,7 +307,7 @@ module RAM32X1D (
always @(posedge clk) if (WE) mem[a] <= D;
endmodule
-(* abc_box_id = 5, abc_scc_break="D,WE" *)
+(* abc_box_id = 6, abc_scc_break="D,WE" *)
module RAM64X1D (
output DPO, SPO,
input D, WCLK, WE,
@@ -317,7 +325,7 @@ module RAM64X1D (
always @(posedge clk) if (WE) mem[a] <= D;
endmodule
-(* abc_box_id = 6, abc_scc_break="D,WE" *)
+(* abc_box_id = 7, abc_scc_break="D,WE" *)
module RAM128X1D (
output DPO, SPO,
input D, WCLK, WE,
diff --git a/techlibs/xilinx/mux_map.v b/techlibs/xilinx/mux_map.v
new file mode 100644
index 000000000..91aaf2118
--- /dev/null
+++ b/techlibs/xilinx/mux_map.v
@@ -0,0 +1,71 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * 2019 Eddie Hung <eddie@fpgeh.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+// The purpose of these mapping rules is to allow preserve all (sufficiently
+// wide) $shiftx cells during 'techmap' so that they can be mapped to hard
+// resources, rather than being bit-blasted to gates during 'techmap'
+// execution
+
+module \$shiftx (A, B, Y);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ input [A_WIDTH-1:0] A;
+ input [B_WIDTH-1:0] B;
+ output [Y_WIDTH-1:0] Y;
+
+ parameter [B_WIDTH-1:0] _TECHMAP_CONSTMSK_B_ = 0;
+ parameter [B_WIDTH-1:0] _TECHMAP_CONSTVAL_B_ = 0;
+
+ generate
+ if (B_SIGNED) begin
+ if (_TECHMAP_CONSTMSK_B_[B_WIDTH-1] && (_TECHMAP_CONSTVAL_B_[B_WIDTH-1] == 1'b0 || _TECHMAP_CONSTVAL_B_[B_WIDTH-1] === 1'bx))
+ // Optimisation to remove B_SIGNED if sign bit of B is constant-0
+ \$shiftx #(
+ .A_SIGNED(A_SIGNED),
+ .B_SIGNED(0),
+ .A_WIDTH(A_WIDTH),
+ .B_WIDTH(B_WIDTH-1'd1),
+ .Y_WIDTH(Y_WIDTH)
+ ) _TECHMAP_REPLACE_ (
+ .A(A), .B(B[B_WIDTH-2:0]), .Y(Y)
+ );
+ else
+ wire _TECHMAP_FAIL_ = 1;
+ end
+ else begin
+ if (((A_WIDTH + Y_WIDTH - 1) / Y_WIDTH) < `MIN_MUX_INPUTS)
+ wire _TECHMAP_FAIL_ = 1;
+ else
+ \$__XILINX_SHIFTX #(
+ .A_SIGNED(A_SIGNED),
+ .B_SIGNED(B_SIGNED),
+ .A_WIDTH(A_WIDTH),
+ .B_WIDTH(B_WIDTH),
+ .Y_WIDTH(Y_WIDTH)
+ ) _TECHMAP_REPLACE_ (
+ .A(A), .B(B), .Y(Y)
+ );
+ end
+ endgenerate
+endmodule
diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc
index 83c2edc86..2f3dfb012 100644
--- a/techlibs/xilinx/synth_xilinx.cc
+++ b/techlibs/xilinx/synth_xilinx.cc
@@ -79,6 +79,11 @@ struct SynthXilinxPass : public ScriptPass
log(" -nowidelut\n");
log(" do not use MUXF[78] resources to implement LUTs larger than LUT6s\n");
log("\n");
+ log(" -widemux <int>\n");
+ log(" enable inference of hard multiplexer resources (MuxFx) for muxes at or\n");
+ log(" above this number of inputs (minimum value 5).\n");
+ log(" default: 0 (no inference)\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");
@@ -101,6 +106,7 @@ struct SynthXilinxPass : public ScriptPass
std::string top_opt, edif_file, blif_file, arch;
bool flatten, retime, vpr, nobram, nodram, nosrl, nocarry, nowidelut, abc9;
+ int widemux;
void clear_flags() YS_OVERRIDE
{
@@ -118,6 +124,7 @@ struct SynthXilinxPass : public ScriptPass
nocarry = false;
nowidelut = false;
abc9 = false;
+ widemux = 0;
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
@@ -188,6 +195,10 @@ struct SynthXilinxPass : public ScriptPass
nosrl = true;
continue;
}
+ if (args[argidx] == "-widemux" && argidx+1 < args.size()) {
+ widemux = atoi(args[++argidx].c_str());
+ continue;
+ }
if (args[argidx] == "-abc9") {
abc9 = true;
continue;
@@ -199,6 +210,9 @@ struct SynthXilinxPass : public ScriptPass
if (arch != "xcup" && arch != "xcu" && arch != "xc7" && arch != "xc6s")
log_cmd_error("Invalid Xilinx -arch setting: %s\n", arch.c_str());
+ if (widemux != 0 && widemux < 5)
+ log_cmd_error("-widemux value must be 0 or >= 5.\n");
+
if (!design->full_selection())
log_cmd_error("This command only operates on fully selected designs!\n");
@@ -214,9 +228,9 @@ struct SynthXilinxPass : public ScriptPass
{
if (check_label("begin")) {
if (vpr)
- run("read_verilog -lib -D _ABC -D_EXPLICIT_CARRY +/xilinx/cells_sim.v");
+ run("read_verilog -lib -icells -D _ABC -D_EXPLICIT_CARRY +/xilinx/cells_sim.v");
else
- run("read_verilog -lib -D _ABC +/xilinx/cells_sim.v");
+ run("read_verilog -lib -icells -D _ABC +/xilinx/cells_sim.v");
run("read_verilog -lib +/xilinx/cells_xtra.v");
@@ -226,26 +240,21 @@ struct SynthXilinxPass : public ScriptPass
run(stringf("hierarchy -check %s", top_opt.c_str()));
}
- if (check_label("flatten", "(with '-flatten' only)")) {
- if (flatten || help_mode) {
- run("proc");
- run("flatten");
- }
- }
-
if (check_label("coarse")) {
- run("synth -run coarse");
+ if (help_mode)
+ run("synth -run coarse [-flatten]", "(with '-flatten')");
+ else
+ run("synth -run coarse" + std::string(flatten ? "" : " -flatten"), "(with '-flatten')");
+
+ if (widemux > 0 || help_mode)
+ run("muxpack", " ('-widemux' only)");
// shregmap -tech xilinx can cope with $shiftx and $mux
// cells for identifying variable-length shift registers,
// so attempt to convert $pmux-es to the former
- if (!nosrl || help_mode)
- run("pmux2shiftx", "(skip if '-nosrl')");
-
- // Run a number of peephole optimisations, including one
- // that optimises $mul cells driving $shiftx's B input
- // and that aids wide mux analysis
- run("peepopt");
+ // Also: wide multiplexer inference benefits from this too
+ if (!(nosrl && widemux == 0) || help_mode)
+ run("pmux2shiftx", "(skip if '-nosrl' and '-widemux' < 5)");
}
if (check_label("bram", "(skip if '-nobram')")) {
@@ -267,32 +276,65 @@ struct SynthXilinxPass : public ScriptPass
run("memory_map");
run("dffsr2dff");
run("dff2dffe");
+ if (help_mode) {
+ run("simplemap t:$mux", " ('-widemux' only)");
+ run("muxcover <internal options>, ('-widemux' only)");
+ }
+ else if (widemux > 0) {
+ run("simplemap t:$mux");
+ std::string muxcover_args = " -nodecode";
+ switch (widemux) {
+ // NB: Cost of mux2 is 100; mux8 should cost between 3 and 4
+ // of those so that 4:1 muxes and below are implemented
+ // out of mux2s
+ case 5: muxcover_args += " -mux8=350 -mux16=400"; break;
+ case 6: muxcover_args += " -mux8=450 -mux16=500"; break;
+ case 7: muxcover_args += " -mux8=550 -mux16=600"; break;
+ case 8: muxcover_args += " -mux8=650 -mux16=700"; break;
+ case 9: muxcover_args += " -mux16=750"; break;
+ case 10: muxcover_args += " -mux16=850"; break;
+ case 11: muxcover_args += " -mux16=950"; break;
+ case 12: muxcover_args += " -mux16=1050"; break;
+ case 13: muxcover_args += " -mux16=1150"; break;
+ case 14: muxcover_args += " -mux16=1250"; break;
+ case 15: muxcover_args += " -mux16=1350"; break;
+ default: muxcover_args += " -mux16=1450"; break;
+ }
+ run("muxcover " + muxcover_args);
+ }
run("opt -full");
if (!nosrl || help_mode) {
// shregmap operates on bit-level flops, not word-level,
// so break those down here
- run("simplemap t:$dff t:$dffe", "(skip if '-nosrl')");
+ run("simplemap t:$dff t:$dffe", " (skip if '-nosrl')");
// shregmap with '-tech xilinx' infers variable length shift regs
run("shregmap -tech xilinx -minlen 3", "(skip if '-nosrl')");
}
- std::string techmap_files = " -map +/techmap.v";
+ std::string techmap_args = " -map +/techmap.v";
+ if (help_mode)
+ techmap_args += " [-map +/xilinx/mux_map.v]";
+ else if (widemux > 0)
+ techmap_args += stringf(" -D MIN_MUX_INPUTS=%d -map +/xilinx/mux_map.v", widemux);
if (help_mode)
- techmap_files += " [-map +/xilinx/arith_map.v]";
+ techmap_args += " [-map +/xilinx/arith_map.v]";
else if (!nocarry) {
- techmap_files += " -map +/xilinx/arith_map.v";
+ techmap_args += " -map +/xilinx/arith_map.v";
if (vpr)
- techmap_files += " -D _EXPLICIT_CARRY";
+ techmap_args += " -D _EXPLICIT_CARRY";
else if (abc9)
- techmap_files += " -D _CLB_CARRY";
+ techmap_args += " -D _CLB_CARRY";
}
- run("techmap " + techmap_files);
+ run("techmap " + techmap_args);
run("opt -fast");
}
if (check_label("map_cells")) {
- run("techmap -map +/techmap.v -map +/xilinx/cells_map.v");
+ std::string techmap_args = "-map +/techmap.v -D _ABC -map +/xilinx/cells_map.v";
+ if (widemux > 0)
+ techmap_args += stringf(" -D MIN_MUX_INPUTS=%d", widemux);
+ run("techmap " + techmap_args);
run("clean");
}
diff --git a/tests/various/muxcover.ys b/tests/various/muxcover.ys
index 8ef619b46..67e9625e6 100644
--- a/tests/various/muxcover.ys
+++ b/tests/various/muxcover.ys
@@ -188,3 +188,323 @@ design -import gate -as gate
miter -equiv -flatten -make_assert -make_outputs gold gate miter
sat -verify -prove-asserts -show-ports miter
+## MUX2 in MUX4 :: https://github.com/YosysHQ/yosys/issues/1132
+
+design -reset
+read_verilog -formal <<EOT
+module mux2in4(input [1:0] i, input s, output o);
+ assign o = s ? i[1] : i[0];
+endmodule
+EOT
+prep
+design -save gold
+
+techmap
+muxcover -mux4=99 -nodecode
+clean
+opt_expr -mux_bool
+select -assert-count 0 t:$_MUX_
+select -assert-count 1 t:$_MUX4_
+select -assert-count 0 t:$_MUX8_
+select -assert-count 0 t:$_MUX16_
+techmap -map +/simcells.v t:$_MUX4_
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+## MUX2 in MUX8 :: https://github.com/YosysHQ/yosys/issues/1132
+
+design -reset
+read_verilog -formal <<EOT
+module mux2in8(input [1:0] i, input s, output o);
+ assign o = s ? i[1] : i[0];
+endmodule
+EOT
+prep
+design -save gold
+
+techmap
+muxcover -mux8=99 -nodecode
+clean
+opt_expr -mux_bool
+select -assert-count 0 t:$_MUX_
+select -assert-count 0 t:$_MUX4_
+select -assert-count 1 t:$_MUX8_
+select -assert-count 0 t:$_MUX16_
+techmap -map +/simcells.v t:$_MUX8_
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+## MUX4 in MUX8 :: https://github.com/YosysHQ/yosys/issues/1132
+
+design -reset
+read_verilog -formal <<EOT
+module mux4in8(input [3:0] i, input [1:0] s, output o);
+ assign o = s[1] ? (s[0] ? i[3] : i[2]) : (s[0] ? i[1] : i[0]);
+endmodule
+EOT
+prep
+design -save gold
+
+techmap
+muxcover -mux8=299 -nodecode
+clean
+opt_expr -mux_bool
+select -assert-count 0 t:$_MUX_
+select -assert-count 0 t:$_MUX4_
+select -assert-count 1 t:$_MUX8_
+select -assert-count 0 t:$_MUX16_
+techmap -map +/simcells.v t:$_MUX8_
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+## MUX2 in MUX16 :: https://github.com/YosysHQ/yosys/issues/1132
+
+design -reset
+read_verilog -formal <<EOT
+module mux2in16(input [1:0] i, input s, output o);
+ assign o = s ? i[1] : i[0];
+endmodule
+EOT
+prep
+design -save gold
+
+techmap
+muxcover -mux16=99 -nodecode
+clean
+opt_expr -mux_bool
+select -assert-count 0 t:$_MUX_
+select -assert-count 0 t:$_MUX4_
+select -assert-count 0 t:$_MUX8_
+select -assert-count 1 t:$_MUX16_
+techmap -map +/simcells.v t:$_MUX16_
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+## MUX4 in MUX16 :: https://github.com/YosysHQ/yosys/issues/1132
+
+design -reset
+read_verilog -formal <<EOT
+module mux4in16(input [3:0] i, input [1:0] s, output o);
+ assign o = s[1] ? (s[0] ? i[3] : i[2]) : (s[0] ? i[1] : i[0]);
+endmodule
+EOT
+prep
+design -save gold
+
+techmap
+muxcover -mux16=299 -nodecode
+clean
+opt_expr -mux_bool
+select -assert-count 0 t:$_MUX_
+select -assert-count 0 t:$_MUX4_
+select -assert-count 0 t:$_MUX8_
+select -assert-count 1 t:$_MUX16_
+techmap -map +/simcells.v t:$_MUX16_
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+## MUX8 in MUX16 :: https://github.com/YosysHQ/yosys/issues/1132
+
+design -reset
+read_verilog -formal <<EOT
+module mux4in16(input [7:0] i, input [2:0] s, output o);
+ assign o = s[2] ? s[1] ? (s[0] ? i[3] : i[2]) : (s[0] ? i[1] : i[0])
+ : s[1] ? (s[0] ? i[7] : i[6]) : (s[0] ? i[5] : i[4]);
+endmodule
+EOT
+prep
+design -save gold
+
+techmap
+muxcover -mux16=699 -nodecode
+clean
+opt_expr -mux_bool
+select -assert-count 0 t:$_MUX_
+select -assert-count 0 t:$_MUX4_
+select -assert-count 0 t:$_MUX8_
+select -assert-count 1 t:$_MUX16_
+techmap -map +/simcells.v t:$_MUX16_
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+## mux_if_bal_5_1 :: https://github.com/YosysHQ/yosys/issues/1132
+
+design -reset
+read_verilog -formal <<EOT
+module mux_if_bal_5_1 #(parameter N=5, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
+always @* begin
+ o <= {{W{{1'bx}}}};
+ if (s[0] == 1'b0)
+ if (s[1] == 1'b0)
+ if (s[2] == 1'b0)
+ o <= i[0*W+:W];
+ else
+ o <= i[1*W+:W];
+ else
+ if (s[2] == 1'b0)
+ o <= i[2*W+:W];
+ else
+ o <= i[3*W+:W];
+ else
+ if (s[1] == 1'b0)
+ if (s[2] == 1'b0)
+ o <= i[4*W+:W];
+end
+endmodule
+EOT
+prep
+design -save gold
+
+wreduce
+opt -full
+techmap
+muxcover -mux8=350
+clean
+opt_expr -mux_bool
+select -assert-count 0 t:$_MUX_
+select -assert-count 0 t:$_MUX4_
+select -assert-count 1 t:$_MUX8_
+select -assert-count 0 t:$_MUX16_
+techmap -map +/simcells.v t:$_MUX8_
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+## mux_if_bal_5_1 (nodecode) :: https://github.com/YosysHQ/yosys/issues/1132
+design -load gold
+
+wreduce
+opt -full
+techmap
+muxcover -mux8=350 -nodecode
+clean
+opt_expr -mux_bool
+select -assert-count 0 t:$_MUX_
+select -assert-count 0 t:$_MUX4_
+select -assert-count 1 t:$_MUX8_
+select -assert-count 0 t:$_MUX16_
+techmap -map +/simcells.v t:$_MUX8_
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+## mux_if_bal_9_1 :: https://github.com/YosysHQ/yosys/issues/1132
+
+design -reset
+read_verilog -formal <<EOT
+module mux_if_bal_9_1 #(parameter N=9, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
+always @* begin
+ o <= {{W{{1'bx}}}};
+ if (s[3] == 1'b0)
+ if (s[2] == 1'b0)
+ if (s[1] == 1'b0)
+ if (s[0] == 1'b0)
+ o <= i[0*W+:W];
+ else
+ o <= i[1*W+:W];
+ else
+ if (s[0] == 1'b0)
+ o <= i[2*W+:W];
+ else
+ o <= i[3*W+:W];
+ else
+ if (s[1] == 1'b0)
+ if (s[0] == 1'b0)
+ o <= i[4*W+:W];
+ else
+ o <= i[5*W+:W];
+ else
+ if (s[0] == 1'b0)
+ o <= i[6*W+:W];
+ else
+ o <= i[7*W+:W];
+ else
+ if (s[2] == 1'b0)
+ if (s[1] == 1'b0)
+ if (s[0] == 1'b0)
+ o <= i[8*W+:W];
+end
+endmodule
+EOT
+prep
+design -save gold
+
+wreduce
+opt -full
+techmap
+muxcover -mux16=750
+clean
+opt_expr -mux_bool
+select -assert-count 0 t:$_MUX_
+select -assert-count 0 t:$_MUX4_
+select -assert-count 0 t:$_MUX8_
+select -assert-count 1 t:$_MUX16_
+techmap -map +/simcells.v t:$_MUX16_
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+## mux_if_bal_9_1 (nodecode) :: https://github.com/YosysHQ/yosys/issues/1132
+
+design -load gold
+
+wreduce
+opt -full
+techmap
+muxcover -mux16=750 -nodecode
+clean
+opt_expr -mux_bool
+select -assert-count 0 t:$_MUX_
+select -assert-count 0 t:$_MUX4_
+select -assert-count 0 t:$_MUX8_
+select -assert-count 1 t:$_MUX16_
+techmap -map +/simcells.v t:$_MUX16_
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold gate miter
+sat -verify -prove-asserts -show-ports miter