From c77b7343d0412a009436a57764d907e2ae332da2 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Fri, 21 Oct 2022 15:41:20 +0200 Subject: Consistent $mux undef handling * Change simlib's $mux cell to use the ternary operator as $_MUX_ already does * Stop opt_expr -keepdc from changing S=x to S=0 * Change const eval of $mux and $pmux to match the updated simlib (fixes sim) * The sat behavior of $mux already matches the updated simlib The verilog frontend uses $mux for the ternary operators and this changes all interpreations of the $mux cell (that I found) to match the verilog simulation behavior for the ternary operator. For 'if' and 'case' expressions the frontend may also use $mux but uses $eqx if the verilog simulation behavior is requested with the '-ifx' option. For $pmux there is a remaining mismatch between the sat behavior and the simlib behavior. Resolving this requires more discussion, as the $pmux cell does not directly correspond to a specific verilog construct. --- kernel/calc.cc | 30 ++++++++++++++++++++++++++++++ kernel/celltypes.h | 14 ++++---------- kernel/rtlil.h | 2 ++ passes/opt/opt_expr.cc | 2 +- techlibs/common/simlib.v | 5 +---- 5 files changed, 38 insertions(+), 15 deletions(-) diff --git a/kernel/calc.cc b/kernel/calc.cc index 0865db526..32e8a49fe 100644 --- a/kernel/calc.cc +++ b/kernel/calc.cc @@ -609,6 +609,36 @@ 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_mux(const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3) +{ + log_assert(arg2.size() == arg1.size()); + if (arg3[0] == State::S0) + return arg1; + else if (arg3[0] == State::S1) + return arg2; + + RTLIL::Const ret = arg1; + for (int i = 0; i < ret.size(); i++) + if (ret[i] != arg2[i]) + ret[i] = State::Sx; + return ret; +} + +RTLIL::Const RTLIL::const_pmux(const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3) +{ + if (arg3.is_fully_zero()) + return arg1; + + if (!arg3.is_onehot()) + return RTLIL::Const(State::Sx, arg1.size()); + + for (int i = 0; i < arg3.size(); i++) + if (arg3[i] == State::S1) + return RTLIL::Const(std::vector(arg2.bits.begin() + i*arg1.bits.size(), arg2.bits.begin() + (i+1)*arg1.bits.size())); + + log_abort(); // unreachable +} + RTLIL::Const RTLIL::const_bmux(const RTLIL::Const &arg1, const RTLIL::Const &arg2) { std::vector t = arg1.bits; diff --git a/kernel/celltypes.h b/kernel/celltypes.h index d62ba1506..e617b4603 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -488,16 +488,10 @@ struct CellTypes static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, bool *errp = nullptr) { - if (cell->type.in(ID($mux), ID($pmux), ID($_MUX_))) { - RTLIL::Const ret = arg1; - for (size_t i = 0; i < arg3.bits.size(); i++) - if (arg3.bits[i] == RTLIL::State::S1) { - std::vector bits(arg2.bits.begin() + i*arg1.bits.size(), arg2.bits.begin() + (i+1)*arg1.bits.size()); - ret = RTLIL::Const(bits); - } - return ret; - } - + if (cell->type.in(ID($mux), ID($_MUX_))) + return const_mux(arg1, arg2, arg3); + if (cell->type == ID($pmux)) + return const_pmux(arg1, arg2, arg3); if (cell->type == ID($_AOI3_)) return eval_not(const_or(const_and(arg1, arg2, false, false, 1), arg3, false, false, 1)); if (cell->type == ID($_OAI3_)) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 27ffdff1f..755abf534 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -500,6 +500,8 @@ 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_mux (const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3); + 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); diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index be0cd470b..9cc0170dc 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -1494,7 +1494,7 @@ skip_identity: RTLIL::SigSpec input = assign_map(cell->getPort(ID::S)); RTLIL::SigSpec inA = assign_map(cell->getPort(ID::A)); RTLIL::SigSpec inB = assign_map(cell->getPort(ID::B)); - if (input.is_fully_const()) + if (input.is_fully_const() && (!keepdc || input.is_fully_def())) ACTION_DO(ID::Y, input.as_bool() ? cell->getPort(ID::B) : cell->getPort(ID::A)); else if (inA == inB) ACTION_DO(ID::Y, cell->getPort(ID::A)); diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index ab9bd7e1d..2fd75372d 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -1282,10 +1282,7 @@ input S; output reg [WIDTH-1:0] Y; always @* begin - if (S) - Y = B; - else - Y = A; + assign Y = S ? B : A; end endmodule -- cgit v1.2.3