diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/calc.cc | 51 | ||||
-rw-r--r-- | kernel/celledges.cc | 40 | ||||
-rw-r--r-- | kernel/celltypes.h | 29 | ||||
-rw-r--r-- | kernel/consteval.h | 35 | ||||
-rw-r--r-- | kernel/qcsat.cc | 2 | ||||
-rw-r--r-- | kernel/rtlil.cc | 47 | ||||
-rw-r--r-- | kernel/rtlil.h | 7 | ||||
-rw-r--r-- | kernel/satgen.cc | 100 |
8 files changed, 291 insertions, 20 deletions
diff --git a/kernel/calc.cc b/kernel/calc.cc index 1e6410f7d..0865db526 100644 --- a/kernel/calc.cc +++ b/kernel/calc.cc @@ -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 diff --git a/kernel/celledges.cc b/kernel/celledges.cc index af07d26b3..c43ba8db3 100644 --- a/kernel/celledges.cc +++ b/kernel/celledges.cc @@ -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 diff --git a/kernel/celltypes.h b/kernel/celltypes.h index 879ac0edc..7e9cfb38d 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -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)) diff --git a/kernel/consteval.h b/kernel/consteval.h index 3edfc490c..642eb42b2 100644 --- a/kernel/consteval.h +++ b/kernel/consteval.h @@ -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); diff --git a/kernel/qcsat.cc b/kernel/qcsat.cc index b7da958db..aaee984fb 100644 --- a/kernel/qcsat.cc +++ b/kernel/qcsat.cc @@ -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_), diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index cd0f5ab12..a89edd992 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -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; diff --git a/kernel/rtlil.h b/kernel/rtlil.h index a562d253c..d8300f159 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -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 = ""); diff --git a/kernel/satgen.cc b/kernel/satgen.cc index 214826f5a..9c40ec66d 100644 --- a/kernel/satgen.cc +++ b/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); |