diff --git a/fpga/src/main/scala/arty100t/HarnessBinders.scala b/fpga/src/main/scala/arty100t/HarnessBinders.scala index dd7c1a35..d6371ed5 100644 --- a/fpga/src/main/scala/arty100t/HarnessBinders.scala +++ b/fpga/src/main/scala/arty100t/HarnessBinders.scala @@ -19,6 +19,7 @@ import sifive.fpgashells.clocks._ import chipyard._ import chipyard.harness._ import chipyard.iobinders._ +import testchipip.serdes._ class WithArty100TUARTTSI extends HarnessBinder({ case (th: HasHarnessInstantiators, port: UARTTSIPort) => { @@ -48,36 +49,47 @@ class WithArty100TSerialTLToGPIO extends HarnessBinder({ val artyTh = th.asInstanceOf[LazyRawModuleImp].wrapper.asInstanceOf[Arty100THarness] val harnessIO = IO(chiselTypeOf(port.io)).suggestName("serial_tl") harnessIO <> port.io - val clkIO = IOPin(harnessIO.clock) - val packagePinsWithPackageIOs = Seq( - ("G13", clkIO), - ("B11", IOPin(harnessIO.bits.out.valid)), - ("A11", IOPin(harnessIO.bits.out.ready)), - ("D12", IOPin(harnessIO.bits.in.valid)), - ("D13", IOPin(harnessIO.bits.in.ready)), - ("B18", IOPin(harnessIO.bits.out.bits, 0)), - ("A18", IOPin(harnessIO.bits.out.bits, 1)), - ("K16", IOPin(harnessIO.bits.out.bits, 2)), - ("E15", IOPin(harnessIO.bits.out.bits, 3)), - ("E16", IOPin(harnessIO.bits.in.bits, 0)), - ("D15", IOPin(harnessIO.bits.in.bits, 1)), - ("C15", IOPin(harnessIO.bits.in.bits, 2)), - ("J17", IOPin(harnessIO.bits.in.bits, 3)) - ) - packagePinsWithPackageIOs foreach { case (pin, io) => { - artyTh.xdc.addPackagePin(io, pin) - artyTh.xdc.addIOStandard(io, "LVCMOS33") - }} - // Don't add IOB to the clock, if its an input - if (DataMirror.directionOf(port.io.clock) == Direction.Input) { - packagePinsWithPackageIOs foreach { case (pin, io) => { - artyTh.xdc.addIOB(io) - }} + harnessIO match { + case io: DecoupledSerialIO => { + val clkIO = io match { + case io: LocallySyncSerialIO => IOPin(io.clock_out) + case io: ExternallySyncSerialIO => IOPin(io.clock_in) + } + val packagePinsWithPackageIOs = Seq( + ("G13", clkIO), + ("B11", IOPin(io.out.valid)), + ("A11", IOPin(io.out.ready)), + ("D12", IOPin(io.in.valid)), + ("D13", IOPin(io.in.ready)), + ("B18", IOPin(io.out.bits, 0)), + ("A18", IOPin(io.out.bits, 1)), + ("K16", IOPin(io.out.bits, 2)), + ("E15", IOPin(io.out.bits, 3)), + ("E16", IOPin(io.in.bits, 0)), + ("D15", IOPin(io.in.bits, 1)), + ("C15", IOPin(io.in.bits, 2)), + ("J17", IOPin(io.in.bits, 3)) + ) + packagePinsWithPackageIOs foreach { case (pin, io) => { + artyTh.xdc.addPackagePin(io, pin) + artyTh.xdc.addIOStandard(io, "LVCMOS33") + }} + + // Don't add IOB to the clock, if its an input + io match { + case io: LocallySyncSerialIO => packagePinsWithPackageIOs foreach { case (pin, io) => { + artyTh.xdc.addIOB(io) + }} + case io: ExternallySyncSerialIO => packagePinsWithPackageIOs.drop(1).foreach { case (pin, io) => { + artyTh.xdc.addIOB(io) + }} + } + + artyTh.sdc.addClock("ser_tl_clock", clkIO, 100) + artyTh.sdc.addGroup(pins = Seq(clkIO)) + artyTh.xdc.clockDedicatedRouteFalse(clkIO) + } } - - artyTh.sdc.addClock("ser_tl_clock", clkIO, 100) - artyTh.sdc.addGroup(pins = Seq(clkIO)) - artyTh.xdc.clockDedicatedRouteFalse(clkIO) } }) diff --git a/generators/chipyard/src/main/scala/example/FlatTestHarness.scala b/generators/chipyard/src/main/scala/example/FlatTestHarness.scala index 304c58a3..d9e37918 100644 --- a/generators/chipyard/src/main/scala/example/FlatTestHarness.scala +++ b/generators/chipyard/src/main/scala/example/FlatTestHarness.scala @@ -11,10 +11,10 @@ import freechips.rocketchip.util.{PlusArg} import freechips.rocketchip.subsystem.{CacheBlockBytes} import freechips.rocketchip.devices.debug.{SimJTAG} import freechips.rocketchip.jtag.{JTAGIO} -import testchipip.serdes.{SerialTLKey} +import testchipip.serdes.{SerialTLKey, LocallySyncSerialIO, ExternallySyncSerialIO} import testchipip.uart.{UARTAdapter} import testchipip.dram.{SimDRAM} -import testchipip.tsi.{TSIHarness, SimTSI} +import testchipip.tsi.{TSIHarness, SimTSI, SerialRAM} import chipyard.harness.{BuildTop} // A "flat" TestHarness that doesn't use IOBinders @@ -46,18 +46,25 @@ class FlatTestHarness(implicit val p: Parameters) extends Module { val serialTLManagerParams = sVal.manager.get require(serialTLManagerParams.isMemoryDevice) - withClockAndReset(clock, reset) { - val serial_bits = dut.serial_tl_pad.bits - if (DataMirror.directionOf(dut.serial_tl_pad.clock) == Direction.Input) { - dut.serial_tl_pad.clock := clock - } - val harnessRAM = TSIHarness.connectRAM( - p(SerialTLKey)(0), - lazyDut.system.serdessers(0), - serial_bits, - reset) - io.success := SimTSI.connect(harnessRAM.module.io.tsi, clock, reset) + // Figure out which clock drives the harness TLSerdes, based on the port type + val serial_ram_clock = dut.serial_tl_pad match { + case io: LocallySyncSerialIO => io.clock_out + case io: ExternallySyncSerialIO => clock + } + withClockAndReset(serial_ram_clock, reset) { + dut.serial_tl_pad match { + case io: ExternallySyncSerialIO => io.clock_in := clock + case io: LocallySyncSerialIO => + } + + // SerialRAM implements the memory regions the chip expects + val ram = Module(LazyModule(new SerialRAM(lazyDut.system.serdessers(0), p(SerialTLKey)(0))).module) + ram.io.ser.in <> dut.serial_tl_pad.out + dut.serial_tl_pad.in <> ram.io.ser.out + + // Allow TSI to master the chip + io.success := SimTSI.connect(ram.io.tsi, serial_ram_clock, reset) } // JTAG diff --git a/generators/chipyard/src/main/scala/harness/HarnessBinders.scala b/generators/chipyard/src/main/scala/harness/HarnessBinders.scala index 6710696d..128cae0e 100644 --- a/generators/chipyard/src/main/scala/harness/HarnessBinders.scala +++ b/generators/chipyard/src/main/scala/harness/HarnessBinders.scala @@ -17,7 +17,7 @@ import testchipip.tsi.{SimTSI, SerialRAM, TSI, TSIIO} import testchipip.soc.{TestchipSimDTM} import testchipip.spi.{SimSPIFlashModel} import testchipip.uart.{UARTAdapter, UARTToSerial} -import testchipip.serdes.{SerialWidthAdapter} +import testchipip.serdes._ import testchipip.iceblk.{SimBlockDevice, BlockDeviceModel} import testchipip.cosim.{SpikeCosim} import icenet.{NicLoopback, SimNetwork} @@ -207,33 +207,41 @@ class WithTiedOffDMI extends HarnessBinder({ class WithSerialTLTiedOff extends HarnessBinder({ case (th: HasHarnessInstantiators, port: SerialTLPort) => { - if (DataMirror.directionOf(port.io.clock) == Direction.Input) { - port.io.clock := false.B.asClock + port.io match { + case io: DecoupledSerialIO => io.out.ready := false.B; io.in.valid := false.B; io.in.bits := DontCare; + } + port.io match { + case io: LocallySyncSerialIO => + case io: ExternallySyncSerialIO => io.clock_in := false.B.asClock } - port.io.bits.out.ready := false.B - port.io.bits.in.valid := false.B - port.io.bits.in.bits := DontCare } }) class WithSimTSIOverSerialTL extends HarnessBinder({ case (th: HasHarnessInstantiators, port: SerialTLPort) => { - val bits = port.io.bits - if (DataMirror.directionOf(port.io.clock) == Direction.Input) { - port.io.clock := th.harnessBinderClock + port.io match { + case io: LocallySyncSerialIO => + case io: ExternallySyncSerialIO => io.clock_in := false.B.asClock + } + + port.io match { + case io: DecoupledSerialIO => { + // If the port is locally synchronous (provides a clock), drive everything with that clock + // Else, drive everything with the harnes clock + val clock = port.io match { + case io: LocallySyncSerialIO => io.clock_out + case io: ExternallySyncSerialIO => th.harnessBinderClock + } + withClock(clock) { + val ram = Module(LazyModule(new SerialRAM(port.serdesser, port.params)(port.serdesser.p)).module) + ram.io.ser.in <> io.out + io.in <> ram.io.ser.out + + val success = SimTSI.connect(ram.io.tsi, clock, th.harnessBinderReset) + when (success) { th.success := true.B } + } + } } - val ram = LazyModule(new SerialRAM(port.serdesser, port.params)(port.serdesser.p)) - Module(ram.module) - ram.module.io.ser <> port.io.bits - val tsi = Module(new SimTSI) - tsi.io.clock := th.harnessBinderClock - tsi.io.reset := th.harnessBinderReset - tsi.io.tsi <> ram.module.io.tsi.get - val exit = tsi.io.exit - val success = exit === 1.U - val error = exit >= 2.U - assert(!error, "*** FAILED *** (exit code = %d)\n", exit >> 1.U) - when (success) { th.success := true.B } } }) diff --git a/generators/chipyard/src/main/scala/harness/MultiHarnessBinders.scala b/generators/chipyard/src/main/scala/harness/MultiHarnessBinders.scala index d3371dfd..d89d2d98 100644 --- a/generators/chipyard/src/main/scala/harness/MultiHarnessBinders.scala +++ b/generators/chipyard/src/main/scala/harness/MultiHarnessBinders.scala @@ -10,7 +10,7 @@ import freechips.rocketchip.devices.debug._ import freechips.rocketchip.subsystem._ import freechips.rocketchip.util._ -import testchipip._ +import testchipip.serdes._ import chipyard._ import chipyard.iobinders.{GetSystemParameters, JTAGChipIO, HasChipyardPorts, Port, SerialTLPort} @@ -60,11 +60,14 @@ class WithMultiChipSerialTL(chip0: Int, chip1: Int, chip0portId: Int = 0, chip1p (p0: SerialTLPort) => p0.portId == chip0portId, (p1: SerialTLPort) => p1.portId == chip1portId, (th: HasHarnessInstantiators, p0: SerialTLPort, p1: SerialTLPort) => { - (DataMirror.directionOf(p0.io.clock), DataMirror.directionOf(p1.io.clock)) match { - case (Direction.Input, Direction.Output) => p0.io.clock := p1.io.clock - case (Direction.Output, Direction.Input) => p1.io.clock := p0.io.clock + def connectDecoupledSyncSerialIO(clkSource: LocallySyncSerialIO, clkSink: ExternallySyncSerialIO) = { + clkSink.clock_in := clkSource.clock_out + clkSink.in <> clkSource.out + clkSource.in <> clkSink.out + } + (p0.io, p1.io) match { + case (io0: LocallySyncSerialIO , io1: ExternallySyncSerialIO) => connectDecoupledSyncSerialIO(io0, io1) + case (io0: ExternallySyncSerialIO, io1: LocallySyncSerialIO) => connectDecoupledSyncSerialIO(io1, io0) } - p0.io.bits.in <> p1.io.bits.out - p1.io.bits.in <> p0.io.bits.out } ) diff --git a/generators/chipyard/src/main/scala/iobinders/Ports.scala b/generators/chipyard/src/main/scala/iobinders/Ports.scala index ba14cc39..feb7bccb 100644 --- a/generators/chipyard/src/main/scala/iobinders/Ports.scala +++ b/generators/chipyard/src/main/scala/iobinders/Ports.scala @@ -72,8 +72,9 @@ case class DMIPort (val getIO: () => ClockedDMIIO) case class JTAGPort (val getIO: () => JTAGChipIO) extends Port[JTAGChipIO] -case class SerialTLPort (val getIO: () => ClockedIO[SerialIO], val params: SerialTLParams, val serdesser: TLSerdesser, val portId: Int) - extends Port[ClockedIO[SerialIO]] +// Lack of nice union types in scala-2 means we have to set this type as Data +case class SerialTLPort (val getIO: () => Data, val params: SerialTLParams, val serdesser: TLSerdesser, val portId: Int) + extends Port[Data] case class UARTTSIPort (val getIO: () => UARTTSIIO) extends Port[UARTTSIIO] diff --git a/generators/firechip/src/main/scala/BridgeBinders.scala b/generators/firechip/src/main/scala/BridgeBinders.scala index 954c104c..25ae6668 100644 --- a/generators/firechip/src/main/scala/BridgeBinders.scala +++ b/generators/firechip/src/main/scala/BridgeBinders.scala @@ -15,6 +15,7 @@ import freechips.rocketchip.prci.{ClockBundle, ClockBundleParameters} import freechips.rocketchip.util.{ResetCatchAndSync} import sifive.blocks.devices.uart._ +import testchipip.serdes.{ExternallySyncSerialIO} import testchipip.tsi.{SerialRAM} import icenet.{CanHavePeripheryIceNIC, SimNetwork, NicLoopback, NICKey, NICIOvonly} @@ -67,18 +68,21 @@ class WithFireSimIOCellModels extends Config((site, here, up) => { class WithTSIBridgeAndHarnessRAMOverSerialTL extends HarnessBinder({ case (th: FireSim, port: SerialTLPort) => { - val bits = port.io.bits - port.io.clock := th.harnessBinderClock - val ram = LazyModule(new SerialRAM(port.serdesser, port.params)(port.serdesser.p)) - Module(ram.module) - ram.module.io.ser <> port.io.bits + port.io match { + case io: ExternallySyncSerialIO => { + io.clock_in := th.harnessBinderClock + val ram = Module(LazyModule(new SerialRAM(port.serdesser, port.params)(port.serdesser.p)).module) + ram.io.ser.in <> io.out + io.in <> ram.io.ser.out - // This assumes that: - // If ExtMem for the target is defined, then FASED bridge will be attached - // If FASED bridge is attached, loadmem widget is present - val hasMainMemory = th.chipParameters(th.p(MultiChipIdx))(ExtMem).isDefined - val mainMemoryName = Option.when(hasMainMemory)(MainMemoryConsts.globalName(th.p(MultiChipIdx))) - TSIBridge(th.harnessBinderClock, ram.module.io.tsi.get, mainMemoryName, th.harnessBinderReset.asBool)(th.p) + // This assumes that: + // If ExtMem for the target is defined, then FASED bridge will be attached + // If FASED bridge is attached, loadmem widget is present + val hasMainMemory = th.chipParameters(th.p(MultiChipIdx))(ExtMem).isDefined + val mainMemoryName = Option.when(hasMainMemory)(MainMemoryConsts.globalName(th.p(MultiChipIdx))) + TSIBridge(th.harnessBinderClock, ram.io.tsi.get, mainMemoryName, th.harnessBinderReset.asBool)(th.p) + } + } } }) diff --git a/generators/testchipip b/generators/testchipip index 70e19831..e53f78aa 160000 --- a/generators/testchipip +++ b/generators/testchipip @@ -1 +1 @@ -Subproject commit 70e198313a7e467f9219e4caba0158a96f851503 +Subproject commit e53f78aa189c0cf7e0d3a9b08b44222ca05ab160