diff --git a/fpga/Makefile b/fpga/Makefile index 1437d8bc76..6196cd99ff 100644 --- a/fpga/Makefile +++ b/fpga/Makefile @@ -30,6 +30,20 @@ ifeq ($(SUB_PROJECT),vcu118) FPGA_BRAND ?= xilinx endif +ifeq ($(SUB_PROJECT),genesys2) + SBT_PROJECT ?= fpga_platforms + MODEL ?= Genesys2FPGATestHarness + VLOG_MODEL ?= Genesys2FPGATestHarness + MODEL_PACKAGE ?= chipyard.fpga.genesys2 + CONFIG ?= RocketGenesys2Config + CONFIG_PACKAGE ?= chipyard.fpga.genesys2 + GENERATOR_PACKAGE ?= chipyard + TB ?= none # unused + TOP ?= ChipTop + BOARD ?= genesys2 + FPGA_BRAND ?= xilinx +endif + ifeq ($(SUB_PROJECT),bringup) SBT_PROJECT ?= fpga_platforms MODEL ?= BringupVCU118FPGATestHarness diff --git a/fpga/src/main/scala/genesys2/Configs.scala b/fpga/src/main/scala/genesys2/Configs.scala new file mode 100644 index 0000000000..866a8c54a8 --- /dev/null +++ b/fpga/src/main/scala/genesys2/Configs.scala @@ -0,0 +1,57 @@ +package chipyard.fpga.genesys2 + +import freechips.rocketchip.config.Config +import freechips.rocketchip.devices.debug.{JtagDTMConfig, JtagDTMKey} +import freechips.rocketchip.diplomacy.DTSTimebase +import freechips.rocketchip.subsystem.{ExtMem, PeripheryBusKey} +import sifive.blocks.devices.uart.{PeripheryUARTKey, UARTParams} +import sifive.fpgashells.shell.xilinx.Genesys2DDRSize +import testchipip.SerialTLKey + +class WithDefaultPeripherals extends Config((site, here, up) => { + case PeripheryUARTKey => List(UARTParams(address = BigInt(0x64000000L))) +}) + +class WithSystemModifications extends Config((site, here, up) => { + case PeripheryBusKey => up(PeripheryBusKey, site).copy(dtsFrequency = Some(site(FPGAFrequencyKey).toInt*1000000)) + case DTSTimebase => BigInt(1000000) + case ExtMem => up(ExtMem, site).map(x => x.copy(master = x.master.copy(size = site(Genesys2DDRSize)))) // set extmem to DDR size + case SerialTLKey => None // remove serialized tl port + case JtagDTMKey => JtagDTMConfig ( + idcodeVersion = 2, + idcodePartNum = 0x000, + idcodeManufId = 0x000, + debugIdleCycles = 5) +}) + +class WithGenesys2Tweaks extends Config( + new WithUART ++ + new WithJTAG ++ + new WithDDRMem ++ + new WithUARTIOPassthrough ++ + new WithJTAGIOPassthrough ++ + new WithTLIOPassthrough ++ + new WithDefaultPeripherals ++ + new chipyard.config.WithTLBackingMemory ++ // use TL backing memory + new WithSystemModifications ++ // setup busses, use sdboot bootrom, setup ext. mem. size + new freechips.rocketchip.subsystem.WithoutTLMonitors ++ + new freechips.rocketchip.subsystem.WithNMemoryChannels(1)) + +class RocketGenesys2Config extends Config( + new WithFPGAFrequency(50) ++ + new WithGenesys2Tweaks ++ + new chipyard.RocketConfig) + +class BoomGenesys2Config extends Config( + new WithFPGAFrequency(50) ++ + new WithGenesys2Tweaks ++ + new chipyard.MegaBoomConfig) + +class WithFPGAFrequency(MHz: Double) extends Config((site, here, up) => { + case FPGAFrequencyKey => MHz +}) + +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/genesys2/HarnessBinders.scala b/fpga/src/main/scala/genesys2/HarnessBinders.scala new file mode 100644 index 0000000000..90cf9a07a3 --- /dev/null +++ b/fpga/src/main/scala/genesys2/HarnessBinders.scala @@ -0,0 +1,47 @@ +package chipyard.fpga.genesys2 + +import chipyard.harness.OverrideHarnessBinder +import chipyard.{CanHaveMasterTLMemPort, HasHarnessSignalReferences} +import chisel3._ +import chisel3.experimental.BaseModule +import freechips.rocketchip.devices.debug.HasPeripheryDebug +import freechips.rocketchip.jtag.JTAGIO +import freechips.rocketchip.tilelink.TLBundle +import freechips.rocketchip.util.HeterogeneousBag +import sifive.blocks.devices.uart.{HasPeripheryUARTModuleImp, UARTPortIO} + +/*** UART ***/ +class WithUART extends OverrideHarnessBinder({ + (system: HasPeripheryUARTModuleImp, th: BaseModule with HasHarnessSignalReferences, ports: Seq[UARTPortIO]) => { + th match { case genesys2th: Genesys2FPGATestHarnessImp => { + genesys2th.genesys2Outer.io_uart_bb.bundle <> ports.head + } } + } +}) + +class WithJTAG extends OverrideHarnessBinder({ + (system: HasPeripheryDebug, th: HasHarnessSignalReferences, ports: Seq[JTAGIO]) => { + th match { case genesys2th: Genesys2FPGATestHarnessImp => { + val j = ports.head + val o = genesys2th.genesys2Outer.io_jtag + j.TCK := o.TCK + j.TDI := o.TDI + j.TMS := o.TMS + o.TDO <> j.TDO + } } + } +}) + +/*** Experimental DDR ***/ +class WithDDRMem extends OverrideHarnessBinder({ + (system: CanHaveMasterTLMemPort, th: BaseModule with HasHarnessSignalReferences, ports: Seq[HeterogeneousBag[TLBundle]]) => { + th match { case genesys2th: Genesys2FPGATestHarnessImp => { + require(ports.size == 1) + + val bundles = genesys2th.genesys2Outer.ddrClient.out.map(_._1) + val ddrClientBundle = Wire(new HeterogeneousBag(bundles.map(_.cloneType))) + bundles.zip(ddrClientBundle).foreach { case (bundle, io) => bundle <> io } + ddrClientBundle <> ports.head + } } + } +}) diff --git a/fpga/src/main/scala/genesys2/IOBinders.scala b/fpga/src/main/scala/genesys2/IOBinders.scala new file mode 100644 index 0000000000..e4d2c0acc2 --- /dev/null +++ b/fpga/src/main/scala/genesys2/IOBinders.scala @@ -0,0 +1,74 @@ +package chipyard.fpga.genesys2 + +import chipyard.CanHaveMasterTLMemPort +import chipyard.iobinders.{GetSystemParameters, OverrideIOBinder, OverrideLazyIOBinder} +import chisel3._ +import chisel3.experimental.{DataMirror, IO} +import freechips.rocketchip.devices.debug._ +import freechips.rocketchip.diplomacy.InModuleBody +import freechips.rocketchip.prci.{ClockSinkNode, ClockSinkParameters} +import freechips.rocketchip.subsystem.BaseSubsystem +import freechips.rocketchip.tilelink.TLBundle +import freechips.rocketchip.util.{HeterogeneousBag, PSDTestMode} +import sifive.blocks.devices.uart.HasPeripheryUARTModuleImp + +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).foreach { case (io, sysio) => + io <> sysio + } + (io_uart_pins_temp, Nil) + } +}) + +class WithJTAGIOPassthrough extends OverrideLazyIOBinder({ + (system: HasPeripheryDebug) => { + implicit val p = GetSystemParameters(system) + val tlbus = system.asInstanceOf[BaseSubsystem].locateTLBusWrapper(p(ExportDebug).slaveWhere) + val clockSinkNode = system.debugOpt.map(_ => ClockSinkNode(Seq(ClockSinkParameters()))) + clockSinkNode.map(_ := tlbus.fixedClockNode) + def clockBundle = clockSinkNode.get.in.head._1 + + InModuleBody { system.asInstanceOf[BaseSubsystem].module match { case system: HasPeripheryDebugModuleImp => { + system.debug.map({ debug => + // We never use the PSDIO, so tie it off on-chip + system.psd.psd.foreach { _ <> 0.U.asTypeOf(new PSDTestMode) } + system.resetctrl.map { rcio => rcio.hartIsInReset.map { _ := clockBundle.reset.asBool } } + system.debug.map { d => + // Tie off extTrigger + d.extTrigger.foreach { t => + t.in.req := false.B + t.out.ack := t.out.req + } + // Tie off disableDebug + d.disableDebug.foreach { d => d := false.B } + // Drive JTAG on-chip IOs + d.systemjtag.map { j => + j.reset := clockBundle.reset + j.mfr_id := p(JtagDTMKey).idcodeManufId.U(11.W) + j.part_number := p(JtagDTMKey).idcodePartNum.U(16.W) + j.version := p(JtagDTMKey).idcodeVersion.U(4.W) + } + } + Debug.connectDebugClockAndReset(Some(debug), clockBundle.clock) + + val jtagPins = debug.systemjtag.map { j => + val io_jtag_pins_temp = IO(Flipped(j.jtag.cloneType)).suggestName(s"debug_jtag") + io_jtag_pins_temp <> j.jtag + io_jtag_pins_temp + }.get + + (Seq(jtagPins), Nil) + }).getOrElse((Nil, 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/genesys2/TestHarness.scala b/fpga/src/main/scala/genesys2/TestHarness.scala new file mode 100644 index 0000000000..3292cf3008 --- /dev/null +++ b/fpga/src/main/scala/genesys2/TestHarness.scala @@ -0,0 +1,107 @@ +package chipyard.fpga.genesys2 + +import chipyard.harness.ApplyHarnessBinders +import chipyard.iobinders.HasIOBinders +import chipyard._ +import chisel3._ +import freechips.rocketchip.config._ +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.tilelink._ +import sifive.blocks.devices.uart._ +import sifive.fpgashells.clocks._ +import sifive.fpgashells.ip.xilinx._ +import sifive.fpgashells.shell._ +import sifive.fpgashells.shell.xilinx._ + +case object FPGAFrequencyKey extends Field[Double](100.0) + +class Genesys2FPGATestHarness(override implicit val p: Parameters) extends Genesys2ShellBasicOverlays { + + def dp = designParameters + + val jtag_location = Some("PMOD_JA") + + // Order matters; ddr depends on sys_clock + val uart = Overlay(UARTOverlayKey, new UARTGenesys2ShellPlacer(this, UARTShellInput())) + val jtag = Overlay(JTAGDebugOverlayKey, new JTAGDebugGenesys2ShellPlacer(this, JTAGDebugShellInput(location = jtag_location))) + + val topDesign = LazyModule(p(BuildTop)(dp)).suggestName("chiptop") + + // place all clocks in the shell + require(dp(ClockInputOverlayKey).nonEmpty) + val sysClkNode = dp(ClockInputOverlayKey).head.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 dutClock = ClockSinkNode(freqMHz = dp(FPGAFrequencyKey)) + val dutWrangler = LazyModule(new ResetWrangler) + val dutGroup = ClockGroup() + dutClock := dutWrangler.node := dutGroup := harnessSysPLL + + /*** UART ***/ + val io_uart_bb = BundleBridgeSource(() => new UARTPortIO(dp(PeripheryUARTKey).head)) + dp(UARTOverlayKey).head.place(UARTDesignInput(io_uart_bb)) + + /*** JTAG ***/ + val io_jtag = dp(JTAGDebugOverlayKey).head.place(JTAGDebugDesignInput()).overlayOutput.jtag + + /*** 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.head + } + } + val ddrClient = TLClientNode(Seq(inParams.master)) + ddrNode := ddrClient + + // module implementation + override lazy val module = new Genesys2FPGATestHarnessImp(this) +} + +class Genesys2FPGATestHarnessImp(_outer: Genesys2FPGATestHarness) extends LazyRawModuleImp(_outer) with HasHarnessSignalReferences { + + val genesys2Outer = _outer + + val reset_n = IO(Input(Bool())) + _outer.xdc.addPackagePin(reset_n, "R19") + _outer.xdc.addIOStandard(reset_n, "LVCMOS33") + + val resetIBUF = Module(new IBUF) + resetIBUF.io.I := ~reset_n + + val sysclk: Clock = _outer.sysClkNode.out.head._1.clock + + val powerOnReset: Bool = PowerOnResetFPGAOnly(sysclk) + _outer.sdc.addAsyncPath(Seq(powerOnReset)) + + + _outer.pllReset := (resetIBUF.io.O || powerOnReset) + + // reset setup + val hReset = Wire(Reset()) + hReset := _outer.dutClock.in.head._1.reset + + val harnessClock = _outer.dutClock.in.head._1.clock + val harnessReset = WireInit(hReset) + val dutReset = hReset.asAsyncReset() + val success = false.B + + childClock := harnessClock + childReset := harnessReset + + // harness binders are non-lazy + _outer.topDesign match { case d: HasTestHarnessFunctions => + d.harnessFunctions.foreach(_(this)) + } + _outer.topDesign match { case d: HasIOBinders => + ApplyHarnessBinders(this, d.lazySystem, d.portMap) + } +}