From d56e21658d23d2d97858a6dbbd93cbe9e19444c7 Mon Sep 17 00:00:00 2001 From: John Ingalls <43973001+ingallsj@users.noreply.github.com> Date: Sun, 18 Apr 2021 23:31:54 -0700 Subject: [PATCH] Prevent TLWidthWidget from generating X outputs (#2815) * Prevent TLWidthWidget from generating X outputs Widening WidthWidgets contain an uninitialized data register. The first transaction through the widget may propagate that register's contents on the bus, which is logically correct but can propagates a X, violating our constraint that we never provide X in the payload of a valid xact. Fix by propagating in.bits.data, rather than the register, until the register has been written at least once. This is cheaper than resetting the register. * Add comments to WidthWidget X fix Co-authored-by: Andrew Waterman --- src/main/scala/tilelink/WidthWidget.scala | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/scala/tilelink/WidthWidget.scala b/src/main/scala/tilelink/WidthWidget.scala index c8d980b8dee..d60c83a08c5 100644 --- a/src/main/scala/tilelink/WidthWidget.scala +++ b/src/main/scala/tilelink/WidthWidget.scala @@ -50,11 +50,18 @@ class TLWidthWidget(innerBeatBytes: Int)(implicit p: Parameters) extends LazyMod } def helper(idata: UInt): UInt = { + // rdata is X until the first time a multi-beat write occurs. + // Prevent the X from leaking outside by jamming the mux control until + // the first time rdata is written (and hence no longer X). + val rdata_written_once = RegInit(false.B) + val masked_enable = enable.map(_ || !rdata_written_once) + val odata = Seq.fill(ratio) { WireInit(idata) } val rdata = Reg(Vec(ratio-1, chiselTypeOf(idata))) val pdata = rdata :+ idata - val mdata = (enable zip (odata zip pdata)) map { case (e, (o, p)) => Mux(e, o, p) } + val mdata = (masked_enable zip (odata zip pdata)) map { case (e, (o, p)) => Mux(e, o, p) } when (in.fire() && !last) { + rdata_written_once := true.B (rdata zip mdata) foreach { case (r, m) => r := m } } Cat(mdata.reverse)