coreplex: support multiple memory channels via diplomatic trickery
This commit is contained in:
parent
e7b35b4bb6
commit
3a5e5a65f8
@ -70,27 +70,23 @@ trait BankedL2CoherenceManagers extends CoreplexNetwork {
|
|||||||
require (isPow2(l2Config.nBanksPerChannel))
|
require (isPow2(l2Config.nBanksPerChannel))
|
||||||
require (isPow2(l1tol2_lineBytes))
|
require (isPow2(l1tol2_lineBytes))
|
||||||
|
|
||||||
val mem = Seq.fill(l2Config.nMemoryChannels) {
|
val mem = TLOutputNode()
|
||||||
|
for (i <- 0 until l2Config.nMemoryChannels) {
|
||||||
val bankBar = LazyModule(new TLXbar)
|
val bankBar = LazyModule(new TLXbar)
|
||||||
val output = TLOutputNode()
|
|
||||||
|
|
||||||
output := bankBar.node
|
mem := bankBar.node
|
||||||
val mask = ~BigInt((l2Config.nBanksPerChannel-1) * l1tol2_lineBytes)
|
val mask = ~BigInt((l2Config.nBanksPerChannel-1) * l1tol2_lineBytes)
|
||||||
for (i <- 0 until l2Config.nBanksPerChannel) {
|
for (i <- 0 until l2Config.nBanksPerChannel) {
|
||||||
val (in, out) = l2Config.coherenceManager(p)
|
val (in, out) = l2Config.coherenceManager(p)
|
||||||
in := TLFilter(AddressSet(i * l1tol2_lineBytes, mask))(l1tol2.node)
|
in := TLFilter(AddressSet(i * l1tol2_lineBytes, mask))(l1tol2.node)
|
||||||
bankBar.node := out
|
bankBar.node := out
|
||||||
}
|
}
|
||||||
|
|
||||||
output
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait BankedL2CoherenceManagersBundle extends CoreplexNetworkBundle {
|
trait BankedL2CoherenceManagersBundle extends CoreplexNetworkBundle {
|
||||||
val outer: BankedL2CoherenceManagers
|
val outer: BankedL2CoherenceManagers
|
||||||
|
val mem = outer.mem.bundleOut
|
||||||
require (l2Config.nMemoryChannels <= 1, "Seq in Chisel Bundle needed to support > 1") // !!!
|
|
||||||
val mem = outer.mem.map(_.bundleOut).toList.headOption // .headOption should be removed !!!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
trait BankedL2CoherenceManagersModule extends CoreplexNetworkModule {
|
trait BankedL2CoherenceManagersModule extends CoreplexNetworkModule {
|
||||||
|
@ -40,7 +40,7 @@ class MemtestStatelessConfig extends Config(
|
|||||||
// Test ALL the things
|
// Test ALL the things
|
||||||
class FancyMemtestConfig extends Config(
|
class FancyMemtestConfig extends Config(
|
||||||
new WithNGenerators(1, 2) ++ new WithNCores(2) ++ new WithMemtest ++
|
new WithNGenerators(1, 2) ++ new WithNCores(2) ++ new WithMemtest ++
|
||||||
new WithNMemoryChannels(1) ++ new WithNBanksPerMemChannel(4) ++ // !!! waiting on Chisel3 support for 2 channels
|
new WithNMemoryChannels(2) ++ new WithNBanksPerMemChannel(4) ++
|
||||||
new WithL2Cache ++ new GroundTestConfig)
|
new WithL2Cache ++ new GroundTestConfig)
|
||||||
|
|
||||||
class CacheFillTestConfig extends Config(
|
class CacheFillTestConfig extends Config(
|
||||||
|
@ -16,11 +16,6 @@ class TestHarness(implicit p: Parameters) extends Module {
|
|||||||
val dut = Module(LazyModule(new GroundTestTop).module)
|
val dut = Module(LazyModule(new GroundTestTop).module)
|
||||||
io.success := dut.io.success
|
io.success := dut.io.success
|
||||||
|
|
||||||
if (dut.io.mem_axi4.nonEmpty) {
|
val channels = p(coreplex.BankedL2Config).nMemoryChannels
|
||||||
val memSize = p(ExtMem).size
|
if (channels > 0) Module(LazyModule(new SimAXIMem(channels)).module).io.axi4 <> dut.io.mem_axi4
|
||||||
require(memSize % dut.io.mem_axi4.size == 0)
|
|
||||||
for (axi4 <- dut.io.mem_axi4) {
|
|
||||||
Module(LazyModule(new SimAXIMem(memSize / dut.io.mem_axi4.size)).module).io.axi4 <> axi4
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ class GroundTestTop(implicit p: Parameters) extends BaseTop
|
|||||||
|
|
||||||
socBus.node := coreplex.mmio
|
socBus.node := coreplex.mmio
|
||||||
coreplex.mmioInt := intBus.intnode
|
coreplex.mmioInt := intBus.intnode
|
||||||
(mem zip coreplex.mem) foreach { case (m, c) => m := c }
|
mem.foreach { _ := coreplex.mem }
|
||||||
}
|
}
|
||||||
|
|
||||||
class GroundTestTopBundle[+L <: GroundTestTop](_outer: L) extends BaseTopBundle(_outer)
|
class GroundTestTopBundle[+L <: GroundTestTop](_outer: L) extends BaseTopBundle(_outer)
|
||||||
|
@ -87,11 +87,11 @@ trait PeripheryMasterAXI4Mem {
|
|||||||
private val config = p(ExtMem)
|
private val config = p(ExtMem)
|
||||||
private val channels = p(BankedL2Config).nMemoryChannels
|
private val channels = p(BankedL2Config).nMemoryChannels
|
||||||
|
|
||||||
val mem_axi4 = Seq.tabulate(channels) { i =>
|
val mem_axi4 = AXI4BlindOutputNode(Seq.tabulate(channels) { i =>
|
||||||
val c_size = config.size/channels
|
val c_size = config.size/channels
|
||||||
val c_base = config.base + c_size*i
|
val c_base = config.base + c_size*i
|
||||||
|
|
||||||
AXI4BlindOutputNode(Seq(AXI4SlavePortParameters(
|
AXI4SlavePortParameters(
|
||||||
slaves = Seq(AXI4SlaveParameters(
|
slaves = Seq(AXI4SlaveParameters(
|
||||||
address = List(AddressSet(c_base, c_size-1)),
|
address = List(AddressSet(c_base, c_size-1)),
|
||||||
regionType = RegionType.UNCACHED, // cacheable
|
regionType = RegionType.UNCACHED, // cacheable
|
||||||
@ -99,12 +99,12 @@ trait PeripheryMasterAXI4Mem {
|
|||||||
supportsWrite = TransferSizes(1, 256), // The slave supports 1-256 byte transfers
|
supportsWrite = TransferSizes(1, 256), // The slave supports 1-256 byte transfers
|
||||||
supportsRead = TransferSizes(1, 256),
|
supportsRead = TransferSizes(1, 256),
|
||||||
interleavedId = Some(0))), // slave does not interleave read responses
|
interleavedId = Some(0))), // slave does not interleave read responses
|
||||||
beatBytes = config.beatBytes)))
|
beatBytes = config.beatBytes)
|
||||||
}
|
})
|
||||||
|
|
||||||
val mem = mem_axi4.map { node =>
|
val mem = Seq.fill(channels) {
|
||||||
val converter = LazyModule(new TLToAXI4(config.idBits))
|
val converter = LazyModule(new TLToAXI4(config.idBits))
|
||||||
node := AXI4Buffer()(converter.node)
|
mem_axi4 := AXI4Buffer()(converter.node)
|
||||||
converter.node
|
converter.node
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -113,7 +113,7 @@ trait PeripheryMasterAXI4MemBundle {
|
|||||||
this: TopNetworkBundle {
|
this: TopNetworkBundle {
|
||||||
val outer: PeripheryMasterAXI4Mem
|
val outer: PeripheryMasterAXI4Mem
|
||||||
} =>
|
} =>
|
||||||
val mem_axi4 = outer.mem_axi4.map(_.bundleOut).toList.headOption // !!! remove headOption when Seq supported
|
val mem_axi4 = outer.mem_axi4.bundleOut
|
||||||
}
|
}
|
||||||
|
|
||||||
trait PeripheryMasterAXI4MemModule {
|
trait PeripheryMasterAXI4MemModule {
|
||||||
|
@ -19,7 +19,7 @@ trait RocketPlexMaster extends L2Crossbar {
|
|||||||
coreplex.l2in := l2.node
|
coreplex.l2in := l2.node
|
||||||
socBus.node := coreplex.mmio
|
socBus.node := coreplex.mmio
|
||||||
coreplex.mmioInt := intBus.intnode
|
coreplex.mmioInt := intBus.intnode
|
||||||
(mem zip coreplex.mem) foreach { case (m, c) => m := c }
|
mem.foreach { _ := coreplex.mem }
|
||||||
}
|
}
|
||||||
|
|
||||||
trait RocketPlexMasterBundle extends L2CrossbarBundle {
|
trait RocketPlexMasterBundle extends L2CrossbarBundle {
|
||||||
|
@ -18,13 +18,8 @@ class TestHarness()(implicit p: Parameters) extends Module {
|
|||||||
for (int <- dut.io.interrupts(0))
|
for (int <- dut.io.interrupts(0))
|
||||||
int := Bool(false)
|
int := Bool(false)
|
||||||
|
|
||||||
if (dut.io.mem_axi4.nonEmpty) {
|
val channels = p(coreplex.BankedL2Config).nMemoryChannels
|
||||||
val memSize = p(ExtMem).size
|
if (channels > 0) Module(LazyModule(new SimAXIMem(channels)).module).io.axi4 <> dut.io.mem_axi4
|
||||||
require(memSize % dut.io.mem_axi4.size == 0)
|
|
||||||
for (axi4 <- dut.io.mem_axi4) {
|
|
||||||
Module(LazyModule(new SimAXIMem(memSize / dut.io.mem_axi4.size)).module).io.axi4 <> axi4
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!p(IncludeJtagDTM)) {
|
if (!p(IncludeJtagDTM)) {
|
||||||
val dtm = Module(new SimDTM).connect(clock, reset, dut.io.debug.get, io.success)
|
val dtm = Module(new SimDTM).connect(clock, reset, dut.io.debug.get, io.success)
|
||||||
@ -32,7 +27,7 @@ class TestHarness()(implicit p: Parameters) extends Module {
|
|||||||
val jtag = Module(new JTAGVPI).connect(dut.io.jtag.get, reset, io.success)
|
val jtag = Module(new JTAGVPI).connect(dut.io.jtag.get, reset, io.success)
|
||||||
}
|
}
|
||||||
|
|
||||||
val mmio_sim = Module(LazyModule(new SimAXIMem(4096)).module)
|
val mmio_sim = Module(LazyModule(new SimAXIMem(1, 4096)).module)
|
||||||
mmio_sim.io.axi4 <> dut.io.mmio_axi4
|
mmio_sim.io.axi4 <> dut.io.mmio_axi4
|
||||||
|
|
||||||
val l2_axi4 = dut.io.l2_axi4(0)
|
val l2_axi4 = dut.io.l2_axi4(0)
|
||||||
@ -43,12 +38,19 @@ class TestHarness()(implicit p: Parameters) extends Module {
|
|||||||
l2_axi4.b .ready := Bool(true)
|
l2_axi4.b .ready := Bool(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
class SimAXIMem(size: BigInt)(implicit p: Parameters) extends LazyModule {
|
class SimAXIMem(channels: Int, forceSize: BigInt = 0)(implicit p: Parameters) extends LazyModule {
|
||||||
val config = p(ExtMem)
|
val config = p(ExtMem)
|
||||||
|
val totalSize = if (forceSize > 0) forceSize else BigInt(config.size)
|
||||||
|
val size = totalSize / channels
|
||||||
|
require(totalSize % channels == 0)
|
||||||
|
|
||||||
val node = AXI4BlindInputNode(Seq(AXI4MasterPortParameters(Seq(AXI4MasterParameters(IdRange(0, 1 << config.idBits))))))
|
val node = AXI4BlindInputNode(Seq.fill(channels) {
|
||||||
val sram = LazyModule(new AXI4RAM(AddressSet(0, size-1), beatBytes = config.beatBytes))
|
AXI4MasterPortParameters(Seq(AXI4MasterParameters(IdRange(0, 1 << config.idBits))))})
|
||||||
sram.node := AXI4Buffer()(AXI4Fragmenter(maxInFlight = 4)(node))
|
|
||||||
|
for (i <- 0 until channels) {
|
||||||
|
val sram = LazyModule(new AXI4RAM(AddressSet(0, size-1), beatBytes = config.beatBytes))
|
||||||
|
sram.node := AXI4Buffer()(AXI4Fragmenter(maxInFlight = 4)(node))
|
||||||
|
}
|
||||||
|
|
||||||
lazy val module = new LazyModuleImp(this) {
|
lazy val module = new LazyModuleImp(this) {
|
||||||
val io = new Bundle {
|
val io = new Bundle {
|
||||||
|
Loading…
Reference in New Issue
Block a user