3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-06-06 14:13:23 +00:00

Add $bmux and $demux cells.

This commit is contained in:
Marcelina Kościelnicka 2022-01-24 16:02:29 +01:00
parent db33b1e535
commit 93508d58da
25 changed files with 694 additions and 49 deletions

View 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

View 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

View 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))

View 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);

View 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_),

View 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;

View 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 = "");

View 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);