1
0

Merge pull request #757 from freechipsproject/isp-port

Inter-System-Port
This commit is contained in:
Henry Cook 2017-06-15 13:07:19 -07:00 committed by GitHub
commit 5368ea60fe
9 changed files with 393 additions and 90 deletions

View File

@ -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

View 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
}

View File

@ -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

View File

@ -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

View File

@ -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))

View 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
}
}

View File

@ -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)

View 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)):_*)
}
}
}

View File

@ -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._