diff --git a/kernel/calc.cc b/kernel/calc.cc index 5ddb230b2..a1ba5f7c8 100644 --- a/kernel/calc.cc +++ b/kernel/calc.cc @@ -658,7 +658,7 @@ RTLIL::Const RTLIL::const_bmux(const RTLIL::Const &arg1, const RTLIL::Const &arg return t; } -RTLIL::Const RTLIL::const_priority(const RTLIL::Const &arg) +RTLIL::Const RTLIL::const_priority(const RTLIL::Const &arg, const RTLIL::Const &polarity) { std::vector t; std::optional first_non_zero = std::nullopt; @@ -666,11 +666,13 @@ RTLIL::Const RTLIL::const_priority(const RTLIL::Const &arg) { 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); + auto inactive = polarity[i] == State::S0 ? State::S1 : State::S0; + auto val = *first_non_zero == State::Sx ? State::Sx : inactive; + t.push_back(val); } else { t.push_back(s); } - if ((!first_non_zero && s != State::S0) || s == State::Sx) { + if ((!first_non_zero && s == polarity[i]) || s == State::Sx) { first_non_zero = s; } } diff --git a/kernel/celltypes.h b/kernel/celltypes.h index d3aa4399c..8423deadc 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -511,7 +511,7 @@ struct CellTypes if (cell->type == ID($priority)) { - return const_priority(arg1); + return const_priority(arg1, cell->getParam(ID::POLARITY)); } bool signed_a = cell->parameters.count(ID::A_SIGNED) > 0 && cell->parameters[ID::A_SIGNED].as_bool(); diff --git a/kernel/constids.inc b/kernel/constids.inc index 315944b9d..250c8688c 100644 --- a/kernel/constids.inc +++ b/kernel/constids.inc @@ -615,6 +615,7 @@ X(PATTERN) X(PCIN) X(PIPELINE_16x16_MULT_REG1) X(PIPELINE_16x16_MULT_REG2) +X(POLARITY) X(PORTID) X(PORT_A1_ADDR) X(PORT_A1_CLK) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index de54c4bd8..505c81da5 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -2656,6 +2656,7 @@ namespace { } if (cell->type.in(ID($priority))) { param(ID::WIDTH); + param(ID::POLARITY); port(ID::A, param(ID::WIDTH)); port(ID::Y, param(ID::WIDTH)); check_expected(); diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 3dddfd7f0..1e16108da 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -848,7 +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_priority (const RTLIL::Const &arg, const RTLIL::Const &polarity); 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); diff --git a/kernel/satgen.cc b/kernel/satgen.cc index 2e5b27530..c608a0c19 100644 --- a/kernel/satgen.cc +++ b/kernel/satgen.cc @@ -436,26 +436,31 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep) std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - int tmp; + const Const& polarity = cell->getParam(ID::POLARITY); + + int any_previous_active; if (a.size()) { - tmp = a[0]; + any_previous_active = polarity[0] ? a[0] : ez->NOT(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]); + int inactive_val = !polarity[i] ? ez->CONST_TRUE : ez->CONST_FALSE; + int active_val = polarity[i] ? ez->CONST_TRUE : ez->CONST_FALSE; + ez->assume(ez->IFF(yy[i], ez->ITE(any_previous_active, inactive_val, a[i]))); + any_previous_active = ez->OR(any_previous_active, ez->IFF(a[i], active_val)); } if (model_undef) { std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + int any_previous_undef; if (a.size()) { - tmp = undef_a[0]; + any_previous_undef = 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)); + any_previous_undef = ez->OR(any_previous_undef, undef_a[i]); + ez->assume(ez->IFF(undef_y[i], any_previous_undef)); } undefGating(y, yy, undef_y); } diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc index a05d9cb16..7ae375d96 100644 --- a/passes/tests/test_cell.cc +++ b/passes/tests/test_cell.cc @@ -149,6 +149,12 @@ static RTLIL::Cell* create_gold_module(RTLIL::Design *design, RTLIL::IdString ce wire->width = width; wire->port_output = true; cell->setPort(ID::Y, wire); + + RTLIL::SigSpec polarity; + for (int i = 0; i < width; i++) + polarity.append(xorshift32(2) ? State::S1 : State::S0); + + cell->setParam(ID::POLARITY, polarity.as_const()); } if (cell_type == ID($fa)) diff --git a/techlibs/common/techmap.v b/techlibs/common/techmap.v index 6eb9d01da..c8f4ec420 100644 --- a/techlibs/common/techmap.v +++ b/techlibs/common/techmap.v @@ -682,7 +682,8 @@ endmodule (* techmap_celltype = "$priority" *) module \$priority (A, Y); - parameter WIDTH = 3; + parameter WIDTH = 0; + parameter POLARITY = 0; (* force_downto *) input [WIDTH-1:0] A; @@ -691,16 +692,21 @@ module \$priority (A, Y); (* force_downto *) wire [WIDTH-1:0] tmp; + (* force_downto *) + wire [WIDTH-1:0] A_active; + wire [WIDTH-1:0] Y_active; + assign A_active = A ^ ~POLARITY; + assign Y = Y_active ^ ~POLARITY; genvar i; generate if (WIDTH > 0) begin - assign tmp[0] = A[0]; - assign Y[0] = A[0]; + assign tmp[0] = A_active[0]; + assign Y_active[0] = A_active[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]; + assign Y_active[i] = tmp[i-1] ? 1'b0 : A_active[i]; + assign tmp[i] = tmp[i-1] | A_active[i]; end endgenerate