diff --git a/kernel/calc.cc b/kernel/calc.cc index 9b0885db9..5ddb230b2 100644 --- a/kernel/calc.cc +++ b/kernel/calc.cc @@ -658,6 +658,25 @@ RTLIL::Const RTLIL::const_bmux(const RTLIL::Const &arg1, const RTLIL::Const &arg return t; } +RTLIL::Const RTLIL::const_priority(const RTLIL::Const &arg) +{ + std::vector t; + std::optional first_non_zero = std::nullopt; + for (int i = 0; i < GetSize(arg); i++) + { + RTLIL::State s = arg.at(i); + if (first_non_zero && s != State::Sx) { + t.push_back(*first_non_zero == State::S1 ? State::S0 : *first_non_zero); + } else { + t.push_back(s); + } + if ((!first_non_zero && s != State::S0) || s == State::Sx) { + first_non_zero = s; + } + } + return t; +} + RTLIL::Const RTLIL::const_demux(const RTLIL::Const &arg1, const RTLIL::Const &arg2) { int width = GetSize(arg1); diff --git a/kernel/celltypes.h b/kernel/celltypes.h index 34b013dd9..d3aa4399c 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -118,7 +118,7 @@ struct CellTypes void setup_internals_eval() { std::vector unary_ops = { - ID($not), ID($pos), ID($buf), ID($neg), + ID($not), ID($pos), ID($buf), ID($neg), ID($priority), ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool), ID($logic_not), ID($slice), ID($lut), ID($sop) }; @@ -509,6 +509,11 @@ struct CellTypes return default_ret; } + if (cell->type == ID($priority)) + { + return const_priority(arg1); + } + bool signed_a = cell->parameters.count(ID::A_SIGNED) > 0 && cell->parameters[ID::A_SIGNED].as_bool(); bool signed_b = cell->parameters.count(ID::B_SIGNED) > 0 && cell->parameters[ID::B_SIGNED].as_bool(); int result_len = cell->parameters.count(ID::Y_WIDTH) > 0 ? cell->parameters[ID::Y_WIDTH].as_int() : -1; diff --git a/kernel/constids.inc b/kernel/constids.inc index c99aa788d..315944b9d 100644 --- a/kernel/constids.inc +++ b/kernel/constids.inc @@ -259,6 +259,7 @@ X($pmux) X($pos) X($pow) X($print) +X($priority) X($recrem) X($reduce_and) X($reduce_bool) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 0dbe8bb13..5c0e0cbee 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -2646,6 +2646,13 @@ namespace { check_expected(); return; } + if (cell->type.in(ID($priority))) { + param(ID::WIDTH); + port(ID::A, param(ID::WIDTH)); + port(ID::Y, param(ID::WIDTH)); + check_expected(); + return; + } /* * Checklist for adding internal cell types * ======================================== @@ -3961,6 +3968,14 @@ RTLIL::Cell* RTLIL::Module::addDlatchsr(RTLIL::IdString name, const RTLIL::SigSp cell->set_src_attribute(src); return cell; } +RTLIL::Cell* RTLIL::Module::addPriority(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, const std::string &src) +{ + RTLIL::Cell *cell = addCell(name, ID($priority)); + cell->setPort(ID::A, sig_a); + cell->setPort(ID::Y, sig_y); + cell->set_src_attribute(src); + return cell; +} RTLIL::Cell* RTLIL::Module::addSrGate(RTLIL::IdString name, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, const RTLIL::SigSpec &sig_q, bool set_polarity, bool clr_polarity, const std::string &src) @@ -4503,7 +4518,7 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed) return; } - if (type == ID($lut) || type == ID($sop)) { + if (type == ID($lut) || type == ID($sop) || type == ID($priority)) { parameters[ID::WIDTH] = GetSize(connections_[ID::A]); return; } diff --git a/kernel/rtlil.h b/kernel/rtlil.h index e3a5a3bf8..bfd8799d1 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -848,6 +848,7 @@ namespace RTLIL { RTLIL::Const const_pmux (const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3); RTLIL::Const const_bmux (const RTLIL::Const &arg1, const RTLIL::Const &arg2); RTLIL::Const const_demux (const RTLIL::Const &arg1, const RTLIL::Const &arg2); + RTLIL::Const const_priority (const RTLIL::Const &arg); RTLIL::Const const_bweqx (const RTLIL::Const &arg1, const RTLIL::Const &arg2); RTLIL::Const const_bwmux (const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3); @@ -2260,6 +2261,8 @@ public: RTLIL::Cell* addAdlatch (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_arst, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, RTLIL::Const arst_value, bool en_polarity = true, bool arst_polarity = true, const std::string &src = ""); RTLIL::Cell* addDlatchsr (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr, RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = ""); + RTLIL::Cell* addPriority (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, const std::string &src = ""); + RTLIL::Cell* addBufGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_y, const std::string &src = ""); RTLIL::Cell* addNotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_y, const std::string &src = ""); RTLIL::Cell* addAndGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const RTLIL::SigBit &sig_y, const std::string &src = ""); diff --git a/kernel/satgen.cc b/kernel/satgen.cc index f2c1e00c2..2e5b27530 100644 --- a/kernel/satgen.cc +++ b/kernel/satgen.cc @@ -430,6 +430,39 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep) return true; } + if (cell->type == ID($priority)) + { + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + std::vector yy = model_undef ? ez->vec_var(y.size()) : y; + + int tmp; + if (a.size()) { + tmp = a[0]; + ez->assume(ez->IFF(yy[0], a[0])); + } + for (size_t i = 1; i < a.size(); i++) { + ez->assume(ez->IFF(yy[i], ez->AND(a[i], ez->NOT(tmp)))); + tmp = ez->OR(tmp, a[i]); + } + if (model_undef) { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + + if (a.size()) { + tmp = undef_a[0]; + ez->assume(ez->IFF(undef_y[0], undef_a[0])); + } + for (size_t i = 1; i < a.size(); i++) { + tmp = ez->OR(tmp, undef_a[i]); + ez->assume(ez->IFF(undef_y[i], tmp)); + } + undefGating(y, yy, undef_y); + } + + return true; + } + if (cell->type.in(ID($pos), ID($buf), ID($neg))) { std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc index 4d28e659b..a05d9cb16 100644 --- a/passes/tests/test_cell.cc +++ b/passes/tests/test_cell.cc @@ -136,6 +136,21 @@ static RTLIL::Cell* create_gold_module(RTLIL::Design *design, RTLIL::IdString ce cell->setPort(ID::Y, wire); } + if (cell_type == ID($priority)) + { + int width = 1 + xorshift32(8 * bloat_factor); + + wire = module->addWire(ID::A); + wire->width = width; + wire->port_input = true; + cell->setPort(ID::A, wire); + + wire = module->addWire(ID::Y); + wire->width = width; + wire->port_output = true; + cell->setPort(ID::Y, wire); + } + if (cell_type == ID($fa)) { int width = 1 + xorshift32(8 * bloat_factor); @@ -1039,6 +1054,7 @@ struct TestCellPass : public Pass { cell_types[ID($mux)] = "*"; cell_types[ID($bmux)] = "*"; cell_types[ID($demux)] = "*"; + cell_types[ID($priority)] = "*"; // $pmux doesn't work in sat, and is not supported with 'techmap -assert' or // '-simlib' if (nosat && techmap_cmd.compare("aigmap") == 0) diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index e0fb9fbfa..fcdbab555 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -3250,3 +3250,19 @@ parameter WIDTH = 0; inout [WIDTH-1:0] Y; endmodule + +// -------------------------------------------------------- +//- +//- $priority (A, Y) +//* group unary +//- +//- Priority operator. An output bit is set if the input bit at the same index is set and no lower index input bit is set. +//- +module \$priority (A, Y); +parameter WIDTH = 8; +input [WIDTH-1:0] A; +output [WIDTH-1:0] Y; + +assign Y = A & (~A + 1); + +endmodule diff --git a/techlibs/common/techmap.v b/techlibs/common/techmap.v index c3364e628..6eb9d01da 100644 --- a/techlibs/common/techmap.v +++ b/techlibs/common/techmap.v @@ -679,3 +679,29 @@ parameter WIDTH = 0; inout [WIDTH-1:0] Y; // This cell is just a maker, so we leave Y undriven endmodule + +(* techmap_celltype = "$priority" *) +module \$priority (A, Y); + parameter WIDTH = 3; + + (* force_downto *) + input [WIDTH-1:0] A; + (* force_downto *) + output [WIDTH-1:0] Y; + + (* force_downto *) + wire [WIDTH-1:0] tmp; + + genvar i; + generate + if (WIDTH > 0) begin + assign tmp[0] = A[0]; + assign Y[0] = A[0]; + end + for (i = 1; i < WIDTH; i = i + 1) begin + assign Y[i] = A[i] & ~tmp[i-1]; + assign tmp[i] = tmp[i-1] | A[i]; + end + endgenerate + +endmodule