add MultiChannel routing to Nasti interconnect generator
This commit is contained in:
parent
8fe4917d8e
commit
3270d17ad3
@ -36,8 +36,8 @@ trait HasAddrMapParameters {
|
||||
abstract class MemRegion { def size: BigInt }
|
||||
|
||||
case class MemSize(size: BigInt, prot: Int) extends MemRegion
|
||||
|
||||
case class MemSubmap(size: BigInt, entries: AddrMap) extends MemRegion
|
||||
case class MemChannels(size: BigInt, nchannels: Int, prot: Int) extends MemRegion
|
||||
|
||||
object AddrMapConsts {
|
||||
val R = 0x4
|
||||
@ -68,6 +68,7 @@ class AddrMap(entries: Seq[AddrMapEntry]) extends scala.collection.IndexedSeq[Ad
|
||||
this map { entry: AddrMapEntry => entry.region match {
|
||||
case MemSize(_, _) => 1
|
||||
case MemSubmap(_, submap) => submap.countSlaves
|
||||
case MemChannels(_, nchannels, _) => nchannels
|
||||
}} reduceLeft(_ + _)
|
||||
}
|
||||
}
|
||||
@ -102,6 +103,17 @@ class AddrHashMap(addrmap: AddrMap) {
|
||||
ind += subpairs.size
|
||||
base += size
|
||||
}
|
||||
// every channel gets the same base and size
|
||||
case MemChannels(size, nchannels, prot) => {
|
||||
if (!startOpt.isEmpty) base = startOpt.get
|
||||
val subpairs = (0 until nchannels).map { i =>
|
||||
val chname = name + ":" + i.toString
|
||||
(chname, AddrHashMapEntry(ind + i, base, size, prot))
|
||||
}
|
||||
pairs = subpairs ++ pairs
|
||||
ind += nchannels
|
||||
base += size
|
||||
}
|
||||
}
|
||||
}
|
||||
pairs
|
||||
|
@ -363,45 +363,32 @@ class NastiErrorSlave(implicit p: Parameters) extends NastiModule {
|
||||
}
|
||||
|
||||
/** Take a single Nasti master and route its requests to various slaves
|
||||
* @param addrmap a sequence of base address + memory size pairs,
|
||||
* on for each slave interface */
|
||||
class NastiRouter(addrmap: Seq[(BigInt, BigInt)])(implicit p: Parameters) extends NastiModule {
|
||||
val nSlaves = addrmap.size
|
||||
* @param nSlaves the number of slaves
|
||||
* @param routeSel a function which takes an address and produces
|
||||
* a one-hot encoded selection of the slave to write to */
|
||||
class NastiRouter(nSlaves: Int, routeSel: UInt => UInt)(implicit p: Parameters)
|
||||
extends NastiModule {
|
||||
|
||||
val io = new Bundle {
|
||||
val master = (new NastiIO).flip
|
||||
val slave = Vec(new NastiIO, nSlaves)
|
||||
}
|
||||
|
||||
val ar_route = routeSel(io.master.ar.bits.addr)
|
||||
val aw_route = routeSel(io.master.aw.bits.addr)
|
||||
|
||||
var ar_ready = Bool(false)
|
||||
var aw_ready = Bool(false)
|
||||
var w_ready = Bool(false)
|
||||
var r_valid_addr = Bool(false)
|
||||
var w_valid_addr = Bool(false)
|
||||
|
||||
addrmap.zip(io.slave).zipWithIndex.foreach { case (((base, size), s), i) =>
|
||||
val bound = base + size
|
||||
|
||||
require(bigIntPow2(size),
|
||||
s"Region size $size is not a power of 2")
|
||||
require(base % size == 0,
|
||||
f"Region base address $base%x not divisible by $size%d" )
|
||||
|
||||
val ar_addr = io.master.ar.bits.addr
|
||||
val ar_match = ar_addr >= UInt(base) && ar_addr < UInt(bound)
|
||||
|
||||
s.ar.valid := io.master.ar.valid && ar_match
|
||||
io.slave.zipWithIndex.foreach { case (s, i) =>
|
||||
s.ar.valid := io.master.ar.valid && ar_route(i)
|
||||
s.ar.bits := io.master.ar.bits
|
||||
ar_ready = ar_ready || (s.ar.ready && ar_match)
|
||||
r_valid_addr = r_valid_addr || ar_match
|
||||
ar_ready = ar_ready || (s.ar.ready && ar_route(i))
|
||||
|
||||
val aw_addr = io.master.aw.bits.addr
|
||||
val aw_match = aw_addr >= UInt(base) && aw_addr < UInt(bound)
|
||||
|
||||
s.aw.valid := io.master.aw.valid && aw_match
|
||||
s.aw.valid := io.master.aw.valid && aw_route(i)
|
||||
s.aw.bits := io.master.aw.bits
|
||||
aw_ready = aw_ready || (s.aw.ready && aw_match)
|
||||
w_valid_addr = w_valid_addr || aw_match
|
||||
aw_ready = aw_ready || (s.aw.ready && aw_route(i))
|
||||
|
||||
val chosen = Reg(init = Bool(false))
|
||||
when (s.aw.fire()) { chosen := Bool(true) }
|
||||
@ -412,16 +399,19 @@ class NastiRouter(addrmap: Seq[(BigInt, BigInt)])(implicit p: Parameters) extend
|
||||
w_ready = w_ready || (s.w.ready && chosen)
|
||||
}
|
||||
|
||||
val r_invalid = !ar_route.orR
|
||||
val w_invalid = !aw_route.orR
|
||||
|
||||
val err_slave = Module(new NastiErrorSlave)
|
||||
err_slave.io.ar.valid := !r_valid_addr && io.master.ar.valid
|
||||
err_slave.io.ar.valid := r_invalid && io.master.ar.valid
|
||||
err_slave.io.ar.bits := io.master.ar.bits
|
||||
err_slave.io.aw.valid := !w_valid_addr && io.master.aw.valid
|
||||
err_slave.io.aw.valid := w_invalid && io.master.aw.valid
|
||||
err_slave.io.aw.bits := io.master.aw.bits
|
||||
err_slave.io.w.valid := io.master.w.valid
|
||||
err_slave.io.w.bits := io.master.w.bits
|
||||
|
||||
io.master.ar.ready := ar_ready || (!r_valid_addr && err_slave.io.ar.ready)
|
||||
io.master.aw.ready := aw_ready || (!w_valid_addr && err_slave.io.aw.ready)
|
||||
io.master.ar.ready := ar_ready || (r_invalid && err_slave.io.ar.ready)
|
||||
io.master.aw.ready := aw_ready || (w_invalid && err_slave.io.aw.ready)
|
||||
io.master.w.ready := w_ready || err_slave.io.w.ready
|
||||
|
||||
val b_arb = Module(new RRArbiter(new NastiWriteResponseChannel, nSlaves + 1))
|
||||
@ -445,25 +435,48 @@ class NastiRouter(addrmap: Seq[(BigInt, BigInt)])(implicit p: Parameters) extend
|
||||
/** Crossbar between multiple Nasti masters and slaves
|
||||
* @param nMasters the number of Nasti masters
|
||||
* @param nSlaves the number of Nasti slaves
|
||||
* @param addrmap a sequence of base - size pairs;
|
||||
* size of addrmap should be nSlaves */
|
||||
class NastiCrossbar(nMasters: Int, nSlaves: Int, addrmap: Seq[(BigInt, BigInt)])
|
||||
* @param routeSel a function selecting the slave to route an address to */
|
||||
class NastiCrossbar(nMasters: Int, nSlaves: Int, routeSel: UInt => UInt)
|
||||
(implicit p: Parameters) extends NastiModule {
|
||||
val io = new Bundle {
|
||||
val masters = Vec(new NastiIO, nMasters).flip
|
||||
val slaves = Vec(new NastiIO, nSlaves)
|
||||
}
|
||||
|
||||
val routers = Vec.fill(nMasters) { Module(new NastiRouter(addrmap)).io }
|
||||
val arbiters = Vec.fill(nSlaves) { Module(new NastiArbiter(nMasters)).io }
|
||||
if (nMasters == 1) {
|
||||
val router = Module(new NastiRouter(nSlaves, routeSel))
|
||||
router.io.master <> io.masters.head
|
||||
io.slaves <> router.io.slave
|
||||
} else {
|
||||
val routers = Vec.fill(nMasters) { Module(new NastiRouter(nSlaves, routeSel)).io }
|
||||
val arbiters = Vec.fill(nSlaves) { Module(new NastiArbiter(nMasters)).io }
|
||||
|
||||
for (i <- 0 until nMasters) {
|
||||
routers(i).master <> io.masters(i)
|
||||
for (i <- 0 until nMasters) {
|
||||
routers(i).master <> io.masters(i)
|
||||
}
|
||||
|
||||
for (i <- 0 until nSlaves) {
|
||||
arbiters(i).master <> Vec(routers.map(r => r.slave(i)))
|
||||
io.slaves(i) <> arbiters(i).slave
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i <- 0 until nSlaves) {
|
||||
arbiters(i).master <> Vec(routers.map(r => r.slave(i)))
|
||||
io.slaves(i) <> arbiters(i).slave
|
||||
object NastiMultiChannelRouter {
|
||||
def apply(master: NastiIO, nChannels: Int)(implicit p: Parameters): Vec[NastiIO] = {
|
||||
require(isPow2(nChannels), "Number of channels must be power of 2")
|
||||
if (nChannels == 1) {
|
||||
Vec(master)
|
||||
} else {
|
||||
val dataBytes = p(MIFDataBits) * p(MIFDataBeats) / 8
|
||||
val selBits = log2Ceil(nChannels)
|
||||
val routeSel = (addr: UInt) => {
|
||||
Vec.tabulate(nChannels)(i => addr(selBits - 1, 0) === UInt(i)).toBits
|
||||
}
|
||||
val router = Module(new NastiRouter(nChannels, routeSel))
|
||||
router.io.master <> master
|
||||
router.io.slave
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -502,30 +515,40 @@ class NastiRecursiveInterconnect(
|
||||
lastEnd = start + size
|
||||
}
|
||||
|
||||
val flatSlaves = if (nMasters > 1) {
|
||||
val xbar = Module(new NastiCrossbar(nMasters, levelSize, realAddrMap))
|
||||
xbar.io.masters <> io.masters
|
||||
xbar.io.slaves
|
||||
} else {
|
||||
val router = Module(new NastiRouter(realAddrMap))
|
||||
router.io.master <> io.masters.head
|
||||
router.io.slave
|
||||
val routeSel = (addr: UInt) => {
|
||||
Vec(realAddrMap.map { case (start, size) =>
|
||||
require(bigIntPow2(size),
|
||||
s"Region size $size is not a power of 2")
|
||||
require(base % size == 0,
|
||||
f"Region base address $base%x not divisible by $size%d" )
|
||||
|
||||
addr >= UInt(start) && addr < UInt(start + size)
|
||||
}).toBits
|
||||
}
|
||||
|
||||
addrmap.zip(realAddrMap).zipWithIndex.foreach {
|
||||
case ((entry, (start, size)), i) => {
|
||||
val xbar = Module(new NastiCrossbar(nMasters, levelSize, routeSel))
|
||||
xbar.io.masters <> io.masters
|
||||
|
||||
addrmap.zip(realAddrMap).zip(xbar.io.slaves).zipWithIndex.foreach {
|
||||
case (((entry, (start, size)), xbarSlave), i) => {
|
||||
entry.region match {
|
||||
case MemSize(_, _) =>
|
||||
io.slaves(slaveInd) <> flatSlaves(i)
|
||||
io.slaves(slaveInd) <> xbarSlave
|
||||
slaveInd += 1
|
||||
case MemSubmap(_, submap) =>
|
||||
val subSlaves = submap.countSlaves
|
||||
val ic = Module(new NastiRecursiveInterconnect(1, subSlaves, submap, start))
|
||||
ic.io.masters.head <> flatSlaves(i)
|
||||
ic.io.masters.head <> xbarSlave
|
||||
io.slaves.drop(slaveInd).take(subSlaves).zip(ic.io.slaves).foreach {
|
||||
case (s, m) => s <> m
|
||||
}
|
||||
slaveInd += subSlaves
|
||||
case MemChannels(_, nchannels, _) =>
|
||||
val routerSlaves = NastiMultiChannelRouter(xbarSlave, nchannels)
|
||||
io.slaves.drop(slaveInd).take(nchannels).zip(routerSlaves).foreach {
|
||||
case (s, m) => s <> m
|
||||
}
|
||||
slaveInd += nchannels
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user