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