Add GPIO Overlay
This commit is contained in:
28
fpga/src/main/scala/vcu118/BringupGPIOs.scala
Normal file
28
fpga/src/main/scala/vcu118/BringupGPIOs.scala
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package chipyard.fpga.vcu118.bringup
|
||||||
|
|
||||||
|
import scala.collection.mutable.{LinkedHashMap}
|
||||||
|
|
||||||
|
object BringupGPIOs {
|
||||||
|
// map of the pin name (akin to die pin name) to (fpga package pin, IOSTANDARD)
|
||||||
|
val pinMapping = LinkedHashMap(
|
||||||
|
// these connect to LEDs and switches on the VCU118 (and use 1.2V)
|
||||||
|
"led0" -> ("AT32", "LVCMOS12"), // 0
|
||||||
|
"led1" -> ("AV34", "LVCMOS12"), // 1
|
||||||
|
"led2" -> ("AY30", "LVCMOS12"), // 2
|
||||||
|
"led3" -> ("BB32", "LVCMOS12"), // 3
|
||||||
|
"led4" -> ("BF32", "LVCMOS12"), // 4
|
||||||
|
"led5" -> ("AU37", "LVCMOS12"), // 5
|
||||||
|
"led6" -> ("AV36", "LVCMOS12"), // 6
|
||||||
|
"led7" -> ("BA37", "LVCMOS12"), // 7
|
||||||
|
"sw0" -> ("B17", "LVCMOS12"), // 8
|
||||||
|
"sw1" -> ("G16", "LVCMOS12"), // 9
|
||||||
|
"sw2" -> ("J16", "LVCMOS12"), // 10
|
||||||
|
"sw3" -> ("D21", "LVCMOS12") // 11
|
||||||
|
)
|
||||||
|
|
||||||
|
// return list of names (ordered)
|
||||||
|
def names: Seq[String] = pinMapping.keys.toSeq
|
||||||
|
|
||||||
|
// return number of GPIOs
|
||||||
|
def width: Int = pinMapping.size
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
// See LICENSE for license details.
|
// See LICENSE for license details.
|
||||||
package chipyard.fpga.vcu118
|
package chipyard.fpga.vcu118
|
||||||
|
|
||||||
|
import math.min
|
||||||
|
|
||||||
import freechips.rocketchip.config._
|
import freechips.rocketchip.config._
|
||||||
import freechips.rocketchip.subsystem._
|
import freechips.rocketchip.subsystem._
|
||||||
import freechips.rocketchip.devices.debug._
|
import freechips.rocketchip.devices.debug._
|
||||||
@@ -9,7 +11,6 @@ import freechips.rocketchip.diplomacy.{DTSModel, DTSTimebase}
|
|||||||
import freechips.rocketchip.system._
|
import freechips.rocketchip.system._
|
||||||
import freechips.rocketchip.tile._
|
import freechips.rocketchip.tile._
|
||||||
|
|
||||||
import sifive.blocks.devices.mockaon._
|
|
||||||
import sifive.blocks.devices.gpio._
|
import sifive.blocks.devices.gpio._
|
||||||
import sifive.blocks.devices.pwm._
|
import sifive.blocks.devices.pwm._
|
||||||
import sifive.blocks.devices.spi._
|
import sifive.blocks.devices.spi._
|
||||||
@@ -20,6 +21,7 @@ import sifive.fpgashells.shell.{DesignKey}
|
|||||||
import sifive.fpgashells.shell.xilinx.{VCU118ShellPMOD}
|
import sifive.fpgashells.shell.xilinx.{VCU118ShellPMOD}
|
||||||
|
|
||||||
import chipyard.{BuildTop}
|
import chipyard.{BuildTop}
|
||||||
|
import chipyard.fpga.vcu118.bringup.{BringupGPIOs}
|
||||||
|
|
||||||
class WithChipyardBuildTop extends Config((site, here, up) => {
|
class WithChipyardBuildTop extends Config((site, here, up) => {
|
||||||
case DesignKey => {(p: Parameters) => new VCU118Platform()(p) }
|
case DesignKey => {(p: Parameters) => new VCU118Platform()(p) }
|
||||||
@@ -32,9 +34,22 @@ class WithBringupPeripherals extends Config((site, here, up) => {
|
|||||||
case PeripherySPIKey => List(
|
case PeripherySPIKey => List(
|
||||||
SPIParams(rAddress = BigInt(0x64001000L)),
|
SPIParams(rAddress = BigInt(0x64001000L)),
|
||||||
SPIParams(rAddress = BigInt(0x64004000L)))
|
SPIParams(rAddress = BigInt(0x64004000L)))
|
||||||
|
case VCU118ShellPMOD => "SDIO"
|
||||||
case PeripheryI2CKey => List(
|
case PeripheryI2CKey => List(
|
||||||
I2CParams(address = BigInt(0x64005000L)))
|
I2CParams(address = BigInt(0x64005000L)))
|
||||||
case VCU118ShellPMOD => "SDIO"
|
case PeripheryGPIOKey => {
|
||||||
|
if (BringupGPIOs.width > 0) {
|
||||||
|
require(BringupGPIOs.width <= 64) // currently only support 64 GPIOs (change addrs to get more)
|
||||||
|
val gpioAddrs = Seq(BigInt(0x64002000), BigInt(0x64007000))
|
||||||
|
val maxGPIOSupport = 32 // max gpios supported by SiFive driver (split by 32)
|
||||||
|
List.tabulate(((BringupGPIOs.width - 1)/maxGPIOSupport) + 1)(n => {
|
||||||
|
GPIOParams(address = gpioAddrs(n), width = min(BringupGPIOs.width - maxGPIOSupport*n, maxGPIOSupport))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
List.empty[GPIOParams]
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
class FakeBringupConfig extends Config(
|
class FakeBringupConfig extends Config(
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
package chipyard.fpga.vcu118.bringup
|
package chipyard.fpga.vcu118.bringup
|
||||||
|
|
||||||
import chisel3._
|
import chisel3._
|
||||||
|
import chisel3.experimental.{attach}
|
||||||
|
|
||||||
import freechips.rocketchip.diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
|
import chipsalliance.rocketchip.config.{Parameters, Field}
|
||||||
|
|
||||||
import sifive.fpgashells.shell._
|
import sifive.fpgashells.shell._
|
||||||
import sifive.fpgashells.ip.xilinx._
|
import sifive.fpgashells.ip.xilinx._
|
||||||
import sifive.fpgashells.shell.xilinx._
|
import sifive.fpgashells.shell.xilinx._
|
||||||
|
|
||||||
|
import sifive.blocks.devices.gpio._
|
||||||
|
|
||||||
import chipyard.fpga.vcu118.{FMCPMap}
|
import chipyard.fpga.vcu118.{FMCPMap}
|
||||||
|
|
||||||
/* Connect the I2C to certain FMC pins */
|
/* Connect the I2C to certain FMC pins */
|
||||||
@@ -63,3 +67,85 @@ class BringupUARTVCU118ShellPlacer(shell: VCU118Shell, val shellInput: UARTShell
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Connect SPI to ADI device */
|
/* Connect SPI to ADI device */
|
||||||
|
class BringupSPIVCU118PlacedOverlay(val shell: VCU118Shell, name: String, val designInput: SPIDesignInput, val shellInput: SPIShellInput)
|
||||||
|
extends SDIOXilinxPlacedOverlay(name, designInput, shellInput)
|
||||||
|
{
|
||||||
|
shell { InModuleBody {
|
||||||
|
val packagePinsWithPackageIOs = Seq((FMCPMap("H37"), IOPin(io.spi_clk)),
|
||||||
|
(FMCPMap("H19"), IOPin(io.spi_cs)),
|
||||||
|
(FMCPMap("H17"), IOPin(io.spi_dat(0))),
|
||||||
|
(FMCPMap("H28"), IOPin(io.spi_dat(1))),
|
||||||
|
(FMCPMap("H29"), IOPin(io.spi_dat(2))),
|
||||||
|
(FMCPMap("H16"), IOPin(io.spi_dat(3))))
|
||||||
|
|
||||||
|
packagePinsWithPackageIOs foreach { case (pin, io) => {
|
||||||
|
shell.xdc.addPackagePin(io, pin)
|
||||||
|
shell.xdc.addIOStandard(io, "LVCMOS18")
|
||||||
|
} }
|
||||||
|
packagePinsWithPackageIOs drop 1 foreach { case (pin, io) => {
|
||||||
|
shell.xdc.addPullup(io)
|
||||||
|
shell.xdc.addIOB(io)
|
||||||
|
} }
|
||||||
|
} }
|
||||||
|
}
|
||||||
|
|
||||||
|
class BringupSPIVCU118ShellPlacer(shell: VCU118Shell, val shellInput: SPIShellInput)(implicit val valName: ValName)
|
||||||
|
extends SPIShellPlacer[VCU118Shell] {
|
||||||
|
def place(designInput: SPIDesignInput) = new BringupSPIVCU118PlacedOverlay(shell, valName.name, designInput, shellInput)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Move this to a different location
|
||||||
|
// SPI device description for ADI part
|
||||||
|
class ADISPIDevice(spi: Device, maxMHz: Double = 1) extends SimpleDevice("clkgen", Seq("analog,adi9516-4")) {
|
||||||
|
override def parent = Some(spi)
|
||||||
|
override def describe(resources: ResourceBindings): Description = {
|
||||||
|
val Description(name, mapping) = super.describe(resources)
|
||||||
|
val extra = Map("spi-max-frequency" -> Seq(ResourceInt(maxMHz * 1000000)))
|
||||||
|
Description(name, mapping ++ extra)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Connect GPIOs to FMC */
|
||||||
|
abstract class GPIOXilinxPlacedOverlay(name: String, di: GPIODesignInput, si: GPIOShellInput)
|
||||||
|
extends GPIOPlacedOverlay(name, di, si)
|
||||||
|
{
|
||||||
|
def shell: XilinxShell
|
||||||
|
|
||||||
|
shell { InModuleBody {
|
||||||
|
(io.gpio zip tlgpioSink.bundle.pins).map { case (ioPin, sinkPin) =>
|
||||||
|
val iobuf = Module(new IOBUF)
|
||||||
|
iobuf.suggestName(s"gpio_iobuf")
|
||||||
|
attach(ioPin, iobuf.io.IO)
|
||||||
|
sinkPin.i.ival := iobuf.io.O
|
||||||
|
iobuf.io.T := !sinkPin.o.oe
|
||||||
|
iobuf.io.I := sinkPin.o.oval
|
||||||
|
}
|
||||||
|
} }
|
||||||
|
}
|
||||||
|
|
||||||
|
class BringupGPIOVCU118PlacedOverlay(val shell: VCU118Shell, name: String, val designInput: GPIODesignInput, val shellInput: GPIOShellInput, gpioNames: Seq[String])
|
||||||
|
extends GPIOXilinxPlacedOverlay(name, designInput, shellInput)
|
||||||
|
{
|
||||||
|
shell { InModuleBody {
|
||||||
|
require(gpioNames.length == io.gpio.length)
|
||||||
|
|
||||||
|
val packagePinsWithIOStdWithPackageIOs = (gpioNames zip io.gpio).map { case (name, io) =>
|
||||||
|
val (pin, iostd) = BringupGPIOs.pinMapping(name)
|
||||||
|
(pin, iostd, IOPin(io))
|
||||||
|
}
|
||||||
|
|
||||||
|
packagePinsWithIOStdWithPackageIOs foreach { case (pin, iostd, io) => {
|
||||||
|
shell.xdc.addPackagePin(io, pin)
|
||||||
|
shell.xdc.addIOStandard(io, iostd)
|
||||||
|
// TODO: no drive strength found
|
||||||
|
//if (iostd == "LVCMOS12") { shell.xdc.addDriveStrength(io, "8") }
|
||||||
|
} }
|
||||||
|
} }
|
||||||
|
}
|
||||||
|
|
||||||
|
class BringupGPIOVCU118ShellPlacer(shell: VCU118Shell, val shellInput: GPIOShellInput, gpioNames: Seq[String])(implicit val valName: ValName)
|
||||||
|
extends GPIOShellPlacer[VCU118Shell] {
|
||||||
|
def place(designInput: GPIODesignInput) = new BringupGPIOVCU118PlacedOverlay(shell, valName.name, designInput, shellInput, gpioNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -12,11 +12,13 @@ import chipyard.{BuildSystem}
|
|||||||
import sifive.blocks.devices.uart._
|
import sifive.blocks.devices.uart._
|
||||||
import sifive.blocks.devices.spi._
|
import sifive.blocks.devices.spi._
|
||||||
import sifive.blocks.devices.i2c._
|
import sifive.blocks.devices.i2c._
|
||||||
|
import sifive.blocks.devices.gpio._
|
||||||
|
|
||||||
trait HasVCU118PlatformIO {
|
trait HasVCU118PlatformIO {
|
||||||
val io_uart: Seq[UARTPortIO]
|
val io_uart: Seq[UARTPortIO]
|
||||||
val io_spi: Seq[SPIPortIO]
|
val io_spi: Seq[SPIPortIO]
|
||||||
val io_i2c: Seq[I2CPort]
|
val io_i2c: Seq[I2CPort]
|
||||||
|
val io_gpio: Seq[GPIOPortIO]
|
||||||
}
|
}
|
||||||
|
|
||||||
class VCU118Platform(override implicit val p: Parameters) extends LazyModule {
|
class VCU118Platform(override implicit val p: Parameters) extends LazyModule {
|
||||||
@@ -52,4 +54,12 @@ class VCU118PlatformModule[+L <: VCU118Platform](_outer: L) extends LazyModuleIm
|
|||||||
}
|
}
|
||||||
io_i2c_pins_temp
|
io_i2c_pins_temp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val io_gpio = _outer.lazySystem.module match { case sys: HasPeripheryGPIOModuleImp =>
|
||||||
|
val io_gpio_pins_temp = p(PeripheryGPIOKey).zipWithIndex.map { case (p, i) => IO(new GPIOPortIO(p)).suggestName(s"gpio_$i") }
|
||||||
|
(io_gpio_pins_temp zip sys.gpio).map { case (io, sysio) =>
|
||||||
|
io <> sysio
|
||||||
|
}
|
||||||
|
io_gpio_pins_temp
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,8 @@ package chipyard.fpga.vcu118
|
|||||||
import chisel3._
|
import chisel3._
|
||||||
import chisel3.experimental.{Analog, IO}
|
import chisel3.experimental.{Analog, IO}
|
||||||
|
|
||||||
import freechips.rocketchip.diplomacy.{LazyModule, LazyRawModuleImp}
|
import freechips.rocketchip.diplomacy._
|
||||||
import freechips.rocketchip.config.{Parameters}
|
import freechips.rocketchip.config.{Parameters}
|
||||||
import freechips.rocketchip.diplomacy.{InModuleBody, BundleBridgeSource}
|
|
||||||
|
|
||||||
import sifive.fpgashells.shell.xilinx._
|
import sifive.fpgashells.shell.xilinx._
|
||||||
import sifive.fpgashells.ip.xilinx._
|
import sifive.fpgashells.ip.xilinx._
|
||||||
@@ -15,6 +14,9 @@ import sifive.fpgashells.clocks._
|
|||||||
import sifive.blocks.devices.uart._
|
import sifive.blocks.devices.uart._
|
||||||
import sifive.blocks.devices.spi._
|
import sifive.blocks.devices.spi._
|
||||||
import sifive.blocks.devices.i2c._
|
import sifive.blocks.devices.i2c._
|
||||||
|
import sifive.blocks.devices.gpio._
|
||||||
|
|
||||||
|
import chipyard.fpga.vcu118.bringup._
|
||||||
|
|
||||||
class VCU118FPGATestHarness(override implicit val p: Parameters) extends VCU118Shell {
|
class VCU118FPGATestHarness(override implicit val p: Parameters) extends VCU118Shell {
|
||||||
|
|
||||||
@@ -47,18 +49,44 @@ class VCU118FPGATestHarness(override implicit val p: Parameters) extends VCU118S
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*** SPI ***/
|
/*** SPI ***/
|
||||||
require(p(PeripherySPIKey).size >= 1)
|
require(p(PeripherySPIKey).size == 2)
|
||||||
|
|
||||||
|
// 1st SPI goes to the VCU118 SDIO port
|
||||||
|
|
||||||
val io_spi_bb = BundleBridgeSource(() => (new SPIPortIO(p(PeripherySPIKey).head)))
|
val io_spi_bb = BundleBridgeSource(() => (new SPIPortIO(p(PeripherySPIKey).head)))
|
||||||
designParameters(SPIOverlayKey).head.place(SPIDesignInput(p(PeripherySPIKey).head, io_spi_bb))
|
val sdio_placed = designParameters(SPIOverlayKey).head.place(SPIDesignInput(p(PeripherySPIKey).head, io_spi_bb))
|
||||||
InModuleBody {
|
InModuleBody {
|
||||||
topDesign.module match { case dutMod: HasVCU118PlatformIO =>
|
topDesign.module match { case dutMod: HasVCU118PlatformIO =>
|
||||||
io_spi_bb.bundle <> dutMod.io_spi.head
|
io_spi_bb.bundle <> dutMod.io_spi.head
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: No access to the TLSPI node...
|
||||||
|
//val mmcDev = new MMCDevice(sdio_placed.device, 1)
|
||||||
|
//ResourceBinding {
|
||||||
|
// Resource(mmcDev, "reg").bind(ResourceAddress(0))
|
||||||
|
//}
|
||||||
|
|
||||||
|
// 2nd SPI goes to the ADI port
|
||||||
|
|
||||||
|
val adi = Overlay(SPIOverlayKey, new chipyard.fpga.vcu118.bringup.BringupSPIVCU118ShellPlacer(this, SPIShellInput()))
|
||||||
|
|
||||||
|
val io_spi_bb_2 = BundleBridgeSource(() => (new SPIPortIO(p(PeripherySPIKey).last)))
|
||||||
|
val adi_placed = designParameters(SPIOverlayKey).last.place(SPIDesignInput(p(PeripherySPIKey).last, io_spi_bb_2))
|
||||||
|
InModuleBody {
|
||||||
|
topDesign.module match { case dutMod: HasVCU118PlatformIO =>
|
||||||
|
io_spi_bb_2.bundle <> dutMod.io_spi.last
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: No access to the TLSPI node...
|
||||||
|
//val adiDev = new chipyard.fpga.vcu118.bringup.ADISPIDevice(adi_placed.device, 1)
|
||||||
|
//ResourceBinding {
|
||||||
|
// Resource(adiDev, "reg").bind(ResourceAddress(0))
|
||||||
|
//}
|
||||||
|
|
||||||
/*** I2C ***/
|
/*** I2C ***/
|
||||||
require(p(PeripheryI2CKey).size >= 1)
|
require(p(PeripheryI2CKey).size == 1)
|
||||||
|
|
||||||
val i2c = Overlay(I2COverlayKey, new chipyard.fpga.vcu118.bringup.BringupI2CVCU118ShellPlacer(this, I2CShellInput()))
|
val i2c = Overlay(I2COverlayKey, new chipyard.fpga.vcu118.bringup.BringupI2CVCU118ShellPlacer(this, I2CShellInput()))
|
||||||
|
|
||||||
@@ -69,5 +97,24 @@ class VCU118FPGATestHarness(override implicit val p: Parameters) extends VCU118S
|
|||||||
io_i2c_bb.bundle <> dutMod.io_i2c.head
|
io_i2c_bb.bundle <> dutMod.io_i2c.head
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*** GPIO ***/
|
||||||
|
val gpio = Seq.tabulate(p(PeripheryGPIOKey).size)(i => {
|
||||||
|
val maxGPIOSupport = 32
|
||||||
|
val names = BringupGPIOs.names.slice(maxGPIOSupport*i, maxGPIOSupport*(i+1))
|
||||||
|
Overlay(GPIOOverlayKey, new chipyard.fpga.vcu118.bringup.BringupGPIOVCU118ShellPlacer(this, GPIOShellInput(), names))
|
||||||
|
})
|
||||||
|
|
||||||
|
val io_gpio_bb = p(PeripheryGPIOKey).map { p => BundleBridgeSource(() => (new GPIOPortIO(p))) }
|
||||||
|
(designParameters(GPIOOverlayKey) zip p(PeripheryGPIOKey)).zipWithIndex.map { case ((placer, params), i) =>
|
||||||
|
placer.place(GPIODesignInput(params, io_gpio_bb(i)))
|
||||||
|
}
|
||||||
|
InModuleBody {
|
||||||
|
topDesign.module match { case dutMod: HasVCU118PlatformIO =>
|
||||||
|
(io_gpio_bb zip dutMod.io_gpio).map { case (bb_io, dut_io) =>
|
||||||
|
bb_io.bundle <> dut_io
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user