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)
|
case SharedMemoryTLEdge => l1tol2.node.edgesIn(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
val intBar = LazyModule(new IntXbar)
|
val asyncIntXbar = LazyModule(new IntXbar)
|
||||||
intBar.intnode := debug.intnode // debug
|
val periphIntXbar = LazyModule(new IntXbar)
|
||||||
intBar.intnode := clint.intnode // msip+mtip
|
val coreIntXbar = LazyModule(new IntXbar)
|
||||||
intBar.intnode := plic.intnode // meip
|
|
||||||
if (c.core.useVM) intBar.intnode := plic.intnode // seip
|
// Local Interrupts must be synchronized to the core clock
|
||||||
lip.foreach { intBar.intnode := _ } // lip
|
// 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 {
|
crossing match {
|
||||||
case SynchronousCrossing(params) => {
|
case SynchronousCrossing(params) => {
|
||||||
@ -55,7 +66,9 @@ trait HasRocketTiles extends CoreplexRISCVPlatform {
|
|||||||
fixer.node :=* buffer.node
|
fixer.node :=* buffer.node
|
||||||
l1tol2.node :=* fixer.node
|
l1tol2.node :=* fixer.node
|
||||||
wrapper.slaveNode :*= cbus.node
|
wrapper.slaveNode :*= cbus.node
|
||||||
wrapper.intNode := intBar.intnode
|
wrapper.asyncIntNode := asyncIntXbar.intnode
|
||||||
|
wrapper.periphIntNode := periphIntXbar.intnode
|
||||||
|
wrapper.coreIntNode := coreIntXbar.intnode
|
||||||
(io: HasRocketTilesBundle) => {
|
(io: HasRocketTilesBundle) => {
|
||||||
// leave clock as default (simpler for hierarchical PnR)
|
// leave clock as default (simpler for hierarchical PnR)
|
||||||
wrapper.module.io.hartid := UInt(i)
|
wrapper.module.io.hartid := UInt(i)
|
||||||
@ -71,7 +84,9 @@ trait HasRocketTiles extends CoreplexRISCVPlatform {
|
|||||||
fixer.node :=* sink.node
|
fixer.node :=* sink.node
|
||||||
l1tol2.node :=* fixer.node
|
l1tol2.node :=* fixer.node
|
||||||
wrapper.slaveNode :*= source.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
|
source.node :*= cbus.node
|
||||||
(io: HasRocketTilesBundle) => {
|
(io: HasRocketTilesBundle) => {
|
||||||
wrapper.module.clock := io.tcrs(i).clock
|
wrapper.module.clock := io.tcrs(i).clock
|
||||||
@ -89,7 +104,9 @@ trait HasRocketTiles extends CoreplexRISCVPlatform {
|
|||||||
fixer.node :=* sink.node
|
fixer.node :=* sink.node
|
||||||
l1tol2.node :=* fixer.node
|
l1tol2.node :=* fixer.node
|
||||||
wrapper.slaveNode :*= source.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
|
source.node :*= cbus.node
|
||||||
(io: HasRocketTilesBundle) => {
|
(io: HasRocketTilesBundle) => {
|
||||||
wrapper.module.clock := io.tcrs(i).clock
|
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 }
|
val slaveNode = new TLInputNode() { override def reverse = true }
|
||||||
rocket.slaveNode :*= slaveNode
|
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))
|
val xing = LazyModule(new IntXing(3))
|
||||||
rocket.intNode := xing.intnode
|
xing.intnode := asyncIntNode
|
||||||
xing.intnode := intNode
|
|
||||||
|
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) {
|
lazy val module = new LazyModuleImp(this) {
|
||||||
val io = new CoreBundle with HasExternallyDrivenTileConstants {
|
val io = new CoreBundle with HasExternallyDrivenTileConstants {
|
||||||
val master = masterNode.bundleOut
|
val master = masterNode.bundleOut
|
||||||
val slave = slaveNode.bundleIn
|
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:
|
// signals that do not change:
|
||||||
rocket.module.io.hartid := io.hartid
|
rocket.module.io.hartid := io.hartid
|
||||||
@ -200,16 +210,33 @@ class AsyncRocketTile(rtp: RocketTileParams, hartid: Int)(implicit p: Parameters
|
|||||||
rocket.slaveNode :*= sink.node
|
rocket.slaveNode :*= sink.node
|
||||||
sink.node :*= slaveNode
|
sink.node :*= slaveNode
|
||||||
|
|
||||||
val intNode = IntInputNode()
|
// Fully async interrupts need synchronizers,
|
||||||
val xing = LazyModule(new IntXing(3))
|
// as do those coming from the periphery clock.
|
||||||
rocket.intNode := xing.intnode
|
// Others need no synchronization.
|
||||||
xing.intnode := intNode
|
|
||||||
|
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) {
|
lazy val module = new LazyModuleImp(this) {
|
||||||
val io = new CoreBundle with HasExternallyDrivenTileConstants {
|
val io = new CoreBundle with HasExternallyDrivenTileConstants {
|
||||||
val master = masterNode.bundleOut
|
val master = masterNode.bundleOut
|
||||||
val slave = slaveNode.bundleIn
|
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:
|
// signals that do not change:
|
||||||
rocket.module.io.hartid := io.hartid
|
rocket.module.io.hartid := io.hartid
|
||||||
@ -230,20 +257,34 @@ class RationalRocketTile(rtp: RocketTileParams, hartid: Int)(implicit p: Paramet
|
|||||||
rocket.slaveNode :*= sink.node
|
rocket.slaveNode :*= sink.node
|
||||||
sink.node :*= slaveNode
|
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
|
val asyncIntNode = IntInputNode()
|
||||||
// if tlClk and coreClk are related (e.g. Debug Interrupt, which
|
val periphIntNode = IntInputNode()
|
||||||
// is coming directly from e.g. TCK)
|
val coreIntNode = IntInputNode()
|
||||||
val xing = LazyModule(new IntXing(3))
|
|
||||||
rocket.intNode := xing.intnode
|
val asyncXing = LazyModule(new IntXing(3))
|
||||||
xing.intnode := intNode
|
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) {
|
lazy val module = new LazyModuleImp(this) {
|
||||||
val io = new CoreBundle with HasExternallyDrivenTileConstants {
|
val io = new CoreBundle with HasExternallyDrivenTileConstants {
|
||||||
val master = masterNode.bundleOut
|
val master = masterNode.bundleOut
|
||||||
val slave = slaveNode.bundleIn
|
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:
|
// signals that do not change:
|
||||||
rocket.module.io.hartid := io.hartid
|
rocket.module.io.hartid := io.hartid
|
||||||
|
@ -9,7 +9,7 @@ import rocketchip._
|
|||||||
|
|
||||||
/** Example Top with Periphery (w/o coreplex) */
|
/** Example Top with Periphery (w/o coreplex) */
|
||||||
abstract class ExampleTop(implicit p: Parameters) extends BaseTop
|
abstract class ExampleTop(implicit p: Parameters) extends BaseTop
|
||||||
with PeripheryExtInterrupts
|
with PeripheryAsyncExtInterrupts
|
||||||
with PeripheryMasterAXI4Mem
|
with PeripheryMasterAXI4Mem
|
||||||
with PeripheryMasterAXI4MMIO
|
with PeripheryMasterAXI4MMIO
|
||||||
with PeripherySlaveAXI4 {
|
with PeripherySlaveAXI4 {
|
||||||
|
@ -47,8 +47,7 @@ trait HasPeripheryParameters {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/////
|
/////
|
||||||
|
abstract trait PeripheryExtInterrupts {
|
||||||
trait PeripheryExtInterrupts {
|
|
||||||
this: HasTopLevelNetworks =>
|
this: HasTopLevelNetworks =>
|
||||||
|
|
||||||
private val device = new Device with DeviceInterrupts {
|
private val device = new Device with DeviceInterrupts {
|
||||||
@ -60,11 +59,6 @@ trait PeripheryExtInterrupts {
|
|||||||
val nExtInterrupts = p(NExtTopInterrupts)
|
val nExtInterrupts = p(NExtTopInterrupts)
|
||||||
val extInterrupts = IntInternalInputNode(IntSourcePortSimple(num = nExtInterrupts, resources = device.int))
|
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 {
|
trait PeripheryExtInterruptsBundle {
|
||||||
@ -82,8 +76,35 @@ trait PeripheryExtInterruptsModule {
|
|||||||
outer.extInterrupts.bundleIn.flatten.zipWithIndex.foreach { case(o, i) => o := io.interrupts(i) }
|
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 {
|
trait PeripheryMasterAXI4Mem {
|
||||||
this: HasTopLevelNetworks =>
|
this: HasTopLevelNetworks =>
|
||||||
val module: PeripheryMasterAXI4MemModule
|
val module: PeripheryMasterAXI4MemModule
|
||||||
|
@ -46,12 +46,15 @@ trait HasExternalInterruptsModule {
|
|||||||
|
|
||||||
// go from flat diplomatic Interrupts to bundled TileInterrupts
|
// go from flat diplomatic Interrupts to bundled TileInterrupts
|
||||||
def decodeCoreInterrupts(core: TileInterrupts) {
|
def decodeCoreInterrupts(core: TileInterrupts) {
|
||||||
val core_ips = Seq(
|
val async_ips = Seq(core.debug)
|
||||||
core.debug,
|
val periph_ips = Seq(
|
||||||
core.msip,
|
core.msip,
|
||||||
core.mtip,
|
core.mtip,
|
||||||
core.meip,
|
core.meip,
|
||||||
core.seip.getOrElse(Wire(Bool()))) ++ core.lip
|
core.seip.getOrElse(Wire(Bool())))
|
||||||
core_ips.zip(io.interrupts(0)).foreach { case(c, i) => c := i }
|
|
||||||
|
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