2017-07-23 17:31:04 +02:00
|
|
|
// See LICENSE.SiFive for license details.
|
|
|
|
|
|
|
|
package freechips.rocketchip.coreplex
|
|
|
|
|
|
|
|
import Chisel._
|
|
|
|
import freechips.rocketchip.config.{Field, Parameters}
|
|
|
|
import freechips.rocketchip.diplomacy._
|
|
|
|
import freechips.rocketchip.tilelink._
|
|
|
|
import freechips.rocketchip.amba.axi4._
|
|
|
|
import freechips.rocketchip.util._
|
|
|
|
|
|
|
|
/** Specifies the size and width of external memory ports */
|
|
|
|
case class MasterPortParams(
|
2017-09-09 01:21:05 +02:00
|
|
|
base: BigInt,
|
|
|
|
size: BigInt,
|
2017-07-23 17:31:04 +02:00
|
|
|
beatBytes: Int,
|
|
|
|
idBits: Int,
|
|
|
|
maxXferBytes: Int = 256,
|
|
|
|
executable: Boolean = true)
|
|
|
|
case object ExtMem extends Field[MasterPortParams]
|
|
|
|
case object ExtBus extends Field[MasterPortParams]
|
|
|
|
|
|
|
|
/** Specifies the width of external slave ports */
|
|
|
|
case class SlavePortParams(beatBytes: Int, idBits: Int, sourceBits: Int)
|
|
|
|
case object ExtIn extends Field[SlavePortParams]
|
|
|
|
|
|
|
|
///// The following traits add ports to the sytem, in some cases converting to different interconnect standards
|
|
|
|
|
|
|
|
/** Adds a port to the system intended to master an AXI4 DRAM controller. */
|
|
|
|
trait HasMasterAXI4MemPort extends HasMemoryBus {
|
|
|
|
val module: HasMasterAXI4MemPortModuleImp
|
|
|
|
|
|
|
|
private val params = p(ExtMem)
|
|
|
|
private val device = new MemoryDevice
|
|
|
|
|
2017-09-14 03:06:03 +02:00
|
|
|
val mem_axi4 = AXI4SlaveNode(Seq.tabulate(nMemoryChannels) { channel =>
|
2017-07-23 17:31:04 +02:00
|
|
|
val base = AddressSet(params.base, params.size-1)
|
|
|
|
val filter = AddressSet(channel * cacheBlockBytes, ~((nMemoryChannels-1) * cacheBlockBytes))
|
|
|
|
|
|
|
|
AXI4SlavePortParameters(
|
|
|
|
slaves = Seq(AXI4SlaveParameters(
|
|
|
|
address = base.intersect(filter).toList,
|
|
|
|
resources = device.reg,
|
|
|
|
regionType = RegionType.UNCACHED, // cacheable
|
|
|
|
executable = true,
|
|
|
|
supportsWrite = TransferSizes(1, cacheBlockBytes),
|
|
|
|
supportsRead = TransferSizes(1, cacheBlockBytes),
|
|
|
|
interleavedId = Some(0))), // slave does not interleave read responses
|
|
|
|
beatBytes = params.beatBytes)
|
|
|
|
})
|
|
|
|
|
2017-10-13 01:41:54 +02:00
|
|
|
val converter = LazyModule(new TLToAXI4())
|
2017-07-23 17:31:04 +02:00
|
|
|
val trim = LazyModule(new AXI4IdIndexer(params.idBits))
|
|
|
|
val yank = LazyModule(new AXI4UserYanker)
|
|
|
|
val buffer = LazyModule(new AXI4Buffer)
|
|
|
|
|
|
|
|
memBuses.map(_.toDRAMController).foreach { case node =>
|
2017-10-27 10:13:19 +02:00
|
|
|
mem_axi4 := buffer.node := yank.node := trim.node := converter.node := node
|
2017-07-23 17:31:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Common io name and methods for propagating or tying off the port bundle */
|
|
|
|
trait HasMasterAXI4MemPortBundle {
|
|
|
|
implicit val p: Parameters
|
|
|
|
val mem_axi4: HeterogeneousBag[AXI4Bundle]
|
|
|
|
val nMemoryChannels: Int
|
|
|
|
def connectSimAXIMem(dummy: Int = 1) = {
|
2017-09-12 21:16:28 +02:00
|
|
|
if (nMemoryChannels > 0) {
|
|
|
|
val mem = LazyModule(new SimAXIMem(nMemoryChannels))
|
|
|
|
Module(mem.module).io.axi4 <> mem_axi4
|
|
|
|
}
|
2017-07-23 17:31:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Actually generates the corresponding IO in the concrete Module */
|
2017-09-14 03:06:03 +02:00
|
|
|
trait HasMasterAXI4MemPortModuleImp extends LazyModuleImp with HasMasterAXI4MemPortBundle {
|
2017-07-23 17:31:04 +02:00
|
|
|
val outer: HasMasterAXI4MemPort
|
2017-09-15 23:44:07 +02:00
|
|
|
val mem_axi4 = IO(HeterogeneousBag.fromNode(outer.mem_axi4.in))
|
2017-09-14 03:06:03 +02:00
|
|
|
(mem_axi4 zip outer.mem_axi4.in) foreach { case (i, (o, _)) => i <> o }
|
2017-07-23 17:31:04 +02:00
|
|
|
val nMemoryChannels = outer.nMemoryChannels
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Adds a AXI4 port to the system intended to master an MMIO device bus */
|
|
|
|
trait HasMasterAXI4MMIOPort extends HasSystemBus {
|
|
|
|
private val params = p(ExtBus)
|
|
|
|
private val device = new SimpleBus("mmio", Nil)
|
2017-09-14 03:06:03 +02:00
|
|
|
val mmio_axi4 = AXI4SlaveNode(Seq(AXI4SlavePortParameters(
|
2017-07-23 17:31:04 +02:00
|
|
|
slaves = Seq(AXI4SlaveParameters(
|
2017-11-11 00:12:28 +01:00
|
|
|
address = AddressSet.misaligned(params.base, params.size),
|
2017-07-23 17:31:04 +02:00
|
|
|
resources = device.ranges,
|
|
|
|
executable = params.executable,
|
|
|
|
supportsWrite = TransferSizes(1, params.maxXferBytes),
|
|
|
|
supportsRead = TransferSizes(1, params.maxXferBytes))),
|
|
|
|
beatBytes = params.beatBytes)))
|
|
|
|
|
2017-10-27 10:13:19 +02:00
|
|
|
(mmio_axi4
|
|
|
|
:= AXI4Buffer()
|
|
|
|
:= AXI4UserYanker()
|
|
|
|
:= AXI4Deinterleaver(sbus.blockBytes)
|
|
|
|
:= AXI4IdIndexer(params.idBits)
|
|
|
|
:= TLToAXI4()
|
|
|
|
:= sbus.toFixedWidthPorts)
|
2017-07-23 17:31:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Common io name and methods for propagating or tying off the port bundle */
|
|
|
|
trait HasMasterAXI4MMIOPortBundle {
|
|
|
|
implicit val p: Parameters
|
|
|
|
val mmio_axi4: HeterogeneousBag[AXI4Bundle]
|
|
|
|
def connectSimAXIMMIO(dummy: Int = 1) {
|
2017-09-12 21:16:28 +02:00
|
|
|
val mmio_mem = LazyModule(new SimAXIMem(1, 4096))
|
|
|
|
Module(mmio_mem.module).io.axi4 <> mmio_axi4
|
2017-07-23 17:31:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Actually generates the corresponding IO in the concrete Module */
|
2017-09-14 03:06:03 +02:00
|
|
|
trait HasMasterAXI4MMIOPortModuleImp extends LazyModuleImp with HasMasterAXI4MMIOPortBundle {
|
2017-07-23 17:31:04 +02:00
|
|
|
val outer: HasMasterAXI4MMIOPort
|
2017-09-15 23:44:07 +02:00
|
|
|
val mmio_axi4 = IO(HeterogeneousBag.fromNode(outer.mmio_axi4.in))
|
2017-09-14 03:06:03 +02:00
|
|
|
(mmio_axi4 zip outer.mmio_axi4.in) foreach { case (i, (o, _)) => i <> o }
|
2017-07-23 17:31:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Adds an AXI4 port to the system intended to be a slave on an MMIO device bus */
|
|
|
|
trait HasSlaveAXI4Port extends HasSystemBus {
|
|
|
|
private val params = p(ExtIn)
|
2017-09-14 03:06:03 +02:00
|
|
|
val l2FrontendAXI4Node = AXI4MasterNode(Seq(AXI4MasterPortParameters(
|
2017-07-23 17:31:04 +02:00
|
|
|
masters = Seq(AXI4MasterParameters(
|
|
|
|
name = "AXI4 periphery",
|
|
|
|
id = IdRange(0, 1 << params.idBits))))))
|
|
|
|
|
|
|
|
private val fifoBits = 1
|
2017-10-27 10:13:19 +02:00
|
|
|
(sbus.fromSyncPorts()
|
|
|
|
:= TLWidthWidget(params.beatBytes)
|
|
|
|
:= AXI4ToTL()
|
|
|
|
:= AXI4UserYanker(Some(1 << (params.sourceBits - fifoBits - 1)))
|
|
|
|
:= AXI4Fragmenter()
|
|
|
|
:= AXI4IdIndexer(fifoBits)
|
|
|
|
:= l2FrontendAXI4Node)
|
2017-07-23 17:31:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Common io name and methods for propagating or tying off the port bundle */
|
|
|
|
trait HasSlaveAXI4PortBundle {
|
|
|
|
implicit val p: Parameters
|
|
|
|
val l2_frontend_bus_axi4: HeterogeneousBag[AXI4Bundle]
|
|
|
|
def tieOffAXI4SlavePort(dummy: Int = 1) {
|
|
|
|
l2_frontend_bus_axi4.foreach { l2_axi4 =>
|
|
|
|
l2_axi4.ar.valid := Bool(false)
|
|
|
|
l2_axi4.aw.valid := Bool(false)
|
|
|
|
l2_axi4.w .valid := Bool(false)
|
|
|
|
l2_axi4.r .ready := Bool(true)
|
|
|
|
l2_axi4.b .ready := Bool(true)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Actually generates the corresponding IO in the concrete Module */
|
2017-09-14 03:06:03 +02:00
|
|
|
trait HasSlaveAXI4PortModuleImp extends LazyModuleImp with HasSlaveAXI4PortBundle {
|
2017-07-23 17:31:04 +02:00
|
|
|
val outer: HasSlaveAXI4Port
|
2017-09-15 23:44:07 +02:00
|
|
|
val l2_frontend_bus_axi4 = IO(HeterogeneousBag.fromNode(outer.l2FrontendAXI4Node.out).flip)
|
2017-09-14 03:06:03 +02:00
|
|
|
(outer.l2FrontendAXI4Node.out zip l2_frontend_bus_axi4) foreach { case ((i, _), o) => i <> o }
|
2017-07-23 17:31:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Adds a TileLink port to the system intended to master an MMIO device bus */
|
|
|
|
trait HasMasterTLMMIOPort extends HasSystemBus {
|
|
|
|
private val params = p(ExtBus)
|
|
|
|
private val device = new SimpleBus("mmio", Nil)
|
2017-09-14 03:06:03 +02:00
|
|
|
val mmio_tl = TLManagerNode(Seq(TLManagerPortParameters(
|
2017-07-23 17:31:04 +02:00
|
|
|
managers = Seq(TLManagerParameters(
|
2017-11-11 00:12:28 +01:00
|
|
|
address = AddressSet.misaligned(params.base, params.size),
|
2017-07-23 17:31:04 +02:00
|
|
|
resources = device.ranges,
|
|
|
|
executable = params.executable,
|
|
|
|
supportsGet = TransferSizes(1, sbus.blockBytes),
|
|
|
|
supportsPutFull = TransferSizes(1, sbus.blockBytes),
|
|
|
|
supportsPutPartial = TransferSizes(1, sbus.blockBytes))),
|
|
|
|
beatBytes = params.beatBytes)))
|
|
|
|
|
2017-10-27 10:13:19 +02:00
|
|
|
mmio_tl := TLBuffer() := TLSourceShrinker(1 << params.idBits) := sbus.toFixedWidthPorts
|
2017-07-23 17:31:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Common io name and methods for propagating or tying off the port bundle */
|
|
|
|
trait HasMasterTLMMIOPortBundle {
|
|
|
|
implicit val p: Parameters
|
|
|
|
val mmio_tl: HeterogeneousBag[TLBundle]
|
|
|
|
def tieOffTLMMIO(dummy: Int = 1) {
|
|
|
|
mmio_tl.foreach { tl =>
|
|
|
|
tl.a.ready := Bool(true)
|
|
|
|
tl.b.valid := Bool(false)
|
|
|
|
tl.c.ready := Bool(true)
|
|
|
|
tl.d.valid := Bool(false)
|
|
|
|
tl.e.ready := Bool(true)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Actually generates the corresponding IO in the concrete Module */
|
2017-09-14 03:06:03 +02:00
|
|
|
trait HasMasterTLMMIOPortModuleImp extends LazyModuleImp with HasMasterTLMMIOPortBundle {
|
2017-07-23 17:31:04 +02:00
|
|
|
val outer: HasMasterTLMMIOPort
|
2017-09-15 23:44:07 +02:00
|
|
|
val mmio_tl = IO(HeterogeneousBag.fromNode(outer.mmio_tl.in))
|
2017-09-14 03:06:03 +02:00
|
|
|
(mmio_tl zip outer.mmio_tl.out) foreach { case (i, (o, _)) => i <> o }
|
2017-07-23 17:31:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Adds an TL port to the system intended to be a slave on an MMIO device bus.
|
|
|
|
* NOTE: this port is NOT allowed to issue Acquires.
|
|
|
|
*/
|
|
|
|
trait HasSlaveTLPort extends HasSystemBus {
|
|
|
|
private val params = p(ExtIn)
|
2017-09-14 03:06:03 +02:00
|
|
|
val l2FrontendTLNode = TLClientNode(Seq(TLClientPortParameters(
|
2017-07-23 17:31:04 +02:00
|
|
|
clients = Seq(TLClientParameters(
|
|
|
|
name = "Front Port (TL)",
|
|
|
|
sourceId = IdRange(0, 1 << params.idBits))))))
|
|
|
|
|
2017-10-27 10:13:19 +02:00
|
|
|
sbus.fromSyncPorts() := TLSourceShrinker(1 << params.sourceBits) := TLWidthWidget(params.beatBytes) := l2FrontendTLNode
|
2017-07-23 17:31:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Common io name and methods for propagating or tying off the port bundle */
|
|
|
|
trait HasSlaveTLPortBundle {
|
|
|
|
implicit val p: Parameters
|
|
|
|
val l2_frontend_bus_tl: HeterogeneousBag[TLBundle]
|
|
|
|
def tieOffSlaveTLPort(dummy: Int = 1) {
|
|
|
|
l2_frontend_bus_tl.foreach { tl =>
|
|
|
|
tl.a.valid := Bool(false)
|
|
|
|
tl.b.ready := Bool(true)
|
|
|
|
tl.c.valid := Bool(false)
|
|
|
|
tl.d.ready := Bool(true)
|
|
|
|
tl.e.valid := Bool(false)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Actually generates the corresponding IO in the concrete Module */
|
2017-09-14 03:06:03 +02:00
|
|
|
trait HasSlaveTLPortModuleImp extends LazyModuleImp with HasSlaveTLPortBundle {
|
2017-07-23 17:31:04 +02:00
|
|
|
val outer: HasSlaveTLPort
|
2017-09-15 23:44:07 +02:00
|
|
|
val l2_frontend_bus_tl = IO(HeterogeneousBag.fromNode(outer.l2FrontendTLNode.out).flip)
|
2017-09-14 03:06:03 +02:00
|
|
|
(outer.l2FrontendTLNode.in zip l2_frontend_bus_tl) foreach { case ((i, _), o) => i <> o }
|
2017-07-23 17:31:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Memory with AXI port for use in elaboratable test harnesses. */
|
|
|
|
class SimAXIMem(channels: Int, forceSize: BigInt = 0)(implicit p: Parameters) extends LazyModule {
|
|
|
|
val config = p(ExtMem)
|
2017-09-09 01:21:05 +02:00
|
|
|
val totalSize = if (forceSize > 0) forceSize else config.size
|
2017-07-23 17:31:04 +02:00
|
|
|
val size = totalSize / channels
|
|
|
|
require(totalSize % channels == 0)
|
|
|
|
|
2017-09-14 03:06:03 +02:00
|
|
|
val node = AXI4MasterNode(Seq.fill(channels) {
|
2017-07-23 17:31:04 +02:00
|
|
|
AXI4MasterPortParameters(Seq(AXI4MasterParameters(
|
|
|
|
name = "dut",
|
|
|
|
id = IdRange(0, 1 << config.idBits)
|
|
|
|
)))
|
|
|
|
})
|
|
|
|
|
|
|
|
for (i <- 0 until channels) {
|
|
|
|
val sram = LazyModule(new AXI4RAM(AddressSet(0, size-1), beatBytes = config.beatBytes))
|
2017-10-27 10:13:19 +02:00
|
|
|
sram.node := AXI4Buffer() := AXI4Fragmenter() := node
|
2017-07-23 17:31:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
lazy val module = new LazyModuleImp(this) {
|
2017-09-14 03:06:03 +02:00
|
|
|
val io = IO(new Bundle {
|
2017-09-15 23:44:07 +02:00
|
|
|
val axi4 = HeterogeneousBag.fromNode(node.out).flip
|
2017-09-14 03:06:03 +02:00
|
|
|
})
|
|
|
|
(node.out zip io.axi4) foreach { case ((i, _), o) => i <> o }
|
2017-07-23 17:31:04 +02:00
|
|
|
}
|
|
|
|
}
|