Add $bmux and $demux cells.
authorMarcelina Kościelnicka <mwk@0x04.net>
Mon, 24 Jan 2022 15:02:29 +0000 (16:02 +0100)
committerMarcelina Kościelnicka <mwk@0x04.net>
Fri, 28 Jan 2022 22:34:41 +0000 (23:34 +0100)
25 files changed:
backends/btor/btor.cc
backends/cxxrtl/cxxrtl.h
backends/cxxrtl/cxxrtl_backend.cc
backends/firrtl/firrtl.cc
backends/smt2/smt2.cc
backends/smv/smv.cc
backends/verilog/verilog_backend.cc
kernel/calc.cc
kernel/celledges.cc
kernel/celltypes.h
kernel/consteval.h
kernel/qcsat.cc
kernel/rtlil.cc
kernel/rtlil.h
kernel/satgen.cc
passes/cmds/clean_zerowidth.cc
passes/cmds/stat.cc
passes/sat/sim.cc
passes/techmap/Makefile.inc
passes/techmap/bmuxmap.cc [new file with mode: 0644]
passes/techmap/demuxmap.cc [new file with mode: 0644]
passes/techmap/simplemap.cc
passes/tests/test_cell.cc
techlibs/common/simlib.v
techlibs/common/techmap.v

index 96df54a2c8e1e4ead82a38957ecdbb700c740b8e..d62cc4c3dfb5956f21ddc39d292a57f3456d32e6 100644 (file)
@@ -1399,6 +1399,11 @@ struct BtorBackend : public Backend {
 
                log_header(design, "Executing BTOR backend.\n");
 
+               log_push();
+               Pass::call(design, "bmuxmap");
+               Pass::call(design, "demuxmap");
+               log_pop();
+
                size_t argidx;
                for (argidx = 1; argidx < args.size(); argidx++)
                {
index 3e1357498cce15d312f750a781d43431e197365d..b4ffa87cd66c6eaaf1911a2c5e83e524ac0baa5d 100644 (file)
@@ -457,6 +457,42 @@ struct value : public expr_base<value<Bits>> {
                return shr<AmountBits, /*Signed=*/true>(amount);
        }
 
+       template<size_t ResultBits, size_t SelBits>
+       value<ResultBits> bmux(const value<SelBits> &sel) const {
+               static_assert(ResultBits << SelBits == Bits, "invalid sizes used in bmux()");
+               size_t amount = sel.data[0] * ResultBits;
+               size_t shift_chunks = amount / chunk::bits;
+               size_t shift_bits   = amount % chunk::bits;
+               value<ResultBits> result;
+               chunk::type carry = 0;
+               if (ResultBits % chunk::bits + shift_bits > chunk::bits)
+                       carry = data[result.chunks + shift_chunks] << (chunk::bits - shift_bits);
+               for (size_t n = 0; n < result.chunks; n++) {
+                       result.data[result.chunks - 1 - n] = carry | (data[result.chunks + shift_chunks - 1 - n] >> shift_bits);
+                       carry = (shift_bits == 0) ? 0
+                               : data[result.chunks + shift_chunks - 1 - n] << (chunk::bits - shift_bits);
+               }
+               return result;
+       }
+
+       template<size_t ResultBits, size_t SelBits>
+       value<ResultBits> demux(const value<SelBits> &sel) const {
+               static_assert(Bits << SelBits == ResultBits, "invalid sizes used in demux()");
+               size_t amount = sel.data[0] * Bits;
+               size_t shift_chunks = amount / chunk::bits;
+               size_t shift_bits   = amount % chunk::bits;
+               value<ResultBits> result;
+               chunk::type carry = 0;
+               for (size_t n = 0; n < chunks; n++) {
+                       result.data[shift_chunks + n] = (data[n] << shift_bits) | carry;
+                       carry = (shift_bits == 0) ? 0
+                               : data[n] >> (chunk::bits - shift_bits);
+               }
+               if (Bits % chunk::bits + shift_bits > chunk::bits)
+                       result.data[shift_chunks + chunks] = carry;
+               return result;
+       }
+
        size_t ctpop() const {
                size_t count = 0;
                for (size_t n = 0; n < chunks; n++) {
index 7a336f8c10d25d0a2819c1eeb7ec4cb014ffc6cb..404755b1e27d9fbedbfa3968da1e562b03a92900 100644 (file)
@@ -198,7 +198,7 @@ bool is_extending_cell(RTLIL::IdString type)
 bool is_inlinable_cell(RTLIL::IdString type)
 {
        return is_unary_cell(type) || is_binary_cell(type) || type.in(
-               ID($mux), ID($concat), ID($slice), ID($pmux));
+               ID($mux), ID($concat), ID($slice), ID($pmux), ID($bmux), ID($demux));
 }
 
 bool is_ff_cell(RTLIL::IdString type)
@@ -1154,6 +1154,22 @@ struct CxxrtlWorker {
                        for (int part = 0; part < s_width; part++) {
                                f << ")";
                        }
+               // Big muxes
+               } else if (cell->type == ID($bmux)) {
+                       dump_sigspec_rhs(cell->getPort(ID::A), for_debug);
+                       f << ".bmux<";
+                       f << cell->getParam(ID::WIDTH).as_int();
+                       f << ">(";
+                       dump_sigspec_rhs(cell->getPort(ID::S), for_debug);
+                       f << ").val()";
+               // Demuxes
+               } else if (cell->type == ID($demux)) {
+                       dump_sigspec_rhs(cell->getPort(ID::A), for_debug);
+                       f << ".demux<";
+                       f << GetSize(cell->getPort(ID::Y));
+                       f << ">(";
+                       dump_sigspec_rhs(cell->getPort(ID::S), for_debug);
+                       f << ").val()";
                // Concats
                } else if (cell->type == ID($concat)) {
                        dump_sigspec_rhs(cell->getPort(ID::B), for_debug);
index 7abe584c9cc7547d1032b887631bba32e578507e..85c44824fd526c3474e9b74a41f8e98c5fabc388 100644 (file)
@@ -1188,6 +1188,8 @@ struct FirrtlBackend : public Backend {
                log("Write a FIRRTL netlist of the current design.\n");
                log("The following commands are executed by this command:\n");
                log("        pmuxtree\n");
+               log("        bmuxmap\n");
+               log("        demuxmap\n");
                log("\n");
        }
        void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override
@@ -1210,7 +1212,9 @@ struct FirrtlBackend : public Backend {
                log_header(design, "Executing FIRRTL backend.\n");
                log_push();
 
-               Pass::call(design, stringf("pmuxtree"));
+               Pass::call(design, "pmuxtree");
+               Pass::call(design, "bmuxmap");
+               Pass::call(design, "demuxmap");
 
                namecache.clear();
                autoid_counter = 0;
index f2fa003bcb665bc2d29409b1d0c711cb67121d24..a928419a1b6437c237e2e076132c4229085e341c 100644 (file)
@@ -1531,6 +1531,11 @@ struct Smt2Backend : public Backend {
 
                log_header(design, "Executing SMT2 backend.\n");
 
+               log_push();
+               Pass::call(design, "bmuxmap");
+               Pass::call(design, "demuxmap");
+               log_pop();
+
                size_t argidx;
                for (argidx = 1; argidx < args.size(); argidx++)
                {
index 7bace69120f43e0ba91ad9405f423c43d020ee5b..7d4f94adcc3e946fe2c24c764a3c20870f23d40d 100644 (file)
@@ -741,6 +741,11 @@ struct SmvBackend : public Backend {
 
                log_header(design, "Executing SMV backend.\n");
 
+               log_push();
+               Pass::call(design, "bmuxmap");
+               Pass::call(design, "demuxmap");
+               log_pop();
+
                size_t argidx;
                for (argidx = 1; argidx < args.size(); argidx++)
                {
index e4781ef3e8744d961cec7e72b0c94fea1d095000..32003cf549d26f4b9f24eca890c86fa8096d8d7b 100644 (file)
@@ -2300,7 +2300,11 @@ struct VerilogBackend : public Backend {
                        extmem_prefix = filename.substr(0, filename.rfind('.'));
                }
 
+               log_push();
+               Pass::call(design, "bmuxmap");
+               Pass::call(design, "demuxmap");
                Pass::call(design, "clean_zerowidth");
+               log_pop();
 
                design->sort();
 
index 1e6410f7dbf0e90de971b99523f363da04c740bc..0865db5261937c821af24d5678da7d9fee89475d 100644 (file)
@@ -609,5 +609,56 @@ RTLIL::Const RTLIL::const_neg(const RTLIL::Const &arg1, const RTLIL::Const&, boo
        return RTLIL::const_sub(zero, arg1_ext, true, signed1, result_len);
 }
 
+RTLIL::Const RTLIL::const_bmux(const RTLIL::Const &arg1, const RTLIL::Const &arg2)
+{
+       std::vector<RTLIL::State> t = arg1.bits;
+
+       for (int i = GetSize(arg2)-1; i >= 0; i--)
+       {
+               RTLIL::State sel = arg2.bits.at(i);
+               std::vector<RTLIL::State> new_t;
+               if (sel == State::S0)
+                       new_t = std::vector<RTLIL::State>(t.begin(), t.begin() + GetSize(t)/2);
+               else if (sel == State::S1)
+                       new_t = std::vector<RTLIL::State>(t.begin() + GetSize(t)/2, t.end());
+               else
+                       for (int j = 0; j < GetSize(t)/2; j++)
+                               new_t.push_back(t[j] == t[j + GetSize(t)/2] ? t[j] : RTLIL::Sx);
+               t.swap(new_t);
+       }
+
+       return t;
+}
+
+RTLIL::Const RTLIL::const_demux(const RTLIL::Const &arg1, const RTLIL::Const &arg2)
+{
+       int width = GetSize(arg1);
+       int s_width = GetSize(arg2);
+       std::vector<RTLIL::State> res;
+       for (int i = 0; i < (1 << s_width); i++)
+       {
+               bool ne = false;
+               bool x = false;
+               for (int j = 0; j < s_width; j++) {
+                       bool bit = i & 1 << j;
+                       if (arg2[j] == (bit ? RTLIL::S0 : RTLIL::S1))
+                               ne = true;
+                       else if (arg2[j] != RTLIL::S0 && arg2[j] != RTLIL::S1)
+                               x = true;
+               }
+               if (ne) {
+                       for (int j = 0; j < width; j++)
+                               res.push_back(State::S0);
+               } else if (x) {
+                       for (int j = 0; j < width; j++)
+                               res.push_back(arg1.bits[j] == State::S0 ? State::S0 : State::Sx);
+               } else {
+                       for (int j = 0; j < width; j++)
+                               res.push_back(arg1.bits[j]);
+               }
+       }
+       return res;
+}
+
 YOSYS_NAMESPACE_END
 
index af07d26b316c04e219b8f134b22e393e90a688b4..c43ba8db330cb079fd2dcf5ef9c6c81155f4aed5 100644 (file)
@@ -142,6 +142,36 @@ void mux_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
        }
 }
 
+void bmux_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
+{
+       int width = GetSize(cell->getPort(ID::Y));
+       int a_width = GetSize(cell->getPort(ID::A));
+       int s_width = GetSize(cell->getPort(ID::S));
+
+       for (int i = 0; i < width; i++)
+       {
+               for (int k = i; k < a_width; k += width)
+                       db->add_edge(cell, ID::A, k, ID::Y, i, -1);
+
+               for (int k = 0; k < s_width; k++)
+                       db->add_edge(cell, ID::S, k, ID::Y, i, -1);
+       }
+}
+
+void demux_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
+{
+       int width = GetSize(cell->getPort(ID::Y));
+       int a_width = GetSize(cell->getPort(ID::A));
+       int s_width = GetSize(cell->getPort(ID::S));
+
+       for (int i = 0; i < width; i++)
+       {
+               db->add_edge(cell, ID::A, i % a_width, ID::Y, i, -1);
+               for (int k = 0; k < s_width; k++)
+                       db->add_edge(cell, ID::S, k, ID::Y, i, -1);
+       }
+}
+
 PRIVATE_NAMESPACE_END
 
 bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL::Cell *cell)
@@ -187,6 +217,16 @@ bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL
                return true;
        }
 
+       if (cell->type == ID($bmux)) {
+               bmux_op(this, cell);
+               return true;
+       }
+
+       if (cell->type == ID($demux)) {
+               demux_op(this, cell);
+               return true;
+       }
+
        // FIXME: $mul $div $mod $divfloor $modfloor $slice $concat
        // FIXME: $lut $sop $alu $lcu $macc $fa
 
index 879ac0edc0b34bb0bcdfb250b3d75614992f1c21..7e9cfb38d2d99f8a6a949acf712ed63bef23db52 100644 (file)
@@ -127,6 +127,9 @@ struct CellTypes
                for (auto type : std::vector<RTLIL::IdString>({ID($mux), ID($pmux)}))
                        setup_type(type, {ID::A, ID::B, ID::S}, {ID::Y}, true);
 
+               for (auto type : std::vector<RTLIL::IdString>({ID($bmux), ID($demux)}))
+                       setup_type(type, {ID::A, ID::S}, {ID::Y}, true);
+
                setup_type(ID($lcu), {ID::P, ID::G, ID::CI}, {ID::CO}, true);
                setup_type(ID($alu), {ID::A, ID::B, ID::CI, ID::BI}, {ID::X, ID::Y, ID::CO}, true);
                setup_type(ID($fa), {ID::A, ID::B, ID::C}, {ID::X, ID::Y}, true);
@@ -411,6 +414,16 @@ struct CellTypes
                        return ret;
                }
 
+               if (cell->type == ID($bmux))
+               {
+                       return const_bmux(arg1, arg2);
+               }
+
+               if (cell->type == ID($demux))
+               {
+                       return const_demux(arg1, arg2);
+               }
+
                if (cell->type == ID($lut))
                {
                        int width = cell->parameters.at(ID::WIDTH).as_int();
@@ -420,21 +433,7 @@ struct CellTypes
                                t.push_back(State::S0);
                        t.resize(1 << width);
 
-                       for (int i = width-1; i >= 0; i--) {
-                               RTLIL::State sel = arg1.bits.at(i);
-                               std::vector<RTLIL::State> new_t;
-                               if (sel == State::S0)
-                                       new_t = std::vector<RTLIL::State>(t.begin(), t.begin() + GetSize(t)/2);
-                               else if (sel == State::S1)
-                                       new_t = std::vector<RTLIL::State>(t.begin() + GetSize(t)/2, t.end());
-                               else
-                                       for (int j = 0; j < GetSize(t)/2; j++)
-                                               new_t.push_back(t[j] == t[j + GetSize(t)/2] ? t[j] : RTLIL::Sx);
-                               t.swap(new_t);
-                       }
-
-                       log_assert(GetSize(t) == 1);
-                       return t;
+                       return const_bmux(t, arg1);
                }
 
                if (cell->type == ID($sop))
index 3edfc490cea587087ffa2036e4d9256b37547c55..642eb42b25d0f7d0692865f9a3e49e40a8f230ac 100644 (file)
@@ -135,8 +135,6 @@ struct ConstEval
 
                if (cell->hasPort(ID::S)) {
                        sig_s = cell->getPort(ID::S);
-                       if (!eval(sig_s, undef, cell))
-                               return false;
                }
 
                if (cell->hasPort(ID::A))
@@ -151,6 +149,9 @@ struct ConstEval
                        int count_maybe_set_s_bits = 0;
                        int count_set_s_bits = 0;
 
+                       if (!eval(sig_s, undef, cell))
+                               return false;
+
                        for (int i = 0; i < sig_s.size(); i++)
                        {
                                RTLIL::State s_bit = sig_s.extract(i, 1).as_const().bits.at(0);
@@ -198,6 +199,36 @@ struct ConstEval
                        else
                                set(sig_y, y_values.front());
                }
+               else if (cell->type == ID($bmux))
+               {
+                       if (!eval(sig_s, undef, cell))
+                               return false;
+
+                       if (sig_s.is_fully_def()) {
+                               int sel = sig_s.as_int();
+                               int width = GetSize(sig_y);
+                               SigSpec res = sig_a.extract(sel * width, width);
+                               if (!eval(res, undef, cell))
+                                       return false;
+                               set(sig_y, res.as_const());
+                       } else {
+                               if (!eval(sig_a, undef, cell))
+                                       return false;
+                               set(sig_y, const_bmux(sig_a.as_const(), sig_s.as_const()));
+                       }
+               }
+               else if (cell->type == ID($demux))
+               {
+                       if (!eval(sig_a, undef, cell))
+                               return false;
+                       if (sig_a.is_fully_zero()) {
+                               set(sig_y, Const(0, GetSize(sig_y)));
+                       } else {
+                               if (!eval(sig_s, undef, cell))
+                                       return false;
+                               set(sig_y, const_demux(sig_a.as_const(), sig_s.as_const()));
+                       }
+               }
                else if (cell->type == ID($fa))
                {
                        RTLIL::SigSpec sig_c = cell->getPort(ID::C);
index b7da958dba19f1013ddd11453803a6c0ba0ead0a..aaee984fbaace7aa6cda5c3ae7fd698a2e553e1b 100644 (file)
@@ -84,7 +84,7 @@ int QuickConeSat::cell_complexity(RTLIL::Cell *cell)
                        ID($reduce_xnor), ID($reduce_bool),
                        ID($logic_not), ID($logic_and), ID($logic_or),
                        ID($eq), ID($ne), ID($eqx), ID($nex), ID($fa),
-                       ID($mux), ID($pmux), ID($lut), ID($sop),
+                       ID($mux), ID($pmux), ID($bmux), ID($demux), ID($lut), ID($sop),
                        ID($_NOT_), ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_),
                        ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_),
                        ID($_MUX_), ID($_NMUX_), ID($_MUX4_), ID($_MUX8_), ID($_MUX16_),
index cd0f5ab1246c8cd6aed4a57cfe500326f45c82f1..a89edd992644effb397d68d086e4e096b26f7f0f 100644 (file)
@@ -1251,6 +1251,22 @@ namespace {
                                return;
                        }
 
+                       if (cell->type == ID($bmux)) {
+                               port(ID::A, param(ID::WIDTH) << param(ID::S_WIDTH));
+                               port(ID::S, param(ID::S_WIDTH));
+                               port(ID::Y, param(ID::WIDTH));
+                               check_expected();
+                               return;
+                       }
+
+                       if (cell->type == ID($demux)) {
+                               port(ID::A, param(ID::WIDTH));
+                               port(ID::S, param(ID::S_WIDTH));
+                               port(ID::Y, param(ID::WIDTH) << param(ID::S_WIDTH));
+                               check_expected();
+                               return;
+                       }
+
                        if (cell->type == ID($lut)) {
                                param(ID::LUT);
                                port(ID::A, param(ID::WIDTH));
@@ -2444,6 +2460,26 @@ DEF_METHOD(Mux,      ID($mux),        0)
 DEF_METHOD(Pmux,     ID($pmux),       1)
 #undef DEF_METHOD
 
+#define DEF_METHOD(_func, _type, _demux) \
+       RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src) { \
+               RTLIL::Cell *cell = addCell(name, _type);                 \
+               cell->parameters[ID::WIDTH] = _demux ? sig_a.size() : sig_y.size(); \
+               cell->parameters[ID::S_WIDTH] = sig_s.size();             \
+               cell->setPort(ID::A, sig_a);                              \
+               cell->setPort(ID::S, sig_s);                              \
+               cell->setPort(ID::Y, sig_y);                              \
+               cell->set_src_attribute(src);                             \
+               return cell;                                              \
+       } \
+       RTLIL::SigSpec RTLIL::Module::_func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const std::string &src) { \
+               RTLIL::SigSpec sig_y = addWire(NEW_ID, _demux ? sig_a.size() << sig_s.size() : sig_a.size() >> sig_s.size()); \
+               add ## _func(name, sig_a, sig_s, sig_y, src);             \
+               return sig_y;                                             \
+       }
+DEF_METHOD(Bmux,     ID($bmux),       0)
+DEF_METHOD(Demux,    ID($demux),      1)
+#undef DEF_METHOD
+
 #define DEF_METHOD_2(_func, _type, _P1, _P2) \
        RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, const RTLIL::SigBit &sig1, const RTLIL::SigBit &sig2, const std::string &src) { \
                RTLIL::Cell *cell = addCell(name, _type);         \
@@ -3358,14 +3394,21 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
                        type.begins_with("$verific$") || type.begins_with("$array:") || type.begins_with("$extern:"))
                return;
 
-       if (type == ID($mux) || type == ID($pmux)) {
+       if (type == ID($mux) || type == ID($pmux) || type == ID($bmux)) {
                parameters[ID::WIDTH] = GetSize(connections_[ID::Y]);
-               if (type == ID($pmux))
+               if (type != ID($mux))
                        parameters[ID::S_WIDTH] = GetSize(connections_[ID::S]);
                check();
                return;
        }
 
+       if (type == ID($demux)) {
+               parameters[ID::WIDTH] = GetSize(connections_[ID::A]);
+               parameters[ID::S_WIDTH] = GetSize(connections_[ID::S]);
+               check();
+               return;
+       }
+
        if (type == ID($lut) || type == ID($sop)) {
                parameters[ID::WIDTH] = GetSize(connections_[ID::A]);
                return;
index a562d253c900d22ed6c5ebfab05af5cdc4440192..d8300f1593ec4a3a97820025f3e4df25da70d893 100644 (file)
@@ -485,6 +485,9 @@ namespace RTLIL
        RTLIL::Const const_pos         (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
        RTLIL::Const const_neg         (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
 
+       RTLIL::Const const_bmux        (const RTLIL::Const &arg1, const RTLIL::Const &arg2);
+       RTLIL::Const const_demux       (const RTLIL::Const &arg1, const RTLIL::Const &arg2);
+
 
        // This iterator-range-pair is used for Design::modules(), Module::wires() and Module::cells().
        // It maintains a reference counter that is used to make sure that the container is not modified while being iterated over.
@@ -1296,6 +1299,8 @@ public:
 
        RTLIL::Cell* addMux  (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = "");
        RTLIL::Cell* addPmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = "");
+       RTLIL::Cell* addBmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = "");
+       RTLIL::Cell* addDemux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = "");
 
        RTLIL::Cell* addSlice  (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, RTLIL::Const offset, const std::string &src = "");
        RTLIL::Cell* addConcat (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const std::string &src = "");
@@ -1421,6 +1426,8 @@ public:
 
        RTLIL::SigSpec Mux      (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const std::string &src = "");
        RTLIL::SigSpec Pmux     (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const std::string &src = "");
+       RTLIL::SigSpec Bmux     (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const std::string &src = "");
+       RTLIL::SigSpec Demux     (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const std::string &src = "");
 
        RTLIL::SigBit BufGate    (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const std::string &src = "");
        RTLIL::SigBit NotGate    (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const std::string &src = "");
index 214826f5ab58be12dcf2e34e3199a8c1dba711e2..9c40ec66d8b432c30b9d1e12993333007b6f3b08 100644 (file)
@@ -252,6 +252,106 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
                return true;
        }
 
+       if (cell->type == ID($bmux))
+       {
+               std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+               std::vector<int> s = importDefSigSpec(cell->getPort(ID::S), timestep);
+               std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
+               std::vector<int> undef_a, undef_s, undef_y;
+
+               if (model_undef)
+               {
+                       undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+                       undef_s = importUndefSigSpec(cell->getPort(ID::S), timestep);
+                       undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
+               }
+
+               if (GetSize(s) == 0) {
+                       ez->vec_set(a, y);
+                       if (model_undef)
+                               ez->vec_set(undef_a, undef_y);
+               } else {
+                       for (int i = GetSize(s)-1; i >= 0; i--)
+                       {
+                               std::vector<int> out = (i == 0) ? y : ez->vec_var(a.size() / 2);
+                               std::vector<int> yy = model_undef ? ez->vec_var(out.size()) : out;
+
+                               std::vector<int> a0(a.begin(), a.begin() + a.size() / 2);
+                               std::vector<int> a1(a.begin() + a.size() / 2, a.end());
+                               ez->assume(ez->vec_eq(ez->vec_ite(s.at(i), a1, a0), yy));
+
+                               if (model_undef)
+                               {
+                                       std::vector<int> undef_out = (i == 0) ? undef_y : ez->vec_var(a.size() / 2);
+                                       std::vector<int> undef_a0(undef_a.begin(), undef_a.begin() + a.size() / 2);
+                                       std::vector<int> undef_a1(undef_a.begin() + a.size() / 2, undef_a.end());
+                                       std::vector<int> unequal_ab = ez->vec_not(ez->vec_iff(a0, a1));
+                                       std::vector<int> undef_ab = ez->vec_or(unequal_ab, ez->vec_or(undef_a0, undef_a1));
+                                       std::vector<int> yX = ez->vec_ite(undef_s.at(i), undef_ab, ez->vec_ite(s.at(i), undef_a1, undef_a0));
+                                       ez->assume(ez->vec_eq(yX, undef_out));
+                                       undefGating(out, yy, undef_out);
+
+                                       undef_a = undef_out;
+                               }
+
+                               a = out;
+                       }
+               }
+               return true;
+       }
+
+       if (cell->type == ID($demux))
+       {
+               std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+               std::vector<int> s = importDefSigSpec(cell->getPort(ID::S), timestep);
+               std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
+               std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
+               std::vector<int> undef_a, undef_s, undef_y;
+
+               if (model_undef)
+               {
+                       undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+                       undef_s = importUndefSigSpec(cell->getPort(ID::S), timestep);
+                       undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
+               }
+
+               if (GetSize(s) == 0) {
+                       ez->vec_set(a, y);
+                       if (model_undef)
+                               ez->vec_set(undef_a, undef_y);
+               } else {
+                       for (int i = 0; i < (1 << GetSize(s)); i++)
+                       {
+                               std::vector<int> ss;
+                               for (int j = 0; j < GetSize(s); j++) {
+                                       if (i & 1 << j)
+                                               ss.push_back(s[j]);
+                                       else
+                                               ss.push_back(ez->NOT(s[j]));
+                               }
+                               int sss = ez->expression(ezSAT::OpAnd, ss);
+
+                               for (int j = 0; j < GetSize(a); j++) {
+                                       ez->SET(ez->AND(sss, a[j]), yy.at(i * GetSize(a) + j));
+                               }
+
+                               if (model_undef)
+                               {
+                                       int s0 = ez->expression(ezSAT::OpOr, ez->vec_and(ez->vec_not(ss), ez->vec_not(undef_s)));
+                                       int us = ez->AND(ez->NOT(s0), ez->expression(ezSAT::OpOr, undef_s));
+                                       for (int j = 0; j < GetSize(a); j++) {
+                                               int a0 = ez->AND(ez->NOT(a[j]), ez->NOT(undef_a[j]));
+                                               int yX = ez->AND(ez->OR(us, undef_a[j]), ez->NOT(ez->OR(s0, a0)));
+                                               ez->SET(yX, undef_y.at(i * GetSize(a) + j));
+                                       }
+                               }
+                       }
+                       if (model_undef)
+                               undefGating(y, yy, undef_y);
+               }
+               return true;
+       }
+
        if (cell->type == ID($pmux))
        {
                std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
index 4e7c68093ad3e1bd1e7256501fe79c5677162af8..bac6b1521328c1bfc258c825da06f14a2fa1f0f9 100644 (file)
@@ -80,7 +80,7 @@ struct CleanZeroWidthPass : public Pass {
                                        if (GetSize(cell->getPort(ID::Q)) == 0) {
                                                module->remove(cell);
                                        }
-                               } else if (cell->type == ID($pmux)) {
+                               } else if (cell->type.in(ID($pmux), ID($bmux), ID($demux))) {
                                        // Remove altogether if WIDTH is 0, replace with
                                        // a connection if S_WIDTH is 0.
                                        if (cell->getParam(ID::WIDTH).as_int() == 0) {
index 14a27ed99952d03129187eca0aeee2f114c7395a..fffdda48e71b01b9f55ed78be22d64fad9b4ad5e 100644 (file)
@@ -117,6 +117,10 @@ struct statdata_t
                                }
                                else if (cell_type.in(ID($mux), ID($pmux)))
                                        cell_type = stringf("%s_%d", cell_type.c_str(), GetSize(cell->getPort(ID::Y)));
+                               else if (cell_type == ID($bmux))
+                                       cell_type = stringf("%s_%d_%d", cell_type.c_str(), GetSize(cell->getPort(ID::Y)), GetSize(cell->getPort(ID::S)));
+                               else if (cell_type == ID($demux))
+                                       cell_type = stringf("%s_%d_%d", cell_type.c_str(), GetSize(cell->getPort(ID::A)), GetSize(cell->getPort(ID::S)));
                                else if (cell_type.in(
                                                ID($sr), ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($dffsre),
                                                ID($adff), ID($adffe), ID($sdff), ID($sdffe), ID($sdffce),
index 4e158da62922e29ac142dbf8db4c44e9341d7f84..8a44830d210f2acf2819964eea45d9eb69916cd4 100644 (file)
@@ -313,6 +313,12 @@ struct SimInstance
                                return;
                        }
 
+                       // (A,S -> Y) cells
+                       if (has_a && !has_b && !has_c && !has_d && has_s && has_y) {
+                               set_state(sig_y, CellTypes::eval(cell, get_state(sig_a), get_state(sig_s)));
+                               return;
+                       }
+
                        // (A,B,S -> Y) cells
                        if (has_a && has_b && !has_c && !has_d && has_s && has_y) {
                                set_state(sig_y, CellTypes::eval(cell, get_state(sig_a), get_state(sig_b), get_state(sig_s)));
index 03569960380e1792e9fcc498b46c4eaf94b3f6ca..98ccfc303dc723c126fca63ee12abb6d7f01f654 100644 (file)
@@ -29,6 +29,8 @@ OBJS += passes/techmap/extract_reduce.o
 OBJS += passes/techmap/alumacc.o
 OBJS += passes/techmap/dffinit.o
 OBJS += passes/techmap/pmuxtree.o
+OBJS += passes/techmap/bmuxmap.o
+OBJS += passes/techmap/demuxmap.o
 OBJS += passes/techmap/muxcover.o
 OBJS += passes/techmap/aigmap.o
 OBJS += passes/techmap/tribuf.o
diff --git a/passes/techmap/bmuxmap.cc b/passes/techmap/bmuxmap.cc
new file mode 100644 (file)
index 0000000..03673c2
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2022  Marcelina Kościelnicka <mwk@0x04.net>
+ *
+ *  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.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct BmuxmapPass : public Pass {
+       BmuxmapPass() : Pass("bmuxmap", "transform $bmux cells to trees of $mux cells") { }
+       void help() override
+       {
+               //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+               log("\n");
+               log("    bmuxmap [selection]\n");
+               log("\n");
+               log("This pass transforms $bmux cells to trees of $mux cells.\n");
+               log("\n");
+       }
+       void execute(std::vector<std::string> args, RTLIL::Design *design) override
+       {
+               log_header(design, "Executing BMUXMAP pass.\n");
+
+               size_t argidx;
+               for (argidx = 1; argidx < args.size(); argidx++) {
+                       break;
+               }
+               extra_args(args, argidx, design);
+
+               for (auto module : design->selected_modules())
+               for (auto cell : module->selected_cells())
+               {
+                       if (cell->type != ID($bmux))
+                               continue;
+
+                       SigSpec sel = cell->getPort(ID::S);
+                       SigSpec data = cell->getPort(ID::A);
+                       int width = GetSize(cell->getPort(ID::Y));
+
+                       for (int idx = 0; idx < GetSize(sel); idx++) {
+                               SigSpec new_data = module->addWire(NEW_ID, GetSize(data)/2);
+                               for (int i = 0; i < GetSize(new_data); i += width) {
+                                       RTLIL::Cell *mux = module->addMux(NEW_ID,
+                                                       data.extract(i*2, width),
+                                                       data.extract(i*2+width, width),
+                                                       sel[idx],
+                                                       new_data.extract(i, width));
+                                       mux->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src));
+                               }
+                               data = new_data;
+                       }
+
+                       module->connect(cell->getPort(ID::Y), data);
+                       module->remove(cell);
+               }
+       }
+} BmuxmapPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/demuxmap.cc b/passes/techmap/demuxmap.cc
new file mode 100644 (file)
index 0000000..292b18b
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2022  Marcelina Kościelnicka <mwk@0x04.net>
+ *
+ *  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.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct DemuxmapPass : public Pass {
+       DemuxmapPass() : Pass("demuxmap", "transform $demux cells to $eq + $mux cells") { }
+       void help() override
+       {
+               //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+               log("\n");
+               log("    demuxmap [selection]\n");
+               log("\n");
+               log("This pass transforms $demux cells to a bunch of equality comparisons.\n");
+               log("\n");
+       }
+       void execute(std::vector<std::string> args, RTLIL::Design *design) override
+       {
+               log_header(design, "Executing DEMUXMAP pass.\n");
+
+               size_t argidx;
+               for (argidx = 1; argidx < args.size(); argidx++) {
+                       break;
+               }
+               extra_args(args, argidx, design);
+
+               for (auto module : design->selected_modules())
+               for (auto cell : module->selected_cells())
+               {
+                       if (cell->type != ID($demux))
+                               continue;
+
+                       SigSpec sel = cell->getPort(ID::S);
+                       SigSpec data = cell->getPort(ID::A);
+                       SigSpec out = cell->getPort(ID::Y);
+                       int width = GetSize(cell->getPort(ID::A));
+
+                       for (int i = 0; i < 1 << GetSize(sel); i++) {
+                               if (width == 1 && data == State::S1) {
+                                       RTLIL::Cell *eq_cell = module->addEq(NEW_ID, sel, Const(i, GetSize(sel)), out[i]);
+                                       eq_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src));
+                               } else {
+                                       Wire *eq = module->addWire(NEW_ID);
+                                       RTLIL::Cell *eq_cell = module->addEq(NEW_ID, sel, Const(i, GetSize(sel)), eq);
+                                       eq_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src));
+                                       RTLIL::Cell *mux = module->addMux(NEW_ID,
+                                                       Const(State::S0, width),
+                                                       data,
+                                                       eq,
+                                                       out.extract(i*width, width));
+                                       mux->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src));
+                               }
+                       }
+
+                       module->remove(cell);
+               }
+       }
+} DemuxmapPass;
+
+PRIVATE_NAMESPACE_END
index 68f44cf6d7543865fd2cff2f989909c37dc60bc7..7d8dba43926ae9e5a4b7e044cf9f1119b22f9fa4 100644 (file)
@@ -299,6 +299,30 @@ void simplemap_tribuf(RTLIL::Module *module, RTLIL::Cell *cell)
        }
 }
 
