1
0

tilelink2: make some Xbar methods reusable

This commit is contained in:
Wesley W. Terpstra 2017-05-19 14:48:00 -07:00
parent 0a2a93c27d
commit de39af7f65

View File

@ -8,34 +8,6 @@ import diplomacy._
class TLXbar(policy: TLArbiter.Policy = TLArbiter.lowestIndexFirst)(implicit p: Parameters) extends LazyModule
{
def mapInputIds (ports: Seq[TLClientPortParameters ]) = assignRanges(ports.map(_.endSourceId)).map(_.get)
def mapOutputIds(ports: Seq[TLManagerPortParameters]) = assignRanges(ports.map(_.endSinkId))
def assignRanges(sizes: Seq[Int]) = {
val pow2Sizes = sizes.map { z => if (z == 0) 0 else 1 << log2Ceil(z) }
val tuples = pow2Sizes.zipWithIndex.sortBy(_._1) // record old index, then sort by increasing size
val starts = tuples.scanRight(0)(_._1 + _).tail // suffix-sum of the sizes = the start positions
val ranges = (tuples zip starts) map { case ((sz, i), st) =>
(if (sz == 0) None else Some(IdRange(st, st+sz)), i)
}
ranges.sortBy(_._2).map(_._1) // Restore orignal order
}
def relabeler() = {
var idFactory = 0
() => {
val fifoMap = scala.collection.mutable.HashMap.empty[Int, Int]
(x: Int) => {
if (fifoMap.contains(x)) fifoMap(x) else {
val out = idFactory
idFactory = idFactory + 1
fifoMap += (x -> out)
out
}
}
}
}
val node = TLNexusNode(
numClientPorts = 1 to 32,
numManagerPorts = 1 to 32,
@ -44,7 +16,7 @@ class TLXbar(policy: TLArbiter.Policy = TLArbiter.lowestIndexFirst)(implicit p:
"An unsafe atomic port can not be combined with any other!")
seq(0).copy(
minLatency = seq.map(_.minLatency).min,
clients = (mapInputIds(seq) zip seq) flatMap { case (range, port) =>
clients = (TLXbar.mapInputIds(seq) zip seq) flatMap { case (range, port) =>
port.clients map { client => client.copy(
sourceId = client.sourceId.shift(range.start)
)}
@ -52,8 +24,8 @@ class TLXbar(policy: TLArbiter.Policy = TLArbiter.lowestIndexFirst)(implicit p:
)
},
managerFn = { seq =>
val fifoIdFactory = relabeler()
val outputIdRanges = mapOutputIds(seq)
val fifoIdFactory = TLXbar.relabeler()
val outputIdRanges = TLXbar.mapOutputIds(seq)
seq(0).copy(
minLatency = seq.map(_.minLatency).min,
endSinkId = outputIdRanges.map(_.map(_.end).getOrElse(0)).max,
@ -75,8 +47,8 @@ class TLXbar(policy: TLArbiter.Policy = TLArbiter.lowestIndexFirst)(implicit p:
}
// Grab the port ID mapping
val inputIdRanges = mapInputIds(node.edgesIn.map(_.client))
val outputIdRanges = mapOutputIds(node.edgesOut.map(_.manager))
val inputIdRanges = TLXbar.mapInputIds(node.edgesIn.map(_.client))
val outputIdRanges = TLXbar.mapOutputIds(node.edgesOut.map(_.manager))
// Find a good mask for address decoding
val port_addrs = node.edgesOut.map(_.manager.managers.map(_.address).flatten)
@ -170,23 +142,12 @@ class TLXbar(policy: TLArbiter.Policy = TLArbiter.lowestIndexFirst)(implicit p:
def transpose[T](x: Seq[Seq[T]]) = Seq.tabulate(x(0).size) { i => Seq.tabulate(x.size) { j => x(j)(i) } }
def filter[T](data: Seq[T], mask: Seq[Boolean]) = (data zip mask).filter(_._2).map(_._1)
// Replicate an input port to each output port
def fanout[T <: TLChannel](input: DecoupledIO[T], select: Seq[Bool]) = {
val filtered = Wire(Vec(select.size, input))
for (i <- 0 until select.size) {
filtered(i).bits := input.bits
filtered(i).valid := input.valid && select(i)
}
input.ready := Mux1H(select, filtered.map(_.ready))
filtered
}
// Fanout the input sources to the output sinks
val portsAOI = transpose((in zip requestAIO) map { case (i, r) => fanout(i.a, r) })
val portsBIO = transpose((out zip requestBOI) map { case (o, r) => fanout(o.b, r) })
val portsCOI = transpose((in zip requestCIO) map { case (i, r) => fanout(i.c, r) })
val portsDIO = transpose((out zip requestDOI) map { case (o, r) => fanout(o.d, r) })
val portsEOI = transpose((in zip requestEIO) map { case (i, r) => fanout(i.e, r) })
val portsAOI = transpose((in zip requestAIO) map { case (i, r) => TLXbar.fanout(i.a, r) })
val portsBIO = transpose((out zip requestBOI) map { case (o, r) => TLXbar.fanout(o.b, r) })
val portsCOI = transpose((in zip requestCIO) map { case (i, r) => TLXbar.fanout(i.c, r) })
val portsDIO = transpose((out zip requestDOI) map { case (o, r) => TLXbar.fanout(o.d, r) })
val portsEOI = transpose((in zip requestEIO) map { case (i, r) => TLXbar.fanout(i.e, r) })
// Arbitrate amongst the sources
for (o <- 0 until out.size) {
@ -210,6 +171,48 @@ class TLXbar(policy: TLArbiter.Policy = TLArbiter.lowestIndexFirst)(implicit p:
}
}
object TLXbar
{
def mapInputIds (ports: Seq[TLClientPortParameters ]) = assignRanges(ports.map(_.endSourceId)).map(_.get)
def mapOutputIds(ports: Seq[TLManagerPortParameters]) = assignRanges(ports.map(_.endSinkId))
def assignRanges(sizes: Seq[Int]) = {
val pow2Sizes = sizes.map { z => if (z == 0) 0 else 1 << log2Ceil(z) }
val tuples = pow2Sizes.zipWithIndex.sortBy(_._1) // record old index, then sort by increasing size
val starts = tuples.scanRight(0)(_._1 + _).tail // suffix-sum of the sizes = the start positions
val ranges = (tuples zip starts) map { case ((sz, i), st) =>
(if (sz == 0) None else Some(IdRange(st, st+sz)), i)
}
ranges.sortBy(_._2).map(_._1) // Restore orignal order
}
def relabeler() = {
var idFactory = 0
() => {
val fifoMap = scala.collection.mutable.HashMap.empty[Int, Int]
(x: Int) => {
if (fifoMap.contains(x)) fifoMap(x) else {
val out = idFactory
idFactory = idFactory + 1
fifoMap += (x -> out)
out
}
}
}
}
// Replicate an input port to each output port
def fanout[T <: TLChannel](input: DecoupledIO[T], select: Seq[Bool]) = {
val filtered = Wire(Vec(select.size, input))
for (i <- 0 until select.size) {
filtered(i).bits := input.bits
filtered(i).valid := input.valid && select(i)
}
input.ready := Mux1H(select, filtered.map(_.ready))
filtered
}
}
/** Synthesizeable unit tests */
import unittest._