Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preserve literals across .asUInt #4148

Merged
merged 1 commit into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions core/src/main/scala/chisel3/Aggregate.scala
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,14 @@ sealed abstract class Aggregate extends Data {
// This means we need the `first` argument so that we can preserve this behavior of Aggregates while still allowing subclasses
// to override .asUInt behavior
override private[chisel3] def _asUIntImpl(first: Boolean)(implicit sourceInfo: SourceInfo): UInt = {
val elts = this.getElements.map(_._asUIntImpl(false))
if (elts.isEmpty && !first) 0.U(0.W) else SeqUtils.do_asUInt(elts)
checkingLitOption(checkForDontCares = false) match {
case Some(value) =>
// Using UInt.Lit instead of .U so we can use Width argument which may be Unknown
UInt.Lit(value, this.width)
case None =>
val elts = this.getElements.map(_._asUIntImpl(false))
if (elts.isEmpty && !first) 0.U(0.W) else SeqUtils.do_asUInt(elts)
}
}

private[chisel3] override def connectFromBits(
Expand Down
19 changes: 16 additions & 3 deletions core/src/main/scala/chisel3/Bits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1023,9 +1023,22 @@ sealed class SInt private[chisel3] (width: Width) extends Bits(width) with Num[S
override def do_>>(that: UInt)(implicit sourceInfo: SourceInfo): SInt =
binop(sourceInfo, SInt(this.width), DynamicShiftRightOp, that)

override private[chisel3] def _asUIntImpl(first: Boolean)(implicit sourceInfo: SourceInfo): UInt = pushOp(
DefPrim(sourceInfo, UInt(this.width), AsUIntOp, ref)
)
override private[chisel3] def _asUIntImpl(first: Boolean)(implicit sourceInfo: SourceInfo): UInt =
this.litOption match {
case Some(value) =>
// This is a reinterpretation of raw bits
val posValue =
if (value.signum == -1) {
(BigInt(1) << this.width.get) + value
} else {
value
}
// Using UInt.Lit instead of .U so we can use Width argument which may be Unknown
UInt.Lit(posValue, this.width)
case None =>
pushOp(DefPrim(sourceInfo, UInt(this.width), AsUIntOp, ref))
}

override def do_asSInt(implicit sourceInfo: SourceInfo): SInt = this

private[chisel3] override def connectFromBits(
Expand Down
58 changes: 55 additions & 3 deletions src/test/scala/chiselTests/BundleLiteralSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package chiselTests

import chisel3._
import chisel3.util.Cat
import circt.stage.ChiselStage
import chisel3.testers.BasicTester
import chisel3.experimental.BundleLiterals._
Expand All @@ -28,6 +29,15 @@ class BundleLiteralSpec extends ChiselFlatSpec with Utils {
val c = UInt(16.W)
}

class ChildBundle extends Bundle {
val foo = UInt(4.W)
}
class ComplexBundle(w: Int) extends Bundle {
val a = Vec(2, new ChildBundle)
val b = UInt(w.W)
val c = UInt(4.W)
}

"bundle literals" should "pack" in {
assertTesterPasses {
new BasicTester {
Expand Down Expand Up @@ -351,7 +361,7 @@ class BundleLiteralSpec extends ChiselFlatSpec with Utils {
}
val (stdout, _, chirrtl) = grabStdOutErr(ChiselStage.emitCHIRRTL(new RawModule {
val lit = (new SimpleBundle).Lit(_.a -> 0xde.U, _.b -> 0xad.U)
val x = lit.asUInt
val x = Cat(lit.a, lit.b)
}))
stdout should include("[W007] Literal value ULit(222,) is too wide for field _.a with width 4")
stdout should include("[W007] Literal value ULit(173,) is too wide for field _.b with width 4")
Expand All @@ -366,7 +376,7 @@ class BundleLiteralSpec extends ChiselFlatSpec with Utils {
val chirrtl = ChiselStage.emitCHIRRTL(
new RawModule {
val lit = (new SimpleBundle).Lit(_.a -> 5.U, _.b -> 0.U)
val x = lit.asUInt
val x = Cat(lit.a, lit.b)
},
args = Array("--warnings-as-errors")
)
Expand Down Expand Up @@ -407,8 +417,50 @@ class BundleLiteralSpec extends ChiselFlatSpec with Utils {
val lit = (new SimpleBundle).Lit(_.a -> 0x3.U, _.b -> 0x3.U(3.W))
lit.a.getWidth should be(4)
lit.b.getWidth should be(4)
val cat = lit.asUInt
val cat = Cat(lit.a, lit.b)
})
chirrtl should include("node cat = cat(UInt<4>(0h3), UInt<4>(0h3))")
}

"Calling .asUInt on a Bundle literal" should "return a UInt literal and work outside of elaboration" in {
val blit = (new MyBundle).Lit(_.a -> 42.U, _.b -> true.B, _.c -> MyEnum.sB)
val ulit = blit.asUInt
ulit.litOption should be(Some(171))

assertTesterPasses {
new BasicTester {
// Check that it gives the same value as the generated hardware
val wire = WireInit(blit).asUInt
chisel3.assert(ulit.litValue.U === wire)
stop()
}
}
}

"Calling .asUInt on a Bundle literal with DontCare fields" should "NOT return a UInt literal" in {
ChiselStage.emitCHIRRTL(new RawModule {
val blit = (new MyBundle).Lit(_.a -> 42.U, _.c -> MyEnum.sB)
val ulit = blit.asUInt
ulit.litOption should be(None)
})
}

"Calling .asUInt on a Bundle literal with zero-width fields" should "return a UInt literal and work outside of elaboration" in {
import chisel3.experimental.VecLiterals._

val vlit = Vec.Lit((new ChildBundle).Lit(_.foo -> 0xa.U), (new ChildBundle).Lit(_.foo -> 0xb.U))
val blit = (new ComplexBundle(0)).Lit(_.a -> vlit, _.b -> 0.U(0.W), _.c -> 0xc.U)
val ulit = blit.asUInt
ulit.litOption should be(Some(0xbac))

assertTesterPasses {
new BasicTester {
// Check that it gives the same value as the generated hardware
val wire = WireInit(blit).asUInt
chisel3.assert(ulit.litValue.U === wire)
stop()
}
}
}

}
28 changes: 28 additions & 0 deletions src/test/scala/chiselTests/SIntOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -219,4 +219,32 @@ class SIntOpsSpec extends ChiselPropSpec with Utils with ShiftRightWidthBehavior
val verilog = ChiselStage.emitSystemVerilog(new TestModule, args)
verilog should include(" widthcheck = in[7];")
}

property("Calling .asUInt on an SInt literal should maintain the literal value") {
val s0 = 3.S
val u0 = s0.asUInt
u0.litValue should be(3)

val s1 = -3.S
val u1 = s1.asUInt
u1.litValue should be(5)

val s2 = -3.S(8.W)
val u2 = s2.asUInt
u2.litValue should be(0xfd)

assertTesterPasses {
new BasicTester {
// Check that it gives the same value as the generated hardware
val wire0 = WireInit(s0).asUInt
chisel3.assert(u0.litValue.U === wire0)
val wire1 = WireInit(s1).asUInt
chisel3.assert(u1.litValue.U === wire1)
val wire2 = WireInit(s2).asUInt
chisel3.assert(u2.litValue.U === wire2)

stop()
}
}
}
}
4 changes: 4 additions & 0 deletions src/test/scala/chiselTests/UIntOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -607,4 +607,8 @@ class UIntOpsSpec extends ChiselPropSpec with Matchers with Utils with ShiftRigh
val e = the[IllegalArgumentException] thrownBy (UInt(-8.W))
e.getMessage should include("Widths must be non-negative, got -8")
}

property("Calling .asUInt on a UInt literal should maintain the literal value") {
3.U.asUInt.litValue should be(3)
}
}
35 changes: 33 additions & 2 deletions src/test/scala/chiselTests/VecLiteralSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package chiselTests

import chisel3._
import chisel3.util.Cat
import chisel3.experimental.BundleLiterals.AddBundleLiteralConstructor
import chisel3.experimental.VecLiterals._
import chisel3.experimental.VecLiteralException
Expand Down Expand Up @@ -537,13 +538,43 @@ class VecLiteralSpec extends ChiselFreeSpec with Utils {
val lit0 = (Vec(2, UInt(4.W))).Lit(0 -> 0x3.U, 1 -> 0x2.U(3.W))
lit0(0).getWidth should be(4)
lit0(1).getWidth should be(4)
val uint0 = lit0.asUInt
val uint0 = Cat(lit0(1), lit0(0))
val lit1 = Vec.Lit(0x3.U, 0x2.U(4.W))
lit1(0).getWidth should be(4)
lit1(1).getWidth should be(4)
val uint1 = lit1.asUInt
val uint1 = Cat(lit1(1), lit1(0))
})
chirrtl should include("node uint0 = cat(UInt<4>(0h2), UInt<4>(0h3))")
chirrtl should include("node uint1 = cat(UInt<4>(0h2), UInt<4>(0h3))")
}

"Calling .asUInt on a Vec literal should return a UInt literal and work outside of elaboration" in {
val vlit0 = Vec(2, UInt(4.W)).Lit(0 -> 0x3.U, 1 -> 0x2.U(3.W))
val ulit0 = vlit0.asUInt
ulit0.litOption should be(Some(0x23))

val vlit1 = Vec.Lit(0x3.U, 0x2.U(4.W))
val ulit1 = vlit1.asUInt
ulit1.litOption should be(Some(0x23))

assertTesterPasses {
new BasicTester {
// Check that it gives the same value as the generated hardware
val wire0 = WireInit(vlit0).asUInt
chisel3.assert(ulit0.litValue.U === wire0)
val wire1 = WireInit(vlit1).asUInt
chisel3.assert(ulit1.litValue.U === wire1)

stop()
}
}
}

"Calling .asUInt on a Vec literal with DontCare fields should NOT return a UInt literal" in {
ChiselStage.emitCHIRRTL(new RawModule {
val vlit = Vec(2, UInt(4.W)).Lit(1 -> 0x2.U(3.W))
val ulit = vlit.asUInt
ulit.litOption should be(None)
})
}
}