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.config.Parameters
|
||||||
import freechips.rocketchip.diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
import freechips.rocketchip.regmapper._
|
import freechips.rocketchip.regmapper._
|
||||||
import freechips.rocketchip.tilelink.{IntSourceNode, IntSourcePortSimple}
|
import freechips.rocketchip.interrupts.{IntSourceNode, IntSourcePortSimple}
|
||||||
import freechips.rocketchip.util.{HeterogeneousBag, MaskGen}
|
import freechips.rocketchip.util.{HeterogeneousBag, MaskGen}
|
||||||
import scala.math.{min,max}
|
import scala.math.{min,max}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import Chisel._
|
|||||||
import freechips.rocketchip.config.Parameters
|
import freechips.rocketchip.config.Parameters
|
||||||
import freechips.rocketchip.diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
import freechips.rocketchip.regmapper._
|
import freechips.rocketchip.regmapper._
|
||||||
import freechips.rocketchip.tilelink.{IntSourceNode, IntSourcePortSimple}
|
import freechips.rocketchip.interrupts.{IntSourceNode, IntSourcePortSimple}
|
||||||
import freechips.rocketchip.util.HeterogeneousBag
|
import freechips.rocketchip.util.HeterogeneousBag
|
||||||
import scala.math.{min,max}
|
import scala.math.{min,max}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import freechips.rocketchip.config.Parameters
|
|||||||
import freechips.rocketchip.diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
import freechips.rocketchip.tilelink._
|
import freechips.rocketchip.tilelink._
|
||||||
import freechips.rocketchip.util._
|
import freechips.rocketchip.util._
|
||||||
|
import freechips.rocketchip.coreplex.{CrossingWrapper, AsynchronousCrossing}
|
||||||
|
|
||||||
class AXI4AsyncCrossingSource(sync: Int = 3)(implicit p: Parameters) extends LazyModule
|
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
|
class AXI4AsyncCrossing(depth: Int = 8, sync: Int = 3)(implicit p: Parameters) extends LazyModule
|
||||||
{
|
{
|
||||||
val source = LazyModule(new AXI4AsyncCrossingSource(sync))
|
val source = LazyModule(new AXI4AsyncCrossingSource(sync))
|
||||||
@ -89,28 +91,21 @@ import freechips.rocketchip.unittest._
|
|||||||
|
|
||||||
class AXI4RAMAsyncCrossing(txns: Int)(implicit p: Parameters) extends LazyModule {
|
class AXI4RAMAsyncCrossing(txns: Int)(implicit p: Parameters) extends LazyModule {
|
||||||
val model = LazyModule(new TLRAMModel("AsyncCrossing"))
|
val model = LazyModule(new TLRAMModel("AsyncCrossing"))
|
||||||
val ram = LazyModule(new AXI4RAM(AddressSet(0x0, 0x3ff)))
|
|
||||||
val fuzz = LazyModule(new TLFuzzer(txns))
|
val fuzz = LazyModule(new TLFuzzer(txns))
|
||||||
val toaxi = LazyModule(new TLToAXI4)
|
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
|
model.node := fuzz.node
|
||||||
toaxi.node := model.node
|
toaxi.node := model.node
|
||||||
cross.node := toaxi.node
|
ram.node := island.crossAXI4In := toaxi.node
|
||||||
ram.node := cross.node
|
|
||||||
|
|
||||||
lazy val module = new LazyModuleImp(this) with UnitTestModule {
|
lazy val module = new LazyModuleImp(this) with UnitTestModule {
|
||||||
io.finished := fuzz.module.io.finished
|
io.finished := fuzz.module.io.finished
|
||||||
|
|
||||||
// Shove the RAM into another clock domain
|
// Shove the RAM into another clock domain
|
||||||
val clocks = Module(new Pow2ClockDivider(2))
|
val clocks = Module(new Pow2ClockDivider(2))
|
||||||
ram.module.clock := clocks.io.clock_out
|
island.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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import Chisel._
|
|||||||
import freechips.rocketchip.config.Parameters
|
import freechips.rocketchip.config.Parameters
|
||||||
import freechips.rocketchip.diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
import freechips.rocketchip.regmapper._
|
import freechips.rocketchip.regmapper._
|
||||||
import freechips.rocketchip.tilelink.{IntSourceNode, IntSourcePortSimple}
|
import freechips.rocketchip.interrupts.{IntSourceNode, IntSourcePortSimple}
|
||||||
import freechips.rocketchip.util.{HeterogeneousBag, MaskGen}
|
import freechips.rocketchip.util.{HeterogeneousBag, MaskGen}
|
||||||
import scala.math.{min,max}
|
import scala.math.{min,max}
|
||||||
|
|
||||||
|
@ -3,10 +3,11 @@
|
|||||||
package freechips.rocketchip.amba
|
package freechips.rocketchip.amba
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import freechips.rocketchip.diplomacy.OutwardNodeHandle
|
import freechips.rocketchip.diplomacy._
|
||||||
|
|
||||||
package object axi4
|
package object axi4
|
||||||
{
|
{
|
||||||
type AXI4OutwardNode = OutwardNodeHandle[AXI4MasterPortParameters, AXI4SlavePortParameters, AXI4Bundle]
|
type AXI4OutwardNode = OutwardNodeHandle[AXI4MasterPortParameters, AXI4SlavePortParameters, AXI4Bundle]
|
||||||
type AXI4AsyncOutwardNode = OutwardNodeHandle[AXI4AsyncMasterPortParameters, AXI4AsyncSlavePortParameters, AXI4AsyncBundle]
|
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 Chisel._
|
||||||
import freechips.rocketchip.config.Parameters
|
import freechips.rocketchip.config.Parameters
|
||||||
import freechips.rocketchip.diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
|
import freechips.rocketchip.interrupts._
|
||||||
import freechips.rocketchip.tilelink._
|
import freechips.rocketchip.tilelink._
|
||||||
import freechips.rocketchip.devices.tilelink._
|
import freechips.rocketchip.devices.tilelink._
|
||||||
import freechips.rocketchip.tile.{BaseTile, TileParams, SharedMemoryTLEdge, HasExternallyDrivenTileConstants}
|
import freechips.rocketchip.tile.{BaseTile, TileParams, SharedMemoryTLEdge, HasExternallyDrivenTileConstants}
|
||||||
import freechips.rocketchip.devices.debug.{HasPeripheryDebug, HasPeripheryDebugModuleImp}
|
import freechips.rocketchip.devices.debug.{HasPeripheryDebug, HasPeripheryDebugModuleImp}
|
||||||
import freechips.rocketchip.util._
|
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 */
|
/** BareCoreplex is the root class for creating a coreplex sub-system */
|
||||||
abstract class BareCoreplex(implicit p: Parameters) extends LazyModule with BindingScope {
|
abstract class BareCoreplex(implicit p: Parameters) extends LazyModule with BindingScope {
|
||||||
lazy val dts = DTS(bindingTree)
|
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
|
master_fixer.node :=* master_buffer.node
|
||||||
inwardNode :=* master_fixer.node
|
inwardNode :=* master_fixer.node
|
||||||
|
|
||||||
def fromSyncPorts(addBuffers: Int = 0, name: Option[String] = None): TLInwardNode = {
|
def fromSyncPorts(addBuffers: Int = 0, name: Option[String] = None): TLInwardNode = SourceCardinality { implicit p =>
|
||||||
val (in, out) = bufferChain(addBuffers, name)
|
TLBuffer.chain(addBuffers).foldLeft(master_buffer.node:TLInwardNode)(_ :=? _)
|
||||||
master_buffer.node :=* out
|
|
||||||
in
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def fromSyncMasters(addBuffers: Int = 0, name: Option[String] = None): TLInwardNode = {
|
def fromSyncMasters(addBuffers: Int = 0, name: Option[String] = None): TLInwardNode = SourceCardinality { implicit p =>
|
||||||
val (in, out) = bufferChain(addBuffers, name)
|
TLBuffer.chain(addBuffers).foldLeft(master_buffer.node:TLInwardNode)(_ :=? _)
|
||||||
master_buffer.node :=* out
|
|
||||||
in
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def fromCoherentChip: TLInwardNode = inwardNode
|
def fromCoherentChip: TLInwardNode = inwardNode
|
||||||
|
@ -5,7 +5,7 @@ package freechips.rocketchip.coreplex
|
|||||||
import Chisel._
|
import Chisel._
|
||||||
import freechips.rocketchip.config.{Field, Parameters}
|
import freechips.rocketchip.config.{Field, Parameters}
|
||||||
import freechips.rocketchip.diplomacy._
|
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 */
|
/** Collects interrupts from internal and external devices and feeds them into the PLIC */
|
||||||
class InterruptBusWrapper(implicit p: Parameters) {
|
class InterruptBusWrapper(implicit p: Parameters) {
|
||||||
|
@ -31,35 +31,23 @@ class PeripheryBus(params: PeripheryBusParams)(implicit p: Parameters) extends T
|
|||||||
TLFragmenter(params.beatBytes, maxXferBytes)(outwardBufNode)
|
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 fromSystemBus: TLInwardNode = {
|
||||||
val atomics = LazyModule(new TLAtomicAutomata(arithmetic = params.arithmetic))
|
val atomics = LazyModule(new TLAtomicAutomata(arithmetic = params.arithmetic))
|
||||||
inwardBufNode := atomics.node
|
inwardBufNode := atomics.node
|
||||||
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,
|
/** Provides buses that serve as attachment points,
|
||||||
|
@ -3,67 +3,54 @@
|
|||||||
package freechips.rocketchip.coreplex
|
package freechips.rocketchip.coreplex
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
|
import chisel3.internal.sourceinfo.SourceInfo
|
||||||
import freechips.rocketchip.config.{Field, Parameters}
|
import freechips.rocketchip.config.{Field, Parameters}
|
||||||
import freechips.rocketchip.devices.tilelink._
|
import freechips.rocketchip.devices.tilelink._
|
||||||
import freechips.rocketchip.devices.debug.{HasPeripheryDebug, HasPeripheryDebugModuleImp}
|
import freechips.rocketchip.devices.debug.{HasPeripheryDebug, HasPeripheryDebugModuleImp}
|
||||||
import freechips.rocketchip.diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
import freechips.rocketchip.tile._
|
import freechips.rocketchip.tile._
|
||||||
import freechips.rocketchip.tilelink._
|
import freechips.rocketchip.tilelink._
|
||||||
|
import freechips.rocketchip.interrupts._
|
||||||
import freechips.rocketchip.util._
|
import freechips.rocketchip.util._
|
||||||
|
|
||||||
case class TLNodeChain(in: TLInwardNode, out: TLOutwardNode)
|
|
||||||
|
|
||||||
// TODO: how specific are these to RocketTiles?
|
// TODO: how specific are these to RocketTiles?
|
||||||
case class TileMasterPortParams(
|
case class TileMasterPortParams(
|
||||||
addBuffers: Int = 0,
|
addBuffers: Int = 0,
|
||||||
blockerCtrlAddr: Option[BigInt] = None,
|
blockerCtrlAddr: Option[BigInt] = None,
|
||||||
cork: Option[Boolean] = 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_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_fixer = LazyModule(new TLFIFOFixer(TLFIFOFixer.allUncacheable))
|
||||||
val tile_master_buffer = LazyModule(new TLBufferChain(addBuffers))
|
|
||||||
|
|
||||||
tile_master_blocker.foreach { _.controlNode := coreplex.pbus.toVariableWidthSlaves }
|
tile_master_blocker.foreach { _.controlNode := coreplex.pbus.toVariableWidthSlaves }
|
||||||
|
(Seq(tile_master_fixer.node) ++ TLBuffer.chain(addBuffers)
|
||||||
val nodes = List(
|
++ tile_master_blocker.map(_.node) ++ tile_master_cork.map(_.node))
|
||||||
Some(tile_master_buffer.node),
|
.foldRight(masterNode)(_ :=* _)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case class TileSlavePortParams(
|
case class TileSlavePortParams(
|
||||||
addBuffers: Int = 0,
|
addBuffers: Int = 0,
|
||||||
blockerCtrlAddr: Option[BigInt] = None) {
|
blockerCtrlAddr: Option[BigInt] = None) {
|
||||||
def adapterChain(coreplex: HasPeripheryBus)
|
|
||||||
(implicit p: Parameters): () => TLNodeChain = {
|
|
||||||
|
|
||||||
val blockerParams = blockerCtrlAddr.map(BasicBusBlockerParams(_, coreplex.pbus.beatBytes, coreplex.sbus.beatBytes))
|
def adapt(coreplex: HasPeripheryBus)
|
||||||
|
(slaveNode: TLInwardNode)
|
||||||
val tile_slave_blocker = blockerParams.map(bp => LazyModule(new BasicBusBlocker(bp)))
|
(implicit p: Parameters, sourceInfo: SourceInfo): TLInwardNode = {
|
||||||
val tile_slave_buffer = LazyModule(new TLBufferChain(addBuffers))
|
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 }
|
tile_slave_blocker.foreach { _.controlNode := coreplex.pbus.toVariableWidthSlaves }
|
||||||
|
(Seq() ++ tile_slave_blocker.map(_.node) ++ TLBuffer.chain(addBuffers))
|
||||||
val nodes = List(
|
.foldLeft(slaveNode)(_ :*= _)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,67 +82,55 @@ trait HasRocketTiles extends HasTiles
|
|||||||
case NumRocketTiles => crossingParams
|
case NumRocketTiles => crossingParams
|
||||||
case _ => throw new Exception("RocketCrossingKey.size must == 1 or == RocketTilesKey.size")
|
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,
|
// Make a wrapper for each tile that will wire it to coreplex devices and crossbars,
|
||||||
// according to the specified type of clock crossing.
|
// 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 tiles: Seq[BaseTile] = crossingTuples.map { case ((lip, tp), crossing) =>
|
||||||
val pWithExtra = p.alterPartial {
|
// 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 TileKey => tp
|
||||||
case BuildRoCC => tp.rocc
|
case BuildRoCC => tp.rocc
|
||||||
case SharedMemoryTLEdge => sharedMemoryTLEdge
|
case SharedMemoryTLEdge => sharedMemoryTLEdge
|
||||||
case RocketCrossingKey => List(crossing)
|
case RocketCrossingKey => List(crossing)
|
||||||
}
|
})
|
||||||
|
).suggestName(tp.name)
|
||||||
|
|
||||||
val wrapper = crossing.crossingType match {
|
// Connect the master ports of the tile to the system bus
|
||||||
case SynchronousCrossing(params) => {
|
sbus.fromTile(tp.name) { implicit p => crossing.master.adapt(this)(wrapper.crossTLOut :=* wrapper.masterNode) }
|
||||||
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
|
|
||||||
|
|
||||||
// Local Interrupts must be synchronized to the core clock
|
// Connect the slave ports of the tile to the periphery bus
|
||||||
// before being passed into this module.
|
pbus.toTile(tp.name) { implicit p => crossing.slave.adapt(this)(wrapper.slaveNode :*= wrapper.crossTLIn) }
|
||||||
// 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
|
|
||||||
|
|
||||||
val periphIntXbar = LazyModule(new IntXbar)
|
// Handle all the different types of interrupts crossing to or from the tile:
|
||||||
periphIntXbar.suggestName("periphIntXbar")
|
// 1. Debug interrupt is definitely asynchronous in all cases.
|
||||||
periphIntXbar.intnode := clint.intnode // msip+mtip
|
// 2. The CLINT and PLIC output interrupts are synchronous to the periphery clock,
|
||||||
periphIntXbar.intnode := plic.intnode // meip
|
// so might need to be synchronized depending on the Tile's crossing type.
|
||||||
if (tp.core.useVM) periphIntXbar.intnode := plic.intnode // seip
|
// 3. Local Interrupts are required to already be synchronous to the tile clock.
|
||||||
wrapper.periphIntNode := periphIntXbar.intnode
|
// 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)
|
wrapper.intXbar.intnode := wrapper { IntSyncCrossingSink(3) } := debug.intnode // 1. always async crossign
|
||||||
coreIntXbar.suggestName("coreIntXbar")
|
|
||||||
lip.foreach { coreIntXbar.intnode := _ } // lip
|
|
||||||
wrapper.coreIntNode := coreIntXbar.intnode
|
|
||||||
|
|
||||||
wrapper.intOutputNode.foreach { case int =>
|
// 2. clint+plic conditionak crossing
|
||||||
val rocketIntXing = LazyModule(new IntXing(wrapper.outputInterruptXingLatency))
|
val periphIntNode = SourceCardinality { implicit p => wrapper.intXbar.intnode :=? wrapper.crossIntIn }
|
||||||
FlipRendering { implicit p => rocketIntXing.intnode := int }
|
periphIntNode := clint.intnode // msip+mtip
|
||||||
plic.intnode := rocketIntXing.intnode
|
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
|
wrapper
|
||||||
|
@ -39,9 +39,7 @@ class SystemBus(params: SystemBusParams)(implicit p: Parameters) extends TLBusWr
|
|||||||
def toSplitSlaves: TLOutwardNode = outwardSplitNode
|
def toSplitSlaves: TLOutwardNode = outwardSplitNode
|
||||||
|
|
||||||
def toPeripheryBus(addBuffers: Int = 0): TLOutwardNode = {
|
def toPeripheryBus(addBuffers: Int = 0): TLOutwardNode = {
|
||||||
val (in, out) = bufferChain(addBuffers, name = Some("pbus"))
|
TLBuffer.chain(addBuffers).foldRight(pbus_fixer.node:TLOutwardNode)(_ := _)
|
||||||
in := pbus_fixer.node
|
|
||||||
out
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val toMemoryBus: TLOutwardNode = outwardNode
|
val toMemoryBus: TLOutwardNode = outwardNode
|
||||||
@ -52,34 +50,14 @@ class SystemBus(params: SystemBusParams)(implicit p: Parameters) extends TLBusWr
|
|||||||
|
|
||||||
def fromFrontBus: TLInwardNode = master_splitter.node
|
def fromFrontBus: TLInwardNode = master_splitter.node
|
||||||
|
|
||||||
def fromSyncTiles(params: BufferParams, adapt: () => TLNodeChain, name: Option[String] = None): TLInwardNode = {
|
def fromTile(name: Option[String])(gen: Parameters => TLOutwardNode) {
|
||||||
val adapters = adapt() // wanted to be called inside SystemBus scope
|
this {
|
||||||
val tile_sink = LazyModule(new TLBuffer(params))
|
LazyScope(s"${busName}FromTile${name.getOrElse("")}") {
|
||||||
name.foreach { n => tile_sink.suggestName(s"${busName}_${n}_TLBuffer") }
|
SourceCardinality { implicit p =>
|
||||||
|
master_splitter.node :=* gen(p)
|
||||||
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 fromSyncPorts(params: BufferParams = BufferParams.default, name: Option[String] = None): TLInwardNode = {
|
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.rocket.Instructions
|
||||||
import freechips.rocketchip.tile.XLen
|
import freechips.rocketchip.tile.XLen
|
||||||
import freechips.rocketchip.tilelink._
|
import freechips.rocketchip.tilelink._
|
||||||
|
import freechips.rocketchip.interrupts._
|
||||||
import freechips.rocketchip.util._
|
import freechips.rocketchip.util._
|
||||||
|
|
||||||
/** Constant values used by both Debug Bus Response & Request
|
/** 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 dmiXbar = LazyModule (new TLXbar())
|
||||||
|
|
||||||
val dmOuter = LazyModule( new TLDebugModuleOuter(device))
|
val dmOuter = LazyModule( new TLDebugModuleOuter(device))
|
||||||
val intnode = dmOuter.intnode
|
val intnode: IntSyncOutwardNode = IntSyncCrossingSource(alreadyRegistered = true) :*= dmOuter.intnode
|
||||||
|
|
||||||
val dmiInnerNode = TLAsyncCrossingSource()(dmiXbar.node)
|
val dmiInnerNode = TLAsyncCrossingSource()(dmiXbar.node)
|
||||||
|
|
||||||
@ -401,7 +402,7 @@ class TLDebugModuleOuterAsync(device: Device)(implicit p: Parameters) extends La
|
|||||||
|
|
||||||
lazy val module = new LazyModuleImp(this) {
|
lazy val module = new LazyModuleImp(this) {
|
||||||
|
|
||||||
val nComponents = intnode.out.size
|
val nComponents = dmOuter.intnode.edges.out.size
|
||||||
|
|
||||||
val io = IO(new Bundle {
|
val io = IO(new Bundle {
|
||||||
val dmi = new DMIIO()(p).flip()
|
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 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 node = dmInner.tlNode
|
||||||
val intnode = dmOuter.intnode
|
val intnode = dmOuter.intnode
|
||||||
@ -1047,7 +1048,7 @@ class TLDebugModule(implicit p: Parameters) extends LazyModule {
|
|||||||
dmInner.dmiNode := dmOuter.dmiInnerNode
|
dmInner.dmiNode := dmOuter.dmiInnerNode
|
||||||
|
|
||||||
lazy val module = new LazyModuleImp(this) {
|
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 io = IO(new Bundle {
|
||||||
val ctrl = new DebugCtrlBundle(nComponents)
|
val ctrl = new DebugCtrlBundle(nComponents)
|
||||||
|
@ -9,6 +9,7 @@ import freechips.rocketchip.diplomacy._
|
|||||||
import freechips.rocketchip.regmapper._
|
import freechips.rocketchip.regmapper._
|
||||||
import freechips.rocketchip.tile.XLen
|
import freechips.rocketchip.tile.XLen
|
||||||
import freechips.rocketchip.tilelink._
|
import freechips.rocketchip.tilelink._
|
||||||
|
import freechips.rocketchip.interrupts._
|
||||||
import freechips.rocketchip.util._
|
import freechips.rocketchip.util._
|
||||||
import scala.math.{min,max}
|
import scala.math.{min,max}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ import freechips.rocketchip.diplomacy._
|
|||||||
import freechips.rocketchip.regmapper._
|
import freechips.rocketchip.regmapper._
|
||||||
import freechips.rocketchip.tile.XLen
|
import freechips.rocketchip.tile.XLen
|
||||||
import freechips.rocketchip.tilelink._
|
import freechips.rocketchip.tilelink._
|
||||||
|
import freechips.rocketchip.interrupts._
|
||||||
import freechips.rocketchip.util._
|
import freechips.rocketchip.util._
|
||||||
import scala.math.min
|
import scala.math.min
|
||||||
|
|
||||||
|
@ -11,17 +11,26 @@ import scala.util.matching._
|
|||||||
|
|
||||||
abstract class LazyModule()(implicit val p: Parameters)
|
abstract class LazyModule()(implicit val p: Parameters)
|
||||||
{
|
{
|
||||||
protected[diplomacy] var bindings = List[() => Unit]()
|
|
||||||
protected[diplomacy] var children = List[LazyModule]()
|
protected[diplomacy] var children = List[LazyModule]()
|
||||||
protected[diplomacy] var nodes = List[BaseNode]()
|
protected[diplomacy] var nodes = List[BaseNode]()
|
||||||
protected[diplomacy] var info: SourceInfo = UnlocatableSourceInfo
|
protected[diplomacy] var info: SourceInfo = UnlocatableSourceInfo
|
||||||
protected[diplomacy] val parent = LazyModule.scope
|
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)
|
LazyModule.scope = Some(this)
|
||||||
parent.foreach(p => p.children = this :: p.children)
|
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
|
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 =
|
private lazy val childNames =
|
||||||
getClass.getMethods.filter { m =>
|
getClass.getMethods.filter { m =>
|
||||||
@ -54,6 +63,7 @@ abstract class LazyModule()(implicit val p: Parameters)
|
|||||||
def name = valName.getOrElse(className)
|
def name = valName.getOrElse(className)
|
||||||
def line = sourceLine(info)
|
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 module: LazyModuleImpLike
|
||||||
|
|
||||||
def omitGraphML: Boolean = !nodes.exists(!_.omitGraphML) && !children.exists(!_.omitGraphML)
|
def omitGraphML: Boolean = !nodes.exists(!_.omitGraphML) && !children.exists(!_.omitGraphML)
|
||||||
@ -154,6 +164,7 @@ sealed trait LazyModuleImpLike extends BaseModule
|
|||||||
implicit val sourceInfo = c.info
|
implicit val sourceInfo = c.info
|
||||||
Module(c.module).dangles
|
Module(c.module).dangles
|
||||||
}
|
}
|
||||||
|
wrapper.instantiate()
|
||||||
val nodeDangles = wrapper.nodes.reverse.flatMap(_.instantiate())
|
val nodeDangles = wrapper.nodes.reverse.flatMap(_.instantiate())
|
||||||
val allDangles = nodeDangles ++ childDangles
|
val allDangles = nodeDangles ++ childDangles
|
||||||
val pairing = SortedMap(allDangles.groupBy(_.source).toSeq:_*)
|
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 }
|
if (d.flipped) { d.data <> io } else { io <> d.data }
|
||||||
d.copy(data = io, name = wrapper.valName.getOrElse("anon") + "_" + d.name)
|
d.copy(data = io, name = wrapper.valName.getOrElse("anon") + "_" + d.name)
|
||||||
}
|
}
|
||||||
wrapper.bindings.reverse.foreach { f => f () }
|
|
||||||
(auto, dangles)
|
(auto, dangles)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,6 +98,8 @@ abstract class BaseNode(implicit val valName: ValName)
|
|||||||
def omitGraphML = outputs.isEmpty && inputs.isEmpty
|
def omitGraphML = outputs.isEmpty && inputs.isEmpty
|
||||||
lazy val nodedebugstring: String = ""
|
lazy val nodedebugstring: String = ""
|
||||||
|
|
||||||
|
def parents: Seq[LazyModule] = lazyModule +: lazyModule.parents
|
||||||
|
|
||||||
def wirePrefix = {
|
def wirePrefix = {
|
||||||
val camelCase = "([a-z])([A-Z])".r
|
val camelCase = "([a-z])([A-Z])".r
|
||||||
val decamel = camelCase.replaceAllIn(valName.name, _ match { case camelCase(l, h) => l + "_" + h })
|
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 gci: Option[BaseNode] // greatest common inner
|
||||||
protected[diplomacy] def gco: Option[BaseNode] // greatest common outer
|
protected[diplomacy] def gco: Option[BaseNode] // greatest common outer
|
||||||
protected[diplomacy] def inputs: Seq[(BaseNode, RenderedEdge)]
|
def inputs: Seq[(BaseNode, RenderedEdge)]
|
||||||
protected[diplomacy] def outputs: Seq[(BaseNode, RenderedEdge)]
|
def outputs: Seq[(BaseNode, RenderedEdge)]
|
||||||
}
|
}
|
||||||
|
|
||||||
object BaseNode
|
object BaseNode
|
||||||
@ -117,22 +119,53 @@ object BaseNode
|
|||||||
protected[diplomacy] var serial = 0
|
protected[diplomacy] var serial = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// !!! rename the nodes we bind?
|
trait NoHandle
|
||||||
case class NodeHandle[DI, UI, BI <: Data, DO, UO, BO <: Data]
|
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])
|
(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 inward = inwardHandle.inward
|
||||||
val outward = outwardHandle.outward
|
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 inward: InwardNode[DI, UI, BI]
|
||||||
def := (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo) { inward.:=(h)(p, sourceInfo) }
|
def parentsIn: Seq[LazyModule] = inward.parents
|
||||||
def :*= (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo) { inward.:*=(h)(p, sourceInfo) }
|
def bind(h: OutwardNodeHandle[DI, UI, BI], binding: NodeBinding)(implicit p: Parameters, sourceInfo: SourceInfo): Unit = inward.bind(h.outward, binding)
|
||||||
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) }
|
// 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
|
sealed trait NodeBinding
|
||||||
@ -140,9 +173,18 @@ case object BIND_ONCE extends NodeBinding
|
|||||||
case object BIND_QUERY extends NodeBinding
|
case object BIND_QUERY extends NodeBinding
|
||||||
case object BIND_STAR 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]
|
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
|
protected[diplomacy] val numPI: Range.Inclusive
|
||||||
require (!numPI.isEmpty, s"No number of inputs would be acceptable to ${name}${lazyModule.line}")
|
require (!numPI.isEmpty, s"No number of inputs would be acceptable to ${name}${lazyModule.line}")
|
||||||
@ -165,16 +207,19 @@ trait InwardNode[DI, UI, BI <: Data] extends BaseNode with InwardNodeHandle[DI,
|
|||||||
protected[diplomacy] val iStar: Int
|
protected[diplomacy] val iStar: Int
|
||||||
protected[diplomacy] val iPortMapping: Seq[(Int, Int)]
|
protected[diplomacy] val iPortMapping: Seq[(Int, Int)]
|
||||||
protected[diplomacy] val iParams: Seq[UI]
|
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]
|
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
|
protected[diplomacy] val numPO: Range.Inclusive
|
||||||
require (!numPO.isEmpty, s"No number of outputs would be acceptable to ${name}${lazyModule.line}")
|
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 numPO: Range.Inclusive,
|
||||||
protected[diplomacy] val numPI: Range.Inclusive)(
|
protected[diplomacy] val numPI: Range.Inclusive)(
|
||||||
implicit valName: ValName)
|
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 resolveStar(iKnown: Int, oKnown: Int, iStar: Int, oStar: Int): (Int, Int)
|
||||||
protected[diplomacy] def mapParamsD(n: Int, p: Seq[DI]): Seq[DO]
|
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
|
// 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 x = this // x := y
|
||||||
val y = h.outward
|
val y = h
|
||||||
val info = sourceLine(sourceInfo, " at ", "")
|
val info = sourceLine(sourceInfo, " at ", "")
|
||||||
val i = x.iPushed
|
val i = x.iPushed
|
||||||
val o = y.oPushed
|
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)
|
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
|
// 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)
|
val re = inner.render(e)
|
||||||
(n, re.copy(flipped = re.flipped != p(RenderFlipped)))
|
(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](
|
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 {
|
tiles.flatMap(_.dcacheOpt).foreach { dc =>
|
||||||
sbus.fromSyncTiles(BufferParams.default, TileMasterPortParams().adapterChain(this)) :=* _.node
|
sbus.fromTile(None) { implicit p => TileMasterPortParams(addBuffers = 1).adapt(this)(dc.node) }
|
||||||
}
|
}
|
||||||
|
|
||||||
val pbusRAM = LazyModule(new TLRAM(AddressSet(testRamAddr, 0xffff), true, false, pbus.beatBytes))
|
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.diplomacy._
|
||||||
import freechips.rocketchip.regmapper._
|
import freechips.rocketchip.regmapper._
|
||||||
import freechips.rocketchip.tilelink._
|
import freechips.rocketchip.tilelink._
|
||||||
|
import freechips.rocketchip.interrupts._
|
||||||
|
|
||||||
trait BusErrors extends Bundle {
|
trait BusErrors extends Bundle {
|
||||||
def toErrorList: List[Option[Valid[UInt]]]
|
def toErrorList: List[Option[Valid[UInt]]]
|
||||||
|
@ -10,6 +10,7 @@ import freechips.rocketchip.coreplex.CacheBlockBytes
|
|||||||
import freechips.rocketchip.diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
import freechips.rocketchip.tile._
|
import freechips.rocketchip.tile._
|
||||||
import freechips.rocketchip.tilelink._
|
import freechips.rocketchip.tilelink._
|
||||||
|
import freechips.rocketchip.interrupts._
|
||||||
import freechips.rocketchip.util._
|
import freechips.rocketchip.util._
|
||||||
|
|
||||||
class ScratchpadSlavePort(address: AddressSet, coreDataBytes: Int, usingAtomics: Boolean)(implicit p: Parameters) extends LazyModule {
|
class ScratchpadSlavePort(address: AddressSet, coreDataBytes: Int, usingAtomics: Boolean)(implicit p: Parameters) extends LazyModule {
|
||||||
|
@ -5,7 +5,7 @@ package freechips.rocketchip.tile
|
|||||||
import Chisel._
|
import Chisel._
|
||||||
|
|
||||||
import freechips.rocketchip.config.Parameters
|
import freechips.rocketchip.config.Parameters
|
||||||
import freechips.rocketchip.tilelink.{IntSinkNode, IntSinkPortSimple}
|
import freechips.rocketchip.interrupts.{IntSinkNode, IntSinkPortSimple}
|
||||||
import freechips.rocketchip.util._
|
import freechips.rocketchip.util._
|
||||||
|
|
||||||
class TileInterrupts(implicit p: Parameters) extends CoreBundle()(p) {
|
class TileInterrupts(implicit p: Parameters) extends CoreBundle()(p) {
|
||||||
|
@ -9,6 +9,7 @@ import freechips.rocketchip.coreplex._
|
|||||||
import freechips.rocketchip.diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
import freechips.rocketchip.rocket._
|
import freechips.rocketchip.rocket._
|
||||||
import freechips.rocketchip.tilelink._
|
import freechips.rocketchip.tilelink._
|
||||||
|
import freechips.rocketchip.interrupts._
|
||||||
import freechips.rocketchip.util._
|
import freechips.rocketchip.util._
|
||||||
|
|
||||||
case class RocketTileParams(
|
case class RocketTileParams(
|
||||||
@ -18,11 +19,12 @@ case class RocketTileParams(
|
|||||||
rocc: Seq[RoCCParams] = Nil,
|
rocc: Seq[RoCCParams] = Nil,
|
||||||
btb: Option[BTBParams] = Some(BTBParams()),
|
btb: Option[BTBParams] = Some(BTBParams()),
|
||||||
dataScratchpadBytes: Int = 0,
|
dataScratchpadBytes: Int = 0,
|
||||||
boundaryBuffers: Boolean = false,
|
|
||||||
trace: Boolean = false,
|
trace: Boolean = false,
|
||||||
hcfOnUncorrectable: Boolean = false,
|
hcfOnUncorrectable: Boolean = false,
|
||||||
name: Option[String] = Some("tile"),
|
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(icache.isDefined)
|
||||||
require(dcache.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)
|
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) {
|
class RocketTileWrapper(
|
||||||
val rocket = LazyModule(new RocketTile(rtp))
|
params: RocketTileParams,
|
||||||
val asyncIntNode : IntInwardNode
|
val crossing: CoreplexClockCrossing)
|
||||||
val periphIntNode : IntInwardNode
|
(implicit p: Parameters) extends BaseTile(params) with HasCrossing {
|
||||||
val coreIntNode : IntInwardNode
|
|
||||||
val intOutputNode = rocket.intOutputNode
|
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)
|
val intXbar = LazyModule(new IntXbar)
|
||||||
|
|
||||||
rocket.intNode := intXbar.intnode
|
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)) {
|
override lazy val module = new BaseTileModule(this, () => new RocketTileWrapperBundle(this)) {
|
||||||
// signals that do not change based on crossing type:
|
// signals that do not change based on crossing type:
|
||||||
rocket.module.io.hartid := io.hartid
|
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 }
|
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.config.Parameters
|
||||||
import freechips.rocketchip.diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
import freechips.rocketchip.util._
|
import freechips.rocketchip.util._
|
||||||
|
import freechips.rocketchip.coreplex.{CrossingWrapper, AsynchronousCrossing}
|
||||||
|
|
||||||
class TLAsyncCrossingSource(sync: Int = 3)(implicit p: Parameters) extends LazyModule
|
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
|
class TLAsyncCrossing(depth: Int = 8, sync: Int = 3)(implicit p: Parameters) extends LazyModule
|
||||||
{
|
{
|
||||||
val source = LazyModule(new TLAsyncCrossingSource(sync))
|
val source = LazyModule(new TLAsyncCrossingSource(sync))
|
||||||
@ -113,26 +115,19 @@ import freechips.rocketchip.unittest._
|
|||||||
|
|
||||||
class TLRAMAsyncCrossing(txns: Int)(implicit p: Parameters) extends LazyModule {
|
class TLRAMAsyncCrossing(txns: Int)(implicit p: Parameters) extends LazyModule {
|
||||||
val model = LazyModule(new TLRAMModel("AsyncCrossing"))
|
val model = LazyModule(new TLRAMModel("AsyncCrossing"))
|
||||||
val ram = LazyModule(new TLRAM(AddressSet(0x0, 0x3ff)))
|
|
||||||
val fuzz = LazyModule(new TLFuzzer(txns))
|
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
|
model.node := fuzz.node
|
||||||
cross.node := TLFragmenter(4, 256)(TLDelayer(0.1)(model.node))
|
ram.node := island.crossTLIn := TLFragmenter(4, 256)(TLDelayer(0.1)(model.node))
|
||||||
ram.node := cross.node
|
|
||||||
|
|
||||||
lazy val module = new LazyModuleImp(this) with UnitTestModule {
|
lazy val module = new LazyModuleImp(this) with UnitTestModule {
|
||||||
io.finished := fuzz.module.io.finished
|
io.finished := fuzz.module.io.finished
|
||||||
|
|
||||||
// Shove the RAM into another clock domain
|
// Shove the RAM into another clock domain
|
||||||
val clocks = Module(new Pow2ClockDivider(2))
|
val clocks = Module(new Pow2ClockDivider(2))
|
||||||
ram.module.clock := clocks.io.clock_out
|
island.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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,28 +71,10 @@ object TLBuffer
|
|||||||
buffer.node :=? x
|
buffer.node :=? x
|
||||||
buffer.node
|
buffer.node
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
class TLBufferChain(depth: Int)(implicit p: Parameters) extends LazyModule {
|
def chain(depth: Int, name: Option[String] = None)(implicit p: Parameters): Seq[TLNode] = {
|
||||||
val buf_chain = List.fill(depth)(LazyModule(new TLBuffer(BufferParams.default)))
|
val buffers = Seq.fill(depth) { LazyModule(new TLBuffer()) }
|
||||||
val node = if (depth > 0) {
|
name.foreach { n => buffers.zipWithIndex.foreach { case (b, i) => b.suggestName(s"${n}_${i}") } }
|
||||||
(buf_chain.init zip buf_chain.tail) foreach { case (prev, next) => next.node :=? prev.node }
|
buffers.map(_.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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,34 +68,24 @@ abstract class TLBusWrapper(params: TLBusParams, val busName: String)(implicit p
|
|||||||
protected def inwardNode: TLInwardNode = xbar.node
|
protected def inwardNode: TLInwardNode = xbar.node
|
||||||
protected def inwardBufNode: TLInwardNode = master_buffer.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 bufferFromMasters: TLInwardNode = inwardBufNode
|
||||||
|
|
||||||
def bufferToSlaves: TLOutwardNode = outwardBufNode
|
def bufferToSlaves: TLOutwardNode = outwardBufNode
|
||||||
|
|
||||||
def toSyncSlaves(name: Option[String] = None, addBuffers: Int = 0): TLOutwardNode = SinkCardinality { implicit p =>
|
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 =>
|
def toAsyncSlaves(sync: Int = 3, name: Option[String] = None, addBuffers: Int = 0): TLAsyncOutwardNode = SinkCardinality { implicit p =>
|
||||||
val source = LazyModule(new TLAsyncCrossingSource(sync))
|
val source = LazyModule(new TLAsyncCrossingSource(sync))
|
||||||
name.foreach{ n => source.suggestName(s"${busName}_${n}_TLAsyncCrossingSource")}
|
name.foreach{ n => source.suggestName(s"${busName}_${n}_TLAsyncCrossingSource")}
|
||||||
source.node :=? TLBufferChain(addBuffers)(outwardNode)
|
source.node :=? TLBuffer.chain(addBuffers).foldRight(outwardNode)(_ :=? _)
|
||||||
source.node
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def toRationalSlaves(name: Option[String] = None, addBuffers: Int = 0): TLRationalOutwardNode = SinkCardinality { implicit p =>
|
def toRationalSlaves(name: Option[String] = None, addBuffers: Int = 0): TLRationalOutwardNode = SinkCardinality { implicit p =>
|
||||||
val source = LazyModule(new TLRationalCrossingSource())
|
val source = LazyModule(new TLRationalCrossingSource())
|
||||||
name.foreach{ n => source.suggestName(s"${busName}_${n}_TLRationalCrossingSource")}
|
name.foreach{ n => source.suggestName(s"${busName}_${n}_TLRationalCrossingSource")}
|
||||||
source.node :=? TLBufferChain(addBuffers)(outwardNode)
|
source.node :=? TLBuffer.chain(addBuffers).foldRight(outwardNode)(_ :=? _)
|
||||||
source.node
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def toVariableWidthSlaves: TLOutwardNode = outwardFragNode
|
def toVariableWidthSlaves: TLOutwardNode = outwardFragNode
|
||||||
|
@ -233,28 +233,16 @@ class TLFuzzRAM(txns: Int)(implicit p: Parameters) extends LazyModule
|
|||||||
val xbar = LazyModule(new TLXbar)
|
val xbar = LazyModule(new TLXbar)
|
||||||
val xbar2= LazyModule(new TLXbar)
|
val xbar2= LazyModule(new TLXbar)
|
||||||
val fuzz = LazyModule(new TLFuzzer(txns))
|
val fuzz = LazyModule(new TLFuzzer(txns))
|
||||||
val cross = LazyModule(new TLAsyncCrossing)
|
|
||||||
|
|
||||||
model.node := fuzz.node
|
model.node := fuzz.node
|
||||||
xbar2.node := TLAtomicAutomata()(model.node)
|
xbar2.node := TLAtomicAutomata()(model.node)
|
||||||
ram2.node := TLFragmenter(16, 256)(xbar2.node)
|
ram2.node := TLFragmenter(16, 256)(xbar2.node)
|
||||||
xbar.node := TLWidthWidget(16)(TLHintHandler()(xbar2.node))
|
xbar.node := TLWidthWidget(16)(TLHintHandler()(xbar2.node))
|
||||||
cross.node := TLFragmenter(4, 256)(TLBuffer()(xbar.node))
|
ram.node := TLFragmenter(4, 256)(TLBuffer()(xbar.node))
|
||||||
ram.node := cross.node
|
|
||||||
gpio.node := TLFragmenter(4, 32)(TLBuffer()(xbar.node))
|
gpio.node := TLFragmenter(4, 32)(TLBuffer()(xbar.node))
|
||||||
|
|
||||||
lazy val module = new LazyModuleImp(this) with UnitTestModule {
|
lazy val module = new LazyModuleImp(this) with UnitTestModule {
|
||||||
io.finished := fuzz.module.io.finished
|
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
|
class TLRationalCrossing(direction: RationalDirection = Symmetric)(implicit p: Parameters) extends LazyModule
|
||||||
{
|
{
|
||||||
val source = LazyModule(new TLRationalCrossingSource)
|
val source = LazyModule(new TLRationalCrossingSource)
|
||||||
|
@ -6,6 +6,7 @@ import Chisel._
|
|||||||
import freechips.rocketchip.config.Parameters
|
import freechips.rocketchip.config.Parameters
|
||||||
import freechips.rocketchip.diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
import freechips.rocketchip.regmapper._
|
import freechips.rocketchip.regmapper._
|
||||||
|
import freechips.rocketchip.interrupts._
|
||||||
import freechips.rocketchip.util.HeterogeneousBag
|
import freechips.rocketchip.util.HeterogeneousBag
|
||||||
import scala.math.{min,max}
|
import scala.math.{min,max}
|
||||||
|
|
||||||
|
@ -9,13 +9,11 @@ package object tilelink
|
|||||||
{
|
{
|
||||||
type TLInwardNode = InwardNodeHandle[TLClientPortParameters, TLManagerPortParameters, TLBundle]
|
type TLInwardNode = InwardNodeHandle[TLClientPortParameters, TLManagerPortParameters, TLBundle]
|
||||||
type TLOutwardNode = OutwardNodeHandle[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 TLAsyncInwardNode = InwardNodeHandle[TLAsyncClientPortParameters, TLAsyncManagerPortParameters, TLAsyncBundle]
|
||||||
type TLAsyncOutwardNode = OutwardNodeHandle[TLAsyncClientPortParameters, TLAsyncManagerPortParameters, TLAsyncBundle]
|
type TLAsyncOutwardNode = OutwardNodeHandle[TLAsyncClientPortParameters, TLAsyncManagerPortParameters, TLAsyncBundle]
|
||||||
type TLRationalInwardNode = InwardNodeHandle[TLRationalClientPortParameters, TLRationalManagerPortParameters, TLRationalBundle]
|
type TLRationalInwardNode = InwardNodeHandle[TLRationalClientPortParameters, TLRationalManagerPortParameters, TLRationalBundle]
|
||||||
type TLRationalOutwardNode = OutwardNodeHandle[TLRationalClientPortParameters, TLRationalManagerPortParameters, TLRationalBundle]
|
type TLRationalOutwardNode = OutwardNodeHandle[TLRationalClientPortParameters, TLRationalManagerPortParameters, TLRationalBundle]
|
||||||
type TLMixedNode = MixedNode[TLClientPortParameters, TLManagerPortParameters, TLEdgeIn, TLBundle,
|
type TLMixedNode = MixedNode[TLClientPortParameters, TLManagerPortParameters, TLEdgeIn, TLBundle,
|
||||||
TLClientPortParameters, TLManagerPortParameters, TLEdgeOut, 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 {
|
abstract class Crossing[T <: Data] extends Module {
|
||||||
val io: CrossingIO[T]
|
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