Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 26 additions & 7 deletions src/main/scala/rocket/PTW.scala
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ class PTE(implicit p: Parameters) extends CoreBundle()(p) {
class L2TLBEntry(nSets: Int)(implicit p: Parameters) extends CoreBundle()(p)
with HasCoreParameters {
val idxBits = log2Ceil(nSets)
val tagBits = maxSVAddrBits - pgIdxBits - idxBits + (if (usingHypervisor) 1 else 0)
val tagBits = maxSVAddrBits - pgIdxBits - idxBits + (if (usingHypervisor) 1 else 0) + (if (usingASID) asidLen else 0)
val tag = UInt(tagBits.W)
val ppn = UInt(ppnBits.W)
/** dirty bit */
Expand Down Expand Up @@ -268,6 +268,7 @@ class PTW(n: Int)(implicit edge: TLEdgeOut, p: Parameters) extends CoreModule()(

/** tlb request */
val r_req = Reg(new PTWReq)
val r_req_asid = usingASID.option(Reg(UInt(asidLen.W)))
/** current selected way in arbitor */
val r_req_dest = Reg(Bits())
// to respond to L1TLB : l2_hit
Expand Down Expand Up @@ -350,7 +351,14 @@ class PTW(n: Int)(implicit edge: TLEdgeOut, p: Parameters) extends CoreModule()(
} else {
val plru = new PseudoLRU(coreParams.nPTECacheEntries)
val valid = RegInit(0.U(coreParams.nPTECacheEntries.W))
val tags = Reg(Vec(coreParams.nPTECacheEntries, UInt((if (usingHypervisor) 1 + vaddrBits else paddrBits).W)))
val baseTagWidth = if (s2) {
if (usingHypervisor) 1 + vaddrBits else paddrBits
} else {
1 + (if (usingHypervisor) vaddrBits else paddrBits)
}
val includeAsid = usingASID && !s2
val tagWidth = baseTagWidth + (if (includeAsid) asidLen else 0)
val tags = Reg(Vec(coreParams.nPTECacheEntries, UInt(tagWidth.W)))
// not include full pte, only ppn
val data = Reg(Vec(coreParams.nPTECacheEntries, UInt((if (usingHypervisor && s2) vpnBits else ppnBits).W)))
val can_hit =
Expand All @@ -359,9 +367,12 @@ class PTW(n: Int)(implicit edge: TLEdgeOut, p: Parameters) extends CoreModule()(
val can_refill =
if (s2) do_both_stages && !stage2 && !stage2_final
else can_hit
val tag =
val tagBase =
if (s2) Cat(true.B, stage2_pte_cache_addr.padTo(vaddrBits))
else Cat(r_req.vstage1, pte_addr.padTo(if (usingHypervisor) vaddrBits else paddrBits))
val tag =
if (includeAsid) Cat(r_req_asid.get, tagBase)
else tagBase

val hits = tags.map(_ === tag).asUInt & valid
val hit = hits.orR && can_hit
Expand Down Expand Up @@ -421,7 +432,9 @@ class PTW(n: Int)(implicit edge: TLEdgeOut, p: Parameters) extends CoreModule()(
val g = Reg(Vec(coreParams.nL2TLBWays, UInt(nL2TLBSets.W)))
val valid = RegInit(VecInit(Seq.fill(coreParams.nL2TLBWays)(0.U(nL2TLBSets.W))))
// use r_req to construct tag
val (r_tag, r_idx) = Split(Cat(r_req.vstage1, r_req.addr(maxSVAddrBits-pgIdxBits-1, 0)), idxBits)
val l2TagBase = Cat(r_req.vstage1, r_req.addr(maxSVAddrBits-pgIdxBits-1, 0))
val l2Tag = if (usingASID) Cat(r_req_asid.get, l2TagBase) else l2TagBase
val (r_tag, r_idx) = Split(l2Tag, idxBits)
/** the valid vec for the selected set(including n ways) */
val r_valid_vec = valid.map(_(r_idx)).asUInt
val r_valid_vec_q = Reg(UInt(coreParams.nL2TLBWays.W))
Expand Down Expand Up @@ -458,9 +471,12 @@ class PTW(n: Int)(implicit edge: TLEdgeOut, p: Parameters) extends CoreModule()(
val hg = usingHypervisor.B && io.dpath.sfence.bits.hg
for (way <- 0 until coreParams.nL2TLBWays) {
valid(way) :=
Mux(!hg && io.dpath.sfence.bits.rs1, valid(way) & ~UIntToOH(io.dpath.sfence.bits.addr(idxBits+pgIdxBits-1, pgIdxBits)),
Mux(!hg && io.dpath.sfence.bits.rs2, valid(way) & g(way),
0.U))
Mux(!hg && io.dpath.sfence.bits.rs1,
valid(way) & ~UIntToOH(io.dpath.sfence.bits.addr(idxBits+pgIdxBits-1, pgIdxBits)),
Mux(!hg && io.dpath.sfence.bits.rs2,
valid(way) & g(way),
0.U)
)
}
}

Expand Down Expand Up @@ -589,6 +605,9 @@ class PTW(n: Int)(implicit edge: TLEdgeOut, p: Parameters) extends CoreModule()(
val aux_ppn = Mux(arb.io.out.bits.bits.vstage1, io.dpath.vsatp.ppn, arb.io.out.bits.bits.addr)

r_req := arb.io.out.bits.bits
if (usingASID) {
r_req_asid.foreach(_ := Mux(arb.io.out.bits.bits.vstage1, io.dpath.vsatp.asid(asidLen-1, 0), io.dpath.ptbr.asid(asidLen-1, 0)))
}
r_req_dest := arb.io.chosen
next_state := Mux(arb.io.out.bits.valid, s_req, s_ready)
stage2 := arb.io.out.bits.bits.stage2
Expand Down
6 changes: 4 additions & 2 deletions src/main/scala/rocket/RocketCore.scala
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ case class RocketCoreParams(
haveCease: Boolean = true, // non-standard CEASE instruction
haveSimTimeout: Boolean = true, // add plusarg for simulation timeout
vector: Option[RocketCoreVectorParams] = None,
enableTraceCoreIngress: Boolean = false
enableTraceCoreIngress: Boolean = false,
override val asidLen: Int = 0
) extends CoreParams {
val lgPauseCycles = 5
val haveFSDirty = false
Expand Down Expand Up @@ -134,7 +135,7 @@ trait HasRocketCoreIO extends HasRocketCoreParameters {
implicit val p: Parameters
def nTotalRoCCCSRs: Int
def traceIngressParams = TraceCoreParams(nGroups = 1, iretireWidth = coreParams.retireWidth,
xlen = coreParams.xLen, iaddrWidth = coreParams.xLen)
xlen = coreParams.xLen, iaddrWidth = vaddrBitsExtended)
val io = IO(new CoreBundle()(p) {
val hartid = Input(UInt(hartIdLen.W))
val reset_vector = Input(UInt(resetVectorLen.W))
Expand Down Expand Up @@ -847,6 +848,7 @@ class Rocket(tile: RocketTile)(implicit p: Parameters) extends CoreModule()(p)

io.trace_core_ingress.get.group(0) <> trace_ingress.io.out
io.trace_core_ingress.get.priv := csr.io.trace(0).priv
io.trace_core_ingress.get.ctx := csr.io.ptbr.asid
io.trace_core_ingress.get.tval := csr.io.tval
io.trace_core_ingress.get.cause := csr.io.cause
io.trace_core_ingress.get.time := csr.io.time
Expand Down
112 changes: 84 additions & 28 deletions src/main/scala/rocket/TLB.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import freechips.rocketchip.util.UIntIsOneOf
import freechips.rocketchip.util.SeqToAugmentedSeq
import freechips.rocketchip.util.SeqBoolBitwiseOps

case object ASIdBits extends Field[Int](0)
case object VMIdBits extends Field[Int](0)

/** =SFENCE=
Expand Down Expand Up @@ -158,6 +157,8 @@ class TLBEntry(val nSectors: Int, val superpage: Boolean, val superpageOnly: Boo
val tag_vpn = UInt(vpnBits.W)
/** tag in vitualization mode */
val tag_v = Bool()
/** asid as additional tag */
val tag_sectored_asid = usingASID.option(Vec(nSectors, UInt(asidLen.W)))
/** entry data */
val data = Vec(nSectors, UInt(new TLBEntryData().getWidth.W))
/** valid bit */
Expand All @@ -169,11 +170,17 @@ class TLBEntry(val nSectors: Int, val superpage: Boolean, val superpageOnly: Boo
/** returns the entry data matched with this vpn*/
def getData(vpn: UInt) = OptimizationBarrier(data(sectorIdx(vpn)).asTypeOf(new TLBEntryData))
/** returns whether a sector hits */
def sectorHit(vpn: UInt, virtual: Bool) = valid.orR && sectorTagMatch(vpn, virtual)
def sectorHit(vpn: UInt, virtual: Bool, asid: UInt) = {
val idx = sectorIdx(vpn)
valid(idx) && sectorTagMatch(vpn, virtual) && asidMatch(asid, idx, false)
}
/** returns whether tag matches vpn */
def sectorTagMatch(vpn: UInt, virtual: Bool) = (((tag_vpn ^ vpn) >> nSectors.log2) === 0.U) && (tag_v === virtual)
/** returns whether current asid matches entry asid */
def asidMatch(asid: UInt, idx: UInt, ignoreAsid: Boolean) = if (usingASID && !ignoreAsid) (entry_data(idx).g === true.B || tag_sectored_asid.get(idx) === asid) else true.B
/** returns hit signal */
def hit(vpn: UInt, virtual: Bool): Bool = {
// ignoreAsid is used to ignore asid check for sfence.
def hit(vpn: UInt, virtual: Bool, asid: UInt, ignoreAsid: Boolean = false): Bool = {
if (superpage && usingVM) {
var tagMatch = valid.head && (tag_v === virtual)
for (j <- 0 until pgLevels) {
Expand All @@ -182,10 +189,10 @@ class TLBEntry(val nSectors: Int, val superpage: Boolean, val superpageOnly: Boo
val ignore = level < j.U || (superpageOnly && j == pgLevels - 1).B
tagMatch = tagMatch && (ignore || (tag_vpn ^ vpn)(base + n - 1, base) === 0.U)
}
tagMatch
tagMatch && asidMatch(asid, 0.U, ignoreAsid)
} else {
val idx = sectorIdx(vpn)
valid(idx) && sectorTagMatch(vpn, virtual)
valid(idx) && sectorTagMatch(vpn, virtual) && asidMatch(asid, idx, ignoreAsid)
}
}
/** returns the ppn of the input TLBEntryData */
Expand All @@ -207,40 +214,67 @@ class TLBEntry(val nSectors: Int, val superpage: Boolean, val superpageOnly: Boo
* find the target entry with vpn tag
* and replace the target entry with the input entry data
*/
def insert(vpn: UInt, virtual: Bool, level: UInt, entry: TLBEntryData): Unit = {
def insert(vpn: UInt, virtual: Bool, level: UInt, entry: TLBEntryData, asid: UInt): Unit = {
this.tag_vpn := vpn
this.tag_v := virtual
this.level := level.extract(log2Ceil(pgLevels - superpageOnly.toInt)-1, 0)

val idx = sectorIdx(vpn)
valid(idx) := true.B
data(idx) := entry.asUInt
if (usingASID) { tag_sectored_asid.get(idx) := asid }
}

def invalidate(): Unit = { valid.foreach(_ := false.B) }
def invalidate(): Unit = {
valid.foreach(_ := false.B)
if (usingASID) { tag_sectored_asid.get.foreach(_ := 0.U) }
}
def invalidate(virtual: Bool): Unit = {
for ((v, e) <- valid zip entry_data)
when (tag_v === virtual) { v := false.B }
for (((v, e), i) <- (valid zip entry_data).zipWithIndex) {
when (tag_v === virtual) {
v := false.B
}
}
}
def invalidateVPN(vpn: UInt, virtual: Bool): Unit = {
if (superpage) {
when (hit(vpn, virtual)) { invalidate() }
when (hit(vpn, virtual, 0.U, ignoreAsid = true)) { invalidate() }
} else {
when (sectorTagMatch(vpn, virtual)) {
for (((v, e), i) <- (valid zip entry_data).zipWithIndex)
when (tag_v === virtual && i.U === sectorIdx(vpn)) { v := false.B }
for (((v, e), i) <- (valid zip entry_data).zipWithIndex) {
when (tag_v === virtual && i.U === sectorIdx(vpn)) {
v := false.B
}
}
}
}
// For fragmented superpage mappings, we assume the worst (largest)
// case, and zap entries whose most-significant VPNs match
when (((tag_vpn ^ vpn) >> (pgLevelBits * (pgLevels - 1))) === 0.U) {
for ((v, e) <- valid zip entry_data)
when (tag_v === virtual && e.fragmented_superpage) { v := false.B }
for (((v, e), i) <- (valid zip entry_data).zipWithIndex) {
when (tag_v === virtual && e.fragmented_superpage) {
v := false.B
}
}
}
}
def invalidateAsid(asid: UInt, virtual: Bool): Unit = {
if (usingASID) {
for (i <- 0 until nSectors) {
when (valid(i) && tag_v === virtual && !entry_data(i).g && tag_sectored_asid.get(i) === asid) {
valid(i) := false.B
tag_sectored_asid.get(i) := 0.U
}
}
}
}
def invalidateNonGlobal(virtual: Bool): Unit = {
for ((v, e) <- valid zip entry_data)
when (tag_v === virtual && !e.g) { v := false.B }
for (((v, e), i) <- (valid zip entry_data).zipWithIndex) {
when (tag_v === virtual && !e.g) {
v := false.B
if (usingASID) { tag_sectored_asid.get(i) := 0.U }
}
}
}
}

Expand Down Expand Up @@ -352,6 +386,7 @@ class TLB(instruction: Boolean, lgMaxSize: Int, cfg: TLBConfig)(implicit edge: T
val state = RegInit(s_ready)
// use vpn as refill_tag
val r_refill_tag = Reg(UInt(vpnBits.W))
val r_refill_asid = usingASID.option(Reg(UInt(asidLen.W)))
val r_superpage_repl_addr = Reg(UInt(log2Ceil(superpage_entries.size).W))
val r_sectored_repl_addr = Reg(UInt(log2Ceil(sectored_entries.head.size).W))
val r_sectored_hit = Reg(Valid(UInt(log2Ceil(sectored_entries.head.size).W)))
Expand All @@ -367,10 +402,18 @@ class TLB(instruction: Boolean, lgMaxSize: Int, cfg: TLBConfig)(implicit edge: T
/** privilege mode */
val priv = io.req.bits.prv
val priv_v = usingHypervisor.B && io.req.bits.v
val priv_s = priv(0)
// 1 if priv is U or H, 0 if priv is S or M
val priv_s = priv(0)
// user mode and supervisor mode
val priv_uses_vm = priv <= PRV.S.U
val satp = Mux(priv_v, io.ptw.vsatp, io.ptw.ptbr)
val currentAsid = if (usingASID) {
val vsAsid = io.ptw.vsatp.asid(asidLen-1, 0)
val sAsid = io.ptw.ptbr.asid(asidLen-1, 0)
Mux(priv_v, vsAsid, sAsid)
} else {
0.U
}
val stage1_en = usingVM.B && satp.mode(satp.mode.getWidth-1)
/** VS-stage translation enable */
val vstage1_en = usingHypervisor.B && priv_v && io.ptw.vsatp.mode(io.ptw.vsatp.mode.getWidth-1)
Expand Down Expand Up @@ -435,15 +478,16 @@ class TLB(instruction: Boolean, lgMaxSize: Int, cfg: TLBConfig)(implicit edge: T
val prot_eff = pma.io.resp.eff

// hit check
val sector_hits = sectored_entries(memIdx).map(_.sectorHit(vpn, priv_v))
val superpage_hits = superpage_entries.map(_.hit(vpn, priv_v))
val hitsVec = all_entries.map(vm_enabled && _.hit(vpn, priv_v))
val sector_hits = sectored_entries(memIdx).map(_.sectorHit(vpn, priv_v, currentAsid))
val superpage_hits = superpage_entries.map(_.hit(vpn, priv_v, currentAsid))
val hitsVec = all_entries.map(vm_enabled && _.hit(vpn, priv_v, currentAsid))
val real_hits = hitsVec.asUInt
val hits = Cat(!vm_enabled, real_hits)

// use ptw response to refill
// permission bit arrays
when (do_refill) {
val refillAsid = if (usingASID) r_refill_asid.get else 0.U
val pte = io.ptw.resp.bits.pte
val refill_v = r_vstage1_en || r_stage2_en
val newEntry = Wire(new TLBEntryData)
Expand Down Expand Up @@ -472,11 +516,11 @@ class TLB(instruction: Boolean, lgMaxSize: Int, cfg: TLBConfig)(implicit edge: T
newEntry.fragmented_superpage := io.ptw.resp.bits.fragmented_superpage
// refill special_entry
when (special_entry.nonEmpty.B && !io.ptw.resp.bits.homogeneous) {
special_entry.foreach(_.insert(r_refill_tag, refill_v, io.ptw.resp.bits.level, newEntry))
special_entry.foreach(_.insert(r_refill_tag, refill_v, io.ptw.resp.bits.level, newEntry, refillAsid))
}.elsewhen (io.ptw.resp.bits.level < (pgLevels-1).U) {
val waddr = Mux(r_superpage_hit.valid && usingHypervisor.B, r_superpage_hit.bits, r_superpage_repl_addr)
for ((e, i) <- superpage_entries.zipWithIndex) when (r_superpage_repl_addr === i.U) {
e.insert(r_refill_tag, refill_v, io.ptw.resp.bits.level, newEntry)
e.insert(r_refill_tag, refill_v, io.ptw.resp.bits.level, newEntry, refillAsid)
when (invalidate_refill) { e.invalidate() }
}
// refill sectored_hit
Expand All @@ -485,7 +529,7 @@ class TLB(instruction: Boolean, lgMaxSize: Int, cfg: TLBConfig)(implicit edge: T
val waddr = Mux(r_sectored_hit.valid, r_sectored_hit.bits, r_sectored_repl_addr)
for ((e, i) <- sectored_entries(r_memIdx).zipWithIndex) when (waddr === i.U) {
when (!r_sectored_hit.valid) { e.invalidate() }
e.insert(r_refill_tag, refill_v, 0.U, newEntry)
e.insert(r_refill_tag, refill_v, 0.U, newEntry, refillAsid)
when (invalidate_refill) { e.invalidate() }
}
}
Expand Down Expand Up @@ -679,6 +723,9 @@ class TLB(instruction: Boolean, lgMaxSize: Int, cfg: TLBConfig)(implicit edge: T
when (io.req.fire && tlb_miss) {
state := s_request
r_refill_tag := vpn
if (usingASID) {
r_refill_asid.foreach(_ := currentAsid)
}
r_need_gpa := tlb_hit_if_not_gpa_miss
r_vstage1_en := vstage1_en
r_stage2_en := stage2_en
Expand Down Expand Up @@ -717,12 +764,21 @@ class TLB(instruction: Boolean, lgMaxSize: Int, cfg: TLBConfig)(implicit edge: T
// SFENCE processing logic.
when (sfence) {
assert(!io.sfence.bits.rs1 || (io.sfence.bits.addr >> pgIdxBits) === vpn)
val hv = usingHypervisor.B && io.sfence.bits.hv
val hg = usingHypervisor.B && io.sfence.bits.hg
val flushAsid = if (usingASID) io.sfence.bits.asid(asidLen-1, 0) else 0.U
for (e <- all_real_entries) {
val hv = usingHypervisor.B && io.sfence.bits.hv
val hg = usingHypervisor.B && io.sfence.bits.hg
when (!hg && io.sfence.bits.rs1) { e.invalidateVPN(vpn, hv) }
.elsewhen (!hg && io.sfence.bits.rs2) { e.invalidateNonGlobal(hv) }
.otherwise { e.invalidate(hv || hg) }
when (!hg && io.sfence.bits.rs1) {
e.invalidateVPN(vpn, hv)
}.elsewhen (!hg && io.sfence.bits.rs2) {
if (usingASID) {
e.invalidateAsid(flushAsid, hv)
} else {
e.invalidateNonGlobal(hv) // not using asid, flush all non-global entries
}
}.otherwise {
e.invalidate(hv || hg)
}
}
}
when(io.req.fire && vsatp_mode_mismatch) {
Expand Down
4 changes: 2 additions & 2 deletions src/main/scala/tile/BaseTile.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import org.chipsalliance.diplomacy.bundlebridge._

import freechips.rocketchip.resources.{PropertyMap, PropertyOption, ResourceReference, DTSTimebase}
import freechips.rocketchip.interrupts.{IntInwardNode, IntOutwardNode}
import freechips.rocketchip.rocket.{ICacheParams, DCacheParams, BTBParams, ASIdBits, VMIdBits, TraceAux, BPWatch}
import freechips.rocketchip.rocket.{ICacheParams, DCacheParams, BTBParams, VMIdBits, TraceAux, BPWatch}
import freechips.rocketchip.subsystem.{
HierarchicalElementParams, InstantiableHierarchicalElementParams, HierarchicalElementCrossingParamsLike,
CacheBlockBytes, SystemBusKey, BaseHierarchicalElement, InsertTimingClosureRegistersOnHartIds, BaseHierarchicalElementModuleImp
Expand Down Expand Up @@ -81,7 +81,7 @@ trait HasNonDiplomaticTileParameters {
require(pgLevels >= res)
res
}
def asIdBits: Int = p(ASIdBits)
def asIdBits: Int = tileParams.core.asidLen
def vmIdBits: Int = p(VMIdBits)
lazy val maxPAddrBits: Int = {
require(xLen == 32 || xLen == 64, s"Only XLENs of 32 or 64 are supported, but got $xLen")
Expand Down
4 changes: 4 additions & 0 deletions src/main/scala/tile/Core.scala
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ trait CoreParams {
val traceHasWdata: Boolean
val xLen: Int
val pgLevels: Int

val asidLen: Int = 0
def traceCustom: Option[Data] = None
def customIsaExt: Option[String] = None
def customCSRs(implicit p: Parameters): CustomCSRs = new CustomCSRs
Expand Down Expand Up @@ -149,6 +151,8 @@ trait HasCoreParameters extends HasTileParameters {
// Requires post-processing due to out-of-order writebacks.
val enableCommitLog = false

def asidLen = coreParams.asidLen
def usingASID = asidLen > 0
}

abstract class CoreModule(implicit val p: Parameters) extends Module
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/tile/RocketTile.scala
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class RocketTile private(
* and selecting trace sink
*/
val trace_encoder_controller = rocketParams.traceParams.map { t =>
val trace_encoder_controller = LazyModule(new TraceEncoderController(t.encoderBaseAddr, xBytes))
val trace_encoder_controller = LazyModule(new TraceEncoderController(t.encoderBaseAddr, xBytes, tileId))
connectTLSlave(trace_encoder_controller.node, xBytes)
trace_encoder_controller
}
Expand Down
Loading