From 6aae66c54fe3653a3aeb294fa4bdd8843becd673 Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Fri, 6 Nov 2020 15:50:28 -0800 Subject: [PATCH] Add TSI Host Widget --- .../main/scala/vcu118/bringup/Configs.scala | 1 + .../scala/vcu118/bringup/CustomOverlays.scala | 208 +++++++++++++----- .../scala/vcu118/bringup/DigitalTop.scala | 2 - .../scala/vcu118/bringup/HarnessBinders.scala | 27 +++ .../main/scala/vcu118/bringup/IOBinders.scala | 14 +- .../scala/vcu118/bringup/TestHarness.scala | 26 +++ generators/testchipip | 2 +- 7 files changed, 217 insertions(+), 63 deletions(-) diff --git a/fpga/src/main/scala/vcu118/bringup/Configs.scala b/fpga/src/main/scala/vcu118/bringup/Configs.scala index 4c6cd5ad..f6e4880c 100644 --- a/fpga/src/main/scala/vcu118/bringup/Configs.scala +++ b/fpga/src/main/scala/vcu118/bringup/Configs.scala @@ -73,6 +73,7 @@ class WithBringupAdditions extends Config( new WithBringupSPI ++ new WithBringupI2C ++ new WithBringupGPIO ++ + new WithBringupTSIHost ++ new WithTSITLIOPassthrough ++ new WithI2CIOPassthrough ++ new WithGPIOIOPassthrough ++ diff --git a/fpga/src/main/scala/vcu118/bringup/CustomOverlays.scala b/fpga/src/main/scala/vcu118/bringup/CustomOverlays.scala index 30a25afe..b138038d 100644 --- a/fpga/src/main/scala/vcu118/bringup/CustomOverlays.scala +++ b/fpga/src/main/scala/vcu118/bringup/CustomOverlays.scala @@ -4,10 +4,16 @@ import chisel3._ import chisel3.experimental.{attach} import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.config.{Parameters, Field} +import freechips.rocketchip.tilelink.{TLInwardNode} import sifive.fpgashells.shell._ import sifive.fpgashells.ip.xilinx._ import sifive.fpgashells.shell.xilinx._ +import sifive.fpgashells.clocks._ +import sifive.fpgashells.devices.xilinx.xilinxvcu118mig.{XilinxVCU118MIGPads, XilinxVCU118MIGParams, XilinxVCU118MIG} + +import testchipip.{TSIHostParams, TSIHostWidgetIO} import chipyard.fpga.vcu118.{FMCPMap} @@ -144,58 +150,150 @@ class BringupGPIOVCU118ShellPlacer(shell: VCU118ShellBasicOverlays, val shellInp def place(designInput: GPIODesignInput) = new BringupGPIOVCU118PlacedOverlay(shell, valName.name, designInput, shellInput, gpioNames) } -//case class TSIShellInput() -//case class TSIDesignInput( -// -// )( -// implicit val p: Parameters)extends DDRDesignInput -// -//abstract class TSIOverlay(val params: TSIOverlayParams) -// extends IOOverlay[TLTSIWithDDRIO, TLTSIHostWidget] -//{ -// implicit val p = params.p -// -// // instantiate the tsi host widget and setup necessary connections -// val (tlTsiHost, tlTsiMemNode) = TLTSIHostWidget.attach(TSIHostWidgetAttachParams(params.tsiHostParams, params.controlBus)) -// val tlTsiHostIONodeSink = tlTsiHost.ioNode.makeSink -// -// // instantiate the DDR -// val size = p(TSIMigDDRSize) -// val migParams = XilinxVCU118MIGParams(address = AddressSet.misaligned(params.tsiHostParams.targetBaseAddress, size)) -// val mig = LazyModule(new XilinxVCU118MIG(migParams)) -// val tsiIONode = BundleBridgeSource(() => new TSIHostWidgetIO(params.tsiHostParams.serialIfWidth)) -// val topTSIIONode = shell { tsiIONode.makeSink() } -// val ddrIONode = BundleBridgeSource(() => mig.module.io.cloneType) -// val topDDRIONode = shell { ddrIONode.makeSink() } -// val ddrUI = shell { ClockSourceNode(freqMHz = 200) } -// val areset = shell { ClockSinkNode(Seq(ClockSinkParameters())) } -// areset := params.ddrParams.wrangler := ddrUI -// val asyncSink = LazyModule(new TLAsyncCrossingSink) -// val migClockReset = BundleBridgeSource(() => new Bundle { -// val clock = Output(Clock()) -// val reset = Output(Bool()) -// }) -// val migClockResetTop = shell { migClockReset.makeSink() } -// -// // connect them -// (mig.node := TLFragmenter(32,64,holdFirstDeny=true) := TLCacheCork() := TLSinkSetter(1 << 1) := TLSourceShrinker(1 << 4) := tlTsiMemNode) -// -// def designOutput = tlTsiHost -// def ioFactory = new TLTSIWithDDRIO(params.tsiHostParams.serialIfWidth, size) // top level io of the shell -// -// InModuleBody { -// val (t, _) = tsiIONode.out(0) -// val tsi = tlTsiHostIONodeSink.bundle -// tsi.serial_clock := t.serial_clock -// tsi.serial.in.bits := t.serial.in.bits -// tsi.serial.in.valid := t.serial.in.valid -// tsi.serial.out.ready := t.serial.out.ready -// t.serial.out.bits := tsi.serial.out.bits -// t.serial.out.valid := tsi.serial.out.valid -// t.serial.in.ready := tsi.serial.in.ready -// ddrIONode.bundle <> mig.module.io -// asyncSink.module.clock := migClockReset.bundle.clock -// asyncSink.module.reset := migClockReset.bundle.reset -// } -//} -// +case class TSIHostShellInput() +case class TSIHostDesignInput( + wrangler: ClockAdapterNode, + corePLL: PLLNode, + tsiHostParams: TSIHostParams, + node: BundleBridgeSource[TSIHostWidgetIO], + vc7074gbdimm: Boolean = false + )( + implicit val p: Parameters) +case class TSIHostOverlayOutput(ddr: TLInwardNode) +trait TSIHostShellPlacer[Shell] extends ShellPlacer[TSIHostDesignInput, TSIHostShellInput, TSIHostOverlayOutput] + +class TSIHostWithDDRIO(val w: Int, val size: BigInt) extends Bundle { + val tsi = new TSIHostWidgetIO(w) + val ddr = new XilinxVCU118MIGPads(size) +} + +case object TSIHostOverlayKey extends Field[Seq[DesignPlacer[TSIHostDesignInput, TSIHostShellInput, TSIHostOverlayOutput]]](Nil) + +abstract class TSIHostPlacedOverlay[IO <: Data](val name: String, val di: TSIHostDesignInput, val si: TSIHostShellInput) + extends IOPlacedOverlay[IO, TSIHostDesignInput, TSIHostShellInput, TSIHostOverlayOutput] +{ + implicit val p = di.p +} + +case object TSIHostVCU118DDRSize extends Field[BigInt](0x40000000L * 2) // 2GB +class TSIHostVCU118PlacedOverlay(val shell: VCU118ShellBasicOverlays, name: String, val designInput: TSIHostDesignInput, val shellInput: TSIHostShellInput) + extends TSIHostPlacedOverlay[TSIHostWithDDRIO](name, designInput, shellInput) +{ + val size = p(TSIHostVCU118DDRSize) + + // connect the DDR + val migParams = XilinxVCU118MIGParams(address = AddressSet.misaligned(di.tsiHostParams.targetBaseAddress, size)) + val mig = LazyModule(new XilinxVCU118MIG(migParams)) + val ioNode = BundleBridgeSource(() => mig.module.io.cloneType) + val topIONode = shell { ioNode.makeSink() } + val ddrUI = shell { ClockSourceNode(freqMHz = 200) } + val areset = shell { ClockSinkNode(Seq(ClockSinkParameters())) } + areset := designInput.wrangler := ddrUI + + // connect the TSI serial + val tlTsiSerialSink = di.node.makeSink() + val tsiIoNode = BundleBridgeSource(() => new TSIHostWidgetIO(di.tsiHostParams.serialIfWidth)) + val topTSIIONode = shell { tsiIoNode.makeSink() } + + def overlayOutput = TSIHostOverlayOutput(ddr = mig.node) + def ioFactory = new TSIHostWithDDRIO(di.tsiHostParams.serialIfWidth, size) + + InModuleBody { + // connect MIG + ioNode.bundle <> mig.module.io + + // connect TSI serial + val tsiSourcePort = tsiIoNode.bundle + val tsiSinkPort = tlTsiSerialSink.bundle + tsiSinkPort.serial_clock := tsiSourcePort.serial_clock + tsiSourcePort.serial.out.bits := tsiSinkPort.serial.out.bits + tsiSourcePort.serial.out.valid := tsiSinkPort.serial.out.valid + tsiSinkPort.serial.out.ready := tsiSourcePort.serial.out.ready + tsiSinkPort.serial.in.bits := tsiSourcePort.serial.in.bits + tsiSinkPort.serial.in.valid := tsiSourcePort.serial.in.valid + tsiSourcePort.serial.in.ready := tsiSinkPort.serial.in.ready + } + + // connect the DDR port + shell { InModuleBody { + require (shell.sys_clock.get.isDefined, "Use of DDRVCU118Overlay depends on SysClockVCU118Overlay") + val (sys, _) = shell.sys_clock.get.get.overlayOutput.node.out(0) + val (ui, _) = ddrUI.out(0) + val (ar, _) = areset.in(0) + val ddrPort = topIONode.bundle.port + io.ddr <> ddrPort + ui.clock := ddrPort.c0_ddr4_ui_clk + ui.reset := /*!ddrPort.mmcm_locked ||*/ ddrPort.c0_ddr4_ui_clk_sync_rst + ddrPort.c0_sys_clk_i := sys.clock.asUInt + ddrPort.sys_rst := sys.reset // pllReset + ddrPort.c0_ddr4_aresetn := !ar.reset + + // This was just copied from the SiFive example, but it's hard to follow. + // The pins are emitted in the following order: + // adr[0->13], we_n, cas_n, ras_n, bg, ba[0->1], reset_n, act_n, ck_c, ck_t, cke, cs_n, odt, dq[0->63], dqs_c[0->7], dqs_t[0->7], dm_dbi_n[0->7] + val allddrpins = Seq( + "AM27", "AL27", "AP26", "AP25", "AN28", "AM28", "AP28", "AP27", "AN26", "AM26", "AR28", "AR27", "AV25", "AT25", // adr[0->13] + "AV28", "AU26", "AV26", "AU27", // we_n, cas_n, ras_n, bg + "AR25", "AU28", // ba[0->1] + "BD35", "AN25", "AT27", "AT26", "AW28", "AY29", "BB29", // reset_n, act_n, ck_c, ck_t, cke, cs_n, odt + "BD30", "BE30", "BD32", "BE33", "BC33", "BD33", "BC31", "BD31", "BA32", "BB33", "BA30", "BA31", "AW31", "AW32", "AY32", "AY33", // dq[0->15] + "AV30", "AW30", "AU33", "AU34", "AT31", "AU32", "AU31", "AV31", "AR33", "AT34", "AT29", "AT30", "AP30", "AR30", "AN30", "AN31", // dq[16->31] + "BE34", "BF34", "BC35", "BC36", "BD36", "BE37", "BF36", "BF37", "BD37", "BE38", "BC39", "BD40", "BB38", "BB39", "BC38", "BD38", // dq[32->47] + "BB36", "BB37", "BA39", "BA40", "AW40", "AY40", "AY38", "AY39", "AW35", "AW36", "AU40", "AV40", "AU38", "AU39", "AV38", "AV39", // dq[48->63] + "BF31", "BA34", "AV29", "AP32", "BF35", "BF39", "BA36", "AW38", // dqs_c[0->7] + "BF30", "AY34", "AU29", "AP31", "BE35", "BE39", "BA35", "AW37", // dqs_t[0->7] + "BE32", "BB31", "AV33", "AR32", "BC34", "BE40", "AY37", "AV35") // dm_dbi_n[0->7] + + (IOPin.of(io) zip allddrpins) foreach { case (io, pin) => shell.xdc.addPackagePin(io, pin) } + } } + + shell.sdc.addGroup(pins = Seq(mig.island.module.blackbox.io.c0_ddr4_ui_clk)) +} + +class BringupTSIHostVCU118PlacedOverlay(override val shell: VCU118ShellBasicOverlays, override val name: String, override val designInput: TSIHostDesignInput, override val shellInput: TSIHostShellInput) + extends TSIHostVCU118PlacedOverlay(shell, name, designInput, shellInput) +{ + // connect the TSI port + shell { InModuleBody { + // connect TSI signals + val tsiPort = topTSIIONode.bundle + io.tsi <> tsiPort + + require(di.tsiHostParams.serialIfWidth == 4) + + val clkIo = IOPin(io.tsi.serial_clock) + val packagePinsWithPackageIOs = Seq( + (FMCPMap("D8"), clkIo), + (FMCPMap("D17"), IOPin(io.tsi.serial.out.ready)), + (FMCPMap("D18"), IOPin(io.tsi.serial.out.valid)), + (FMCPMap("D11"), IOPin(io.tsi.serial.out.bits, 0)), + (FMCPMap("D12"), IOPin(io.tsi.serial.out.bits, 1)), + (FMCPMap("D14"), IOPin(io.tsi.serial.out.bits, 2)), + (FMCPMap("D15"), IOPin(io.tsi.serial.out.bits, 3)), + (FMCPMap("D26"), IOPin(io.tsi.serial.in.ready)), + (FMCPMap("D27"), IOPin(io.tsi.serial.in.valid)), + (FMCPMap("D20"), IOPin(io.tsi.serial.in.bits, 0)), + (FMCPMap("D21"), IOPin(io.tsi.serial.in.bits, 1)), + (FMCPMap("D23"), IOPin(io.tsi.serial.in.bits, 2)), + (FMCPMap("D24"), IOPin(io.tsi.serial.in.bits, 3))) + + packagePinsWithPackageIOs foreach { case (pin, io) => { + shell.xdc.addPackagePin(io, pin) + shell.xdc.addIOStandard(io, "LVCMOS18") + } } + + // Don't add an IOB to the clock + (packagePinsWithPackageIOs take 1) foreach { case (pin, io) => { + shell.xdc.addIOB(io) + } } + + shell.sdc.addClock("TSI_CLK", clkIo, 50) + shell.sdc.addGroup(pins = Seq(clkIo)) + shell.xdc.clockDedicatedRouteFalse(clkIo) + } } +} + +class BringupTSIHostVCU118ShellPlacer(shell: VCU118ShellBasicOverlays, val shellInput: TSIHostShellInput)(implicit val valName: ValName) + extends TSIHostShellPlacer[VCU118ShellBasicOverlays] { + def place(designInput: TSIHostDesignInput) = new BringupTSIHostVCU118PlacedOverlay(shell, valName.name, designInput, shellInput) +} diff --git a/fpga/src/main/scala/vcu118/bringup/DigitalTop.scala b/fpga/src/main/scala/vcu118/bringup/DigitalTop.scala index a9105e26..42ea7af2 100644 --- a/fpga/src/main/scala/vcu118/bringup/DigitalTop.scala +++ b/fpga/src/main/scala/vcu118/bringup/DigitalTop.scala @@ -10,7 +10,6 @@ import freechips.rocketchip.diplomacy._ import freechips.rocketchip.tilelink._ import chipyard.fpga.vcu118.{VCU118DigitalTop, VCU118DigitalTopModule} - // ------------------------------------ // BringupVCU118 DigitalTop // ------------------------------------ @@ -24,4 +23,3 @@ class BringupVCU118DigitalTop(implicit p: Parameters) extends VCU118DigitalTop class BringupVCU118DigitalTopModule[+L <: BringupVCU118DigitalTop](l: L) extends VCU118DigitalTopModule(l) with sifive.blocks.devices.i2c.HasPeripheryI2CModuleImp - with testchipip.HasPeripheryTSIHostWidgetModuleImp diff --git a/fpga/src/main/scala/vcu118/bringup/HarnessBinders.scala b/fpga/src/main/scala/vcu118/bringup/HarnessBinders.scala index 531b3c8d..02b821b4 100644 --- a/fpga/src/main/scala/vcu118/bringup/HarnessBinders.scala +++ b/fpga/src/main/scala/vcu118/bringup/HarnessBinders.scala @@ -3,11 +3,16 @@ package chipyard.fpga.vcu118.bringup import chisel3._ import chisel3.experimental.{Analog, IO, BaseModule} +import freechips.rocketchip.util.{HeterogeneousBag} +import freechips.rocketchip.tilelink.{TLBundle} + import sifive.blocks.devices.uart.{HasPeripheryUARTModuleImp, UARTPortIO} import sifive.blocks.devices.spi.{HasPeripherySPI, SPIPortIO} import sifive.blocks.devices.i2c.{HasPeripheryI2CModuleImp, I2CPort} import sifive.blocks.devices.gpio.{HasPeripheryGPIOModuleImp, GPIOPortIO} +import testchipip.{HasPeripheryTSIHostWidget, TSIHostWidgetIO} + import chipyard.{HasHarnessSignalReferences} import chipyard.harness.{ComposeHarnessBinder, OverrideHarnessBinder} @@ -54,3 +59,25 @@ class WithBringupGPIO extends OverrideHarnessBinder({ } } } }) + +/*** TSI Host Widget ***/ +class WithBringupTSIHost extends OverrideHarnessBinder({ + (system: HasPeripheryTSIHostWidget, th: BaseModule with HasHarnessSignalReferences, ports: Seq[Data]) => { + th match { case vcu118th: BringupVCU118FPGATestHarnessImp => { + require(ports.size == 2) // 1st goes to the TL mem, 2nd goes to the serial link + + ports.head match { case tlPort: HeterogeneousBag[TLBundle] => + val tsiBundles = vcu118th.bringupOuter.tsiDdrClient.out.map(_._1) + val tsiDdrClientBundle = Wire(new HeterogeneousBag(tsiBundles.map(_.cloneType))) + tsiBundles.zip(tsiDdrClientBundle).foreach { case (bundle, io) => bundle <> io } + tsiDdrClientBundle <> tlPort + } + + ports.last match { case serialPort: TSIHostWidgetIO => + vcu118th.bringupOuter.io_tsi_serial_bb.bundle <> serialPort + } + } } + } +}) + + diff --git a/fpga/src/main/scala/vcu118/bringup/IOBinders.scala b/fpga/src/main/scala/vcu118/bringup/IOBinders.scala index 32badd2a..87763cde 100644 --- a/fpga/src/main/scala/vcu118/bringup/IOBinders.scala +++ b/fpga/src/main/scala/vcu118/bringup/IOBinders.scala @@ -9,7 +9,7 @@ import freechips.rocketchip.tilelink.{TLBundle} import sifive.blocks.devices.gpio.{HasPeripheryGPIOModuleImp} import sifive.blocks.devices.i2c.{HasPeripheryI2CModuleImp} -import testchipip.{HasPeripheryTSIHostWidget} +import testchipip.{HasPeripheryTSIHostWidget, TSIHostWidgetIO} import chipyard.iobinders.{OverrideIOBinder} @@ -35,9 +35,13 @@ class WithI2CIOPassthrough extends OverrideIOBinder({ class WithTSITLIOPassthrough extends OverrideIOBinder({ (system: HasPeripheryTSIHostWidget) => { - require(system.tsiMem.size == 1) - val io_tsi_tl_mem_pins_temp = IO(DataMirror.internal.chiselTypeClone[HeterogeneousBag[TLBundle]](system.tsiMem.head)).suggestName("tsi_tl_slave") - io_tsi_tl_mem_pins_temp <> system.tsiMem.head - (Seq(io_tsi_tl_mem_pins_temp), Nil) + require(system.tsiTLMem.size == 1) + val io_tsi_tl_mem_pins_temp = IO(DataMirror.internal.chiselTypeClone[HeterogeneousBag[TLBundle]](system.tsiTLMem.head)).suggestName("tsi_tl_slave") + io_tsi_tl_mem_pins_temp <> system.tsiTLMem.head + + require(system.tsiSerial.size == 1) + val io_tsi_serial_pins_temp = IO(DataMirror.internal.chiselTypeClone[TSIHostWidgetIO](system.tsiSerial.head)).suggestName("tsi_serial") + io_tsi_serial_pins_temp <> system.tsiSerial.head + (Seq(io_tsi_tl_mem_pins_temp, io_tsi_serial_pins_temp), Nil) } }) diff --git a/fpga/src/main/scala/vcu118/bringup/TestHarness.scala b/fpga/src/main/scala/vcu118/bringup/TestHarness.scala index 8a4ae8fc..e3b4c137 100644 --- a/fpga/src/main/scala/vcu118/bringup/TestHarness.scala +++ b/fpga/src/main/scala/vcu118/bringup/TestHarness.scala @@ -17,8 +17,12 @@ import sifive.blocks.devices.spi._ import sifive.blocks.devices.i2c._ import sifive.blocks.devices.gpio._ +import testchipip.{HasPeripheryTSIHostWidget, PeripheryTSIHostKey, TSIHostWidgetIO, TLSinkSetter} + import chipyard.fpga.vcu118.{VCU118FPGATestHarness, VCU118FPGATestHarnessImp} +import chipyard.{ChipTop} + class BringupVCU118FPGATestHarness(override implicit val p: Parameters) extends VCU118FPGATestHarness { /*** UART ***/ @@ -63,6 +67,28 @@ class BringupVCU118FPGATestHarness(override implicit val p: Parameters) extends placer.place(GPIODesignInput(params, io_gpio_bb(i))) } + /*** TSI Host Widget ***/ + require(dp(PeripheryTSIHostKey).size == 1) + + val tsi_host = Overlay(TSIHostOverlayKey, new BringupTSIHostVCU118ShellPlacer(this, TSIHostShellInput())) + + val io_tsi_serial_bb = BundleBridgeSource(() => (new TSIHostWidgetIO(dp(PeripheryTSIHostKey).head.serialIfWidth))) + val tsiDdrPlaced = dp(TSIHostOverlayKey).head.place(TSIHostDesignInput(dutWrangler.node, harnessSysPLL, dp(PeripheryTSIHostKey).head, io_tsi_serial_bb)) + + // connect 1 mem. channel to the FPGA DDR + val inTsiParams = topDesign match { case td: ChipTop => + td.lazySystem match { case lsys: HasPeripheryTSIHostWidget => + lsys.tsiMemTLNodes.head.edges.in(0) + } + } + val tsiDdrClient = TLClientNode(Seq(inTsiParams.master)) + (tsiDdrPlaced.overlayOutput.ddr + := TLFragmenter(8,64,holdFirstDeny=true) + := TLCacheCork() + := TLAtomicAutomata(passthrough=false) + := TLSinkSetter(64) + := tsiDdrClient) + // module implementation override lazy val module = new BringupVCU118FPGATestHarnessImp(this) } diff --git a/generators/testchipip b/generators/testchipip index 5dae68ef..e956a60c 160000 --- a/generators/testchipip +++ b/generators/testchipip @@ -1 +1 @@ -Subproject commit 5dae68efbc925d09c6a8758064e88f6a3661baa2 +Subproject commit e956a60cbfd848c31bd849ffe0140eb0f9af2524