1
0
Fork 0

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:
Megan Wachs 2017-04-28 14:49:24 -07:00 committed by GitHub
parent 9b688ce7e2
commit d67738204f
5 changed files with 123 additions and 41 deletions

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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 }
}
}