diff --git a/core/src/main/scala/chisel3/experimental/dataview/package.scala b/core/src/main/scala/chisel3/experimental/dataview/package.scala index a6f9cef2a32..1c4d86ca726 100644 --- a/core/src/main/scala/chisel3/experimental/dataview/package.scala +++ b/core/src/main/scala/chisel3/experimental/dataview/package.scala @@ -258,6 +258,7 @@ package object dataview { * @note An Aggregate may be a view of unrelated [[Data]] (eg. like a Seq or tuple) and thus this * there is no single Data representing the Target and this function will return None * @return The single Data target of this view or None if a single Data doesn't exist + * @note Returns Some(_) of the argument if it is not a view */ private[chisel3] def reifySingleData(data: Data): Option[Data] = { val candidate: Option[Data] = @@ -265,7 +266,7 @@ package object dataview { case None => None case Some(ViewBinding(target)) => Some(target) case Some(AggregateViewBinding(lookup)) => lookup.get(data) - case Some(_) => None + case Some(_) => Some(data) } candidate.flatMap { d => // Candidate may itself be a view, keep tracing in those cases diff --git a/src/main/scala/chisel3/simulator/package.scala b/src/main/scala/chisel3/simulator/package.scala index c1a7797e8f6..166c5780d60 100644 --- a/src/main/scala/chisel3/simulator/package.scala +++ b/src/main/scala/chisel3/simulator/package.scala @@ -2,6 +2,7 @@ package chisel3 import svsim._ import chisel3.reflect.DataMirror +import chisel3.experimental.dataview.reifySingleData import scala.collection.mutable import java.nio.file.{Files, Path, Paths} @@ -33,7 +34,16 @@ package object simulator { case (data, port) => data -> controller.port(port.name) }.toMap def port(data: Data): Simulation.Port = { - simulationPorts(data) + // TODO, we can support non 1-1 views, but it will require changing this API to return a Seq[Port] + // and packing/unpacking the BigInt literal representation. + val reified = reifySingleData(data).getOrElse { + val url = "https://github.com/chipsalliance/chisel/issues/new/choose" + throw new Exception( + s"Cannot poke $data as is a view that does not map to a single Data. " + + s"Please file an issue at $url requesting support for this use case." + ) + } + simulationPorts(reified) } // -- Peek/Poke API Support diff --git a/src/test/scala/chiselTests/simulator/SimulatorSpec.scala b/src/test/scala/chiselTests/simulator/SimulatorSpec.scala index 6190df73c40..8189dd97abb 100644 --- a/src/test/scala/chiselTests/simulator/SimulatorSpec.scala +++ b/src/test/scala/chiselTests/simulator/SimulatorSpec.scala @@ -137,5 +137,28 @@ class SimulatorSpec extends AnyFunSpec with Matchers { (actualSV should not).include("emptyBundle") actualSV should include("bundle_x") } + + it("support peeking and poking FlatIO ports and other views of ports") { + import chisel3.experimental.dataview._ + class SimpleModule extends Module { + val io = FlatIO(new Bundle { + val in = Input(UInt(8.W)) + val out = Output(UInt(8.W)) + }) + val viewOfClock = clock.viewAs[Clock] + val delay = RegNext(io.in) + io.out := delay + } + new VerilatorSimulator("test_run_dir/simulator/flat_io_ports") + .simulate(new SimpleModule) { module => + import PeekPokeAPI._ + val dut = module.wrapped + dut.io.in.poke(12.U) + dut.viewOfClock.step(1) + dut.io.out.peek() + dut.io.out.expect(12) + } + .result + } } }