1*6d5ddbceSLemover/*************************************************************************************** 2*6d5ddbceSLemover* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences 3*6d5ddbceSLemover* 4*6d5ddbceSLemover* XiangShan is licensed under Mulan PSL v2. 5*6d5ddbceSLemover* You can use this software according to the terms and conditions of the Mulan PSL v2. 6*6d5ddbceSLemover* You may obtain a copy of Mulan PSL v2 at: 7*6d5ddbceSLemover* http://license.coscl.org.cn/MulanPSL2 8*6d5ddbceSLemover* 9*6d5ddbceSLemover* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10*6d5ddbceSLemover* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11*6d5ddbceSLemover* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12*6d5ddbceSLemover* 13*6d5ddbceSLemover* See the Mulan PSL v2 for more details. 14*6d5ddbceSLemover***************************************************************************************/ 15*6d5ddbceSLemover 16*6d5ddbceSLemoverpackage xiangshan.cache.mmu 17*6d5ddbceSLemover 18*6d5ddbceSLemoverimport chipsalliance.rocketchip.config.Parameters 19*6d5ddbceSLemoverimport chisel3._ 20*6d5ddbceSLemoverimport chisel3.util._ 21*6d5ddbceSLemoverimport xiangshan._ 22*6d5ddbceSLemoverimport xiangshan.cache.{HasDCacheParameters, MemoryOpConstants} 23*6d5ddbceSLemoverimport utils._ 24*6d5ddbceSLemoverimport freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp} 25*6d5ddbceSLemoverimport freechips.rocketchip.tilelink._ 26*6d5ddbceSLemover 27*6d5ddbceSLemoverclass PTWRepeater(Width: Int = 1)(implicit p: Parameters) extends XSModule with HasPtwConst { 28*6d5ddbceSLemover val io = IO(new Bundle { 29*6d5ddbceSLemover val tlb = Flipped(new TlbPtwIO(Width)) 30*6d5ddbceSLemover val ptw = new TlbPtwIO 31*6d5ddbceSLemover val sfence = Input(new SfenceBundle) 32*6d5ddbceSLemover }) 33*6d5ddbceSLemover val req_in = if (Width == 1) { 34*6d5ddbceSLemover io.tlb.req(0) 35*6d5ddbceSLemover } else { 36*6d5ddbceSLemover val arb = Module(new RRArbiter(io.tlb.req(0).bits.cloneType, Width)) 37*6d5ddbceSLemover arb.io.in <> io.tlb.req 38*6d5ddbceSLemover arb.io.out 39*6d5ddbceSLemover } 40*6d5ddbceSLemover val (tlb, ptw, sfence) = (io.tlb, io.ptw, RegNext(io.sfence.valid)) 41*6d5ddbceSLemover val req = RegEnable(req_in.bits, req_in.fire()) 42*6d5ddbceSLemover val resp = RegEnable(ptw.resp.bits, ptw.resp.fire()) 43*6d5ddbceSLemover val haveOne = BoolStopWatch(req_in.fire(), tlb.resp.fire() || sfence) 44*6d5ddbceSLemover val sent = BoolStopWatch(ptw.req(0).fire(), req_in.fire() || sfence) 45*6d5ddbceSLemover val recv = BoolStopWatch(ptw.resp.fire(), req_in.fire() || sfence) 46*6d5ddbceSLemover 47*6d5ddbceSLemover req_in.ready := !haveOne 48*6d5ddbceSLemover ptw.req(0).valid := haveOne && !sent 49*6d5ddbceSLemover ptw.req(0).bits := req 50*6d5ddbceSLemover 51*6d5ddbceSLemover tlb.resp.bits := resp 52*6d5ddbceSLemover tlb.resp.valid := haveOne && recv 53*6d5ddbceSLemover ptw.resp.ready := !recv 54*6d5ddbceSLemover 55*6d5ddbceSLemover XSPerfAccumulate("req_count", ptw.req(0).fire()) 56*6d5ddbceSLemover XSPerfAccumulate("tlb_req_cycle", BoolStopWatch(req_in.fire(), tlb.resp.fire() || sfence)) 57*6d5ddbceSLemover XSPerfAccumulate("ptw_req_cycle", BoolStopWatch(ptw.req(0).fire(), ptw.resp.fire() || sfence)) 58*6d5ddbceSLemover 59*6d5ddbceSLemover XSDebug(haveOne, p"haveOne:${haveOne} sent:${sent} recv:${recv} sfence:${sfence} req:${req} resp:${resp}") 60*6d5ddbceSLemover XSDebug(req_in.valid || io.tlb.resp.valid, p"tlb: ${tlb}\n") 61*6d5ddbceSLemover XSDebug(io.ptw.req(0).valid || io.ptw.resp.valid, p"ptw: ${ptw}\n") 62*6d5ddbceSLemover assert(!RegNext(recv && io.ptw.resp.valid, init = false.B), "re-receive ptw.resp") 63*6d5ddbceSLemover} 64*6d5ddbceSLemover 65*6d5ddbceSLemover/* dtlb 66*6d5ddbceSLemover * 67*6d5ddbceSLemover */ 68*6d5ddbceSLemoverclass PTWFilter(Width: Int, Size: Int)(implicit p: Parameters) extends XSModule with HasPtwConst { 69*6d5ddbceSLemover val io = IO(new Bundle { 70*6d5ddbceSLemover val tlb = Flipped(new TlbPtwIO(Width)) 71*6d5ddbceSLemover val ptw = new TlbPtwIO 72*6d5ddbceSLemover val sfence = Input(new SfenceBundle) 73*6d5ddbceSLemover }) 74*6d5ddbceSLemover 75*6d5ddbceSLemover require(Size >= Width) 76*6d5ddbceSLemover 77*6d5ddbceSLemover val v = RegInit(VecInit(Seq.fill(Size)(false.B))) 78*6d5ddbceSLemover val vpn = Reg(Vec(Size, UInt(vpnLen.W))) 79*6d5ddbceSLemover val enqPtr = RegInit(0.U(log2Up(Size).W)) // Enq 80*6d5ddbceSLemover val issPtr = RegInit(0.U(log2Up(Size).W)) // Iss to Ptw 81*6d5ddbceSLemover val deqPtr = RegInit(0.U(log2Up(Size).W)) // Deq 82*6d5ddbceSLemover val mayFullDeq = RegInit(false.B) 83*6d5ddbceSLemover val mayFullIss = RegInit(false.B) 84*6d5ddbceSLemover val counter = RegInit(0.U(log2Up(Size+1).W)) 85*6d5ddbceSLemover 86*6d5ddbceSLemover val sfence = RegNext(io.sfence) 87*6d5ddbceSLemover val ptwResp = RegEnable(io.ptw.resp.bits, io.ptw.resp.fire()) 88*6d5ddbceSLemover val ptwResp_valid = RegNext(io.ptw.resp.valid, init = false.B) 89*6d5ddbceSLemover val reqs = filter(io.tlb.req) 90*6d5ddbceSLemover 91*6d5ddbceSLemover var enqPtr_next = WireInit(deqPtr) 92*6d5ddbceSLemover val isFull = enqPtr === deqPtr && mayFullDeq 93*6d5ddbceSLemover val isEmptyDeq = enqPtr === deqPtr && !mayFullDeq 94*6d5ddbceSLemover val isEmptyIss = enqPtr === issPtr && !mayFullIss 95*6d5ddbceSLemover val accumEnqNum = (0 until Width).map(i => PopCount(reqs.take(i).map(_.valid))) 96*6d5ddbceSLemover val enqPtrVec = VecInit((0 until Width).map(i => enqPtr + accumEnqNum(i))) 97*6d5ddbceSLemover val enqNum = PopCount(reqs.map(_.valid)) 98*6d5ddbceSLemover val canEnqueue = counter +& enqNum <= Size.U 99*6d5ddbceSLemover 100*6d5ddbceSLemover io.tlb.req.map(_.ready := true.B) // NOTE: just drop un-fire reqs 101*6d5ddbceSLemover io.tlb.resp.valid := ptwResp_valid 102*6d5ddbceSLemover io.tlb.resp.bits := ptwResp 103*6d5ddbceSLemover io.ptw.req(0).valid := v(issPtr) && !isEmptyIss && !(ptwResp_valid && ptwResp.entry.hit(io.ptw.req(0).bits.vpn)) 104*6d5ddbceSLemover io.ptw.req(0).bits.vpn := vpn(issPtr) 105*6d5ddbceSLemover io.ptw.resp.ready := true.B 106*6d5ddbceSLemover 107*6d5ddbceSLemover reqs.zipWithIndex.map{ 108*6d5ddbceSLemover case (req, i) => 109*6d5ddbceSLemover when (req.valid && canEnqueue) { 110*6d5ddbceSLemover v(enqPtrVec(i)) := true.B 111*6d5ddbceSLemover vpn(enqPtrVec(i)) := req.bits.vpn 112*6d5ddbceSLemover } 113*6d5ddbceSLemover } 114*6d5ddbceSLemover 115*6d5ddbceSLemover val do_enq = canEnqueue && Cat(reqs.map(_.valid)).orR 116*6d5ddbceSLemover val do_deq = (!v(deqPtr) && !isEmptyDeq) 117*6d5ddbceSLemover val do_iss = io.ptw.req(0).fire() || (!v(issPtr) && !isEmptyIss) 118*6d5ddbceSLemover when (do_enq) { 119*6d5ddbceSLemover enqPtr := enqPtr + enqNum 120*6d5ddbceSLemover } 121*6d5ddbceSLemover when (do_deq) { 122*6d5ddbceSLemover deqPtr := deqPtr + 1.U 123*6d5ddbceSLemover } 124*6d5ddbceSLemover when (do_iss) { 125*6d5ddbceSLemover issPtr := issPtr + 1.U 126*6d5ddbceSLemover } 127*6d5ddbceSLemover when (do_enq =/= do_deq) { 128*6d5ddbceSLemover mayFullDeq := do_enq 129*6d5ddbceSLemover } 130*6d5ddbceSLemover when (do_enq =/= do_iss) { 131*6d5ddbceSLemover mayFullIss := do_enq 132*6d5ddbceSLemover } 133*6d5ddbceSLemover 134*6d5ddbceSLemover when (ptwResp_valid) { 135*6d5ddbceSLemover vpn.zip(v).map{case (pi, vi) => 136*6d5ddbceSLemover when (vi && ptwResp.entry.hit(pi, allType = true)) { vi := false.B } 137*6d5ddbceSLemover } 138*6d5ddbceSLemover } 139*6d5ddbceSLemover 140*6d5ddbceSLemover counter := counter - do_deq + Mux(do_enq, enqNum, 0.U) 141*6d5ddbceSLemover assert(counter <= Size.U, "counter should be less than Size") 142*6d5ddbceSLemover when (counter === 0.U) { 143*6d5ddbceSLemover assert(!io.ptw.req(0).fire(), "when counter is 0, should not req") 144*6d5ddbceSLemover assert(isEmptyDeq && isEmptyIss, "when counter is 0, should be empty") 145*6d5ddbceSLemover } 146*6d5ddbceSLemover when (counter === Size.U) { 147*6d5ddbceSLemover assert(mayFullDeq, "when counter is Size, should be full") 148*6d5ddbceSLemover } 149*6d5ddbceSLemover 150*6d5ddbceSLemover when (sfence.valid) { 151*6d5ddbceSLemover v.map(_ := false.B) 152*6d5ddbceSLemover deqPtr := 0.U 153*6d5ddbceSLemover enqPtr := 0.U 154*6d5ddbceSLemover issPtr := 0.U 155*6d5ddbceSLemover ptwResp_valid := false.B 156*6d5ddbceSLemover mayFullDeq := false.B 157*6d5ddbceSLemover mayFullIss := false.B 158*6d5ddbceSLemover counter := 0.U 159*6d5ddbceSLemover } 160*6d5ddbceSLemover 161*6d5ddbceSLemover def canMerge(vpnReq: UInt, reqs: Seq[DecoupledIO[PtwReq]], index: Int) : Bool = { 162*6d5ddbceSLemover Cat((vpn ++ reqs.take(index).map(_.bits.vpn)) 163*6d5ddbceSLemover .zip(v ++ reqs.take(index).map(_.valid)) 164*6d5ddbceSLemover .map{case (pi, vi) => vi && pi === vpnReq} 165*6d5ddbceSLemover ).orR || (ptwResp_valid && ptwResp.entry.hit(vpnReq)) 166*6d5ddbceSLemover } 167*6d5ddbceSLemover 168*6d5ddbceSLemover def filter(tlbReq: Vec[DecoupledIO[PtwReq]]) = { 169*6d5ddbceSLemover val reqs = tlbReq.indices.map{ i => 170*6d5ddbceSLemover val req = Wire(ValidIO(new PtwReq())) 171*6d5ddbceSLemover req.bits := tlbReq(i).bits 172*6d5ddbceSLemover req.valid := !canMerge(tlbReq(i).bits.vpn, tlbReq, i) && tlbReq(i).valid 173*6d5ddbceSLemover req 174*6d5ddbceSLemover } 175*6d5ddbceSLemover reqs 176*6d5ddbceSLemover } 177*6d5ddbceSLemover 178*6d5ddbceSLemover // perf 179*6d5ddbceSLemover val inflight_counter = RegInit(0.U(log2Up(Size + 1).W)) 180*6d5ddbceSLemover when (io.ptw.req(0).fire() =/= io.ptw.resp.fire()) { 181*6d5ddbceSLemover inflight_counter := Mux(io.ptw.req(0).fire(), inflight_counter + 1.U, inflight_counter - 1.U) 182*6d5ddbceSLemover } 183*6d5ddbceSLemover when (sfence.valid) { 184*6d5ddbceSLemover inflight_counter := 0.U 185*6d5ddbceSLemover } 186*6d5ddbceSLemover XSPerfAccumulate("tlb_req_count", PopCount(Cat(io.tlb.req.map(_.valid)))) 187*6d5ddbceSLemover XSPerfAccumulate("tlb_req_count_filtered", Mux(do_enq, accumEnqNum(Width - 1), 0.U)) 188*6d5ddbceSLemover XSPerfAccumulate("ptw_req_count", io.ptw.req(0).fire()) 189*6d5ddbceSLemover XSPerfAccumulate("ptw_req_cycle", inflight_counter) 190*6d5ddbceSLemover XSPerfAccumulate("tlb_resp_count", io.tlb.resp.fire()) 191*6d5ddbceSLemover XSPerfAccumulate("ptw_resp_count", io.ptw.resp.fire()) 192*6d5ddbceSLemover XSPerfAccumulate("inflight_cycle", !isEmptyDeq) 193*6d5ddbceSLemover for (i <- 0 until Size + 1) { 194*6d5ddbceSLemover XSPerfAccumulate(s"counter${i}", counter === i.U) 195*6d5ddbceSLemover } 196*6d5ddbceSLemover}