From 3f53bed3f55da94c5b11c29cfd48b128ee51deed Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 6 Jun 2024 15:48:58 -0700 Subject: [PATCH] Preserve literal value across .asSInt and .zext (#4151) (#4152) (cherry picked from commit dbbf73ac210962dca26a5a2847de2b3e1411e8cb) Co-authored-by: Jack Koenig --- core/src/main/scala/chisel3/Bits.scala | 24 ++++++++++++++++++++---- src/test/scala/chiselTests/SIntOps.scala | 5 +++++ src/test/scala/chiselTests/UIntOps.scala | 18 ++++++++++++++++++ 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/core/src/main/scala/chisel3/Bits.scala b/core/src/main/scala/chisel3/Bits.scala index b993067ab86..f61c694a8a2 100644 --- a/core/src/main/scala/chisel3/Bits.scala +++ b/core/src/main/scala/chisel3/Bits.scala @@ -757,11 +757,27 @@ sealed class UInt private[chisel3] (width: Width) extends Bits(width) with Num[U final def zext: SInt = macro SourceInfoTransform.noArg /** @group SourceInfoTransformMacro */ - def do_zext(implicit sourceInfo: SourceInfo): SInt = - pushOp(DefPrim(sourceInfo, SInt(width + 1), ConvertOp, ref)) + def do_zext(implicit sourceInfo: SourceInfo): SInt = this.litOption match { + case Some(value) => SInt.Lit(value, this.width + 1) + case None => pushOp(DefPrim(sourceInfo, SInt(width + 1), ConvertOp, ref)) + } - override def do_asSInt(implicit sourceInfo: SourceInfo): SInt = - pushOp(DefPrim(sourceInfo, SInt(width), AsSIntOp, ref)) + override def do_asSInt(implicit sourceInfo: SourceInfo): SInt = this.litOption match { + case Some(value) => + val w = this.width.get // Literals always have a known width, will be minimum legal width if not set + val signedValue = + // If width is 0, just return value (which will be 0). + if (w > 0 && value.testBit(w - 1)) { + // If the most significant bit is set, the SInt is negative and we need to adjust the value. + value - (BigInt(1) << w) + } else { + value + } + // Using SInt.Lit instead of .S so we can use Width argument which may be Unknown + SInt.Lit(signedValue, this.width.max(Width(1))) // SInt literal has width >= 1 + case None => + pushOp(DefPrim(sourceInfo, SInt(width), AsSIntOp, ref)) + } override private[chisel3] def _asUIntImpl(first: Boolean)(implicit sourceInfo: SourceInfo): UInt = this diff --git a/src/test/scala/chiselTests/SIntOps.scala b/src/test/scala/chiselTests/SIntOps.scala index 1cbdf2bce2b..7cfbf69d641 100644 --- a/src/test/scala/chiselTests/SIntOps.scala +++ b/src/test/scala/chiselTests/SIntOps.scala @@ -225,4 +225,9 @@ class SIntOpsSpec extends ChiselPropSpec with Utils { } } } + + property("Calling .asSInt on a SInt literal should maintain the literal value") { + 3.S.asSInt.litValue should be(3) + -5.S.asSInt.litValue should be(-5) + } } diff --git a/src/test/scala/chiselTests/UIntOps.scala b/src/test/scala/chiselTests/UIntOps.scala index c342630ace0..b36726cbeda 100644 --- a/src/test/scala/chiselTests/UIntOps.scala +++ b/src/test/scala/chiselTests/UIntOps.scala @@ -494,4 +494,22 @@ class UIntOpsSpec extends ChiselPropSpec with Matchers with Utils { property("Calling .asUInt on a UInt literal should maintain the literal value") { 3.U.asUInt.litValue should be(3) } + + property("Calling .asSInt on a UInt literal should reinterpret the literal value") { + 5.U.asSInt.litValue should be(-3) + 5.U(8.W).asSInt.litValue should be(5) + 0.U.asSInt.litValue should be(0) + 0.U.asSInt.widthOption should be(Some(1)) + // There are no zero-width SInt literals + 0.U(0.W).asSInt.widthOption should be(Some(1)) + } + + property("Calling .zext on a UInt literal should maintain the literal value") { + 5.U.zext.litValue should be(5) + 5.U.zext.getWidth should be(4) + 5.U(8.W).zext.litValue should be(5) + 0.U.zext.litValue should be(0) + 0.U.zext.widthOption should be(Some(2)) + 0.U(0.W).zext.widthOption should be(Some(1)) + } }