Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "MergedCreditedCrossing" for TileLink channels #3645

Open
wants to merge 9 commits into
base: dev
Choose a base branch
from
17 changes: 12 additions & 5 deletions src/main/scala/prci/ClockCrossingType.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,29 @@ trait HasClockDomainCrossing extends HasDomainCrossing { this: LazyModule =>
}

/** Enumerates the types of clock crossings generally supported by Diplomatic bus protocols */
sealed trait ClockCrossingType extends CrossingType
trait ClockCrossingType extends CrossingType
{
def sameClock = this match {
case _: SynchronousCrossing | _: CreditedCrossing => true
case _ => false
}
def sameClock: Boolean
}

case object NoCrossing // converts to SynchronousCrossing(BufferParams.none) via implicit def in package
case class SynchronousCrossing(params: BufferParams = BufferParams.default) extends ClockCrossingType
{
def sameClock = true
}
case class RationalCrossing(direction: RationalDirection = FastToSlow) extends ClockCrossingType
{
def sameClock = false
}
case class AsynchronousCrossing(depth: Int = 8, sourceSync: Int = 3, sinkSync: Int = 3, safe: Boolean = true, narrow: Boolean = false) extends ClockCrossingType
{
def sameClock = false
def asSinkParams = AsyncQueueParams(depth, sinkSync, safe, narrow)
}
case class CreditedCrossing(sourceDelay: CreditedDelay, sinkDelay: CreditedDelay) extends ClockCrossingType
{
def sameClock = true
}

object CreditedCrossing {
def apply(delay: CreditedDelay): CreditedCrossing = CreditedCrossing(delay, delay.flip)
Expand Down
12 changes: 11 additions & 1 deletion src/main/scala/subsystem/Configs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import freechips.rocketchip.devices.debug.{DebugModuleKey, DefaultDebugModulePar
import freechips.rocketchip.devices.tilelink.{
BuiltInErrorDeviceParams, BootROMLocated, BootROMParams, CLINTKey, DevNullDevice, CLINTParams, PLICKey, PLICParams, DevNullParams
}
import freechips.rocketchip.prci.{SynchronousCrossing, AsynchronousCrossing, RationalCrossing, ClockCrossingType}
import freechips.rocketchip.prci.{SynchronousCrossing, AsynchronousCrossing, RationalCrossing, ClockCrossingType, CreditedCrossing}
import freechips.rocketchip.diplomacy.{
AddressSet, MonitorsEnabled,
}
Expand Down Expand Up @@ -517,6 +517,16 @@ class WithRationalRocketTiles extends Config((site, here, up) => {
}
})

class WithCreditedRocketTiles(mergedCredited: Boolean = false) extends Config((site, here, up) => {
case TilesLocated(location) => up(TilesLocated(location), site) map {
case tp: RocketTileAttachParams => tp.copy(crossingParams = tp.crossingParams.copy(
crossingType = CreditedCrossing(),
forceMergedCreditedTLCrossings = mergedCredited
))
case t => t
}
})

class WithEdgeDataBits(dataBits: Int) extends Config((site, here, up) => {
case MemoryBusKey => up(MemoryBusKey, site).copy(beatBytes = dataBits/8)
case ExtIn => up(ExtIn, site).map(_.copy(beatBytes = dataBits/8))
Expand Down
2 changes: 2 additions & 0 deletions src/main/scala/subsystem/HierarchicalElement.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ trait HierarchicalElementCrossingParamsLike {
def resetCrossingType: ResetCrossingType
/** Keep the element clock separate from the interconnect clock (e.g. even if they are synchronous to one another) */
def forceSeparateClockReset: Boolean
/** Used a MergedCreditedTLCrossing for credited TL crossings to save pins */
def forceMergedCreditedTLCrossings: Boolean
}

/** An interface for describing the parameterization of how a particular element port is connected to an interconnect */
Expand Down
10 changes: 7 additions & 3 deletions src/main/scala/subsystem/HierarchicalElementPRCIDomain.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import freechips.rocketchip.diplomacy.{DisableMonitors, FlipRendering}
import freechips.rocketchip.interrupts.{IntInwardNode, IntOutwardNode}
import freechips.rocketchip.prci.{ClockCrossingType, ResetCrossingType, ResetDomain, ClockSinkNode, ClockSinkParameters, ClockIdentityNode, FixedClockBroadcast, ClockDomain}
import freechips.rocketchip.tile.{RocketTile, TraceBundle}
import freechips.rocketchip.tilelink.{TLInwardNode, TLOutwardNode}
import freechips.rocketchip.tilelink.{TLInwardNode, TLOutwardNode, UseTLMergedCreditedCrossing}
import freechips.rocketchip.util.TraceCoreInterface

import freechips.rocketchip.tilelink.TLClockDomainCrossing
Expand Down Expand Up @@ -83,7 +83,9 @@ abstract class HierarchicalElementPRCIDomain[T <: BaseHierarchicalElement](
element { element.makeSlaveBoundaryBuffers(crossingType) }
}
val tlSlaveClockXing = this.crossIn(tlSlaveResetXing)
tlSlaveClockXing(crossingType)
tlSlaveClockXing(crossingType)(p.alterPartial {
case UseTLMergedCreditedCrossing => crossingParams.forceMergedCreditedTLCrossings
})
} } }

