Merge pull request #757 from freechipsproject/isp-port
Inter-System-Port
This commit is contained in:
commit
5368ea60fe
@ -13,6 +13,8 @@ trait CoreplexNetwork extends HasCoreplexParameters {
|
|||||||
val module: CoreplexNetworkModule
|
val module: CoreplexNetworkModule
|
||||||
def bindingTree: ResourceMap
|
def bindingTree: ResourceMap
|
||||||
|
|
||||||
|
val tile_splitter = LazyModule(new TLSplitter)
|
||||||
|
|
||||||
val l1tol2 = LazyModule(new TLXbar)
|
val l1tol2 = LazyModule(new TLXbar)
|
||||||
val l1tol2_beatBytes = l1tol2Config.beatBytes
|
val l1tol2_beatBytes = l1tol2Config.beatBytes
|
||||||
val l1tol2_lineBytes = p(CacheBlockBytes)
|
val l1tol2_lineBytes = p(CacheBlockBytes)
|
||||||
@ -34,6 +36,7 @@ trait CoreplexNetwork extends HasCoreplexParameters {
|
|||||||
private val l2in_buffer = LazyModule(new TLBuffer)
|
private val l2in_buffer = LazyModule(new TLBuffer)
|
||||||
private val l2in_fifo = LazyModule(new TLFIFOFixer)
|
private val l2in_fifo = LazyModule(new TLFIFOFixer)
|
||||||
l1tol2.node :=* l2in_fifo.node
|
l1tol2.node :=* l2in_fifo.node
|
||||||
|
l1tol2.node :=* tile_splitter.node
|
||||||
l2in_fifo.node :=* l2in_buffer.node
|
l2in_fifo.node :=* l2in_buffer.node
|
||||||
l2in_buffer.node :=* l2in
|
l2in_buffer.node :=* l2in
|
||||||
|
|
||||||
@ -83,7 +86,7 @@ trait CoreplexNetwork extends HasCoreplexParameters {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Make topManagers an Option[] so as to avoid LM name reflection evaluating it...
|
// Make topManagers an Option[] so as to avoid LM name reflection evaluating it...
|
||||||
lazy val topManagers = Some(ManagerUnification(l1tol2.node.edgesIn.headOption.map(_.manager.managers).getOrElse(Nil)))
|
lazy val topManagers = Some(ManagerUnification(tile_splitter.node.edgesIn.headOption.map(_.manager.managers).getOrElse(Nil)))
|
||||||
ResourceBinding {
|
ResourceBinding {
|
||||||
val managers = topManagers.get
|
val managers = topManagers.get
|
||||||
val max = managers.flatMap(_.address).map(_.max).max
|
val max = managers.flatMap(_.address).map(_.max).max
|
||||||
|
44
src/main/scala/coreplex/ISPPort.scala
Normal file
44
src/main/scala/coreplex/ISPPort.scala
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
|
package coreplex
|
||||||
|
|
||||||
|
import Chisel._
|
||||||
|
import config._
|
||||||
|
import diplomacy._
|
||||||
|
import rocket._
|
||||||
|
import tile._
|
||||||
|
import uncore.tilelink2._
|
||||||
|
import util._
|
||||||
|
|
||||||
|
trait HasISPPort extends CoreplexNetwork {
|
||||||
|
val module: HasISPPortModule
|
||||||
|
|
||||||
|
// TODO: use ChipLink instead of AsyncTileLink
|
||||||
|
val isp_in = TLAsyncInputNode()
|
||||||
|
val isp_out = TLAsyncOutputNode()
|
||||||
|
|
||||||
|
private val out_xbar = LazyModule(new TLXbar)
|
||||||
|
private val out_nums = LazyModule(new TLNodeNumberer)
|
||||||
|
private val out_async = LazyModule(new TLAsyncCrossingSource)
|
||||||
|
out_xbar.node :=* tile_splitter.node
|
||||||
|
out_nums.node :*= out_xbar.node
|
||||||
|
out_async.node :*= out_nums.node
|
||||||
|
isp_out :*= out_async.node
|
||||||
|
|
||||||
|
private val in_async = LazyModule(new TLAsyncCrossingSink)
|
||||||
|
in_async.node :=* isp_in
|
||||||
|
l1tol2.node :=* in_async.node
|
||||||
|
}
|
||||||
|
|
||||||
|
trait HasISPPortBundle extends CoreplexNetworkBundle {
|
||||||
|
val outer: HasISPPort
|
||||||
|
|
||||||
|
// TODO: move to IO(...) in Module?
|
||||||
|
val isp_in = outer.isp_in.bundleIn
|
||||||
|
val isp_out = outer.isp_out.bundleOut
|
||||||
|
}
|
||||||
|
|
||||||
|
trait HasISPPortModule extends CoreplexNetworkModule {
|
||||||
|
val outer: HasISPPort
|
||||||
|
val io: HasISPPortBundle
|
||||||
|
}
|
@ -36,7 +36,7 @@ trait HasRocketTiles extends CoreplexRISCVPlatform {
|
|||||||
val pWithExtra = p.alterPartial {
|
val pWithExtra = p.alterPartial {
|
||||||
case TileKey => c
|
case TileKey => c
|
||||||
case BuildRoCC => c.rocc
|
case BuildRoCC => c.rocc
|
||||||
case SharedMemoryTLEdge => l1tol2.node.edgesIn(0)
|
case SharedMemoryTLEdge => tile_splitter.node.edgesIn(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
val asyncIntXbar = LazyModule(new IntXbar)
|
val asyncIntXbar = LazyModule(new IntXbar)
|
||||||
@ -64,7 +64,7 @@ trait HasRocketTiles extends CoreplexRISCVPlatform {
|
|||||||
val fixer = LazyModule(new TLFIFOFixer)
|
val fixer = LazyModule(new TLFIFOFixer)
|
||||||
buffer.node :=* wrapper.masterNode
|
buffer.node :=* wrapper.masterNode
|
||||||
fixer.node :=* buffer.node
|
fixer.node :=* buffer.node
|
||||||
l1tol2.node :=* fixer.node
|
tile_splitter.node :=* fixer.node
|
||||||
wrapper.slaveNode :*= cbus.node
|
wrapper.slaveNode :*= cbus.node
|
||||||
wrapper.asyncIntNode := asyncIntXbar.intnode
|
wrapper.asyncIntNode := asyncIntXbar.intnode
|
||||||
wrapper.periphIntNode := periphIntXbar.intnode
|
wrapper.periphIntNode := periphIntXbar.intnode
|
||||||
@ -82,7 +82,7 @@ trait HasRocketTiles extends CoreplexRISCVPlatform {
|
|||||||
val fixer = LazyModule(new TLFIFOFixer)
|
val fixer = LazyModule(new TLFIFOFixer)
|
||||||
sink.node :=* wrapper.masterNode
|
sink.node :=* wrapper.masterNode
|
||||||
fixer.node :=* sink.node
|
fixer.node :=* sink.node
|
||||||
l1tol2.node :=* fixer.node
|
tile_splitter.node :=* fixer.node
|
||||||
wrapper.slaveNode :*= source.node
|
wrapper.slaveNode :*= source.node
|
||||||
wrapper.asyncIntNode := asyncIntXbar.intnode
|
wrapper.asyncIntNode := asyncIntXbar.intnode
|
||||||
wrapper.periphIntNode := periphIntXbar.intnode
|
wrapper.periphIntNode := periphIntXbar.intnode
|
||||||
@ -102,7 +102,7 @@ trait HasRocketTiles extends CoreplexRISCVPlatform {
|
|||||||
val fixer = LazyModule(new TLFIFOFixer)
|
val fixer = LazyModule(new TLFIFOFixer)
|
||||||
sink.node :=* wrapper.masterNode
|
sink.node :=* wrapper.masterNode
|
||||||
fixer.node :=* sink.node
|
fixer.node :=* sink.node
|
||||||
l1tol2.node :=* fixer.node
|
tile_splitter.node :=* fixer.node
|
||||||
wrapper.slaveNode :*= source.node
|
wrapper.slaveNode :*= source.node
|
||||||
wrapper.asyncIntNode := asyncIntXbar.intnode
|
wrapper.asyncIntNode := asyncIntXbar.intnode
|
||||||
wrapper.periphIntNode := periphIntXbar.intnode
|
wrapper.periphIntNode := periphIntXbar.intnode
|
||||||
|
@ -159,15 +159,13 @@ abstract class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](
|
|||||||
protected[diplomacy] val numPI: Range.Inclusive)
|
protected[diplomacy] val numPI: Range.Inclusive)
|
||||||
extends BaseNode with InwardNode[DI, UI, BI] with OutwardNode[DO, UO, BO]
|
extends BaseNode with InwardNode[DI, UI, BI] with OutwardNode[DO, UO, BO]
|
||||||
{
|
{
|
||||||
protected[diplomacy] def resolveStarO(i: Int, o: Int): Int
|
protected[diplomacy] def resolveStar(iKnown: Int, oKnown: Int, iStar: Int, oStar: Int): (Int, Int)
|
||||||
protected[diplomacy] def resolveStarI(i: Int, o: Int): Int
|
|
||||||
protected[diplomacy] def mapParamsD(n: Int, p: Seq[DI]): Seq[DO]
|
protected[diplomacy] def mapParamsD(n: Int, p: Seq[DI]): Seq[DO]
|
||||||
protected[diplomacy] def mapParamsU(n: Int, p: Seq[UO]): Seq[UI]
|
protected[diplomacy] def mapParamsU(n: Int, p: Seq[UO]): Seq[UI]
|
||||||
|
|
||||||
protected[diplomacy] lazy val (oPortMapping, iPortMapping, oStar, iStar) = {
|
protected[diplomacy] lazy val (oPortMapping, iPortMapping, oStar, iStar) = {
|
||||||
val oStars = oBindings.filter { case (_,_,b) => b == BIND_STAR }.size
|
val oStars = oBindings.filter { case (_,_,b) => b == BIND_STAR }.size
|
||||||
val iStars = iBindings.filter { case (_,_,b) => b == BIND_STAR }.size
|
val iStars = iBindings.filter { case (_,_,b) => b == BIND_STAR }.size
|
||||||
require (oStars + iStars <= 1, s"${name} appears beside a :*= ${iStars} times and a :=* ${oStars} times; at most once is allowed${lazyModule.line}")
|
|
||||||
val oKnown = oBindings.map { case (_, n, b) => b match {
|
val oKnown = oBindings.map { case (_, n, b) => b match {
|
||||||
case BIND_ONCE => 1
|
case BIND_ONCE => 1
|
||||||
case BIND_QUERY => n.iStar
|
case BIND_QUERY => n.iStar
|
||||||
@ -176,8 +174,7 @@ abstract class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](
|
|||||||
case BIND_ONCE => 1
|
case BIND_ONCE => 1
|
||||||
case BIND_QUERY => n.oStar
|
case BIND_QUERY => n.oStar
|
||||||
case BIND_STAR => 0 }}.foldLeft(0)(_+_)
|
case BIND_STAR => 0 }}.foldLeft(0)(_+_)
|
||||||
val oStar = if (oStars > 0) resolveStarO(iKnown, oKnown) else 0
|
val (iStar, oStar) = resolveStar(iKnown, oKnown, iStars, oStars)
|
||||||
val iStar = if (iStars > 0) resolveStarI(iKnown, oKnown) else 0
|
|
||||||
val oSum = oBindings.map { case (_, n, b) => b match {
|
val oSum = oBindings.map { case (_, n, b) => b match {
|
||||||
case BIND_ONCE => 1
|
case BIND_ONCE => 1
|
||||||
case BIND_QUERY => n.iStar
|
case BIND_QUERY => n.iStar
|
||||||
@ -274,6 +271,23 @@ abstract class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](
|
|||||||
protected[diplomacy] def inputs = iPorts.map(_._2) zip edgesIn .map(e => inner.labelI(e))
|
protected[diplomacy] def inputs = iPorts.map(_._2) zip edgesIn .map(e => inner.labelI(e))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract class MixedCustomNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](
|
||||||
|
inner: InwardNodeImp [DI, UI, EI, BI],
|
||||||
|
outer: OutwardNodeImp[DO, UO, EO, BO])(
|
||||||
|
numPO: Range.Inclusive,
|
||||||
|
numPI: Range.Inclusive)
|
||||||
|
extends MixedNode(inner, outer)(numPO, numPI)
|
||||||
|
{
|
||||||
|
def resolveStar(iKnown: Int, oKnown: Int, iStars: Int, oStars: Int): (Int, Int)
|
||||||
|
def mapParamsD(n: Int, p: Seq[DI]): Seq[DO]
|
||||||
|
def mapParamsU(n: Int, p: Seq[UO]): Seq[UI]
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class CustomNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])(
|
||||||
|
numPO: Range.Inclusive,
|
||||||
|
numPI: Range.Inclusive)
|
||||||
|
extends MixedCustomNode(imp, imp)(numPO, numPI)
|
||||||
|
|
||||||
class MixedAdapterNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](
|
class MixedAdapterNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](
|
||||||
inner: InwardNodeImp [DI, UI, EI, BI],
|
inner: InwardNodeImp [DI, UI, EI, BI],
|
||||||
outer: OutwardNodeImp[DO, UO, EO, BO])(
|
outer: OutwardNodeImp[DO, UO, EO, BO])(
|
||||||
@ -285,13 +299,15 @@ class MixedAdapterNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](
|
|||||||
val externalIn: Boolean = true
|
val externalIn: Boolean = true
|
||||||
val externalOut: Boolean = true
|
val externalOut: Boolean = true
|
||||||
|
|
||||||
protected[diplomacy] def resolveStarO(i: Int, o: Int): Int = {
|
protected[diplomacy] def resolveStar(iKnown: Int, oKnown: Int, iStars: Int, oStars: Int): (Int, Int) = {
|
||||||
require (i >= o, s"${name} has ${o} outputs and ${i} inputs; cannot assign ${i-o} edges to resolve :=*${lazyModule.line}")
|
require (oStars + iStars <= 1, s"${name} (an adapter) appears left of a :*= ${iStars} times and right of a :=* ${oStars} times; at most once is allowed${lazyModule.line}")
|
||||||
i - o
|
if (oStars > 0) {
|
||||||
}
|
require (iKnown >= oKnown, s"${name} (an adapter) has ${oKnown} outputs and ${iKnown} inputs; cannot assign ${iKnown-oKnown} edges to resolve :=*${lazyModule.line}")
|
||||||
protected[diplomacy] def resolveStarI(i: Int, o: Int): Int = {
|
(0, iKnown - oKnown)
|
||||||
require (o >= i, s"${name} has ${o} outputs and ${i} inputs; cannot assign ${o-i} edges to resolve :*=${lazyModule.line}")
|
} else {
|
||||||
o - i
|
require (oKnown >= iKnown, s"${name} (an adapter) has ${oKnown} outputs and ${iKnown} inputs; cannot assign ${oKnown-iKnown} edges to resolve :*=${lazyModule.line}")
|
||||||
|
(oKnown - iKnown, 0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
protected[diplomacy] def mapParamsD(n: Int, p: Seq[DI]): Seq[DO] = {
|
protected[diplomacy] def mapParamsD(n: Int, p: Seq[DI]): Seq[DO] = {
|
||||||
require(n == p.size, s"${name} has ${p.size} inputs and ${n} outputs; they must match${lazyModule.line}")
|
require(n == p.size, s"${name} has ${p.size} inputs and ${n} outputs; they must match${lazyModule.line}")
|
||||||
@ -318,13 +334,10 @@ class MixedNexusNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](
|
|||||||
val externalIn: Boolean = true
|
val externalIn: Boolean = true
|
||||||
val externalOut: Boolean = true
|
val externalOut: Boolean = true
|
||||||
|
|
||||||
protected[diplomacy] def resolveStarO(i: Int, o: Int): Int = {
|
protected[diplomacy] def resolveStar(iKnown: Int, oKnown: Int, iStars: Int, oStars: Int): (Int, Int) = {
|
||||||
require (false, "${name} cannot resolve :=*${lazyModule.line}")
|
require (iStars == 0, s"${name} (a nexus) appears left of :*= (perhaps you should flip the '*' to :=*?)${lazyModule.line}")
|
||||||
0
|
require (oStars == 0, s"${name} (a nexus) appears right of a :=* (perhaps you should flip the '*' to :*=?)${lazyModule.line}")
|
||||||
}
|
(0, 0)
|
||||||
protected[diplomacy] def resolveStarI(i: Int, o: Int): Int = {
|
|
||||||
require (false, s"${name} cannot resolve :*=${lazyModule.line}")
|
|
||||||
0
|
|
||||||
}
|
}
|
||||||
protected[diplomacy] def mapParamsD(n: Int, p: Seq[DI]): Seq[DO] = Seq.fill(n) { dFn(p) }
|
protected[diplomacy] def mapParamsD(n: Int, p: Seq[DI]): Seq[DO] = Seq.fill(n) { dFn(p) }
|
||||||
protected[diplomacy] def mapParamsU(n: Int, p: Seq[UO]): Seq[UI] = Seq.fill(n) { uFn(p) }
|
protected[diplomacy] def mapParamsU(n: Int, p: Seq[UO]): Seq[UI] = Seq.fill(n) { uFn(p) }
|
||||||
@ -343,6 +356,45 @@ class NexusNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])(
|
|||||||
numPI: Range.Inclusive = 1 to 999)
|
numPI: Range.Inclusive = 1 to 999)
|
||||||
extends MixedNexusNode[D, U, EI, B, D, U, EO, B](imp, imp)(dFn, uFn, numPO, numPI)
|
extends MixedNexusNode[D, U, EI, B, D, U, EO, B](imp, imp)(dFn, uFn, numPO, numPI)
|
||||||
|
|
||||||
|
case class SplitterArg[T](newSize: Int, ports: Seq[T])
|
||||||
|
class MixedSplitterNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](
|
||||||
|
inner: InwardNodeImp [DI, UI, EI, BI],
|
||||||
|
outer: OutwardNodeImp[DO, UO, EO, BO])(
|
||||||
|
dFn: SplitterArg[DI] => Seq[DO],
|
||||||
|
uFn: SplitterArg[UO] => Seq[UI],
|
||||||
|
numPO: Range.Inclusive = 1 to 999,
|
||||||
|
numPI: Range.Inclusive = 1 to 999)
|
||||||
|
extends MixedNode(inner, outer)(numPO, numPI)
|
||||||
|
{
|
||||||
|
override val externalIn: Boolean = true
|
||||||
|
override val externalOut: Boolean = true
|
||||||
|
|
||||||
|
protected[diplomacy] def resolveStar(iKnown: Int, oKnown: Int, iStars: Int, oStars: Int): (Int, Int) = {
|
||||||
|
require (oKnown == 0, s"${name} (a splitter) appears right of a := or :*=; use a :=* instead${lazyModule.line}")
|
||||||
|
require (iStars == 0, s"${name} (a splitter) cannot appear left of a :*=; did you mean :=*?${lazyModule.line}")
|
||||||
|
(0, iKnown)
|
||||||
|
}
|
||||||
|
protected[diplomacy] def mapParamsD(n: Int, p: Seq[DI]): Seq[DO] = {
|
||||||
|
require (p.size == 0 || n % p.size == 0, s"Diplomacy bug; splitter inputs do not divide outputs")
|
||||||
|
val out = dFn(SplitterArg(n, p))
|
||||||
|
require (out.size == n, s"${name} created the wrong number of outputs from inputs${lazyModule.line}")
|
||||||
|
out
|
||||||
|
}
|
||||||
|
protected[diplomacy] def mapParamsU(n: Int, p: Seq[UO]): Seq[UI] = {
|
||||||
|
require (n == 0 || p.size % n == 0, s"Diplomacy bug; splitter outputs indivisable by inputs")
|
||||||
|
val out = uFn(SplitterArg(n, p))
|
||||||
|
require (out.size == n, s"${name} created the wrong number of inputs from outputs${lazyModule.line}")
|
||||||
|
out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SplitterNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])(
|
||||||
|
dFn: SplitterArg[D] => Seq[D],
|
||||||
|
uFn: SplitterArg[U] => Seq[U],
|
||||||
|
numPO: Range.Inclusive = 1 to 999,
|
||||||
|
numPI: Range.Inclusive = 1 to 999)
|
||||||
|
extends MixedSplitterNode[D, U, EI, B, D, U, EO, B](imp, imp)(dFn, uFn, numPO, numPI)
|
||||||
|
|
||||||
class IdentityNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])
|
class IdentityNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])
|
||||||
extends AdapterNode(imp)({s => s}, {s => s})
|
extends AdapterNode(imp)({s => s}, {s => s})
|
||||||
|
|
||||||
@ -367,13 +419,12 @@ class SourceNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])(po: Seq
|
|||||||
override val externalIn: Boolean = false
|
override val externalIn: Boolean = false
|
||||||
override val externalOut: Boolean = true
|
override val externalOut: Boolean = true
|
||||||
|
|
||||||
protected[diplomacy] def resolveStarO(i: Int, o: Int): Int = {
|
protected[diplomacy] def resolveStar(iKnown: Int, oKnown: Int, iStars: Int, oStars: Int): (Int, Int) = {
|
||||||
require (po.size >= o, s"${name} has ${o} outputs out of ${po.size}; cannot assign ${po.size - o} edges to resolve :=*${lazyModule.line}")
|
require (oStars <= 1, s"${name} (a source) appears right of a :=* ${oStars} times; at most once is allowed${lazyModule.line}")
|
||||||
po.size - o
|
require (iStars == 0, s"${name} (a source) cannot appear left of a :*=${lazyModule.line}")
|
||||||
}
|
require (iKnown == 0, s"${name} (a source) cannot appear left of a :=${lazyModule.line}")
|
||||||
protected[diplomacy] def resolveStarI(i: Int, o: Int): Int = {
|
require (po.size >= oKnown, s"${name} (a source) has ${oKnown} outputs out of ${po.size}; cannot assign ${po.size - oKnown} edges to resolve :=*${lazyModule.line}")
|
||||||
require (false, s"${name} cannot resolve :*=${lazyModule.line}")
|
(0, po.size - oKnown)
|
||||||
0
|
|
||||||
}
|
}
|
||||||
protected[diplomacy] def mapParamsD(n: Int, p: Seq[D]): Seq[D] = po
|
protected[diplomacy] def mapParamsD(n: Int, p: Seq[D]): Seq[D] = po
|
||||||
protected[diplomacy] def mapParamsU(n: Int, p: Seq[U]): Seq[U] = Seq()
|
protected[diplomacy] def mapParamsU(n: Int, p: Seq[U]): Seq[U] = Seq()
|
||||||
@ -387,13 +438,12 @@ class SinkNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])(pi: Seq[U
|
|||||||
override val externalIn: Boolean = true
|
override val externalIn: Boolean = true
|
||||||
override val externalOut: Boolean = false
|
override val externalOut: Boolean = false
|
||||||
|
|
||||||
protected[diplomacy] def resolveStarO(i: Int, o: Int): Int = {
|
protected[diplomacy] def resolveStar(iKnown: Int, oKnown: Int, iStars: Int, oStars: Int): (Int, Int) = {
|
||||||
require (false, s"${name} cannot resolve :=*${lazyModule.line}")
|
require (iStars <= 1, s"${name} (a sink) appears left of a :*= ${iStars} times; at most once is allowed${lazyModule.line}")
|
||||||
0
|
require (oStars == 0, s"${name} (a sink) cannot appear right of a :=*${lazyModule.line}")
|
||||||
}
|
require (oKnown == 0, s"${name} (a sink) cannot appear right of a :=${lazyModule.line}")
|
||||||
protected[diplomacy] def resolveStarI(i: Int, o: Int): Int = {
|
require (pi.size >= iKnown, s"${name} (a sink) has ${iKnown} inputs out of ${pi.size}; cannot assign ${pi.size - iKnown} edges to resolve :*=${lazyModule.line}")
|
||||||
require (pi.size >= i, s"${name} has ${i} inputs out of ${pi.size}; cannot assign ${pi.size - i} edges to resolve :*=${lazyModule.line}")
|
(pi.size - iKnown, 0)
|
||||||
pi.size - i
|
|
||||||
}
|
}
|
||||||
protected[diplomacy] def mapParamsD(n: Int, p: Seq[D]): Seq[D] = Seq()
|
protected[diplomacy] def mapParamsD(n: Int, p: Seq[D]): Seq[D] = Seq()
|
||||||
protected[diplomacy] def mapParamsU(n: Int, p: Seq[U]): Seq[U] = pi
|
protected[diplomacy] def mapParamsU(n: Int, p: Seq[U]): Seq[U] = pi
|
||||||
|
@ -24,7 +24,7 @@ class GroundTestCoreplex(implicit p: Parameters) extends BaseCoreplex {
|
|||||||
case TileId => i
|
case TileId => i
|
||||||
case CacheBlockOffsetBits => log2Up(site(CacheBlockBytes))
|
case CacheBlockOffsetBits => log2Up(site(CacheBlockBytes))
|
||||||
case AmoAluOperandBits => site(XLen)
|
case AmoAluOperandBits => site(XLen)
|
||||||
case SharedMemoryTLEdge => l1tol2.node.edgesIn(0)
|
case SharedMemoryTLEdge => tile_splitter.node.edgesIn(0)
|
||||||
case TLId => "L1toL2"
|
case TLId => "L1toL2"
|
||||||
case TLKey("L1toL2") =>
|
case TLKey("L1toL2") =>
|
||||||
TileLinkParameters(
|
TileLinkParameters(
|
||||||
@ -41,7 +41,7 @@ class GroundTestCoreplex(implicit p: Parameters) extends BaseCoreplex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val fixer = LazyModule(new TLFIFOFixer)
|
val fixer = LazyModule(new TLFIFOFixer)
|
||||||
l1tol2.node :=* fixer.node
|
tile_splitter.node :=* fixer.node
|
||||||
tiles.foreach { fixer.node :=* _.masterNode }
|
tiles.foreach { fixer.node :=* _.masterNode }
|
||||||
|
|
||||||
val cbusRAM = LazyModule(new TLRAM(AddressSet(testRamAddr, 0xffff), false, cbus_beatBytes))
|
val cbusRAM = LazyModule(new TLRAM(AddressSet(testRamAddr, 0xffff), false, cbus_beatBytes))
|
||||||
|
73
src/main/scala/uncore/tilelink2/NodeNumberer.scala
Normal file
73
src/main/scala/uncore/tilelink2/NodeNumberer.scala
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
|
package uncore.tilelink2
|
||||||
|
|
||||||
|
import Chisel._
|
||||||
|
import chisel3.internal.sourceinfo.SourceInfo
|
||||||
|
import config._
|
||||||
|
import diplomacy._
|
||||||
|
|
||||||
|
case class TLNodeNumbererNode(nodeAddressOffset: Option[Int] = None) extends TLCustomNode(0 to 999, 0 to 999)
|
||||||
|
{
|
||||||
|
val externalIn = true
|
||||||
|
val externalOut = true
|
||||||
|
|
||||||
|
def resolveStar(iKnown: Int, oKnown: Int, iStars: Int, oStars: Int): (Int, Int) = {
|
||||||
|
require (oStars + iStars <= 1, s"${name} (a custom adapter) appears left of a :*= ${iStars} times and right of a :=* ${oStars} times; at most once is allowed${lazyModule.line}")
|
||||||
|
if (oStars > 0) {
|
||||||
|
require (iKnown >= oKnown, s"${name} (a custom adapter) has ${oKnown} outputs and ${iKnown} inputs; cannot assign ${iKnown-oKnown} edges to resolve :=*${lazyModule.line}")
|
||||||
|
(0, iKnown - oKnown)
|
||||||
|
} else {
|
||||||
|
require (oKnown >= iKnown, s"${name} (a custom adapter) has ${oKnown} outputs and ${iKnown} inputs; cannot assign ${oKnown-iKnown} edges to resolve :*=${lazyModule.line}")
|
||||||
|
(oKnown - iKnown, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def mapParamsD(n: Int, p: Seq[TLClientPortParameters]): Seq[TLClientPortParameters] = {
|
||||||
|
require(n == p.size, s"${name} has ${p.size} inputs and ${n} outputs; they must match${lazyModule.line}")
|
||||||
|
p
|
||||||
|
}
|
||||||
|
|
||||||
|
def mapParamsU(n: Int, p: Seq[TLManagerPortParameters]): Seq[TLManagerPortParameters] = {
|
||||||
|
require(n == p.size, s"${name} has ${n} inputs and ${p.size} outputs; they must match${lazyModule.line}")
|
||||||
|
val minNodeOffset = log2Ceil(p.map(_.maxAddress).max)
|
||||||
|
val nodeOffset = nodeAddressOffset.getOrElse(minNodeOffset)
|
||||||
|
require (nodeOffset >= minNodeOffset)
|
||||||
|
|
||||||
|
p.zipWithIndex.map { case (mp, i) =>
|
||||||
|
val nodeIndex = BigInt(i+1) << nodeOffset
|
||||||
|
mp.copy(managers = mp.managers.map(m => m.copy(address = m.address.map(a => a.copy(base = a.base | nodeIndex)))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TLNodeNumberer(nodeAddressOffset: Option[Int] = None)(implicit p: Parameters) extends LazyModule
|
||||||
|
{
|
||||||
|
val node = TLNodeNumbererNode(nodeAddressOffset)
|
||||||
|
|
||||||
|
lazy val module = new LazyModuleImp(this) {
|
||||||
|
val io = new Bundle {
|
||||||
|
val in = node.bundleIn
|
||||||
|
val out = node.bundleOut
|
||||||
|
}
|
||||||
|
|
||||||
|
val minNodeOffset = log2Ceil(node.edgesOut.map(_.manager.maxAddress).max)
|
||||||
|
val nodeOffset = nodeAddressOffset.getOrElse(minNodeOffset)
|
||||||
|
|
||||||
|
(io.in zip io.out).zipWithIndex foreach { case ((in, out), i) =>
|
||||||
|
out <> in
|
||||||
|
// a&c address already get truncated
|
||||||
|
in.b.bits.address := (UInt(i+1) << nodeOffset) | out.b.bits.address
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object TLNodeNumberer
|
||||||
|
{
|
||||||
|
// applied to the TL source node; y.node := TLBuffer(x.node)
|
||||||
|
def apply(nodeAddressOffset: Option[Int] = None)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = {
|
||||||
|
val numberer = LazyModule(new TLNodeNumberer(nodeAddressOffset))
|
||||||
|
numberer.node := x
|
||||||
|
numberer.node
|
||||||
|
}
|
||||||
|
}
|
@ -92,6 +92,18 @@ case class TLNexusNode(
|
|||||||
numManagerPorts: Range.Inclusive = 1 to 999)
|
numManagerPorts: Range.Inclusive = 1 to 999)
|
||||||
extends NexusNode(TLImp)(clientFn, managerFn, numClientPorts, numManagerPorts)
|
extends NexusNode(TLImp)(clientFn, managerFn, numClientPorts, numManagerPorts)
|
||||||
|
|
||||||
|
case class TLSplitterNode(
|
||||||
|
clientFn: SplitterArg[TLClientPortParameters] => Seq[TLClientPortParameters],
|
||||||
|
managerFn: SplitterArg[TLManagerPortParameters] => Seq[TLManagerPortParameters],
|
||||||
|
numClientPorts: Range.Inclusive = 0 to 999,
|
||||||
|
numManagerPorts: Range.Inclusive = 0 to 999)
|
||||||
|
extends SplitterNode(TLImp)(clientFn, managerFn, numClientPorts, numManagerPorts)
|
||||||
|
|
||||||
|
abstract class TLCustomNode(
|
||||||
|
numClientPorts: Range.Inclusive,
|
||||||
|
numManagerPorts: Range.Inclusive)
|
||||||
|
extends CustomNode(TLImp)(numClientPorts, numManagerPorts)
|
||||||
|
|
||||||
// Nodes passed from an inner module
|
// Nodes passed from an inner module
|
||||||
case class TLOutputNode() extends OutputNode(TLImp)
|
case class TLOutputNode() extends OutputNode(TLImp)
|
||||||
case class TLInputNode() extends InputNode(TLImp)
|
case class TLInputNode() extends InputNode(TLImp)
|
||||||
|
118
src/main/scala/uncore/tilelink2/Splitter.scala
Normal file
118
src/main/scala/uncore/tilelink2/Splitter.scala
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
|
package uncore.tilelink2
|
||||||
|
|
||||||
|
import Chisel._
|
||||||
|
import config._
|
||||||
|
import diplomacy._
|
||||||
|
|
||||||
|
class TLSplitter(policy: TLArbiter.Policy = TLArbiter.lowestIndexFirst)(implicit p: Parameters) extends LazyModule
|
||||||
|
{
|
||||||
|
val node = TLSplitterNode(
|
||||||
|
clientFn = { case SplitterArg(newSize, ports) =>
|
||||||
|
if (newSize == 0) Nil else
|
||||||
|
Seq.fill(newSize / ports.size) { ports }.flatten
|
||||||
|
},
|
||||||
|
managerFn = { case SplitterArg(newSize, ports) =>
|
||||||
|
if (newSize == 0) Nil else
|
||||||
|
ports.grouped(newSize).toList.transpose.map { 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,
|
||||||
|
managers = ManagerUnification(seq.zipWithIndex.flatMap { case (port, i) =>
|
||||||
|
require (port.beatBytes == seq(0).beatBytes,
|
||||||
|
s"Splitter data widths don't match: ${port.managers.map(_.name)} has ${port.beatBytes}B vs ${seq(0).managers.map(_.name)} has ${seq(0).beatBytes}B")
|
||||||
|
val fifoIdMapper = fifoIdFactory()
|
||||||
|
port.managers map { manager => manager.copy(
|
||||||
|
fifoId = manager.fifoId.map(fifoIdMapper(_))
|
||||||
|
)}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
lazy val module = new LazyModuleImp(this) {
|
||||||
|
val io = new Bundle {
|
||||||
|
val in = node.bundleIn
|
||||||
|
val out = node.bundleOut
|
||||||
|
}
|
||||||
|
|
||||||
|
def group[T](x: Seq[T]) =
|
||||||
|
if (x.isEmpty) Nil else x.grouped(node.edgesIn.size).toList.transpose
|
||||||
|
|
||||||
|
((node.edgesIn zip io.in) zip (group(node.edgesOut) zip group(io.out))) foreach {
|
||||||
|
case ((edgeIn, io_in), (edgesOut, io_out)) =>
|
||||||
|
|
||||||
|
// Grab the port ID mapping
|
||||||
|
val outputIdRanges = TLXbar.mapOutputIds(edgesOut.map(_.manager))
|
||||||
|
|
||||||
|
// Find a good mask for address decoding
|
||||||
|
val port_addrs = edgesOut.map(_.manager.managers.map(_.address).flatten)
|
||||||
|
val routingMask = AddressDecoder(port_addrs)
|
||||||
|
val route_addrs = port_addrs.map(_.map(_.widen(~routingMask)).distinct)
|
||||||
|
val outputPorts = route_addrs.map(seq => (addr: UInt) => seq.map(_.contains(addr)).reduce(_ || _))
|
||||||
|
|
||||||
|
// We need an intermediate size of bundle with the widest possible identifiers
|
||||||
|
val wide_bundle = TLBundleParameters.union(Seq(io_in.params) ++ io_out.map(_.params))
|
||||||
|
|
||||||
|
// Transform input bundle sources (sinks use global namespace on both sides)
|
||||||
|
val in = Wire(TLBundle(wide_bundle))
|
||||||
|
in.a <> io_in.a
|
||||||
|
io_in.d <> in.d
|
||||||
|
|
||||||
|
if (edgeIn.client.anySupportProbe && edgesOut.exists(_.manager.anySupportAcquireB)) {
|
||||||
|
in.c <> io_in.c
|
||||||
|
in.e <> io_in.e
|
||||||
|
io_in.b <> in.b
|
||||||
|
} else {
|
||||||
|
in.c.valid := Bool(false)
|
||||||
|
in.e.valid := Bool(false)
|
||||||
|
in.b.ready := Bool(false)
|
||||||
|
io_in.c.ready := Bool(true)
|
||||||
|
io_in.e.ready := Bool(true)
|
||||||
|
io_in.b.valid := Bool(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle size = 1 gracefully (Chisel3 empty range is broken)
|
||||||
|
def trim(id: UInt, size: Int) = if (size <= 1) UInt(0) else id(log2Ceil(size)-1, 0)
|
||||||
|
|
||||||
|
// Transform output bundle sinks (sources use global namespace on both sides)
|
||||||
|
val out = Wire(Vec(io_out.size, TLBundle(wide_bundle)))
|
||||||
|
for (i <- 0 until out.size) {
|
||||||
|
val r = outputIdRanges(i)
|
||||||
|
|
||||||
|
io_out(i).a <> out(i).a
|
||||||
|
out(i).d <> io_out(i).d
|
||||||
|
out(i).d.bits.sink := io_out(i).d.bits.sink | UInt(r.map(_.start).getOrElse(0))
|
||||||
|
|
||||||
|
if (edgesOut(i).manager.anySupportAcquireB && edgeIn.client.anySupportProbe) {
|
||||||
|
io_out(i).c <> out(i).c
|
||||||
|
io_out(i).e <> out(i).e
|
||||||
|
out(i).b <> io_out(i).b
|
||||||
|
io_out(i).e.bits.sink := trim(out(i).e.bits.sink, r.map(_.size).getOrElse(0))
|
||||||
|
} else {
|
||||||
|
out(i).c.ready := Bool(false)
|
||||||
|
out(i).e.ready := Bool(false)
|
||||||
|
out(i).b.valid := Bool(false)
|
||||||
|
io_out(i).c.valid := Bool(false)
|
||||||
|
io_out(i).e.valid := Bool(false)
|
||||||
|
io_out(i).b.ready := Bool(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val requestA = Vec(outputPorts.map { o => o(in.a.bits.address) })
|
||||||
|
val requestC = Vec(outputPorts.map { o => o(in.c.bits.address) })
|
||||||
|
val requestE = Vec(outputIdRanges.map { o => o.map(_.contains(in.e.bits.sink)).getOrElse(Bool(false)) })
|
||||||
|
(out.map(_.a) zip TLXbar.fanout(in.a, requestA)) foreach { case (o, i) => o <> i }
|
||||||
|
(out.map(_.c) zip TLXbar.fanout(in.c, requestC)) foreach { case (o, i) => o <> i }
|
||||||
|
(out.map(_.e) zip TLXbar.fanout(in.e, requestE)) foreach { case (o, i) => o <> i }
|
||||||
|
|
||||||
|
val beatsB = Vec((out zip edgesOut) map { case (o, e) => e.numBeats1(o.b.bits) })
|
||||||
|
val beatsD = Vec((out zip edgesOut) map { case (o, e) => e.numBeats1(o.d.bits) })
|
||||||
|
TLArbiter(policy)(in.b, (beatsB zip out.map(_.b)):_*)
|
||||||
|
TLArbiter(policy)(in.d, (beatsD zip out.map(_.d)):_*)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,34 +8,6 @@ import diplomacy._
|
|||||||
|
|
||||||
class TLXbar(policy: TLArbiter.Policy = TLArbiter.roundRobin)(implicit p: Parameters) extends LazyModule
|
class TLXbar(policy: TLArbiter.Policy = TLArbiter.roundRobin)(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(
|
val node = TLNexusNode(
|
||||||
numClientPorts = 1 to 32,
|
numClientPorts = 1 to 32,
|
||||||
numManagerPorts = 1 to 32,
|
numManagerPorts = 1 to 32,
|
||||||
@ -44,7 +16,7 @@ class TLXbar(policy: TLArbiter.Policy = TLArbiter.roundRobin)(implicit p: Parame
|
|||||||
"An unsafe atomic port can not be combined with any other!")
|
"An unsafe atomic port can not be combined with any other!")
|
||||||
seq(0).copy(
|
seq(0).copy(
|
||||||
minLatency = seq.map(_.minLatency).min,
|
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(
|
port.clients map { client => client.copy(
|
||||||
sourceId = client.sourceId.shift(range.start)
|
sourceId = client.sourceId.shift(range.start)
|
||||||
)}
|
)}
|
||||||
@ -52,8 +24,8 @@ class TLXbar(policy: TLArbiter.Policy = TLArbiter.roundRobin)(implicit p: Parame
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
managerFn = { seq =>
|
managerFn = { seq =>
|
||||||
val fifoIdFactory = relabeler()
|
val fifoIdFactory = TLXbar.relabeler()
|
||||||
val outputIdRanges = mapOutputIds(seq)
|
val outputIdRanges = TLXbar.mapOutputIds(seq)
|
||||||
seq(0).copy(
|
seq(0).copy(
|
||||||
minLatency = seq.map(_.minLatency).min,
|
minLatency = seq.map(_.minLatency).min,
|
||||||
endSinkId = outputIdRanges.map(_.map(_.end).getOrElse(0)).max,
|
endSinkId = outputIdRanges.map(_.map(_.end).getOrElse(0)).max,
|
||||||
@ -75,8 +47,8 @@ class TLXbar(policy: TLArbiter.Policy = TLArbiter.roundRobin)(implicit p: Parame
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Grab the port ID mapping
|
// Grab the port ID mapping
|
||||||
val inputIdRanges = mapInputIds(node.edgesIn.map(_.client))
|
val inputIdRanges = TLXbar.mapInputIds(node.edgesIn.map(_.client))
|
||||||
val outputIdRanges = mapOutputIds(node.edgesOut.map(_.manager))
|
val outputIdRanges = TLXbar.mapOutputIds(node.edgesOut.map(_.manager))
|
||||||
|
|
||||||
// Find a good mask for address decoding
|
// Find a good mask for address decoding
|
||||||
val port_addrs = node.edgesOut.map(_.manager.managers.map(_.address).flatten)
|
val port_addrs = node.edgesOut.map(_.manager.managers.map(_.address).flatten)
|
||||||
@ -105,7 +77,7 @@ class TLXbar(policy: TLArbiter.Policy = TLArbiter.roundRobin)(implicit p: Parame
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We need an intermediate size of bundle with the widest possible identifiers
|
// We need an intermediate size of bundle with the widest possible identifiers
|
||||||
val wide_bundle = io.in(0).params.union(io.out(0).params)
|
val wide_bundle = TLBundleParameters.union(io.in.map(_.params) ++ io.out.map(_.params))
|
||||||
|
|
||||||
// Handle size = 1 gracefully (Chisel3 empty range is broken)
|
// Handle size = 1 gracefully (Chisel3 empty range is broken)
|
||||||
def trim(id: UInt, size: Int) = if (size <= 1) UInt(0) else id(log2Ceil(size)-1, 0)
|
def trim(id: UInt, size: Int) = if (size <= 1) UInt(0) else id(log2Ceil(size)-1, 0)
|
||||||
@ -179,23 +151,12 @@ class TLXbar(policy: TLArbiter.Policy = TLArbiter.roundRobin)(implicit p: Parame
|
|||||||
def transpose[T](x: Seq[Seq[T]]) = Seq.tabulate(x(0).size) { i => Seq.tabulate(x.size) { j => x(j)(i) } }
|
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)
|
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
|
// Fanout the input sources to the output sinks
|
||||||
val portsAOI = transpose((in zip requestAIO) map { case (i, r) => fanout(i.a, 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) => fanout(o.b, 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) => fanout(i.c, 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) => fanout(o.d, 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) => fanout(i.e, r) })
|
val portsEOI = transpose((in zip requestEIO) map { case (i, r) => TLXbar.fanout(i.e, r) })
|
||||||
|
|
||||||
// Arbitrate amongst the sources
|
// Arbitrate amongst the sources
|
||||||
for (o <- 0 until out.size) {
|
for (o <- 0 until out.size) {
|
||||||
@ -219,6 +180,48 @@ class TLXbar(policy: TLArbiter.Policy = TLArbiter.roundRobin)(implicit p: Parame
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 */
|
/** Synthesizeable unit tests */
|
||||||
import unittest._
|
import unittest._
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user