package chipyard.fpga.vcu118 import chisel3._ import chisel3.experimental.{IO} 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 VCU118FPGATestHarness(override implicit val p: Parameters) extends VCU118ShellBasicOverlays { def dp = designParameters val pmod_is_sdio = p(VCU118ShellPMOD) == "SDIO" val jtag_location = Some(if (pmod_is_sdio) "FMC_J2" else "PMOD_J52") // Order matters; ddr depends on sys_clock val uart = Overlay(UARTOverlayKey, new UARTVCU118ShellPlacer(this, UARTShellInput())) val sdio = if (pmod_is_sdio) Some(Overlay(SPIOverlayKey, new SDIOVCU118ShellPlacer(this, SPIShellInput()))) else None val jtag = Overlay(JTAGDebugOverlayKey, new JTAGDebugVCU118ShellPlacer(this, JTAGDebugShellInput(location = jtag_location))) val cjtag = Overlay(cJTAGDebugOverlayKey, new cJTAGDebugVCU118ShellPlacer(this, cJTAGDebugShellInput())) val jtagBScan = Overlay(JTAGDebugBScanOverlayKey, new JTAGDebugBScanVCU118ShellPlacer(this, JTAGDebugBScanShellInput())) val fmc = Overlay(PCIeOverlayKey, new PCIeVCU118FMCShellPlacer(this, PCIeShellInput())) val edge = Overlay(PCIeOverlayKey, new PCIeVCU118EdgeShellPlacer(this, PCIeShellInput())) val sys_clock2 = Overlay(ClockInputOverlayKey, new SysClock2VCU118ShellPlacer(this, ClockInputShellInput())) val ddr2 = Overlay(DDROverlayKey, new DDR2VCU118ShellPlacer(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"VCU118 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 VCU118 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 VCU118 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 // module implementation override lazy val module = new VCU118FPGATestHarnessImp(this) } class VCU118FPGATestHarnessImp(_outer: VCU118FPGATestHarness) extends LazyRawModuleImp(_outer) with HasHarnessInstantiators { override def provideImplicitClockToLazyChildren = true val vcu118Outer = _outer val reset = IO(Input(Bool())).suggestName("reset") _outer.xdc.addPackagePin(reset, "L19") _outer.xdc.addIOStandard(reset, "LVCMOS12") 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: ChipLinkVCU118PlacedOverlay) => !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 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() }