/** External code looking to connect the ports where this tile masters an interconnect
Expand All @@ -95,6 +97,8 @@ abstract class HierarchicalElementPRCIDomain[T <: BaseHierarchicalElement](
element_reset_domain.crossTLOut(element.masterNode)
} }
val tlMasterClockXing = this.crossOut(tlMasterResetXing)
tlMasterClockXing(crossingType)
tlMasterClockXing(crossingType)(p.alterPartial {
case UseTLMergedCreditedCrossing => crossingParams.forceMergedCreditedTLCrossings
})
}
}
3 changes: 2 additions & 1 deletion src/main/scala/subsystem/RocketSubsystem.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ case class RocketCrossingParams(
slave: HierarchicalElementSlavePortParams = HierarchicalElementSlavePortParams(),
mmioBaseAddressPrefixWhere: TLBusWrapperLocation = CBUS,
resetCrossingType: ResetCrossingType = NoResetCrossing(),
forceSeparateClockReset: Boolean = false
forceSeparateClockReset: Boolean = false,
forceMergedCreditedTLCrossings: Boolean = false
) extends HierarchicalElementCrossingParamsLike

case class RocketTileAttachParams(
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/tilelink/Arbiter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ abstract class DecoupledArbiterTest(
case (z, i) => (beatsLeftFromIdx(i), z)
}:_*)

count := count + 1.U
when (!io.finished) { count := count + 1.U }
io.finished := count >= txns.U
}

Expand Down
44 changes: 42 additions & 2 deletions src/main/scala/tilelink/Bundles.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ package freechips.rocketchip.tilelink
import chisel3._
import freechips.rocketchip.util._
import scala.collection.immutable.ListMap
import chisel3.util.Decoupled
import chisel3.util.DecoupledIO
import chisel3.util.{Decoupled, DecoupledIO, Valid}
import chisel3.reflect.DataMirror

abstract class TLBundleBase(val params: TLBundleParameters) extends Bundle
Expand Down Expand Up @@ -317,3 +316,44 @@ class TLCreditedBundle(params: TLBundleParameters) extends TLBundleBase(params)
val d = Flipped(CreditedIO(new TLBundleD(params)))
val e = CreditedIO(new TLBundleE(params))
}

class TLBundleACE(params: TLBundleParameters) extends TLBundleBase(params)
{
// fixed fields during multibeat:
val opcode = UInt(3.W)
val param = UInt(List(TLAtomics.width, TLPermissions.aWidth, TLPermissions.cWidth, TLHints.width).max.W)
val size = UInt(params.sizeBits.W)
val source = UInt(params.sourceBits.W) // from
val address = UInt(params.addressBits.W) // to
val sink = UInt(params.sinkBits.W) // to
val user = BundleMap(params.requestFields)
val echo = BundleMap(params.echoFields)
// variable fields during multibeat:
val mask = UInt((params.dataBits/8).W)
val data = UInt(params.dataBits.W)
val corrupt = Bool() // only applies to *Data messages
}

class TLBundleBD(params: TLBundleParameters) extends TLBundleBase(params)
{
// fixed fields during multibeat:
val opcode = UInt(3.W)
val param = UInt(TLPermissions.bdWidth.W) // cap perms
val size = UInt(params.sizeBits.W)
val source = UInt(params.sourceBits.W) // to
val address = UInt(params.addressBits.W) // from
val sink = UInt(params.sinkBits.W) // from
val denied = Bool() // implies corrupt iff *Data
val user = BundleMap(params.responseFields)
val echo = BundleMap(params.echoFields)
// variable fields during multibeat:
val mask = UInt((params.dataBits/8).W)
val data = UInt(params.dataBits.W)
val corrupt = Bool() // only applies to *Data messages
}

class TLMergedCreditedBundle(params: TLBundleParameters) extends TLBundleBase(params)
{
val eca = MultiCreditedIO(new TLBundleACE(params), 3)
val db = Flipped(MultiCreditedIO(new TLBundleBD(params), 2))
}
10 changes: 8 additions & 2 deletions src/main/scala/tilelink/CrossingHelper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,11 @@ case class TLInwardClockCrossingHelper(name: String, scope: LazyScope, node: TLI
node :*=* scope { TLRationalCrossingSink(direction.flip) :*=* TLRationalNameNode(name) } :*=* TLRationalNameNode(name) :*=* TLRationalCrossingSource()
case SynchronousCrossing(buffer) =>
node :*=* scope { TLBuffer(buffer) :*=* TLNameNode(name) } :*=* TLNameNode(name)
case CreditedCrossing(sourceDelay, sinkDelay) =>
case CreditedCrossing(sourceDelay, sinkDelay) => if (p(UseTLMergedCreditedCrossing)) {
node :*=* scope { TLMergedCreditedSink(sinkDelay) :*=* TLMergedCreditedNameNode(name) } :*=* TLMergedCreditedNameNode(name) :*=* TLMergedCreditedSource(sourceDelay)
} else {
node :*=* scope { TLCreditedSink(sinkDelay) :*=* TLCreditedNameNode(name) } :*=* TLCreditedNameNode(name) :*=* TLCreditedSource(sourceDelay)
}
}
}
}
Expand Down Expand Up @@ -63,8 +66,11 @@ case class TLOutwardClockCrossingHelper(name: String, scope: LazyScope, node: TL
TLRationalCrossingSink(direction) :*=* TLRationalNameNode(name) :*=* scope { TLRationalNameNode(name) :*=* TLRationalCrossingSource() } :*=* node
case SynchronousCrossing(buffer) =>
TLNameNode(name) :*=* scope { TLNameNode(name) :*=* TLBuffer(buffer) } :*=* node
case CreditedCrossing(sourceDelay, sinkDelay) =>
case CreditedCrossing(sourceDelay, sinkDelay) => if (p(UseTLMergedCreditedCrossing)) {
TLMergedCreditedSink(sinkDelay) :*=* TLMergedCreditedNameNode(name) :*=* scope { TLMergedCreditedNameNode(name) :*=* TLMergedCreditedSource(sourceDelay) } :*=* node
} else {
TLCreditedSink(sinkDelay) :*=* TLCreditedNameNode(name) :*=* scope { TLCreditedNameNode(name) :*=* TLCreditedSource(sourceDelay) } :*=* node
}
}
}
}
Expand Down
128 changes: 128 additions & 0 deletions src/main/scala/tilelink/MergedCredited.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package freechips.rocketchip.tilelink

import chisel3._
import chisel3.util._

import org.chipsalliance.cde.config._
import org.chipsalliance.diplomacy.lazymodule._

import freechips.rocketchip.diplomacy.{AddressSet}
import freechips.rocketchip.prci.{ClockCrossingType, CreditedCrossing}
import freechips.rocketchip.subsystem.CrossingWrapper
import freechips.rocketchip.util.{CreditedDelay, MultiCreditedIO}

case object UseTLMergedCreditedCrossing extends Field[Boolean](false)

class TLMergedCreditedSource(delay: TLMergedCreditedDelay)(implicit p: Parameters) extends LazyModule
{
val node = TLMergedCreditedSourceNode(delay)
override lazy val module = new Impl
class Impl extends LazyModuleImp(this) {
(node.in zip node.out) foreach { case ((in, edgeIn), (out, edgeOut)) =>
val tld = edgeOut.delay

val to_credited = Wire(Vec(3, Decoupled(new TLBundleACE(edgeIn.bundle))))
val from_credited = Wire(Vec(2, Decoupled(new TLBundleBD(edgeIn.bundle))))

out.eca <> MultiCreditedIO.fromSenders(to_credited, tld.ace.total).pipeline(delay.ace)
from_credited <> VecInit(out.db.pipeline(delay.bd).toReceivers(tld.bd.total))

Seq(in.e, in.c, in.a).zipWithIndex.foreach { case (channel, i) =>
val out = to_credited(i)
channel.ready := out.ready
out.valid := channel.valid
out.bits := DontCare
(out.bits: Data).waiveAll :<>= (channel.bits: Data).waiveAll
}

Seq(in.d, in.b).zipWithIndex.foreach { case (channel, i) =>
val out = from_credited(i)
out.ready := channel.ready
channel.valid := out.valid
(channel.bits: Data).waiveAll :<>= (out.bits: Data).waiveAll
}
}
}
}

object TLMergedCreditedSource {
def apply(delay: TLMergedCreditedDelay)(implicit p: Parameters): TLMergedCreditedSourceNode = {
val source = LazyModule(new TLMergedCreditedSource(delay))
source.node
}
def apply(delay: CreditedDelay)(implicit p: Parameters): TLMergedCreditedSourceNode = apply(TLMergedCreditedDelay(delay))
def apply()(implicit p: Parameters): TLMergedCreditedSourceNode = apply(CreditedDelay(1, 1))
}


class TLMergedCreditedSink(delay: TLMergedCreditedDelay)(implicit p: Parameters) extends LazyModule
{
val node = TLMergedCreditedSinkNode(delay)
override lazy val module = new Impl
class Impl extends LazyModuleImp(this) {
(node.in zip node.out) foreach { case ((in, edgeIn), (out, edgeOut)) =>
val tld = edgeIn.delay

val to_credited = Wire(Vec(2, Decoupled(new TLBundleBD(edgeOut.bundle))))
val from_credited = Wire(Vec(3, Decoupled(new TLBundleACE(edgeOut.bundle))))

in.db <> MultiCreditedIO.fromSenders(to_credited, tld.bd.total).pipeline(delay.bd)
from_credited <> in.eca.pipeline(delay.ace).toReceivers(tld.ace.total)

Seq(out.d, out.b).zipWithIndex.foreach { case (channel, i) =>
val in = to_credited(i)
channel.ready := in.ready
in.valid := channel.valid
in.bits := DontCare
(in.bits: Data).waiveAll :<>= (channel.bits: Data).waiveAll
}

Seq(out.e, out.c, out.a).zipWithIndex.foreach { case (channel, i) =>
val in = from_credited(i)
in.ready := channel.ready
channel.valid := in.valid
(channel.bits: Data).waiveAll :<>= (in.bits: Data).waiveAll
}
}
}
}

object TLMergedCreditedSink {
def apply(delay: TLMergedCreditedDelay)(implicit p: Parameters): TLMergedCreditedSinkNode = {
val sink = LazyModule(new TLMergedCreditedSink(delay))
sink.node
}
def apply(delay: CreditedDelay)(implicit p: Parameters): TLMergedCreditedSinkNode = apply(TLMergedCreditedDelay(delay))
def apply()(implicit p: Parameters): TLMergedCreditedSinkNode = apply(CreditedDelay(1, 1))
}

// Synthesizable unit tests
import freechips.rocketchip.unittest._

class TLRAMMergedCreditedCrossing(txns: Int, params: CreditedCrossing)(implicit p: Parameters) extends LazyModule {
val model = LazyModule(new TLRAMModel("MergedCreditedCrossing"))
val fuzz = LazyModule(new TLFuzzer(txns))
val island = LazyModule(new CrossingWrapper(params))
val ram = island { LazyModule(new TLRAM(AddressSet(0x0, 0x3ff))) }

island.crossTLIn(ram.node) := TLFragmenter(4, 256) := TLDelayer(0.1) := model.node := fuzz.node

lazy val module = new Impl
class Impl extends LazyModuleImp(this) with UnitTestModule {
io.finished := fuzz.module.io.finished
}
}

class TLRAMMergedCreditedCrossingTest(txns: Int = 5000, timeout: Int = 500000)(implicit p: Parameters) extends UnitTest(timeout) {
val u = p.alterPartial { case UseTLMergedCreditedCrossing => true }

val dut_1000 = Module(LazyModule(new TLRAMMergedCreditedCrossing(txns, CreditedCrossing(CreditedDelay(1, 0), CreditedDelay(0, 0)))(u)).module)
val dut_0100 = Module(LazyModule(new TLRAMMergedCreditedCrossing(txns, CreditedCrossing(CreditedDelay(0, 1), CreditedDelay(0, 0)))(u)).module)
val dut_0010 = Module(LazyModule(new TLRAMMergedCreditedCrossing(txns, CreditedCrossing(CreditedDelay(0, 0), CreditedDelay(1, 0)))(u)).module)
val dut_0001 = Module(LazyModule(new TLRAMMergedCreditedCrossing(txns, CreditedCrossing(CreditedDelay(0, 0), CreditedDelay(0, 1)))(u)).module)
val dut_1111 = Module(LazyModule(new TLRAMMergedCreditedCrossing(txns, CreditedCrossing(CreditedDelay(1, 1), CreditedDelay(1, 1)))(u)).module)

val duts = Seq(dut_1000, dut_0100, dut_0010, dut_0001, dut_1111)
duts.foreach { _.io.start := true.B }
io.finished := duts.map(_.io.finished).reduce(_ && _)
}
39 changes: 39 additions & 0 deletions src/main/scala/tilelink/Nodes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -192,3 +192,42 @@ case class TLCreditedSinkNode(delay: TLCreditedDelay)(implicit valName: ValName)
extends MixedAdapterNode(TLCreditedImp, TLImp)(
dFn = { p => p.base.v1copy(minLatency = 1) },
uFn = { p => TLCreditedManagerPortParameters(delay, p) }) with FormatNode[TLCreditedEdgeParameters, TLEdgeOut]

// Merged Credited version of TileLink channels
trait TLMergedCreditedFormatNode extends FormatNode[TLMergedCreditedEdgeParameters, TLMergedCreditedEdgeParameters]

object TLMergedCreditedImp extends SimpleNodeImp[TLMergedCreditedClientPortParameters, TLMergedCreditedManagerPortParameters, TLMergedCreditedEdgeParameters, TLMergedCreditedBundle]
{
def edge(pd: TLMergedCreditedClientPortParameters, pu: TLMergedCreditedManagerPortParameters, p: Parameters, sourceInfo: SourceInfo) = TLMergedCreditedEdgeParameters(pd, pu, p, sourceInfo)
def bundle(e: TLMergedCreditedEdgeParameters) = new TLMergedCreditedBundle(e.bundle)
def render(e: TLMergedCreditedEdgeParameters) = RenderedEdge(colour = "#ffff00" /* yellow */, e.delay.toString)

