Fix vsransu padding error Unsigned input upcasting should always padd the MSBs with 0s, whereas signed input upcasting padds the MSBs with the sign bit. Bug: 307590638 Change-Id: If424adceaa78590f0b60ce2e1cde4c83c5d6e1ed
diff --git a/hdl/chisel/src/kelvin/vector/VAluInt.scala b/hdl/chisel/src/kelvin/vector/VAluInt.scala index 90f648b..1d767f9 100644 --- a/hdl/chisel/src/kelvin/vector/VAluInt.scala +++ b/hdl/chisel/src/kelvin/vector/VAluInt.scala
@@ -1083,28 +1083,29 @@ val shamt = b(log2Ceil(s * size) - 1, 0) val srl = a >> shamt - val srs = MuxOR(a(s * size - 1), ((~0.U((s * size).W)) << ((s * size - 1).U - shamt))(s * size - 1, 0)) + // Signed MSB padding for negative input a. Otherwise it should always + // pad with zeros. + val srs = MuxOR(a(s * size - 1) && signed, + ((~0.U((s * size).W)) << ((s * size - 1).U - shamt))(s * size - 1, 0)) val sra = srs | srl assert(srl.getWidth == (s * size)) assert(srs.getWidth == (s * size)) val rbit = Cat(a(s * size - 2, 0), 0.U(1.W))(shamt) assert(rbit.getWidth == 1) - val umax = ((1 << size) - 1).S((s * size).W) - val umin = 0.S((s * size).W) + val umax = ((1 << size) - 1).U((s * size).W) val smax = ((1 << (size - 1)) - 1).S((s * size).W) val smin = -(1 << (size - 1)).S((s * size).W) val rshf = Mux(round && rbit, sra + 1.U, sra) - val is_umax = !signed && (rshf.asSInt > umax) - val is_umin = !signed && (rshf.asSInt < umin) + val is_umax = !signed && (rshf.asUInt > umax) + // No unsigned negative capping because it's always >=0. val is_smax = signed && (rshf.asSInt > smax) val is_smin = signed && (rshf.asSInt < smin) - val is_norm = !(is_umax || is_umin || is_smax || is_smin) - assert(PopCount(Cat(is_umax, is_umin, is_smax, is_smin, is_norm)) <= 1.U) + val is_norm = !(is_umax || is_smax || is_smin) + assert(PopCount(Cat(is_umax, is_smax, is_smin, is_norm)) <= 1.U) val r = MuxOR(is_umax, umax.asUInt(size - 1, 0)) | - MuxOR(is_umin, umin.asUInt(size - 1, 0)) | MuxOR(is_smax, smax.asUInt(size - 1, 0)) | MuxOR(is_smin, smin.asUInt(size - 1, 0)) | MuxOR(is_norm, rshf(size - 1, 0))
diff --git a/tests/verilator_sim/kelvin/alu_ref.h b/tests/verilator_sim/kelvin/alu_ref.h index bf61daf..4158f7b 100644 --- a/tests/verilator_sim/kelvin/alu_ref.h +++ b/tests/verilator_sim/kelvin/alu_ref.h
@@ -357,7 +357,8 @@ constexpr int n = sizeof(T2) * 8; constexpr int m = sizeof(T1) * 8; b &= (n - 1); - int64_t s = (static_cast<int64_t>(a) + (b && r ? (1ll << (b - 1)) : 0)) >> b; + int64_t pad_a = u ? (int64_t(a) & ((1ll << n) - 1)) : int64_t(a); + int64_t s = (pad_a + (b && r ? (1ll << (b - 1)) : 0)) >> b; int64_t neg_max = !u ? -1ll << (m - 1) : 0; int64_t pos_max = !u ? (1ll << (m - 1)) - 1 : (1ull << m) - 1; bool neg_sat = s < neg_max;