// SPDX-License-Identifier: Apache-2.0 package chiselTests import chisel3._ class SimpleBundle extends Bundle { val x = UInt(4.W) val y = UInt() } object SimpleBundle { def intoWire(): SimpleBundle = { val w = Wire(new SimpleBundle) w.x := 0.U(4.W) w.y := 0.U(4.W) w } } class WidthSpec extends ChiselFlatSpec { "Literals without specified widths" should "get the minimum legal width" in { "hdeadbeef".U.getWidth should be(32) "h_dead_beef".U.getWidth should be(32) "h0a".U.getWidth should be(4) "h1a".U.getWidth should be(5) "h0".U.getWidth should be(1) 1.U.getWidth should be(1) 1.S.getWidth should be(2) } } abstract class WireRegWidthSpecImpl extends ChiselFlatSpec { def name: String def builder[T <: Data](x: T): T behavior.of(name) it should "set the width if the template type has a set width" in { assertKnownWidth(4) { builder(UInt(4.W)) } assertKnownWidth(4) { val w = builder(new SimpleBundle) w := SimpleBundle.intoWire() w.x } assertKnownWidth(4) { val x = builder(Vec(1, UInt(4.W))) x(0) } } it should "infer the width if the template type has no width" in { assertInferredWidth(4) { val w = builder(UInt()) w := 0.U(4.W) w } assertInferredWidth(4) { val w = builder(new SimpleBundle) w := SimpleBundle.intoWire() w.y } assertInferredWidth(4) { val w = builder(Vec(1, UInt())) w(0) := 0.U(4.W) w(0) } } } class WireWidthSpec extends WireRegWidthSpecImpl { def name: String = "Wire" def builder[T <: Data](x: T): T = Wire(x) } class RegWidthSpec extends WireRegWidthSpecImpl { def name: String = "Reg" def builder[T <: Data](x: T): T = Reg(x) } abstract class WireDefaultRegInitSpecImpl extends ChiselFlatSpec { def name: String def builder1[T <: Data](x: T): T def builder2[T <: Data](x: T, y: T): T behavior.of(s"$name (Single Argument)") it should "set width if passed a literal with forced width" in { assertKnownWidth(4) { builder1(3.U(4.W)) } } it should "NOT set width if passed a literal without a forced width" in { assertInferredWidth(4) { val w = builder1(3.U) w := 3.U(4.W) w } } it should "NOT set width if passed a non-literal" in { assertInferredWidth(4) { val w = WireDefault(3.U(4.W)) builder1(w) } } it should "copy the widths of aggregates" in { assertInferredWidth(4) { val w = builder1(SimpleBundle.intoWire()) w.y } assertKnownWidth(4) { val w = builder1(SimpleBundle.intoWire()) w.x } assertInferredWidth(4) { val x = Wire(Vec(1, UInt())) x(0) := 0.U(4.W) val w = builder1(x) w(0) } assertKnownWidth(4) { val x = Wire(Vec(1, UInt(4.W))) x(0) := 0.U(4.W) val w = builder1(x) w(0) } } behavior.of(s"$name (Double Argument)") it should "set the width if the template type has a set width" in { assertKnownWidth(4) { WireDefault(UInt(4.W), 0.U) } assertKnownWidth(4) { WireDefault(UInt(4.W), 0.U(2.W)) } assertKnownWidth(4) { val w = WireDefault(new SimpleBundle, SimpleBundle.intoWire()) w.x } assertKnownWidth(4) { val x = Wire(Vec(1, UInt())) x(0) := 0.U(4.W) val w = WireDefault(Vec(1, UInt(4.W)), x) w(0) } } it should "infer the width if the template type has no width" in { val templates = Seq( () => 0.U, () => 0.U(2.W), () => WireDefault(0.U), () => WireDefault(0.U(2.W)) ) for (gen <- templates) { assertInferredWidth(4) { val w = WireDefault(UInt(), gen()) w := 0.U(4.W) w } } assertInferredWidth(4) { val w = WireDefault(new SimpleBundle, SimpleBundle.intoWire()) w.y } assertInferredWidth(4) { val x = Wire(Vec(1, UInt())) x(0) := 0.U(4.W) val w = WireDefault(Vec(1, UInt()), x) w(0) } } } class WireDefaultWidthSpec extends WireDefaultRegInitSpecImpl { def name: String = "WireDefault" def builder1[T <: Data](x: T): T = WireDefault(x) def builder2[T <: Data](x: T, y: T): T = WireDefault(x, y) } class RegInitWidthSpec extends WireDefaultRegInitSpecImpl { def name: String = "RegInit" def builder1[T <: Data](x: T): T = RegInit(x) def builder2[T <: Data](x: T, y: T): T = RegInit(x, y) } class OpWidthSpec extends ChiselFlatSpec { import firrtl._ import firrtl.ir._ val maxWidth = 5 val uIntOps: Seq[((UInt, UInt) => UInt, PrimOp)] = Seq( (_ +& _, PrimOps.Add), (_ -& _, PrimOps.Sub), (_ * _, PrimOps.Mul), (_ / _, PrimOps.Div), (_ % _, PrimOps.Rem), (_ << _, PrimOps.Dshl), (_ >> _, PrimOps.Dshr) ) assertTesterPasses(new chisel3.testers.BasicTester { for (i <- 0 to maxWidth) { for (j <- 0 to maxWidth) { for ((cOp, fOp) <- uIntOps) { val args = Seq(i, j).map(w => Reference("", UIntType(IntWidth(w)))) fOp.propagateType(DoPrim(fOp, args, Nil, UnknownType)) match { case UIntType(IntWidth(w)) => val x = 0.U(maxWidth.W).head(i) val y = 0.U(maxWidth.W).head(j) assert(w == cOp(x, y).getWidth) } } } } stop() }) val sIntOps: Seq[((SInt, SInt) => SInt, PrimOp)] = Seq( (_ +& _, PrimOps.Add), (_ -& _, PrimOps.Sub), (_ * _, PrimOps.Mul), (_ / _, PrimOps.Div), (_ % _, PrimOps.Rem) ) assertTesterPasses(new chisel3.testers.BasicTester { for (i <- 0 to maxWidth) { for (j <- 0 to maxWidth) { for ((cOp, fOp) <- sIntOps) { val args = Seq(i, j).map(w => Reference("", SIntType(IntWidth(w)))) fOp.propagateType(DoPrim(fOp, args, Nil, UnknownType)) match { case SIntType(IntWidth(w)) => val x = 0.U(maxWidth.W).head(i).asSInt val y = 0.U(maxWidth.W).head(j).asSInt assert(w == cOp(x, y).getWidth) } } } } stop() }) }