Skip to content

Commit

Permalink
mmu.l2tlb: add TimeOutAssert & cut down mem resp data buffer (#1021)
Browse files Browse the repository at this point in the history
* mmu.l2tlb: add object TimeOutAssert

* mmu.l2tlb: add TimeOutAssert to Repeater

* mmu.l2tlb: cut down mem req buffer from 8 ptes to 1 pte each

* util: move some utils from MMUBundle to utils
  • Loading branch information
Lemover committed Sep 11, 2021
1 parent c9ebdf9 commit 9bd9cdf
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 63 deletions.
36 changes: 36 additions & 0 deletions src/main/scala/utils/Hold.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,39 @@ object ReadAndHold {
def apply[T <: Data](x: Mem[T], addr: UInt, en: Bool): T = HoldUnless(x.read(addr), en)
def apply[T <: Data](x: SyncReadMem[T], addr: UInt, en: Bool): T = HoldUnless(x.read(addr, en), RegNext(en))
}

/*
* Hold the in fire unless out fire or flush happens
* similar to BoolStopWatch
*/
object ValidHold {
def apply(infire: Bool, outfire: Bool, flush: Bool = false.B ) = {
val valid = RegInit(false.B)
when (outfire) { valid := false.B }
when (infire) { valid := true.B }
when (flush) { valid := false.B } // NOTE: the flush will flush in & out, is that ok?
valid
}
}

/*
* Hold the 'fire' for only one cycle unless new fire comes in
*/
object OneCycleValid {
def apply(fire: Bool, flush: Bool = false.B) = {
val valid = RegInit(false.B)
when (valid) { valid := false.B }
when (fire) { valid := true.B }
when (flush) { valid := false.B }
valid
}
}

/*
* Hold the data when it is valid and bypass latest data
*/
object DataHoldBypass {
def apply(data: UInt, valid: Bool): UInt = {
Mux(valid, data, RegEnable(data, valid))
}
}
15 changes: 15 additions & 0 deletions src/main/scala/utils/Misc.scala
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,18 @@ object Transpose
VecInit((0 until n).map(i => VecInit(in.map(row => row(i)))))
}
}

