From ba529c37167cadb19747a5bcd5d641021af1a8da Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 28 Oct 2016 21:20:49 -0700 Subject: [PATCH] rocketchip: use TileLink2 interrupts --- src/main/scala/coreplex/BaseCoreplex.scala | 54 ++-- src/main/scala/diplomacy/Nodes.scala | 21 +- src/main/scala/rocketchip/BaseTop.scala | 14 +- src/main/scala/rocketchip/Periphery.scala | 25 +- src/main/scala/rocketchip/TestHarness.scala | 2 +- src/main/scala/rocketchip/Utils.scala | 33 +-- src/main/scala/uncore/devices/Plic.scala | 268 +++++++++++------- src/main/scala/uncore/devices/Prci.scala | 36 ++- .../scala/uncore/tilelink2/IntNodes.scala | 28 +- .../uncore/tilelink2/RegisterRouter.scala | 3 +- 10 files changed, 270 insertions(+), 214 deletions(-) diff --git a/src/main/scala/coreplex/BaseCoreplex.scala b/src/main/scala/coreplex/BaseCoreplex.scala index b37a0a79..52482d1f 100644 --- a/src/main/scala/coreplex/BaseCoreplex.scala +++ b/src/main/scala/coreplex/BaseCoreplex.scala @@ -36,14 +36,9 @@ trait HasCoreplexParameters { lazy val outerMMIOParams = p.alterPartial({ case TLId => "L2toMMIO" }) lazy val globalAddrMap = p(rocketchip.GlobalAddrMap) lazy val nTiles = p(uncore.devices.NTiles) - lazy val nExtInterrupts = p(rocketchip.NExtInterrupts) lazy val nSlaves = p(rocketchip.NCoreplexExtClients) lazy val nMemChannels = p(NMemoryChannels) lazy val hasSupervisor = p(rocket.UseVM) - - lazy val nInterruptPriorities = if (nExtInterrupts <= 1) 0 else (nExtInterrupts min 7) - lazy val plicKey = PLICConfig(nTiles, hasSupervisor, nExtInterrupts, nInterruptPriorities) - lazy val clintKey = CoreplexLocalInterrupterConfig() } case class CoreplexParameters(implicit val p: Parameters) extends HasCoreplexParameters @@ -55,7 +50,7 @@ abstract class BareCoreplexModule[+B <: BareCoreplexBundle[BareCoreplex]](val io } trait CoreplexNetwork extends HasCoreplexParameters { - this: BareCoreplex => + this: BareCoreplex => val l1tol2 = LazyModule(new TLXbar) val l1tol2_beatBytes = p(rocketchip.EdgeDataBits)/8 @@ -65,16 +60,29 @@ trait CoreplexNetwork extends HasCoreplexParameters { val cbus_beatBytes = p(XLen)/8 val cbus_lineBytes = l1tol2_lineBytes + val mmio = TLOutputNode() + val mmioInt = IntInputNode() + cbus.node := TLAtomicAutomata(arithmetic = true)( // disable once TLB uses TL2 metadata TLWidthWidget(l1tol2_beatBytes)( TLBuffer()( l1tol2.node))) + + mmio := + TLBuffer()( + TLWidthWidget(l1tol2_beatBytes)( + l1tol2.node)) } trait CoreplexNetworkBundle extends HasCoreplexParameters { - this: BareCoreplexBundle[BareCoreplex] => + this: { + val outer: CoreplexNetwork + } => + implicit val p = outer.p + val mmio = outer.mmio.bundleOut + val interrupts = outer.mmioInt.bundleIn } trait CoreplexNetworkModule extends HasCoreplexParameters { @@ -88,11 +96,11 @@ trait CoreplexRISCV { // Build a set of Tiles val lazyTiles = p(BuildTiles) map { _(p) } val legacy = LazyModule(new TLLegacy()(outerMMIOParams)) + val tileIntNode = IntInternalOutputNode() // this should be moved into the Tile... val debug = LazyModule(new TLDebugModule()) - val plic = LazyModule(new TLPLIC(() => plicKey)) - val clint = LazyModule(new CoreplexLocalInterrupter(clintKey)) - val mmio = TLOutputNode() + val plic = LazyModule(new TLPLIC(hasSupervisor, maxPriorities = 7)) + val clint = LazyModule(new CoreplexLocalInterrupter) // Kill this once we move TL2 into rocket l1tol2.node := @@ -103,10 +111,8 @@ trait CoreplexRISCV { plic.node := TLFragmenter(cbus_beatBytes, cbus_lineBytes)(cbus.node) clint.node := TLFragmenter(cbus_beatBytes, cbus_lineBytes)(cbus.node) - mmio := - TLBuffer()( - TLWidthWidget(l1tol2_beatBytes)( - l1tol2.node)) + plic.intnode := mmioInt + lazyTiles.foreach { _ => tileIntNode := plic.intnode } } trait CoreplexRISCVBundle { @@ -114,13 +120,11 @@ trait CoreplexRISCVBundle { val outer: CoreplexRISCV } => - val mmio = outer.mmio.bundleOut val mem = Vec(nMemChannels, new ClientUncachedTileLinkIO()(outerMemParams)) val slave = Vec(nSlaves, new ClientUncachedTileLinkIO()(innerParams)).flip val resetVector = UInt(INPUT, p(XLen)) val success = Bool(OUTPUT) // used for testing val debug = new DebugBusIO().flip - val interrupts = Vec(nExtInterrupts, Bool()).asInput } trait CoreplexRISCVModule { @@ -134,7 +138,7 @@ trait CoreplexRISCVModule { // Create and export the ConfigString val managers = outer.l1tol2.node.edgesIn(0).manager.managers - val configString = rocketchip.GenerateConfigString(p, managers) + val configString = rocketchip.GenerateConfigString(p, outer.clint, outer.plic, managers) println(s"\nGenerated Configuration String\n${configString}") ConfigStringOutput.contents = Some(configString) @@ -192,22 +196,16 @@ trait CoreplexRISCVModule { for ((tile, i) <- (uncoreTileIOs zipWithIndex)) { tile.hartid := UInt(i) tile.resetVector := io.resetVector - tile.interrupts <> outer.clint.module.io.tiles(i) - tile.interrupts.meip := outer.plic.module.io.harts(plicKey.context(i, 'M')) - tile.interrupts.seip.foreach(_ := outer.plic.module.io.harts(plicKey.context(i, 'S'))) tile.interrupts.debug := outer.debug.module.io.debugInterrupts(i) - } - - // Coreplex doesn't know when to stop running - io.success := Bool(false) - for (i <- 0 until io.interrupts.size) { - val gateway = Module(new LevelGateway) - gateway.io.interrupt := io.interrupts(i) - outer.plic.module.io.devices(i) <> gateway.io.plic + tile.interrupts.meip := outer.tileIntNode.bundleOut(i)(0) + tile.interrupts.seip.foreach(_ := outer.tileIntNode.bundleOut(i)(1)) } outer.debug.module.io.db <> io.debug outer.clint.module.io.rtcTick := Counter(p(rocketchip.RTCPeriod)).inc() + + // Coreplex doesn't know when to stop running + io.success := Bool(false) } class BaseCoreplex(implicit p: Parameters) extends BareCoreplex diff --git a/src/main/scala/diplomacy/Nodes.scala b/src/main/scala/diplomacy/Nodes.scala index 88880a9f..83e0c80a 100644 --- a/src/main/scala/diplomacy/Nodes.scala +++ b/src/main/scala/diplomacy/Nodes.scala @@ -166,9 +166,12 @@ class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]( val flip = false // needed for blind nodes private def flipO(b: Vec[BO]) = if (flip) b.flip else b private def flipI(b: Vec[BI]) = if (flip) b else b.flip + val wire = false // needed if you want to grab access to from inside a module + private def wireO(b: Vec[BO]) = if (wire) Wire(b) else b + private def wireI(b: Vec[BI]) = if (wire) Wire(b) else b - lazy val bundleOut = flipO(outer.bundleO(edgesOut)) - lazy val bundleIn = flipI(inner.bundleI(edgesIn)) + lazy val bundleOut = wireO(flipO(outer.bundleO(edgesOut))) + lazy val bundleIn = wireI(flipI(inner.bundleI(edgesIn))) // connects the outward part of a node with the inward part of this node override def := (h: OutwardNodeHandle[DI, UI, BI])(implicit sourceInfo: SourceInfo): Option[LazyModule] = { @@ -234,6 +237,20 @@ class BlindInputNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B]) override lazy val bundleIn = bundleOut } +class InternalOutputNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])(pi: PI) + extends SimpleNode(imp)({case (0, _) => Seq()}, {case (n, Seq()) => Seq.fill(n)(pi)}, 0 to 0, 1 to 1) +{ + override val wire = true + override lazy val bundleOut = bundleIn +} + +class InternalInputNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])(po: PO) + extends SimpleNode(imp)({case (n, Seq()) => Seq.fill(n)(po)}, {case (0, _) => Seq()}, 1 to 1, 0 to 0) +{ + override val wire = true + override lazy val bundleIn = bundleOut +} + class InteriorNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B]) (oFn: Seq[PO] => PO, iFn: Seq[PI] => PI, numPO: Range.Inclusive, numPI: Range.Inclusive) extends SimpleNode(imp)({case (n,s) => Seq.fill(n)(oFn(s))}, {case (n,s) => Seq.fill(n)(iFn(s))}, numPO, numPI) diff --git a/src/main/scala/rocketchip/BaseTop.scala b/src/main/scala/rocketchip/BaseTop.scala index de2e8720..db22bff4 100644 --- a/src/main/scala/rocketchip/BaseTop.scala +++ b/src/main/scala/rocketchip/BaseTop.scala @@ -16,14 +16,12 @@ import coreplex._ // the following parameters will be refactored properly with TL2 case object GlobalAddrMap extends Field[AddrMap] case object NCoreplexExtClients extends Field[Int] -case object NExtInterrupts extends Field[Int] /** Enable or disable monitoring of Diplomatic buses */ case object TLEmitMonitors extends Field[Bool] /** Base Top with no Periphery */ abstract class BaseTop[+C <: BaseCoreplex](buildCoreplex: Parameters => C)(implicit q: Parameters) extends LazyModule { // the following variables will be refactored properly with TL2 - val pInterrupts = new RangeManager val pBusMasters = new RangeManager TLImp.emitMonitors = q(TLEmitMonitors) @@ -31,11 +29,11 @@ abstract class BaseTop[+C <: BaseCoreplex](buildCoreplex: Parameters => C)(impli // Add a SoC and peripheral bus val socBus = LazyModule(new TLXbar) val peripheryBus = LazyModule(new TLXbar) + val intBus = LazyModule(new IntXbar) // Fill in the TL1 legacy parameters implicit val p = q.alterPartial { case NCoreplexExtClients => pBusMasters.sum - case NExtInterrupts => pInterrupts.sum case GlobalAddrMap => legacyAddrMap } @@ -64,7 +62,6 @@ abstract class BaseTopModule[+B <: BaseTopBundle[BaseTop[BaseCoreplex]]](val io: val coreplexMem : Vec[ClientUncachedTileLinkIO] = Wire(outer.coreplex.module.io.mem) val coreplexSlave : Vec[ClientUncachedTileLinkIO] = Wire(outer.coreplex.module.io.slave) val coreplexDebug : DebugBusIO = Wire(outer.coreplex.module.io.debug) - val coreplexInterrupts : Vec[Bool] = Wire(outer.coreplex.module.io.interrupts) println("Generated Address Map") for (entry <- p(GlobalAddrMap).flatten) { @@ -79,17 +76,16 @@ abstract class BaseTopModule[+B <: BaseTopBundle[BaseTop[BaseCoreplex]]](val io: println(f"\t$name%s $start%x - $end%x, $protStr$cacheable") } - println("\nGenerated Interrupt Vector") - outer.pInterrupts.print - io.success := outer.coreplex.module.io.success } trait DirectConnection { val coreplex: BaseCoreplex val socBus: TLXbar + val intBus: IntXbar socBus.node := coreplex.mmio + coreplex.mmioInt := intBus.intnode } trait DirectConnectionModule { @@ -98,10 +94,8 @@ trait DirectConnectionModule { val coreplexMem : Vec[ClientUncachedTileLinkIO] val coreplexSlave : Vec[ClientUncachedTileLinkIO] val coreplexDebug : DebugBusIO - val coreplexInterrupts : Vec[Bool] - coreplexMem <> outer.coreplex.module.io.mem - coreplexInterrupts <> outer.coreplex.module.io.interrupts + coreplexMem <> outer.coreplex.module.io.mem outer.coreplex.module.io.slave <> coreplexSlave outer.coreplex.module.io.debug <> coreplexDebug } diff --git a/src/main/scala/rocketchip/Periphery.scala b/src/main/scala/rocketchip/Periphery.scala index 5162bf0d..8d3e02bc 100644 --- a/src/main/scala/rocketchip/Periphery.scala +++ b/src/main/scala/rocketchip/Periphery.scala @@ -129,28 +129,21 @@ trait PeripheryDebugModule { trait PeripheryExtInterrupts extends LazyModule { implicit val p: Parameters - val pInterrupts: RangeManager + val intBus: IntXbar - pInterrupts.add("ext", p(NExtTopInterrupts)) + val extInterrupts = IntBlindInputNode(p(NExtTopInterrupts)) + val extInterruptXing = LazyModule(new IntXing) + + intBus.intnode := extInterruptXing.intnode + extInterruptXing.intnode := extInterrupts } trait PeripheryExtInterruptsBundle { - implicit val p: Parameters - val interrupts = Vec(p(NExtTopInterrupts), Bool()).asInput + val outer: PeripheryExtInterrupts + val interrupts = outer.extInterrupts.bundleIn } trait PeripheryExtInterruptsModule { - implicit val p: Parameters - val outer: PeripheryExtInterrupts - val io: PeripheryExtInterruptsBundle - val coreplexInterrupts: Vec[Bool] - - { - val r = outer.pInterrupts.range("ext") - ((r._1 until r._2) zipWithIndex) foreach { case (c, i) => - coreplexInterrupts(c) := io.interrupts(i) - } - } } ///// @@ -220,9 +213,7 @@ trait PeripheryMasterAXI4MMIO extends HasPeripheryParameters { } trait PeripheryMasterAXI4MMIOBundle extends HasPeripheryParameters { - implicit val p: Parameters val outer: PeripheryMasterAXI4MMIO - val mmio_axi = outer.mmio_axi4.bundleOut } diff --git a/src/main/scala/rocketchip/TestHarness.scala b/src/main/scala/rocketchip/TestHarness.scala index 50eb45b6..400e6a93 100644 --- a/src/main/scala/rocketchip/TestHarness.scala +++ b/src/main/scala/rocketchip/TestHarness.scala @@ -26,7 +26,7 @@ class TestHarness(q: Parameters) extends Module { require(dut.io.bus_clk.isEmpty) require(dut.io.bus_rst.isEmpty) - for (int <- dut.io.interrupts) + for (int <- dut.io.interrupts(0)) int := Bool(false) if (dut.io.mem_axi.nonEmpty) { diff --git a/src/main/scala/rocketchip/Utils.scala b/src/main/scala/rocketchip/Utils.scala index f44cc105..d4839120 100644 --- a/src/main/scala/rocketchip/Utils.scala +++ b/src/main/scala/rocketchip/Utils.scala @@ -88,21 +88,12 @@ object GenerateGlobalAddrMap { } object GenerateConfigString { - def apply(p: Parameters, peripheryManagers: Seq[TLManagerParameters]) = { + def apply(p: Parameters, clint: CoreplexLocalInterrupter, plic: TLPLIC, peripheryManagers: Seq[TLManagerParameters]) = { val c = CoreplexParameters()(p) val addrMap = p(GlobalAddrMap) - val plicAddr = addrMap("TL2:plic").start - val clint = CoreplexLocalInterrupterConfig() - val xLen = p(XLen) val res = new StringBuilder - res append "plic {\n" - res append s" priority 0x${plicAddr.toString(16)};\n" - res append s" pending 0x${(plicAddr + PLICConsts.pendingBase).toString(16)};\n" - res append s" ndevs ${c.plicKey.nDevices};\n" - res append "};\n" - res append "rtc {\n" - res append s" addr 0x${clint.timeAddress.toString(16)};\n" - res append "};\n" + res append plic.module.globalConfigString + res append clint.module.globalConfigString if (addrMap contains "mem") { res append "ram {\n" res append " 0 {\n" @@ -124,22 +115,8 @@ object GenerateConfigString { res append s" $i {\n" res append " 0 {\n" res append s" isa $isa;\n" - res append s" timecmp 0x${clint.timecmpAddress(i).toString(16)};\n" - res append s" ipi 0x${clint.msipAddress(i).toString(16)};\n" - res append s" plic {\n" - res append s" m {\n" - res append s" ie 0x${(plicAddr + c.plicKey.enableAddr(i, 'M')).toString(16)};\n" - res append s" thresh 0x${(plicAddr + c.plicKey.threshAddr(i, 'M')).toString(16)};\n" - res append s" claim 0x${(plicAddr + c.plicKey.claimAddr(i, 'M')).toString(16)};\n" - res append s" };\n" - if (c.hasSupervisor) { - res append s" s {\n" - res append s" ie 0x${(plicAddr + c.plicKey.enableAddr(i, 'S')).toString(16)};\n" - res append s" thresh 0x${(plicAddr + c.plicKey.threshAddr(i, 'S')).toString(16)};\n" - res append s" claim 0x${(plicAddr + c.plicKey.claimAddr(i, 'S')).toString(16)};\n" - res append s" };\n" - } - res append " };\n" + res append clint.module.hartConfigStrings(i) + res append plic.module.hartConfigStrings(i) res append " };\n" res append " };\n" } diff --git a/src/main/scala/uncore/devices/Plic.scala b/src/main/scala/uncore/devices/Plic.scala index dec058b0..fa442b46 100644 --- a/src/main/scala/uncore/devices/Plic.scala +++ b/src/main/scala/uncore/devices/Plic.scala @@ -6,9 +6,11 @@ import Chisel._ import Chisel.ImplicitConversions._ import junctions._ +import diplomacy._ import regmapper._ import uncore.tilelink2._ import cde.Parameters +import scala.math.min class GatewayPLICIO extends Bundle { val valid = Bool(OUTPUT) @@ -49,113 +51,161 @@ object PLICConsts require(hartBase >= enableBase(maxHarts)) } -case class PLICConfig(nHartsIn: Int, supervisor: Boolean, nDevices: Int, nPriorities: Int) { - import PLICConsts._ - - def contextsPerHart = if (supervisor) 2 else 1 - def nHarts = contextsPerHart * nHartsIn - def context(i: Int, mode: Char) = mode match { - case 'M' => i * contextsPerHart - case 'S' => require(supervisor); i * contextsPerHart + 1 - } - def claimAddr(i: Int, mode: Char) = hartBase(context(i, mode)) + claimOffset - def threshAddr(i: Int, mode: Char) = hartBase(context(i, mode)) - def enableAddr(i: Int, mode: Char) = enableBase(context(i, mode)) - - require(nDevices <= maxDevices) - require(nHarts > 0 && nHarts <= maxHarts) - require(nPriorities >= 0 && nPriorities <= nDevices) -} - -trait HasPLICParameters { - val params: (() => PLICConfig, Parameters) - val cfg = params._1 () - implicit val p = params._2 -} - -trait PLICBundle extends Bundle with HasPLICParameters { - val devices = Vec(cfg.nDevices, new GatewayPLICIO).flip - val harts = Vec(cfg.nHarts, Bool()).asOutput -} - -trait PLICModule extends Module with HasRegMap with HasPLICParameters { - val io: PLICBundle - - val priority = - if (cfg.nPriorities > 0) Reg(Vec(cfg.nDevices+1, UInt(width=log2Up(cfg.nPriorities+1)))) - else Wire(init=Vec.fill(cfg.nDevices+1)(UInt(1))) - val threshold = - if (cfg.nPriorities > 0) Reg(Vec(cfg.nHarts, UInt(width = log2Up(cfg.nPriorities+1)))) - else Wire(init=Vec.fill(cfg.nHarts)(UInt(0))) - val pending = Reg(init=Vec.fill(cfg.nDevices+1){Bool(false)}) - val enables = Reg(Vec(cfg.nHarts, Vec(cfg.nDevices+1, Bool()))) - - for ((p, g) <- pending.tail zip io.devices) { - g.ready := !p - g.complete := false - when (g.valid) { p := true } - } - - def findMax(x: Seq[UInt]): (UInt, UInt) = { - if (x.length > 1) { - val half = 1 << (log2Ceil(x.length) - 1) - val lMax = findMax(x take half) - val rMax = findMax(x drop half) - val useLeft = lMax._1 >= rMax._1 - (Mux(useLeft, lMax._1, rMax._1), Mux(useLeft, lMax._2, UInt(half) | rMax._2)) - } else (x.head, UInt(0)) - } - - val maxDevs = Reg(Vec(cfg.nHarts, UInt(width = log2Up(pending.size)))) - for (hart <- 0 until cfg.nHarts) { - val effectivePriority = - for (((p, en), pri) <- (pending zip enables(hart) zip priority).tail) - yield Cat(p && en, pri) - val (maxPri, maxDev) = findMax((UInt(1) << priority(0).getWidth) +: effectivePriority) - - maxDevs(hart) := maxDev - io.harts(hart) := Reg(next = maxPri) > Cat(UInt(1), threshold(hart)) - } - - def priorityRegField(x: UInt) = if (cfg.nPriorities > 0) RegField(32, x) else RegField.r(32, x) - val priorityRegFields = Seq(PLICConsts.priorityBase -> priority.map(p => priorityRegField(p))) - val pendingRegFields = Seq(PLICConsts.pendingBase -> pending .map(b => RegField.r(1, b))) - - val enableRegFields = enables.zipWithIndex.map { case (e, i) => - PLICConsts.enableBase(i) -> e.map(b => RegField(1, b)) - } - - val hartRegFields = Seq.tabulate(cfg.nHarts) { i => - PLICConsts.hartBase(i) -> Seq( - priorityRegField(threshold(i)), - RegField(32, - RegReadFn { valid => - when (valid) { - pending(maxDevs(i)) := Bool(false) - maxDevs(i) := UInt(0) // flush pipeline - } - (Bool(true), maxDevs(i)) - }, - RegWriteFn { (valid, data) => - when (valid && enables(i)(data)) { - io.devices(data - UInt(1)).complete := Bool(true) - } - Bool(true) - } - ) - ) - } - - regmap((priorityRegFields ++ pendingRegFields ++ enableRegFields ++ hartRegFields):_*) - - priority(0) := 0 - pending(0) := false - for (e <- enables) - e(0) := false -} - /** Platform-Level Interrupt Controller */ -class TLPLIC(c: () => PLICConfig, address: BigInt = 0xC000000)(implicit val p: Parameters) - extends TLRegisterRouter(address, size = PLICConsts.size, beatBytes = p(rocket.XLen)/8, undefZero = false)( - new TLRegBundle((c, p), _) with PLICBundle)( - new TLRegModule((c, p), _, _) with PLICModule) +class TLPLIC(supervisor: Boolean, maxPriorities: Int, address: BigInt = 0xC000000)(implicit val p: Parameters) extends LazyModule +{ + val contextsPerHart = if (supervisor) 2 else 1 + require (maxPriorities >= 0) + + val node = TLRegisterNode( + address = AddressSet(address, PLICConsts.size-1), + beatBytes = p(rocket.XLen)/8, + undefZero = false) + + val intnode = IntAdapterNode( + numSourcePorts = 0 to 1024, + numSinkPorts = 0 to 1024, + sourceFn = { _ => IntSourcePortParameters(Seq(IntSourceParameters(contextsPerHart))) }, + sinkFn = { _ => IntSinkPortParameters(Seq(IntSinkParameters())) }) + + lazy val module = new LazyModuleImp(this) { + val io = new Bundle { + val tl_in = node.bundleIn + val devices = intnode.bundleIn + val harts = intnode.bundleOut + } + + // Assign all the devices unique ranges + val sources = intnode.edgesIn.map(_.source) + val flatSources = (sources zip sources.map(_.num).scanLeft(0)(_+_).init).map { + case (s, o) => s.sources.map(z => z.copy(range = z.range.offset(o))) + }.flatten + // Compact the interrupt vector the same way + val interrupts = (intnode.edgesIn zip io.devices).map { case (e, i) => i.take(e.source.num) }.flatten + // This flattens the harts into an MSMSMSMSMS... or MMMMM.... sequence + val harts = io.harts.flatten + + println("\nInterrupt map:") + flatSources.foreach { s => + println(s" [${s.range.start}, ${s.range.end}) => ${s.name}") + } + + val nDevices = interrupts.size + val nPriorities = min(maxPriorities, nDevices) + val nHarts = harts.size + + require(nDevices <= PLICConsts.maxDevices) + require(nHarts > 0 && nHarts <= PLICConsts.maxHarts) + + def context(i: Int, mode: Char) = mode match { + case 'M' => i * contextsPerHart + case 'S' => require(supervisor); i * contextsPerHart + 1 + } + def claimAddr(i: Int, mode: Char) = address + PLICConsts.hartBase(context(i, mode)) + PLICConsts.claimOffset + def threshAddr(i: Int, mode: Char) = address + PLICConsts.hartBase(context(i, mode)) + def enableAddr(i: Int, mode: Char) = address + PLICConsts.enableBase(context(i, mode)) + + // Create the global PLIC config string + val globalConfigString = Seq( + s"plic {\n", + s" priority 0x${address.toString(16)};\n", + s" pending 0x${(address + PLICConsts.pendingBase).toString(16)};\n", + s" ndevs ${nDevices};\n", + s"};\n").mkString + + // Create the per-Hart config string + val hartConfigStrings = io.harts.zipWithIndex.map { case (_, i) => (Seq( + s" plic {\n", + s" m {\n", + s" ie 0x${enableAddr(i, 'M').toString(16)};\n", + s" thresh 0x${threshAddr(i, 'M').toString(16)};\n", + s" claim 0x${claimAddr(i, 'M').toString(16)};\n", + s" };\n") ++ (if (!supervisor) Seq() else Seq( + s" s {\n", + s" ie 0x${enableAddr(i, 'S').toString(16)};\n", + s" thresh 0x${threshAddr(i, 'S').toString(16)};\n", + s" claim 0x${claimAddr(i, 'S').toString(16)};\n", + s" };\n")) ++ Seq( + s" };\n")).mkString + } + + // For now, use LevelGateways for all TL2 interrupts + val gateways = Vec(interrupts.map { case i => + val gateway = Module(new LevelGateway) + gateway.io.interrupt := i + gateway.io.plic + }) + + val priority = + if (nPriorities > 0) Reg(Vec(nDevices+1, UInt(width=log2Up(nPriorities+1)))) + else Wire(init=Vec.fill(nDevices+1)(UInt(1))) + val threshold = + if (nPriorities > 0) Reg(Vec(nHarts, UInt(width = log2Up(nPriorities+1)))) + else Wire(init=Vec.fill(nHarts)(UInt(0))) + val pending = Reg(init=Vec.fill(nDevices+1){Bool(false)}) + val enables = Reg(Vec(nHarts, Vec(nDevices+1, Bool()))) + + for ((p, g) <- pending.tail zip gateways) { + g.ready := !p + g.complete := false + when (g.valid) { p := true } + } + + def findMax(x: Seq[UInt]): (UInt, UInt) = { + if (x.length > 1) { + val half = 1 << (log2Ceil(x.length) - 1) + val lMax = findMax(x take half) + val rMax = findMax(x drop half) + val useLeft = lMax._1 >= rMax._1 + (Mux(useLeft, lMax._1, rMax._1), Mux(useLeft, lMax._2, UInt(half) | rMax._2)) + } else (x.head, UInt(0)) + } + + val maxDevs = Reg(Vec(nHarts, UInt(width = log2Up(pending.size)))) + for (hart <- 0 until nHarts) { + val effectivePriority = + for (((p, en), pri) <- (pending zip enables(hart) zip priority).tail) + yield Cat(p && en, pri) + val (maxPri, maxDev) = findMax((UInt(1) << priority(0).getWidth) +: effectivePriority) + + maxDevs(hart) := maxDev + harts(hart) := Reg(next = maxPri) > Cat(UInt(1), threshold(hart)) + } + + def priorityRegField(x: UInt) = if (nPriorities > 0) RegField(32, x) else RegField.r(32, x) + val priorityRegFields = Seq(PLICConsts.priorityBase -> priority.map(p => priorityRegField(p))) + val pendingRegFields = Seq(PLICConsts.pendingBase -> pending .map(b => RegField.r(1, b))) + + val enableRegFields = enables.zipWithIndex.map { case (e, i) => + PLICConsts.enableBase(i) -> e.map(b => RegField(1, b)) + } + + val hartRegFields = Seq.tabulate(nHarts) { i => + PLICConsts.hartBase(i) -> Seq( + priorityRegField(threshold(i)), + RegField(32, + RegReadFn { valid => + when (valid) { + pending(maxDevs(i)) := Bool(false) + maxDevs(i) := UInt(0) // flush pipeline + } + (Bool(true), maxDevs(i)) + }, + RegWriteFn { (valid, data) => + when (valid && enables(i)(data)) { + gateways(data - UInt(1)).complete := Bool(true) + } + Bool(true) + } + ) + ) + } + + node.regmap((priorityRegFields ++ pendingRegFields ++ enableRegFields ++ hartRegFields):_*) + + priority(0) := 0 + pending(0) := false + for (e <- enables) + e(0) := false + } +} diff --git a/src/main/scala/uncore/devices/Prci.scala b/src/main/scala/uncore/devices/Prci.scala index 41217a69..604c89ab 100644 --- a/src/main/scala/uncore/devices/Prci.scala +++ b/src/main/scala/uncore/devices/Prci.scala @@ -6,6 +6,7 @@ import Chisel._ import junctions._ import junctions.NastiConstants._ import regmapper._ +import diplomacy._ import uncore.tilelink2._ import uncore.util._ import util._ @@ -20,22 +21,19 @@ class CoreplexLocalInterrupts extends Bundle { val msip = Bool() } -case class CoreplexLocalInterrupterConfig(address: BigInt = 0x02000000) { +object ClintConsts +{ def msipOffset(hart: Int) = hart * msipBytes - def msipAddress(hart: Int) = address + msipOffset(hart) def timecmpOffset(hart: Int) = 0x4000 + hart * timecmpBytes - def timecmpAddress(hart: Int) = address + timecmpOffset(hart) def timeOffset = 0xbff8 - def timeAddress = address + timeOffset def msipBytes = 4 def timecmpBytes = 8 def size = 0x10000 } trait MixCoreplexLocalInterrupterParameters { - val params: (CoreplexLocalInterrupterConfig, Parameters) - val c = params._1 - implicit val p = params._2 + val params: Parameters + implicit val p = params } trait CoreplexLocalInterrupterBundle extends Bundle with MixCoreplexLocalInterrupterParameters { @@ -45,6 +43,7 @@ trait CoreplexLocalInterrupterBundle extends Bundle with MixCoreplexLocalInterru trait CoreplexLocalInterrupterModule extends Module with HasRegMap with MixCoreplexLocalInterrupterParameters { val io: CoreplexLocalInterrupterBundle + val address: AddressSet val timeWidth = 64 val regWidth = 32 @@ -64,6 +63,15 @@ trait CoreplexLocalInterrupterModule extends Module with HasRegMap with MixCorep tile.mtip := time.asUInt >= timecmp(i).asUInt } + val globalConfigString = Seq( + s"rtc {\n", + s" addr 0x${(address.base + ClintConsts.timeOffset).toString(16)};\n", + s"};\n").mkString + val hartConfigStrings = (0 until p(NTiles)).map { i => Seq( + s" timecmp 0x${(address.base + ClintConsts.timecmpOffset(i)).toString(16)};\n", + s" ipi 0x${(address.base + ClintConsts.msipOffset(i)).toString(16)};\n").mkString + } + /* 0000 msip hart 0 * 0004 msip hart 1 * 4000 mtimecmp hart 0 lo @@ -75,16 +83,16 @@ trait CoreplexLocalInterrupterModule extends Module with HasRegMap with MixCorep */ regmap( - 0 -> makeRegFields(ipi), - c.timecmpOffset(0) -> makeRegFields(timecmp.flatten), - c.timeOffset -> makeRegFields(time)) + 0 -> makeRegFields(ipi), + ClintConsts.timecmpOffset(0) -> makeRegFields(timecmp.flatten), + ClintConsts.timeOffset -> makeRegFields(time)) def makeRegFields(s: Seq[UInt]) = s.map(r => RegField(regWidth, r)) } /** Power, Reset, Clock, Interrupt */ // Magic TL2 Incantation to create a TL2 Slave -class CoreplexLocalInterrupter(c: CoreplexLocalInterrupterConfig)(implicit val p: Parameters) - extends TLRegisterRouter(c.address, size = c.size, beatBytes = p(rocket.XLen)/8, undefZero = false)( - new TLRegBundle((c, p), _) with CoreplexLocalInterrupterBundle)( - new TLRegModule((c, p), _, _) with CoreplexLocalInterrupterModule) +class CoreplexLocalInterrupter(address: BigInt = 0x02000000)(implicit val p: Parameters) + extends TLRegisterRouter(address, size = ClintConsts.size, beatBytes = p(rocket.XLen)/8, undefZero = false)( + new TLRegBundle(p, _) with CoreplexLocalInterrupterBundle)( + new TLRegModule(p, _, _) with CoreplexLocalInterrupterModule) diff --git a/src/main/scala/uncore/tilelink2/IntNodes.scala b/src/main/scala/uncore/tilelink2/IntNodes.scala index 0c6474e9..d98e93e7 100644 --- a/src/main/scala/uncore/tilelink2/IntNodes.scala +++ b/src/main/scala/uncore/tilelink2/IntNodes.scala @@ -79,9 +79,6 @@ object IntImp extends NodeImp[IntSourcePortParameters, IntSinkPortParameters, In } case class IntIdentityNode() extends IdentityNode(IntImp) -case class IntOutputNode() extends OutputNode(IntImp) -case class IntInputNode() extends InputNode(IntImp) - case class IntSourceNode(num: Int) extends SourceNode(IntImp)( IntSourcePortParameters(Seq(IntSourceParameters(num))), (if (num == 0) 0 else 1) to 1) case class IntSinkNode() extends SinkNode(IntImp)( @@ -94,11 +91,20 @@ case class IntAdapterNode( numSinkPorts: Range.Inclusive = 1 to 1) extends InteriorNode(IntImp)(sourceFn, sinkFn, numSourcePorts, numSinkPorts) +case class IntOutputNode() extends OutputNode(IntImp) +case class IntInputNode() extends InputNode(IntImp) + +case class IntBlindOutputNode() extends BlindOutputNode(IntImp)(IntSinkPortParameters(Seq(IntSinkParameters()))) +case class IntBlindInputNode(num: Int) extends BlindInputNode(IntImp)(IntSourcePortParameters(Seq(IntSourceParameters(num)))) + +case class IntInternalOutputNode() extends InternalOutputNode(IntImp)(IntSinkPortParameters(Seq(IntSinkParameters()))) +case class IntInternalInputNode(num: Int) extends InternalInputNode(IntImp)(IntSourcePortParameters(Seq(IntSourceParameters(num)))) + class IntXbar extends LazyModule { val intnode = IntAdapterNode( numSourcePorts = 1 to 1, // does it make sense to have more than one interrupt sink? - numSinkPorts = 1 to 128, + numSinkPorts = 0 to 128, sinkFn = { _ => IntSinkPortParameters(Seq(IntSinkParameters())) }, sourceFn = { seq => IntSourcePortParameters((seq zip seq.map(_.num).scanLeft(0)(_+_).init).map { @@ -116,3 +122,17 @@ class IntXbar extends LazyModule io.out.foreach { _ := cat } } } + +class IntXing extends LazyModule +{ + val intnode = IntIdentityNode() + + lazy val module = new LazyModuleImp(this) { + val io = new Bundle { + val in = intnode.bundleIn + val out = intnode.bundleOut + } + + io.out := RegNext(RegNext(RegNext(io.in))) + } +} diff --git a/src/main/scala/uncore/tilelink2/RegisterRouter.scala b/src/main/scala/uncore/tilelink2/RegisterRouter.scala index d100917e..3004ea1f 100644 --- a/src/main/scala/uncore/tilelink2/RegisterRouter.scala +++ b/src/main/scala/uncore/tilelink2/RegisterRouter.scala @@ -79,7 +79,7 @@ object TLRegisterNode // register mapped device from a totally abstract register mapped device. // See GPIO.scala in this directory for an example -abstract class TLRegisterRouterBase(address: AddressSet, interrupts: Int, concurrency: Int, beatBytes: Int, undefZero: Boolean, executable: Boolean) extends LazyModule +abstract class TLRegisterRouterBase(val address: AddressSet, interrupts: Int, concurrency: Int, beatBytes: Int, undefZero: Boolean, executable: Boolean) extends LazyModule { val node = TLRegisterNode(address, concurrency, beatBytes, undefZero, executable) val intnode = IntSourceNode(interrupts) @@ -100,6 +100,7 @@ class TLRegModule[P, B <: TLRegBundleBase](val params: P, bundleBuilder: => B, r { val io = bundleBuilder val interrupts = if (io.interrupts.isEmpty) Vec(0, Bool()) else io.interrupts(0) + val address = router.address def regmap(mapping: RegField.Map*) = router.node.regmap(mapping:_*) }