bb3f514e8d
Unfortunately, I had to touch a lot of code, which weren't quite possible to split up into multiple commits. This commit gets rid of the "extra" infrastructure to add periphery devices into Top.
332 lines
11 KiB
Scala
332 lines
11 KiB
Scala
// See LICENSE for license details.
|
|
|
|
package rocketchip
|
|
|
|
import Chisel._
|
|
import cde.{Parameters, Field}
|
|
import junctions._
|
|
import uncore.tilelink._
|
|
import uncore.tilelink2.{LazyModule, LazyModuleImp}
|
|
import uncore.converters._
|
|
import uncore.devices._
|
|
import uncore.util._
|
|
import rocket.Util._
|
|
import coreplex._
|
|
|
|
/** Options for memory bus interface */
|
|
object BusType {
|
|
sealed trait EnumVal
|
|
case object AXI extends EnumVal
|
|
case object AHB extends EnumVal
|
|
case object TL extends EnumVal
|
|
val busTypes = Seq(AXI, AHB, TL)
|
|
}
|
|
|
|
/** Memory channel controls */
|
|
case object TMemoryChannels extends Field[BusType.EnumVal]
|
|
/** External MMIO controls */
|
|
case object NExtMMIOAXIChannels extends Field[Int]
|
|
case object NExtMMIOAHBChannels extends Field[Int]
|
|
case object NExtMMIOTLChannels extends Field[Int]
|
|
/** External Bus controls */
|
|
case object NExtBusAXIChannels extends Field[Int]
|
|
/** Async configurations */
|
|
case object AsyncBusChannels extends Field[Boolean]
|
|
case object AsyncDebugBus extends Field[Boolean]
|
|
case object AsyncMemChannels extends Field[Boolean]
|
|
case object AsyncMMIOChannels extends Field[Boolean]
|
|
/** External address map settings */
|
|
case object ExtMMIOPorts extends Field[Seq[AddrMapEntry]]
|
|
/** Specifies the size of external memory */
|
|
case object ExtMemSize extends Field[Long]
|
|
/** Specifies the number of external interrupts */
|
|
case object NExtTopInterrupts extends Field[Int]
|
|
/** Source of RTC. First bundle is TopIO.extra, Second bundle is periphery.io.extra **/
|
|
case object RTCPeriod extends Field[Int]
|
|
|
|
object PeripheryUtils {
|
|
def addQueueAXI(source: NastiIO)(implicit p: Parameters) = {
|
|
val sink = Wire(new NastiIO)
|
|
sink.ar <> Queue(source.ar, 1)
|
|
sink.aw <> Queue(source.aw, 1)
|
|
sink.w <> Queue(source.w)
|
|
source.r <> Queue(sink.r)
|
|
source.b <> Queue(sink.b, 1)
|
|
sink
|
|
}
|
|
def convertTLtoAXI(tl: ClientUncachedTileLinkIO)(implicit p: Parameters) = {
|
|
val bridge = Module(new NastiIOTileLinkIOConverter())
|
|
bridge.io.tl <> tl
|
|
addQueueAXI(bridge.io.nasti)
|
|
}
|
|
def convertTLtoAHB(tl: ClientUncachedTileLinkIO, atomics: Boolean)(implicit p: Parameters) = {
|
|
val bridge = Module(new AHBBridge(atomics))
|
|
bridge.io.tl <> tl
|
|
bridge.io.ahb
|
|
}
|
|
}
|
|
|
|
/** Utility trait for quick access to some relevant parameters */
|
|
trait HasPeripheryParameters {
|
|
implicit val p: Parameters
|
|
lazy val tMemChannels = p(TMemoryChannels)
|
|
lazy val nMemChannels = p(NMemoryChannels)
|
|
lazy val nMemAXIChannels = if (tMemChannels == BusType.AXI) nMemChannels else 0
|
|
lazy val nMemAHBChannels = if (tMemChannels == BusType.AHB) nMemChannels else 0
|
|
lazy val nMemTLChannels = if (tMemChannels == BusType.TL) nMemChannels else 0
|
|
lazy val innerParams = p.alterPartial({ case TLId => "L1toL2" })
|
|
lazy val innerMMIOParams = p.alterPartial({ case TLId => "L2toMMIO" })
|
|
lazy val outermostParams = p.alterPartial({ case TLId => "Outermost" })
|
|
lazy val outermostMMIOParams = p.alterPartial({ case TLId => "MMIO_Outermost" })
|
|
}
|
|
|
|
/////
|
|
|
|
trait PeripheryDebug extends LazyModule {
|
|
implicit val p: Parameters
|
|
}
|
|
|
|
trait PeripheryDebugBundle {
|
|
implicit val p: Parameters
|
|
val debug_clk = (p(AsyncDebugBus) && !p(IncludeJtagDTM)).option(Clock(INPUT))
|
|
val debug_rst = (p(AsyncDebugBus) && !p(IncludeJtagDTM)).option(Bool(INPUT))
|
|
val debug = (!p(IncludeJtagDTM)).option(new DebugBusIO()(p).flip)
|
|
val jtag = p(IncludeJtagDTM).option(new JTAGIO(true).flip)
|
|
}
|
|
|
|
trait PeripheryDebugModule {
|
|
implicit val p: Parameters
|
|
val outer: PeripheryDebug
|
|
val io: PeripheryDebugBundle
|
|
val coreplex: Coreplex
|
|
|
|
if (p(IncludeJtagDTM)) {
|
|
// JtagDTMWithSync is a wrapper which
|
|
// handles the synchronization as well.
|
|
val dtm = Module (new JtagDTMWithSync()(p))
|
|
dtm.io.jtag <> io.jtag.get
|
|
coreplex.io.debug <> dtm.io.debug
|
|
} else {
|
|
coreplex.io.debug <>
|
|
(if (p(AsyncDebugBus)) AsyncDebugBusFrom(io.debug_clk.get, io.debug_rst.get, io.debug.get)
|
|
else io.debug.get)
|
|
}
|
|
}
|
|
|
|
/////
|
|
|
|
trait PeripheryExtInterrupts extends LazyModule {
|
|
implicit val p: Parameters
|
|
val pInterrupts: RangeManager
|
|
|
|
pInterrupts.add("ext", p(NExtTopInterrupts))
|
|
}
|
|
|
|
trait PeripheryExtInterruptsBundle {
|
|
implicit val p: Parameters
|
|
val interrupts = Vec(p(NExtTopInterrupts), Bool()).asInput
|
|
}
|
|
|
|
trait PeripheryExtInterruptsModule {
|
|
implicit val p: Parameters
|
|
val outer: PeripheryExtInterrupts
|
|
val io: PeripheryExtInterruptsBundle
|
|
val coreplex: Coreplex
|
|
|
|
{
|
|
val r = outer.pInterrupts.range("ext")
|
|
((r._1 until r._2) zipWithIndex) foreach { case (c, i) =>
|
|
coreplex.io.interrupts(c) := io.interrupts(i)
|
|
}
|
|
}
|
|
}
|
|
|
|
/////
|
|
|
|
trait PeripheryMasterMem extends LazyModule {
|
|
implicit val p: Parameters
|
|
}
|
|
|
|
trait PeripheryMasterMemBundle extends HasPeripheryParameters {
|
|
implicit val p: Parameters
|
|
val mem_clk = p(AsyncMemChannels).option(Vec(nMemChannels, Clock(INPUT)))
|
|
val mem_rst = p(AsyncMemChannels).option(Vec(nMemChannels, Bool (INPUT)))
|
|
val mem_axi = Vec(nMemAXIChannels, new NastiIO)
|
|
val mem_ahb = Vec(nMemAHBChannels, new HastiMasterIO)
|
|
val mem_tl = Vec(nMemTLChannels, new ClientUncachedTileLinkIO()(outermostParams))
|
|
}
|
|
|
|
trait PeripheryMasterMemModule extends HasPeripheryParameters {
|
|
implicit val p: Parameters
|
|
val outer: PeripheryMasterMem
|
|
val io: PeripheryMasterMemBundle
|
|
val coreplex: Coreplex
|
|
|
|
// Abuse the fact that zip takes the shorter of the two lists
|
|
((io.mem_axi zip coreplex.io.master.mem) zipWithIndex) foreach { case ((axi, mem), idx) =>
|
|
val axi_sync = PeripheryUtils.convertTLtoAXI(mem)(outermostParams)
|
|
axi_sync.ar.bits.cache := UInt("b0011")
|
|
axi_sync.aw.bits.cache := UInt("b0011")
|
|
axi <> (
|
|
if (!p(AsyncMemChannels)) axi_sync
|
|
else AsyncNastiTo(io.mem_clk.get(idx), io.mem_rst.get(idx), axi_sync)
|
|
)
|
|
}
|
|
|
|
(io.mem_ahb zip coreplex.io.master.mem) foreach { case (ahb, mem) =>
|
|
ahb <> PeripheryUtils.convertTLtoAHB(mem, atomics = false)(outermostParams)
|
|
}
|
|
|
|
(io.mem_tl zip coreplex.io.master.mem) foreach { case (tl, mem) =>
|
|
tl <> ClientUncachedTileLinkEnqueuer(mem, 2)(outermostParams)
|
|
}
|
|
}
|
|
|
|
/////
|
|
|
|
trait PeripheryMasterMMIO extends LazyModule {
|
|
implicit val p: Parameters
|
|
}
|
|
|
|
trait PeripheryMasterMMIOBundle extends HasPeripheryParameters {
|
|
implicit val p: Parameters
|
|
val mmio_clk = p(AsyncMMIOChannels).option(Vec(p(NExtMMIOAXIChannels), Clock(INPUT)))
|
|
val mmio_rst = p(AsyncMMIOChannels).option(Vec(p(NExtMMIOAXIChannels), Bool (INPUT)))
|
|
val mmio_axi = Vec(p(NExtMMIOAXIChannels), new NastiIO)
|
|
val mmio_ahb = Vec(p(NExtMMIOAHBChannels), new HastiMasterIO)
|
|
val mmio_tl = Vec(p(NExtMMIOTLChannels), new ClientUncachedTileLinkIO()(outermostMMIOParams))
|
|
}
|
|
|
|
trait PeripheryMasterMMIOModule extends HasPeripheryParameters {
|
|
implicit val p: Parameters
|
|
val outer: PeripheryMasterMMIO
|
|
val io: PeripheryMasterMMIOBundle
|
|
val mmioNetwork: Option[TileLinkRecursiveInterconnect]
|
|
|
|
val mmio_ports = p(ExtMMIOPorts) map { port =>
|
|
TileLinkWidthAdapter(mmioNetwork.get.port(port.name), "MMIO_Outermost")
|
|
}
|
|
|
|
val mmio_axi_start = 0
|
|
val mmio_axi_end = mmio_axi_start + p(NExtMMIOAXIChannels)
|
|
val mmio_ahb_start = mmio_axi_end
|
|
val mmio_ahb_end = mmio_ahb_start + p(NExtMMIOAHBChannels)
|
|
val mmio_tl_start = mmio_ahb_end
|
|
val mmio_tl_end = mmio_tl_start + p(NExtMMIOTLChannels)
|
|
require (mmio_tl_end == mmio_ports.size)
|
|
|
|
for (i <- 0 until mmio_ports.size) {
|
|
if (mmio_axi_start <= i && i < mmio_axi_end) {
|
|
val idx = i-mmio_axi_start
|
|
val axi_sync = PeripheryUtils.convertTLtoAXI(mmio_ports(i))(outermostMMIOParams)
|
|
io.mmio_axi(idx) <> (
|
|
if (!p(AsyncMMIOChannels)) axi_sync
|
|
else AsyncNastiTo(io.mmio_clk.get(idx), io.mmio_rst.get(idx), axi_sync)
|
|
)
|
|
} else if (mmio_ahb_start <= i && i < mmio_ahb_end) {
|
|
val idx = i-mmio_ahb_start
|
|
io.mmio_ahb(idx) <> PeripheryUtils.convertTLtoAHB(mmio_ports(i), atomics = true)(outermostMMIOParams)
|
|
} else if (mmio_tl_start <= i && i < mmio_tl_end) {
|
|
val idx = i-mmio_tl_start
|
|
io.mmio_tl(idx) <> ClientUncachedTileLinkEnqueuer(mmio_ports(i), 2)(outermostMMIOParams)
|
|
} else {
|
|
require(false, "Unconnected external MMIO port")
|
|
}
|
|
}
|
|
}
|
|
|
|
/////
|
|
|
|
trait PeripherySlave extends LazyModule {
|
|
implicit val p: Parameters
|
|
val pBusMasters: RangeManager
|
|
|
|
if (p(NExtBusAXIChannels) > 0) pBusMasters.add("ext", 1) // NExtBusAXIChannels are arbitrated into one TL port
|
|
}
|
|
|
|
trait PeripherySlaveBundle extends HasPeripheryParameters {
|
|
implicit val p: Parameters
|
|
val bus_clk = p(AsyncBusChannels).option(Vec(p(NExtBusAXIChannels), Clock(INPUT)))
|
|
val bus_rst = p(AsyncBusChannels).option(Vec(p(NExtBusAXIChannels), Bool (INPUT)))
|
|
val bus_axi = Vec(p(NExtBusAXIChannels), new NastiIO).flip
|
|
}
|
|
|
|
trait PeripherySlaveModule extends HasPeripheryParameters {
|
|
implicit val p: Parameters
|
|
val outer: PeripherySlave
|
|
val io: PeripherySlaveBundle
|
|
val coreplex: Coreplex
|
|
|
|
if (p(NExtBusAXIChannels) > 0) {
|
|
val arb = Module(new NastiArbiter(p(NExtBusAXIChannels)))
|
|
((io.bus_axi zip arb.io.master) zipWithIndex) foreach { case ((bus, port), idx) =>
|
|
port <> (
|
|
if (!p(AsyncBusChannels)) bus
|
|
else AsyncNastiFrom(io.bus_clk.get(idx), io.bus_rst.get(idx), bus)
|
|
)
|
|
}
|
|
val conv = Module(new TileLinkIONastiIOConverter()(innerParams))
|
|
conv.io.nasti <> arb.io.slave
|
|
|
|
val r = outer.pBusMasters.range("ext")
|
|
require(r._2 - r._1 == 1, "RangeManager should return 1 slot")
|
|
coreplex.io.slave(r._1) <> conv.io.tl
|
|
}
|
|
}
|
|
|
|
/////
|
|
|
|
trait PeripheryTestRAM extends LazyModule {
|
|
implicit val p: Parameters
|
|
val pDevices: ResourceManager[AddrMapEntry]
|
|
|
|
val ramSize = 0x1000
|
|
pDevices.add(AddrMapEntry("testram", MemSize(ramSize, MemAttr(AddrMapProt.RW))))
|
|
}
|
|
|
|
trait PeripheryTestRAMBundle {
|
|
implicit val p: Parameters
|
|
}
|
|
|
|
trait PeripheryTestRAMModule extends HasPeripheryParameters {
|
|
implicit val p: Parameters
|
|
val outer: PeripheryTestRAM
|
|
val io: PeripheryTestRAMBundle
|
|
val mmioNetwork: Option[TileLinkRecursiveInterconnect]
|
|
|
|
val testram = Module(new TileLinkTestRAM(outer.ramSize)(innerMMIOParams))
|
|
testram.io <> mmioNetwork.get.port("testram")
|
|
}
|
|
|
|
/////
|
|
|
|
trait PeripheryTestBusMaster extends LazyModule {
|
|
implicit val p: Parameters
|
|
val pBusMasters: RangeManager
|
|
val pDevices: ResourceManager[AddrMapEntry]
|
|
|
|
pBusMasters.add("busmaster", 1)
|
|
pDevices.add(AddrMapEntry("busmaster", MemSize(4096, MemAttr(AddrMapProt.RW))))
|
|
}
|
|
|
|
trait PeripheryTestBusMasterBundle {
|
|
implicit val p: Parameters
|
|
}
|
|
|
|
trait PeripheryTestBusMasterModule {
|
|
implicit val p: Parameters
|
|
val outer: PeripheryTestBusMaster
|
|
val io: PeripheryTestBusMasterBundle
|
|
val mmioNetwork: Option[TileLinkRecursiveInterconnect]
|
|
val coreplex: Coreplex
|
|
|
|
val busmaster = Module(new groundtest.ExampleBusMaster()(p))
|
|
busmaster.io.mmio <> mmioNetwork.get.port("busmaster")
|
|
|
|
{
|
|
val r = outer.pBusMasters.range("busmaster")
|
|
require(r._2 - r._1 == 1, "RangeManager should return 1 slot")
|
|
coreplex.io.slave(r._1) <> busmaster.io.mem
|
|
}
|
|
}
|