2017-03-15 09:18:39 +01:00
|
|
|
// See LICENSE.SiFive for license details.
|
|
|
|
|
|
|
|
package rocket
|
|
|
|
|
|
|
|
import Chisel._
|
|
|
|
import Chisel.ImplicitConversions._
|
|
|
|
import config._
|
|
|
|
import tile._
|
|
|
|
import util._
|
|
|
|
|
|
|
|
class PMPConfig extends Bundle {
|
2017-03-30 09:31:34 +02:00
|
|
|
val l = Bool()
|
|
|
|
val res = UInt(width = 2)
|
2017-03-15 09:18:39 +01:00
|
|
|
val a = UInt(width = 2)
|
|
|
|
val x = Bool()
|
|
|
|
val w = Bool()
|
|
|
|
val r = Bool()
|
|
|
|
}
|
|
|
|
|
2017-03-20 09:34:47 +01:00
|
|
|
object PMP {
|
|
|
|
def lgAlign = 2
|
|
|
|
|
2017-03-20 13:21:50 +01:00
|
|
|
def apply(reg: PMPReg): PMP = {
|
|
|
|
val pmp = Wire(new PMP()(reg.p))
|
|
|
|
pmp := reg
|
|
|
|
pmp.mask := pmp.computeMask
|
|
|
|
pmp
|
|
|
|
}
|
|
|
|
}
|
2017-03-20 09:34:47 +01:00
|
|
|
|
2017-03-20 13:21:50 +01:00
|
|
|
class PMPReg(implicit p: Parameters) extends CoreBundle()(p) {
|
2017-03-15 09:18:39 +01:00
|
|
|
val cfg = new PMPConfig
|
2017-03-20 13:21:50 +01:00
|
|
|
val addr = UInt(width = paddrBits - PMP.lgAlign)
|
2017-03-15 09:18:39 +01:00
|
|
|
|
2017-03-30 09:31:34 +02:00
|
|
|
def napot = cfg.a(1)
|
|
|
|
def torNotNAPOT = cfg.a(0)
|
|
|
|
def cfgLocked = cfg.l
|
|
|
|
def addrLocked(next: PMPReg) = cfgLocked || next.cfgLocked && next.cfg.a(1)
|
2017-03-20 13:21:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
class PMP(implicit p: Parameters) extends PMPReg {
|
|
|
|
val mask = UInt(width = paddrBits)
|
2017-03-15 09:18:39 +01:00
|
|
|
|
2017-03-20 13:21:50 +01:00
|
|
|
import PMP._
|
2017-03-26 20:12:41 +02:00
|
|
|
def computeMask = Cat((Cat(addr, cfg.a(0)) + 1) ^ Cat(addr, cfg.a(0)), UInt((BigInt(1) << (lgAlign-1)) - 1, lgAlign-1))
|
2017-03-20 21:34:35 +01:00
|
|
|
private def comparand = addr << lgAlign
|
2017-03-15 09:18:39 +01:00
|
|
|
|
2017-03-20 09:34:47 +01:00
|
|
|
private def pow2Match(x: UInt, lgSize: UInt, lgMaxSize: Int) = {
|
|
|
|
def eval(a: UInt, b: UInt, m: UInt) = ((a ^ b) & ~m) === 0
|
|
|
|
if (lgMaxSize <= lgAlign) {
|
|
|
|
eval(x, comparand, mask)
|
|
|
|
} else {
|
|
|
|
// break up the circuit; the MSB part will be CSE'd
|
|
|
|
val lsbMask = mask | ~(((BigInt(1) << lgMaxSize) - 1).U << lgSize)
|
|
|
|
val msbMatch = eval(x >> lgMaxSize, comparand >> lgMaxSize, mask >> lgMaxSize)
|
|
|
|
val lsbMatch = eval(x(lgMaxSize-1, 0), comparand(lgMaxSize-1, 0), lsbMask(lgMaxSize-1, 0))
|
|
|
|
msbMatch && lsbMatch
|
|
|
|
}
|
2017-03-15 09:18:39 +01:00
|
|
|
}
|
|
|
|
|
2017-03-21 20:01:32 +01:00
|
|
|
private def boundMatch(x: UInt, lsbMask: UInt, lgMaxSize: Int) = {
|
|
|
|
if (lgMaxSize <= lgAlign) {
|
|
|
|
x < comparand
|
|
|
|
} else {
|
|
|
|
// break up the circuit; the MSB part will be CSE'd
|
|
|
|
val msbsLess = (x >> lgMaxSize) < (comparand >> lgMaxSize)
|
|
|
|
val msbsEqual = ((x >> lgMaxSize) ^ (comparand >> lgMaxSize)) === 0
|
|
|
|
val lsbsLess = (x(lgMaxSize-1, 0) | lsbMask) < comparand(lgMaxSize-1, 0)
|
|
|
|
msbsLess || (msbsEqual && lsbsLess)
|
|
|
|
}
|
2017-03-15 09:18:39 +01:00
|
|
|
}
|
2017-03-20 09:34:47 +01:00
|
|
|
|
|
|
|
private def lowerBoundMatch(x: UInt, lgSize: UInt, lgMaxSize: Int) =
|
2017-03-21 20:01:32 +01:00
|
|
|
!boundMatch(x, ~(((BigInt(1) << lgMaxSize) - 1).U << lgSize)(lgMaxSize-1, 0), lgMaxSize)
|
2017-03-20 09:34:47 +01:00
|
|
|
|
|
|
|
private def upperBoundMatch(x: UInt, lgMaxSize: Int) =
|
2017-03-21 20:01:32 +01:00
|
|
|
boundMatch(x, 0.U, lgMaxSize)
|
2017-03-20 09:34:47 +01:00
|
|
|
|
|
|
|
private def rangeMatch(x: UInt, lgSize: UInt, lgMaxSize: Int, prev: PMP) =
|
|
|
|
prev.lowerBoundMatch(x, lgSize, lgMaxSize) && upperBoundMatch(x, lgMaxSize)
|
|
|
|
|
2017-03-20 21:34:35 +01:00
|
|
|
private def pow2Homogeneous(x: UInt, pgLevel: UInt) = {
|
2017-04-15 09:54:49 +02:00
|
|
|
val maskHomogeneous = pgLevelMap { idxBits => if (idxBits > paddrBits) false.B else mask(idxBits - 1) } (pgLevel)
|
2017-03-20 21:34:35 +01:00
|
|
|
maskHomogeneous || (pgLevelMap { idxBits => ((x ^ comparand) >> idxBits) =/= 0 } (pgLevel))
|
2017-03-20 09:34:47 +01:00
|
|
|
}
|
|
|
|
|
2017-03-20 21:34:35 +01:00
|
|
|
private def pgLevelMap[T](f: Int => T) = (0 until pgLevels).map { i =>
|
|
|
|
f(pgIdxBits + (pgLevels - 1 - i) * pgLevelBits)
|
|
|
|
}
|
|
|
|
|
2017-03-21 20:01:32 +01:00
|
|
|
private def rangeHomogeneous(x: UInt, pgLevel: UInt, prev: PMP) = {
|
|
|
|
val beginsAfterLower = !(x < prev.comparand)
|
|
|
|
val beginsAfterUpper = !(x < comparand)
|
2017-03-24 02:02:13 +01:00
|
|
|
|
2017-04-15 09:54:49 +02:00
|
|
|
val pgMask = pgLevelMap { idxBits => (((BigInt(1) << paddrBits) - (BigInt(1) << idxBits)) max 0).U } (pgLevel)
|
2017-03-24 02:02:13 +01:00
|
|
|
val endsBeforeLower = (x & pgMask) < (prev.comparand & pgMask)
|
|
|
|
val endsBeforeUpper = (x & pgMask) < (comparand & pgMask)
|
|
|
|
|
2017-03-20 09:34:47 +01:00
|
|
|
endsBeforeLower || beginsAfterUpper || (beginsAfterLower && endsBeforeUpper)
|
|
|
|
}
|
|
|
|
|
2017-03-20 23:05:15 +01:00
|
|
|
// returns whether this PMP completely contains, or contains none of, a page
|
2017-03-21 20:01:32 +01:00
|
|
|
def homogeneous(x: UInt, pgLevel: UInt, prev: PMP): Bool =
|
2017-03-30 09:31:34 +02:00
|
|
|
Mux(napot, pow2Homogeneous(x, pgLevel), !torNotNAPOT || rangeHomogeneous(x, pgLevel, prev))
|
2017-03-20 09:34:47 +01:00
|
|
|
|
2017-03-20 23:05:15 +01:00
|
|
|
// returns whether this matching PMP fully contains the access
|
2017-03-20 23:05:42 +01:00
|
|
|
def aligned(x: UInt, lgSize: UInt, lgMaxSize: Int, prev: PMP): Bool = if (lgMaxSize <= lgAlign) true.B else {
|
2017-03-21 20:01:32 +01:00
|
|
|
val lsbMask = ~(((BigInt(1) << lgMaxSize) - 1).U << lgSize)(lgMaxSize-1, 0)
|
|
|
|
val straddlesLowerBound = ((x >> lgMaxSize) ^ (prev.comparand >> lgMaxSize)) === 0 && (prev.comparand(lgMaxSize-1, 0) & ~x(lgMaxSize-1, 0)) =/= 0
|
|
|
|
val straddlesUpperBound = ((x >> lgMaxSize) ^ (comparand >> lgMaxSize)) === 0 && (comparand(lgMaxSize-1, 0) & (x(lgMaxSize-1, 0) | lsbMask)) =/= 0
|
|
|
|
val rangeAligned = !(straddlesLowerBound || straddlesUpperBound)
|
|
|
|
val pow2Aligned = (lsbMask & ~mask(lgMaxSize-1, 0)) === 0
|
2017-03-30 09:31:34 +02:00
|
|
|
Mux(napot, pow2Aligned, rangeAligned)
|
2017-03-20 09:34:47 +01:00
|
|
|
}
|
|
|
|
|
2017-03-20 23:05:15 +01:00
|
|
|
// returns whether this PMP matches at least one byte of the access
|
2017-03-20 09:34:47 +01:00
|
|
|
def hit(x: UInt, lgSize: UInt, lgMaxSize: Int, prev: PMP): Bool =
|
2017-03-30 09:31:34 +02:00
|
|
|
Mux(napot, pow2Match(x, lgSize, lgMaxSize), torNotNAPOT && rangeMatch(x, lgSize, lgMaxSize, prev))
|
2017-03-15 09:18:39 +01:00
|
|
|
}
|
|
|
|
|
2017-03-21 20:01:32 +01:00
|
|
|
class PMPHomogeneityChecker(pmps: Seq[PMP])(implicit p: Parameters) {
|
|
|
|
def apply(addr: UInt, pgLevel: UInt): Bool = {
|
|
|
|
((true.B, 0.U.asTypeOf(new PMP)) /: pmps) { case ((h, prev), pmp) =>
|
|
|
|
(h && pmp.homogeneous(addr, pgLevel, prev), pmp)
|
|
|
|
}._1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-15 09:18:39 +01:00
|
|
|
class PMPChecker(lgMaxSize: Int)(implicit p: Parameters) extends CoreModule()(p)
|
|
|
|
with HasRocketCoreParameters {
|
|
|
|
val io = new Bundle {
|
|
|
|
val prv = UInt(INPUT, PRV.SZ)
|
|
|
|
val pmp = Vec(nPMPs, new PMP).asInput
|
|
|
|
val addr = UInt(INPUT, paddrBits)
|
|
|
|
val size = UInt(INPUT, log2Ceil(lgMaxSize + 1))
|
2017-03-16 02:00:32 +01:00
|
|
|
val r = Bool(OUTPUT)
|
|
|
|
val w = Bool(OUTPUT)
|
|
|
|
val x = Bool(OUTPUT)
|
2017-03-15 09:18:39 +01:00
|
|
|
}
|
|
|
|
|
2017-03-24 23:55:51 +01:00
|
|
|
val default = if (io.pmp.isEmpty) true.B else io.prv > PRV.S
|
2017-03-20 09:34:47 +01:00
|
|
|
val pmp0 = Wire(init = 0.U.asTypeOf(new PMP))
|
|
|
|
pmp0.cfg.r := default
|
|
|
|
pmp0.cfg.w := default
|
|
|
|
pmp0.cfg.x := default
|
|
|
|
|
|
|
|
val res = (pmp0 /: (io.pmp zip (pmp0 +: io.pmp)).reverse) { case (prev, (pmp, prevPMP)) =>
|
|
|
|
val hit = pmp.hit(io.addr, io.size, lgMaxSize, prevPMP)
|
2017-03-30 09:31:34 +02:00
|
|
|
val ignore = default && !pmp.cfg.l
|
2017-03-20 09:34:47 +01:00
|
|
|
val aligned = pmp.aligned(io.addr, io.size, lgMaxSize, prevPMP)
|
|
|
|
val cur = Wire(init = pmp)
|
|
|
|
cur.cfg.r := (aligned && pmp.cfg.r) || ignore
|
|
|
|
cur.cfg.w := (aligned && pmp.cfg.w) || ignore
|
|
|
|
cur.cfg.x := (aligned && pmp.cfg.x) || ignore
|
|
|
|
Mux(hit, cur, prev)
|
2017-03-15 09:18:39 +01:00
|
|
|
}
|
|
|
|
|
2017-03-20 09:34:47 +01:00
|
|
|
io.r := res.cfg.r
|
|
|
|
io.w := res.cfg.w
|
|
|
|
io.x := res.cfg.x
|
2017-03-15 09:18:39 +01:00
|
|
|
}
|