diff --git a/src/main/scala/amba/ahb/Nodes.scala b/src/main/scala/amba/ahb/Nodes.scala index c104f9d9..95727ecc 100644 --- a/src/main/scala/amba/ahb/Nodes.scala +++ b/src/main/scala/amba/ahb/Nodes.scala @@ -24,10 +24,8 @@ case class AHBMasterNode(portParams: Seq[AHBMasterPortParameters])(implicit valN case class AHBSlaveNode(portParams: Seq[AHBSlavePortParameters])(implicit valName: ValName) extends SinkNode(AHBImp)(portParams) case class AHBNexusNode( masterFn: Seq[AHBMasterPortParameters] => AHBMasterPortParameters, - slaveFn: Seq[AHBSlavePortParameters] => AHBSlavePortParameters, - numMasterPorts: Range.Inclusive = 1 to 999, - numSlavePorts: Range.Inclusive = 1 to 999)( + slaveFn: Seq[AHBSlavePortParameters] => AHBSlavePortParameters)( implicit valName: ValName) - extends NexusNode(AHBImp)(masterFn, slaveFn, numMasterPorts, numSlavePorts) + extends NexusNode(AHBImp)(masterFn, slaveFn) case class AHBIdentityNode()(implicit valName: ValName) extends IdentityNode(AHBImp)() diff --git a/src/main/scala/amba/ahb/Xbar.scala b/src/main/scala/amba/ahb/Xbar.scala index 5298a441..2d52b611 100644 --- a/src/main/scala/amba/ahb/Xbar.scala +++ b/src/main/scala/amba/ahb/Xbar.scala @@ -10,37 +10,40 @@ import scala.math.{min,max} class AHBFanout()(implicit p: Parameters) extends LazyModule { val node = AHBNexusNode( - numSlavePorts = 1 to 1, - numMasterPorts = 1 to 32, masterFn = { case Seq(m) => m }, slaveFn = { seq => seq(0).copy(slaves = seq.flatMap(_.slaves)) }) lazy val module = new LazyModuleImp(this) { - // Require consistent bus widths - val (io_out, edgesOut) = node.out.unzip - val port0 = edgesOut(0).slave - edgesOut.foreach { edge => - val port = edge.slave - require (port.beatBytes == port0.beatBytes, - s"${port.slaves.map(_.name)} ${port.beatBytes} vs ${port0.slaves.map(_.name)} ${port0.beatBytes}") + if (node.edges.in.size >= 1) { + require (node.edges.in.size == 1, "AHBFanout does not support multiple masters") + require (node.edges.out.size > 0, "AHBFanout requires at least one slave") + + // Require consistent bus widths + val (io_out, edgesOut) = node.out.unzip + val port0 = edgesOut(0).slave + edgesOut.foreach { edge => + val port = edge.slave + require (port.beatBytes == port0.beatBytes, + s"${port.slaves.map(_.name)} ${port.beatBytes} vs ${port0.slaves.map(_.name)} ${port0.beatBytes}") + } + + val port_addrs = edgesOut.map(_.slave.slaves.map(_.address).flatten) + val routingMask = AddressDecoder(port_addrs) + val route_addrs = port_addrs.map(_.map(_.widen(~routingMask)).distinct) + + val (in, _) = node.in(0) + val a_sel = Vec(route_addrs.map(seq => seq.map(_.contains(in.haddr)).reduce(_ || _))) + val d_sel = Reg(a_sel) + + when (in.hready) { d_sel := a_sel } + (a_sel zip io_out) foreach { case (sel, out) => + out := in + out.hsel := in.hsel && sel + } + + in.hreadyout := !Mux1H(d_sel, io_out.map(!_.hreadyout)) + in.hresp := Mux1H(d_sel, io_out.map(_.hresp)) + in.hrdata := Mux1H(d_sel, io_out.map(_.hrdata)) } - - val port_addrs = edgesOut.map(_.slave.slaves.map(_.address).flatten) - val routingMask = AddressDecoder(port_addrs) - val route_addrs = port_addrs.map(_.map(_.widen(~routingMask)).distinct) - - val (in, _) = node.in(0) - val a_sel = Vec(route_addrs.map(seq => seq.map(_.contains(in.haddr)).reduce(_ || _))) - val d_sel = Reg(a_sel) - - when (in.hready) { d_sel := a_sel } - (a_sel zip io_out) foreach { case (sel, out) => - out := in - out.hsel := in.hsel && sel - } - - in.hreadyout := !Mux1H(d_sel, io_out.map(!_.hreadyout)) - in.hresp := Mux1H(d_sel, io_out.map(_.hresp)) - in.hrdata := Mux1H(d_sel, io_out.map(_.hrdata)) } } diff --git a/src/main/scala/amba/apb/Nodes.scala b/src/main/scala/amba/apb/Nodes.scala index 47e67dbc..cc09a9d9 100644 --- a/src/main/scala/amba/apb/Nodes.scala +++ b/src/main/scala/amba/apb/Nodes.scala @@ -23,10 +23,8 @@ case class APBMasterNode(portParams: Seq[APBMasterPortParameters])(implicit valN case class APBSlaveNode(portParams: Seq[APBSlavePortParameters])(implicit valName: ValName) extends SinkNode(APBImp)(portParams) case class APBNexusNode( masterFn: Seq[APBMasterPortParameters] => APBMasterPortParameters, - slaveFn: Seq[APBSlavePortParameters] => APBSlavePortParameters, - numMasterPorts: Range.Inclusive = 1 to 1, - numSlavePorts: Range.Inclusive = 1 to 1)( + slaveFn: Seq[APBSlavePortParameters] => APBSlavePortParameters)( implicit valName: ValName) - extends NexusNode(APBImp)(masterFn, slaveFn, numMasterPorts, numSlavePorts) + extends NexusNode(APBImp)(masterFn, slaveFn) case class APBIdentityNode()(implicit valName: ValName) extends IdentityNode(APBImp)() diff --git a/src/main/scala/amba/apb/Xbar.scala b/src/main/scala/amba/apb/Xbar.scala index c72e6547..b4a5bf9b 100644 --- a/src/main/scala/amba/apb/Xbar.scala +++ b/src/main/scala/amba/apb/Xbar.scala @@ -10,36 +10,39 @@ import scala.math.{min,max} class APBFanout()(implicit p: Parameters) extends LazyModule { val node = APBNexusNode( - numSlavePorts = 1 to 1, - numMasterPorts = 1 to 32, masterFn = { case Seq(m) => m }, slaveFn = { seq => seq(0).copy(slaves = seq.flatMap(_.slaves)) }) lazy val module = new LazyModuleImp(this) { - val (in, _) = node.in(0) + if (node.edges.in.size >= 1) { + require (node.edges.in.size == 1, "APBFanout does not support multiple masters") + require (node.edges.out.size > 0, "APBFanout requires at least one slave") - // Require consistent bus widths - val (io_out, edgesOut) = node.out.unzip - val port0 = edgesOut(0).slave - edgesOut.foreach { edge => - val port = edge.slave - require (port.beatBytes == port0.beatBytes, - s"${port.slaves.map(_.name)} ${port.beatBytes} vs ${port0.slaves.map(_.name)} ${port0.beatBytes}") + val (in, _) = node.in(0) + + // Require consistent bus widths + val (io_out, edgesOut) = node.out.unzip + val port0 = edgesOut(0).slave + edgesOut.foreach { edge => + val port = edge.slave + require (port.beatBytes == port0.beatBytes, + s"${port.slaves.map(_.name)} ${port.beatBytes} vs ${port0.slaves.map(_.name)} ${port0.beatBytes}") + } + + val port_addrs = edgesOut.map(_.slave.slaves.map(_.address).flatten) + val routingMask = AddressDecoder(port_addrs) + val route_addrs = port_addrs.map(_.map(_.widen(~routingMask)).distinct) + + val sel = Vec(route_addrs.map(seq => seq.map(_.contains(in.paddr)).reduce(_ || _))) + (sel zip io_out) foreach { case (sel, out) => + out := in + out.psel := sel && in.psel + out.penable := sel && in.penable + } + + in.pready := !Mux1H(sel, io_out.map(!_.pready)) + in.pslverr := Mux1H(sel, io_out.map(_.pslverr)) + in.prdata := Mux1H(sel, io_out.map(_.prdata)) } - - val port_addrs = edgesOut.map(_.slave.slaves.map(_.address).flatten) - val routingMask = AddressDecoder(port_addrs) - val route_addrs = port_addrs.map(_.map(_.widen(~routingMask)).distinct) - - val sel = Vec(route_addrs.map(seq => seq.map(_.contains(in.paddr)).reduce(_ || _))) - (sel zip io_out) foreach { case (sel, out) => - out := in - out.psel := sel && in.psel - out.penable := sel && in.penable - } - - in.pready := !Mux1H(sel, io_out.map(!_.pready)) - in.pslverr := Mux1H(sel, io_out.map(_.pslverr)) - in.prdata := Mux1H(sel, io_out.map(_.prdata)) } } diff --git a/src/main/scala/amba/axi4/Nodes.scala b/src/main/scala/amba/axi4/Nodes.scala index 172feff2..e4815046 100644 --- a/src/main/scala/amba/axi4/Nodes.scala +++ b/src/main/scala/amba/axi4/Nodes.scala @@ -23,17 +23,14 @@ case class AXI4MasterNode(portParams: Seq[AXI4MasterPortParameters])(implicit va case class AXI4SlaveNode(portParams: Seq[AXI4SlavePortParameters])(implicit valName: ValName) extends SinkNode(AXI4Imp)(portParams) case class AXI4NexusNode( masterFn: Seq[AXI4MasterPortParameters] => AXI4MasterPortParameters, - slaveFn: Seq[AXI4SlavePortParameters] => AXI4SlavePortParameters, - numMasterPorts: Range.Inclusive = 1 to 999, - numSlavePorts: Range.Inclusive = 1 to 999)( + slaveFn: Seq[AXI4SlavePortParameters] => AXI4SlavePortParameters)( implicit valName: ValName) - extends NexusNode(AXI4Imp)(masterFn, slaveFn, numMasterPorts, numSlavePorts) + extends NexusNode(AXI4Imp)(masterFn, slaveFn) case class AXI4AdapterNode( masterFn: AXI4MasterPortParameters => AXI4MasterPortParameters = { m => m }, - slaveFn: AXI4SlavePortParameters => AXI4SlavePortParameters = { s => s }, - numPorts: Range.Inclusive = 0 to 999)( + slaveFn: AXI4SlavePortParameters => AXI4SlavePortParameters = { s => s })( implicit valName: ValName) - extends AdapterNode(AXI4Imp)(masterFn, slaveFn, numPorts) + extends AdapterNode(AXI4Imp)(masterFn, slaveFn) case class AXI4IdentityNode()(implicit valName: ValName) extends IdentityNode(AXI4Imp)() object AXI4AsyncImp extends SimpleNodeImp[AXI4AsyncMasterPortParameters, AXI4AsyncSlavePortParameters, AXI4AsyncEdgeParameters, AXI4AsyncBundle] diff --git a/src/main/scala/amba/axi4/Xbar.scala b/src/main/scala/amba/axi4/Xbar.scala index eab6d3b9..70a8f1e7 100644 --- a/src/main/scala/amba/axi4/Xbar.scala +++ b/src/main/scala/amba/axi4/Xbar.scala @@ -18,8 +18,6 @@ class AXI4Xbar( require (awQueueDepth >= 1) val node = AXI4NexusNode( - numMasterPorts = 1 to 999, - numSlavePorts = 1 to 999, masterFn = { seq => seq(0).copy( userBits = seq.map(_.userBits).max, @@ -56,14 +54,14 @@ class AXI4Xbar( val awIn = Seq.fill(io_in .size) { Module(new Queue(UInt(width = io_out.size), awQueueDepth, flow = true)) } val awOut = Seq.fill(io_out.size) { Module(new Queue(UInt(width = io_in .size), awQueueDepth, flow = true)) } - val requestARIO = Vec(io_in.map { i => Vec(outputPorts.map { o => o(i.ar.bits.addr) }) }) - val requestAWIO = Vec(io_in.map { i => Vec(outputPorts.map { o => o(i.aw.bits.addr) }) }) - val requestROI = Vec(io_out.map { o => Vec(inputIdRanges.map { i => i.contains(o.r.bits.id) }) }) - val requestBOI = Vec(io_out.map { o => Vec(inputIdRanges.map { i => i.contains(o.b.bits.id) }) }) + val requestARIO = io_in.map { i => Vec(outputPorts.map { o => o(i.ar.bits.addr) }) } + val requestAWIO = io_in.map { i => Vec(outputPorts.map { o => o(i.aw.bits.addr) }) } + val requestROI = io_out.map { o => inputIdRanges.map { i => i.contains(o.r.bits.id) } } + val requestBOI = io_out.map { o => inputIdRanges.map { i => i.contains(o.b.bits.id) } } // W follows the path dictated by the AW Q for (i <- 0 until io_in.size) { awIn(i).io.enq.bits := requestAWIO(i).asUInt } - val requestWIO = Vec(awIn.map { q => if (io_out.size > 1) Vec(q.io.deq.bits.toBools) else Vec.fill(1){Bool(true)} }) + val requestWIO = awIn.map { q => if (io_out.size > 1) q.io.deq.bits.toBools else Seq(Bool(true)) } // We need an intermediate size of bundle with the widest possible identifiers val wide_bundle = AXI4BundleParameters.union(io_in.map(_.params) ++ io_out.map(_.params)) diff --git a/src/main/scala/devices/debug/Debug.scala b/src/main/scala/devices/debug/Debug.scala index a0da5a04..9167a715 100644 --- a/src/main/scala/devices/debug/Debug.scala +++ b/src/main/scala/devices/debug/Debug.scala @@ -279,11 +279,9 @@ class TLDebugModuleOuter(device: Device)(implicit p: Parameters) extends LazyMod import DMI_RegAddrs._ val intnode = IntNexusNode( - numSourcePorts = 1 to 1024, - numSinkPorts = 0 to 0, sourceFn = { _ => IntSourcePortParameters(Seq(IntSourceParameters(1, Seq(Resource(device, "int"))))) }, - sinkFn = { _ => IntSinkPortParameters(Seq(IntSinkParameters())) } - ) + sinkFn = { _ => IntSinkPortParameters(Seq(IntSinkParameters())) }, + outputRequiresInput = false) val dmiNode = TLRegisterNode ( address = AddressSet.misaligned(DMI_DMCONTROL << 2, 4), @@ -293,6 +291,7 @@ class TLDebugModuleOuter(device: Device)(implicit p: Parameters) extends LazyMod ) lazy val module = new LazyModuleImp(this) { + require (intnode.edges.in.size == 0, "Debug Module does not accept interrupts") val nComponents = intnode.out.size diff --git a/src/main/scala/devices/tilelink/BusBypass.scala b/src/main/scala/devices/tilelink/BusBypass.scala index 03989899..4433d535 100644 --- a/src/main/scala/devices/tilelink/BusBypass.scala +++ b/src/main/scala/devices/tilelink/BusBypass.scala @@ -37,14 +37,21 @@ class TLBusBypass(beatBytes: Int)(implicit p: Parameters) extends TLBusBypassBas } } +class TLBypassNode(implicit valName: ValName) extends TLCustomNode +{ + def resolveStar(iKnown: Int, oKnown: Int, iStars: Int, oStars: Int): (Int, Int) = { + require (iStars == 0 && oStars == 0, "TLBypass node does not support :=* or :*=") + require (iKnown == 1, "TLBypass node expects exactly one input") + require (oKnown == 2, "TLBypass node expects exactly one output") + (0, 0) + } + def mapParamsD(n: Int, p: Seq[TLClientPortParameters]): Seq[TLClientPortParameters] = { p ++ p } + def mapParamsU(n: Int, p: Seq[TLManagerPortParameters]): Seq[TLManagerPortParameters] = { p.tail } +} + class TLBusBypassBar(implicit p: Parameters) extends LazyModule { - // The client only sees the second slave port - val node = TLNexusNode( - numClientPorts = 2 to 2 , - numManagerPorts = 1 to 1, - clientFn = { seq => seq(0) }, - managerFn = { seq => seq(1) }) + val node = new TLBypassNode() lazy val module = new LazyModuleImp(this) { val io = IO(new Bundle { diff --git a/src/main/scala/devices/tilelink/Clint.scala b/src/main/scala/devices/tilelink/Clint.scala index 9cc83030..94a75fee 100644 --- a/src/main/scala/devices/tilelink/Clint.scala +++ b/src/main/scala/devices/tilelink/Clint.scala @@ -48,12 +48,13 @@ class CoreplexLocalInterrupter(params: ClintParams)(implicit p: Parameters) exte beatBytes = p(XLen)/8) val intnode = IntNexusNode( - numSourcePorts = 0 to 1024, - numSinkPorts = 0 to 0, - sourceFn = { _ => IntSourcePortParameters(Seq(IntSourceParameters(ints, Seq(Resource(device, "int"))))) }, - sinkFn = { _ => IntSinkPortParameters(Seq(IntSinkParameters())) }) + sourceFn = { _ => IntSourcePortParameters(Seq(IntSourceParameters(ints, Seq(Resource(device, "int"))))) }, + sinkFn = { _ => IntSinkPortParameters(Seq(IntSinkParameters())) }, + outputRequiresInput = false) lazy val module = new LazyModuleImp(this) { + require (intnode.edges.in.size == 0, "CLINT only produces interrupts; it does not accept them") + val io = IO(new Bundle { val rtcTick = Bool(INPUT) }) diff --git a/src/main/scala/devices/tilelink/Plic.scala b/src/main/scala/devices/tilelink/Plic.scala index a6ede5b7..ee915e1d 100644 --- a/src/main/scala/devices/tilelink/Plic.scala +++ b/src/main/scala/devices/tilelink/Plic.scala @@ -86,10 +86,10 @@ class TLPLIC(params: PLICParams)(implicit p: Parameters) extends LazyModule concurrency = 1) // limiting concurrency handles RAW hazards on claim registers val intnode = IntNexusNode( - numSourcePorts = 0 to 1024, - numSinkPorts = 0 to 1024, - sourceFn = { _ => IntSourcePortParameters(Seq(IntSourceParameters(1, Seq(Resource(device, "int"))))) }, - sinkFn = { _ => IntSinkPortParameters(Seq(IntSinkParameters())) }) + sourceFn = { _ => IntSourcePortParameters(Seq(IntSourceParameters(1, Seq(Resource(device, "int"))))) }, + sinkFn = { _ => IntSinkPortParameters(Seq(IntSinkParameters())) }, + outputRequiresInput = false, + inputRequiresOutput = false) /* Negotiated sizes */ def nDevices: Int = intnode.edges.in.map(_.source.num).sum diff --git a/src/main/scala/diplomacy/Nodes.scala b/src/main/scala/diplomacy/Nodes.scala index fb017814..b5ea1b4a 100644 --- a/src/main/scala/diplomacy/Nodes.scala +++ b/src/main/scala/diplomacy/Nodes.scala @@ -188,18 +188,12 @@ object NodeBinding trait InwardNode[DI, UI, BI <: Data] extends BaseNode { - protected[diplomacy] val numPI: Range.Inclusive - require (!numPI.isEmpty, s"No number of inputs would be acceptable to ${name}${lazyModule.line}") - require (numPI.start >= 0, s"${name} accepts a negative number of inputs${lazyModule.line}") - private val accPI = ListBuffer[(Int, OutwardNode[DI, UI, BI], NodeBinding, Parameters, SourceInfo)]() private var iRealized = false protected[diplomacy] def iPushed = accPI.size protected[diplomacy] def iPush(index: Int, node: OutwardNode[DI, UI, BI], binding: NodeBinding)(implicit p: Parameters, 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 its .module was used" + info) accPI += ((index, node, binding, p, sourceInfo)) } @@ -222,18 +216,12 @@ trait OutwardNodeHandle[DO, UO, EO, BO <: Data] extends NoHandle trait OutwardNode[DO, UO, BO <: Data] extends BaseNode { - protected[diplomacy] 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], NodeBinding, Parameters, SourceInfo)]() private var oRealized = false protected[diplomacy] def oPushed = accPO.size protected[diplomacy] def oPush(index: Int, node: InwardNode [DO, UO, BO], binding: NodeBinding)(implicit p: Parameters, 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 its .module was used" + info) accPO += ((index, node, binding, p, sourceInfo)) } @@ -255,8 +243,6 @@ case class Edges[EI, EO](in: EI, out: EO) sealed abstract class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]( val inner: InwardNodeImp [DI, UI, EI, BI], val outer: OutwardNodeImp[DO, UO, EO, BO])( - protected[diplomacy] val numPO: Range.Inclusive, - protected[diplomacy] val numPI: Range.Inclusive)( implicit valName: ValName) extends BaseNode with NodeHandle[DI, UI, EI, BI, DO, UO, EO, BO] with InwardNode[DI, UI, BI] with OutwardNode[DO, UO, BO] { @@ -292,8 +278,6 @@ sealed abstract class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]( case BIND_STAR => iStar }}.scanLeft(0)(_+_) val oTotal = oSum.lastOption.getOrElse(0) val iTotal = iSum.lastOption.getOrElse(0) - require(numPO.contains(oTotal), s"${name} has ${oTotal} outputs, expected ${numPO}${lazyModule.line}") - require(numPI.contains(iTotal), s"${name} has ${iTotal} inputs, expected ${numPI}${lazyModule.line}") (oSum.init zip oSum.tail, iSum.init zip iSum.tail, oStar, iStar) } catch { case c: StarCycleException => throw c.copy(loop = s"${name}${lazyModule.line}" +: c.loop) @@ -417,10 +401,8 @@ sealed abstract class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]( 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)( implicit valName: ValName) - extends MixedNode(inner, outer)(numPO, numPI) + extends MixedNode(inner, outer) { def resolveStar(iKnown: Int, oKnown: Int, iStars: Int, oStars: Int): (Int, Int) def mapParamsD(n: Int, p: Seq[DI]): Seq[DO] @@ -428,28 +410,28 @@ abstract class MixedCustomNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]( } abstract class CustomNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])( - numPO: Range.Inclusive, - numPI: Range.Inclusive)( implicit valName: ValName) - extends MixedCustomNode(imp, imp)(numPO, numPI) + extends MixedCustomNode(imp, imp) class MixedAdapterNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]( inner: InwardNodeImp [DI, UI, EI, BI], outer: OutwardNodeImp[DO, UO, EO, BO])( dFn: DI => DO, - uFn: UO => UI, - num: Range.Inclusive = 0 to 999)( + uFn: UO => UI)( implicit valName: ValName) - extends MixedNode(inner, outer)(num, num) + extends MixedNode(inner, outer) { protected[diplomacy] def resolveStar(iKnown: Int, oKnown: Int, iStars: Int, oStars: Int): (Int, Int) = { 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}") 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}") (0, iKnown - oKnown) - } else { + } else if (iStars > 0) { 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) + } else { + require (oKnown == iKnown, s"${name} (an adapter) has ${oKnown} outputs and ${iKnown} inputs; these do not match") + (0, 0) } } protected[diplomacy] def mapParamsD(n: Int, p: Seq[DI]): Seq[DO] = { @@ -464,10 +446,9 @@ class MixedAdapterNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]( class AdapterNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])( dFn: D => D, - uFn: U => U, - num: Range.Inclusive = 0 to 999)( + uFn: U => U)( implicit valName: ValName) - extends MixedAdapterNode[D, U, EI, B, D, U, EO, B](imp, imp)(dFn, uFn, num) + extends MixedAdapterNode[D, U, EI, B, D, U, EO, B](imp, imp)(dFn, uFn) // IdentityNodes automatically connect their inputs to outputs class IdentityNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])()(implicit valName: ValName) @@ -486,39 +467,39 @@ class MixedNexusNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]( outer: OutwardNodeImp[DO, UO, EO, BO])( dFn: Seq[DI] => DO, uFn: Seq[UO] => UI, - numPO: Range.Inclusive = 1 to 999, - numPI: Range.Inclusive = 1 to 999)( + // no inputs and no outputs is always allowed + inputRequiresOutput: Boolean = true, + outputRequiresInput: Boolean = true)( implicit valName: ValName) - extends MixedNode(inner, outer)(numPO, numPI) + extends MixedNode(inner, outer) { -// require (numPO.end >= 1, s"${name} does not accept outputs${lazyModule.line}") -// require (numPI.end >= 1, s"${name} does not accept inputs${lazyModule.line}") - protected[diplomacy] def resolveStar(iKnown: Int, oKnown: Int, iStars: Int, oStars: Int): (Int, Int) = { - require (iStars == 0, s"${name} (a nexus) appears left of :*= (perhaps you should flip the '*' to :=*?)${lazyModule.line}") - require (oStars == 0, s"${name} (a nexus) appears right of a :=* (perhaps you should flip the '*' to :*=?)${lazyModule.line}") - (0, 0) + // a nexus treats :=* as a weak pointer + require (!outputRequiresInput || oKnown == 0 || iStars + iKnown != 0, s"${name} (a nexus) has ${oKnown} required outputs and no possible inputs") + require (!inputRequiresOutput || iKnown == 0 || oStars + oKnown != 0, s"${name} (a nexus) has ${iKnown} required inputs and no possible outputs") + if (iKnown == 0 && oKnown == 0) (0, 0) else (1, 1) } - protected[diplomacy] def mapParamsD(n: Int, p: Seq[DI]): Seq[DO] = { val a = dFn(p); Seq.fill(n)(a) } - protected[diplomacy] def mapParamsU(n: Int, p: Seq[UO]): Seq[UI] = { val a = uFn(p); Seq.fill(n)(a) } + protected[diplomacy] def mapParamsD(n: Int, p: Seq[DI]): Seq[DO] = { if (n > 0) { val a = dFn(p); Seq.fill(n)(a) } else Nil } + protected[diplomacy] def mapParamsU(n: Int, p: Seq[UO]): Seq[UI] = { if (n > 0) { val a = uFn(p); Seq.fill(n)(a) } else Nil } } class NexusNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])( dFn: Seq[D] => D, uFn: Seq[U] => U, - numPO: Range.Inclusive = 1 to 999, - numPI: Range.Inclusive = 1 to 999)( + inputRequiresOutput: Boolean = true, + outputRequiresInput: Boolean = true)( implicit valName: ValName) - 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, inputRequiresOutput, outputRequiresInput) // There are no Mixed SourceNodes class SourceNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])(po: Seq[D])(implicit valName: ValName) - extends MixedNode(imp, imp)(po.size to po.size, 0 to 0) + extends MixedNode(imp, imp) { protected[diplomacy] def resolveStar(iKnown: Int, oKnown: Int, iStars: Int, oStars: Int): (Int, Int) = { require (oStars <= 1, s"${name} (a source) appears right of a :=* ${oStars} times; at most once is allowed${lazyModule.line}") 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}") + require (po.size == oKnown || oStars == 1, s"${name} (a source) has only ${oKnown} outputs connected out of ${po.size}") 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}") (0, po.size - oKnown) } @@ -528,12 +509,13 @@ class SourceNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])(po: Seq // There are no Mixed SinkNodes class SinkNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])(pi: Seq[U])(implicit valName: ValName) - extends MixedNode(imp, imp)(0 to 0, pi.size to pi.size) + extends MixedNode(imp, imp) { protected[diplomacy] def resolveStar(iKnown: Int, oKnown: Int, iStars: Int, oStars: Int): (Int, Int) = { require (iStars <= 1, s"${name} (a sink) appears left of a :*= ${iStars} times; at most once is allowed${lazyModule.line}") 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}") + require (pi.size == iKnown || iStars == 1, s"${name} (a sink) has only ${iKnown} inputs connected out of ${pi.size}") 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}") (pi.size - iKnown, 0) } @@ -544,9 +526,7 @@ class SinkNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])(pi: Seq[U class MixedTestNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data] protected[diplomacy]( node: NodeHandle [DI, UI, EI, BI, DO, UO, EO, BO], clone: CloneLazyModule)( implicit valName: ValName) - extends MixedNode(node.inner, node.outer)( - numPI = node.inward .uiParams.size to node.inward .uiParams.size, - numPO = node.outward.doParams.size to node.outward.doParams.size) + extends MixedNode(node.inner, node.outer) { // The devices connected to this test node must recreate these parameters: def iParams: Seq[DI] = node.inward .diParams @@ -555,6 +535,8 @@ class MixedTestNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data] protected[di protected[diplomacy] def resolveStar(iKnown: Int, oKnown: Int, iStars: Int, oStars: Int): (Int, Int) = { require (oStars <= 1, s"${name} (a test node) appears right of a :=* ${oStars} times; at most once is allowed${lazyModule.line}") require (iStars <= 1, s"${name} (a test node) appears left of a :*= ${iStars} times; at most once is allowed${lazyModule.line}") + require (node.inward .uiParams.size == iKnown || iStars == 1, s"${name} (a test node) has only ${iKnown} inputs connected out of ${node.inward.uiParams.size}") + require (node.outward.doParams.size == oKnown || oStars == 1, s"${name} (a test node) has only ${oKnown} outputs connected out of ${node.outward.doParams.size}") (node.inward.uiParams.size - iKnown, node.outward.doParams.size - oKnown) } diff --git a/src/main/scala/interrupts/Nodes.scala b/src/main/scala/interrupts/Nodes.scala index 6b431cc2..03df8c53 100644 --- a/src/main/scala/interrupts/Nodes.scala +++ b/src/main/scala/interrupts/Nodes.scala @@ -23,19 +23,18 @@ case class IntSourceNode(portParams: Seq[IntSourcePortParameters])(implicit valN case class IntSinkNode(portParams: Seq[IntSinkPortParameters])(implicit valName: ValName) extends SinkNode(IntImp)(portParams) case class IntAdapterNode( sourceFn: IntSourcePortParameters => IntSourcePortParameters = { s => s }, - sinkFn: IntSinkPortParameters => IntSinkPortParameters = { s => s }, - num: Range.Inclusive = 0 to 999)( + sinkFn: IntSinkPortParameters => IntSinkPortParameters = { s => s })( implicit valName: ValName) - extends AdapterNode(IntImp)(sourceFn, sinkFn, num) + extends AdapterNode(IntImp)(sourceFn, sinkFn) case class IntIdentityNode()(implicit valName: ValName) extends IdentityNode(IntImp)() case class IntNexusNode( sourceFn: Seq[IntSourcePortParameters] => IntSourcePortParameters, sinkFn: Seq[IntSinkPortParameters] => IntSinkPortParameters, - numSourcePorts: Range.Inclusive = 0 to 128, - numSinkPorts: Range.Inclusive = 0 to 128)( + inputRequiresOutput: Boolean = true, + outputRequiresInput: Boolean = true)( implicit valName: ValName) - extends NexusNode(IntImp)(sourceFn, sinkFn, numSourcePorts, numSinkPorts) + extends NexusNode(IntImp)(sourceFn, sinkFn, inputRequiresOutput, outputRequiresInput) object IntSyncImp extends SimpleNodeImp[IntSourcePortParameters, IntSinkPortParameters, IntEdge, SyncInterrupts] { diff --git a/src/main/scala/tilelink/NodeNumberer.scala b/src/main/scala/tilelink/NodeNumberer.scala index 88e22f6a..6394a1f4 100644 --- a/src/main/scala/tilelink/NodeNumberer.scala +++ b/src/main/scala/tilelink/NodeNumberer.scala @@ -6,7 +6,7 @@ import Chisel._ import freechips.rocketchip.config.Parameters import freechips.rocketchip.diplomacy._ -case class TLNodeNumbererNode(nodeAddressOffset: Option[Int] = None)(implicit valName: ValName) extends TLCustomNode(0 to 999, 0 to 999) +case class TLNodeNumbererNode(nodeAddressOffset: Option[Int] = None)(implicit valName: ValName) extends TLCustomNode { 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}") diff --git a/src/main/scala/tilelink/Nodes.scala b/src/main/scala/tilelink/Nodes.scala index 605c1662..c629c0b9 100644 --- a/src/main/scala/tilelink/Nodes.scala +++ b/src/main/scala/tilelink/Nodes.scala @@ -49,26 +49,20 @@ case class TLManagerNode(portParams: Seq[TLManagerPortParameters])(implicit valN case class TLAdapterNode( clientFn: TLClientPortParameters => TLClientPortParameters = { s => s }, - managerFn: TLManagerPortParameters => TLManagerPortParameters = { s => s }, - num: Range.Inclusive = 0 to 999)( + managerFn: TLManagerPortParameters => TLManagerPortParameters = { s => s })( implicit valName: ValName) - extends AdapterNode(TLImp)(clientFn, managerFn, num) + extends AdapterNode(TLImp)(clientFn, managerFn) case class TLIdentityNode()(implicit valName: ValName) extends IdentityNode(TLImp)() case class TLNexusNode( clientFn: Seq[TLClientPortParameters] => TLClientPortParameters, - managerFn: Seq[TLManagerPortParameters] => TLManagerPortParameters, - numClientPorts: Range.Inclusive = 1 to 999, - numManagerPorts: Range.Inclusive = 1 to 999)( + managerFn: Seq[TLManagerPortParameters] => TLManagerPortParameters)( implicit valName: ValName) - extends NexusNode(TLImp)(clientFn, managerFn, numClientPorts, numManagerPorts) + extends NexusNode(TLImp)(clientFn, managerFn) -abstract class TLCustomNode( - numClientPorts: Range.Inclusive, - numManagerPorts: Range.Inclusive)( - implicit valName: ValName) - extends CustomNode(TLImp)(numClientPorts, numManagerPorts) +abstract class TLCustomNode(implicit valName: ValName) + extends CustomNode(TLImp) // Asynchronous crossings @@ -86,10 +80,9 @@ object TLAsyncImp extends SimpleNodeImp[TLAsyncClientPortParameters, TLAsyncMana case class TLAsyncAdapterNode( clientFn: TLAsyncClientPortParameters => TLAsyncClientPortParameters = { s => s }, - managerFn: TLAsyncManagerPortParameters => TLAsyncManagerPortParameters = { s => s }, - num: Range.Inclusive = 0 to 999)( + managerFn: TLAsyncManagerPortParameters => TLAsyncManagerPortParameters = { s => s })( implicit valName: ValName) - extends AdapterNode(TLAsyncImp)(clientFn, managerFn, num) + extends AdapterNode(TLAsyncImp)(clientFn, managerFn) case class TLAsyncIdentityNode()(implicit valName: ValName) extends IdentityNode(TLAsyncImp)() @@ -119,10 +112,9 @@ object TLRationalImp extends SimpleNodeImp[TLRationalClientPortParameters, TLRat case class TLRationalAdapterNode( clientFn: TLRationalClientPortParameters => TLRationalClientPortParameters = { s => s }, - managerFn: TLRationalManagerPortParameters => TLRationalManagerPortParameters = { s => s }, - num: Range.Inclusive = 0 to 999)( + managerFn: TLRationalManagerPortParameters => TLRationalManagerPortParameters = { s => s })( implicit valName: ValName) - extends AdapterNode(TLRationalImp)(clientFn, managerFn, num) + extends AdapterNode(TLRationalImp)(clientFn, managerFn) case class TLRationalIdentityNode()(implicit valName: ValName) extends IdentityNode(TLRationalImp)() diff --git a/src/main/scala/tilelink/Splitter.scala b/src/main/scala/tilelink/Splitter.scala index f5da7e6c..74496c34 100644 --- a/src/main/scala/tilelink/Splitter.scala +++ b/src/main/scala/tilelink/Splitter.scala @@ -9,11 +9,9 @@ import freechips.rocketchip.diplomacy._ case class SplitterArg[T](newSize: Int, ports: Seq[T]) 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)( + managerFn: SplitterArg[TLManagerPortParameters] => Seq[TLManagerPortParameters])( implicit valName: ValName) - extends TLCustomNode(numClientPorts, numManagerPorts) + extends TLCustomNode { 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}") diff --git a/src/main/scala/tilelink/Xbar.scala b/src/main/scala/tilelink/Xbar.scala index 72b679ba..b9c39ac1 100644 --- a/src/main/scala/tilelink/Xbar.scala +++ b/src/main/scala/tilelink/Xbar.scala @@ -31,8 +31,6 @@ private case object ForceFanoutKey extends Field(ForceFanoutParams(false, false, class TLXbar(policy: TLArbiter.Policy = TLArbiter.roundRobin)(implicit p: Parameters) extends LazyModule { val node = TLNexusNode( - numClientPorts = 1 to 999, - numManagerPorts = 1 to 999, clientFn = { seq => seq(0).copy( minLatency = seq.map(_.minLatency).min, @@ -159,20 +157,20 @@ class TLXbar(policy: TLArbiter.Policy = TLArbiter.roundRobin)(implicit p: Parame val addressA = (in zip edgesIn) map { case (i, e) => e.address(i.a.bits) } val addressC = (in zip edgesIn) map { case (i, e) => e.address(i.c.bits) } - val requestAIO = Vec(addressA.map { i => Vec(outputPorts.map { o => o(i) }) }) - val requestCIO = Vec(addressC.map { i => Vec(outputPorts.map { o => o(i) }) }) - val requestBOI = Vec(out.map { o => Vec(inputIdRanges.map { i => i.contains(o.b.bits.source) }) }) - val requestDOI = Vec(out.map { o => Vec(inputIdRanges.map { i => i.contains(o.d.bits.source) }) }) - val requestEIO = Vec(in.map { i => Vec(outputIdRanges.map { o => o.map(_.contains(i.e.bits.sink)).getOrElse(Bool(false)) }) }) + val requestAIO = addressA.map { i => outputPorts.map { o => o(i) } } + val requestCIO = addressC.map { i => outputPorts.map { o => o(i) } } + val requestBOI = out.map { o => inputIdRanges.map { i => i.contains(o.b.bits.source) } } + val requestDOI = out.map { o => inputIdRanges.map { i => i.contains(o.d.bits.source) } } + val requestEIO = in.map { i => outputIdRanges.map { o => o.map(_.contains(i.e.bits.sink)).getOrElse(Bool(false)) } } - val beatsAI = Vec((in zip edgesIn) map { case (i, e) => e.numBeats1(i.a.bits) }) - val beatsBO = Vec((out zip edgesOut) map { case (o, e) => e.numBeats1(o.b.bits) }) - val beatsCI = Vec((in zip edgesIn) map { case (i, e) => e.numBeats1(i.c.bits) }) - val beatsDO = Vec((out zip edgesOut) map { case (o, e) => e.numBeats1(o.d.bits) }) - val beatsEI = Vec((in zip edgesIn) map { case (i, e) => e.numBeats1(i.e.bits) }) + val beatsAI = (in zip edgesIn) map { case (i, e) => e.numBeats1(i.a.bits) } + val beatsBO = (out zip edgesOut) map { case (o, e) => e.numBeats1(o.b.bits) } + val beatsCI = (in zip edgesIn) map { case (i, e) => e.numBeats1(i.c.bits) } + val beatsDO = (out zip edgesOut) map { case (o, e) => e.numBeats1(o.d.bits) } + val beatsEI = (in zip edgesIn) map { case (i, e) => e.numBeats1(i.e.bits) } // Which pairs support support transfers - 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]]) = if (x.isEmpty) Nil else 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) // Fanout the input sources to the output sinks