mirror of https://github.com/YosysHQ/yosys.git
Add $bmux and $demux cells.
This commit is contained in:
parent
db33b1e535
commit
93508d58da
|
@ -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++)
|
||||
{
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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++)
|
||||
{
|
||||
|
|
|
@ -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++)
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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_),
|
||||
|
|
|
@ -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,9 +3394,16 @@ 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;
|
||||
|
|
|
@ -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 = "");
|
||||
|
|
100
kernel/satgen.cc
100
kernel/satgen.cc
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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)));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -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";
|
||||
|
||||
if (edges) {
|
||||
cell_types[ID($mux)] = "*";
|
||||
cell_types[ID($bmux)] = "*";
|
||||
cell_types[ID($demux)] = "*";
|
||||
if (edges) {
|
||||
cell_types[ID($pmux)] = "*";
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
output Y;
|
||||
|
||||
wire lut0_out, lut1_out;
|
||||
|
||||
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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue