commit
8730887baa
@ -3,7 +3,8 @@
|
|||||||
package uncore.tilelink2
|
package uncore.tilelink2
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import chisel3.util.{Irrevocable, IrrevocableIO}
|
import chisel3.util.{Irrevocable, IrrevocableIO, ReadyValidIO}
|
||||||
|
import util.{AsyncQueueSource, AsyncQueueSink}
|
||||||
|
|
||||||
abstract class GenericParameterizedBundle[T <: Object](val params: T) extends Bundle
|
abstract class GenericParameterizedBundle[T <: Object](val params: T) extends Bundle
|
||||||
{
|
{
|
||||||
@ -190,7 +191,7 @@ object TLBundle
|
|||||||
def apply(params: TLBundleParameters) = new TLBundle(params)
|
def apply(params: TLBundleParameters) = new TLBundle(params)
|
||||||
}
|
}
|
||||||
|
|
||||||
class IrrevocableSnoop[+T <: Data](gen: T) extends Bundle
|
final class IrrevocableSnoop[+T <: Data](gen: T) extends Bundle
|
||||||
{
|
{
|
||||||
val ready = Bool()
|
val ready = Bool()
|
||||||
val valid = Bool()
|
val valid = Bool()
|
||||||
@ -232,3 +233,53 @@ object TLBundleSnoop
|
|||||||
out
|
out
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final class AsyncBundle[T <: Data](val depth: Int, gen: T) extends Bundle
|
||||||
|
{
|
||||||
|
require (isPow2(depth))
|
||||||
|
val ridx = UInt(width = log2Up(depth)+1).flip
|
||||||
|
val widx = UInt(width = log2Up(depth)+1)
|
||||||
|
val mem = Vec(depth, gen)
|
||||||
|
override def cloneType: this.type = new AsyncBundle(depth, gen).asInstanceOf[this.type]
|
||||||
|
}
|
||||||
|
|
||||||
|
object FromAsyncBundle
|
||||||
|
{
|
||||||
|
def apply[T <: Data](x: AsyncBundle[T], sync: Int = 3): IrrevocableIO[T] = {
|
||||||
|
val sink = Module(new AsyncQueueSink(x.mem(0), x.depth, sync))
|
||||||
|
x.ridx := sink.io.ridx
|
||||||
|
sink.io.widx := x.widx
|
||||||
|
sink.io.mem := x.mem
|
||||||
|
val out = Wire(Irrevocable(x.mem(0)))
|
||||||
|
out.valid := sink.io.deq.valid
|
||||||
|
out.bits := sink.io.deq.bits
|
||||||
|
sink.io.deq.ready := out.ready
|
||||||
|
out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object ToAsyncBundle
|
||||||
|
{
|
||||||
|
def apply[T <: Data](x: ReadyValidIO[T], depth: Int = 8, sync: Int = 3): AsyncBundle[T] = {
|
||||||
|
val source = Module(new AsyncQueueSource(x.bits, depth, sync))
|
||||||
|
source.io.enq.valid := x.valid
|
||||||
|
source.io.enq.bits := x.bits
|
||||||
|
x.ready := source.io.enq.ready
|
||||||
|
val out = Wire(new AsyncBundle(depth, x.bits))
|
||||||
|
source.io.ridx := out.ridx
|
||||||
|
out.mem := source.io.mem
|
||||||
|
out.widx := source.io.widx
|
||||||
|
out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TLAsyncBundleBase(params: TLAsyncBundleParameters) extends GenericParameterizedBundle(params)
|
||||||
|
|
||||||
|
class TLAsyncBundle(params: TLAsyncBundleParameters) extends TLAsyncBundleBase(params)
|
||||||
|
{
|
||||||
|
val a = new AsyncBundle(params.depth, new TLBundleA(params.base))
|
||||||
|
val b = new AsyncBundle(params.depth, new TLBundleB(params.base)).flip
|
||||||
|
val c = new AsyncBundle(params.depth, new TLBundleC(params.base))
|
||||||
|
val d = new AsyncBundle(params.depth, new TLBundleD(params.base)).flip
|
||||||
|
val e = new AsyncBundle(params.depth, new TLBundleE(params.base))
|
||||||
|
}
|
||||||
|
@ -6,33 +6,63 @@ import Chisel._
|
|||||||
import chisel3.internal.sourceinfo.SourceInfo
|
import chisel3.internal.sourceinfo.SourceInfo
|
||||||
import util._
|
import util._
|
||||||
|
|
||||||
class TLAsyncCrossing(depth: Int = 8, sync: Int = 3) extends LazyModule
|
class TLAsyncCrossingSource(sync: Int = 3) extends LazyModule
|
||||||
{
|
{
|
||||||
val node = TLIdentityNode()
|
val node = TLAsyncSourceNode()
|
||||||
|
|
||||||
lazy val module = new LazyModuleImp(this) {
|
lazy val module = new LazyModuleImp(this) {
|
||||||
val io = new Bundle {
|
val io = new Bundle {
|
||||||
val in = node.bundleIn
|
val in = node.bundleIn
|
||||||
val in_clock = Clock(INPUT)
|
|
||||||
val in_reset = Bool(INPUT)
|
|
||||||
val out = node.bundleOut
|
val out = node.bundleOut
|
||||||
val out_clock = Clock(INPUT)
|
|
||||||
val out_reset = Bool(INPUT)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transfer all TL2 bundles from/to the same domains
|
|
||||||
((io.in zip io.out) zip (node.edgesIn zip node.edgesOut)) foreach { case ((in, out), (edgeIn, edgeOut)) =>
|
((io.in zip io.out) zip (node.edgesIn zip node.edgesOut)) foreach { case ((in, out), (edgeIn, edgeOut)) =>
|
||||||
out.a <> AsyncIrrevocableCrossing(io.in_clock, io.in_reset, in.a, io.out_clock, io.out_reset, depth, sync)
|
val bce = edgeIn.manager.anySupportAcquire && edgeIn.client.anySupportProbe
|
||||||
in.d <> AsyncIrrevocableCrossing(io.out_clock, io.out_reset, out.d, io.in_clock, io.in_reset, depth, sync)
|
val depth = edgeOut.manager.depth
|
||||||
|
|
||||||
if (edgeOut.manager.anySupportAcquire && edgeOut.client.anySupportProbe) {
|
out.a := ToAsyncBundle(in.a, depth, sync)
|
||||||
in.b <> AsyncIrrevocableCrossing(io.out_clock, io.out_reset, out.b, io.in_clock, io.in_reset, depth, sync)
|
in.d := FromAsyncBundle(out.d, sync)
|
||||||
out.c <> AsyncIrrevocableCrossing(io.in_clock, io.in_reset, in.c, io.out_clock, io.out_reset, depth, sync)
|
|
||||||
out.e <> AsyncIrrevocableCrossing(io.in_clock, io.in_reset, in.e, io.out_clock, io.out_reset, depth, sync)
|
if (bce) {
|
||||||
|
in.b := FromAsyncBundle(out.b, sync)
|
||||||
|
out.c := ToAsyncBundle(in.c, depth, sync)
|
||||||
|
out.e := ToAsyncBundle(in.e, depth, sync)
|
||||||
} else {
|
} else {
|
||||||
in.b.valid := Bool(false)
|
in.b.valid := Bool(false)
|
||||||
in.c.ready := Bool(true)
|
in.c.ready := Bool(true)
|
||||||
in.e.ready := Bool(true)
|
in.e.ready := Bool(true)
|
||||||
|
out.b.ridx := UInt(0)
|
||||||
|
out.c.widx := UInt(0)
|
||||||
|
out.e.widx := UInt(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TLAsyncCrossingSink(depth: Int = 8, sync: Int = 3) extends LazyModule
|
||||||
|
{
|
||||||
|
val node = TLAsyncSinkNode(depth)
|
||||||
|
|
||||||
|
lazy val module = new LazyModuleImp(this) {
|
||||||
|
val io = new Bundle {
|
||||||
|
val in = node.bundleIn
|
||||||
|
val out = node.bundleOut
|
||||||
|
}
|
||||||
|
|
||||||
|
((io.in zip io.out) zip (node.edgesIn zip node.edgesOut)) foreach { case ((in, out), (edgeIn, edgeOut)) =>
|
||||||
|
val bce = edgeOut.manager.anySupportAcquire && edgeOut.client.anySupportProbe
|
||||||
|
|
||||||
|
out.a := FromAsyncBundle(in.a, sync)
|
||||||
|
in.d := ToAsyncBundle(out.d, depth, sync)
|
||||||
|
|
||||||
|
if (bce) {
|
||||||
|
in.b := ToAsyncBundle(out.b, depth, sync)
|
||||||
|
out.c := FromAsyncBundle(in.c, sync)
|
||||||
|
out.e := FromAsyncBundle(in.e, sync)
|
||||||
|
} else {
|
||||||
|
in.b.widx := UInt(0)
|
||||||
|
in.c.ridx := UInt(0)
|
||||||
|
in.e.ridx := UInt(0)
|
||||||
out.b.ready := Bool(true)
|
out.b.ready := Bool(true)
|
||||||
out.c.valid := Bool(false)
|
out.c.valid := Bool(false)
|
||||||
out.e.valid := Bool(false)
|
out.e.valid := Bool(false)
|
||||||
@ -41,6 +71,44 @@ class TLAsyncCrossing(depth: Int = 8, sync: Int = 3) extends LazyModule
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TLAsyncCrossing(depth: Int = 8, sync: Int = 3) extends LazyModule
|
||||||
|
{
|
||||||
|
val nodeIn = TLInputNode()
|
||||||
|
val nodeOut = TLOutputNode()
|
||||||
|
|
||||||
|
val source = LazyModule(new TLAsyncCrossingSource(sync))
|
||||||
|
val sink = LazyModule(new TLAsyncCrossingSink(depth, sync))
|
||||||
|
|
||||||
|
val _ = (sink.node := source.node) // no monitor
|
||||||
|
val in = (source.node := nodeIn)
|
||||||
|
val out = (nodeOut := sink.node)
|
||||||
|
|
||||||
|
lazy val module = new LazyModuleImp(this) {
|
||||||
|
val io = new Bundle {
|
||||||
|
val in = nodeIn.bundleIn
|
||||||
|
val in_clock = Clock(INPUT)
|
||||||
|
val in_reset = Bool(INPUT)
|
||||||
|
val out = nodeOut.bundleOut
|
||||||
|
val out_clock = Clock(INPUT)
|
||||||
|
val out_reset = Bool(INPUT)
|
||||||
|
}
|
||||||
|
|
||||||
|
source.module.clock := io.in_clock
|
||||||
|
source.module.reset := io.in_reset
|
||||||
|
in.foreach { lm =>
|
||||||
|
lm.module.clock := io.in_clock
|
||||||
|
lm.module.reset := io.in_reset
|
||||||
|
}
|
||||||
|
|
||||||
|
sink.module.clock := io.out_clock
|
||||||
|
sink.module.reset := io.out_reset
|
||||||
|
out.foreach { lm =>
|
||||||
|
lm.module.clock := io.out_clock
|
||||||
|
lm.module.reset := io.out_reset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Synthesizeable unit tests */
|
/** Synthesizeable unit tests */
|
||||||
import unittest._
|
import unittest._
|
||||||
|
|
||||||
@ -51,8 +119,8 @@ class TLRAMCrossing extends LazyModule {
|
|||||||
val cross = LazyModule(new TLAsyncCrossing)
|
val cross = LazyModule(new TLAsyncCrossing)
|
||||||
|
|
||||||
model.node := fuzz.node
|
model.node := fuzz.node
|
||||||
cross.node := TLFragmenter(4, 256)(model.node)
|
cross.nodeIn := TLFragmenter(4, 256)(model.node)
|
||||||
val monitor = (ram.node := cross.node)
|
val monitor = (ram.node := cross.nodeOut)
|
||||||
|
|
||||||
lazy val module = new LazyModuleImp(this) with HasUnitTestIO {
|
lazy val module = new LazyModuleImp(this) with HasUnitTestIO {
|
||||||
io.finished := fuzz.module.io.finished
|
io.finished := fuzz.module.io.finished
|
||||||
|
@ -224,8 +224,8 @@ class TLFuzzRAM extends LazyModule
|
|||||||
xbar2.node := TLAtomicAutomata()(model.node)
|
xbar2.node := TLAtomicAutomata()(model.node)
|
||||||
ram2.node := TLFragmenter(16, 256)(xbar2.node)
|
ram2.node := TLFragmenter(16, 256)(xbar2.node)
|
||||||
xbar.node := TLWidthWidget(16)(TLHintHandler()(xbar2.node))
|
xbar.node := TLWidthWidget(16)(TLHintHandler()(xbar2.node))
|
||||||
cross.node := TLFragmenter(4, 256)(TLBuffer()(xbar.node))
|
cross.nodeIn := TLFragmenter(4, 256)(TLBuffer()(xbar.node))
|
||||||
val monitor = (ram.node := cross.node)
|
val monitor = (ram.node := cross.nodeOut)
|
||||||
gpio.node := TLFragmenter(4, 32)(TLBuffer()(xbar.node))
|
gpio.node := TLFragmenter(4, 32)(TLBuffer()(xbar.node))
|
||||||
|
|
||||||
lazy val module = new LazyModuleImp(this) with HasUnitTestIO {
|
lazy val module = new LazyModuleImp(this) with HasUnitTestIO {
|
||||||
|
@ -23,13 +23,13 @@ object IntRange
|
|||||||
|
|
||||||
case class IntSourceParameters(
|
case class IntSourceParameters(
|
||||||
range: IntRange,
|
range: IntRange,
|
||||||
nodePath: Seq[IntBaseNode] = Seq())
|
nodePath: Seq[BaseNode] = Seq())
|
||||||
{
|
{
|
||||||
val name = nodePath.lastOption.map(_.lazyModule.name).getOrElse("disconnected")
|
val name = nodePath.lastOption.map(_.lazyModule.name).getOrElse("disconnected")
|
||||||
}
|
}
|
||||||
|
|
||||||
case class IntSinkParameters(
|
case class IntSinkParameters(
|
||||||
nodePath: Seq[IntBaseNode] = Seq())
|
nodePath: Seq[BaseNode] = Seq())
|
||||||
{
|
{
|
||||||
val name = nodePath.lastOption.map(_.lazyModule.name).getOrElse("disconnected")
|
val name = nodePath.lastOption.map(_.lazyModule.name).getOrElse("disconnected")
|
||||||
}
|
}
|
||||||
@ -49,8 +49,8 @@ case class IntEdge(source: IntSourcePortParameters, sink: IntSinkPortParameters)
|
|||||||
|
|
||||||
object IntImp extends NodeImp[IntSourcePortParameters, IntSinkPortParameters, IntEdge, IntEdge, Vec[Bool]]
|
object IntImp extends NodeImp[IntSourcePortParameters, IntSinkPortParameters, IntEdge, IntEdge, Vec[Bool]]
|
||||||
{
|
{
|
||||||
def edgeO(po: IntSourcePortParameters, pi: IntSinkPortParameters): IntEdge = IntEdge(po, pi)
|
def edgeO(pd: IntSourcePortParameters, pu: IntSinkPortParameters): IntEdge = IntEdge(pd, pu)
|
||||||
def edgeI(po: IntSourcePortParameters, pi: IntSinkPortParameters): IntEdge = IntEdge(po, pi)
|
def edgeI(pd: IntSourcePortParameters, pu: IntSinkPortParameters): IntEdge = IntEdge(pd, pu)
|
||||||
def bundleO(eo: Seq[IntEdge]): Vec[Vec[Bool]] = {
|
def bundleO(eo: Seq[IntEdge]): Vec[Vec[Bool]] = {
|
||||||
if (eo.isEmpty) Vec(0, Vec(0, Bool())) else
|
if (eo.isEmpty) Vec(0, Vec(0, Bool())) else
|
||||||
Vec(eo.size, Vec(eo.map(_.source.num).max, Bool()))
|
Vec(eo.size, Vec(eo.map(_.source.num).max, Bool()))
|
||||||
@ -60,18 +60,17 @@ object IntImp extends NodeImp[IntSourcePortParameters, IntSinkPortParameters, In
|
|||||||
Vec(ei.size, Vec(ei.map(_.source.num).max, Bool())).flip
|
Vec(ei.size, Vec(ei.map(_.source.num).max, Bool())).flip
|
||||||
}
|
}
|
||||||
|
|
||||||
def connect(bo: => Vec[Bool], eo: => IntEdge, bi: => Vec[Bool], ei: => IntEdge)(implicit sourceInfo: SourceInfo): (Option[LazyModule], () => Unit) = {
|
def connect(bo: => Vec[Bool], bi: => Vec[Bool], ei: => IntEdge)(implicit sourceInfo: SourceInfo): (Option[LazyModule], () => Unit) = {
|
||||||
(None, () => {
|
(None, () => {
|
||||||
require (eo == ei)
|
|
||||||
// Cannot use bulk connect, because the widths could differ
|
// Cannot use bulk connect, because the widths could differ
|
||||||
(bo zip bi) foreach { case (o, i) => i := o }
|
(bo zip bi) foreach { case (o, i) => i := o }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
override def mixO(po: IntSourcePortParameters, node: IntBaseNode): IntSourcePortParameters =
|
override def mixO(pd: IntSourcePortParameters, node: OutwardNode[IntSourcePortParameters, IntSinkPortParameters, Vec[Bool]]): IntSourcePortParameters =
|
||||||
po.copy(sources = po.sources.map { s => s.copy (nodePath = node +: s.nodePath) })
|
pd.copy(sources = pd.sources.map { s => s.copy (nodePath = node +: s.nodePath) })
|
||||||
override def mixI(pi: IntSinkPortParameters, node: IntBaseNode): IntSinkPortParameters =
|
override def mixI(pu: IntSinkPortParameters, node: InwardNode[IntSourcePortParameters, IntSinkPortParameters, Vec[Bool]]): IntSinkPortParameters =
|
||||||
pi.copy(sinks = pi.sinks.map { s => s.copy (nodePath = node +: s.nodePath) })
|
pu.copy(sinks = pu.sinks.map { s => s.copy (nodePath = node +: s.nodePath) })
|
||||||
}
|
}
|
||||||
|
|
||||||
case class IntIdentityNode() extends IdentityNode(IntImp)
|
case class IntIdentityNode() extends IdentityNode(IntImp)
|
||||||
|
@ -9,18 +9,13 @@ abstract class LazyModule
|
|||||||
{
|
{
|
||||||
protected[tilelink2] var bindings = List[() => Unit]()
|
protected[tilelink2] var bindings = List[() => Unit]()
|
||||||
protected[tilelink2] var children = List[LazyModule]()
|
protected[tilelink2] var children = List[LazyModule]()
|
||||||
protected[tilelink2] var nodes = List[RootNode]()
|
protected[tilelink2] var nodes = List[BaseNode]()
|
||||||
protected[tilelink2] var info: SourceInfo = UnlocatableSourceInfo
|
protected[tilelink2] var info: SourceInfo = UnlocatableSourceInfo
|
||||||
protected[tilelink2] val parent = LazyModule.stack.headOption
|
protected[tilelink2] val parent = LazyModule.stack.headOption
|
||||||
|
|
||||||
LazyModule.stack = this :: LazyModule.stack
|
LazyModule.stack = this :: LazyModule.stack
|
||||||
parent.foreach(p => p.children = this :: p.children)
|
parent.foreach(p => p.children = this :: p.children)
|
||||||
|
|
||||||
// Use as: connect(source -> sink, source2 -> sink2, ...)
|
|
||||||
def connect[PO, PI, EO, EI, B <: Data](edges: (BaseNode[PO, PI, EO, EI, B], BaseNode[PO, PI, EO, EI, B])*)(implicit sourceInfo: SourceInfo) = {
|
|
||||||
edges.foreach { case (source, sink) => sink := source }
|
|
||||||
}
|
|
||||||
|
|
||||||
def name = getClass.getName.split('.').last
|
def name = getClass.getName.split('.').last
|
||||||
def line = sourceLine(info)
|
def line = sourceLine(info)
|
||||||
|
|
||||||
|
@ -6,23 +6,33 @@ import Chisel._
|
|||||||
import scala.collection.mutable.ListBuffer
|
import scala.collection.mutable.ListBuffer
|
||||||
import chisel3.internal.sourceinfo.SourceInfo
|
import chisel3.internal.sourceinfo.SourceInfo
|
||||||
|
|
||||||
// PI = PortInputParameters
|
// DI = Downwards flowing Parameters received on the inner side of the node
|
||||||
// PO = PortOutputParameters
|
// UI = Upwards flowing Parameters generated by the inner side of the node
|
||||||
// EI = EdgeInput
|
// EI = Edge Parameters describing a connection on the inner side of the node
|
||||||
// EO = EdgeOutput
|
// BI = Bundle type used when connecting to the inner side of the node
|
||||||
abstract class NodeImp[PO, PI, EO, EI, B <: Data]
|
trait InwardNodeImp[DI, UI, EI, BI <: Data]
|
||||||
{
|
{
|
||||||
def edgeO(po: PO, pi: PI): EO
|
def edgeI(pd: DI, pu: UI): EI
|
||||||
def edgeI(po: PO, pi: PI): EI
|
def bundleI(ei: Seq[EI]): Vec[BI]
|
||||||
def bundleO(eo: Seq[EO]): Vec[B]
|
def mixI(pu: UI, node: InwardNode[DI, UI, BI]): UI = pu
|
||||||
def bundleI(ei: Seq[EI]): Vec[B]
|
def connect(bo: => BI, bi: => BI, e: => EI)(implicit sourceInfo: SourceInfo): (Option[LazyModule], () => Unit)
|
||||||
def connect(bo: => B, eo: => EO, bi: => B, ei: => EI)(implicit sourceInfo: SourceInfo): (Option[LazyModule], () => Unit)
|
|
||||||
// If you want to track parameters as they flow through nodes, overload these:
|
|
||||||
def mixO(po: PO, node: BaseNode[PO, PI, EO, EI, B]): PO = po
|
|
||||||
def mixI(pi: PI, node: BaseNode[PO, PI, EO, EI, B]): PI = pi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class RootNode
|
// DO = Downwards flowing Parameters generated by the outner side of the node
|
||||||
|
// UO = Upwards flowing Parameters received on the outner side of the node
|
||||||
|
// EO = Edge Parameters describing a connection on the outer side of the node
|
||||||
|
// BO = Bundle type used when connecting to the outer side of the node
|
||||||
|
trait OutwardNodeImp[DO, UO, EO, BO <: Data]
|
||||||
|
{
|
||||||
|
def edgeO(pd: DO, pu: UO): EO
|
||||||
|
def bundleO(eo: Seq[EO]): Vec[BO]
|
||||||
|
def mixO(pd: DO, node: OutwardNode[DO, UO, BO]): DO = pd
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class NodeImp[D, U, EO, EI, B <: Data]
|
||||||
|
extends Object with InwardNodeImp[D, U, EI, B] with OutwardNodeImp[D, U, EO, B]
|
||||||
|
|
||||||
|
abstract class BaseNode
|
||||||
{
|
{
|
||||||
// You cannot create a Node outside a LazyModule!
|
// You cannot create a Node outside a LazyModule!
|
||||||
require (!LazyModule.stack.isEmpty)
|
require (!LazyModule.stack.isEmpty)
|
||||||
@ -35,108 +45,146 @@ abstract class RootNode
|
|||||||
def colour = "blue"
|
def colour = "blue"
|
||||||
def omitGraphML = outputs.isEmpty && inputs.isEmpty
|
def omitGraphML = outputs.isEmpty && inputs.isEmpty
|
||||||
|
|
||||||
protected[tilelink2] def outputs: Seq[RootNode]
|
protected[tilelink2] def outputs: Seq[BaseNode]
|
||||||
protected[tilelink2] def inputs: Seq[RootNode]
|
protected[tilelink2] def inputs: Seq[BaseNode]
|
||||||
}
|
}
|
||||||
|
|
||||||
class BaseNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])(
|
trait InwardNode[DI, UI, BI <: Data] extends BaseNode
|
||||||
private val oFn: (Int, Seq[PO]) => Seq[PO],
|
|
||||||
private val iFn: (Int, Seq[PI]) => Seq[PI],
|
|
||||||
private val numPO: Range.Inclusive,
|
|
||||||
private val numPI: Range.Inclusive) extends RootNode
|
|
||||||
{
|
{
|
||||||
// At least 0 ports must be supported
|
protected[tilelink2] val numPI: Range.Inclusive
|
||||||
require (!numPO.isEmpty, s"No number of outputs would be acceptable to ${name}${lazyModule.line}")
|
|
||||||
require (!numPI.isEmpty, s"No number of inputs would be acceptable to ${name}${lazyModule.line}")
|
require (!numPI.isEmpty, s"No number of inputs would be acceptable to ${name}${lazyModule.line}")
|
||||||
require (numPO.start >= 0, s"${name} accepts a negative number of outputs${lazyModule.line}")
|
|
||||||
require (numPI.start >= 0, s"${name} accepts a negative number of inputs${lazyModule.line}")
|
require (numPI.start >= 0, s"${name} accepts a negative number of inputs${lazyModule.line}")
|
||||||
|
|
||||||
val noOs = numPO.size == 1 && numPO.contains(0)
|
private val accPI = ListBuffer[(Int, OutwardNode[DI, UI, BI])]()
|
||||||
val noIs = numPI.size == 1 && numPI.contains(0)
|
|
||||||
|
|
||||||
private val accPO = ListBuffer[(Int, BaseNode[PO, PI, EO, EI, B])]()
|
|
||||||
private val accPI = ListBuffer[(Int, BaseNode[PO, PI, EO, EI, B])]()
|
|
||||||
private var oRealized = false
|
|
||||||
private var iRealized = false
|
private var iRealized = false
|
||||||
|
|
||||||
private def reqO() = require(numPO.contains(accPO.size), s"${name} has ${accPO.size} outputs, expected ${numPO}${lazyModule.line}")
|
protected[tilelink2] def iPushed = accPI.size
|
||||||
|
protected[tilelink2] def iPush(index: Int, node: OutwardNode[DI, UI, BI])(implicit sourceInfo: SourceInfo) {
|
||||||
|
val info = sourceLine(sourceInfo, " at ", "")
|
||||||
|
val noIs = numPI.size == 1 && numPI.contains(0)
|
||||||
|
require (!noIs, s"${name}${lazyModule.line} was incorrectly connected as a sink" + info)
|
||||||
|
require (!iRealized, s"${name}${lazyModule.line} was incorrectly connected as a sink after it's .module was used" + info)
|
||||||
|
accPI += ((index, node))
|
||||||
|
}
|
||||||
|
|
||||||
private def reqI() = require(numPI.contains(accPI.size), s"${name} has ${accPI.size} inputs, expected ${numPI}${lazyModule.line}")
|
private def reqI() = require(numPI.contains(accPI.size), s"${name} has ${accPI.size} inputs, expected ${numPI}${lazyModule.line}")
|
||||||
protected def reqE(o: Int, i: Int) = require(i == o, s"${name} has ${i} inputs and ${o} outputs; they must match${lazyModule.line}")
|
protected[tilelink2] lazy val iPorts = { iRealized = true; reqI(); accPI.result() }
|
||||||
|
|
||||||
private lazy val oPorts = { oRealized = true; reqO(); accPO.result() }
|
protected[tilelink2] val iParams: Seq[UI]
|
||||||
private lazy val iPorts = { iRealized = true; reqI(); accPI.result() }
|
protected[tilelink2] def iConnect: Vec[BI]
|
||||||
|
}
|
||||||
|
|
||||||
|
trait OutwardNode[DO, UO, BO <: Data] extends BaseNode
|
||||||
|
{
|
||||||
|
protected[tilelink2] val numPO: Range.Inclusive
|
||||||
|
require (!numPO.isEmpty, s"No number of outputs would be acceptable to ${name}${lazyModule.line}")
|
||||||
|
require (numPO.start >= 0, s"${name} accepts a negative number of outputs${lazyModule.line}")
|
||||||
|
|
||||||
|
private val accPO = ListBuffer[(Int, InwardNode [DO, UO, BO])]()
|
||||||
|
private var oRealized = false
|
||||||
|
|
||||||
|
protected[tilelink2] def oPushed = accPO.size
|
||||||
|
protected[tilelink2] def oPush(index: Int, node: InwardNode [DO, UO, BO])(implicit sourceInfo: SourceInfo) {
|
||||||
|
val info = sourceLine(sourceInfo, " at ", "")
|
||||||
|
val noOs = numPO.size == 1 && numPO.contains(0)
|
||||||
|
require (!noOs, s"${name}${lazyModule.line} was incorrectly connected as a source" + info)
|
||||||
|
require (!oRealized, s"${name}${lazyModule.line} was incorrectly connected as a source after it's .module was used" + info)
|
||||||
|
accPO += ((index, node))
|
||||||
|
}
|
||||||
|
|
||||||
|
private def reqO() = require(numPO.contains(accPO.size), s"${name} has ${accPO.size} outputs, expected ${numPO}${lazyModule.line}")
|
||||||
|
protected[tilelink2] lazy val oPorts = { oRealized = true; reqO(); accPO.result() }
|
||||||
|
|
||||||
|
protected[tilelink2] val oParams: Seq[DO]
|
||||||
|
protected[tilelink2] def oConnect: Vec[BO]
|
||||||
|
}
|
||||||
|
|
||||||
|
class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](
|
||||||
|
inner: InwardNodeImp [DI, UI, EI, BI],
|
||||||
|
outer: OutwardNodeImp[DO, UO, EO, BO])(
|
||||||
|
private val dFn: (Int, Seq[DI]) => Seq[DO],
|
||||||
|
private val uFn: (Int, Seq[UO]) => Seq[UI],
|
||||||
|
protected[tilelink2] val numPO: Range.Inclusive,
|
||||||
|
protected[tilelink2] val numPI: Range.Inclusive)
|
||||||
|
extends BaseNode with InwardNode[DI, UI, BI] with OutwardNode[DO, UO, BO]
|
||||||
|
{
|
||||||
|
// meta-data for printing the node graph
|
||||||
protected[tilelink2] def outputs = oPorts.map(_._2)
|
protected[tilelink2] def outputs = oPorts.map(_._2)
|
||||||
protected[tilelink2] def inputs = iPorts.map(_._2)
|
protected[tilelink2] def inputs = iPorts.map(_._2)
|
||||||
|
|
||||||
private lazy val oParams : Seq[PO] = {
|
private def reqE(o: Int, i: Int) = require(i == o, s"${name} has ${i} inputs and ${o} outputs; they must match${lazyModule.line}")
|
||||||
val o = oFn(oPorts.size, iPorts.map{ case (i, n) => n.oParams(i) })
|
protected[tilelink2] lazy val oParams: Seq[DO] = {
|
||||||
|
val o = dFn(oPorts.size, iPorts.map { case (i, n) => n.oParams(i) })
|
||||||
reqE(oPorts.size, o.size)
|
reqE(oPorts.size, o.size)
|
||||||
o.map(imp.mixO(_, this))
|
o.map(outer.mixO(_, this))
|
||||||
}
|
}
|
||||||
private lazy val iParams : Seq[PI] = {
|
protected[tilelink2] lazy val iParams: Seq[UI] = {
|
||||||
val i = iFn(iPorts.size, oPorts.map{ case (o, n) => n.iParams(o) })
|
val i = uFn(iPorts.size, oPorts.map { case (o, n) => n.iParams(o) })
|
||||||
reqE(i.size, iPorts.size)
|
reqE(i.size, iPorts.size)
|
||||||
i.map(imp.mixI(_, this))
|
i.map(inner.mixI(_, this))
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy val edgesOut = (oPorts zip oParams).map { case ((i, n), o) => imp.edgeO(o, n.iParams(i)) }
|
lazy val edgesOut = (oPorts zip oParams).map { case ((i, n), o) => outer.edgeO(o, n.iParams(i)) }
|
||||||
lazy val edgesIn = (iPorts zip iParams).map { case ((o, n), i) => imp.edgeI(n.oParams(o), i) }
|
lazy val edgesIn = (iPorts zip iParams).map { case ((o, n), i) => inner.edgeI(n.oParams(o), i) }
|
||||||
|
|
||||||
lazy val bundleOut = imp.bundleO(edgesOut)
|
lazy val bundleOut = outer.bundleO(edgesOut)
|
||||||
lazy val bundleIn = imp.bundleI(edgesIn)
|
lazy val bundleIn = inner.bundleI(edgesIn)
|
||||||
|
|
||||||
def connectOut = bundleOut
|
def oConnect = bundleOut
|
||||||
def connectIn = bundleIn
|
def iConnect = bundleIn
|
||||||
|
|
||||||
def := (y: BaseNode[PO, PI, EO, EI, B])(implicit sourceInfo: SourceInfo): Option[LazyModule] = {
|
// connects the outward part of a node with the inward part of this node
|
||||||
|
def := (y: OutwardNode[DI, UI, BI])(implicit sourceInfo: SourceInfo): Option[LazyModule] = {
|
||||||
val x = this // x := y
|
val x = this // x := y
|
||||||
val info = sourceLine(sourceInfo, " at ", "")
|
val info = sourceLine(sourceInfo, " at ", "")
|
||||||
require (!LazyModule.stack.isEmpty, s"${y.name} cannot be connected to ${x.name} outside of LazyModule scope" + info)
|
require (!LazyModule.stack.isEmpty, s"${y.name} cannot be connected to ${x.name} outside of LazyModule scope" + info)
|
||||||
require (!y.noOs, s"${y.name}${y.lazyModule.line} was incorrectly connected as a source" + info)
|
val i = x.iPushed
|
||||||
require (!y.oRealized, s"${y.name}${y.lazyModule.line} was incorrectly connected as a source after it's .module was used" + info)
|
val o = y.oPushed
|
||||||
require (!x.noIs, s"${x.name}${x.lazyModule.line} was incorrectly connected as a sink" + info)
|
y.oPush(i, x)
|
||||||
require (!x.iRealized, s"${x.name}${x.lazyModule.line} was incorrectly connected as a sink after it's .module was used" + info)
|
x.iPush(o, y)
|
||||||
val i = x.accPI.size
|
val (out, binding) = inner.connect(y.oConnect(o), x.iConnect(i), x.edgesIn(i))
|
||||||
val o = y.accPO.size
|
|
||||||
y.accPO += ((i, x))
|
|
||||||
x.accPI += ((o, y))
|
|
||||||
val (out, binding) = imp.connect(y.connectOut(o), y.edgesOut(o), x.connectIn(i), x.edgesIn(i))
|
|
||||||
LazyModule.stack.head.bindings = binding :: LazyModule.stack.head.bindings
|
LazyModule.stack.head.bindings = binding :: LazyModule.stack.head.bindings
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SimpleNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])(
|
||||||
|
oFn: (Int, Seq[D]) => Seq[D],
|
||||||
|
iFn: (Int, Seq[U]) => Seq[U],
|
||||||
|
numPO: Range.Inclusive,
|
||||||
|
numPI: Range.Inclusive)
|
||||||
|
extends MixedNode[D, U, EI, B, D, U, EO, B](imp, imp)(oFn, iFn, numPO, numPI)
|
||||||
|
|
||||||
class IdentityNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])
|
class IdentityNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])
|
||||||
extends BaseNode(imp)({case (_, s) => s}, {case (_, s) => s}, 0 to 999, 0 to 999)
|
extends SimpleNode(imp)({case (_, s) => s}, {case (_, s) => s}, 0 to 999, 0 to 999)
|
||||||
|
|
||||||
class OutputNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B]) extends IdentityNode(imp)
|
class OutputNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B]) extends IdentityNode(imp)
|
||||||
{
|
{
|
||||||
override def connectOut = bundleOut
|
override def oConnect = bundleOut
|
||||||
override def connectIn = bundleOut
|
override def iConnect = bundleOut
|
||||||
}
|
}
|
||||||
|
|
||||||
class InputNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B]) extends IdentityNode(imp)
|
class InputNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B]) extends IdentityNode(imp)
|
||||||
{
|
{
|
||||||
override def connectOut = bundleIn
|
override def oConnect = bundleIn
|
||||||
override def connectIn = bundleIn
|
override def iConnect = bundleIn
|
||||||
}
|
}
|
||||||
|
|
||||||
class SourceNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])(po: PO, num: Range.Inclusive = 1 to 1)
|
class SourceNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])(po: PO, num: Range.Inclusive = 1 to 1)
|
||||||
extends BaseNode(imp)({case (n, Seq()) => Seq.fill(n)(po)}, {case (0, _) => Seq()}, num, 0 to 0)
|
extends SimpleNode(imp)({case (n, Seq()) => Seq.fill(n)(po)}, {case (0, _) => Seq()}, num, 0 to 0)
|
||||||
{
|
{
|
||||||
require (num.end >= 1, s"${name} is a source which does not accept outputs${lazyModule.line}")
|
require (num.end >= 1, s"${name} is a source which does not accept outputs${lazyModule.line}")
|
||||||
}
|
}
|
||||||
|
|
||||||
class SinkNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])(pi: PI, num: Range.Inclusive = 1 to 1)
|
class SinkNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])(pi: PI, num: Range.Inclusive = 1 to 1)
|
||||||
extends BaseNode(imp)({case (0, _) => Seq()}, {case (n, Seq()) => Seq.fill(n)(pi)}, 0 to 0, num)
|
extends SimpleNode(imp)({case (0, _) => Seq()}, {case (n, Seq()) => Seq.fill(n)(pi)}, 0 to 0, num)
|
||||||
{
|
{
|
||||||
require (num.end >= 1, s"${name} is a sink which does not accept inputs${lazyModule.line}")
|
require (num.end >= 1, s"${name} is a sink which does not accept inputs${lazyModule.line}")
|
||||||
}
|
}
|
||||||
|
|
||||||
class InteriorNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])
|
class InteriorNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])
|
||||||
(oFn: Seq[PO] => PO, iFn: Seq[PI] => PI, numPO: Range.Inclusive, numPI: Range.Inclusive)
|
(oFn: Seq[PO] => PO, iFn: Seq[PI] => PI, numPO: Range.Inclusive, numPI: Range.Inclusive)
|
||||||
extends BaseNode(imp)({case (n,s) => Seq.fill(n)(oFn(s))}, {case (n,s) => Seq.fill(n)(iFn(s))}, numPO, numPI)
|
extends SimpleNode(imp)({case (n,s) => Seq.fill(n)(oFn(s))}, {case (n,s) => Seq.fill(n)(iFn(s))}, numPO, numPI)
|
||||||
{
|
{
|
||||||
require (numPO.end >= 1, s"${name} is an adapter which does not accept outputs${lazyModule.line}")
|
require (numPO.end >= 1, s"${name} is an adapter which does not accept outputs${lazyModule.line}")
|
||||||
require (numPI.end >= 1, s"${name} is an adapter which does not accept inputs${lazyModule.line}")
|
require (numPI.end >= 1, s"${name} is an adapter which does not accept inputs${lazyModule.line}")
|
||||||
|
@ -149,7 +149,7 @@ case class TLManagerParameters(
|
|||||||
sinkId: IdRange = IdRange(0, 1),
|
sinkId: IdRange = IdRange(0, 1),
|
||||||
regionType: RegionType.T = RegionType.GET_EFFECTS,
|
regionType: RegionType.T = RegionType.GET_EFFECTS,
|
||||||
executable: Boolean = false, // processor can execute from this memory
|
executable: Boolean = false, // processor can execute from this memory
|
||||||
nodePath: Seq[TLBaseNode] = Seq(),
|
nodePath: Seq[BaseNode] = Seq(),
|
||||||
// Supports both Acquire+Release+Finish of these sizes
|
// Supports both Acquire+Release+Finish of these sizes
|
||||||
supportsAcquire: TransferSizes = TransferSizes.none,
|
supportsAcquire: TransferSizes = TransferSizes.none,
|
||||||
supportsArithmetic: TransferSizes = TransferSizes.none,
|
supportsArithmetic: TransferSizes = TransferSizes.none,
|
||||||
@ -293,7 +293,7 @@ case class TLManagerPortParameters(
|
|||||||
|
|
||||||
case class TLClientParameters(
|
case class TLClientParameters(
|
||||||
sourceId: IdRange = IdRange(0,1),
|
sourceId: IdRange = IdRange(0,1),
|
||||||
nodePath: Seq[TLBaseNode] = Seq(),
|
nodePath: Seq[BaseNode] = Seq(),
|
||||||
// Supports both Probe+Grant of these sizes
|
// Supports both Probe+Grant of these sizes
|
||||||
supportsProbe: TransferSizes = TransferSizes.none,
|
supportsProbe: TransferSizes = TransferSizes.none,
|
||||||
supportsArithmetic: TransferSizes = TransferSizes.none,
|
supportsArithmetic: TransferSizes = TransferSizes.none,
|
||||||
@ -401,6 +401,17 @@ case class TLBundleParameters(
|
|||||||
max(sizeBits, x.sizeBits))
|
max(sizeBits, x.sizeBits))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object TLBundleParameters
|
||||||
|
{
|
||||||
|
def apply(client: TLClientPortParameters, manager: TLManagerPortParameters) =
|
||||||
|
new TLBundleParameters(
|
||||||
|
addrHiBits = log2Up(manager.maxAddress + 1) - log2Ceil(manager.beatBytes),
|
||||||
|
dataBits = manager.beatBytes * 8,
|
||||||
|
sourceBits = log2Up(client.endSourceId),
|
||||||
|
sinkBits = log2Up(manager.endSinkId),
|
||||||
|
sizeBits = log2Up(log2Ceil(max(client.maxTransfer, manager.maxTransfer))+1))
|
||||||
|
}
|
||||||
|
|
||||||
case class TLEdgeParameters(
|
case class TLEdgeParameters(
|
||||||
client: TLClientPortParameters,
|
client: TLClientPortParameters,
|
||||||
manager: TLManagerPortParameters)
|
manager: TLManagerPortParameters)
|
||||||
@ -411,10 +422,13 @@ case class TLEdgeParameters(
|
|||||||
// Sanity check the link...
|
// Sanity check the link...
|
||||||
require (maxTransfer >= manager.beatBytes)
|
require (maxTransfer >= manager.beatBytes)
|
||||||
|
|
||||||
val bundle = TLBundleParameters(
|
val bundle = TLBundleParameters(client, manager)
|
||||||
addrHiBits = log2Up(manager.maxAddress + 1) - log2Ceil(manager.beatBytes),
|
}
|
||||||
dataBits = manager.beatBytes * 8,
|
|
||||||
sourceBits = log2Up(client.endSourceId),
|
case class TLAsyncManagerPortParameters(depth: Int, base: TLManagerPortParameters) { require (isPow2(depth)) }
|
||||||
sinkBits = log2Up(manager.endSinkId),
|
case class TLAsyncClientPortParameters(base: TLClientPortParameters)
|
||||||
sizeBits = log2Up(maxLgSize+1))
|
case class TLAsyncBundleParameters(depth: Int, base: TLBundleParameters) { require (isPow2(depth)) }
|
||||||
|
case class TLAsyncEdgeParameters(client: TLAsyncClientPortParameters, manager: TLAsyncManagerPortParameters)
|
||||||
|
{
|
||||||
|
val bundle = TLAsyncBundleParameters(manager.depth, TLBundleParameters(client.base, manager.base))
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,8 @@ import chisel3.internal.sourceinfo.SourceInfo
|
|||||||
|
|
||||||
object TLImp extends NodeImp[TLClientPortParameters, TLManagerPortParameters, TLEdgeOut, TLEdgeIn, TLBundle]
|
object TLImp extends NodeImp[TLClientPortParameters, TLManagerPortParameters, TLEdgeOut, TLEdgeIn, TLBundle]
|
||||||
{
|
{
|
||||||
def edgeO(po: TLClientPortParameters, pi: TLManagerPortParameters): TLEdgeOut = new TLEdgeOut(po, pi)
|
def edgeO(pd: TLClientPortParameters, pu: TLManagerPortParameters): TLEdgeOut = new TLEdgeOut(pd, pu)
|
||||||
def edgeI(po: TLClientPortParameters, pi: TLManagerPortParameters): TLEdgeIn = new TLEdgeIn(po, pi)
|
def edgeI(pd: TLClientPortParameters, pu: TLManagerPortParameters): TLEdgeIn = new TLEdgeIn(pd, pu)
|
||||||
def bundleO(eo: Seq[TLEdgeOut]): Vec[TLBundle] = {
|
def bundleO(eo: Seq[TLEdgeOut]): Vec[TLBundle] = {
|
||||||
require (!eo.isEmpty)
|
require (!eo.isEmpty)
|
||||||
Vec(eo.size, TLBundle(eo.map(_.bundle).reduce(_.union(_))))
|
Vec(eo.size, TLBundle(eo.map(_.bundle).reduce(_.union(_))))
|
||||||
@ -19,19 +19,18 @@ object TLImp extends NodeImp[TLClientPortParameters, TLManagerPortParameters, TL
|
|||||||
Vec(ei.size, TLBundle(ei.map(_.bundle).reduce(_.union(_)))).flip
|
Vec(ei.size, TLBundle(ei.map(_.bundle).reduce(_.union(_)))).flip
|
||||||
}
|
}
|
||||||
|
|
||||||
def connect(bo: => TLBundle, eo: => TLEdgeOut, bi: => TLBundle, ei: => TLEdgeIn)(implicit sourceInfo: SourceInfo): (Option[LazyModule], () => Unit) = {
|
def connect(bo: => TLBundle, bi: => TLBundle, ei: => TLEdgeIn)(implicit sourceInfo: SourceInfo): (Option[LazyModule], () => Unit) = {
|
||||||
val monitor = LazyModule(new TLMonitor(() => new TLBundleSnoop(bo.params), () => eo, sourceInfo))
|
val monitor = LazyModule(new TLMonitor(() => new TLBundleSnoop(bo.params), () => ei, sourceInfo))
|
||||||
(Some(monitor), () => {
|
(Some(monitor), () => {
|
||||||
require (eo.asInstanceOf[TLEdgeParameters] == ei.asInstanceOf[TLEdgeParameters])
|
|
||||||
bi <> bo
|
bi <> bo
|
||||||
monitor.module.io.in := TLBundleSnoop(bo)
|
monitor.module.io.in := TLBundleSnoop(bo)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
override def mixO(po: TLClientPortParameters, node: TLBaseNode): TLClientPortParameters =
|
override def mixO(pd: TLClientPortParameters, node: OutwardNode[TLClientPortParameters, TLManagerPortParameters, TLBundle]): TLClientPortParameters =
|
||||||
po.copy(clients = po.clients.map { c => c.copy (nodePath = node +: c.nodePath) })
|
pd.copy(clients = pd.clients.map { c => c.copy (nodePath = node +: c.nodePath) })
|
||||||
override def mixI(pi: TLManagerPortParameters, node: TLBaseNode): TLManagerPortParameters =
|
override def mixI(pu: TLManagerPortParameters, node: InwardNode[TLClientPortParameters, TLManagerPortParameters, TLBundle]): TLManagerPortParameters =
|
||||||
pi.copy(managers = pi.managers.map { m => m.copy (nodePath = node +: m.nodePath) })
|
pu.copy(managers = pu.managers.map { m => m.copy (nodePath = node +: m.nodePath) })
|
||||||
}
|
}
|
||||||
|
|
||||||
case class TLIdentityNode() extends IdentityNode(TLImp)
|
case class TLIdentityNode() extends IdentityNode(TLImp)
|
||||||
@ -72,3 +71,42 @@ class TLInputNodeTest extends UnitTest(500000) {
|
|||||||
|
|
||||||
io.finished := Module(fuzzer.module).io.finished
|
io.finished := Module(fuzzer.module).io.finished
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object TLAsyncImp extends NodeImp[TLAsyncClientPortParameters, TLAsyncManagerPortParameters, TLAsyncEdgeParameters, TLAsyncEdgeParameters, TLAsyncBundle]
|
||||||
|
{
|
||||||
|
def edgeO(pd: TLAsyncClientPortParameters, pu: TLAsyncManagerPortParameters): TLAsyncEdgeParameters = TLAsyncEdgeParameters(pd, pu)
|
||||||
|
def edgeI(pd: TLAsyncClientPortParameters, pu: TLAsyncManagerPortParameters): TLAsyncEdgeParameters = TLAsyncEdgeParameters(pd, pu)
|
||||||
|
def bundleO(eo: Seq[TLAsyncEdgeParameters]): Vec[TLAsyncBundle] = {
|
||||||
|
require (eo.size == 1)
|
||||||
|
Vec(eo.size, new TLAsyncBundle(eo(0).bundle))
|
||||||
|
}
|
||||||
|
def bundleI(ei: Seq[TLAsyncEdgeParameters]): Vec[TLAsyncBundle] = {
|
||||||
|
require (ei.size == 1)
|
||||||
|
Vec(ei.size, new TLAsyncBundle(ei(0).bundle)).flip
|
||||||
|
}
|
||||||
|
|
||||||
|
def connect(bo: => TLAsyncBundle, bi: => TLAsyncBundle, ei: => TLAsyncEdgeParameters)(implicit sourceInfo: SourceInfo): (Option[LazyModule], () => Unit) = {
|
||||||
|
(None, () => { bi <> bo })
|
||||||
|
}
|
||||||
|
|
||||||
|
override def mixO(pd: TLAsyncClientPortParameters, node: OutwardNode[TLAsyncClientPortParameters, TLAsyncManagerPortParameters, TLAsyncBundle]): TLAsyncClientPortParameters =
|
||||||
|
pd.copy(base = pd.base.copy(clients = pd.base.clients.map { c => c.copy (nodePath = node +: c.nodePath) }))
|
||||||
|
override def mixI(pu: TLAsyncManagerPortParameters, node: InwardNode[TLAsyncClientPortParameters, TLAsyncManagerPortParameters, TLAsyncBundle]): TLAsyncManagerPortParameters =
|
||||||
|
pu.copy(base = pu.base.copy(managers = pu.base.managers.map { m => m.copy (nodePath = node +: m.nodePath) }))
|
||||||
|
}
|
||||||
|
|
||||||
|
case class TLAsyncIdentityNode() extends IdentityNode(TLAsyncImp)
|
||||||
|
case class TLAsyncOutputNode() extends OutputNode(TLAsyncImp)
|
||||||
|
case class TLAsyncInputNode() extends InputNode(TLAsyncImp)
|
||||||
|
|
||||||
|
case class TLAsyncSourceNode() extends MixedNode(TLImp, TLAsyncImp)(
|
||||||
|
dFn = { case (1, s) => s.map(TLAsyncClientPortParameters(_)) },
|
||||||
|
uFn = { case (1, s) => s.map(_.base) },
|
||||||
|
numPO = 1 to 1,
|
||||||
|
numPI = 1 to 1)
|
||||||
|
|
||||||
|
case class TLAsyncSinkNode(depth: Int) extends MixedNode(TLAsyncImp, TLImp)(
|
||||||
|
dFn = { case (1, s) => s.map(_.base) },
|
||||||
|
uFn = { case (1, s) => s.map(TLAsyncManagerPortParameters(depth, _)) },
|
||||||
|
numPO = 1 to 1,
|
||||||
|
numPI = 1 to 1)
|
||||||
|
@ -5,8 +5,8 @@ import chisel3.internal.sourceinfo.{SourceInfo, SourceLine, UnlocatableSourceInf
|
|||||||
|
|
||||||
package object tilelink2
|
package object tilelink2
|
||||||
{
|
{
|
||||||
type TLBaseNode = BaseNode[TLClientPortParameters, TLManagerPortParameters, TLEdgeOut, TLEdgeIn, TLBundle]
|
type TLBaseNode = SimpleNode[TLClientPortParameters, TLManagerPortParameters, TLEdgeOut, TLEdgeIn, TLBundle]
|
||||||
type IntBaseNode = BaseNode[IntSourcePortParameters, IntSinkPortParameters, IntEdge, IntEdge, Vec[Bool]]
|
type IntBaseNode = SimpleNode[IntSourcePortParameters, IntSinkPortParameters, IntEdge, IntEdge, Vec[Bool]]
|
||||||
def OH1ToUInt(x: UInt) = OHToUInt((x << 1 | UInt(1)) ^ x)
|
def OH1ToUInt(x: UInt) = OHToUInt((x << 1 | UInt(1)) ^ x)
|
||||||
def UIntToOH1(x: UInt, width: Int) = ~(SInt(-1, width=width).asUInt << x)(width-1, 0)
|
def UIntToOH1(x: UInt, width: Int) = ~(SInt(-1, width=width).asUInt << x)(width-1, 0)
|
||||||
def trailingZeros(x: Int) = if (x > 0) Some(log2Ceil(x & -x)) else None
|
def trailingZeros(x: Int) = if (x > 0) Some(log2Ceil(x & -x)) else None
|
||||||
|
@ -25,8 +25,7 @@ object AsyncGrayCounter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AsyncQueueSource[T <: Data](gen: T, depth: Int, sync: Int, clockIn: Clock, resetIn: Bool)
|
class AsyncQueueSource[T <: Data](gen: T, depth: Int, sync: Int) extends Module {
|
||||||
extends Module(_clock = clockIn, _reset = resetIn) {
|
|
||||||
val bits = log2Ceil(depth)
|
val bits = log2Ceil(depth)
|
||||||
val io = new Bundle {
|
val io = new Bundle {
|
||||||
// These come from the source domain
|
// These come from the source domain
|
||||||
@ -53,8 +52,7 @@ class AsyncQueueSource[T <: Data](gen: T, depth: Int, sync: Int, clockIn: Clock,
|
|||||||
io.mem := mem
|
io.mem := mem
|
||||||
}
|
}
|
||||||
|
|
||||||
class AsyncQueueSink[T <: Data](gen: T, depth: Int, sync: Int, clockIn: Clock, resetIn: Bool)
|
class AsyncQueueSink[T <: Data](gen: T, depth: Int, sync: Int) extends Module {
|
||||||
extends Module(_clock = clockIn, _reset = resetIn) {
|
|
||||||
val bits = log2Ceil(depth)
|
val bits = log2Ceil(depth)
|
||||||
val io = new Bundle {
|
val io = new Bundle {
|
||||||
// These come from the sink domain
|
// These come from the sink domain
|
||||||
@ -88,8 +86,13 @@ class AsyncQueue[T <: Data](gen: T, depth: Int = 8, sync: Int = 3) extends Cross
|
|||||||
require (depth > 0 && isPow2(depth))
|
require (depth > 0 && isPow2(depth))
|
||||||
|
|
||||||
val io = new CrossingIO(gen)
|
val io = new CrossingIO(gen)
|
||||||
val source = Module(new AsyncQueueSource(gen, depth, sync, io.enq_clock, io.enq_reset))
|
val source = Module(new AsyncQueueSource(gen, depth, sync))
|
||||||
val sink = Module(new AsyncQueueSink (gen, depth, sync, io.deq_clock, io.deq_reset))
|
val sink = Module(new AsyncQueueSink (gen, depth, sync))
|
||||||
|
|
||||||
|
source.clock := io.enq_clock
|
||||||
|
source.reset := io.enq_reset
|
||||||
|
sink.clock := io.deq_clock
|
||||||
|
sink.reset := io.deq_reset
|
||||||
|
|
||||||
source.io.enq <> io.enq
|
source.io.enq <> io.enq
|
||||||
io.deq <> sink.io.deq
|
io.deq <> sink.io.deq
|
||||||
|
Loading…
Reference in New Issue
Block a user