+void simplemap_bmux(RTLIL::Module *module, RTLIL::Cell *cell)
+{
+       SigSpec sel = cell->getPort(ID::S);
+       SigSpec data = cell->getPort(ID::A);
+       int width = GetSize(cell->getPort(ID::Y));
+
+       for (int idx = 0; idx < GetSize(sel); idx++) {
+               SigSpec new_data = module->addWire(NEW_ID, GetSize(data)/2);
+               for (int i = 0; i < GetSize(new_data); i += width) {
+                       for (int k = 0; k < width; k++) {
+                               RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_));
+                               gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src));
+                               gate->setPort(ID::A, data[i*2+k]);
+                               gate->setPort(ID::B, data[i*2+width+k]);
+                               gate->setPort(ID::S, sel[idx]);
+                               gate->setPort(ID::Y, new_data[i+k]);
+                       }
+               }
+               data = new_data;
+       }
+
+       module->connect(cell->getPort(ID::Y), data);
+}
+
 void simplemap_lut(RTLIL::Module *module, RTLIL::Cell *cell)
 {
        SigSpec lut_ctrl = cell->getPort(ID::A);
@@ -306,7 +330,6 @@ void simplemap_lut(RTLIL::Module *module, RTLIL::Cell *cell)
        lut_data.extend_u0(1 << cell->getParam(ID::WIDTH).as_int());
 
        for (int idx = 0; GetSize(lut_data) > 1; idx++) {
-               SigSpec sig_s = lut_ctrl[idx];
                SigSpec new_lut_data = module->addWire(NEW_ID, GetSize(lut_data)/2);
                for (int i = 0; i < GetSize(lut_data); i += 2) {
                        RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_));
@@ -400,6 +423,7 @@ void simplemap_get_mappers(dict<IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)>
        mappers[ID($nex)]         = simplemap_eqne;
        mappers[ID($mux)]         = simplemap_mux;
        mappers[ID($tribuf)]      = simplemap_tribuf;
+       mappers[ID($bmux)]        = simplemap_bmux;
        mappers[ID($lut)]         = simplemap_lut;
        mappers[ID($sop)]         = simplemap_sop;
        mappers[ID($slice)]       = simplemap_slice;
index 4e437e409ab174570f3999393f970f3ad86dfc62..e21ec452cc88223f8170904350049c6eb2087892 100644 (file)
@@ -69,6 +69,48 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
                cell->setPort(ID::Y, wire);
        }
 
