Interrupts: Less Pessimistic Synchronization (#714)
* interrupts: Less pessimistic synchronization for the different interrupt types. There are some issues with the interrupt number assignments. * interrupts: Allow an option to NOT synchronize all the external interrupts coming into PLIC * interrupts: ExampleRocketChipTop uses PeripheryAsyncExtInterrupts. Realized 'abstract' doesn't do what I thought in Scala. * interrupts: use consistent async/periph/core ordering * interrupts: Properly condition on 0 External interrupts * interrupts: CLINT is also synchronous to periph clock
This commit is contained in:
parent
9b688ce7e2
commit
d67738204f
@ -39,12 +39,23 @@ trait HasRocketTiles extends CoreplexRISCVPlatform {
|
||||
case SharedMemoryTLEdge => l1tol2.node.edgesIn(0)
|
||||
}
|
||||
|
||||
val intBar = LazyModule(new IntXbar)
|
||||
intBar.intnode := debug.intnode // debug
|
||||
intBar.intnode := clint.intnode // msip+mtip
|
||||
intBar.intnode := plic.intnode // meip
|
||||
if (c.core.useVM) intBar.intnode := plic.intnode // seip
|
||||
lip.foreach { intBar.intnode := _ } // lip
|
||||
val asyncIntXbar = LazyModule(new IntXbar)
|
||||
val periphIntXbar = LazyModule(new IntXbar)
|
||||
val coreIntXbar = LazyModule(new IntXbar)
|
||||
|
||||
// Local Interrupts must be synchronized to the core clock
|
||||
// before being passed into this module.
|
||||
// This allows faster latency for interrupts which are already synchronized.
|
||||
// The CLINT and PLIC outputs interrupts that are synchronous to the periphery clock,
|
||||
// so may or may not need to be synchronized depending on the Tile's
|
||||
// synchronization type.
|
||||
// Debug interrupt is definitely asynchronous in all cases.
|
||||
|
||||
asyncIntXbar.intnode := debug.intnode // debug
|
||||
periphIntXbar.intnode := clint.intnode // msip+mtip
|
||||
periphIntXbar.intnode := plic.intnode // meip
|
||||
if (c.core.useVM) periphIntXbar.intnode := plic.intnode // seip
|
||||
lip.foreach { coreIntXbar.intnode := _ } // lip
|
||||
|
||||
crossing match {
|
||||
case SynchronousCrossing(params) => {
|
||||
@ -55,7 +66,9 @@ trait HasRocketTiles extends CoreplexRISCVPlatform {
|
||||
fixer.node :=* buffer.node
|
||||
l1tol2.node :=* fixer.node
|
||||
wrapper.slaveNode :*= cbus.node
|
||||
wrapper.intNode := intBar.intnode
|
||||
wrapper.asyncIntNode := asyncIntXbar.intnode
|
||||
wrapper.periphIntNode := periphIntXbar.intnode
|
||||
wrapper.coreIntNode := coreIntXbar.intnode
|
||||
(io: HasRocketTilesBundle) => {
|
||||
// leave clock as default (simpler for hierarchical PnR)
|
||||
wrapper.module.io.hartid := UInt(i)
|
||||
@ -71,7 +84,9 @@ trait HasRocketTiles extends CoreplexRISCVPlatform {
|
||||
fixer.node :=* sink.node
|
||||
l1tol2.node :=* fixer.node
|
||||
wrapper.slaveNode :*= source.node
|
||||
wrapper.intNode := intBar.intnode
|
||||
wrapper.asyncIntNode := asyncIntXbar.intnode
|
||||
wrapper.periphIntNode := periphIntXbar.intnode
|
||||
wrapper.coreIntNode := coreIntXbar.intnode
|
||||
source.node :*= cbus.node
|
||||
(io: HasRocketTilesBundle) => {
|
||||
wrapper.module.clock := io.tcrs(i).clock
|
||||
@ -89,7 +104,9 @@ trait HasRocketTiles extends CoreplexRISCVPlatform {
|
||||
fixer.node :=* sink.node
|
||||
l1tol2.node :=* fixer.node
|
||||
wrapper.slaveNode :*= source.node
|
||||
wrapper.intNode := intBar.intnode
|
||||
wrapper.asyncIntNode := asyncIntXbar.intnode
|
||||
wrapper.periphIntNode := periphIntXbar.intnode
|
||||
wrapper.coreIntNode := coreIntXbar.intnode
|
||||
source.node :*= cbus.node
|
||||
(io: HasRocketTilesBundle) => {
|
||||
wrapper.module.clock := io.tcrs(i).clock
|
||||
|
@ -166,20 +166,30 @@ class SyncRocketTile(rtp: RocketTileParams, hartid: Int)(implicit p: Parameters)
|
||||
val slaveNode = new TLInputNode() { override def reverse = true }
|
||||
rocket.slaveNode :*= slaveNode
|
||||
|
||||
val intNode = IntInputNode()
|
||||
// Fully async interrupts need synchronizers.
|
||||
// Others need no synchronization.
|
||||
|
||||
val asyncIntNode = IntInputNode()
|
||||
val periphIntNode = IntInputNode()
|
||||
val coreIntNode = IntInputNode()
|
||||
|
||||
// Some interrupt sources may be completely asynchronous, even
|
||||
// if tlClk and coreClk are the same (e.g. Debug Interrupt, which
|
||||
// is coming directly from e.g. TCK)
|
||||
val xing = LazyModule(new IntXing(3))
|
||||
rocket.intNode := xing.intnode
|
||||
xing.intnode := intNode
|
||||
xing.intnode := asyncIntNode
|
||||
|
||||
val intXbar = LazyModule(new IntXbar)
|
||||
intXbar.intnode := xing.intnode
|
||||
intXbar.intnode := periphIntNode
|
||||
intXbar.intnode := coreIntNode
|
||||
|
||||
rocket.intNode := intXbar.intnode
|
||||
|
||||
lazy val module = new LazyModuleImp(this) {
|
||||
val io = new CoreBundle with HasExternallyDrivenTileConstants {
|
||||
val master = masterNode.bundleOut
|
||||
val slave = slaveNode.bundleIn
|
||||
val interrupts = intNode.bundleIn
|
||||
val asyncInterrupts = asyncIntNode.bundleIn
|
||||
val periphInterrupts = periphIntNode.bundleIn
|
||||
val coreInterrupts = coreIntNode.bundleIn
|
||||
}
|
||||
// signals that do not change:
|
||||
rocket.module.io.hartid := io.hartid
|
||||
@ -200,16 +210,33 @@ class AsyncRocketTile(rtp: RocketTileParams, hartid: Int)(implicit p: Parameters
|
||||
rocket.slaveNode :*= sink.node
|
||||
sink.node :*= slaveNode
|
||||
|
||||
val intNode = IntInputNode()
|
||||
val xing = LazyModule(new IntXing(3))
|
||||
rocket.intNode := xing.intnode
|
||||
xing.intnode := intNode
|
||||
// Fully async interrupts need synchronizers,
|
||||
// as do those coming from the periphery clock.
|
||||
// Others need no synchronization.
|
||||
|
||||
val asyncIntNode = IntInputNode()
|
||||
val periphIntNode = IntInputNode()
|
||||
val coreIntNode = IntInputNode()
|
||||
|
||||
val asyncXing = LazyModule(new IntXing(3))
|
||||
val periphXing = LazyModule(new IntXing(3))
|
||||
asyncXing.intnode := asyncIntNode
|
||||
periphXing.intnode := periphIntNode
|
||||
|
||||
val intXbar = LazyModule(new IntXbar)
|
||||
intXbar.intnode := asyncXing.intnode
|
||||
intXbar.intnode := periphXing.intnode
|
||||
intXbar.intnode := coreIntNode
|
||||
|
||||
rocket.intNode := intXbar.intnode
|
||||
|
||||
lazy val module = new LazyModuleImp(this) {
|
||||
val io = new CoreBundle with HasExternallyDrivenTileConstants {
|
||||
val master = masterNode.bundleOut
|
||||
val slave = slaveNode.bundleIn
|
||||
val interrupts = intNode.bundleIn
|
||||
val asyncInterrupts = asyncIntNode.bundleIn
|
||||
val periphInterrupts = periphIntNode.bundleIn
|
||||
val coreInterrupts = coreIntNode.bundleIn
|
||||
}
|
||||
// signals that do not change:
|
||||
rocket.module.io.hartid := io.hartid
|
||||
@ -230,20 +257,34 @@ class RationalRocketTile(rtp: RocketTileParams, hartid: Int)(implicit p: Paramet
|
||||
rocket.slaveNode :*= sink.node
|
||||
sink.node :*= slaveNode
|
||||
|
||||
val intNode = IntInputNode()
|
||||
// Fully async interrupts need synchronizers.
|
||||
// Those coming from periphery clock need a
|
||||
// rational synchronizer.
|
||||
// Others need no synchronization.
|
||||
|
||||
// Some interrupt sources may be completely asynchronous, even
|
||||
// if tlClk and coreClk are related (e.g. Debug Interrupt, which
|
||||
// is coming directly from e.g. TCK)
|
||||
val xing = LazyModule(new IntXing(3))
|
||||
rocket.intNode := xing.intnode
|
||||
xing.intnode := intNode
|
||||
val asyncIntNode = IntInputNode()
|
||||
val periphIntNode = IntInputNode()
|
||||
val coreIntNode = IntInputNode()
|
||||
|
||||
val asyncXing = LazyModule(new IntXing(3))
|
||||
val periphXing = LazyModule(new IntXing(1))
|
||||
asyncXing.intnode := asyncIntNode
|
||||
periphXing.intnode := periphIntNode
|
||||
|
||||
val intXbar = LazyModule(new IntXbar)
|
||||
intXbar.intnode := asyncXing.intnode
|
||||
intXbar.intnode := periphXing.intnode
|
||||
intXbar.intnode := coreIntNode
|
||||
|
||||
rocket.intNode := intXbar.intnode
|
||||
|
||||
lazy val module = new LazyModuleImp(this) {
|
||||
val io = new CoreBundle with HasExternallyDrivenTileConstants {
|
||||
val master = masterNode.bundleOut
|
||||
val slave = slaveNode.bundleIn
|
||||
val interrupts = intNode.bundleIn
|
||||
val asyncInterrupts = asyncIntNode.bundleIn
|
||||
val periphInterrupts = periphIntNode.bundleIn
|
||||
val coreInterrupts = coreIntNode.bundleIn
|
||||
}
|
||||
// signals that do not change:
|
||||
rocket.module.io.hartid := io.hartid
|
||||
|
@ -9,7 +9,7 @@ import rocketchip._
|
||||
|
||||
/** Example Top with Periphery (w/o coreplex) */
|
||||
abstract class ExampleTop(implicit p: Parameters) extends BaseTop
|
||||
with PeripheryExtInterrupts
|
||||
with PeripheryAsyncExtInterrupts
|
||||
with PeripheryMasterAXI4Mem
|
||||
with PeripheryMasterAXI4MMIO
|
||||
with PeripherySlaveAXI4 {
|
||||
|
@ -47,8 +47,7 @@ trait HasPeripheryParameters {
|
||||
}
|
||||
|
||||
/////
|
||||
|
||||
trait PeripheryExtInterrupts {
|
||||
abstract trait PeripheryExtInterrupts {
|
||||
this: HasTopLevelNetworks =>
|
||||
|
||||
private val device = new Device with DeviceInterrupts {
|
||||
@ -60,11 +59,6 @@ trait PeripheryExtInterrupts {
|
||||
val nExtInterrupts = p(NExtTopInterrupts)
|
||||
val extInterrupts = IntInternalInputNode(IntSourcePortSimple(num = nExtInterrupts, resources = device.int))
|
||||
|
||||
if (nExtInterrupts > 0) {
|
||||
val extInterruptXing = LazyModule(new IntXing)
|
||||
intBus.intnode := extInterruptXing.intnode
|
||||
extInterruptXing.intnode := extInterrupts
|
||||
}
|
||||
}
|
||||
|
||||
trait PeripheryExtInterruptsBundle {
|
||||
@ -82,8 +76,35 @@ trait PeripheryExtInterruptsModule {
|
||||
outer.extInterrupts.bundleIn.flatten.zipWithIndex.foreach { case(o, i) => o := io.interrupts(i) }
|
||||
}
|
||||
|
||||
// This trait should be used if the External Interrupts have NOT
|
||||
// already been synchronized
|
||||
// to the Periphery (PLIC) Clock.
|
||||
|
||||
trait PeripheryAsyncExtInterrupts extends PeripheryExtInterrupts {
|
||||
this: HasTopLevelNetworks =>
|
||||
|
||||
if (nExtInterrupts > 0) {
|
||||
val extInterruptXing = LazyModule(new IntXing)
|
||||
intBus.intnode := extInterruptXing.intnode
|
||||
extInterruptXing.intnode := extInterrupts
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// This trait can be used if the External Interrupts have already been synchronized
|
||||
// to the Periphery (PLIC) Clock.
|
||||
|
||||
trait PeripherySyncExtInterrupts extends PeripheryExtInterrupts {
|
||||
this: HasTopLevelNetworks =>
|
||||
|
||||
if (nExtInterrupts > 0) {
|
||||
intBus.intnode := extInterrupts
|
||||
}
|
||||
}
|
||||
|
||||
/////
|
||||
|
||||
|
||||
trait PeripheryMasterAXI4Mem {
|
||||
this: HasTopLevelNetworks =>
|
||||
val module: PeripheryMasterAXI4MemModule
|
||||
|
@ -46,12 +46,15 @@ trait HasExternalInterruptsModule {
|
||||
|
||||
// go from flat diplomatic Interrupts to bundled TileInterrupts
|
||||
def decodeCoreInterrupts(core: TileInterrupts) {
|
||||
val core_ips = Seq(
|
||||
core.debug,
|
||||
val async_ips = Seq(core.debug)
|
||||
val periph_ips = Seq(
|
||||
core.msip,
|
||||
core.mtip,
|
||||
core.meip,
|
||||
core.seip.getOrElse(Wire(Bool()))) ++ core.lip
|
||||
core_ips.zip(io.interrupts(0)).foreach { case(c, i) => c := i }
|
||||
core.seip.getOrElse(Wire(Bool())))
|
||||
|
||||
val core_ips = core.lip
|
||||
|
||||
(async_ips ++ periph_ips ++ core_ips).zip(io.interrupts(0)).foreach { case(c, i) => c := i }
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user