override def mixO(pd: TLMergedCreditedClientPortParameters, node: OutwardNode[TLMergedCreditedClientPortParameters, TLMergedCreditedManagerPortParameters, TLMergedCreditedBundle]): TLMergedCreditedClientPortParameters =
pd.copy(base = pd.base.v1copy(clients = pd.base.clients.map { c => c.v1copy (nodePath = node +: c.nodePath) }))
override def mixI(pu: TLMergedCreditedManagerPortParameters, node: InwardNode[TLMergedCreditedClientPortParameters, TLMergedCreditedManagerPortParameters, TLMergedCreditedBundle]): TLMergedCreditedManagerPortParameters =
pu.copy(base = pu.base.v1copy(managers = pu.base.managers.map { m => m.v1copy (nodePath = node +: m.nodePath) }))
}

case class TLMergedCreditedAdapterNode(
clientFn: TLMergedCreditedClientPortParameters => TLMergedCreditedClientPortParameters = { s => s },
managerFn: TLMergedCreditedManagerPortParameters => TLMergedCreditedManagerPortParameters = { s => s })(
implicit valName: ValName)
extends AdapterNode(TLMergedCreditedImp)(clientFn, managerFn) with TLMergedCreditedFormatNode

case class TLMergedCreditedIdentityNode()(implicit valName: ValName) extends IdentityNode(TLMergedCreditedImp)() with TLMergedCreditedFormatNode

object TLMergedCreditedNameNode {
def apply(name: ValName) = TLMergedCreditedIdentityNode()(name)
def apply(name: Option[String]): TLMergedCreditedIdentityNode = apply(ValName(name.getOrElse("with_no_name")))
def apply(name: String): TLMergedCreditedIdentityNode = apply(Some(name))
}

case class TLMergedCreditedSourceNode(delay: TLMergedCreditedDelay)(implicit valName: ValName)
extends MixedAdapterNode(TLImp, TLMergedCreditedImp)(
dFn = { p => TLMergedCreditedClientPortParameters(delay, p) },
uFn = { p => p.base.v1copy(minLatency = 1) }) with FormatNode[TLEdgeIn, TLMergedCreditedEdgeParameters] // discard cycles from other clock domain

case class TLMergedCreditedSinkNode(delay: TLMergedCreditedDelay)(implicit valName: ValName)
extends MixedAdapterNode(TLMergedCreditedImp, TLImp)(
dFn = { p => p.base.v1copy(minLatency = 1) },
uFn = { p => TLMergedCreditedManagerPortParameters(delay, p) }) with FormatNode[TLMergedCreditedEdgeParameters, TLEdgeOut]
Loading
Loading