+       if (cell_type == ID($bmux))
+       {
+               int width = 1 + xorshift32(8);
+               int swidth = 1 + xorshift32(4);
+
+               wire = module->addWire(ID::A);
+               wire->width = width << swidth;
+               wire->port_input = true;
+               cell->setPort(ID::A, wire);
+
+               wire = module->addWire(ID::S);
+               wire->width = swidth;
+               wire->port_input = true;
+               cell->setPort(ID::S, wire);
+
+               wire = module->addWire(ID::Y);
+               wire->width = width;
+               wire->port_output = true;
+               cell->setPort(ID::Y, wire);
+       }
+
+       if (cell_type == ID($demux))
+       {
+               int width = 1 + xorshift32(8);
+               int swidth = 1 + xorshift32(6);
+
+               wire = module->addWire(ID::A);
+               wire->width = width;
+               wire->port_input = true;
+               cell->setPort(ID::A, wire);
+
+               wire = module->addWire(ID::S);
+               wire->width = swidth;
+               wire->port_input = true;
+               cell->setPort(ID::S, wire);
+
+               wire = module->addWire(ID::Y);
+               wire->width = width << swidth;
+               wire->port_output = true;
+               cell->setPort(ID::Y, wire);
+       }
+
        if (cell_type == ID($fa))
        {
                int width = 1 + xorshift32(8);
@@ -855,8 +897,10 @@ struct TestCellPass : public Pass {
                cell_types[ID($logic_and)] = "ABSY";
                cell_types[ID($logic_or)]  = "ABSY";
 
+               cell_types[ID($mux)] = "*";
+               cell_types[ID($bmux)] = "*";
+               cell_types[ID($demux)] = "*";
                if (edges) {
-                       cell_types[ID($mux)] = "*";
                        cell_types[ID($pmux)] = "*";
                }
 
index e9129f690118e70be0e7dbf6e46f46c0c30b8b0d..b14488ff44691e74771709e1054d3c78cd54d921 100644 (file)
@@ -1292,6 +1292,33 @@ endmodule
 
 // --------------------------------------------------------
 
+module \$bmux (A, S, Y);
+
+parameter WIDTH = 0;
+parameter S_WIDTH = 0;
+
+input [(WIDTH << S_WIDTH)-1:0] A;
+input [S_WIDTH-1:0] S;
+output [WIDTH-1:0] Y;
+
+wire [WIDTH-1:0] bm0_out, bm1_out;
+
+generate
+       if (S_WIDTH > 1) begin:muxlogic
+               \$bmux #(.WIDTH(WIDTH), .S_WIDTH(S_WIDTH-1)) bm0 (.A(A), .S(S[S_WIDTH-2:0]), .Y(bm0_out));
+               \$bmux #(.WIDTH(WIDTH), .S_WIDTH(S_WIDTH-1)) bm1 (.A(A[(WIDTH << S_WIDTH)-1:WIDTH << (S_WIDTH - 1)]), .S(S[S_WIDTH-2:0]), .Y(bm1_out));
+               assign Y = S[S_WIDTH-1] ? bm1_out : bm0_out;
+       end else if (S_WIDTH == 1) begin:simple
+               assign Y = S ? A[1] : A[0];
+       end else begin:passthru
+               assign Y = A;
+       end
+endgenerate
+
+endmodule
+
+// --------------------------------------------------------
+
 module \$pmux (A, B, S, Y);
 
 parameter WIDTH = 0;
@@ -1317,6 +1344,26 @@ end
 
 endmodule
 
+// --------------------------------------------------------
+
+module \$demux (A, S, Y);
+
+parameter WIDTH = 1;
+parameter S_WIDTH = 1;
+
+input [WIDTH-1:0] A;
+input [S_WIDTH-1:0] S;
+output [(WIDTH << S_WIDTH)-1:0] Y;
+
+genvar i;
+generate
+       for (i = 0; i < (1 << S_WIDTH); i = i + 1) begin:slices
+               assign Y[i*WIDTH+:WIDTH] = (S == i) ? A : 0;
+       end
+endgenerate
+
+endmodule
+
 // --------------------------------------------------------
 `ifndef SIMLIB_NOLUT
 
@@ -1326,30 +1373,9 @@ parameter WIDTH = 0;
 parameter LUT = 0;
 
 input [WIDTH-1:0] A;
-output reg Y;
-
-wire lut0_out, lut1_out;
+output Y;
 
-generate
-       if (WIDTH <= 1) begin:simple
-               assign {lut1_out, lut0_out} = LUT;
-       end else begin:complex
-               \$lut #( .WIDTH(WIDTH-1), .LUT(LUT                  ) ) lut0 ( .A(A[WIDTH-2:0]), .Y(lut0_out) );
-               \$lut #( .WIDTH(WIDTH-1), .LUT(LUT >> (2**(WIDTH-1))) ) lut1 ( .A(A[WIDTH-2:0]), .Y(lut1_out) );
-       end
-
-       if (WIDTH > 0) begin:lutlogic
-               always @* begin
-                       casez ({A[WIDTH-1], lut0_out, lut1_out})
-                               3'b?11: Y = 1'b1;
-                               3'b?00: Y = 1'b0;
-                               3'b0??: Y = lut0_out;
-                               3'b1??: Y = lut1_out;
-                               default: Y = 1'bx;
-                       endcase
-               end
-       end
-endgenerate
+\$bmux #(.WIDTH(1), .S_WIDTH(WIDTH)) mux(.A(LUT), .S(A), .Y(Y));
 
 endmodule
 
index 667773e1bfb9d6a352b289bf8ad1ffbdb59e918a..91d385b80a795219b685fc9fe38f2f89a8ea13bf 100644 (file)
@@ -59,7 +59,7 @@ module _90_simplemap_compare_ops;
 endmodule
 
 (* techmap_simplemap *)
-(* techmap_celltype = "$pos $slice $concat $mux $tribuf" *)
+(* techmap_celltype = "$pos $slice $concat $mux $tribuf $bmux" *)
 module _90_simplemap_various;
 endmodule
 
@@ -597,6 +597,43 @@ module _90_pmux (A, B, S, Y);
        assign Y = |S ? Y_B : A;
 endmodule
 
+// --------------------------------------------------------
+// Demultiplexers
+// --------------------------------------------------------
+
+(* techmap_celltype = "$demux" *)
+module _90_demux (A, S, Y);
+       parameter WIDTH = 1;
+       parameter S_WIDTH = 1;
+
+       (* force_downto *)
+       input [WIDTH-1:0] A;
+       (* force_downto *)
+       input [S_WIDTH-1:0] S;
+       (* force_downto *)
+       output [(WIDTH << S_WIDTH)-1:0] Y;
+
+       generate
+               if (S_WIDTH == 0) begin
+                       assign Y = A;
+               end else if (S_WIDTH == 1) begin
+                       assign Y[0+:WIDTH] = S ? 0 : A;
+                       assign Y[WIDTH+:WIDTH] = S ? A : 0;
+               end else begin
+                       localparam SPLIT = S_WIDTH / 2;
+                       wire [(1 << (S_WIDTH-SPLIT))-1:0] YH;
+                       wire [(1 << SPLIT)-1:0] YL;
+                       $demux #(.WIDTH(1), .S_WIDTH(SPLIT)) lo (.A(1'b1), .S(S[SPLIT-1:0]), .Y(YL));
+                       $demux #(.WIDTH(1), .S_WIDTH(S_WIDTH-SPLIT)) hi (.A(1'b1), .S(S[S_WIDTH-1:SPLIT]), .Y(YH));
+                       genvar i;
+                       for (i = 0; i < (1 << S_WIDTH); i = i + 1) begin
+                               localparam [S_WIDTH-1:0] IDX = i;
+                               assign Y[i*WIDTH+:WIDTH] = (YL[IDX[SPLIT-1:0]] & YH[IDX[S_WIDTH-1:SPLIT]]) ? A : 0;
+                       end
+               end
+       endgenerate
+endmodule
+
 
 // --------------------------------------------------------
 // LUTs