From fb793d7ee993dc594246bc769f4f7157f227187c Mon Sep 17 00:00:00 2001 From: Haoan Li Date: Thu, 24 Nov 2022 16:08:15 +0900 Subject: [PATCH] Add support for VC707 fpga board --- fpga/Makefile | 14 ++ fpga/src/main/resources/vc707 | 1 + fpga/src/main/scala/vc707/Configs.scala | 78 +++++++++++ .../src/main/scala/vc707/HarnessBinders.scala | 39 ++++++ fpga/src/main/scala/vc707/IOBinders.scala | 53 ++++++++ fpga/src/main/scala/vc707/TestHarness.scala | 122 ++++++++++++++++++ 6 files changed, 307 insertions(+) create mode 120000 fpga/src/main/resources/vc707 create mode 100644 fpga/src/main/scala/vc707/Configs.scala create mode 100644 fpga/src/main/scala/vc707/HarnessBinders.scala create mode 100644 fpga/src/main/scala/vc707/IOBinders.scala create mode 100644 fpga/src/main/scala/vc707/TestHarness.scala diff --git a/fpga/Makefile b/fpga/Makefile index c6e161ee..60d67d4e 100644 --- a/fpga/Makefile +++ b/fpga/Makefile @@ -16,6 +16,20 @@ sim_name := none ######################################################################################### SUB_PROJECT ?= vcu118 +ifeq ($(SUB_PROJECT),vc707) + SBT_PROJECT ?= fpga_platforms + MODEL ?= VC707FPGATestHarness + VLOG_MODEL ?= VC707FPGATestHarness + MODEL_PACKAGE ?= chipyard.fpga.vc707 + CONFIG ?= RocketVC707Config + CONFIG_PACKAGE ?= chipyard.fpga.vc707 + GENERATOR_PACKAGE ?= chipyard + TB ?= none # unused + TOP ?= ChipTop + BOARD ?= vc707 + FPGA_BRAND ?= xilinx +endif + ifeq ($(SUB_PROJECT),vcu118) SBT_PROJECT ?= fpga_platforms MODEL ?= VCU118FPGATestHarness diff --git a/fpga/src/main/resources/vc707 b/fpga/src/main/resources/vc707 new file mode 120000 index 00000000..968bccac --- /dev/null +++ b/fpga/src/main/resources/vc707 @@ -0,0 +1 @@ +vcu118 \ No newline at end of file diff --git a/fpga/src/main/scala/vc707/Configs.scala b/fpga/src/main/scala/vc707/Configs.scala new file mode 100644 index 00000000..7acb2bb9 --- /dev/null +++ b/fpga/src/main/scala/vc707/Configs.scala @@ -0,0 +1,78 @@ +package chipyard.fpga.vc707 + +import sys.process._ + +import freechips.rocketchip.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.{DTSModel, DTSTimebase, RegionType, AddressSet} +import freechips.rocketchip.tile.{XLen} + +import sifive.blocks.devices.spi.{PeripherySPIKey, SPIParams} +import sifive.blocks.devices.uart.{PeripheryUARTKey, UARTParams} + +import sifive.fpgashells.shell.{DesignKey} +import sifive.fpgashells.shell.xilinx.{VC7074GDDRSize} + +import testchipip.{SerialTLKey} + +import chipyard.{BuildSystem, ExtTLMem, DefaultClockFrequencyKey} + +class WithDefaultPeripherals extends Config((site, here, up) => { + case PeripheryUARTKey => List(UARTParams(address = BigInt(0x64000000L))) + case PeripherySPIKey => List(SPIParams(rAddress = BigInt(0x64001000L))) +}) + +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(DefaultClockFrequencyKey) * 1e6).toLong + val make = s"make -C fpga/src/main/resources/vc707/sdboot PBUS_CLK=${freqMHz} bin" + require (make.! == 0, "Failed to build bootrom") + p.copy(hang = 0x10000, contentFileName = s"./fpga/src/main/resources/vc707/sdboot/build/sdboot.bin") + } + case ExtMem => up(ExtMem, site).map(x => x.copy(master = x.master.copy(size = site(VC7074GDDRSize)))) // set extmem to DDR size + case SerialTLKey => None // remove serialized tl port +}) + +// DOC include start: AbstractVC707 and Rocket +class WithVC707Tweaks extends Config( + // harness binders + new WithVC707UARTHarnessBinder ++ + new WithVC707SPISDCardHarnessBinder ++ + new WithVC707DDRMemHarnessBinder ++ + // io binders + new WithUARTIOPassthrough ++ + new WithSPIIOPassthrough ++ + new WithTLIOPassthrough ++ + // 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) ++ + new WithFPGAFrequency(50) // default 50MHz freq +) + +class RocketVC707Config extends Config( + new WithVC707Tweaks ++ + new chipyard.RocketConfig) +// DOC include end: AbstractVC707 and Rocket + +class BoomVC707Config extends Config( + new WithFPGAFrequency(50) ++ + new WithVC707Tweaks ++ + new chipyard.MegaBoomConfig) + +class WithFPGAFrequency(fMHz: Double) extends Config( + new chipyard.config.WithPeripheryBusFrequency(fMHz) ++ // assumes using PBUS as default freq. + 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/vc707/HarnessBinders.scala b/fpga/src/main/scala/vc707/HarnessBinders.scala new file mode 100644 index 00000000..c662f131 --- /dev/null +++ b/fpga/src/main/scala/vc707/HarnessBinders.scala @@ -0,0 +1,39 @@ +package chipyard.fpga.vc707 + +import chisel3._ + +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.fpgashells.devices.xilinx.xilinxvc707pciex1.{HasSystemXilinxVC707PCIeX1ModuleImp, XilinxVC707PCIeX1IO} + +import chipyard.{CanHaveMasterTLMemPort} +import chipyard.harness.{OverrideHarnessBinder} + +/*** UART ***/ +class WithVC707UARTHarnessBinder extends OverrideHarnessBinder({ + (system: HasPeripheryUARTModuleImp, th: VC707FPGATestHarness, ports: Seq[UARTPortIO]) => { + th.io_uart_bb.bundle <> ports.head + } +}) + +/*** SPI ***/ +class WithVC707SPISDCardHarnessBinder extends OverrideHarnessBinder({ + (system: HasPeripherySPI, th: VC707FPGATestHarness, ports: Seq[SPIPortIO]) => { + th.io_spi_bb.bundle <> ports.head + } +}) + +/*** Experimental DDR ***/ +class WithVC707DDRMemHarnessBinder extends OverrideHarnessBinder({ + (system: CanHaveMasterTLMemPort, th: VC707FPGATestHarness, ports: Seq[HeterogeneousBag[TLBundle]]) => { + require(ports.size == 1) + + val bundles = th.ddrClient.out.map(_._1) + val ddrClientBundle = Wire(new HeterogeneousBag(bundles.map(_.cloneType))) + bundles.zip(ddrClientBundle).foreach { case (bundle, io) => bundle <> io } + ddrClientBundle <> ports.head + } +}) \ No newline at end of file diff --git a/fpga/src/main/scala/vc707/IOBinders.scala b/fpga/src/main/scala/vc707/IOBinders.scala new file mode 100644 index 00000000..6978e3c3 --- /dev/null +++ b/fpga/src/main/scala/vc707/IOBinders.scala @@ -0,0 +1,53 @@ +package chipyard.fpga.vc707 + +import chisel3._ +import chisel3.experimental.{IO, 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.{HasPeripheryUARTModuleImp} +import sifive.blocks.devices.spi.{HasPeripherySPI, HasPeripherySPIModuleImp, MMCDevice} +import sifive.fpgashells.devices.xilinx.xilinxvc707pciex1.{HasSystemXilinxVC707PCIeX1ModuleImp} + +import chipyard.{CanHaveMasterTLMemPort} +import chipyard.iobinders.{OverrideIOBinder, OverrideLazyIOBinder} + +class WithUARTIOPassthrough extends OverrideIOBinder({ + (system: HasPeripheryUARTModuleImp) => { + 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/vc707/TestHarness.scala b/fpga/src/main/scala/vc707/TestHarness.scala new file mode 100644 index 00000000..abfca4a9 --- /dev/null +++ b/fpga/src/main/scala/vc707/TestHarness.scala @@ -0,0 +1,122 @@ +package chipyard.fpga.vc707 + +import chisel3._ +import chisel3.experimental.{IO} + +import freechips.rocketchip.diplomacy.{LazyModule, LazyRawModuleImp, BundleBridgeSource} +import freechips.rocketchip.config.{Parameters} +import freechips.rocketchip.tilelink.{TLClientNode} + +import sifive.fpgashells.shell.xilinx.{VC707Shell, UARTVC707ShellPlacer, PCIeVC707ShellPlacer, ChipLinkVC707PlacedOverlay} +import sifive.fpgashells.ip.xilinx.{IBUF, PowerOnResetFPGAOnly} +import sifive.fpgashells.shell.{ClockInputOverlayKey, ClockInputDesignInput, UARTOverlayKey, UARTDesignInput, UARTShellInput, SPIOverlayKey, SPIDesignInput, PCIeOverlayKey, PCIeDesignInput, PCIeShellInput, DDROverlayKey, DDRDesignInput} +import sifive.fpgashells.clocks.{ClockGroup, ClockSinkNode, PLLFactoryKey, ResetWrangler} +import sifive.fpgashells.devices.xilinx.xilinxvc707pciex1.{XilinxVC707PCIeX1IO} + +import sifive.blocks.devices.uart.{PeripheryUARTKey, UARTPortIO} +import sifive.blocks.devices.spi.{PeripherySPIKey, SPIPortIO} + +import chipyard.{HasHarnessSignalReferences, BuildTop, ChipTop, ExtTLMem, CanHaveMasterTLMemPort, DefaultClockFrequencyKey} +import chipyard.iobinders.{HasIOBinders} +import chipyard.harness.{ApplyHarnessBinders} + +class VC707FPGATestHarness(override implicit val p: Parameters) extends VC707Shell { outer => + + def dp = designParameters + + + // Order matters; ddr depends on sys_clock + val uart = Overlay(UARTOverlayKey, new UARTVC707ShellPlacer(this, UARTShellInput())) + val pcie = Overlay(PCIeOverlayKey, new PCIeVC707ShellPlacer(this, PCIeShellInput())) + + val topDesign = LazyModule(p(BuildTop)(dp)).suggestName("chiptop") + + // 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 + println(s"VC707 FPGA Base Clock Freq: ${dp(DefaultClockFrequencyKey)} MHz") + val dutClock = ClockSinkNode(freqMHz = dp(DefaultClockFrequencyKey)) + val dutWrangler = LazyModule(new ResetWrangler) + val dutGroup = ClockGroup() + dutClock := dutWrangler.node := dutGroup := harnessSysPLL + + /*** UART ***/ + + // 1st UART goes to the VC707 dedicated UART + + val io_uart_bb = BundleBridgeSource(() => (new UARTPortIO(dp(PeripheryUARTKey).head))) + dp(UARTOverlayKey).head.place(UARTDesignInput(io_uart_bb)) + + /*** SPI ***/ + + // 1st SPI goes to the VC707 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 inParams = topDesign match { case td: ChipTop => + td.lazySystem match { case lsys: CanHaveMasterTLMemPort => + lsys.memTLNode.edges.in(0) + } + } + val ddrClient = TLClientNode(Seq(inParams.master)) + ddrNode := ddrClient + + // module implementation + override lazy val module = new LazyRawModuleImp(this) with HasHarnessSignalReferences { + val reset = IO(Input(Bool())) + xdc.addBoardPin(reset, "reset") + + val resetIBUF = Module(new IBUF) + resetIBUF.io.I := reset + + val sysclk: Clock = sysClkNode.out.head._1.clock + // val sysclk: Clock = sys_clock.get() match { + // case Some(x: SysClockVC707PlacedOverlay) => x.clock + // } + + val powerOnReset: Bool = PowerOnResetFPGAOnly(sysclk) + sdc.addAsyncPath(Seq(powerOnReset)) + + val ereset: Bool = chiplink.get() match { + case Some(x: ChipLinkVC707PlacedOverlay) => !x.ereset_n + case _ => false.B + } + + pllReset := (resetIBUF.io.O || powerOnReset || ereset) + + // reset setup + val hReset = Wire(Reset()) + hReset := dutClock.in.head._1.reset + + val buildtopClock = dutClock.in.head._1.clock + val buildtopReset = WireInit(hReset) + val dutReset = hReset.asAsyncReset + val success = false.B + + childClock := buildtopClock + childReset := buildtopReset + + // harness binders are non-lazy + topDesign match { case d: HasIOBinders => + ApplyHarnessBinders(this, d.lazySystem, d.portMap) + } + + // check the top-level reference clock is equal to the default + // non-exhaustive since you need all ChipTop clocks to equal the default + require(getRefClockFreq == p(DefaultClockFrequencyKey)) + } +} \ No newline at end of file