diff --git a/core/src/main/scala/chisel3/Mem.scala b/core/src/main/scala/chisel3/Mem.scala index d6ab9c4b04a..2c5e4290084 100644 --- a/core/src/main/scala/chisel3/Mem.scala +++ b/core/src/main/scala/chisel3/Mem.scala @@ -367,7 +367,7 @@ sealed class SyncReadMem[T <: Data] private[chisel3] (t: T, n: BigInt, val readU def do_read(idx: UInt, en: Bool)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = _read_impl(idx, en, Builder.forcedClock, true) - def read(idx: UInt, en: Bool, clock: Clock): T = macro SourceInfoTransform.xyzArg + def read(idx: UInt, en: Bool, clock: Clock): T = macro SourceInfoTransform.idxEnClockArg /** @group SourceInfoTransformMacro */ def do_read(idx: UInt, en: Bool, clock: Clock)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = diff --git a/macros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala b/macros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala index 3e310774d5f..857bf871182 100644 --- a/macros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala +++ b/macros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala @@ -200,13 +200,58 @@ class SourceInfoTransform(val c: Context) extends AutoSourceTransform { q"$thisObj.$doFuncTerm($x, $y)($implicitSourceInfo, $implicitCompileOptions)" } - def xyzArg(idx: c.Tree, en: c.Tree, clock: c.Tree): c.Tree = { + def nxArg(n: c.Tree, x: c.Tree): c.Tree = { + q"$thisObj.$doFuncTerm($n, $x)($implicitSourceInfo, $implicitCompileOptions)" + } + + def idxEnClockArg(idx: c.Tree, en: c.Tree, clock: c.Tree): c.Tree = { q"$thisObj.$doFuncTerm($idx, $en, $clock)($implicitSourceInfo, $implicitCompileOptions)" } def xEnArg(x: c.Tree, en: c.Tree): c.Tree = { q"$thisObj.$doFuncTerm($x, $en)($implicitSourceInfo, $implicitCompileOptions)" } + + def arArg(a: c.Tree, r: c.Tree*): c.Tree = { + q"$thisObj.$doFuncTerm($a, ..$r)($implicitSourceInfo, $implicitCompileOptions)" + } + + def rArg(r: c.Tree): c.Tree = { + q"$thisObj.$doFuncTerm($r)($implicitSourceInfo, $implicitCompileOptions)" + } + + def nInArg(n: c.Tree, in: c.Tree): c.Tree = { + q"$thisObj.$doFuncTerm($n, $in)($implicitSourceInfo, $implicitCompileOptions)" + } + + def nextEnableArg(next: c.Tree, enable: c.Tree): c.Tree = { + q"$thisObj.$doFuncTerm($next, $enable)($implicitSourceInfo, $implicitCompileOptions)" + } + + def nextInitEnableArg(next: c.Tree, init: c.Tree, enable: c.Tree): c.Tree = { + q"$thisObj.$doFuncTerm($next, $init, $enable)($implicitSourceInfo, $implicitCompileOptions)" + } + + def inNArg(in: c.Tree, n: c.Tree): c.Tree = { + q"$thisObj.$doFuncTerm($in, $n)($implicitSourceInfo, $implicitCompileOptions)" + } + + def inNEnArg(in: c.Tree, n: c.Tree, en: c.Tree): c.Tree = { + q"$thisObj.$doFuncTerm($in, $n, $en)($implicitSourceInfo, $implicitCompileOptions)" + } + + def inNResetEnArg(in: c.Tree, n: c.Tree, reset: c.Tree, en: c.Tree): c.Tree = { + q"$thisObj.$doFuncTerm($in, $n, $reset, $en)($implicitSourceInfo, $implicitCompileOptions)" + } + + def inNResetDataArg(in: c.Tree, n: c.Tree, resetData: c.Tree): c.Tree = { + q"$thisObj.$doFuncTerm($in, $n, $resetData)($implicitSourceInfo, $implicitCompileOptions)" + } + + def inNResetDataEnArg(in: c.Tree, n: c.Tree, resetData: c.Tree, en: c.Tree): c.Tree = { + q"$thisObj.$doFuncTerm($in, $n, $resetData, $en)($implicitSourceInfo, $implicitCompileOptions)" + } + } // Workaround for https://github.com/sbt/sbt/issues/3966 diff --git a/src/main/scala/chisel3/util/Bitwise.scala b/src/main/scala/chisel3/util/Bitwise.scala index 8abe3645065..fe820bf22cc 100644 --- a/src/main/scala/chisel3/util/Bitwise.scala +++ b/src/main/scala/chisel3/util/Bitwise.scala @@ -6,6 +6,8 @@ package chisel3.util import chisel3._ +import chisel3.internal.sourceinfo.{SourceInfo, SourceInfoTransform} +import scala.language.experimental.macros /** Creates repetitions of each bit of the input in order. * @@ -24,13 +26,29 @@ object FillInterleaved { * * Output data-equivalent to in(size(in)-1) (n times) ## ... ## in(1) (n times) ## in(0) (n times) */ - def apply(n: Int, in: UInt): UInt = apply(n, in.asBools) + def apply(n: Int, in: UInt): UInt = macro SourceInfoTransform.nInArg + + /** @group SourceInfoTransformMacro */ + def do_apply(n: Int, in: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = + _apply_impl(n, in.asBools) /** Creates n repetitions of each bit of x in order. * * Output data-equivalent to in(size(in)-1) (n times) ## ... ## in(1) (n times) ## in(0) (n times) */ - def apply(n: Int, in: Seq[Bool]): UInt = Cat(in.map(Fill(n, _)).reverse) + def apply(n: Int, in: Seq[Bool]): UInt = macro SourceInfoTransform.nInArg + + /** @group SourceInfoTransformMacro */ + def do_apply(n: Int, in: Seq[Bool])(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = + _apply_impl(n, in) + + private def _apply_impl( + n: Int, + in: Seq[Bool] + )( + implicit sourceInfo: SourceInfo, + compileOptions: CompileOptions + ): UInt = Cat(in.map(Fill(n, _)).reverse) } /** Returns the number of bits set (value is 1 or true) in the input signal. @@ -45,9 +63,23 @@ object FillInterleaved { * }}} */ object PopCount { - def apply(in: Iterable[Bool]): UInt = SeqUtils.count(in.toSeq) - def apply(in: Bits): UInt = apply((0 until in.getWidth).map(in(_))) + def apply(in: Iterable[Bool]): UInt = macro SourceInfoTransform.inArg + + /** @group SourceInfoTransformMacro */ + def do_apply(in: Iterable[Bool])(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = _apply_impl( + in.toSeq + ) + + def apply(in: Bits): UInt = macro SourceInfoTransform.inArg + + /** @group SourceInfoTransformMacro */ + def do_apply(in: Bits)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = _apply_impl( + (0 until in.getWidth).map(in(_)) + ) + + private def _apply_impl(in: Iterable[Bool])(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = + SeqUtils.count(in.toSeq) } /** Create repetitions of the input using a tree fanout topology. @@ -65,7 +97,10 @@ object Fill { * Output data-equivalent to x ## x ## ... ## x (n repetitions). * @throws java.lang.IllegalArgumentException if `n` is less than zero */ - def apply(n: Int, x: UInt): UInt = { + def apply(n: Int, x: UInt): UInt = macro SourceInfoTransform.nxArg + + /** @group SourceInfoTransformMacro */ + def do_apply(n: Int, x: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = { n match { case _ if n < 0 => throw new IllegalArgumentException(s"n (=$n) must be nonnegative integer.") case 0 => UInt(0.W) @@ -92,24 +127,29 @@ object Fill { * }}} */ object Reverse { - private def doit(in: UInt, length: Int): UInt = length match { - case _ if length < 0 => throw new IllegalArgumentException(s"length (=$length) must be nonnegative integer.") - case _ if length <= 1 => in - case _ if isPow2(length) && length >= 8 && length <= 64 => - // This esoterica improves simulation performance - var res = in - var shift = length >> 1 - var mask = ((BigInt(1) << length) - 1).asUInt(length.W) - do { - mask = mask ^ (mask(length - shift - 1, 0) << shift) - res = ((res >> shift) & mask) | ((res(length - shift - 1, 0) << shift) & ~mask) - shift = shift >> 1 - } while (shift > 0) - res - case _ => - val half = (1 << log2Ceil(length)) / 2 - Cat(doit(in(half - 1, 0), half), doit(in(length - 1, half), length - half)) - } - def apply(in: UInt): UInt = doit(in, in.getWidth) + private def doit(in: UInt, length: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = + length match { + case _ if length < 0 => throw new IllegalArgumentException(s"length (=$length) must be nonnegative integer.") + case _ if length <= 1 => in + case _ if isPow2(length) && length >= 8 && length <= 64 => + // This esoterica improves simulation performance + var res = in + var shift = length >> 1 + var mask = ((BigInt(1) << length) - 1).asUInt(length.W) + do { + mask = mask ^ (mask(length - shift - 1, 0) << shift) + res = ((res >> shift) & mask) | ((res(length - shift - 1, 0) << shift) & ~mask) + shift = shift >> 1 + } while (shift > 0) + res + case _ => + val half = (1 << log2Ceil(length)) / 2 + Cat(doit(in(half - 1, 0), half), doit(in(length - 1, half), length - half)) + } + + def apply(in: UInt): UInt = macro SourceInfoTransform.inArg + + /** @group SourceInfoTransformMacro */ + def do_apply(in: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = doit(in, in.getWidth) } diff --git a/src/main/scala/chisel3/util/Cat.scala b/src/main/scala/chisel3/util/Cat.scala index c5adce56efe..117dd282895 100644 --- a/src/main/scala/chisel3/util/Cat.scala +++ b/src/main/scala/chisel3/util/Cat.scala @@ -2,7 +2,10 @@ package chisel3.util +import scala.language.experimental.macros + import chisel3._ +import chisel3.internal.sourceinfo.{SourceInfo, SourceInfoTransform} /** Concatenates elements of the input, in order, together. * @@ -19,7 +22,11 @@ object Cat { /** Concatenates the argument data elements, in argument order, together. The first argument * forms the most significant bits, while the last argument forms the least significant bits. */ - def apply[T <: Bits](a: T, r: T*): UInt = apply(a :: r.toList) + def apply[T <: Bits](a: T, r: T*): UInt = macro SourceInfoTransform.arArg + + /** @group SourceInfoTransformMacro */ + def do_apply[T <: Bits](a: T, r: T*)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = + _apply_impl(a :: r.toList) /** Concatenates the data elements of the input sequence, in reverse sequence order, together. * The first element of the sequence forms the most significant bits, while the last element @@ -28,5 +35,12 @@ object Cat { * Equivalent to r(0) ## r(1) ## ... ## r(n-1). * @note This returns a `0.U` if applied to a zero-element `Vec`. */ - def apply[T <: Bits](r: Seq[T]): UInt = SeqUtils.asUInt(r.reverse) + def apply[T <: Bits](r: Seq[T]): UInt = macro SourceInfoTransform.rArg + + /** @group SourceInfoTransformMacro */ + def do_apply[T <: Bits](r: Seq[T])(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = + _apply_impl(r) + + private def _apply_impl[T <: Bits](r: Seq[T])(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = + SeqUtils.asUInt(r.reverse) } diff --git a/src/main/scala/chisel3/util/Reg.scala b/src/main/scala/chisel3/util/Reg.scala index ddb74dd683a..309cc4e64a7 100644 --- a/src/main/scala/chisel3/util/Reg.scala +++ b/src/main/scala/chisel3/util/Reg.scala @@ -2,7 +2,10 @@ package chisel3.util +import scala.language.experimental.macros + import chisel3._ +import chisel3.internal.sourceinfo.{SourceInfo, SourceInfoTransform} object RegEnable { @@ -12,7 +15,10 @@ object RegEnable { * val regWithEnable = RegEnable(nextVal, ena) * }}} */ - def apply[T <: Data](next: T, enable: Bool): T = { + def apply[T <: Data](next: T, enable: Bool): T = macro SourceInfoTransform.nextEnableArg + + /** @group SourceInfoTransformMacro */ + def do_apply[T <: Data](next: T, enable: Bool)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = { val r = Reg(chiselTypeOf(next)) when(enable) { r := next } r @@ -24,7 +30,17 @@ object RegEnable { * val regWithEnableAndReset = RegEnable(nextVal, 0.U, ena) * }}} */ - def apply[T <: Data](next: T, init: T, enable: Bool): T = { + def apply[T <: Data](next: T, init: T, enable: Bool): T = macro SourceInfoTransform.nextInitEnableArg + + /** @group SourceInfoTransformMacro */ + def do_apply[T <: Data]( + next: T, + init: T, + enable: Bool + )( + implicit sourceInfo: SourceInfo, + compileOptions: CompileOptions + ): T = { val r = RegInit(init) when(enable) { r := next } r @@ -43,7 +59,45 @@ object ShiftRegister { * val regDelayTwo = ShiftRegister(nextVal, 2, ena) * }}} */ - def apply[T <: Data](in: T, n: Int, en: Bool = true.B): T = ShiftRegisters(in, n, en).lastOption.getOrElse(in) + def apply[T <: Data](in: T, n: Int, en: Bool): T = macro SourceInfoTransform.inNEnArg + + /** @group SourceInfoTransformMacro */ + def do_apply[T <: Data]( + in: T, + n: Int, + en: Bool = true.B + )( + implicit sourceInfo: SourceInfo, + compileOptions: CompileOptions + ): T = + _apply_impl(in, n, en) + + /** Returns the n-cycle delayed version of the input signal. + * + * Enable is assumed to be true. + * + * @param in input to delay + * @param n number of cycles to delay + * + * @example {{{ + * val regDelayTwo = ShiftRegister(nextVal, 2) + * }}} + */ + def apply[T <: Data](in: T, n: Int): T = macro SourceInfoTransform.inNArg + + /** @group SourceInfoTransformMacro */ + def do_apply[T <: Data](in: T, n: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = + _apply_impl(in, n) + + private def _apply_impl[T <: Data]( + in: T, + n: Int, + en: Bool = true.B + )( + implicit sourceInfo: SourceInfo, + compileOptions: CompileOptions + ): T = + ShiftRegisters(in, n, en).lastOption.getOrElse(in) /** Returns the n-cycle delayed version of the input signal with reset initialization. * @@ -56,7 +110,18 @@ object ShiftRegister { * val regDelayTwoReset = ShiftRegister(nextVal, 2, 0.U, ena) * }}} */ - def apply[T <: Data](in: T, n: Int, resetData: T, en: Bool): T = + def apply[T <: Data](in: T, n: Int, resetData: T, en: Bool): T = macro SourceInfoTransform.inNResetDataEnArg + + /** @group SourceInfoTransformMacro */ + def do_apply[T <: Data]( + in: T, + n: Int, + resetData: T, + en: Bool + )( + implicit sourceInfo: SourceInfo, + compileOptions: CompileOptions + ): T = ShiftRegisters(in, n, resetData, en).lastOption.getOrElse(in) } @@ -68,9 +133,41 @@ object ShiftRegisters { * @param n number of cycles to delay * @param en enable the shift */ - def apply[T <: Data](in: T, n: Int, en: Bool = true.B): Seq[T] = + def apply[T <: Data](in: T, n: Int, en: Bool): Seq[T] = macro SourceInfoTransform.inNEnArg + + /** @group SourceInfoTransformMacro */ + def do_apply[T <: Data]( + in: T, + n: Int, + en: Bool + )( + implicit sourceInfo: SourceInfo, + compileOptions: CompileOptions + ): Seq[T] = _apply_impl(in, n, en) + + private def _apply_impl[T <: Data]( + in: T, + n: Int, + en: Bool = true.B + )( + implicit sourceInfo: SourceInfo, + compileOptions: CompileOptions + ): Seq[T] = Seq.iterate(in, n + 1)(util.RegEnable(_, en)).drop(1) + /** Returns a sequence of delayed input signal registers from 1 to n. + * + * Enable is assumed to be true. + * + * @param in input to delay + * @param n number of cycles to delay + */ + def apply[T <: Data](in: T, n: Int): Seq[T] = macro SourceInfoTransform.inNArg + + /** @group SourceInfoTransformMacro */ + def do_apply[T <: Data](in: T, n: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Seq[T] = + _apply_impl(in, n) + /** Returns delayed input signal registers with reset initialization from 1 to n. * * @param in input to delay @@ -78,6 +175,17 @@ object ShiftRegisters { * @param resetData reset value for each register in the shift * @param en enable the shift */ - def apply[T <: Data](in: T, n: Int, resetData: T, en: Bool): Seq[T] = + def apply[T <: Data](in: T, n: Int, resetData: T, en: Bool): Seq[T] = macro SourceInfoTransform.inNResetDataEnArg + + /** @group SourceInfoTransformMacro */ + def do_apply[T <: Data]( + in: T, + n: Int, + resetData: T, + en: Bool + )( + implicit sourceInfo: SourceInfo, + compileOptions: CompileOptions + ): Seq[T] = Seq.iterate(in, n + 1)(util.RegEnable(_, resetData, en)).drop(1) } diff --git a/src/test/scala/chiselTests/util/BitwiseSpec.scala b/src/test/scala/chiselTests/util/BitwiseSpec.scala new file mode 100644 index 00000000000..3bf0ca5f1b0 --- /dev/null +++ b/src/test/scala/chiselTests/util/BitwiseSpec.scala @@ -0,0 +1,97 @@ +package chiselTests.util + +import chisel3._ +import chisel3.stage.ChiselStage +import chisel3.util.{Fill, FillInterleaved, PopCount, Reverse} + +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +class FillInterleavedSpec extends AnyFlatSpec with Matchers { + behavior.of("util.FillInterleaved") + + it should "have source locators when passed a UInt" in { + class MyModule extends RawModule { + val out = IO(Output(UInt())) + out := FillInterleaved(2, "b1000".U) + } + val chirrtl = ChiselStage.emitChirrtl(new MyModule) + val cat = """cat.*BitwiseSpec\.scala""".r + (chirrtl should include).regex(cat) + val mux = """mux.*BitwiseSpec\.scala""".r + (chirrtl should include).regex(mux) + (chirrtl should not).include("Bitwise.scala") + } + + it should "have source locators when passed a Seq[Bool]" in { + class MyModule extends RawModule { + val out = IO(Output(UInt())) + out := FillInterleaved(2, Seq(true.B, false.B, false.B, false.B)) + } + val chirrtl = ChiselStage.emitChirrtl(new MyModule) + val cat = """cat.*BitwiseSpec\.scala""".r + (chirrtl should include).regex(cat) + val mux = """mux.*BitwiseSpec\.scala""".r + (chirrtl should include).regex(mux) + (chirrtl should not).include("Bitwise.scala") + } +} + +class PopCountSpec extends AnyFlatSpec with Matchers { + behavior.of("util.PopCount") + + it should "have source locators when passed a Iterable[Bool]" in { + class MyModule extends RawModule { + val out = IO(Output(UInt())) + out := PopCount(Seq(true.B, false.B, false.B, false.B)) + } + val chirrtl = ChiselStage.emitChirrtl(new MyModule) + val add = """add.*BitwiseSpec\.scala""".r + (chirrtl should include).regex(add) + val bits = """bits.*BitwiseSpec\.scala""".r + (chirrtl should include).regex(bits) + (chirrtl should not).include("Bitwise.scala") + } + + it should "have source locators when passed a Bits" in { + class MyModule extends RawModule { + val out = IO(Output(UInt())) + out := PopCount("b1000".U) + } + val chirrtl = ChiselStage.emitChirrtl(new MyModule) + val add = """add.*BitwiseSpec\.scala""".r + (chirrtl should include).regex(add) + val bits = """bits.*BitwiseSpec\.scala""".r + (chirrtl should include).regex(bits) + (chirrtl should not).include("Bitwise.scala") + } +} + +class FillSpec extends AnyFlatSpec with Matchers { + behavior.of("util.Fill") + it should "have source locators when passed a Bits" in { + class MyModule extends RawModule { + val out = IO(Output(UInt())) + out := Fill(2, "b1000".U) + } + val chirrtl = ChiselStage.emitChirrtl(new MyModule) + val cat = """cat.*BitwiseSpec\.scala""".r + (chirrtl should include).regex(cat) + (chirrtl should not).include("Bitwise.scala") + } +} + +class ReverseSpec extends AnyFlatSpec with Matchers { + behavior.of("util.Reverse") + + it should "have source locators when passed a UInt" in { + class MyModule extends RawModule { + val out = IO(Output(UInt())) + out := Reverse("b1101".U) + } + val chirrtl = ChiselStage.emitChirrtl(new MyModule) + val cat = """cat.*BitwiseSpec\.scala""".r + (chirrtl should include).regex(cat) + (chirrtl should not).include("Bitwise.scala") + } +} diff --git a/src/test/scala/chiselTests/util/CatSpec.scala b/src/test/scala/chiselTests/util/CatSpec.scala index a75c4ec0c84..66834797e0e 100644 --- a/src/test/scala/chiselTests/util/CatSpec.scala +++ b/src/test/scala/chiselTests/util/CatSpec.scala @@ -60,4 +60,28 @@ class CatSpec extends ChiselFlatSpec { chirrtl should include("node hi_hi = cat(in[0], in[1])") } + it should "have a source locator when passing a seq" in { + class MyModule extends RawModule { + val in = IO(Input(Vec(8, UInt(8.W)))) + val out = IO(Output(UInt())) + + // noPrefix to avoid `out` as prefix + out := Cat(in) + } + val chirrtl = ChiselStage.emitChirrtl(new MyModule) + chirrtl should include("cat(in[0], in[1]) @[CatSpec.scala") + (chirrtl should not).include("Cat.scala") + } + + it should "have a source locator when passing args" in { + class MyModule extends RawModule { + val in = IO(Input(Vec(8, UInt(8.W)))) + val out = IO(Output(UInt())) + out := Cat(in(0), in(1)) + } + val chirrtl = ChiselStage.emitChirrtl(new MyModule) + chirrtl should include("cat(in[0], in[1]) @[CatSpec.scala") + (chirrtl should not).include("Cat.scala") + } + } diff --git a/src/test/scala/chiselTests/util/RegSpec.scala b/src/test/scala/chiselTests/util/RegSpec.scala new file mode 100644 index 00000000000..876341b2318 --- /dev/null +++ b/src/test/scala/chiselTests/util/RegSpec.scala @@ -0,0 +1,134 @@ +package chiselTests.util + +import chisel3._ +import chisel3.stage.ChiselStage +import chisel3.util.{RegEnable, ShiftRegister, ShiftRegisters} + +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +class RegEnableSpec extends AnyFlatSpec with Matchers { + behavior.of("util.RegEnable") + + it should "have source locators when passed nextVal, ena" in { + class MyModule extends Module { + val in = IO(Input(Bool())) + val out = IO(Output(Bool())) + out := RegEnable(in, true.B) + } + val chirrtl = ChiselStage.emitChirrtl(new MyModule) + val reset = """reset.*RegSpec.scala""".r + (chirrtl should include).regex(reset) + val update = """out_r.* in .*RegSpec.scala""".r + (chirrtl should include).regex(update) + (chirrtl should not).include("Reg.scala") + } + + it should "have source locators when passed next, init, enable" in { + class MyModule extends Module { + val in = IO(Input(Bool())) + val out = IO(Output(Bool())) + out := RegEnable(in, true.B, true.B) + } + val chirrtl = ChiselStage.emitChirrtl(new MyModule) + val reset = """reset .*RegSpec.scala""".r + (chirrtl should include).regex(reset) + val update = """out_r.* in .*RegSpec.scala""".r + (chirrtl should include).regex(update) + (chirrtl should not).include("Reg.scala") + } +} + +class ShiftRegisterSpec extends AnyFlatSpec with Matchers { + behavior.of("util.ShiftRegister") + + it should "have source locators when passed in, n, en" in { + class MyModule extends Module { + val in = IO(Input(Bool())) + val out = IO(Output(Bool())) + out := ShiftRegister(in, 2, true.B) + } + val chirrtl = ChiselStage.emitChirrtl(new MyModule) + val reset = """reset .*RegSpec.scala""".r + (chirrtl should include).regex(reset) + val update = """out_r.* in .*RegSpec.scala""".r + (chirrtl should include).regex(update) + (chirrtl should not).include("Reg.scala") + } + + it should "have source locators when passed in, n" in { + class MyModule extends Module { + val in = IO(Input(Bool())) + val out = IO(Output(Bool())) + out := ShiftRegister(in, 2) + } + val chirrtl = ChiselStage.emitChirrtl(new MyModule) + val reset = """reset .*RegSpec.scala""".r + (chirrtl should include).regex(reset) + val update = """out_r.* in .*RegSpec.scala""".r + (chirrtl should include).regex(update) + (chirrtl should not).include("Reg.scala") + } + + it should "have source locators when passed in, n, resetData, en" in { + class MyModule extends Module { + val in = IO(Input(Bool())) + val out = IO(Output(Bool())) + out := ShiftRegister(in, 2, false.B, true.B) + } + val chirrtl = ChiselStage.emitChirrtl(new MyModule) + val reset = """reset .*RegSpec.scala""".r + (chirrtl should include).regex(reset) + val update = """out_r.* in .*RegSpec.scala""".r + (chirrtl should include).regex(update) + (chirrtl should not).include("Reg.scala") + } + +} + +class ShiftRegistersSpec extends AnyFlatSpec with Matchers { + behavior.of("util.ShiftRegisters") + + it should "have source locators when passed in, n, en" in { + class MyModule extends Module { + val in = IO(Input(Bool())) + val out = IO(Output(Bool())) + out := ShiftRegisters(in, 2, true.B)(0) + } + val chirrtl = ChiselStage.emitChirrtl(new MyModule) + val reset = """reset .*RegSpec.scala""".r + (chirrtl should include).regex(reset) + val update = """out_r.* in .*RegSpec.scala""".r + (chirrtl should include).regex(update) + (chirrtl should not).include("Reg.scala") + } + + it should "have source locators when passed in, n" in { + class MyModule extends Module { + val in = IO(Input(Bool())) + val out = IO(Output(Bool())) + out := ShiftRegisters(in, 2)(0) + } + val chirrtl = ChiselStage.emitChirrtl(new MyModule) + val reset = """reset .*RegSpec.scala""".r + (chirrtl should include).regex(reset) + val update = """out_r.* in .*RegSpec.scala""".r + (chirrtl should include).regex(update) + (chirrtl should not).include("Reg.scala") + } + + it should "have source locators when passed in, n, resetData, en" in { + class MyModule extends Module { + val in = IO(Input(Bool())) + val out = IO(Output(Bool())) + out := ShiftRegisters(in, 2, false.B, true.B)(0) + } + val chirrtl = ChiselStage.emitChirrtl(new MyModule) + val reset = """reset .*RegSpec.scala""".r + (chirrtl should include).regex(reset) + val update = """out_r.* in .*RegSpec.scala""".r + (chirrtl should include).regex(update) + (chirrtl should not).include("Reg.scala") + } + +}