/**
* assert when 'signal' is true for more than 'threshold' cycles
*/
object TimeOutAssert {
def apply(signal: Bool, threshold: Int, message: String): Unit = {
val counter = RegInit(0.U(32.W))
when (signal) {
counter := counter + 1.U
}.otherwise {
counter := 0.U
}
assert(counter <= threshold.U, message)
}
}
9 changes: 1 addition & 8 deletions src/main/scala/xiangshan/cache/mmu/L2TLBMissQueue.scala
Original file line number Diff line number Diff line change
Expand Up @@ -193,15 +193,8 @@ class L2TlbMissQueue(implicit p: Parameters) extends XSModule with HasPtwConst {
XSPerfAccumulate("mem_count", io.mem.req.fire())
XSPerfAccumulate("mem_cycle", PopCount(is_waiting) =/= 0.U)

// time out assert
for (i <- 0 until MSHRSize) {
val wait_counter = RegInit(0.U(32.W))
when (state(i) =/= state_idle) {
wait_counter := wait_counter + 1.U
}.otherwise {
wait_counter := 0.U
}
assert(wait_counter <= 2000.U, s"missqueue time out no out ${i}")
TimeOutAssert(state(i) =/= state_idle, timeOutThreshold, s"missqueue time out no out ${i}")
}
assert(!io.in.valid || io.in.ready, "when io.in.valid, should always ready")
}
22 changes: 1 addition & 21 deletions src/main/scala/xiangshan/cache/mmu/MMUBundle.scala
Original file line number Diff line number Diff line change
Expand Up @@ -609,24 +609,4 @@ class PtwIO(implicit p: Parameters) extends PtwBundle {
class L2TlbMemReqBundle(implicit p: Parameters) extends PtwBundle {
val addr = UInt(PAddrBits.W)
val id = UInt(bMemID.W)
}

object ValidHold {
def apply(infire: Bool, outfire: Bool, flush: Bool = false.B ) = {
val valid = RegInit(false.B)
when (outfire) { valid := false.B }
when (infire) { valid := true.B }
when (flush) { valid := false.B } // NOTE: the flush will flush in & out, is that ok?
valid
}
}

object OneCycleValid {
def apply(fire: Bool, flush: Bool = false.B) = {
val valid = RegInit(false.B)
when (valid) { valid := false.B }
when (fire) { valid := true.B }
when (flush) { valid := false.B }
valid
}
}
}
2 changes: 2 additions & 0 deletions src/main/scala/xiangshan/cache/mmu/MMUConst.scala
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ trait HasTlbConst extends HasXSParameter {

val sramSinglePort = true

val timeOutThreshold = 2000

def get_idx(vpn: UInt, nSets: Int): UInt = {
vpn(log2Up(nSets)-1, 0)
}
Expand Down
39 changes: 15 additions & 24 deletions src/main/scala/xiangshan/cache/mmu/PTW.scala
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ class PTWImp(outer: PTW)(implicit p: Parameters) extends PtwModule(outer) {
assert(!sfence_latch(i) || waiting_resp(i)) // when sfence_latch wait for mem resp, waiting_resp should be true
}

val mq_out = missQueue.io.out
val mq_mem = missQueue.io.mem
mq_mem.req_mask := waiting_resp.take(MSHRSize)
fsm.io.mem.mask := waiting_resp.last
Expand All @@ -151,6 +152,7 @@ class PTWImp(outer: PTW)(implicit p: Parameters) extends PtwModule(outer) {
mem_arb.io.out.ready := mem.a.ready

val req_addr_low = Reg(Vec(MemReqWidth, UInt((log2Up(l2tlbParams.blockBytes)-log2Up(XLEN/8)).W)))

when (mem_arb.io.out.fire()) {
req_addr_low(mem_arb.io.out.bits.id) := mem_arb.io.out.bits.addr(log2Up(l2tlbParams.blockBytes)-1, log2Up(XLEN/8))
waiting_resp(mem_arb.io.out.bits.id) := true.B
Expand All @@ -166,14 +168,19 @@ class PTWImp(outer: PTW)(implicit p: Parameters) extends PtwModule(outer) {
mem.a.valid := mem_arb.io.out.valid
mem.d.ready := true.B
// mem -> data buffer
val refill_data = Reg(Vec(MemReqWidth, Vec(blockBits / l1BusDataWidth, UInt(l1BusDataWidth.W))))
val refill_data = Reg(Vec(blockBits / l1BusDataWidth, UInt(l1BusDataWidth.W)))
val refill_helper = edge.firstlastHelper(mem.d.bits, mem.d.fire())
val mem_resp_done = refill_helper._3
val mem_resp_from_mq = from_missqueue(mem.d.bits.source)
when (mem.d.valid) {
assert(mem.d.bits.source <= MSHRSize.U)
refill_data(mem.d.bits.source)(refill_helper._4) := mem.d.bits.data
refill_data(refill_helper._4) := mem.d.bits.data
}
// save only one pte for each id
// (miss queue may can't resp to tlb with low latency, it should have highest priority, but diffcult to design cache)
val resp_pte = VecInit((0 until MemReqWidth).map(i =>
DataHoldBypass(get_part(refill_data, RegNext(req_addr_low(mem.d.bits.source))), RegNext(i.U === mem.d.bits.source && mem.d.valid))
))
// mem -> control signal
when (mem_resp_done) {
waiting_resp(mem.d.bits.source) := false.B
Expand All @@ -185,16 +192,16 @@ class PTWImp(outer: PTW)(implicit p: Parameters) extends PtwModule(outer) {
// mem -> fsm
fsm.io.mem.req.ready := mem.a.ready
fsm.io.mem.resp.valid := mem_resp_done && !mem_resp_from_mq
fsm.io.mem.resp.bits := get_part(refill_data(MSHRSize), req_addr_low(MSHRSize))
fsm.io.mem.resp.bits := resp_pte.last
// mem -> cache
val refill_from_mq = RegNext(mem_resp_from_mq)
cache.io.refill.valid := RegNext(mem_resp_done && !io.sfence.valid && !sfence_latch(mem.d.bits.source))
cache.io.refill.bits.ptes := refill_data(RegNext(mem.d.bits.source)).asUInt
cache.io.refill.bits.ptes := refill_data.asUInt
cache.io.refill.bits.vpn := Mux(refill_from_mq, mq_mem.refill_vpn, fsm.io.refill.vpn)
cache.io.refill.bits.level := Mux(refill_from_mq, 2.U, RegEnable(fsm.io.refill.level, init = 0.U, fsm.io.mem.req.fire()))
cache.io.refill.bits.addr_low := req_addr_low(RegNext(mem.d.bits.source))

val mq_out = missQueue.io.out

mq_out.ready := MuxLookup(missQueue.io.out.bits.source, false.B,
(0 until PtwWidth).map(i => i.U -> outArb(i).in(outArbMqPort).ready))
for (i <- 0 until PtwWidth) {
Expand All @@ -204,9 +211,7 @@ class PTWImp(outer: PTW)(implicit p: Parameters) extends PtwModule(outer) {
outArb(i).in(outArbFsmPort).valid := fsm.io.resp.valid && fsm.io.resp.bits.source===i.U
outArb(i).in(outArbFsmPort).bits := fsm.io.resp.bits.resp
outArb(i).in(outArbMqPort).valid := mq_out.valid && mq_out.bits.source===i.U
outArb(i).in(outArbMqPort).bits := pte_to_ptwResp(get_part(refill_data(mq_out.bits.id),
req_addr_low(mq_out.bits.id)),
mq_out.bits.vpn)
outArb(i).in(outArbMqPort).bits := pte_to_ptwResp(resp_pte(mq_out.bits.id), mq_out.bits.vpn)
}

// io.tlb.map(_.resp) <> outArb.map(_.out)
Expand Down Expand Up @@ -271,22 +276,8 @@ class PTWImp(outer: PTW)(implicit p: Parameters) extends PtwModule(outer) {

// time out assert
for (i <- 0 until MSHRSize + 1) {
val wait_counter = RegInit(0.U(32.W))
when (waiting_resp(i)) {
wait_counter := wait_counter + 1.U
}.otherwise {
wait_counter := 0.U
}
assert(wait_counter <= 2000.U, "ptw mem resp time out wait_resp")
}
for (i <- 0 until MSHRSize + 1) {
val wait_counter = RegInit(0.U(32.W))
when (sfence_latch(i)) {
wait_counter := wait_counter + 1.U
}.otherwise {
wait_counter := 0.U
}
assert(wait_counter <= 2000.U, "ptw mem resp time out sfence_latch")
TimeOutAssert(waiting_resp(i), timeOutThreshold, s"ptw mem resp time out wait_resp${i}")
TimeOutAssert(sfence_latch(i), timeOutThreshold, s"ptw mem resp time out sfence_latch${i}")
}
}

Expand Down
9 changes: 1 addition & 8 deletions src/main/scala/xiangshan/cache/mmu/PageTableWalker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -161,12 +161,5 @@ class PtwFsm()(implicit p: Parameters) extends XSModule with HasPtwConst {
XSPerfAccumulate("mem_cycle", BoolStopWatch(mem.req.fire, mem.resp.fire(), true))
XSPerfAccumulate("mem_blocked", mem.req.valid && !mem.req.ready)

// time out assert
val wait_counter = RegInit(0.U(32.W))
when (state =/= s_idle) {
wait_counter := wait_counter + 1.U
}.otherwise {
wait_counter := 0.U
}
assert(wait_counter <= 2000.U, "page table walker time out")
TimeOutAssert(state =/= s_idle, timeOutThreshold, "page table walker time out")
}
7 changes: 5 additions & 2 deletions src/main/scala/xiangshan/cache/mmu/Repeater.scala
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class PTWRepeater(Width: Int = 1)(implicit p: Parameters) extends XSModule with
XSDebug(req_in.valid || io.tlb.resp.valid, p"tlb: ${tlb}\n")
XSDebug(io.ptw.req(0).valid || io.ptw.resp.valid, p"ptw: ${ptw}\n")
assert(!RegNext(recv && io.ptw.resp.valid, init = false.B), "re-receive ptw.resp")
TimeOutAssert(sent && !recv, timeOutThreshold, "Repeater doesn't recv resp in time")
}

/* dtlb
Expand Down Expand Up @@ -116,7 +117,6 @@ class PTWFilter(Width: Int, Size: Int)(implicit p: Parameters) extends XSModule
reqs
}


val reqs = filter_req()
val req_ports = filter_ports
var enqPtr_next = WireInit(deqPtr)
Expand Down Expand Up @@ -194,7 +194,6 @@ class PTWFilter(Width: Int, Size: Int)(implicit p: Parameters) extends XSModule
counter := 0.U
}


// perf
val inflight_counter = RegInit(0.U(log2Up(Size + 1).W))
when (io.ptw.req(0).fire() =/= io.ptw.resp.fire()) {
Expand All @@ -213,4 +212,8 @@ class PTWFilter(Width: Int, Size: Int)(implicit p: Parameters) extends XSModule
for (i <- 0 until Size + 1) {
XSPerfAccumulate(s"counter${i}", counter === i.U)
}

for (i <- 0 until Size) {
TimeOutAssert(v(i), timeOutThreshold, s"Filter ${i} doesn't recv resp in time")
}
}

0 comments on commit 9bd9cdf

Please sign in to comment.