2016-03-31 20:38:54 +02:00
|
|
|
package uncore
|
|
|
|
|
|
|
|
import Chisel._
|
|
|
|
import junctions._
|
|
|
|
import scala.collection.mutable.ArraySeq
|
|
|
|
import cde.{Parameters, Field}
|
|
|
|
|
|
|
|
class ClientUncachedTileLinkIORouter(
|
|
|
|
nOuter: Int, routeSel: UInt => UInt)(implicit p: Parameters)
|
|
|
|
extends TLModule {
|
|
|
|
|
|
|
|
val io = new Bundle {
|
|
|
|
val in = (new ClientUncachedTileLinkIO).flip
|
|
|
|
val out = Vec(nOuter, new ClientUncachedTileLinkIO)
|
|
|
|
}
|
|
|
|
|
|
|
|
val acq_route = routeSel(io.in.acquire.bits.full_addr())
|
|
|
|
|
|
|
|
io.in.acquire.ready := Bool(false)
|
|
|
|
|
|
|
|
io.out.zipWithIndex.foreach { case (out, i) =>
|
|
|
|
out.acquire.valid := io.in.acquire.valid && acq_route(i)
|
|
|
|
out.acquire.bits := io.in.acquire.bits
|
|
|
|
when (acq_route(i)) { io.in.acquire.ready := out.acquire.ready }
|
|
|
|
}
|
|
|
|
|
|
|
|
val gnt_arb = Module(new LockingRRArbiter(
|
|
|
|
new Grant, nOuter, tlDataBeats, Some((gnt: Grant) => gnt.hasMultibeatData())))
|
|
|
|
gnt_arb.io.in <> io.out.map(_.grant)
|
|
|
|
io.in.grant <> gnt_arb.io.out
|
|
|
|
}
|
|
|
|
|
|
|
|
class TileLinkInterconnectIO(val nInner: Int, val nOuter: Int)
|
|
|
|
(implicit p: Parameters) extends Bundle {
|
|
|
|
val in = Vec(nInner, new ClientUncachedTileLinkIO).flip
|
|
|
|
val out = Vec(nOuter, new ClientUncachedTileLinkIO)
|
|
|
|
}
|
|
|
|
|
|
|
|
class ClientUncachedTileLinkIOCrossbar(
|
|
|
|
nInner: Int, nOuter: Int, routeSel: UInt => UInt)
|
|
|
|
(implicit p: Parameters) extends TLModule {
|
|
|
|
|
|
|
|
val io = new TileLinkInterconnectIO(nInner, nOuter)
|
|
|
|
|
|
|
|
if (nInner == 1) {
|
|
|
|
val router = Module(new ClientUncachedTileLinkIORouter(nOuter, routeSel))
|
|
|
|
router.io.in <> io.in.head
|
|
|
|
io.out <> router.io.out
|
|
|
|
} else {
|
|
|
|
val routers = List.fill(nInner) {
|
|
|
|
Module(new ClientUncachedTileLinkIORouter(nOuter, routeSel)) }
|
|
|
|
val arbiters = List.fill(nOuter) {
|
|
|
|
Module(new ClientUncachedTileLinkIOArbiter(nInner)) }
|
|
|
|
|
|
|
|
for (i <- 0 until nInner) {
|
|
|
|
routers(i).io.in <> io.in(i)
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i <- 0 until nOuter) {
|
|
|
|
arbiters(i).io.in <> routers.map(r => r.io.out(i))
|
|
|
|
io.out(i) <> arbiters(i).io.out
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
abstract class TileLinkInterconnect(implicit p: Parameters) extends TLModule()(p) {
|
|
|
|
val nInner: Int
|
|
|
|
val nOuter: Int
|
|
|
|
|
|
|
|
lazy val io = new TileLinkInterconnectIO(nInner, nOuter)
|
|
|
|
}
|
|
|
|
|
|
|
|
class TileLinkRecursiveInterconnect(
|
|
|
|
val nInner: Int, val nOuter: Int,
|
|
|
|
addrmap: AddrMap, base: BigInt)
|
|
|
|
(implicit p: Parameters) extends TileLinkInterconnect()(p) {
|
|
|
|
var lastEnd = base
|
|
|
|
var outInd = 0
|
|
|
|
val levelSize = addrmap.size
|
|
|
|
val realAddrMap = new ArraySeq[(BigInt, BigInt)](addrmap.size)
|
|
|
|
|
|
|
|
addrmap.zipWithIndex.foreach { case (AddrMapEntry(name, startOpt, region), i) =>
|
|
|
|
val start = startOpt.getOrElse(lastEnd)
|
|
|
|
val size = region.size
|
|
|
|
|
|
|
|
require(bigIntPow2(size),
|
|
|
|
s"Region $name size $size is not a power of 2")
|
|
|
|
require(start % size == 0,
|
|
|
|
f"Region $name start address 0x$start%x not divisible by 0x$size%x" )
|
|
|
|
require(start >= lastEnd,
|
|
|
|
f"Region $name start address 0x$start%x before previous region end")
|
|
|
|
|
|
|
|
realAddrMap(i) = (start, size)
|
|
|
|
lastEnd = start + size
|
|
|
|
}
|
|
|
|
|
|
|
|
val routeSel = (addr: UInt) => {
|
|
|
|
Cat(realAddrMap.map { case (start, size) =>
|
|
|
|
addr >= UInt(start) && addr < UInt(start + size)
|
|
|
|
}.reverse)
|
|
|
|
}
|
|
|
|
|
|
|
|
val xbar = Module(new ClientUncachedTileLinkIOCrossbar(nInner, levelSize, routeSel))
|
|
|
|
xbar.io.in <> io.in
|
|
|
|
|
|
|
|
addrmap.zip(realAddrMap).zip(xbar.io.out).zipWithIndex.foreach {
|
|
|
|
case (((entry, (start, size)), xbarOut), i) => {
|
|
|
|
entry.region match {
|
|
|
|
case MemSize(_, _) =>
|
|
|
|
io.out(outInd) <> xbarOut
|
|
|
|
outInd += 1
|
|
|
|
case MemSubmap(_, submap) =>
|
|
|
|
if (submap.isEmpty) {
|
|
|
|
xbarOut.acquire.ready := Bool(false)
|
|
|
|
xbarOut.grant.valid := Bool(false)
|
|
|
|
} else {
|
|
|
|
val subSlaves = submap.countSlaves
|
|
|
|
val outputs = io.out.drop(outInd).take(subSlaves)
|
|
|
|
val ic = Module(new TileLinkRecursiveInterconnect(1, subSlaves, submap, start))
|
|
|
|
ic.io.in.head <> xbarOut
|
|
|
|
for ((o, s) <- outputs zip ic.io.out)
|
|
|
|
o <> s
|
|
|
|
outInd += subSlaves
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-04-01 03:15:51 +02:00
|
|
|
|
|
|
|
class TileLinkMemoryInterconnect(
|
|
|
|
nBanksPerChannel: Int, nChannels: Int)
|
|
|
|
(implicit p: Parameters) extends TileLinkInterconnect()(p) {
|
|
|
|
|
|
|
|
val nBanks = nBanksPerChannel * nChannels
|
|
|
|
val nInner = nBanks
|
|
|
|
val nOuter = nChannels
|
|
|
|
|
|
|
|
def connectChannel(outer: ClientUncachedTileLinkIO, inner: ClientUncachedTileLinkIO) {
|
|
|
|
outer <> inner
|
|
|
|
outer.acquire.bits.addr_block := inner.acquire.bits.addr_block >> UInt(log2Ceil(nChannels))
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i <- 0 until nChannels) {
|
|
|
|
/* Bank assignments to channels are strided so that consecutive banks
|
|
|
|
* map to different channels. That way, consecutive cache lines also
|
|
|
|
* map to different channels */
|
|
|
|
val banks = (i until nBanks by nChannels).map(j => io.in(j))
|
|
|
|
|
|
|
|
val channelArb = Module(new ClientUncachedTileLinkIOArbiter(nBanksPerChannel))
|
|
|
|
channelArb.io.in <> banks
|
|
|
|
connectChannel(io.out(i), channelArb.io.out)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Allows users to switch between various memory configurations. Note that
|
|
|
|
* this is a dangerous operation: not only does switching the select input to
|
|
|
|
* this module violate TileLink, it also causes the memory of the machine to
|
|
|
|
* become garbled. It's expected that select only changes at boot time, as
|
|
|
|
* part of the memory controller configuration. */
|
|
|
|
class TileLinkMemorySelectorIO(val nBanks: Int, val maxMemChannels: Int, nConfigs: Int)
|
|
|
|
(implicit p: Parameters)
|
|
|
|
extends TileLinkInterconnectIO(nBanks, maxMemChannels) {
|
|
|
|
val select = UInt(INPUT, width = log2Up(nConfigs))
|
|
|
|
override def cloneType =
|
|
|
|
new TileLinkMemorySelectorIO(nBanks, maxMemChannels, nConfigs).asInstanceOf[this.type]
|
|
|
|
}
|
|
|
|
|
|
|
|
class TileLinkMemorySelector(nBanks: Int, maxMemChannels: Int, configs: Seq[Int])
|
|
|
|
(implicit p: Parameters)
|
|
|
|
extends TileLinkInterconnect()(p) {
|
|
|
|
val nInner = nBanks
|
|
|
|
val nOuter = maxMemChannels
|
|
|
|
val nConfigs = configs.size
|
|
|
|
|
|
|
|
override lazy val io = new TileLinkMemorySelectorIO(nBanks, maxMemChannels, nConfigs)
|
|
|
|
|
|
|
|
def muxOnSelect[T <: Data](up: DecoupledIO[T], dn: DecoupledIO[T], active: Bool): Unit = {
|
|
|
|
when (active) { dn.bits := up.bits }
|
|
|
|
when (active) { up.ready := dn.ready }
|
|
|
|
when (active) { dn.valid := up.valid }
|
|
|
|
}
|
|
|
|
|
|
|
|
def muxOnSelect(up: ClientUncachedTileLinkIO, dn: ClientUncachedTileLinkIO, active: Bool): Unit = {
|
|
|
|
muxOnSelect(up.acquire, dn.acquire, active)
|
|
|
|
muxOnSelect(dn.grant, up.grant, active)
|
|
|
|
}
|
|
|
|
|
|
|
|
def muxOnSelect(up: Vec[ClientUncachedTileLinkIO], dn: Vec[ClientUncachedTileLinkIO], active: Bool) : Unit = {
|
|
|
|
for (i <- 0 until up.size)
|
|
|
|
muxOnSelect(up(i), dn(i), active)
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Disconnects a vector of TileLink ports, which involves setting them to
|
|
|
|
* invalid. Due to Chisel reasons, we need to also set the bits to 0 (since
|
|
|
|
* there can't be any unconnected inputs). */
|
|
|
|
def disconnectOuter(outer: Vec[ClientUncachedTileLinkIO]) = {
|
|
|
|
outer.foreach{ m =>
|
|
|
|
m.acquire.valid := Bool(false)
|
|
|
|
m.acquire.bits := m.acquire.bits.fromBits(UInt(0))
|
|
|
|
m.grant.ready := Bool(false)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
def disconnectInner(inner: Vec[ClientUncachedTileLinkIO]) = {
|
|
|
|
inner.foreach { m =>
|
|
|
|
m.grant.valid := Bool(false)
|
|
|
|
m.grant.bits := m.grant.bits.fromBits(UInt(0))
|
|
|
|
m.acquire.ready := Bool(false)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Provides default wires on all our outputs. */
|
|
|
|
disconnectOuter(io.out)
|
|
|
|
disconnectInner(io.in)
|
|
|
|
|
|
|
|
/* Constructs interconnects for each of the layouts suggested by the
|
|
|
|
* configuration and switches between them based on the select input. */
|
|
|
|
configs.zipWithIndex.foreach{ case (nChannels, select) =>
|
|
|
|
val nBanksPerChannel = nBanks / nChannels
|
|
|
|
val ic = Module(new TileLinkMemoryInterconnect(nBanksPerChannel, nChannels))
|
|
|
|
disconnectInner(ic.io.out)
|
|
|
|
disconnectOuter(ic.io.in)
|
|
|
|
muxOnSelect(io.in, ic.io.in, io.select === UInt(select))
|
|
|
|
muxOnSelect(ic.io.out, io.out, io.select === UInt(select))
|
|
|
|
}
|
|
|
|
}
|