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)) + } }