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;