PLIC: converted to TL2
This commit is contained in:
parent
bddfa4d69b
commit
b99662796d
@ -51,13 +51,21 @@ case class CoreplexConfig(
|
|||||||
abstract class BaseCoreplex(c: CoreplexConfig)(implicit val p: Parameters) extends LazyModule with HasCoreplexParameters {
|
abstract class BaseCoreplex(c: CoreplexConfig)(implicit val p: Parameters) extends LazyModule with HasCoreplexParameters {
|
||||||
|
|
||||||
val debugLegacy = LazyModule(new TLLegacy()(outerMMIOParams))
|
val debugLegacy = LazyModule(new TLLegacy()(outerMMIOParams))
|
||||||
val debugModule = LazyModule(new TLDebugModule())
|
val debug = LazyModule(new TLDebugModule())
|
||||||
debugModule.node :=
|
debug.node :=
|
||||||
TLHintHandler()(
|
TLHintHandler()(
|
||||||
TLBuffer()(
|
TLBuffer()(
|
||||||
TLFragmenter(p(XLen)/8, debugLegacy.tlDataBeats * debugLegacy.tlDataBytes)(
|
TLFragmenter(p(XLen)/8, debugLegacy.tlDataBeats * debugLegacy.tlDataBytes)(
|
||||||
TLWidthWidget(debugLegacy.tlDataBytes)(debugLegacy.node))))
|
TLWidthWidget(debugLegacy.tlDataBytes)(debugLegacy.node))))
|
||||||
|
|
||||||
|
val plicLegacy = LazyModule(new TLLegacy()(outerMMIOParams))
|
||||||
|
val plic = LazyModule(new TLPLIC(c.plicKey))
|
||||||
|
plic.node :=
|
||||||
|
TLHintHandler()(
|
||||||
|
TLBuffer()(
|
||||||
|
TLFragmenter(p(XLen)/8, plicLegacy.tlDataBeats * plicLegacy.tlDataBytes)(
|
||||||
|
TLWidthWidget(plicLegacy.tlDataBytes)(plicLegacy.node))))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class BaseCoreplexBundle(val c: CoreplexConfig)(implicit val p: Parameters) extends Bundle with HasCoreplexParameters {
|
abstract class BaseCoreplexBundle(val c: CoreplexConfig)(implicit val p: Parameters) extends Bundle with HasCoreplexParameters {
|
||||||
@ -142,23 +150,22 @@ abstract class BaseCoreplexModule[+L <: BaseCoreplex, +B <: BaseCoreplexBundle](
|
|||||||
val cBus = Module(new TileLinkRecursiveInterconnect(1, ioAddrMap))
|
val cBus = Module(new TileLinkRecursiveInterconnect(1, ioAddrMap))
|
||||||
cBus.io.in.head <> mmio
|
cBus.io.in.head <> mmio
|
||||||
|
|
||||||
val plic = Module(new PLIC(c.plicKey))
|
outer.plicLegacy.module.io.legacy <> cBus.port("cbus:plic")
|
||||||
plic.io.tl <> cBus.port("cbus:plic")
|
|
||||||
for (i <- 0 until io.interrupts.size) {
|
for (i <- 0 until io.interrupts.size) {
|
||||||
val gateway = Module(new LevelGateway)
|
val gateway = Module(new LevelGateway)
|
||||||
gateway.io.interrupt := io.interrupts(i)
|
gateway.io.interrupt := io.interrupts(i)
|
||||||
plic.io.devices(i) <> gateway.io.plic
|
outer.plic.module.io.devices(i) <> gateway.io.plic
|
||||||
}
|
}
|
||||||
|
|
||||||
outer.debugLegacy.module.io.legacy <> cBus.port("cbus:debug")
|
outer.debugLegacy.module.io.legacy <> cBus.port("cbus:debug")
|
||||||
outer.debugModule.module.io.db <> io.debug
|
outer.debug.module.io.db <> io.debug
|
||||||
|
|
||||||
// connect coreplex-internal interrupts to tiles
|
// connect coreplex-internal interrupts to tiles
|
||||||
for ((tile, i) <- (uncoreTileIOs zipWithIndex)) {
|
for ((tile, i) <- (uncoreTileIOs zipWithIndex)) {
|
||||||
tile.interrupts <> io.clint(i)
|
tile.interrupts <> io.clint(i)
|
||||||
tile.interrupts.meip := plic.io.harts(plic.cfg.context(i, 'M'))
|
tile.interrupts.meip := outer.plic.module.io.harts(c.plicKey.context(i, 'M'))
|
||||||
tile.interrupts.seip.foreach(_ := plic.io.harts(plic.cfg.context(i, 'S')))
|
tile.interrupts.seip.foreach(_ := outer.plic.module.io.harts(c.plicKey.context(i, 'S')))
|
||||||
tile.interrupts.debug := outer.debugModule.module.io.debugInterrupts(i)
|
tile.interrupts.debug := outer.debug.module.io.debugInterrupts(i)
|
||||||
tile.hartid := UInt(i)
|
tile.hartid := UInt(i)
|
||||||
tile.resetVector := io.resetVector
|
tile.resetVector := io.resetVector
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,8 @@ import Chisel._
|
|||||||
import Chisel.ImplicitConversions._
|
import Chisel.ImplicitConversions._
|
||||||
|
|
||||||
import junctions._
|
import junctions._
|
||||||
import uncore.tilelink._
|
import regmapper._
|
||||||
|
import uncore.tilelink2._
|
||||||
import cde.Parameters
|
import cde.Parameters
|
||||||
|
|
||||||
class GatewayPLICIO extends Bundle {
|
class GatewayPLICIO extends Bundle {
|
||||||
@ -27,7 +28,7 @@ class LevelGateway extends Module {
|
|||||||
io.plic.valid := io.interrupt && !inFlight
|
io.plic.valid := io.interrupt && !inFlight
|
||||||
}
|
}
|
||||||
|
|
||||||
case class PLICConfig(nHartsIn: Int, supervisor: Boolean, nDevices: Int, nPriorities: Int) {
|
case class PLICConfig(nHartsIn: Int, supervisor: Boolean, nDevices: Int, nPriorities: Int, address: BigInt = 0xC000000) {
|
||||||
def contextsPerHart = if (supervisor) 2 else 1
|
def contextsPerHart = if (supervisor) 2 else 1
|
||||||
def nHarts = contextsPerHart * nHartsIn
|
def nHarts = contextsPerHart * nHartsIn
|
||||||
def context(i: Int, mode: Char) = mode match {
|
def context(i: Int, mode: Char) = mode match {
|
||||||
@ -41,6 +42,7 @@ case class PLICConfig(nHartsIn: Int, supervisor: Boolean, nDevices: Int, nPriori
|
|||||||
|
|
||||||
def maxDevices = 1023
|
def maxDevices = 1023
|
||||||
def maxHarts = 15872
|
def maxHarts = 15872
|
||||||
|
def priorityBase = 0x0
|
||||||
def pendingBase = 0x1000
|
def pendingBase = 0x1000
|
||||||
def enableBase = 0x2000
|
def enableBase = 0x2000
|
||||||
def hartBase = 0x200000
|
def hartBase = 0x200000
|
||||||
@ -56,15 +58,19 @@ case class PLICConfig(nHartsIn: Int, supervisor: Boolean, nDevices: Int, nPriori
|
|||||||
require(nPriorities >= 0 && nPriorities <= nDevices)
|
require(nPriorities >= 0 && nPriorities <= nDevices)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Platform-Level Interrupt Controller */
|
trait HasPLICParamters {
|
||||||
class PLIC(val cfg: PLICConfig)(implicit val p: Parameters) extends Module
|
val params: (PLICConfig, Parameters)
|
||||||
with HasTileLinkParameters
|
val cfg = params._1
|
||||||
with HasAddrMapParameters {
|
implicit val p = params._2
|
||||||
val io = new Bundle {
|
}
|
||||||
|
|
||||||
|
trait PLICBundle extends Bundle with HasPLICParamters {
|
||||||
val devices = Vec(cfg.nDevices, new GatewayPLICIO).flip
|
val devices = Vec(cfg.nDevices, new GatewayPLICIO).flip
|
||||||
val harts = Vec(cfg.nHarts, Bool()).asOutput
|
val harts = Vec(cfg.nHarts, Bool()).asOutput
|
||||||
val tl = new ClientUncachedTileLinkIO().flip
|
}
|
||||||
}
|
|
||||||
|
trait PLICModule extends Module with HasRegMap with HasPLICParamters {
|
||||||
|
val io: PLICBundle
|
||||||
|
|
||||||
val priority =
|
val priority =
|
||||||
if (cfg.nPriorities > 0) Reg(Vec(cfg.nDevices+1, UInt(width=log2Up(cfg.nPriorities+1))))
|
if (cfg.nPriorities > 0) Reg(Vec(cfg.nDevices+1, UInt(width=log2Up(cfg.nPriorities+1))))
|
||||||
@ -87,7 +93,7 @@ class PLIC(val cfg: PLICConfig)(implicit val p: Parameters) extends Module
|
|||||||
val lMax = findMax(x take half)
|
val lMax = findMax(x take half)
|
||||||
val rMax = findMax(x drop half)
|
val rMax = findMax(x drop half)
|
||||||
val useLeft = lMax._1 >= rMax._1
|
val useLeft = lMax._1 >= rMax._1
|
||||||
(Mux(useLeft, lMax._1, rMax._1), Mux(useLeft, lMax._2, UInt(half) + rMax._2))
|
(Mux(useLeft, lMax._1, rMax._1), Mux(useLeft, lMax._2, UInt(half) | rMax._2))
|
||||||
} else (x.head, UInt(0))
|
} else (x.head, UInt(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,86 +108,45 @@ class PLIC(val cfg: PLICConfig)(implicit val p: Parameters) extends Module
|
|||||||
io.harts(hart) := Reg(next = maxPri) > Cat(UInt(1), threshold(hart))
|
io.harts(hart) := Reg(next = maxPri) > Cat(UInt(1), threshold(hart))
|
||||||
}
|
}
|
||||||
|
|
||||||
val acq = Queue(io.tl.acquire, 1)
|
def priorityRegField(x: UInt) = if (cfg.nPriorities > 0) RegField(32, x) else RegField.r(32, x)
|
||||||
val read = acq.fire() && acq.bits.isBuiltInType(Acquire.getType)
|
val piorityRegFields = Seq(cfg.priorityBase -> priority.map(p => priorityRegField(p)))
|
||||||
val write = acq.fire() && acq.bits.isBuiltInType(Acquire.putType)
|
val pendingRegFields = Seq(cfg.pendingBase -> pending .map(b => RegField.r(1, b)))
|
||||||
assert(!acq.fire() || read || write, "unsupported PLIC operation")
|
|
||||||
val addr = acq.bits.full_addr()(log2Up(cfg.size)-1,0)
|
|
||||||
|
|
||||||
val claimant =
|
val enableRegFields = enables.zipWithIndex.map { case (e, i) =>
|
||||||
if (cfg.nHarts == 1) UInt(0)
|
cfg.enableBase + cfg.enableOffset(i) -> e.map(b => RegField(1, b))
|
||||||
else (addr - cfg.hartBase)(log2Up(cfg.hartOffset(cfg.nHarts))-1,log2Up(cfg.hartOffset(1)))
|
}
|
||||||
val hart = Wire(init = claimant)
|
|
||||||
val myMaxDev = maxDevs(claimant)
|
|
||||||
val myEnables = enables(hart)
|
|
||||||
val rdata = Wire(init = UInt(0, tlDataBits))
|
|
||||||
val masked_wdata = (acq.bits.data & acq.bits.full_wmask()) | (rdata & ~acq.bits.full_wmask())
|
|
||||||
|
|
||||||
if (cfg.nDevices > 0) when (addr >= cfg.hartBase) {
|
val hartRegFields = Seq.tabulate(cfg.nHarts) { i =>
|
||||||
val word =
|
cfg.hartBase + cfg.hartOffset(i) -> Seq(
|
||||||
if (tlDataBytes > cfg.claimOffset) UInt(0)
|
priorityRegField(threshold(i)),
|
||||||
else addr(log2Up(cfg.claimOffset),log2Up(tlDataBytes))
|
RegField(32,
|
||||||
rdata := Cat(myMaxDev, UInt(0, 8*cfg.priorityBytes-threshold(0).getWidth), threshold(claimant)) >> (word * tlDataBits)
|
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)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
when (read && addr(log2Ceil(cfg.claimOffset))) {
|
regmap((piorityRegFields ++ pendingRegFields ++ enableRegFields ++ hartRegFields):_*)
|
||||||
pending(myMaxDev) := false
|
|
||||||
}
|
|
||||||
when (write) {
|
|
||||||
when (if (tlDataBytes > cfg.claimOffset) acq.bits.wmask()(cfg.claimOffset) else addr(log2Ceil(cfg.claimOffset))) {
|
|
||||||
val dev = (acq.bits.data >> ((8 * cfg.claimOffset) % tlDataBits))(log2Up(pending.size)-1,0)
|
|
||||||
when (myEnables(dev)) { io.devices(dev-1).complete := true }
|
|
||||||
}.otherwise {
|
|
||||||
if (cfg.nPriorities > 0) threshold(claimant) := acq.bits.data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.elsewhen (addr >= cfg.enableBase) {
|
|
||||||
val enableHart =
|
|
||||||
if (cfg.nHarts > 1) (addr - cfg.enableBase)(log2Up(cfg.enableOffset(cfg.nHarts))-1,log2Up(cfg.enableOffset(1)))
|
|
||||||
else UInt(0)
|
|
||||||
hart := enableHart
|
|
||||||
val word =
|
|
||||||
if (tlDataBits >= myEnables.size) UInt(0)
|
|
||||||
else addr(log2Ceil((myEnables.size-1)/tlDataBits+1) + tlByteAddrBits - 1, tlByteAddrBits)
|
|
||||||
for (i <- 0 until myEnables.size by tlDataBits) {
|
|
||||||
when (word === i/tlDataBits) {
|
|
||||||
rdata := Cat(myEnables.slice(i, i + tlDataBits).reverse)
|
|
||||||
for (j <- 0 until (tlDataBits min (myEnables.size - i))) {
|
|
||||||
when (write) { enables(enableHart)(i+j) := masked_wdata(j) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.elsewhen (addr >= cfg.pendingBase) {
|
|
||||||
val word =
|
|
||||||
if (tlDataBytes >= pending.size) UInt(0)
|
|
||||||
else addr(log2Up(pending.size)-1,log2Up(tlDataBytes))
|
|
||||||
rdata := pending.asUInt >> (word * tlDataBits)
|
|
||||||
}.otherwise {
|
|
||||||
val regsPerBeat = tlDataBytes >> log2Up(cfg.priorityBytes)
|
|
||||||
val word =
|
|
||||||
if (regsPerBeat >= priority.size) UInt(0)
|
|
||||||
else addr(log2Up(priority.size*cfg.priorityBytes)-1,log2Up(tlDataBytes))
|
|
||||||
for (i <- 0 until priority.size by regsPerBeat) {
|
|
||||||
when (word === i/regsPerBeat) {
|
|
||||||
rdata := Cat(priority.slice(i, i + regsPerBeat).map(p => Cat(UInt(0, 8*cfg.priorityBytes-p.getWidth), p)).reverse)
|
|
||||||
for (j <- 0 until (regsPerBeat min (priority.size - i))) {
|
|
||||||
if (cfg.nPriorities > 0) when (write) { priority(i+j) := masked_wdata >> (j * 8 * cfg.priorityBytes) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
priority(0) := 0
|
priority(0) := 0
|
||||||
pending(0) := false
|
pending(0) := false
|
||||||
for (e <- enables)
|
for (e <- enables)
|
||||||
e(0) := false
|
e(0) := false
|
||||||
|
|
||||||
io.tl.grant.valid := acq.valid
|
|
||||||
acq.ready := io.tl.grant.ready
|
|
||||||
io.tl.grant.bits := Grant(
|
|
||||||
is_builtin_type = Bool(true),
|
|
||||||
g_type = acq.bits.getBuiltInGrantType(),
|
|
||||||
client_xact_id = acq.bits.client_xact_id,
|
|
||||||
manager_xact_id = UInt(0),
|
|
||||||
addr_beat = UInt(0),
|
|
||||||
data = rdata)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Platform-Level Interrupt Controller */
|
||||||
|
class TLPLIC(c: PLICConfig)(implicit val p: Parameters)
|
||||||
|
extends TLRegisterRouter(c.address, size = c.size, beatBytes = p(rocket.XLen)/8, undefZero = false)(
|
||||||
|
new TLRegBundle((c, p), _) with PLICBundle)(
|
||||||
|
new TLRegModule((c, p), _, _) with PLICModule)
|
||||||
|
Loading…
Reference in New Issue
Block a user