From 7fcd3146b6b1a6d4655cfb2583d6fecb8db7ab34 Mon Sep 17 00:00:00 2001 From: Trevor McKay Date: Fri, 25 Oct 2024 15:00:46 -0700 Subject: [PATCH] Allow BoringUtils to use existing port in a closed module (#4484) * fix case ordering when drilling connection * add test (cherry picked from commit 9d58f0dfb6d607892eb4762e550ee33b7265595a) # Conflicts: # src/main/scala/chisel3/util/experimental/BoringUtils.scala --- .../util/experimental/BoringUtils.scala | 5 +++ .../chiselTests/BoringUtilsTapSpec.scala | 40 +++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/src/main/scala/chisel3/util/experimental/BoringUtils.scala b/src/main/scala/chisel3/util/experimental/BoringUtils.scala index eee7fbb0e52..c82bb48d1dd 100644 --- a/src/main/scala/chisel3/util/experimental/BoringUtils.scala +++ b/src/main/scala/chisel3/util/experimental/BoringUtils.scala @@ -246,13 +246,18 @@ object BoringUtils { } def drill(source: A, path: Seq[BaseModule], connectionLocation: Seq[BaseModule], up: Boolean): A = { path.zip(connectionLocation).foldLeft(source) { +<<<<<<< HEAD case (rhs, (module, conLoc)) if (module.isFullyClosed) => boringError(module); DontCare.asInstanceOf[A] case (rhs, (module, _)) if (up && module == path(0) && isPort(rhs) && (!createProbe.nonEmpty || !createProbe.get.writable)) => { // When drilling from the original source, if it's already a port just return it. // As an exception, insist rwTaps are done from within the module and exported out. +======= + case (rhs, (module, _)) if ((up || isDriveDone(rhs)) && module == path(0) && isPort(rhs)) => { +>>>>>>> 9d58f0dfb (Allow BoringUtils to use existing port in a closed module (#4484)) rhs } + case (rhs, (module, conLoc)) if (module.isFullyClosed) => boringError(module); DontCare.asInstanceOf[A] case (rhs, (module, conLoc)) => skipPrefix { // so `lcaSource` isn't in the name of the secret port if (!up && createProbe.nonEmpty && createProbe.get.writable) { diff --git a/src/test/scala/chiselTests/BoringUtilsTapSpec.scala b/src/test/scala/chiselTests/BoringUtilsTapSpec.scala index 24d606635bd..7df1ba871d1 100644 --- a/src/test/scala/chiselTests/BoringUtilsTapSpec.scala +++ b/src/test/scala/chiselTests/BoringUtilsTapSpec.scala @@ -639,4 +639,44 @@ class BoringUtilsTapSpec extends ChiselFlatSpec with ChiselRunners with Utils wi val e = the[ChiselException] thrownBy circt.stage.ChiselStage.emitCHIRRTL(new Top) e.getMessage should include("BoringUtils currently only support identity views") } + + it should "reuse existing port in a closed module" in { + class Foo extends Module { + val io = IO(Output(UInt(32.W))) + val ioProbe = IO(probe.RWProbe(UInt(32.W))) + probe.define(ioProbe, probe.RWProbeValue(io)) + io := 0.U + } + + class Bar extends Module { + val foo = Module(new Foo) + val ioNames = reflect.DataMirror.modulePorts(foo).map(_._1) // close foo + val io = IO(Output(UInt(32.W))) + io := foo.io + } + + class Baz extends Module { + val bar = Module(new Bar) + val reProbe = Wire(probe.RWProbe(UInt(32.W))) + probe.define(reProbe, BoringUtils.rwTap(bar.foo.ioProbe)) + probe.forceInitial(reProbe, 1.U) + } + + val chirrtl = circt.stage.ChiselStage.emitCHIRRTL(new Baz) + matchesAndOmits(chirrtl)( + "module Foo :", + "output io : UInt<32>", + "output ioProbe : RWProbe>", + "define ioProbe = rwprobe(io)", + "module Bar :", + "inst foo of Foo", + "output bore : RWProbe>", + "define bore = foo.ioProbe", + "module Baz :", + "inst bar of Bar", + "wire reProbe : RWProbe>", + "define reProbe = bar.bore", + "force_initial(reProbe, UInt<32>(0h1))" + )() + } }