diff --git a/src/main/scala/coreplex/RocketTiles.scala b/src/main/scala/coreplex/RocketTiles.scala index 4e531f26..3b7acd67 100644 --- a/src/main/scala/coreplex/RocketTiles.scala +++ b/src/main/scala/coreplex/RocketTiles.scala @@ -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 diff --git a/src/main/scala/rocket/Tile.scala b/src/main/scala/rocket/Tile.scala index 8691d9a3..eb59dd3c 100644 --- a/src/main/scala/rocket/Tile.scala +++ b/src/main/scala/rocket/Tile.scala @@ -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 diff --git a/src/main/scala/rocketchip/ExampleTop.scala b/src/main/scala/rocketchip/ExampleTop.scala index 66fd1112..96eabc2c 100644 --- a/src/main/scala/rocketchip/ExampleTop.scala +++ b/src/main/scala/rocketchip/ExampleTop.scala @@ -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 { diff --git a/src/main/scala/rocketchip/Periphery.scala b/src/main/scala/rocketchip/Periphery.scala index 73a63ccb..75071cf0 100644 --- a/src/main/scala/rocketchip/Periphery.scala +++ b/src/main/scala/rocketchip/Periphery.scala @@ -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 diff --git a/src/main/scala/tile/Interrupts.scala b/src/main/scala/tile/Interrupts.scala index 4d76c2c4..c88ef040 100644 --- a/src/main/scala/tile/Interrupts.scala +++ b/src/main/scala/tile/Interrupts.scala @@ -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 } } }