Skip to content
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
6 changes: 3 additions & 3 deletions src/main/scala/rocket/Configs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import chisel3.util._
import org.chipsalliance.cde.config._
import org.chipsalliance.diplomacy.lazymodule._

import freechips.rocketchip.prci.{SynchronousCrossing, AsynchronousCrossing, RationalCrossing, ClockCrossingType}
import freechips.rocketchip.prci.{SynchronousCrossing, AsynchronousCrossing, RationalCrossing, CreditedCrossing, ClockCrossingType}
import freechips.rocketchip.subsystem.{TilesLocated, NumTiles, HierarchicalLocation, RocketCrossingParams, SystemBusKey, CacheBlockBytes, RocketTileAttachParams, InSubsystem, InCluster, HierarchicalElementMasterPortParams, HierarchicalElementSlavePortParams, CBUS, CCBUS, ClustersLocated, TileAttachConfig, CloneTileAttachParams}
import freechips.rocketchip.tile.{RocketTileParams, RocketTileBoundaryBufferParams, FPUParams}
import freechips.rocketchip.util.{RationalDirection, Flexible}
Expand Down Expand Up @@ -305,12 +305,12 @@ class WithDefaultBtb extends RocketTileConfig(t => t.copy(btb = Some(BTBParams()
class WithNoBtb extends RocketTileConfig(_.copy(btb = None))

// Tile CDC configs
class WithCDC(crossingType: ClockCrossingType = SynchronousCrossing()) extends RocketCrossingConfig(_.copy(crossingType = crossingType))
class WithCDC(crossingType: ClockCrossingType = SynchronousCrossing(), mergedCredited: Boolean = false) extends RocketCrossingConfig(_.copy(crossingType = crossingType, forceMergedCreditedTLCrossings = mergedCredited))
class WithSeperateClockReset extends RocketCrossingConfig(_.copy(forceSeparateClockReset = true))
class WithSynchronousCDCs extends WithCDC(SynchronousCrossing())
class WithAsynchronousCDCs(depth: Int, sync: Int) extends WithCDC(AsynchronousCrossing(depth, sync))
class WithRationalCDCs(direction: RationalDirection = Flexible) extends WithCDC(RationalCrossing(direction))

class WithCreditedCDCs(mergedCredited: Boolean = false) extends WithCDC(CreditedCrossing(), mergedCredited)


class WithCloneRocketTiles(
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/subsystem/Configs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,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
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.trace.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 @@ -322,3 +321,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