diff --git a/fpga/src/main/scala/zcu102/Configs.scala b/fpga/src/main/scala/zcu102/Configs.scala new file mode 100644 index 000000000..2e4ca56d3 --- /dev/null +++ b/fpga/src/main/scala/zcu102/Configs.scala @@ -0,0 +1,96 @@ +package chipyard.fpga.zcu102 + +import sys.process._ + +import org.chipsalliance.cde.config.{Config, Parameters} +import freechips.rocketchip.subsystem.{SystemBusKey, PeripheryBusKey, ControlBusKey, ExtMem} +import freechips.rocketchip.devices.debug.{DebugModuleKey, ExportDebug, JTAG} +import freechips.rocketchip.devices.tilelink.{DevNullParams, BootROMLocated} +import freechips.rocketchip.diplomacy.{RegionType, AddressSet} +import freechips.rocketchip.resources.{DTSModel, DTSTimebase} + + +import sifive.blocks.devices.spi.{PeripherySPIKey, SPIParams} +import sifive.blocks.devices.uart.{PeripheryUARTKey, UARTParams} + +import sifive.fpgashells.shell.{DesignKey} +import sifive.fpgashells.shell.xilinx.{ZCU102ShellPMOD, ZCU102DDRSize} + +import testchipip.serdes.{SerialTLKey} + +import chipyard._ +import chipyard.harness._ + +class WithDefaultPeripherals extends Config((site, here, up) => { + case PeripheryUARTKey => List(UARTParams(address = BigInt(0x64000000L))) + case PeripherySPIKey => List(SPIParams(rAddress = BigInt(0x64001000L))) + case ZCU102ShellPMOD => "SDIO" +}) + +class WithSystemModifications extends Config((site, here, up) => { + case DTSTimebase => BigInt((1e6).toLong) + case BootROMLocated(x) => up(BootROMLocated(x), site).map { p => + // invoke makefile for sdboot + val freqMHz = (site(SystemBusKey).dtsFrequency.get / (1000 * 1000)).toLong + val make = s"make -C fpga/src/main/resources/zcu102/sdboot PBUS_CLK=${freqMHz} bin" + require (make.! == 0, "Failed to build bootrom") + p.copy(hang = 0x10000, contentFileName = s"./fpga/src/main/resources/zcu102/sdboot/build/sdboot.bin") + } + case ExtMem => up(ExtMem, site).map(x => x.copy(master = x.master.copy(size = site(ZCU102DDRSize)))) // set extmem to DDR size + case SerialTLKey => Nil // remove serialized tl port +}) + +// DOC include start: AbstractZCU102 and Rocket +class WithZCU102Tweaks extends Config( + // clocking + new chipyard.harness.WithAllClocksFromHarnessClockInstantiator ++ + new chipyard.clocking.WithPassthroughClockGenerator ++ + new chipyard.config.WithUniformBusFrequencies(100) ++ + new WithFPGAFrequency(100) ++ // default 100MHz freq + // harness binders + new WithUART ++ + new WithSPISDCard ++ + new WithDDRMem ++ + new WithJTAG ++ + // io binders + new chipyard.iobinders.WithUARTTSIPunchthrough ++ // Is it correctly? + new chipyard.iobinders.WithSPIIOPunchthrough ++ // Is it correctly? + // other configuration + new WithDefaultPeripherals ++ + new chipyard.config.WithTLBackingMemory ++ // use TL backing memory + new WithSystemModifications ++ // setup busses, use sdboot bootrom, setup ext. mem. size + // new chipyard.config.WithNoDebug ++ // remove debug module + new freechips.rocketchip.subsystem.WithoutTLMonitors ++ + new freechips.rocketchip.subsystem.WithNMemoryChannels(1) +) + +class RocketZCU102Config extends Config( + new WithFPGAFrequency(25) ++ + new WithZCU102Tweaks ++ + new chipyard.RocketConfig) +// DOC include end: AbstractZCU102 and Rocket + +class RocketZCU102ConfigWithHyp extends Config( + new freechips.rocketchip.system.HypervisorConfig ++ // Would like to support H-ext + new WithFPGAFrequency(25) ++ + new WithZCU102Tweaks ++ + new chipyard.RocketConfig) + +class BoomZCU102Config extends Config( + new WithFPGAFrequency(50) ++ + new WithZCU102Tweaks ++ + new chipyard.MegaBoomV3Config) //Changed to Small from Mega + +class WithFPGAFrequency(fMHz: Double) extends Config( + new chipyard.harness.WithHarnessBinderClockFreqMHz(fMHz) ++ + new chipyard.config.WithSystemBusFrequency(fMHz) ++ + new chipyard.config.WithPeripheryBusFrequency(fMHz) ++ + new chipyard.config.WithControlBusFrequency(fMHz) ++ + new chipyard.config.WithFrontBusFrequency(fMHz) ++ + new chipyard.config.WithMemoryBusFrequency(fMHz) +) + +class WithFPGAFreq25MHz extends WithFPGAFrequency(25) +class WithFPGAFreq50MHz extends WithFPGAFrequency(50) +class WithFPGAFreq75MHz extends WithFPGAFrequency(75) +class WithFPGAFreq100MHz extends WithFPGAFrequency(100) diff --git a/fpga/src/main/scala/zcu102/CustomOverlays.scala b/fpga/src/main/scala/zcu102/CustomOverlays.scala new file mode 100644 index 000000000..b4d4ccf40 --- /dev/null +++ b/fpga/src/main/scala/zcu102/CustomOverlays.scala @@ -0,0 +1,109 @@ +package chipyard.fpga.zcu102 + +import chisel3._ + +import freechips.rocketchip.diplomacy._ +import org.chipsalliance.cde.config.{Parameters, Field} +import freechips.rocketchip.tilelink.{TLInwardNode, TLAsyncCrossingSink} +import freechips.rocketchip.prci._ +import sifive.fpgashells.shell._ +import sifive.fpgashells.ip.xilinx._ +import sifive.fpgashells.shell.xilinx._ +import sifive.fpgashells.clocks._ +import sifive.fpgashells.devices.xilinx.xilinxzcu102mig.{XilinxZCU102MIGPads, XilinxZCU102MIGParams, XilinxZCU102MIG} + +class SysClock2ZCU102PlacedOverlay(val shell: ZCU102ShellBasicOverlays, name: String, val designInput: ClockInputDesignInput, val shellInput: ClockInputShellInput) + extends LVDSClockInputXilinxPlacedOverlay(name, designInput, shellInput) +{ + val node = shell { ClockSourceNode(freqMHz = 300, jitterPS = 50)(ValName(name)) } + + shell { InModuleBody { + shell.xdc.addPackagePin(io.p, "AL8") + shell.xdc.addPackagePin(io.n, "AL7") + shell.xdc.addIOStandard(io.p, "DIFF_SSTL12") + shell.xdc.addIOStandard(io.n, "DIFF_SSTL12") + } } +} +class SysClock2ZCU102ShellPlacer(shell: ZCU102ShellBasicOverlays, val shellInput: ClockInputShellInput)(implicit val valName: ValName) + extends ClockInputShellPlacer[ZCU102ShellBasicOverlays] +{ + def place(designInput: ClockInputDesignInput) = new SysClock2ZCU102PlacedOverlay(shell, valName.name, designInput, shellInput) +} + +case object ZCU102DDR2Size extends Field[BigInt](0x40000000L * 2) // 2GB +class DDR2ZCU102PlacedOverlay(val shell: ZCU102FPGATestHarness, name: String, val designInput: DDRDesignInput, val shellInput: DDRShellInput) + extends DDRPlacedOverlay[XilinxZCU102MIGPads](name, designInput, shellInput) +{ + val size = p(ZCU102DDRSize) + + val migParams = XilinxZCU102MIGParams(address = AddressSet.misaligned(di.baseAddress, size)) + val mig = LazyModule(new XilinxZCU102MIG(migParams)) + val ioNode = BundleBridgeSource(() => mig.module.io.cloneType) + val topIONode = shell { ioNode.makeSink() } + val ddrUI = shell { ClockSourceNode(freqMHz = 300) } + val areset = shell { ClockSinkNode(Seq(ClockSinkParameters())) } + areset := designInput.wrangler := ddrUI + + // since this uses a separate clk/rst need to put an async crossing + val asyncSink = LazyModule(new TLAsyncCrossingSink()) + val migClkRstNode = BundleBridgeSource(() => new Bundle { + val clock = Output(Clock()) + val reset = Output(Bool()) + }) + val topMigClkRstIONode = shell { migClkRstNode.makeSink() } + + def overlayOutput = DDROverlayOutput(ddr = mig.node) + def ioFactory = new XilinxZCU102MIGPads(size) + + InModuleBody { + ioNode.bundle <> mig.module.io + + // setup async crossing + asyncSink.module.clock := migClkRstNode.bundle.clock + asyncSink.module.reset := migClkRstNode.bundle.reset + } + + shell { InModuleBody { + require (shell.sys_clock2.get.isDefined, "Use of DDRZCU102Overlay depends on SysClock2ZCU102Overlay") + val (sys, _) = shell.sys_clock2.get.get.overlayOutput.node.out(0) + val (ui, _) = ddrUI.out(0) + val (ar, _) = areset.in(0) + + // connect the async fifo sync to sys_clock2 + topMigClkRstIONode.bundle.clock := sys.clock + topMigClkRstIONode.bundle.reset := sys.reset + + val port = topIONode.bundle.port + io <> port + ui.clock := port.c0_ddr4_ui_clk + ui.reset := /*!port.mmcm_locked ||*/ port.c0_ddr4_ui_clk_sync_rst + port.c0_sys_clk_i := sys.clock.asUInt + port.sys_rst := sys.reset // pllReset + port.c0_ddr4_aresetn := !(ar.reset.asBool) + + // 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( + + "AM8", "AM9", "AP8", "AN8", "AK10", "AJ10", "AP9", "AN9", "AP10", "AP11", "AM10", "AL10", "AM11", "AL11", // adr[0->13] + "AJ7", "AL5", "AJ9", "AK7", // we_n, cas_n, ras_n, bg + "AK12", "AJ12", // ba[0->1] + "AH9", "AK8", "AP7", "AN7", "AM3", "AP2", "AK9", // reset_n, act_n, ck_c, ck_t, cke, cs_n, odt + + "AK4", "AK5", "AN4", "AM4", "AP4", "AP5", "AM5", "AM6", "AK2", "AK3", "AL1", "AK1", "AN1", "AM1", "AP3", "AN3", // dq[0->15] + "AP6", "AL2", // dqs_c[0->1] + "AN6", "AL3", // dqs_t[0->1] + "AL6", "AN2") // dm_dbi_n[0->1] + + (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 DDR2ZCU102ShellPlacer(shell: ZCU102FPGATestHarness, val shellInput: DDRShellInput)(implicit val valName: ValName) + extends DDRShellPlacer[ZCU102FPGATestHarness] { + def place(designInput: DDRDesignInput) = new DDR2ZCU102PlacedOverlay(shell, valName.name, designInput, shellInput) +} + diff --git a/fpga/src/main/scala/zcu102/FMCUtil.scala b/fpga/src/main/scala/zcu102/FMCUtil.scala new file mode 100644 index 000000000..b6277a6d7 --- /dev/null +++ b/fpga/src/main/scala/zcu102/FMCUtil.scala @@ -0,0 +1,127 @@ +package chipyard.fpga.zcu102 + +import scala.collection.immutable.HashMap + +// TODO: was typed by hand, so this needs a once-over before it can be considered trustworthy + +object FMCMap { + // Take an FMC pin name and return the VCU118 package pin + // See https://www.xilinx.com/support/documentation/boards_and_kits/vcu118/ug1224-vcu118-eval-bd.pdf + // Pages 97-98 + // Omitted pins are not connected to a GPIO + // ZCU106 Updates: https://docs.xilinx.com/v/u/en-US/ug1244-zcu106-eval-bd + // Pages 105-109 + def apply(fmcPin: String): String = HashMap( + //pg 105 + "A2" -> "J4", + "A3" -> "J3", + "A6" -> "F2", + "A7" -> "F1", + "A10" -> "K2", + "A11" -> "K1", + "A14" -> "L4", + "A15" -> "L3", + "A18" -> "P2", + "A19" -> "P1", + "A22" -> "H6", + "A23" -> "H5", + "A26" -> "F6", + "A27" -> "F5", + "A30" -> "K6", + "A31" -> "K5", + "A34" -> "M6", + "A35" -> "M5", + "A38" -> "P6", + "A39" -> "P5", + "B12" -> "M2", + "B13" -> "M1", + "B16" -> "T2", + "B17" -> "T1", + "B20" -> "L8", + "B21" -> "L7", + "B32" -> "N4", + "B33" -> "N3", + "B36" -> "R4", + "B37" -> "R3", + //pg 106 + "C2" -> "G4", + "C3" -> "G3", + "C6" -> "H2", + "C7" -> "H1", + "C10" -> "AC2", + "C11" -> "AC1", + "C14" -> "W5", + "C15" -> "W4", + "C18" -> "AC7", + "C19" -> "AC6", + "C22" -> "N9", + "C23" -> "N8", + "C26" -> "M10", + "C27" -> "L10", + "D4" -> "G8", + "D5" -> "G7", + "D8" -> "AB4", + "D9" -> "AC4", + "D11" -> "AB3", + "D12" -> "AC3", + "D14" -> "W2", + "D15" -> "W1", + "D17" -> "AB8", + "D18" -> "AC8", + "D20" -> "P11", + "D21" -> "N11", + "D23" -> "L16", + "D24" -> "K16", + "D26" -> "L15", + "D27" -> "K15", + //pg 108 + "G2" -> "T8", + "G3" -> "R8", + "G6" -> "Y4", + "G7" -> "Y3", + "G9" -> "Y2", + "G10" -> "Y1", + "G12" -> "V4", + "G13" -> "V3", + "G15" -> "W7", + "G16" -> "W6", + "G18" -> "Y12", + "G19" -> "AA12", + "G21" -> "N13", + "G22" -> "M13", + "G24" -> "M15", + "G25" -> "M14", + "G27" -> "M11", + "G28" -> "L11", + "G30" -> "U9", + "G31" -> "U8", + "G33" -> "V8", + "G34" -> "V7", + "G36" -> "V12", + "G37" -> "V11", + "H4" -> "AA7", + "H5" -> "AA6", + "H7" -> "V2", + "H8" -> "V1", + "H10" -> "AA2", + "H11" -> "AA1", + "H13" -> "U5", + "H14" -> "U4", + "H16" -> "AB6", + "H17" -> "AB5", + "H19" -> "Y10", + "H20" -> "Y9", + "H22" -> "L13", + "H23" -> "K13", + "H25" -> "P12", + "H26" -> "N12", + "H28" -> "L12", + "H29" -> "K12", + "H31" -> "T7", + "H32" -> "T6", + "H34" -> "V6", + "H35" -> "U6", + "H37" -> "U11", + "H38" -> "T11" + )(fmcPin) +} \ No newline at end of file diff --git a/fpga/src/main/scala/zcu102/HarnessBinders.scala b/fpga/src/main/scala/zcu102/HarnessBinders.scala new file mode 100644 index 000000000..a15f4bbfe --- /dev/null +++ b/fpga/src/main/scala/zcu102/HarnessBinders.scala @@ -0,0 +1,52 @@ +package chipyard.fpga.zcu102 + +import chisel3._ +import chisel3.experimental.{BaseModule} + +import org.chipsalliance.diplomacy.nodes.{HeterogeneousBag} +import freechips.rocketchip.tilelink.{TLBundle} + +import sifive.blocks.devices.uart.{UARTPortIO} +import sifive.blocks.devices.spi.{HasPeripherySPI, SPIPortIO} + +import chipyard._ +import chipyard.harness._ +import chipyard.iobinders._ + +/*** UART ***/ +class WithUART extends HarnessBinder({ + case (th: ZCU102FPGATestHarnessImp, port: UARTPort, chipId: Int) => { + th.zcu102Outer.io_uart_bb.bundle <> port.io + } +}) + +/*** SPI ***/ +class WithSPISDCard extends HarnessBinder({ + case (th: ZCU102FPGATestHarnessImp, port: SPIPort, chipId: Int) => { + th.zcu102Outer.io_spi_bb.bundle <> port.io + } +}) + +/*** Experimental DDR ***/ +class WithDDRMem extends HarnessBinder({ + case (th: ZCU102FPGATestHarnessImp, port: TLMemPort, chipId: Int) => { + val bundles = th.zcu102Outer.ddrClient.out.map(_._1) + val ddrClientBundle = Wire(new HeterogeneousBag(bundles.map(_.cloneType))) + bundles.zip(ddrClientBundle).foreach { case (bundle, io) => bundle <> io } + ddrClientBundle <> port.io + } +}) + +class WithJTAG extends HarnessBinder({ + case (th: ZCU102FPGATestHarnessImp, port: JTAGPort, chipId: Int) => { + val jtag_io = th.zcu102Outer.jtagPlacedOverlay.overlayOutput.jtag.getWrappedValue + port.io.TCK := jtag_io.TCK + port.io.TMS := jtag_io.TMS + port.io.TDI := jtag_io.TDI + jtag_io.TDO.data := port.io.TDO + jtag_io.TDO.driven := true.B + // ignore srst_n + jtag_io.srst_n := DontCare + + } +}) diff --git a/fpga/src/main/scala/zcu102/IOBinders.scala b/fpga/src/main/scala/zcu102/IOBinders.scala new file mode 100644 index 000000000..db32d1586 --- /dev/null +++ b/fpga/src/main/scala/zcu102/IOBinders.scala @@ -0,0 +1,63 @@ + +package chipyard.fpga.zcu102 + +/* + This file has been replaced by + new chipyard.iobinders.WithUARTTSIPunchthrough ++ +*/ + +// import chisel3._ +// import chisel3.reflect.DataMirror + +// import freechips.rocketchip.diplomacy.{ResourceBinding, Resource, ResourceAddress, InModuleBody} +// import freechips.rocketchip.subsystem.{BaseSubsystem} +// import freechips.rocketchip.util.{HeterogeneousBag} +// import freechips.rocketchip.tilelink.{TLBundle} + +// import sifive.blocks.devices.uart._ +// import sifive.blocks.devices.spi._ + +// import chipyard.{CanHaveMasterTLMemPort} +// import chipyard.iobinders.{OverrideIOBinder, OverrideLazyIOBinder} + +// class WithUARTIOPassthrough extends OverrideIOBinder({ +// (system: HasPeripheryUART) => { +// val io_uart_pins_temp = system.uart.zipWithIndex.map { case (dio, i) => IO(dio.cloneType).suggestName(s"uart_$i") } +// (io_uart_pins_temp zip system.uart).map { case (io, sysio) => +// io <> sysio +// } +// (io_uart_pins_temp, Nil) +// } +// }) + + + + +// class WithSPIIOPassthrough extends OverrideLazyIOBinder({ +// (system: HasPeripherySPI) => { +// // attach resource to 1st SPI +// ResourceBinding { +// Resource(new MMCDevice(system.tlSpiNodes.head.device, 1), "reg").bind(ResourceAddress(0)) +// } + +// InModuleBody { +// system.asInstanceOf[BaseSubsystem].module match { case system: HasPeripherySPIModuleImp => { +// val io_spi_pins_temp = system.spi.zipWithIndex.map { case (dio, i) => IO(dio.cloneType).suggestName(s"spi_$i") } +// (io_spi_pins_temp zip system.spi).map { case (io, sysio) => +// io <> sysio +// } +// (io_spi_pins_temp, Nil) +// } } +// } +// } +// }) + +// class WithTLIOPassthrough extends OverrideIOBinder({ +// (system: CanHaveMasterTLMemPort) => { +// val io_tl_mem_pins_temp = IO(DataMirror.internal.chiselTypeClone[HeterogeneousBag[TLBundle]](system.mem_tl)).suggestName("tl_slave") +// io_tl_mem_pins_temp <> system.mem_tl +// (Seq(io_tl_mem_pins_temp), Nil) +// } +// }) + + diff --git a/fpga/src/main/scala/zcu102/TestHarness.scala b/fpga/src/main/scala/zcu102/TestHarness.scala new file mode 100644 index 000000000..55850a2e3 --- /dev/null +++ b/fpga/src/main/scala/zcu102/TestHarness.scala @@ -0,0 +1,166 @@ +package chipyard.fpga.zcu102 + +import chisel3._ +import chisel3.util._ + +import freechips.rocketchip.diplomacy.{LazyModule, LazyRawModuleImp, BundleBridgeSource} +import org.chipsalliance.cde.config.{Parameters} +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.diplomacy.{IdRange, TransferSizes} +import freechips.rocketchip.subsystem.{SystemBusKey} +import freechips.rocketchip.prci._ +import sifive.fpgashells.shell.xilinx._ +import sifive.fpgashells.ip.xilinx.{IBUF, PowerOnResetFPGAOnly} +import sifive.fpgashells.shell._ +import sifive.fpgashells.clocks._ + +import sifive.blocks.devices.uart.{PeripheryUARTKey, UARTPortIO} +import sifive.blocks.devices.spi.{PeripherySPIKey, SPIPortIO} + +import chipyard._ +import chipyard.harness._ + +class ZCU102FPGATestHarness(override implicit val p: Parameters) extends ZCU102ShellBasicOverlays { + + def dp = designParameters + + val pmod_is_sdio = p(ZCU102ShellPMOD) == "SDIO" + val jtag_location = Some(if (pmod_is_sdio) "FMC_J5" else "PMOD_J55") + + // // Order matters; ddr depends on sys_clock + val uart = Overlay(UARTOverlayKey, new UARTZCU102ShellPlacer(this, UARTShellInput())) + val sdio = if (pmod_is_sdio) Some(Overlay(SPIOverlayKey, new SDIOZCU102ShellPlacer(this, SPIShellInput()))) else None + val jtag = Overlay(JTAGDebugOverlayKey, new JTAGDebugZCU102ShellPlacer(this, JTAGDebugShellInput(location = jtag_location))) + val cjtag = Overlay(cJTAGDebugOverlayKey, new cJTAGDebugZCU102ShellPlacer(this, cJTAGDebugShellInput())) + val jtagBScan = Overlay(JTAGDebugBScanOverlayKey, new JTAGDebugBScanZCU102ShellPlacer(this, JTAGDebugBScanShellInput())) + val fmc = Overlay(PCIeOverlayKey, new PCIeZCU102FMCShellPlacer(this, PCIeShellInput())) + //val edge = Overlay(PCIeOverlayKey, new PCIeZCU102EdgeShellPlacer(this, PCIeShellInput())) + val sys_clock2 = Overlay(ClockInputOverlayKey, new SysClock2ZCU102ShellPlacer(this, ClockInputShellInput())) + val ddr2 = Overlay(DDROverlayKey, new DDR2ZCU102ShellPlacer(this, DDRShellInput())) + + + // DOC include start: ClockOverlay + // place all clocks in the shell + require(dp(ClockInputOverlayKey).size >= 1) + val sysClkNode = dp(ClockInputOverlayKey)(0).place(ClockInputDesignInput()).overlayOutput.node + + /*** Connect/Generate clocks ***/ + + // connect to the PLL that will generate multiple clocks + val harnessSysPLL = dp(PLLFactoryKey)() + harnessSysPLL := sysClkNode + + // create and connect to the dutClock + val dutFreqMHz = (dp(SystemBusKey).dtsFrequency.get / (1000 * 1000)).toInt + val dutClock = ClockSinkNode(freqMHz = dutFreqMHz) + println(s"ZCU102 FPGA Base Clock Freq: ${dutFreqMHz} MHz") + val dutWrangler = LazyModule(new ResetWrangler) + val dutGroup = ClockGroup() + dutClock := dutWrangler.node := dutGroup := harnessSysPLL + // DOC include end: ClockOverlay + + /*** UART ***/ + + // DOC include start: UartOverlay + // 1st UART goes to the ZCU102 dedicated UART + + val io_uart_bb = BundleBridgeSource(() => (new UARTPortIO(dp(PeripheryUARTKey).head))) + dp(UARTOverlayKey).head.place(UARTDesignInput(io_uart_bb)) + // DOC include end: UartOverlay + + /*** SPI ***/ + + // 1st SPI goes to the ZCU102 SDIO port + + val io_spi_bb = BundleBridgeSource(() => (new SPIPortIO(dp(PeripherySPIKey).head))) + dp(SPIOverlayKey).head.place(SPIDesignInput(dp(PeripherySPIKey).head, io_spi_bb)) + + /*** DDR ***/ + + val ddrNode = dp(DDROverlayKey).head.place(DDRDesignInput(dp(ExtTLMem).get.master.base, dutWrangler.node, harnessSysPLL)).overlayOutput.ddr + + // connect 1 mem. channel to the FPGA DDR + val ddrClient = TLClientNode(Seq(TLMasterPortParameters.v1(Seq(TLMasterParameters.v1( + name = "chip_ddr", + sourceId = IdRange(0, 1 << dp(ExtTLMem).get.master.idBits) + ))))) + ddrNode := TLWidthWidget(dp(ExtTLMem).get.master.beatBytes) := ddrClient + + // val ledOverlays = dp(LEDOverlayKey).map(_.place(LEDDesignInput())) + // val all_leds = ledOverlays.map(_.overlayOutput.led) + // val status_leds = all_leds.take(3) + // val reset_led = all_leds(4) + // val other_leds = all_leds.drop(4) + /*** JTAG ***/ + val jtagPlacedOverlay = dp(JTAGDebugOverlayKey).head.place(JTAGDebugDesignInput()) + // module implementation + override lazy val module = new ZCU102FPGATestHarnessImp(this) +} + +class ZCU102FPGATestHarnessImp(_outer: ZCU102FPGATestHarness) extends LazyRawModuleImp(_outer) with HasHarnessInstantiators { + override def provideImplicitClockToLazyChildren = true + val zcu102Outer = _outer + + val reset = IO(Input(Bool())).suggestName("reset") + _outer.xdc.addPackagePin(reset, "AM13") + _outer.xdc.addIOStandard(reset, "LVCMOS33") + + val resetIBUF = Module(new IBUF) + resetIBUF.io.I := reset + + val sysclk: Clock = _outer.sysClkNode.out.head._1.clock + + val powerOnReset: Bool = PowerOnResetFPGAOnly(sysclk) + _outer.sdc.addAsyncPath(Seq(powerOnReset)) + + val ereset: Bool = _outer.chiplink.get() match { + case Some(x: ChipLinkZCU102PlacedOverlay) => !x.ereset_n + case _ => false.B + } + + _outer.pllReset := (resetIBUF.io.O || powerOnReset || ereset) + + // reset setup + val hReset = Wire(Reset()) + hReset := _outer.dutClock.in.head._1.reset + + + + val sys_clk_mhz = _outer.sysClkNode.out.head._1.clock + val clk_50mhz = _outer.dutClock.in.head._1.clock + val clk_300mhz = _outer.sysClkNode.out.head._2.clock //What is this? + + // Blink the status LEDs for sanity + // withClockAndReset(sys_clk_mhz, _outer.pllReset) { + // val period = (BigInt(100) << 20) / _outer.status_leds.size + // val counter = RegInit(0.U(log2Ceil(period).W)) + // val on = RegInit(0.U(log2Ceil(_outer.status_leds.size).W)) + // _outer.status_leds.zipWithIndex.map { case (o,s) => o := on === s.U } + // counter := Mux(counter === (period-1).U, 0.U, counter + 1.U) + // when (counter === 0.U) { + // on := Mux(on === (_outer.status_leds.size-1).U, 0.U, on + 1.U) + // } + // } + + // withClockAndReset(clk_50mhz, _outer.pllReset) { + // val period = (BigInt(100) << 20) / (_outer.other_leds.size - 1) + // val counter = RegInit(0.U(log2Ceil(period).W)) + // val on = RegInit(0.U(log2Ceil(_outer.other_leds.size).W)) + // _outer.other_leds.zipWithIndex.map { case (o,s) => o := on === s.U } + // counter := Mux(counter === (period-1).U, 0.U, counter + 1.U) + // when (counter === 0.U) { + // on := Mux(on === (_outer.other_leds.size-1).U, 0.U, on + 1.U) + // } + // } + + // _outer.reset_led := _outer.pllReset + def referenceClockFreqMHz = _outer.dutFreqMHz + def referenceClock = _outer.dutClock.in.head._1.clock + def referenceReset = hReset + def success = { require(false, "Unused"); false.B } + + childClock := referenceClock + childReset := referenceReset + + instantiateChipTops() +}