Merge pull request #1065 from freechipsproject/better-bus-wrappers
Better crossings deployed to bus and tile wrappers
This commit is contained in:
commit
91d8a97f1a
@ -6,7 +6,7 @@ import Chisel._
|
||||
import freechips.rocketchip.config.Parameters
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.regmapper._
|
||||
import freechips.rocketchip.tilelink.{IntSourceNode, IntSourcePortSimple}
|
||||
import freechips.rocketchip.interrupts.{IntSourceNode, IntSourcePortSimple}
|
||||
import freechips.rocketchip.util.{HeterogeneousBag, MaskGen}
|
||||
import scala.math.{min,max}
|
||||
|
||||
|
@ -6,7 +6,7 @@ import Chisel._
|
||||
import freechips.rocketchip.config.Parameters
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.regmapper._
|
||||
import freechips.rocketchip.tilelink.{IntSourceNode, IntSourcePortSimple}
|
||||
import freechips.rocketchip.interrupts.{IntSourceNode, IntSourcePortSimple}
|
||||
import freechips.rocketchip.util.HeterogeneousBag
|
||||
import scala.math.{min,max}
|
||||
|
||||
|
@ -8,6 +8,7 @@ import freechips.rocketchip.config.Parameters
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.tilelink._
|
||||
import freechips.rocketchip.util._
|
||||
import freechips.rocketchip.coreplex.{CrossingWrapper, AsynchronousCrossing}
|
||||
|
||||
class AXI4AsyncCrossingSource(sync: Int = 3)(implicit p: Parameters) extends LazyModule
|
||||
{
|
||||
@ -61,6 +62,7 @@ object AXI4AsyncCrossingSink
|
||||
}
|
||||
}
|
||||
|
||||
@deprecated("AXI4AsyncCrossing is fragile. Use AXI4AsyncCrossingSource and AXI4AsyncCrossingSink", "rocket-chip 1.2")
|
||||
class AXI4AsyncCrossing(depth: Int = 8, sync: Int = 3)(implicit p: Parameters) extends LazyModule
|
||||
{
|
||||
val source = LazyModule(new AXI4AsyncCrossingSource(sync))
|
||||
@ -89,28 +91,21 @@ import freechips.rocketchip.unittest._
|
||||
|
||||
class AXI4RAMAsyncCrossing(txns: Int)(implicit p: Parameters) extends LazyModule {
|
||||
val model = LazyModule(new TLRAMModel("AsyncCrossing"))
|
||||
val ram = LazyModule(new AXI4RAM(AddressSet(0x0, 0x3ff)))
|
||||
val fuzz = LazyModule(new TLFuzzer(txns))
|
||||
val toaxi = LazyModule(new TLToAXI4)
|
||||
val cross = LazyModule(new AXI4AsyncCrossing)
|
||||
val island = LazyModule(new CrossingWrapper(AsynchronousCrossing(8)))
|
||||
val ram = island { LazyModule(new AXI4RAM(AddressSet(0x0, 0x3ff))) }
|
||||
|
||||
model.node := fuzz.node
|
||||
toaxi.node := model.node
|
||||
cross.node := toaxi.node
|
||||
ram.node := cross.node
|
||||
ram.node := island.crossAXI4In := toaxi.node
|
||||
|
||||
lazy val module = new LazyModuleImp(this) with UnitTestModule {
|
||||
io.finished := fuzz.module.io.finished
|
||||
|
||||
// Shove the RAM into another clock domain
|
||||
val clocks = Module(new Pow2ClockDivider(2))
|
||||
ram.module.clock := clocks.io.clock_out
|
||||
|
||||
// ... and safely cross AXI42 into it
|
||||
cross.module.io.in_clock := clock
|
||||
cross.module.io.in_reset := reset
|
||||
cross.module.io.out_clock := clocks.io.clock_out
|
||||
cross.module.io.out_reset := reset
|
||||
island.module.clock := clocks.io.clock_out
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ import Chisel._
|
||||
import freechips.rocketchip.config.Parameters
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.regmapper._
|
||||
import freechips.rocketchip.tilelink.{IntSourceNode, IntSourcePortSimple}
|
||||
import freechips.rocketchip.interrupts.{IntSourceNode, IntSourcePortSimple}
|
||||
import freechips.rocketchip.util.{HeterogeneousBag, MaskGen}
|
||||
import scala.math.{min,max}
|
||||
|
||||
|
@ -3,10 +3,11 @@
|
||||
package freechips.rocketchip.amba
|
||||
|
||||
import Chisel._
|
||||
import freechips.rocketchip.diplomacy.OutwardNodeHandle
|
||||
import freechips.rocketchip.diplomacy._
|
||||
|
||||
package object axi4
|
||||
{
|
||||
type AXI4OutwardNode = OutwardNodeHandle[AXI4MasterPortParameters, AXI4SlavePortParameters, AXI4Bundle]
|
||||
type AXI4AsyncOutwardNode = OutwardNodeHandle[AXI4AsyncMasterPortParameters, AXI4AsyncSlavePortParameters, AXI4AsyncBundle]
|
||||
type AXI4Node = NodeHandle[AXI4MasterPortParameters, AXI4SlavePortParameters, AXI4Bundle, AXI4MasterPortParameters, AXI4SlavePortParameters, AXI4Bundle]
|
||||
}
|
||||
|
@ -5,18 +5,13 @@ package freechips.rocketchip.coreplex
|
||||
import Chisel._
|
||||
import freechips.rocketchip.config.Parameters
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.interrupts._
|
||||
import freechips.rocketchip.tilelink._
|
||||
import freechips.rocketchip.devices.tilelink._
|
||||
import freechips.rocketchip.tile.{BaseTile, TileParams, SharedMemoryTLEdge, HasExternallyDrivenTileConstants}
|
||||
import freechips.rocketchip.devices.debug.{HasPeripheryDebug, HasPeripheryDebugModuleImp}
|
||||
import freechips.rocketchip.util._
|
||||
|
||||
/** Enumerates the three types of clock crossing between tiles and system bus */
|
||||
sealed trait CoreplexClockCrossing
|
||||
case class SynchronousCrossing(params: BufferParams = BufferParams.default) extends CoreplexClockCrossing
|
||||
case class RationalCrossing(direction: RationalDirection = FastToSlow) extends CoreplexClockCrossing
|
||||
case class AsynchronousCrossing(depth: Int, sync: Int = 3) extends CoreplexClockCrossing
|
||||
|
||||
/** BareCoreplex is the root class for creating a coreplex sub-system */
|
||||
abstract class BareCoreplex(implicit p: Parameters) extends LazyModule with BindingScope {
|
||||
lazy val dts = DTS(bindingTree)
|
||||
|
192
src/main/scala/coreplex/CrossingWrapper.scala
Normal file
192
src/main/scala/coreplex/CrossingWrapper.scala
Normal file
@ -0,0 +1,192 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.coreplex
|
||||
|
||||
import Chisel._
|
||||
import freechips.rocketchip.config._
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.tilelink._
|
||||
import freechips.rocketchip.amba.axi4._
|
||||
import freechips.rocketchip.interrupts._
|
||||
import freechips.rocketchip.util._
|
||||
|
||||
/** Enumerates the three types of clock crossing between tiles and system bus */
|
||||
sealed trait CoreplexClockCrossing
|
||||
case class SynchronousCrossing(params: BufferParams = BufferParams.default) extends CoreplexClockCrossing
|
||||
case class RationalCrossing(direction: RationalDirection = FastToSlow) extends CoreplexClockCrossing
|
||||
case class AsynchronousCrossing(depth: Int, sync: Int = 3) extends CoreplexClockCrossing
|
||||
|
||||
private case class CrossingCheck(out: Boolean, source: BaseNode, sink: BaseNode)
|
||||
|
||||
trait HasCrossingMethods extends LazyModule with LazyScope
|
||||
{
|
||||
// Detect incorrect crossing connectivity
|
||||
|
||||
private var checks: List[CrossingCheck] = Nil
|
||||
private def inside(node: BaseNode) = node.parents.exists(_ eq this)
|
||||
override def instantiate() {
|
||||
super.instantiate()
|
||||
checks.foreach { case CrossingCheck(out, source, sink) =>
|
||||
source.inputs.foreach { case (syncSource, _) =>
|
||||
require (inside(syncSource) == out, s"${syncSource.name} must ${if(out)""else"not "}be inside ${name} (wrong .cross direction?)")
|
||||
}
|
||||
sink.outputs.foreach { case (syncSink, _) =>
|
||||
require (inside(syncSink) != out, s"${syncSink.name} must ${if(out)"not "else""}be inside ${name} (wrong .cross direction?)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TileLink
|
||||
|
||||
def crossTLSyncInOut(out: Boolean)(params: BufferParams = BufferParams.default)(implicit p: Parameters): TLNode = {
|
||||
val node = this { LazyModule(new TLBuffer(params)).node }
|
||||
checks = CrossingCheck(out, node, node) :: checks
|
||||
node
|
||||
}
|
||||
|
||||
def crossTLAsyncInOut(out: Boolean)(depth: Int = 8, sync: Int = 3)(implicit p: Parameters): TLNode = {
|
||||
def sourceGen = LazyModule(new TLAsyncCrossingSource(sync))
|
||||
def sinkGen = LazyModule(new TLAsyncCrossingSink(depth, sync))
|
||||
val source = if (out) this { sourceGen } else sourceGen
|
||||
val sink = if (out) sinkGen else this { sinkGen }
|
||||
sink.node :=? source.node
|
||||
checks = CrossingCheck(out, source.node, sink.node) :: checks
|
||||
NodeHandle(source.node, sink.node)
|
||||
}
|
||||
|
||||
def crossTLRationalInOut(out: Boolean)(direction: RationalDirection)(implicit p: Parameters): TLNode = {
|
||||
def sourceGen = LazyModule(new TLRationalCrossingSource)
|
||||
def sinkGen = LazyModule(new TLRationalCrossingSink(if (out) direction else direction.flip))
|
||||
val source = if (out) this { sourceGen } else sourceGen
|
||||
val sink = if (out) sinkGen else this { sinkGen }
|
||||
sink.node :=? source.node
|
||||
checks = CrossingCheck(out, source.node, sink.node) :: checks
|
||||
NodeHandle(source.node, sink.node)
|
||||
}
|
||||
|
||||
def crossTLSyncIn (params: BufferParams = BufferParams.default)(implicit p: Parameters): TLNode = crossTLSyncInOut(false)(params)
|
||||
def crossTLSyncOut(params: BufferParams = BufferParams.default)(implicit p: Parameters): TLNode = crossTLSyncInOut(true )(params)
|
||||
def crossTLAsyncIn (depth: Int = 8, sync: Int = 3)(implicit p: Parameters): TLNode = crossTLAsyncInOut(false)(depth, sync)
|
||||
def crossTLAsyncOut(depth: Int = 8, sync: Int = 3)(implicit p: Parameters): TLNode = crossTLAsyncInOut(true )(depth, sync)
|
||||
def crossTLRationalIn (direction: RationalDirection)(implicit p: Parameters): TLNode = crossTLRationalInOut(false)(direction)
|
||||
def crossTLRationalOut(direction: RationalDirection)(implicit p: Parameters): TLNode = crossTLRationalInOut(true )(direction)
|
||||
|
||||
def crossTLIn(arg: CoreplexClockCrossing)(implicit p: Parameters): TLNode = arg match {
|
||||
case x: SynchronousCrossing => crossTLSyncIn(x.params)
|
||||
case x: AsynchronousCrossing => crossTLAsyncIn(x.depth, x.sync)
|
||||
case x: RationalCrossing => crossTLRationalIn(x.direction)
|
||||
}
|
||||
|
||||
def crossTLOut(arg: CoreplexClockCrossing)(implicit p: Parameters): TLNode = arg match {
|
||||
case x: SynchronousCrossing => crossTLSyncOut(x.params)
|
||||
case x: AsynchronousCrossing => crossTLAsyncOut(x.depth, x.sync)
|
||||
case x: RationalCrossing => crossTLRationalOut(x.direction)
|
||||
}
|
||||
|
||||
// AXI4
|
||||
|
||||
def crossAXI4SyncInOut(out: Boolean)(params: BufferParams = BufferParams.default)(implicit p: Parameters): AXI4Node = {
|
||||
val node = this { LazyModule(new AXI4Buffer(params)).node }
|
||||
checks = CrossingCheck(out, node, node) :: checks
|
||||
node
|
||||
}
|
||||
|
||||
def crossAXI4AsyncInOut(out: Boolean)(depth: Int = 8, sync: Int = 3)(implicit p: Parameters): AXI4Node = {
|
||||
def sourceGen = LazyModule(new AXI4AsyncCrossingSource(sync))
|
||||
def sinkGen = LazyModule(new AXI4AsyncCrossingSink(depth, sync))
|
||||
val source = if (out) this { sourceGen } else sourceGen
|
||||
val sink = if (out) sinkGen else this { sinkGen }
|
||||
sink.node :=? source.node
|
||||
checks = CrossingCheck(out, source.node, sink.node) :: checks
|
||||
NodeHandle(source.node, sink.node)
|
||||
}
|
||||
|
||||
def crossAXI4SyncIn (params: BufferParams = BufferParams.default)(implicit p: Parameters): AXI4Node = crossAXI4SyncInOut(false)(params)
|
||||
def crossAXI4SyncOut(params: BufferParams = BufferParams.default)(implicit p: Parameters): AXI4Node = crossAXI4SyncInOut(true )(params)
|
||||
def crossAXI4AsyncIn (depth: Int = 8, sync: Int = 3)(implicit p: Parameters): AXI4Node = crossAXI4AsyncInOut(false)(depth, sync)
|
||||
def crossAXI4AsyncOut(depth: Int = 8, sync: Int = 3)(implicit p: Parameters): AXI4Node = crossAXI4AsyncInOut(true )(depth, sync)
|
||||
|
||||
def crossAXI4In(arg: CoreplexClockCrossing)(implicit p: Parameters): AXI4Node = arg match {
|
||||
case x: SynchronousCrossing => crossAXI4SyncIn(x.params)
|
||||
case x: AsynchronousCrossing => crossAXI4AsyncIn(x.depth, x.sync)
|
||||
case x: RationalCrossing => throw new IllegalArgumentException("AXI4 Rational crossing unimplemented")
|
||||
}
|
||||
|
||||
def crossAXI4Out(arg: CoreplexClockCrossing)(implicit p: Parameters): AXI4Node = arg match {
|
||||
case x: SynchronousCrossing => crossAXI4SyncOut(x.params)
|
||||
case x: AsynchronousCrossing => crossAXI4AsyncOut(x.depth, x.sync)
|
||||
case x: RationalCrossing => throw new IllegalArgumentException("AXI4 Rational crossing unimplemented")
|
||||
}
|
||||
|
||||
// Interrupts
|
||||
|
||||
def crossIntSyncInOut(out: Boolean)(alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = {
|
||||
def sourceGen = LazyModule(new IntSyncCrossingSource(alreadyRegistered))
|
||||
def sinkGen = LazyModule(new IntSyncCrossingSink(0))
|
||||
val source = if (out) this { sourceGen } else sourceGen
|
||||
val sink = if (out) sinkGen else this { sinkGen }
|
||||
sink.node :=? source.node
|
||||
checks = CrossingCheck(out, source.node, sink.node) :: checks
|
||||
NodeHandle(source.node, sink.node)
|
||||
}
|
||||
|
||||
def crossIntAsyncInOut(out: Boolean)(sync: Int = 3, alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = {
|
||||
def sourceGen = LazyModule(new IntSyncCrossingSource(alreadyRegistered))
|
||||
def sinkGen = LazyModule(new IntSyncCrossingSink(sync))
|
||||
val source = if (out) this { sourceGen } else sourceGen
|
||||
val sink = if (out) sinkGen else this { sinkGen }
|
||||
sink.node :=? source.node
|
||||
checks = CrossingCheck(out, source.node, sink.node) :: checks
|
||||
NodeHandle(source.node, sink.node)
|
||||
}
|
||||
|
||||
def crossIntRationalInOut(out: Boolean)(alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = {
|
||||
def sourceGen = LazyModule(new IntSyncCrossingSource(alreadyRegistered))
|
||||
def sinkGen = LazyModule(new IntSyncCrossingSink(1))
|
||||
val source = if (out) this { sourceGen } else sourceGen
|
||||
val sink = if (out) sinkGen else this { sinkGen }
|
||||
sink.node :=? source.node
|
||||
checks = CrossingCheck(out, source.node, sink.node) :: checks
|
||||
NodeHandle(source.node, sink.node)
|
||||
}
|
||||
|
||||
def crossIntSyncIn (alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = crossIntSyncInOut(false)(alreadyRegistered)
|
||||
def crossIntSyncOut(alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = crossIntSyncInOut(true )(alreadyRegistered)
|
||||
def crossIntAsyncIn (sync: Int = 3, alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = crossIntAsyncInOut(false)(sync, alreadyRegistered)
|
||||
def crossIntAsyncOut(sync: Int = 3, alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = crossIntAsyncInOut(true )(sync, alreadyRegistered)
|
||||
def crossIntRationalIn (alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = crossIntRationalInOut(false)(alreadyRegistered)
|
||||
def crossIntRationalOut(alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = crossIntRationalInOut(true )(alreadyRegistered)
|
||||
|
||||
def crossIntIn(arg: CoreplexClockCrossing, alreadyRegistered: Boolean)(implicit p: Parameters): IntNode = arg match {
|
||||
case x: SynchronousCrossing => crossIntSyncIn(alreadyRegistered)
|
||||
case x: AsynchronousCrossing => crossIntAsyncIn(x.sync, alreadyRegistered)
|
||||
case x: RationalCrossing => crossIntRationalIn(alreadyRegistered)
|
||||
}
|
||||
|
||||
def crossIntOut(arg: CoreplexClockCrossing, alreadyRegistered: Boolean)(implicit p: Parameters): IntNode = arg match {
|
||||
case x: SynchronousCrossing => crossIntSyncOut(alreadyRegistered)
|
||||
case x: AsynchronousCrossing => crossIntAsyncOut(x.sync, alreadyRegistered)
|
||||
case x: RationalCrossing => crossIntRationalOut(alreadyRegistered)
|
||||
}
|
||||
|
||||
def crossIntIn (arg: CoreplexClockCrossing)(implicit p: Parameters): IntNode = crossIntIn (arg, false)
|
||||
def crossIntOut(arg: CoreplexClockCrossing)(implicit p: Parameters): IntNode = crossIntOut(arg, false)
|
||||
}
|
||||
|
||||
trait HasCrossing extends HasCrossingMethods
|
||||
{
|
||||
this: LazyModule =>
|
||||
val crossing: CoreplexClockCrossing
|
||||
|
||||
def crossTLIn (implicit p: Parameters): TLNode = crossTLIn (crossing)
|
||||
def crossTLOut (implicit p: Parameters): TLNode = crossTLOut (crossing)
|
||||
def crossAXI4In (implicit p: Parameters): AXI4Node= crossAXI4In (crossing)
|
||||
def crossAXI4Out(implicit p: Parameters): AXI4Node= crossAXI4Out(crossing)
|
||||
def crossIntIn (implicit p: Parameters): IntNode = crossIntIn (crossing)
|
||||
def crossIntOut (implicit p: Parameters): IntNode = crossIntOut (crossing)
|
||||
|
||||
def crossIntIn (alreadyRegistered: Boolean)(implicit p: Parameters): IntNode = crossIntIn (crossing, alreadyRegistered)
|
||||
def crossIntOut(alreadyRegistered: Boolean)(implicit p: Parameters): IntNode = crossIntOut(crossing, alreadyRegistered)
|
||||
}
|
||||
|
||||
class CrossingWrapper(val crossing: CoreplexClockCrossing)(implicit p: Parameters) extends SimpleLazyModule with HasCrossing
|
@ -28,16 +28,12 @@ class FrontBus(params: FrontBusParams)(implicit p: Parameters) extends TLBusWrap
|
||||
master_fixer.node :=* master_buffer.node
|
||||
inwardNode :=* master_fixer.node
|
||||
|
||||
def fromSyncPorts(addBuffers: Int = 0, name: Option[String] = None): TLInwardNode = {
|
||||
val (in, out) = bufferChain(addBuffers, name)
|
||||
master_buffer.node :=* out
|
||||
in
|
||||
def fromSyncPorts(addBuffers: Int = 0, name: Option[String] = None): TLInwardNode = SourceCardinality { implicit p =>
|
||||
TLBuffer.chain(addBuffers).foldLeft(master_buffer.node:TLInwardNode)(_ :=? _)
|
||||
}
|
||||
|
||||
def fromSyncMasters(addBuffers: Int = 0, name: Option[String] = None): TLInwardNode = {
|
||||
val (in, out) = bufferChain(addBuffers, name)
|
||||
master_buffer.node :=* out
|
||||
in
|
||||
def fromSyncMasters(addBuffers: Int = 0, name: Option[String] = None): TLInwardNode = SourceCardinality { implicit p =>
|
||||
TLBuffer.chain(addBuffers).foldLeft(master_buffer.node:TLInwardNode)(_ :=? _)
|
||||
}
|
||||
|
||||
def fromCoherentChip: TLInwardNode = inwardNode
|
||||
|
@ -5,7 +5,7 @@ package freechips.rocketchip.coreplex
|
||||
import Chisel._
|
||||
import freechips.rocketchip.config.{Field, Parameters}
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.tilelink._
|
||||
import freechips.rocketchip.interrupts._
|
||||
|
||||
/** Collects interrupts from internal and external devices and feeds them into the PLIC */
|
||||
class InterruptBusWrapper(implicit p: Parameters) {
|
||||
|
@ -31,35 +31,23 @@ class PeripheryBus(params: PeripheryBusParams)(implicit p: Parameters) extends T
|
||||
TLFragmenter(params.beatBytes, maxXferBytes)(outwardBufNode)
|
||||
}
|
||||
|
||||
def toSyncSlaves(adapt: () => TLNodeChain, name: Option[String]): TLOutwardNode = SinkCardinality { implicit p =>
|
||||
val adapters = adapt()
|
||||
adapters.in :=? outwardBufNode
|
||||
adapters.out
|
||||
}
|
||||
|
||||
def toAsyncSlaves(sync: Int, adapt: () => TLNodeChain, name: Option[String]): TLAsyncOutwardNode = SinkCardinality { implicit p =>
|
||||
val adapters = adapt()
|
||||
val source = LazyModule(new TLAsyncCrossingSource(sync))
|
||||
name.foreach{ n => source.suggestName(s"${busName}_${n}_TLAsyncCrossingSource")}
|
||||
adapters.in :=? outwardNode
|
||||
source.node :=? adapters.out
|
||||
source.node
|
||||
}
|
||||
|
||||
def toRationalSlaves(adapt: () => TLNodeChain, name: Option[String]): TLRationalOutwardNode = SinkCardinality { implicit p =>
|
||||
val adapters = adapt()
|
||||
val source = LazyModule(new TLRationalCrossingSource())
|
||||
name.foreach{ n => source.suggestName(s"${busName}_${n}_TLRationalCrossingSource")}
|
||||
adapters.in :=? outwardNode
|
||||
source.node :=? adapters.out
|
||||
source.node
|
||||
}
|
||||
|
||||
val fromSystemBus: TLInwardNode = {
|
||||
val atomics = LazyModule(new TLAtomicAutomata(arithmetic = params.arithmetic))
|
||||
inwardBufNode := atomics.node
|
||||
atomics.node
|
||||
}
|
||||
|
||||
def toTile(name: Option[String] = None)(gen: Parameters => TLInwardNode) {
|
||||
this {
|
||||
LazyScope(s"${busName}ToTile${name.getOrElse("")}") {
|
||||
SinkCardinality { implicit p =>
|
||||
FlipRendering { implicit p =>
|
||||
gen(p) :*= outwardNode
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides buses that serve as attachment points,
|
||||
|
@ -3,67 +3,54 @@
|
||||
package freechips.rocketchip.coreplex
|
||||
|
||||
import Chisel._
|
||||
import chisel3.internal.sourceinfo.SourceInfo
|
||||
import freechips.rocketchip.config.{Field, Parameters}
|
||||
import freechips.rocketchip.devices.tilelink._
|
||||
import freechips.rocketchip.devices.debug.{HasPeripheryDebug, HasPeripheryDebugModuleImp}
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.tile._
|
||||
import freechips.rocketchip.tilelink._
|
||||
import freechips.rocketchip.interrupts._
|
||||
import freechips.rocketchip.util._
|
||||
|
||||
case class TLNodeChain(in: TLInwardNode, out: TLOutwardNode)
|
||||
|
||||
// TODO: how specific are these to RocketTiles?
|
||||
case class TileMasterPortParams(
|
||||
addBuffers: Int = 0,
|
||||
blockerCtrlAddr: Option[BigInt] = None,
|
||||
cork: Option[Boolean] = None) {
|
||||
def adapterChain(coreplex: HasPeripheryBus)
|
||||
(implicit p: Parameters): () => TLNodeChain = {
|
||||
|
||||
val blockerParams = blockerCtrlAddr.map(BasicBusBlockerParams(_, coreplex.pbus.beatBytes, coreplex.sbus.beatBytes, deadlock = true))
|
||||
|
||||
def adapt(coreplex: HasPeripheryBus)
|
||||
(masterNode: TLOutwardNode)
|
||||
(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = {
|
||||
val tile_master_cork = cork.map(u => (LazyModule(new TLCacheCork(unsafe = u))))
|
||||
val tile_master_blocker = blockerParams.map(bp => LazyModule(new BasicBusBlocker(bp)))
|
||||
val tile_master_blocker =
|
||||
blockerCtrlAddr
|
||||
.map(BasicBusBlockerParams(_, coreplex.pbus.beatBytes, coreplex.sbus.beatBytes, deadlock = true))
|
||||
.map(bp => LazyModule(new BasicBusBlocker(bp)))
|
||||
val tile_master_fixer = LazyModule(new TLFIFOFixer(TLFIFOFixer.allUncacheable))
|
||||
val tile_master_buffer = LazyModule(new TLBufferChain(addBuffers))
|
||||
|
||||
tile_master_blocker.foreach { _.controlNode := coreplex.pbus.toVariableWidthSlaves }
|
||||
|
||||
val nodes = List(
|
||||
Some(tile_master_buffer.node),
|
||||
Some(tile_master_fixer.node),
|
||||
tile_master_blocker.map(_.node),
|
||||
tile_master_cork.map(_.node)
|
||||
).flatMap(b=>b)
|
||||
|
||||
nodes.init zip nodes.tail foreach { case(front, back) => front :=* back }
|
||||
|
||||
() => TLNodeChain(in = nodes.last, out = nodes.head)
|
||||
(Seq(tile_master_fixer.node) ++ TLBuffer.chain(addBuffers)
|
||||
++ tile_master_blocker.map(_.node) ++ tile_master_cork.map(_.node))
|
||||
.foldRight(masterNode)(_ :=* _)
|
||||
}
|
||||
}
|
||||
|
||||
case class TileSlavePortParams(
|
||||
addBuffers: Int = 0,
|
||||
blockerCtrlAddr: Option[BigInt] = None) {
|
||||
def adapterChain(coreplex: HasPeripheryBus)
|
||||
(implicit p: Parameters): () => TLNodeChain = {
|
||||
|
||||
val blockerParams = blockerCtrlAddr.map(BasicBusBlockerParams(_, coreplex.pbus.beatBytes, coreplex.sbus.beatBytes))
|
||||
|
||||
val tile_slave_blocker = blockerParams.map(bp => LazyModule(new BasicBusBlocker(bp)))
|
||||
val tile_slave_buffer = LazyModule(new TLBufferChain(addBuffers))
|
||||
def adapt(coreplex: HasPeripheryBus)
|
||||
(slaveNode: TLInwardNode)
|
||||
(implicit p: Parameters, sourceInfo: SourceInfo): TLInwardNode = {
|
||||
val tile_slave_blocker =
|
||||
blockerCtrlAddr
|
||||
.map(BasicBusBlockerParams(_, coreplex.pbus.beatBytes, coreplex.sbus.beatBytes))
|
||||
.map(bp => LazyModule(new BasicBusBlocker(bp)))
|
||||
|
||||
tile_slave_blocker.foreach { _.controlNode := coreplex.pbus.toVariableWidthSlaves }
|
||||
|
||||
val nodes = List(
|
||||
Some(tile_slave_buffer.node),
|
||||
tile_slave_blocker.map(_.node)
|
||||
).flatMap(b=>b)
|
||||
|
||||
nodes.init zip nodes.tail foreach { case(front, back) => front :=* back }
|
||||
|
||||
() => TLNodeChain(in = nodes.last, out = nodes.head)
|
||||
(Seq() ++ tile_slave_blocker.map(_.node) ++ TLBuffer.chain(addBuffers))
|
||||
.foldLeft(slaveNode)(_ :*= _)
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,67 +82,55 @@ trait HasRocketTiles extends HasTiles
|
||||
case NumRocketTiles => crossingParams
|
||||
case _ => throw new Exception("RocketCrossingKey.size must == 1 or == RocketTilesKey.size")
|
||||
}
|
||||
private val crossingTuples = localIntNodes.zip(tileParams).zip(crossings)
|
||||
|
||||
// Make a wrapper for each tile that will wire it to coreplex devices and crossbars,
|
||||
// according to the specified type of clock crossing.
|
||||
private val crossingTuples = localIntNodes.zip(tileParams).zip(crossings)
|
||||
val tiles: Seq[BaseTile] = crossingTuples.map { case ((lip, tp), crossing) =>
|
||||
val pWithExtra = p.alterPartial {
|
||||
case TileKey => tp
|
||||
case BuildRoCC => tp.rocc
|
||||
case SharedMemoryTLEdge => sharedMemoryTLEdge
|
||||
case RocketCrossingKey => List(crossing)
|
||||
}
|
||||
// For legacy reasons, it is convenient to store some state
|
||||
// in the global Parameters about the specific tile being built now
|
||||
val wrapper = LazyModule(new RocketTileWrapper(
|
||||
params = tp,
|
||||
crossing = crossing.crossingType
|
||||
)(p.alterPartial {
|
||||
case TileKey => tp
|
||||
case BuildRoCC => tp.rocc
|
||||
case SharedMemoryTLEdge => sharedMemoryTLEdge
|
||||
case RocketCrossingKey => List(crossing)
|
||||
})
|
||||
).suggestName(tp.name)
|
||||
|
||||
val wrapper = crossing.crossingType match {
|
||||
case SynchronousCrossing(params) => {
|
||||
val wrapper = LazyModule(new SyncRocketTile(tp)(pWithExtra))
|
||||
sbus.fromSyncTiles(params, crossing.master.adapterChain(this), tp.name) :=* wrapper.masterNode
|
||||
FlipRendering { implicit p => wrapper.slaveNode :*= pbus.toSyncSlaves(crossing.slave.adapterChain(this), tp.name) }
|
||||
wrapper
|
||||
}
|
||||
case AsynchronousCrossing(depth, sync) => {
|
||||
val wrapper = LazyModule(new AsyncRocketTile(tp)(pWithExtra))
|
||||
sbus.fromAsyncTiles(depth, sync, crossing.master.adapterChain(this), tp.name) :=* wrapper.masterNode
|
||||
FlipRendering { implicit p => wrapper.slaveNode :*= pbus.toAsyncSlaves(sync, crossing.slave.adapterChain(this), tp.name) }
|
||||
wrapper
|
||||
}
|
||||
case RationalCrossing(direction) => {
|
||||
val wrapper = LazyModule(new RationalRocketTile(tp)(pWithExtra))
|
||||
sbus.fromRationalTiles(direction, crossing.master.adapterChain(this), tp.name) :=* wrapper.masterNode
|
||||
FlipRendering { implicit p => wrapper.slaveNode :*= pbus.toRationalSlaves(crossing.slave.adapterChain(this), tp.name) }
|
||||
wrapper
|
||||
}
|
||||
}
|
||||
tp.name.foreach(wrapper.suggestName) // Try to stabilize this name for downstream tools
|
||||
// Connect the master ports of the tile to the system bus
|
||||
sbus.fromTile(tp.name) { implicit p => crossing.master.adapt(this)(wrapper.crossTLOut :=* wrapper.masterNode) }
|
||||
|
||||
// Local Interrupts must be synchronized to the core clock
|
||||
// before being passed into this module.
|
||||
// This allows faster latency for interrupts which are already synchronized.
|
||||
// The CLINT and PLIC outputs interrupts that are synchronous to the periphery clock,
|
||||
// so may or may not need to be synchronized depending on the Tile's crossing type.
|
||||
// Debug interrupt is definitely asynchronous in all cases.
|
||||
val asyncIntXbar = LazyModule(new IntXbar)
|
||||
asyncIntXbar.suggestName("asyncIntXbar")
|
||||
asyncIntXbar.intnode := debug.intnode // debug
|
||||
wrapper.asyncIntNode := asyncIntXbar.intnode
|
||||
// Connect the slave ports of the tile to the periphery bus
|
||||
pbus.toTile(tp.name) { implicit p => crossing.slave.adapt(this)(wrapper.slaveNode :*= wrapper.crossTLIn) }
|
||||
|
||||
val periphIntXbar = LazyModule(new IntXbar)
|
||||
periphIntXbar.suggestName("periphIntXbar")
|
||||
periphIntXbar.intnode := clint.intnode // msip+mtip
|
||||
periphIntXbar.intnode := plic.intnode // meip
|
||||
if (tp.core.useVM) periphIntXbar.intnode := plic.intnode // seip
|
||||
wrapper.periphIntNode := periphIntXbar.intnode
|
||||
// Handle all the different types of interrupts crossing to or from the tile:
|
||||
// 1. Debug interrupt is definitely asynchronous in all cases.
|
||||
// 2. The CLINT and PLIC output interrupts are synchronous to the periphery clock,
|
||||
// so might need to be synchronized depending on the Tile's crossing type.
|
||||
// 3. Local Interrupts are required to already be synchronous to the tile clock.
|
||||
// 4. Interrupts coming out of the tile are sent to the PLIC,
|
||||
// so might need to be synchronized depending on the Tile's crossing type.
|
||||
// NOTE: The order of calls to := matters! They must match how interrupts
|
||||
// are decoded from rocket.intNode inside the tile.
|
||||
|
||||
val coreIntXbar = LazyModule(new IntXbar)
|
||||
coreIntXbar.suggestName("coreIntXbar")
|
||||
lip.foreach { coreIntXbar.intnode := _ } // lip
|
||||
wrapper.coreIntNode := coreIntXbar.intnode
|
||||
wrapper.intXbar.intnode := wrapper { IntSyncCrossingSink(3) } := debug.intnode // 1. always async crossign
|
||||
|
||||
wrapper.intOutputNode.foreach { case int =>
|
||||
val rocketIntXing = LazyModule(new IntXing(wrapper.outputInterruptXingLatency))
|
||||
FlipRendering { implicit p => rocketIntXing.intnode := int }
|
||||
plic.intnode := rocketIntXing.intnode
|
||||
// 2. clint+plic conditionak crossing
|
||||
val periphIntNode = SourceCardinality { implicit p => wrapper.intXbar.intnode :=? wrapper.crossIntIn }
|
||||
periphIntNode := clint.intnode // msip+mtip
|
||||
periphIntNode := plic.intnode // meip
|
||||
if (tp.core.useVM) periphIntNode := plic.intnode // seip
|
||||
|
||||
lip.foreach { wrapper.intXbar.intnode := _ } // 3. lip never crosses
|
||||
|
||||
// From core to PLIC
|
||||
wrapper.rocket.intOutputNode.foreach { i => // 4. conditional crossing
|
||||
FlipRendering { implicit p => SourceCardinality { implicit p =>
|
||||
plic.intnode :=? wrapper.crossIntOut :=? i
|
||||
} }
|
||||
}
|
||||
|
||||
wrapper
|
||||
|
@ -39,9 +39,7 @@ class SystemBus(params: SystemBusParams)(implicit p: Parameters) extends TLBusWr
|
||||
def toSplitSlaves: TLOutwardNode = outwardSplitNode
|
||||
|
||||
def toPeripheryBus(addBuffers: Int = 0): TLOutwardNode = {
|
||||
val (in, out) = bufferChain(addBuffers, name = Some("pbus"))
|
||||
in := pbus_fixer.node
|
||||
out
|
||||
TLBuffer.chain(addBuffers).foldRight(pbus_fixer.node:TLOutwardNode)(_ := _)
|
||||
}
|
||||
|
||||
val toMemoryBus: TLOutwardNode = outwardNode
|
||||
@ -52,34 +50,14 @@ class SystemBus(params: SystemBusParams)(implicit p: Parameters) extends TLBusWr
|
||||
|
||||
def fromFrontBus: TLInwardNode = master_splitter.node
|
||||
|
||||
def fromSyncTiles(params: BufferParams, adapt: () => TLNodeChain, name: Option[String] = None): TLInwardNode = {
|
||||
val adapters = adapt() // wanted to be called inside SystemBus scope
|
||||
val tile_sink = LazyModule(new TLBuffer(params))
|
||||
name.foreach { n => tile_sink.suggestName(s"${busName}_${n}_TLBuffer") }
|
||||
|
||||
adapters.in :=* tile_sink.node
|
||||
master_splitter.node :=* adapters.out
|
||||
tile_sink.node
|
||||
}
|
||||
|
||||
def fromRationalTiles(dir: RationalDirection, adapt: () => TLNodeChain, name: Option[String] = None): TLRationalInwardNode = {
|
||||
val adapters = adapt() // wanted to be called inside SystemBus scope
|
||||
val tile_sink = LazyModule(new TLRationalCrossingSink(direction = dir))
|
||||
name.foreach { n => tile_sink.suggestName(s"${busName}_${n}_TLRationalCrossingSink") }
|
||||
|
||||
adapters.in :=* tile_sink.node
|
||||
master_splitter.node :=* adapters.out
|
||||
tile_sink.node
|
||||
}
|
||||
|
||||
def fromAsyncTiles(depth: Int, sync: Int, adapt: () => TLNodeChain, name: Option[String] = None): TLAsyncInwardNode = {
|
||||
val adapters = adapt() // wanted to be called inside SystemBus scope
|
||||
val tile_sink = LazyModule(new TLAsyncCrossingSink(depth, sync))
|
||||
name.foreach { n => tile_sink.suggestName(s"${busName}_${n}_TLAsyncCrossingSink") }
|
||||
|
||||
adapters.in :=* tile_sink.node
|
||||
master_splitter.node :=* adapters.out
|
||||
tile_sink.node
|
||||
def fromTile(name: Option[String])(gen: Parameters => TLOutwardNode) {
|
||||
this {
|
||||
LazyScope(s"${busName}FromTile${name.getOrElse("")}") {
|
||||
SourceCardinality { implicit p =>
|
||||
master_splitter.node :=* gen(p)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def fromSyncPorts(params: BufferParams = BufferParams.default, name: Option[String] = None): TLInwardNode = {
|
||||
|
12
src/main/scala/coreplex/package.scala
Normal file
12
src/main/scala/coreplex/package.scala
Normal file
@ -0,0 +1,12 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip
|
||||
|
||||
import freechips.rocketchip.tilelink.TLOutwardNode
|
||||
import freechips.rocketchip.interrupts.IntOutwardNode
|
||||
|
||||
package object coreplex
|
||||
{
|
||||
implicit class TLCrossableNode(val node: TLOutwardNode)
|
||||
implicit class IntCrossableNode(val node: IntOutwardNode)
|
||||
}
|
@ -9,6 +9,7 @@ import freechips.rocketchip.regmapper._
|
||||
import freechips.rocketchip.rocket.Instructions
|
||||
import freechips.rocketchip.tile.XLen
|
||||
import freechips.rocketchip.tilelink._
|
||||
import freechips.rocketchip.interrupts._
|
||||
import freechips.rocketchip.util._
|
||||
|
||||
/** Constant values used by both Debug Bus Response & Request
|
||||
@ -392,7 +393,7 @@ class TLDebugModuleOuterAsync(device: Device)(implicit p: Parameters) extends La
|
||||
val dmiXbar = LazyModule (new TLXbar())
|
||||
|
||||
val dmOuter = LazyModule( new TLDebugModuleOuter(device))
|
||||
val intnode = dmOuter.intnode
|
||||
val intnode: IntSyncOutwardNode = IntSyncCrossingSource(alreadyRegistered = true) :*= dmOuter.intnode
|
||||
|
||||
val dmiInnerNode = TLAsyncCrossingSource()(dmiXbar.node)
|
||||
|
||||
@ -401,7 +402,7 @@ class TLDebugModuleOuterAsync(device: Device)(implicit p: Parameters) extends La
|
||||
|
||||
lazy val module = new LazyModuleImp(this) {
|
||||
|
||||
val nComponents = intnode.out.size
|
||||
val nComponents = dmOuter.intnode.edges.out.size
|
||||
|
||||
val io = IO(new Bundle {
|
||||
val dmi = new DMIIO()(p).flip()
|
||||
@ -1039,7 +1040,7 @@ class TLDebugModule(implicit p: Parameters) extends LazyModule {
|
||||
}
|
||||
|
||||
val dmOuter = LazyModule(new TLDebugModuleOuterAsync(device)(p))
|
||||
val dmInner = LazyModule(new TLDebugModuleInnerAsync(device, () => {intnode.edges.out.size})(p))
|
||||
val dmInner = LazyModule(new TLDebugModuleInnerAsync(device, () => {dmOuter.dmOuter.intnode.edges.out.size})(p))
|
||||
|
||||
val node = dmInner.tlNode
|
||||
val intnode = dmOuter.intnode
|
||||
@ -1047,7 +1048,7 @@ class TLDebugModule(implicit p: Parameters) extends LazyModule {
|
||||
dmInner.dmiNode := dmOuter.dmiInnerNode
|
||||
|
||||
lazy val module = new LazyModuleImp(this) {
|
||||
val nComponents = intnode.out.size
|
||||
val nComponents = dmOuter.dmOuter.intnode.edges.out.size
|
||||
|
||||
val io = IO(new Bundle {
|
||||
val ctrl = new DebugCtrlBundle(nComponents)
|
||||
|
@ -9,6 +9,7 @@ import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.regmapper._
|
||||
import freechips.rocketchip.tile.XLen
|
||||
import freechips.rocketchip.tilelink._
|
||||
import freechips.rocketchip.interrupts._
|
||||
import freechips.rocketchip.util._
|
||||
import scala.math.{min,max}
|
||||
|
||||
|
@ -10,6 +10,7 @@ import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.regmapper._
|
||||
import freechips.rocketchip.tile.XLen
|
||||
import freechips.rocketchip.tilelink._
|
||||
import freechips.rocketchip.interrupts._
|
||||
import freechips.rocketchip.util._
|
||||
import scala.math.min
|
||||
|
||||
|
@ -11,17 +11,26 @@ import scala.util.matching._
|
||||
|
||||
abstract class LazyModule()(implicit val p: Parameters)
|
||||
{
|
||||
protected[diplomacy] var bindings = List[() => Unit]()
|
||||
protected[diplomacy] var children = List[LazyModule]()
|
||||
protected[diplomacy] var nodes = List[BaseNode]()
|
||||
protected[diplomacy] var info: SourceInfo = UnlocatableSourceInfo
|
||||
protected[diplomacy] val parent = LazyModule.scope
|
||||
|
||||
def parents: Seq[LazyModule] = parent match {
|
||||
case None => Nil
|
||||
case Some(x) => x +: x.parents
|
||||
}
|
||||
|
||||
LazyModule.scope = Some(this)
|
||||
parent.foreach(p => p.children = this :: p.children)
|
||||
|
||||
// suggestedName accumulates Some(names), taking the final one. Nones are ignored.
|
||||
private var suggestedName: Option[String] = None
|
||||
def suggestName(x: String) = suggestedName = Some(x)
|
||||
def suggestName(x: String): this.type = suggestName(Some(x))
|
||||
def suggestName(x: Option[String]): this.type = {
|
||||
x.foreach { n => suggestedName = Some(n) }
|
||||
this
|
||||
}
|
||||
|
||||
private lazy val childNames =
|
||||
getClass.getMethods.filter { m =>
|
||||
@ -54,6 +63,7 @@ abstract class LazyModule()(implicit val p: Parameters)
|
||||
def name = valName.getOrElse(className)
|
||||
def line = sourceLine(info)
|
||||
|
||||
def instantiate() { } // a hook for running things in module scope (after children exist, but before dangles+auto exists)
|
||||
def module: LazyModuleImpLike
|
||||
|
||||
def omitGraphML: Boolean = !nodes.exists(!_.omitGraphML) && !children.exists(!_.omitGraphML)
|
||||
@ -154,6 +164,7 @@ sealed trait LazyModuleImpLike extends BaseModule
|
||||
implicit val sourceInfo = c.info
|
||||
Module(c.module).dangles
|
||||
}
|
||||
wrapper.instantiate()
|
||||
val nodeDangles = wrapper.nodes.reverse.flatMap(_.instantiate())
|
||||
val allDangles = nodeDangles ++ childDangles
|
||||
val pairing = SortedMap(allDangles.groupBy(_.source).toSeq:_*)
|
||||
@ -168,7 +179,6 @@ sealed trait LazyModuleImpLike extends BaseModule
|
||||
if (d.flipped) { d.data <> io } else { io <> d.data }
|
||||
d.copy(data = io, name = wrapper.valName.getOrElse("anon") + "_" + d.name)
|
||||
}
|
||||
wrapper.bindings.reverse.foreach { f => f () }
|
||||
(auto, dangles)
|
||||
}
|
||||
}
|
||||
|
@ -98,6 +98,8 @@ abstract class BaseNode(implicit val valName: ValName)
|
||||
def omitGraphML = outputs.isEmpty && inputs.isEmpty
|
||||
lazy val nodedebugstring: String = ""
|
||||
|
||||
def parents: Seq[LazyModule] = lazyModule +: lazyModule.parents
|
||||
|
||||
def wirePrefix = {
|
||||
val camelCase = "([a-z])([A-Z])".r
|
||||
val decamel = camelCase.replaceAllIn(valName.name, _ match { case camelCase(l, h) => l + "_" + h })
|
||||
@ -108,8 +110,8 @@ abstract class BaseNode(implicit val valName: ValName)
|
||||
|
||||
protected[diplomacy] def gci: Option[BaseNode] // greatest common inner
|
||||
protected[diplomacy] def gco: Option[BaseNode] // greatest common outer
|
||||
protected[diplomacy] def inputs: Seq[(BaseNode, RenderedEdge)]
|
||||
protected[diplomacy] def outputs: Seq[(BaseNode, RenderedEdge)]
|
||||
def inputs: Seq[(BaseNode, RenderedEdge)]
|
||||
def outputs: Seq[(BaseNode, RenderedEdge)]
|
||||
}
|
||||
|
||||
object BaseNode
|
||||
@ -117,22 +119,53 @@ object BaseNode
|
||||
protected[diplomacy] var serial = 0
|
||||
}
|
||||
|
||||
// !!! rename the nodes we bind?
|
||||
case class NodeHandle[DI, UI, BI <: Data, DO, UO, BO <: Data]
|
||||
trait NoHandle
|
||||
case object NoHandleObject extends NoHandle
|
||||
|
||||
trait NodeHandle[DI, UI, BI <: Data, DO, UO, BO <: Data]
|
||||
extends InwardNodeHandle[DI, UI, BI] with OutwardNodeHandle[DO, UO, BO]
|
||||
{
|
||||
// connecting two full nodes => full node
|
||||
override def := [DX, UX, BX <: Data](h: NodeHandle[DX, UX, BX, DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NodeHandle[DX, UX, BX, DO, UO, BO] = { bind(h, BIND_ONCE); NodeHandle(h, this) }
|
||||
override def :*= [DX, UX, BX <: Data](h: NodeHandle[DX, UX, BX, DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NodeHandle[DX, UX, BX, DO, UO, BO] = { bind(h, BIND_STAR); NodeHandle(h, this) }
|
||||
override def :=* [DX, UX, BX <: Data](h: NodeHandle[DX, UX, BX, DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NodeHandle[DX, UX, BX, DO, UO, BO] = { bind(h, BIND_QUERY); NodeHandle(h, this) }
|
||||
override def :=? [DX, UX, BX <: Data](h: NodeHandle[DX, UX, BX, DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NodeHandle[DX, UX, BX, DO, UO, BO] = { bind(h, p(CardinalityInferenceDirectionKey)); NodeHandle(h, this) }
|
||||
// connecting a full node with an output => an output
|
||||
override def := (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): OutwardNodeHandle[DO, UO, BO] = { bind(h, BIND_ONCE); this }
|
||||
override def :*= (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): OutwardNodeHandle[DO, UO, BO] = { bind(h, BIND_STAR); this }
|
||||
override def :=* (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): OutwardNodeHandle[DO, UO, BO] = { bind(h, BIND_QUERY); this }
|
||||
override def :=? (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): OutwardNodeHandle[DO, UO, BO] = { bind(h, p(CardinalityInferenceDirectionKey)); this }
|
||||
}
|
||||
|
||||
object NodeHandle
|
||||
{
|
||||
def apply[DI, UI, BI <: Data, DO, UO, BO <: Data](i: InwardNodeHandle[DI, UI, BI], o: OutwardNodeHandle[DO, UO, BO]) = NodeHandlePair(i, o)
|
||||
}
|
||||
|
||||
case class NodeHandlePair[DI, UI, BI <: Data, DO, UO, BO <: Data]
|
||||
(inwardHandle: InwardNodeHandle[DI, UI, BI], outwardHandle: OutwardNodeHandle[DO, UO, BO])
|
||||
extends Object with InwardNodeHandle[DI, UI, BI] with OutwardNodeHandle[DO, UO, BO]
|
||||
extends NodeHandle[DI, UI, BI, DO, UO, BO]
|
||||
{
|
||||
val inward = inwardHandle.inward
|
||||
val outward = outwardHandle.outward
|
||||
}
|
||||
|
||||
trait InwardNodeHandle[DI, UI, BI <: Data]
|
||||
trait InwardNodeHandle[DI, UI, BI <: Data] extends NoHandle
|
||||
{
|
||||
protected[diplomacy] val inward: InwardNode[DI, UI, BI]
|
||||
def := (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo) { inward.:=(h)(p, sourceInfo) }
|
||||
def :*= (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo) { inward.:*=(h)(p, sourceInfo) }
|
||||
def :=* (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo) { inward.:=*(h)(p, sourceInfo) }
|
||||
def :=? (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo) { inward.:=?(h)(p, sourceInfo) }
|
||||
def inward: InwardNode[DI, UI, BI]
|
||||
def parentsIn: Seq[LazyModule] = inward.parents
|
||||
def bind(h: OutwardNodeHandle[DI, UI, BI], binding: NodeBinding)(implicit p: Parameters, sourceInfo: SourceInfo): Unit = inward.bind(h.outward, binding)
|
||||
|
||||
// connecting an input node with a full nodes => an input node
|
||||
def := [DX, UX, BX <: Data](h: NodeHandle[DX, UX, BX, DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): InwardNodeHandle[DX, UX, BX] = { bind(h, BIND_ONCE); h }
|
||||
def :*= [DX, UX, BX <: Data](h: NodeHandle[DX, UX, BX, DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): InwardNodeHandle[DX, UX, BX] = { bind(h, BIND_STAR); h }
|
||||
def :=* [DX, UX, BX <: Data](h: NodeHandle[DX, UX, BX, DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): InwardNodeHandle[DX, UX, BX] = { bind(h, BIND_QUERY); h }
|
||||
def :=? [DX, UX, BX <: Data](h: NodeHandle[DX, UX, BX, DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): InwardNodeHandle[DX, UX, BX] = { bind(h, p(CardinalityInferenceDirectionKey)); h }
|
||||
// connecting input node with output node => no node
|
||||
def := (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NoHandle = { bind(h, BIND_ONCE); NoHandleObject }
|
||||
def :*= (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NoHandle = { bind(h, BIND_STAR); NoHandleObject }
|
||||
def :=* (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NoHandle = { bind(h, BIND_QUERY); NoHandleObject }
|
||||
def :=? (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): NoHandle = { bind(h, p(CardinalityInferenceDirectionKey)); NoHandleObject }
|
||||
}
|
||||
|
||||
sealed trait NodeBinding
|
||||
@ -140,9 +173,18 @@ case object BIND_ONCE extends NodeBinding
|
||||
case object BIND_QUERY extends NodeBinding
|
||||
case object BIND_STAR extends NodeBinding
|
||||
|
||||
object NodeBinding
|
||||
{
|
||||
implicit def apply(card: CardinalityInferenceDirection.T): NodeBinding = card match {
|
||||
case CardinalityInferenceDirection.SOURCE_TO_SINK => BIND_QUERY
|
||||
case CardinalityInferenceDirection.SINK_TO_SOURCE => BIND_STAR
|
||||
case CardinalityInferenceDirection.NO_INFERENCE => BIND_ONCE
|
||||
}
|
||||
}
|
||||
|
||||
trait InwardNode[DI, UI, BI <: Data] extends BaseNode with InwardNodeHandle[DI, UI, BI]
|
||||
{
|
||||
protected[diplomacy] val inward = this
|
||||
val inward = this
|
||||
|
||||
protected[diplomacy] val numPI: Range.Inclusive
|
||||
require (!numPI.isEmpty, s"No number of inputs would be acceptable to ${name}${lazyModule.line}")
|
||||
@ -165,16 +207,19 @@ trait InwardNode[DI, UI, BI <: Data] extends BaseNode with InwardNodeHandle[DI,
|
||||
protected[diplomacy] val iStar: Int
|
||||
protected[diplomacy] val iPortMapping: Seq[(Int, Int)]
|
||||
protected[diplomacy] val iParams: Seq[UI]
|
||||
|
||||
protected[diplomacy] def bind(h: OutwardNode[DI, UI, BI], binding: NodeBinding)(implicit p: Parameters, sourceInfo: SourceInfo): Unit
|
||||
}
|
||||
|
||||
trait OutwardNodeHandle[DO, UO, BO <: Data]
|
||||
trait OutwardNodeHandle[DO, UO, BO <: Data] extends NoHandle
|
||||
{
|
||||
protected[diplomacy] val outward: OutwardNode[DO, UO, BO]
|
||||
def outward: OutwardNode[DO, UO, BO]
|
||||
def parentsOut: Seq[LazyModule] = outward.parents
|
||||
}
|
||||
|
||||
trait OutwardNode[DO, UO, BO <: Data] extends BaseNode with OutwardNodeHandle[DO, UO, BO]
|
||||
{
|
||||
protected[diplomacy] val outward = this
|
||||
val outward = this
|
||||
|
||||
protected[diplomacy] val numPO: Range.Inclusive
|
||||
require (!numPO.isEmpty, s"No number of outputs would be acceptable to ${name}${lazyModule.line}")
|
||||
@ -211,7 +256,7 @@ sealed abstract class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](
|
||||
protected[diplomacy] val numPO: Range.Inclusive,
|
||||
protected[diplomacy] val numPI: Range.Inclusive)(
|
||||
implicit valName: ValName)
|
||||
extends BaseNode with InwardNode[DI, UI, BI] with OutwardNode[DO, UO, BO]
|
||||
extends BaseNode with NodeHandle[DI, UI, BI, DO, UO, BO] with InwardNode[DI, UI, BI] with OutwardNode[DO, UO, BO]
|
||||
{
|
||||
protected[diplomacy] def resolveStar(iKnown: Int, oKnown: Int, iStar: Int, oStar: Int): (Int, Int)
|
||||
protected[diplomacy] def mapParamsD(n: Int, p: Seq[DI]): Seq[DO]
|
||||
@ -337,9 +382,9 @@ sealed abstract class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](
|
||||
}
|
||||
|
||||
// connects the outward part of a node with the inward part of this node
|
||||
private def bind(h: OutwardNodeHandle[DI, UI, BI], binding: NodeBinding)(implicit p: Parameters, sourceInfo: SourceInfo) {
|
||||
protected[diplomacy] def bind(h: OutwardNode[DI, UI, BI], binding: NodeBinding)(implicit p: Parameters, sourceInfo: SourceInfo) {
|
||||
val x = this // x := y
|
||||
val y = h.outward
|
||||
val y = h
|
||||
val info = sourceLine(sourceInfo, " at ", "")
|
||||
val i = x.iPushed
|
||||
val o = y.oPushed
|
||||
@ -350,23 +395,12 @@ sealed abstract class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](
|
||||
x.iPush(o, y, binding)
|
||||
}
|
||||
|
||||
override def := (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo) = bind(h, BIND_ONCE)
|
||||
override def :*= (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo) = bind(h, BIND_STAR)
|
||||
override def :=* (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo) = bind(h, BIND_QUERY)
|
||||
override def :=? (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo) = {
|
||||
p(CardinalityInferenceDirectionKey) match {
|
||||
case CardinalityInferenceDirection.SOURCE_TO_SINK => this :=* h
|
||||
case CardinalityInferenceDirection.SINK_TO_SOURCE => this :*= h
|
||||
case CardinalityInferenceDirection.NO_INFERENCE => this := h
|
||||
}
|
||||
}
|
||||
|
||||
// meta-data for printing the node graph
|
||||
protected[diplomacy] def inputs = (iPorts zip edgesIn) map { case ((_, n, p, _), e) =>
|
||||
def inputs = (iPorts zip edgesIn) map { case ((_, n, p, _), e) =>
|
||||
val re = inner.render(e)
|
||||
(n, re.copy(flipped = re.flipped != p(RenderFlipped)))
|
||||
}
|
||||
protected[diplomacy] def outputs = oPorts map { case (i, n, _, _) => (n, n.inputs(i)._2) }
|
||||
def outputs = oPorts map { case (i, n, _, _) => (n, n.inputs(i)._2) }
|
||||
}
|
||||
|
||||
abstract class MixedCustomNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](
|
||||
|
@ -25,8 +25,8 @@ class GroundTestCoreplex(implicit p: Parameters) extends BaseCoreplex
|
||||
})
|
||||
)}
|
||||
|
||||
tiles.flatMap(_.dcacheOpt).foreach {
|
||||
sbus.fromSyncTiles(BufferParams.default, TileMasterPortParams().adapterChain(this)) :=* _.node
|
||||
tiles.flatMap(_.dcacheOpt).foreach { dc =>
|
||||
sbus.fromTile(None) { implicit p => TileMasterPortParams(addBuffers = 1).adapt(this)(dc.node) }
|
||||
}
|
||||
|
||||
val pbusRAM = LazyModule(new TLRAM(AddressSet(testRamAddr, 0xffff), true, false, pbus.beatBytes))
|
||||
|
12
src/main/scala/interrupts/Bundles.scala
Normal file
12
src/main/scala/interrupts/Bundles.scala
Normal file
@ -0,0 +1,12 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.interrupts
|
||||
|
||||
import Chisel._
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.util._
|
||||
|
||||
class SyncInterrupts(params: IntEdge) extends GenericParameterizedBundle(params)
|
||||
{
|
||||
val sync = Vec(params.source.num, Bool())
|
||||
}
|
58
src/main/scala/interrupts/Crossing.scala
Normal file
58
src/main/scala/interrupts/Crossing.scala
Normal file
@ -0,0 +1,58 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.interrupts
|
||||
|
||||
import Chisel._
|
||||
import freechips.rocketchip.config.Parameters
|
||||
import freechips.rocketchip.util.SynchronizerShiftReg
|
||||
import freechips.rocketchip.diplomacy._
|
||||
|
||||
@deprecated("IntXing does not ensure interrupt source is glitch free. Use IntSyncSource and IntSyncSink", "rocket-chip 1.2")
|
||||
class IntXing(sync: Int = 3)(implicit p: Parameters) extends LazyModule
|
||||
{
|
||||
val intnode = IntAdapterNode()
|
||||
|
||||
lazy val module = new LazyModuleImp(this) {
|
||||
(intnode.in zip intnode.out) foreach { case ((in, _), (out, _)) =>
|
||||
out := SynchronizerShiftReg(in, sync)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object IntSyncCrossingSource
|
||||
{
|
||||
def apply(alreadyRegistered: Boolean = false)(implicit p: Parameters) = LazyModule(new IntSyncCrossingSource(alreadyRegistered)).node
|
||||
}
|
||||
|
||||
|
||||
class IntSyncCrossingSource(alreadyRegistered: Boolean = false)(implicit p: Parameters) extends LazyModule
|
||||
{
|
||||
val node = IntSyncSourceNode(alreadyRegistered)
|
||||
|
||||
lazy val module = new LazyModuleImp(this) {
|
||||
(node.in zip node.out) foreach { case ((in, edgeIn), (out, edgeOut)) =>
|
||||
if (alreadyRegistered) {
|
||||
out.sync := in
|
||||
} else {
|
||||
out.sync := RegNext(in)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class IntSyncCrossingSink(sync: Int = 3)(implicit p: Parameters) extends LazyModule
|
||||
{
|
||||
val node = IntSyncSinkNode(sync)
|
||||
|
||||
lazy val module = new LazyModuleImp(this) {
|
||||
(node.in zip node.out) foreach { case ((in, edgeIn), (out, edgeOut)) =>
|
||||
out := SynchronizerShiftReg(in.sync, sync)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object IntSyncCrossingSink
|
||||
{
|
||||
def apply(sync: Int = 3)(implicit p: Parameters) = LazyModule(new IntSyncCrossingSink(sync)).node
|
||||
}
|
68
src/main/scala/interrupts/Nodes.scala
Normal file
68
src/main/scala/interrupts/Nodes.scala
Normal file
@ -0,0 +1,68 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.interrupts
|
||||
|
||||
import Chisel._
|
||||
import chisel3.internal.sourceinfo.SourceInfo
|
||||
import freechips.rocketchip.config.Parameters
|
||||
import freechips.rocketchip.diplomacy._
|
||||
|
||||
object IntImp extends SimpleNodeImp[IntSourcePortParameters, IntSinkPortParameters, IntEdge, Vec[Bool]]
|
||||
{
|
||||
def edge(pd: IntSourcePortParameters, pu: IntSinkPortParameters, p: Parameters, sourceInfo: SourceInfo) = IntEdge(pd, pu, p, sourceInfo)
|
||||
def bundle(e: IntEdge) = Vec(e.source.num, Bool())
|
||||
def render(e: IntEdge) = RenderedEdge(colour = "#0000ff" /* blue */, label = e.source.sources.map(_.range.size).sum.toString, flipped = true)
|
||||
|
||||
override def mixO(pd: IntSourcePortParameters, node: OutwardNode[IntSourcePortParameters, IntSinkPortParameters, Vec[Bool]]): IntSourcePortParameters =
|
||||
pd.copy(sources = pd.sources.map { s => s.copy (nodePath = node +: s.nodePath) })
|
||||
override def mixI(pu: IntSinkPortParameters, node: InwardNode[IntSourcePortParameters, IntSinkPortParameters, Vec[Bool]]): IntSinkPortParameters =
|
||||
pu.copy(sinks = pu.sinks.map { s => s.copy (nodePath = node +: s.nodePath) })
|
||||
}
|
||||
|
||||
case class IntSourceNode(portParams: Seq[IntSourcePortParameters])(implicit valName: ValName) extends SourceNode(IntImp)(portParams)
|
||||
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)(
|
||||
implicit valName: ValName)
|
||||
extends AdapterNode(IntImp)(sourceFn, sinkFn, num)
|
||||
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)(
|
||||
implicit valName: ValName)
|
||||
extends NexusNode(IntImp)(sourceFn, sinkFn, numSourcePorts, numSinkPorts)
|
||||
|
||||
object IntSyncImp extends SimpleNodeImp[IntSourcePortParameters, IntSinkPortParameters, IntEdge, SyncInterrupts]
|
||||
{
|
||||
def edge(pd: IntSourcePortParameters, pu: IntSinkPortParameters, p: Parameters, sourceInfo: SourceInfo) = IntEdge(pd, pu, p, sourceInfo)
|
||||
def bundle(e: IntEdge) = new SyncInterrupts(e)
|
||||
def render(e: IntEdge) = RenderedEdge(colour = "#ff00ff" /* purple */, label = e.source.sources.map(_.range.size).sum.toString, flipped = true)
|
||||
|
||||
override def mixO(pd: IntSourcePortParameters, node: OutwardNode[IntSourcePortParameters, IntSinkPortParameters, SyncInterrupts]): IntSourcePortParameters =
|
||||
pd.copy(sources = pd.sources.map { s => s.copy (nodePath = node +: s.nodePath) })
|
||||
override def mixI(pu: IntSinkPortParameters, node: InwardNode[IntSourcePortParameters, IntSinkPortParameters, SyncInterrupts]): IntSinkPortParameters =
|
||||
pu.copy(sinks = pu.sinks.map { s => s.copy (nodePath = node +: s.nodePath) })
|
||||
}
|
||||
|
||||
case class IntSyncIdentityNode()(implicit valName: ValName) extends IdentityNode(IntSyncImp)()
|
||||
|
||||
case class IntSyncSourceNode(alreadyRegistered: Boolean)(implicit valName: ValName)
|
||||
extends MixedAdapterNode(IntImp, IntSyncImp)(
|
||||
dFn = { p => p },
|
||||
uFn = { p => p })
|
||||
{
|
||||
override lazy val nodedebugstring = s"alreadyRegistered:${alreadyRegistered}"
|
||||
}
|
||||
|
||||
case class IntSyncSinkNode(sync: Int)(implicit valName: ValName)
|
||||
extends MixedAdapterNode(IntSyncImp, IntImp)(
|
||||
dFn = { p => p },
|
||||
uFn = { p => p })
|
||||
{
|
||||
override lazy val nodedebugstring = s"sync:${sync}"
|
||||
}
|
61
src/main/scala/interrupts/Parameters.scala
Normal file
61
src/main/scala/interrupts/Parameters.scala
Normal file
@ -0,0 +1,61 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.interrupts
|
||||
|
||||
import Chisel._
|
||||
import chisel3.internal.sourceinfo.SourceInfo
|
||||
import freechips.rocketchip.config.Parameters
|
||||
import freechips.rocketchip.diplomacy._
|
||||
|
||||
// A potentially empty half-open range; [start, end)
|
||||
case class IntRange(start: Int, end: Int)
|
||||
{
|
||||
require (start >= 0)
|
||||
require (start <= end)
|
||||
def size = end - start
|
||||
def overlaps(x: IntRange) = start < x.end && x.start < end
|
||||
def offset(x: Int) = IntRange(x+start, x+end)
|
||||
}
|
||||
|
||||
object IntRange
|
||||
{
|
||||
implicit def apply(end: Int): IntRange = apply(0, end)
|
||||
}
|
||||
|
||||
case class IntSourceParameters(
|
||||
range: IntRange,
|
||||
resources: Seq[Resource] = Seq(),
|
||||
nodePath: Seq[BaseNode] = Seq())
|
||||
{
|
||||
val name = nodePath.lastOption.map(_.lazyModule.name).getOrElse("disconnected")
|
||||
}
|
||||
|
||||
case class IntSinkParameters(
|
||||
nodePath: Seq[BaseNode] = Seq())
|
||||
{
|
||||
val name = nodePath.lastOption.map(_.lazyModule.name).getOrElse("disconnected")
|
||||
}
|
||||
|
||||
case class IntSourcePortParameters(sources: Seq[IntSourceParameters])
|
||||
{
|
||||
val num = sources.map(_.range.size).sum
|
||||
// The interrupts mapping must not overlap
|
||||
sources.map(_.range).combinations(2).foreach { case Seq(a, b) => require (!a.overlaps(b)) }
|
||||
// The interrupts must perfectly cover the range
|
||||
require (sources.isEmpty || sources.map(_.range.end).max == num)
|
||||
}
|
||||
object IntSourcePortSimple
|
||||
{
|
||||
def apply(num: Int = 1, ports: Int = 1, sources: Int = 1, resources: Seq[Resource] = Nil) =
|
||||
if (num == 0) Nil else
|
||||
Seq.fill(ports)(IntSourcePortParameters(Seq.fill(sources)(IntSourceParameters(range = IntRange(0, num), resources = resources))))
|
||||
}
|
||||
|
||||
case class IntSinkPortParameters(sinks: Seq[IntSinkParameters])
|
||||
object IntSinkPortSimple
|
||||
{
|
||||
def apply(ports: Int = 1, sinks: Int = 1) =
|
||||
Seq.fill(ports)(IntSinkPortParameters(Seq.fill(sinks)(IntSinkParameters())))
|
||||
}
|
||||
|
||||
case class IntEdge(source: IntSourcePortParameters, sink: IntSinkPortParameters, params: Parameters, sourceInfo: SourceInfo)
|
23
src/main/scala/interrupts/Xbar.scala
Normal file
23
src/main/scala/interrupts/Xbar.scala
Normal file
@ -0,0 +1,23 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.interrupts
|
||||
|
||||
import Chisel._
|
||||
import freechips.rocketchip.config.Parameters
|
||||
import freechips.rocketchip.diplomacy._
|
||||
|
||||
class IntXbar()(implicit p: Parameters) extends LazyModule
|
||||
{
|
||||
val intnode = IntNexusNode(
|
||||
sinkFn = { _ => IntSinkPortParameters(Seq(IntSinkParameters())) },
|
||||
sourceFn = { seq =>
|
||||
IntSourcePortParameters((seq zip seq.map(_.num).scanLeft(0)(_+_).init).map {
|
||||
case (s, o) => s.sources.map(z => z.copy(range = z.range.offset(o)))
|
||||
}.flatten)
|
||||
})
|
||||
|
||||
lazy val module = new LazyModuleImp(this) {
|
||||
val cat = intnode.in.map { case (i, e) => i.take(e.source.num) }.flatten
|
||||
intnode.out.foreach { case (o, _) => o := cat }
|
||||
}
|
||||
}
|
15
src/main/scala/interrupts/package.scala
Normal file
15
src/main/scala/interrupts/package.scala
Normal file
@ -0,0 +1,15 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip
|
||||
|
||||
import Chisel._
|
||||
import freechips.rocketchip.diplomacy._
|
||||
|
||||
package object interrupts
|
||||
{
|
||||
type IntInwardNode = InwardNodeHandle[IntSourcePortParameters, IntSinkPortParameters, Vec[Bool]]
|
||||
type IntOutwardNode = OutwardNodeHandle[IntSourcePortParameters, IntSinkPortParameters, Vec[Bool]]
|
||||
type IntNode = NodeHandle[IntSourcePortParameters, IntSinkPortParameters, Vec[Bool], IntSourcePortParameters, IntSinkPortParameters, Vec[Bool]]
|
||||
type IntSyncInwardNode = InwardNodeHandle[IntSourcePortParameters, IntSinkPortParameters, SyncInterrupts]
|
||||
type IntSyncOutwardNode = OutwardNodeHandle[IntSourcePortParameters, IntSinkPortParameters, SyncInterrupts]
|
||||
}
|
@ -11,6 +11,7 @@ import freechips.rocketchip.tile._
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.regmapper._
|
||||
import freechips.rocketchip.tilelink._
|
||||
import freechips.rocketchip.interrupts._
|
||||
|
||||
trait BusErrors extends Bundle {
|
||||
def toErrorList: List[Option[Valid[UInt]]]
|
||||
|
@ -10,6 +10,7 @@ import freechips.rocketchip.coreplex.CacheBlockBytes
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.tile._
|
||||
import freechips.rocketchip.tilelink._
|
||||
import freechips.rocketchip.interrupts._
|
||||
import freechips.rocketchip.util._
|
||||
|
||||
class ScratchpadSlavePort(address: AddressSet, coreDataBytes: Int, usingAtomics: Boolean)(implicit p: Parameters) extends LazyModule {
|
||||
|
@ -5,7 +5,7 @@ package freechips.rocketchip.tile
|
||||
import Chisel._
|
||||
|
||||
import freechips.rocketchip.config.Parameters
|
||||
import freechips.rocketchip.tilelink.{IntSinkNode, IntSinkPortSimple}
|
||||
import freechips.rocketchip.interrupts.{IntSinkNode, IntSinkPortSimple}
|
||||
import freechips.rocketchip.util._
|
||||
|
||||
class TileInterrupts(implicit p: Parameters) extends CoreBundle()(p) {
|
||||
|
@ -9,6 +9,7 @@ import freechips.rocketchip.coreplex._
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.rocket._
|
||||
import freechips.rocketchip.tilelink._
|
||||
import freechips.rocketchip.interrupts._
|
||||
import freechips.rocketchip.util._
|
||||
|
||||
case class RocketTileParams(
|
||||
@ -18,11 +19,12 @@ case class RocketTileParams(
|
||||
rocc: Seq[RoCCParams] = Nil,
|
||||
btb: Option[BTBParams] = Some(BTBParams()),
|
||||
dataScratchpadBytes: Int = 0,
|
||||
boundaryBuffers: Boolean = false,
|
||||
trace: Boolean = false,
|
||||
hcfOnUncorrectable: Boolean = false,
|
||||
name: Option[String] = Some("tile"),
|
||||
hartid: Int = 0) extends TileParams {
|
||||
hartid: Int = 0,
|
||||
boundaryBuffers: Boolean = false // if synthesized with hierarchical PnR, cut feed-throughs?
|
||||
) extends TileParams {
|
||||
require(icache.isDefined)
|
||||
require(dcache.isDefined)
|
||||
}
|
||||
@ -187,38 +189,44 @@ class RocketTileWrapperBundle[+L <: RocketTileWrapper](_outer: L) extends BaseTi
|
||||
val halt_and_catch_fire = _outer.rocket.module.io.halt_and_catch_fire.map(_.cloneType)
|
||||
}
|
||||
|
||||
abstract class RocketTileWrapper(rtp: RocketTileParams)(implicit p: Parameters) extends BaseTile(rtp) {
|
||||
val rocket = LazyModule(new RocketTile(rtp))
|
||||
val asyncIntNode : IntInwardNode
|
||||
val periphIntNode : IntInwardNode
|
||||
val coreIntNode : IntInwardNode
|
||||
val intOutputNode = rocket.intOutputNode
|
||||
class RocketTileWrapper(
|
||||
params: RocketTileParams,
|
||||
val crossing: CoreplexClockCrossing)
|
||||
(implicit p: Parameters) extends BaseTile(params) with HasCrossing {
|
||||
|
||||
val rocket = LazyModule(new RocketTile(params))
|
||||
|
||||
// The buffers needed to cut feed-through paths are microarchitecture specific, so belong here
|
||||
val masterBuffer = LazyModule(new TLBuffer(BufferParams.none, BufferParams.flow, BufferParams.none, BufferParams.flow, BufferParams(1)))
|
||||
val masterNode: TLOutwardNode = crossing match {
|
||||
case _: AsynchronousCrossing => rocket.masterNode
|
||||
case SynchronousCrossing(b) =>
|
||||
require (!params.boundaryBuffers || (b.depth >= 1 && !b.flow && !b.pipe), "Buffer misconfiguration creates feed-through paths")
|
||||
rocket.masterNode
|
||||
case RationalCrossing(dir) =>
|
||||
require (dir != SlowToFast, "Misconfiguration? Core slower than fabric")
|
||||
if (params.boundaryBuffers) {
|
||||
masterBuffer.node :=* rocket.masterNode
|
||||
} else {
|
||||
rocket.masterNode
|
||||
}
|
||||
}
|
||||
|
||||
val slaveBuffer = LazyModule(new TLBuffer(BufferParams.flow, BufferParams.none, BufferParams.none, BufferParams.none, BufferParams.none))
|
||||
val slaveNode: TLInwardNode = crossing match {
|
||||
case _: SynchronousCrossing => rocket.slaveNode // requirement already checked
|
||||
case _: AsynchronousCrossing => rocket.slaveNode
|
||||
case _: RationalCrossing =>
|
||||
if (params.boundaryBuffers) {
|
||||
DisableMonitors { implicit p => rocket.slaveNode :*= slaveBuffer.node }
|
||||
} else {
|
||||
rocket.slaveNode
|
||||
}
|
||||
}
|
||||
|
||||
val intXbar = LazyModule(new IntXbar)
|
||||
|
||||
rocket.intNode := intXbar.intnode
|
||||
|
||||
def optionalMasterBuffer(in: TLOutwardNode): TLOutwardNode = {
|
||||
if (rtp.boundaryBuffers) {
|
||||
val mbuf = LazyModule(new TLBuffer(BufferParams.none, BufferParams.flow, BufferParams.none, BufferParams.flow, BufferParams(1)))
|
||||
mbuf.node :=* in
|
||||
mbuf.node
|
||||
} else {
|
||||
in
|
||||
}
|
||||
}
|
||||
|
||||
def optionalSlaveBuffer(out: TLInwardNode): TLInwardNode = {
|
||||
if (rtp.boundaryBuffers) {
|
||||
val sbuf = LazyModule(new TLBuffer(BufferParams.flow, BufferParams.none, BufferParams.none, BufferParams.none, BufferParams.none))
|
||||
DisableMonitors { implicit p => out :*= sbuf.node }
|
||||
sbuf.node
|
||||
} else {
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
def outputInterruptXingLatency: Int
|
||||
|
||||
override lazy val module = new BaseTileModule(this, () => new RocketTileWrapperBundle(this)) {
|
||||
// signals that do not change based on crossing type:
|
||||
rocket.module.io.hartid := io.hartid
|
||||
@ -227,76 +235,3 @@ abstract class RocketTileWrapper(rtp: RocketTileParams)(implicit p: Parameters)
|
||||
io.halt_and_catch_fire.foreach { _ := rocket.module.io.halt_and_catch_fire.get }
|
||||
}
|
||||
}
|
||||
|
||||
class SyncRocketTile(rtp: RocketTileParams)(implicit p: Parameters) extends RocketTileWrapper(rtp) {
|
||||
val masterNode = optionalMasterBuffer(rocket.masterNode)
|
||||
val slaveNode = optionalSlaveBuffer(rocket.slaveNode)
|
||||
|
||||
// Fully async interrupts need synchronizers.
|
||||
// Others need no synchronization.
|
||||
val xing = LazyModule(new IntXing(3))
|
||||
val asyncIntNode = xing.intnode
|
||||
|
||||
val periphIntNode = IntIdentityNode()
|
||||
val coreIntNode = IntIdentityNode()
|
||||
|
||||
// order here matters
|
||||
intXbar.intnode := xing.intnode
|
||||
intXbar.intnode := periphIntNode
|
||||
intXbar.intnode := coreIntNode
|
||||
|
||||
def outputInterruptXingLatency = 0
|
||||
}
|
||||
|
||||
class AsyncRocketTile(rtp: RocketTileParams)(implicit p: Parameters) extends RocketTileWrapper(rtp) {
|
||||
val source = LazyModule(new TLAsyncCrossingSource)
|
||||
source.node :=* rocket.masterNode
|
||||
val masterNode = source.node
|
||||
|
||||
val sink = LazyModule(new TLAsyncCrossingSink)
|
||||
DisableMonitors { implicit p => rocket.slaveNode :*= sink.node }
|
||||
val slaveNode = sink.node
|
||||
|
||||
// Fully async interrupts need synchronizers,
|
||||
// as do those coming from the periphery clock.
|
||||
// Others need no synchronization.
|
||||
val asyncXing = LazyModule(new IntXing(3))
|
||||
val periphXing = LazyModule(new IntXing(3))
|
||||
val asyncIntNode = asyncXing.intnode
|
||||
val periphIntNode = periphXing.intnode
|
||||
val coreIntNode = IntIdentityNode()
|
||||
|
||||
// order here matters
|
||||
intXbar.intnode := asyncXing.intnode
|
||||
intXbar.intnode := periphXing.intnode
|
||||
intXbar.intnode := coreIntNode
|
||||
|
||||
def outputInterruptXingLatency = 3
|
||||
}
|
||||
|
||||
class RationalRocketTile(rtp: RocketTileParams)(implicit p: Parameters) extends RocketTileWrapper(rtp) {
|
||||
val source = LazyModule(new TLRationalCrossingSource)
|
||||
source.node :=* optionalMasterBuffer(rocket.masterNode)
|
||||
val masterNode = source.node
|
||||
|
||||
val sink = LazyModule(new TLRationalCrossingSink(SlowToFast))
|
||||
DisableMonitors { implicit p => optionalSlaveBuffer(rocket.slaveNode) :*= sink.node }
|
||||
val slaveNode = sink.node
|
||||
|
||||
// Fully async interrupts need synchronizers.
|
||||
// Those coming from periphery clock need a
|
||||
// rational synchronizer.
|
||||
// Others need no synchronization.
|
||||
val asyncXing = LazyModule(new IntXing(3))
|
||||
val periphXing = LazyModule(new IntXing(1))
|
||||
val asyncIntNode = asyncXing.intnode
|
||||
val periphIntNode = periphXing.intnode
|
||||
val coreIntNode = IntIdentityNode()
|
||||
|
||||
// order here matters
|
||||
intXbar.intnode := asyncXing.intnode
|
||||
intXbar.intnode := periphXing.intnode
|
||||
intXbar.intnode := coreIntNode
|
||||
|
||||
def outputInterruptXingLatency = 1
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import chisel3.internal.sourceinfo.SourceInfo
|
||||
import freechips.rocketchip.config.Parameters
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.util._
|
||||
import freechips.rocketchip.coreplex.{CrossingWrapper, AsynchronousCrossing}
|
||||
|
||||
class TLAsyncCrossingSource(sync: Int = 3)(implicit p: Parameters) extends LazyModule
|
||||
{
|
||||
@ -85,6 +86,7 @@ object TLAsyncCrossingSink
|
||||
}
|
||||
}
|
||||
|
||||
@deprecated("TLAsyncCrossing is fragile. Use TLAsyncCrossingSource and TLAsyncCrossingSink", "rocket-chip 1.2")
|
||||
class TLAsyncCrossing(depth: Int = 8, sync: Int = 3)(implicit p: Parameters) extends LazyModule
|
||||
{
|
||||
val source = LazyModule(new TLAsyncCrossingSource(sync))
|
||||
@ -113,26 +115,19 @@ import freechips.rocketchip.unittest._
|
||||
|
||||
class TLRAMAsyncCrossing(txns: Int)(implicit p: Parameters) extends LazyModule {
|
||||
val model = LazyModule(new TLRAMModel("AsyncCrossing"))
|
||||
val ram = LazyModule(new TLRAM(AddressSet(0x0, 0x3ff)))
|
||||
val fuzz = LazyModule(new TLFuzzer(txns))
|
||||
val cross = LazyModule(new TLAsyncCrossing)
|
||||
val island = LazyModule(new CrossingWrapper(AsynchronousCrossing(8)))
|
||||
val ram = island { LazyModule(new TLRAM(AddressSet(0x0, 0x3ff))) }
|
||||
|
||||
model.node := fuzz.node
|
||||
cross.node := TLFragmenter(4, 256)(TLDelayer(0.1)(model.node))
|
||||
ram.node := cross.node
|
||||
ram.node := island.crossTLIn := TLFragmenter(4, 256)(TLDelayer(0.1)(model.node))
|
||||
|
||||
lazy val module = new LazyModuleImp(this) with UnitTestModule {
|
||||
io.finished := fuzz.module.io.finished
|
||||
|
||||
// Shove the RAM into another clock domain
|
||||
val clocks = Module(new Pow2ClockDivider(2))
|
||||
ram.module.clock := clocks.io.clock_out
|
||||
|
||||
// ... and safely cross TL2 into it
|
||||
cross.module.io.in_clock := clock
|
||||
cross.module.io.in_reset := reset
|
||||
cross.module.io.out_clock := clocks.io.clock_out
|
||||
cross.module.io.out_reset := reset
|
||||
island.module.clock := clocks.io.clock_out
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,28 +71,10 @@ object TLBuffer
|
||||
buffer.node :=? x
|
||||
buffer.node
|
||||
}
|
||||
}
|
||||
|
||||
class TLBufferChain(depth: Int)(implicit p: Parameters) extends LazyModule {
|
||||
val buf_chain = List.fill(depth)(LazyModule(new TLBuffer(BufferParams.default)))
|
||||
val node = if (depth > 0) {
|
||||
(buf_chain.init zip buf_chain.tail) foreach { case (prev, next) => next.node :=? prev.node }
|
||||
NodeHandle(buf_chain.head.node, buf_chain.last.node)
|
||||
} else {
|
||||
TLIdentityNode()
|
||||
}
|
||||
lazy val module = new LazyModuleImp(this) { }
|
||||
}
|
||||
|
||||
object TLBufferChain
|
||||
{
|
||||
def apply(depth: Int)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = {
|
||||
if (depth > 0) {
|
||||
val buffer = LazyModule(new TLBufferChain(depth))
|
||||
buffer.node :=? x
|
||||
buffer.node
|
||||
} else {
|
||||
x
|
||||
}
|
||||
def chain(depth: Int, name: Option[String] = None)(implicit p: Parameters): Seq[TLNode] = {
|
||||
val buffers = Seq.fill(depth) { LazyModule(new TLBuffer()) }
|
||||
name.foreach { n => buffers.zipWithIndex.foreach { case (b, i) => b.suggestName(s"${n}_${i}") } }
|
||||
buffers.map(_.node)
|
||||
}
|
||||
}
|
||||
|
@ -68,34 +68,24 @@ abstract class TLBusWrapper(params: TLBusParams, val busName: String)(implicit p
|
||||
protected def inwardNode: TLInwardNode = xbar.node
|
||||
protected def inwardBufNode: TLInwardNode = master_buffer.node
|
||||
|
||||
protected def bufferChain(depth: Int, name: Option[String] = None): (TLInwardNode, TLOutwardNode) = {
|
||||
SourceCardinality { implicit p =>
|
||||
val chain = LazyModule(new TLBufferChain(depth))
|
||||
name.foreach { n => chain.suggestName(s"${busName}_${n}_TLBufferChain")}
|
||||
(chain.node, chain.node)
|
||||
}
|
||||
}
|
||||
|
||||
def bufferFromMasters: TLInwardNode = inwardBufNode
|
||||
|
||||
def bufferToSlaves: TLOutwardNode = outwardBufNode
|
||||
|
||||
def toSyncSlaves(name: Option[String] = None, addBuffers: Int = 0): TLOutwardNode = SinkCardinality { implicit p =>
|
||||
TLBufferChain(addBuffers)(outwardBufNode)
|
||||
TLBuffer.chain(addBuffers).foldRight(outwardBufNode)(_ :=? _)
|
||||
}
|
||||
|
||||
def toAsyncSlaves(sync: Int = 3, name: Option[String] = None, addBuffers: Int = 0): TLAsyncOutwardNode = SinkCardinality { implicit p =>
|
||||
val source = LazyModule(new TLAsyncCrossingSource(sync))
|
||||
name.foreach{ n => source.suggestName(s"${busName}_${n}_TLAsyncCrossingSource")}
|
||||
source.node :=? TLBufferChain(addBuffers)(outwardNode)
|
||||
source.node
|
||||
source.node :=? TLBuffer.chain(addBuffers).foldRight(outwardNode)(_ :=? _)
|
||||
}
|
||||
|
||||
def toRationalSlaves(name: Option[String] = None, addBuffers: Int = 0): TLRationalOutwardNode = SinkCardinality { implicit p =>
|
||||
val source = LazyModule(new TLRationalCrossingSource())
|
||||
name.foreach{ n => source.suggestName(s"${busName}_${n}_TLRationalCrossingSource")}
|
||||
source.node :=? TLBufferChain(addBuffers)(outwardNode)
|
||||
source.node
|
||||
source.node :=? TLBuffer.chain(addBuffers).foldRight(outwardNode)(_ :=? _)
|
||||
}
|
||||
|
||||
def toVariableWidthSlaves: TLOutwardNode = outwardFragNode
|
||||
|
@ -233,28 +233,16 @@ class TLFuzzRAM(txns: Int)(implicit p: Parameters) extends LazyModule
|
||||
val xbar = LazyModule(new TLXbar)
|
||||
val xbar2= LazyModule(new TLXbar)
|
||||
val fuzz = LazyModule(new TLFuzzer(txns))
|
||||
val cross = LazyModule(new TLAsyncCrossing)
|
||||
|
||||
model.node := fuzz.node
|
||||
xbar2.node := TLAtomicAutomata()(model.node)
|
||||
ram2.node := TLFragmenter(16, 256)(xbar2.node)
|
||||
xbar.node := TLWidthWidget(16)(TLHintHandler()(xbar2.node))
|
||||
cross.node := TLFragmenter(4, 256)(TLBuffer()(xbar.node))
|
||||
ram.node := cross.node
|
||||
ram.node := TLFragmenter(4, 256)(TLBuffer()(xbar.node))
|
||||
gpio.node := TLFragmenter(4, 32)(TLBuffer()(xbar.node))
|
||||
|
||||
lazy val module = new LazyModuleImp(this) with UnitTestModule {
|
||||
io.finished := fuzz.module.io.finished
|
||||
|
||||
// Shove the RAM into another clock domain
|
||||
val clocks = Module(new Pow2ClockDivider(2))
|
||||
ram.module.clock := clocks.io.clock_out
|
||||
|
||||
// ... and safely cross TL2 into it
|
||||
cross.module.io.in_clock := clock
|
||||
cross.module.io.in_reset := reset
|
||||
cross.module.io.out_clock := clocks.io.clock_out
|
||||
cross.module.io.out_reset := reset
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,121 +0,0 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.tilelink
|
||||
|
||||
import Chisel._
|
||||
import chisel3.internal.sourceinfo.SourceInfo
|
||||
import freechips.rocketchip.config.Parameters
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.util.SynchronizerShiftReg
|
||||
import scala.collection.mutable.ListBuffer
|
||||
import scala.math.max
|
||||
|
||||
// A potentially empty half-open range; [start, end)
|
||||
case class IntRange(start: Int, end: Int)
|
||||
{
|
||||
require (start >= 0)
|
||||
require (start <= end)
|
||||
def size = end - start
|
||||
def overlaps(x: IntRange) = start < x.end && x.start < end
|
||||
def offset(x: Int) = IntRange(x+start, x+end)
|
||||
}
|
||||
|
||||
object IntRange
|
||||
{
|
||||
implicit def apply(end: Int): IntRange = apply(0, end)
|
||||
}
|
||||
|
||||
case class IntSourceParameters(
|
||||
range: IntRange,
|
||||
resources: Seq[Resource] = Seq(),
|
||||
nodePath: Seq[BaseNode] = Seq())
|
||||
{
|
||||
val name = nodePath.lastOption.map(_.lazyModule.name).getOrElse("disconnected")
|
||||
}
|
||||
|
||||
case class IntSinkParameters(
|
||||
nodePath: Seq[BaseNode] = Seq())
|
||||
{
|
||||
val name = nodePath.lastOption.map(_.lazyModule.name).getOrElse("disconnected")
|
||||
}
|
||||
|
||||
case class IntSourcePortParameters(sources: Seq[IntSourceParameters])
|
||||
{
|
||||
val num = sources.map(_.range.size).sum
|
||||
// The interrupts mapping must not overlap
|
||||
sources.map(_.range).combinations(2).foreach { case Seq(a, b) => require (!a.overlaps(b)) }
|
||||
// The interrupts must perfectly cover the range
|
||||
require (sources.isEmpty || sources.map(_.range.end).max == num)
|
||||
}
|
||||
object IntSourcePortSimple
|
||||
{
|
||||
def apply(num: Int = 1, ports: Int = 1, sources: Int = 1, resources: Seq[Resource] = Nil) =
|
||||
if (num == 0) Nil else
|
||||
Seq.fill(ports)(IntSourcePortParameters(Seq.fill(sources)(IntSourceParameters(range = IntRange(0, num), resources = resources))))
|
||||
}
|
||||
|
||||
case class IntSinkPortParameters(sinks: Seq[IntSinkParameters])
|
||||
object IntSinkPortSimple
|
||||
{
|
||||
def apply(ports: Int = 1, sinks: Int = 1) =
|
||||
Seq.fill(ports)(IntSinkPortParameters(Seq.fill(sinks)(IntSinkParameters())))
|
||||
}
|
||||
|
||||
case class IntEdge(source: IntSourcePortParameters, sink: IntSinkPortParameters, params: Parameters, sourceInfo: SourceInfo)
|
||||
|
||||
object IntImp extends SimpleNodeImp[IntSourcePortParameters, IntSinkPortParameters, IntEdge, Vec[Bool]]
|
||||
{
|
||||
def edge(pd: IntSourcePortParameters, pu: IntSinkPortParameters, p: Parameters, sourceInfo: SourceInfo) = IntEdge(pd, pu, p, sourceInfo)
|
||||
def bundle(e: IntEdge) = Vec(e.source.num, Bool())
|
||||
def render(e: IntEdge) = RenderedEdge(colour = "#0000ff" /* blue */, label = e.source.sources.map(_.range.size).sum.toString, flipped = true)
|
||||
|
||||
override def mixO(pd: IntSourcePortParameters, node: OutwardNode[IntSourcePortParameters, IntSinkPortParameters, Vec[Bool]]): IntSourcePortParameters =
|
||||
pd.copy(sources = pd.sources.map { s => s.copy (nodePath = node +: s.nodePath) })
|
||||
override def mixI(pu: IntSinkPortParameters, node: InwardNode[IntSourcePortParameters, IntSinkPortParameters, Vec[Bool]]): IntSinkPortParameters =
|
||||
pu.copy(sinks = pu.sinks.map { s => s.copy (nodePath = node +: s.nodePath) })
|
||||
}
|
||||
|
||||
case class IntSourceNode(portParams: Seq[IntSourcePortParameters])(implicit valName: ValName) extends SourceNode(IntImp)(portParams)
|
||||
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)(
|
||||
implicit valName: ValName)
|
||||
extends AdapterNode(IntImp)(sourceFn, sinkFn, num)
|
||||
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)(
|
||||
implicit valName: ValName)
|
||||
extends NexusNode(IntImp)(sourceFn, sinkFn, numSourcePorts, numSinkPorts)
|
||||
|
||||
class IntXbar()(implicit p: Parameters) extends LazyModule
|
||||
{
|
||||
val intnode = IntNexusNode(
|
||||
sinkFn = { _ => IntSinkPortParameters(Seq(IntSinkParameters())) },
|
||||
sourceFn = { seq =>
|
||||
IntSourcePortParameters((seq zip seq.map(_.num).scanLeft(0)(_+_).init).map {
|
||||
case (s, o) => s.sources.map(z => z.copy(range = z.range.offset(o)))
|
||||
}.flatten)
|
||||
})
|
||||
|
||||
lazy val module = new LazyModuleImp(this) {
|
||||
val cat = intnode.in.map { case (i, e) => i.take(e.source.num) }.flatten
|
||||
intnode.out.foreach { case (o, _) => o := cat }
|
||||
}
|
||||
}
|
||||
|
||||
class IntXing(sync: Int = 3)(implicit p: Parameters) extends LazyModule
|
||||
{
|
||||
val intnode = IntAdapterNode()
|
||||
|
||||
lazy val module = new LazyModuleImp(this) {
|
||||
(intnode.in zip intnode.out) foreach { case ((in, _), (out, _)) =>
|
||||
out := SynchronizerShiftReg(in, sync)
|
||||
}
|
||||
}
|
||||
}
|
@ -97,6 +97,7 @@ object TLRationalCrossingSink
|
||||
}
|
||||
}
|
||||
|
||||
@deprecated("TLRationalCrossing is fragile. Use TLRationalCrossingSource and TLRationalCrossingSink", "rocket-chip 1.2")
|
||||
class TLRationalCrossing(direction: RationalDirection = Symmetric)(implicit p: Parameters) extends LazyModule
|
||||
{
|
||||
val source = LazyModule(new TLRationalCrossingSource)
|
||||
|
@ -6,6 +6,7 @@ import Chisel._
|
||||
import freechips.rocketchip.config.Parameters
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.regmapper._
|
||||
import freechips.rocketchip.interrupts._
|
||||
import freechips.rocketchip.util.HeterogeneousBag
|
||||
import scala.math.{min,max}
|
||||
|
||||
|
@ -9,13 +9,11 @@ package object tilelink
|
||||
{
|
||||
type TLInwardNode = InwardNodeHandle[TLClientPortParameters, TLManagerPortParameters, TLBundle]
|
||||
type TLOutwardNode = OutwardNodeHandle[TLClientPortParameters, TLManagerPortParameters, TLBundle]
|
||||
type TLNode = NodeHandle[TLClientPortParameters, TLManagerPortParameters, TLBundle, TLClientPortParameters, TLManagerPortParameters, TLBundle]
|
||||
type TLAsyncInwardNode = InwardNodeHandle[TLAsyncClientPortParameters, TLAsyncManagerPortParameters, TLAsyncBundle]
|
||||
type TLAsyncOutwardNode = OutwardNodeHandle[TLAsyncClientPortParameters, TLAsyncManagerPortParameters, TLAsyncBundle]
|
||||
type TLRationalInwardNode = InwardNodeHandle[TLRationalClientPortParameters, TLRationalManagerPortParameters, TLRationalBundle]
|
||||
type TLRationalOutwardNode = OutwardNodeHandle[TLRationalClientPortParameters, TLRationalManagerPortParameters, TLRationalBundle]
|
||||
type TLMixedNode = MixedNode[TLClientPortParameters, TLManagerPortParameters, TLEdgeIn, TLBundle,
|
||||
TLClientPortParameters, TLManagerPortParameters, TLEdgeOut, TLBundle]
|
||||
|
||||
type IntInwardNode = InwardNodeHandle[IntSourcePortParameters, IntSinkPortParameters, Vec[Bool]]
|
||||
type IntOutwardNode = OutwardNodeHandle[IntSourcePortParameters, IntSinkPortParameters, Vec[Bool]]
|
||||
}
|
||||
|
@ -19,118 +19,3 @@ class CrossingIO[T <: Data](gen: T) extends Bundle {
|
||||
abstract class Crossing[T <: Data] extends Module {
|
||||
val io: CrossingIO[T]
|
||||
}
|
||||
|
||||
class AsyncScope extends Module { val io = new Bundle }
|
||||
object AsyncScope { def apply() = Module(new AsyncScope) }
|
||||
|
||||
object AsyncDecoupledCrossing
|
||||
{
|
||||
// takes from_source from the 'from' clock domain and puts it into the 'to' clock domain
|
||||
def apply[T <: Data](from_clock: Clock, from_reset: Bool, from_source: ReadyValidIO[T], to_clock: Clock, to_reset: Bool, depth: Int = 8, sync: Int = 3): DecoupledIO[T] = {
|
||||
val crossing = Module(new AsyncQueue(from_source.bits, depth, sync)).io
|
||||
crossing.enq_clock := from_clock
|
||||
crossing.enq_reset := from_reset
|
||||
crossing.enq <> from_source
|
||||
crossing.deq_clock := to_clock
|
||||
crossing.deq_reset := to_reset
|
||||
crossing.deq
|
||||
}
|
||||
}
|
||||
|
||||
object AsyncDecoupledTo
|
||||
{
|
||||
// takes source from your clock domain and puts it into the 'to' clock domain
|
||||
def apply[T <: Data](to_clock: Clock, to_reset: Bool, source: ReadyValidIO[T], depth: Int = 8, sync: Int = 3): DecoupledIO[T] = {
|
||||
val scope = AsyncScope()
|
||||
AsyncDecoupledCrossing(scope.clock, scope.reset, source, to_clock, to_reset, depth, sync)
|
||||
}
|
||||
}
|
||||
|
||||
object AsyncDecoupledFrom
|
||||
{
|
||||
// takes from_source from the 'from' clock domain and puts it into your clock domain
|
||||
def apply[T <: Data](from_clock: Clock, from_reset: Bool, from_source: ReadyValidIO[T], depth: Int = 8, sync: Int = 3): DecoupledIO[T] = {
|
||||
val scope = AsyncScope()
|
||||
AsyncDecoupledCrossing(from_clock, from_reset, from_source, scope.clock, scope.reset, depth, sync)
|
||||
}
|
||||
}
|
||||
|
||||
object PostQueueIrrevocablize
|
||||
{
|
||||
def apply[T <: Data](deq: DecoupledIO[T]): IrrevocableIO[T] = {
|
||||
val irr = Wire(new IrrevocableIO(deq.bits))
|
||||
irr.bits := deq.bits
|
||||
irr.valid := deq.valid
|
||||
deq.ready := irr.ready
|
||||
irr
|
||||
}
|
||||
}
|
||||
|
||||
object AsyncIrrevocableCrossing {
|
||||
def apply[T <: Data](from_clock: Clock, from_reset: Bool, from_source: ReadyValidIO[T], to_clock: Clock, to_reset: Bool, depth: Int = 8, sync: Int = 3): IrrevocableIO[T] = {
|
||||
PostQueueIrrevocablize(AsyncDecoupledCrossing(from_clock, from_reset, from_source, to_clock, to_reset, depth, sync))
|
||||
}
|
||||
}
|
||||
|
||||
object AsyncIrrevocableTo
|
||||
{
|
||||
// takes source from your clock domain and puts it into the 'to' clock domain
|
||||
def apply[T <: Data](to_clock: Clock, to_reset: Bool, source: ReadyValidIO[T], depth: Int = 8, sync: Int = 3): IrrevocableIO[T] = {
|
||||
PostQueueIrrevocablize(AsyncDecoupledTo(to_clock, to_reset, source, depth, sync))
|
||||
}
|
||||
}
|
||||
|
||||
object AsyncIrrevocableFrom
|
||||
{
|
||||
// takes from_source from the 'from' clock domain and puts it into your clock domain
|
||||
def apply[T <: Data](from_clock: Clock, from_reset: Bool, from_source: ReadyValidIO[T], depth: Int = 8, sync: Int = 3): IrrevocableIO[T] = {
|
||||
PostQueueIrrevocablize(AsyncDecoupledFrom(from_clock, from_reset, from_source, depth, sync))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This helper object synchronizes a level-sensitive signal from one
|
||||
* clock domain to another.
|
||||
*/
|
||||
object LevelSyncCrossing {
|
||||
class SynchronizerBackend(sync: Int, _clock: Clock) extends Module(Some(_clock)) {
|
||||
val io = new Bundle {
|
||||
val in = Bool(INPUT)
|
||||
val out = Bool(OUTPUT)
|
||||
}
|
||||
|
||||
io.out := SynchronizerShiftReg(io.in, sync)
|
||||
}
|
||||
|
||||
class SynchronizerFrontend(_clock: Clock) extends Module(Some(_clock)) {
|
||||
val io = new Bundle {
|
||||
val in = Bool(INPUT)
|
||||
val out = Bool(OUTPUT)
|
||||
}
|
||||
|
||||
io.out := RegNext(io.in)
|
||||
}
|
||||
|
||||
def apply(from_clock: Clock, to_clock: Clock, in: Bool, sync: Int = 2): Bool = {
|
||||
val front = Module(new SynchronizerFrontend(from_clock))
|
||||
val back = Module(new SynchronizerBackend(sync, to_clock))
|
||||
|
||||
front.io.in := in
|
||||
back.io.in := front.io.out
|
||||
back.io.out
|
||||
}
|
||||
}
|
||||
|
||||
object LevelSyncTo {
|
||||
def apply(to_clock: Clock, in: Bool, sync: Int = 2): Bool = {
|
||||
val scope = AsyncScope()
|
||||
LevelSyncCrossing(scope.clock, to_clock, in, sync)
|
||||
}
|
||||
}
|
||||
|
||||
object LevelSyncFrom {
|
||||
def apply(from_clock: Clock, in: Bool, sync: Int = 2): Bool = {
|
||||
val scope = AsyncScope()
|
||||
LevelSyncCrossing(from_clock, scope.clock, in, sync)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user