TLB: add a helper API to determine homogeneous page permissions
This commit is contained in:
parent
fe287864ef
commit
c847559853
97
src/main/scala/rocket/TLBPermissions.scala
Normal file
97
src/main/scala/rocket/TLBPermissions.scala
Normal file
@ -0,0 +1,97 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package rocket
|
||||
|
||||
import Chisel._
|
||||
import diplomacy._
|
||||
import uncore.tilelink2._
|
||||
|
||||
case class TLBPermissions(
|
||||
homogeneous: Bool, // if false, the below are undefined
|
||||
r: Bool, // readable
|
||||
w: Bool, // writeable
|
||||
x: Bool, // executable
|
||||
c: Bool, // cacheable
|
||||
a: Bool, // arithmetic ops
|
||||
l: Bool) // logical ops
|
||||
|
||||
object TLBPageLookup
|
||||
{
|
||||
private case class TLBFixedPermissions(
|
||||
r: Boolean, // readable
|
||||
w: Boolean, // writeable
|
||||
x: Boolean, // executable
|
||||
c: Boolean, // cacheable
|
||||
a: Boolean, // arithmetic ops
|
||||
l: Boolean) { // logical ops
|
||||
val useful = r || w || x || c || a || l
|
||||
}
|
||||
|
||||
// Unmapped memory is considered to be inhomogeneous
|
||||
def apply(managers: Seq[TLManagerParameters], xLen: Int, cacheBlockBytes: Int, pageSize: BigInt): UInt => TLBPermissions = {
|
||||
require (isPow2(xLen) && xLen >= 8)
|
||||
require (isPow2(cacheBlockBytes) && cacheBlockBytes >= xLen/8)
|
||||
require (isPow2(pageSize) && pageSize >= cacheBlockBytes)
|
||||
|
||||
val xferSizes = TransferSizes(cacheBlockBytes, cacheBlockBytes)
|
||||
val allSizes = TransferSizes(1, cacheBlockBytes)
|
||||
val amoSizes = TransferSizes(4, xLen/8)
|
||||
|
||||
val permissions = managers.map { m =>
|
||||
require (!m.supportsGet || m.supportsGet .contains(allSizes), s"MemoryMap region ${m.name} only supports ${m.supportsGet} Get, but must support ${allSizes}")
|
||||
require (!m.supportsPutFull || m.supportsPutFull .contains(allSizes), s"MemoryMap region ${m.name} only supports ${m.supportsPutFull} PutFull, but must support ${allSizes}")
|
||||
require (!m.supportsAcquireB || m.supportsAcquireB .contains(xferSizes), s"MemoryMap region ${m.name} only supports ${m.supportsAcquireB} AcquireB, but must support ${xferSizes}")
|
||||
require (!m.supportsAcquireT || m.supportsAcquireT .contains(xferSizes), s"MemoryMap region ${m.name} only supports ${m.supportsAcquireT} AcquireT, but must support ${xferSizes}")
|
||||
require (!m.supportsLogical || m.supportsLogical .contains(amoSizes), s"MemoryMap region ${m.name} only supports ${m.supportsLogical} Logical, but must support ${amoSizes}")
|
||||
require (!m.supportsArithmetic || m.supportsArithmetic.contains(amoSizes), s"MemoryMap region ${m.name} only supports ${m.supportsArithmetic} Arithmetic, but must support ${amoSizes}")
|
||||
require (m.supportsAcquireT || !m.supportsAcquireB, s"MemoryMap region ${m.name} supports AcquireB (cached read) but not AcquireT (cached write)... and rocket assumes this")
|
||||
|
||||
(m.address, TLBFixedPermissions(
|
||||
r = m.supportsGet || m.supportsAcquireB, // if cached, never uses Get
|
||||
w = m.supportsPutFull || m.supportsAcquireT, // if cached, never uses Put
|
||||
x = m.executable,
|
||||
c = m.supportsAcquireB,
|
||||
a = m.supportsArithmetic,
|
||||
l = m.supportsLogical))
|
||||
}
|
||||
|
||||
val grouped: Map[TLBFixedPermissions, Seq[AddressSet]] = permissions
|
||||
.filter(_._2.useful) // get rid of no-permission devices
|
||||
.groupBy(_._2) // group by permission type
|
||||
.mapValues(seq =>
|
||||
AddressSet.unify(seq.flatMap(_._1)) // coalesce same-permission regions
|
||||
.filter(_.alignment >= pageSize)) // discard any region that's not big enough
|
||||
|
||||
def lowCostProperty(prop: TLBFixedPermissions => Boolean): UInt => Bool = {
|
||||
val (yesm, nom) = grouped.partition { case (k, eq) => prop(k) }
|
||||
val (yes, no) = (yesm.values.flatten.toList, nom.values.flatten.toList)
|
||||
// Find the minimal bits needed to distinguish between yes and no
|
||||
val decisionMask = AddressDecoder(Seq(yes, no))
|
||||
def simplify(x: Seq[AddressSet]) = AddressSet.unify(x.map(_.widen(~decisionMask)).distinct)
|
||||
val (yesf, nof) = (simplify(yes), simplify(no))
|
||||
if (yesf.size < no.size) {
|
||||
(x: UInt) => yesf.map(_.contains(x)).reduce(_ || _)
|
||||
} else {
|
||||
(x: UInt) => !nof.map(_.contains(x)).reduce(_ || _)
|
||||
}
|
||||
}
|
||||
|
||||
// Derive simplified property circuits (don't care when !homo)
|
||||
val rfn = lowCostProperty(_.r)
|
||||
val wfn = lowCostProperty(_.w)
|
||||
val xfn = lowCostProperty(_.x)
|
||||
val cfn = lowCostProperty(_.c)
|
||||
val afn = lowCostProperty(_.a)
|
||||
val lfn = lowCostProperty(_.l)
|
||||
|
||||
val homo = AddressSet.unify(grouped.values.flatten.toList)
|
||||
(x: UInt) => TLBPermissions(
|
||||
homogeneous = homo.map(_.contains(x)).reduce(_ || _),
|
||||
r = rfn(x),
|
||||
w = wfn(x),
|
||||
x = xfn(x),
|
||||
c = cfn(x),
|
||||
a = afn(x),
|
||||
l = lfn(x))
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user