192e3bfefSLemover/*************************************************************************************** 292e3bfefSLemover* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences 392e3bfefSLemover* Copyright (c) 2020-2021 Peng Cheng Laboratory 492e3bfefSLemover* 592e3bfefSLemover* XiangShan is licensed under Mulan PSL v2. 692e3bfefSLemover* You can use this software according to the terms and conditions of the Mulan PSL v2. 792e3bfefSLemover* You may obtain a copy of Mulan PSL v2 at: 892e3bfefSLemover* http://license.coscl.org.cn/MulanPSL2 992e3bfefSLemover* 1092e3bfefSLemover* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 1192e3bfefSLemover* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 1292e3bfefSLemover* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 1392e3bfefSLemover* 1492e3bfefSLemover* See the Mulan PSL v2 for more details. 1592e3bfefSLemover***************************************************************************************/ 1692e3bfefSLemover 1792e3bfefSLemoverpackage xiangshan.cache.mmu 1892e3bfefSLemover 1992e3bfefSLemoverimport chipsalliance.rocketchip.config.Parameters 2092e3bfefSLemoverimport chisel3._ 2192e3bfefSLemoverimport chisel3.experimental.ExtModule 2292e3bfefSLemoverimport chisel3.util._ 2392e3bfefSLemoverimport chisel3.internal.naming.chiselName 2492e3bfefSLemoverimport xiangshan._ 2592e3bfefSLemoverimport xiangshan.cache.{HasDCacheParameters, MemoryOpConstants} 2692e3bfefSLemoverimport utils._ 273c02ee8fSwakafaimport utility._ 2892e3bfefSLemoverimport freechips.rocketchip.diplomacy.{IdRange, LazyModule, LazyModuleImp} 2992e3bfefSLemoverimport freechips.rocketchip.tilelink._ 3092e3bfefSLemoverimport xiangshan.backend.fu.{PMP, PMPChecker, PMPReqBundle, PMPRespBundle} 3192e3bfefSLemoverimport xiangshan.backend.fu.util.HasCSRConst 323c02ee8fSwakafaimport utility.ChiselDB 339c26bab7SHaoyuan Fengimport difftest._ 3492e3bfefSLemover 3592e3bfefSLemoverclass L2TLB()(implicit p: Parameters) extends LazyModule with HasPtwConst { 3692e3bfefSLemover 3792e3bfefSLemover val node = TLClientNode(Seq(TLMasterPortParameters.v1( 3892e3bfefSLemover clients = Seq(TLMasterParameters.v1( 3992e3bfefSLemover "ptw", 4092e3bfefSLemover sourceId = IdRange(0, MemReqWidth) 4192e3bfefSLemover )) 4292e3bfefSLemover ))) 4392e3bfefSLemover 4492e3bfefSLemover lazy val module = new L2TLBImp(this) 4592e3bfefSLemover} 4692e3bfefSLemover 4792e3bfefSLemover@chiselName 4892e3bfefSLemoverclass L2TLBImp(outer: L2TLB)(implicit p: Parameters) extends PtwModule(outer) with HasCSRConst with HasPerfEvents { 4992e3bfefSLemover 5092e3bfefSLemover val (mem, edge) = outer.node.out.head 5192e3bfefSLemover 5292e3bfefSLemover val io = IO(new L2TLBIO) 5392e3bfefSLemover val difftestIO = IO(new Bundle() { 5492e3bfefSLemover val ptwResp = Output(Bool()) 5592e3bfefSLemover val ptwAddr = Output(UInt(64.W)) 5692e3bfefSLemover val ptwData = Output(Vec(4, UInt(64.W))) 5792e3bfefSLemover }) 5892e3bfefSLemover 5992e3bfefSLemover /* Ptw processes multiple requests 6092e3bfefSLemover * Divide Ptw procedure into two stages: cache access ; mem access if cache miss 6192e3bfefSLemover * miss queue itlb dtlb 6292e3bfefSLemover * | | | 6392e3bfefSLemover * ------arbiter------ 6492e3bfefSLemover * | 6592e3bfefSLemover * l1 - l2 - l3 - sp 6692e3bfefSLemover * | 6792e3bfefSLemover * ------------------------------------------- 6892e3bfefSLemover * miss | queue | hit 6992e3bfefSLemover * [][][][][][] | 7092e3bfefSLemover * | | 7192e3bfefSLemover * state machine accessing mem | 7292e3bfefSLemover * | | 7392e3bfefSLemover * ---------------arbiter--------------------- 7492e3bfefSLemover * | | 7592e3bfefSLemover * itlb dtlb 7692e3bfefSLemover */ 7792e3bfefSLemover 7892e3bfefSLemover difftestIO <> DontCare 7992e3bfefSLemover 807797f035SbugGenerator val sfence_tmp = DelayN(io.sfence, 1) 817797f035SbugGenerator val csr_tmp = DelayN(io.csr.tlb, 1) 827797f035SbugGenerator val sfence_dup = Seq.fill(8)(RegNext(sfence_tmp)) 837797f035SbugGenerator val csr_dup = Seq.fill(7)(RegNext(csr_tmp)) 847797f035SbugGenerator val satp = csr_dup(0).satp 857797f035SbugGenerator val priv = csr_dup(0).priv 867797f035SbugGenerator val flush = sfence_dup(0).valid || satp.changed 8792e3bfefSLemover 8892e3bfefSLemover val pmp = Module(new PMP()) 8992e3bfefSLemover val pmp_check = VecInit(Seq.fill(2)(Module(new PMPChecker(lgMaxSize = 3, sameCycle = true)).io)) 9092e3bfefSLemover pmp.io.distribute_csr := io.csr.distribute_csr 9192e3bfefSLemover pmp_check.foreach(_.check_env.apply(ModeS, pmp.io.pmp, pmp.io.pma)) 9292e3bfefSLemover 9392e3bfefSLemover val missQueue = Module(new L2TlbMissQueue) 9492e3bfefSLemover val cache = Module(new PtwCache) 9592e3bfefSLemover val ptw = Module(new PTW) 9692e3bfefSLemover val llptw = Module(new LLPTW) 977797f035SbugGenerator val blockmq = Module(new BlockHelper(3)) 9892e3bfefSLemover val arb1 = Module(new Arbiter(new PtwReq, PtwWidth)) 9992e3bfefSLemover val arb2 = Module(new Arbiter(new Bundle { 10092e3bfefSLemover val vpn = UInt(vpnLen.W) 10192e3bfefSLemover val source = UInt(bSourceWidth.W) 1029c503409SLemover }, if (l2tlbParams.enablePrefetch) 4 else 3)) 103*63632028SHaoyuan Feng val outArb = (0 until PtwWidth).map(i => Module(new Arbiter(new PtwSectorResp, 1)).io) 104*63632028SHaoyuan Feng val mergeArb = (0 until PtwWidth).map(i => Module(new Arbiter(new PtwMergeResp, 3)).io) 10592e3bfefSLemover val outArbCachePort = 0 10692e3bfefSLemover val outArbFsmPort = 1 10792e3bfefSLemover val outArbMqPort = 2 10892e3bfefSLemover 1099c503409SLemover // arb2 input port 1109c503409SLemover val InArbPTWPort = 0 1119c503409SLemover val InArbMissQueuePort = 1 1129c503409SLemover val InArbTlbPort = 2 1139c503409SLemover val InArbPrefetchPort = 3 11492e3bfefSLemover // NOTE: when cache out but miss and ptw doesnt accept, 11592e3bfefSLemover arb1.io.in <> VecInit(io.tlb.map(_.req(0))) 1169c503409SLemover arb1.io.out.ready := arb2.io.in(InArbTlbPort).ready 11792e3bfefSLemover 1189c503409SLemover arb2.io.in(InArbPTWPort).valid := ptw.io.llptw.valid 1199c503409SLemover arb2.io.in(InArbPTWPort).bits.vpn := ptw.io.llptw.bits.req_info.vpn 1209c503409SLemover arb2.io.in(InArbPTWPort).bits.source := ptw.io.llptw.bits.req_info.source 1219c503409SLemover ptw.io.llptw.ready := arb2.io.in(InArbPTWPort).ready 12292e3bfefSLemover block_decoupled(missQueue.io.out, arb2.io.in(InArbMissQueuePort), !ptw.io.req.ready) 1237797f035SbugGenerator 12492e3bfefSLemover arb2.io.in(InArbTlbPort).valid := arb1.io.out.valid 12592e3bfefSLemover arb2.io.in(InArbTlbPort).bits.vpn := arb1.io.out.bits.vpn 12692e3bfefSLemover arb2.io.in(InArbTlbPort).bits.source := arb1.io.chosen 12792e3bfefSLemover if (l2tlbParams.enablePrefetch) { 12892e3bfefSLemover val prefetch = Module(new L2TlbPrefetch()) 12992e3bfefSLemover val recv = cache.io.resp 13092e3bfefSLemover // NOTE: 1. prefetch doesn't gen prefetch 2. req from mq doesn't gen prefetch 13192e3bfefSLemover // NOTE: 1. miss req gen prefetch 2. hit but prefetched gen prefetch 13292e3bfefSLemover prefetch.io.in.valid := recv.fire() && !from_pre(recv.bits.req_info.source) && (!recv.bits.hit || 13392e3bfefSLemover recv.bits.prefetch) && recv.bits.isFirst 13492e3bfefSLemover prefetch.io.in.bits.vpn := recv.bits.req_info.vpn 1357797f035SbugGenerator prefetch.io.sfence := sfence_dup(0) 1367797f035SbugGenerator prefetch.io.csr := csr_dup(0) 13792e3bfefSLemover arb2.io.in(InArbPrefetchPort) <> prefetch.io.out 1385afdf73cSHaoyuan Feng 1395afdf73cSHaoyuan Feng val L2TlbPrefetchTable = ChiselDB.createTable("L2TlbPrefetch_hart" + p(XSCoreParamsKey).HartId.toString, new L2TlbPrefetchDB) 1405afdf73cSHaoyuan Feng val L2TlbPrefetchDB = Wire(new L2TlbPrefetchDB) 1415afdf73cSHaoyuan Feng L2TlbPrefetchDB.vpn := prefetch.io.out.bits.vpn 1425afdf73cSHaoyuan Feng L2TlbPrefetchTable.log(L2TlbPrefetchDB, prefetch.io.out.fire, "L2TlbPrefetch", clock, reset) 14392e3bfefSLemover } 14492e3bfefSLemover arb2.io.out.ready := cache.io.req.ready 14592e3bfefSLemover 1467797f035SbugGenerator 1477797f035SbugGenerator val mq_arb = Module(new Arbiter(new L2TlbInnerBundle, 2)) 1487797f035SbugGenerator mq_arb.io.in(0).valid := cache.io.resp.valid && !cache.io.resp.bits.hit && 1497797f035SbugGenerator (!cache.io.resp.bits.toFsm.l2Hit || cache.io.resp.bits.bypassed) && 1507797f035SbugGenerator !from_pre(cache.io.resp.bits.req_info.source) && 1517797f035SbugGenerator (cache.io.resp.bits.bypassed || cache.io.resp.bits.isFirst || !ptw.io.req.ready) 1527797f035SbugGenerator mq_arb.io.in(0).bits := cache.io.resp.bits.req_info 1537797f035SbugGenerator mq_arb.io.in(1) <> llptw.io.cache 1547797f035SbugGenerator missQueue.io.in <> mq_arb.io.out 1557797f035SbugGenerator missQueue.io.sfence := sfence_dup(6) 1567797f035SbugGenerator missQueue.io.csr := csr_dup(5) 1577797f035SbugGenerator 1587797f035SbugGenerator blockmq.io.start := missQueue.io.out.fire 1597797f035SbugGenerator blockmq.io.enable := ptw.io.req.fire() 1607797f035SbugGenerator 1619c503409SLemover llptw.io.in.valid := cache.io.resp.valid && !cache.io.resp.bits.hit && cache.io.resp.bits.toFsm.l2Hit && !cache.io.resp.bits.bypassed 1629c503409SLemover llptw.io.in.bits.req_info := cache.io.resp.bits.req_info 1639c503409SLemover llptw.io.in.bits.ppn := cache.io.resp.bits.toFsm.ppn 1647797f035SbugGenerator llptw.io.sfence := sfence_dup(1) 1657797f035SbugGenerator llptw.io.csr := csr_dup(1) 16692e3bfefSLemover 16792e3bfefSLemover cache.io.req.valid := arb2.io.out.valid 16892e3bfefSLemover cache.io.req.bits.req_info.vpn := arb2.io.out.bits.vpn 16992e3bfefSLemover cache.io.req.bits.req_info.source := arb2.io.out.bits.source 17092e3bfefSLemover cache.io.req.bits.isFirst := arb2.io.chosen =/= InArbMissQueuePort.U 1711f4a7c0cSLemover cache.io.req.bits.bypassed.map(_ := false.B) 1727797f035SbugGenerator cache.io.sfence := sfence_dup(2) 1737797f035SbugGenerator cache.io.csr := csr_dup(2) 1747797f035SbugGenerator cache.io.sfence_dup.zip(sfence_dup.drop(2).take(4)).map(s => s._1 := s._2) 1757797f035SbugGenerator cache.io.csr_dup.zip(csr_dup.drop(2).take(3)).map(c => c._1 := c._2) 17692e3bfefSLemover cache.io.resp.ready := Mux(cache.io.resp.bits.hit, 17792e3bfefSLemover outReady(cache.io.resp.bits.req_info.source, outArbCachePort), 1789c503409SLemover Mux(cache.io.resp.bits.toFsm.l2Hit && !cache.io.resp.bits.bypassed, llptw.io.in.ready, 1797797f035SbugGenerator Mux(cache.io.resp.bits.bypassed || cache.io.resp.bits.isFirst, mq_arb.io.in(0).ready, mq_arb.io.in(0).ready || ptw.io.req.ready))) 18092e3bfefSLemover 18192e3bfefSLemover // NOTE: missQueue req has higher priority 1827797f035SbugGenerator ptw.io.req.valid := cache.io.resp.valid && !cache.io.resp.bits.hit && !cache.io.resp.bits.toFsm.l2Hit && 1837797f035SbugGenerator !cache.io.resp.bits.bypassed && 1847797f035SbugGenerator !cache.io.resp.bits.isFirst 18592e3bfefSLemover ptw.io.req.bits.req_info := cache.io.resp.bits.req_info 18692e3bfefSLemover ptw.io.req.bits.l1Hit := cache.io.resp.bits.toFsm.l1Hit 18792e3bfefSLemover ptw.io.req.bits.ppn := cache.io.resp.bits.toFsm.ppn 1887797f035SbugGenerator ptw.io.sfence := sfence_dup(7) 1897797f035SbugGenerator ptw.io.csr := csr_dup(6) 19092e3bfefSLemover ptw.io.resp.ready := outReady(ptw.io.resp.bits.source, outArbFsmPort) 19192e3bfefSLemover 19292e3bfefSLemover // mem req 19392e3bfefSLemover def blockBytes_align(addr: UInt) = { 19492e3bfefSLemover Cat(addr(PAddrBits - 1, log2Up(l2tlbParams.blockBytes)), 0.U(log2Up(l2tlbParams.blockBytes).W)) 19592e3bfefSLemover } 19692e3bfefSLemover def addr_low_from_vpn(vpn: UInt) = { 19792e3bfefSLemover vpn(log2Ceil(l2tlbParams.blockBytes)-log2Ceil(XLEN/8)-1, 0) 19892e3bfefSLemover } 19992e3bfefSLemover def addr_low_from_paddr(paddr: UInt) = { 20092e3bfefSLemover paddr(log2Up(l2tlbParams.blockBytes)-1, log2Up(XLEN/8)) 20192e3bfefSLemover } 20292e3bfefSLemover def from_missqueue(id: UInt) = { 20392e3bfefSLemover (id =/= l2tlbParams.llptwsize.U) 20492e3bfefSLemover } 20592e3bfefSLemover val waiting_resp = RegInit(VecInit(Seq.fill(MemReqWidth)(false.B))) 20692e3bfefSLemover val flush_latch = RegInit(VecInit(Seq.fill(MemReqWidth)(false.B))) 20792e3bfefSLemover for (i <- waiting_resp.indices) { 20892e3bfefSLemover assert(!flush_latch(i) || waiting_resp(i)) // when sfence_latch wait for mem resp, waiting_resp should be true 20992e3bfefSLemover } 21092e3bfefSLemover 21192e3bfefSLemover val llptw_out = llptw.io.out 21292e3bfefSLemover val llptw_mem = llptw.io.mem 21392e3bfefSLemover llptw_mem.req_mask := waiting_resp.take(l2tlbParams.llptwsize) 21492e3bfefSLemover ptw.io.mem.mask := waiting_resp.last 21592e3bfefSLemover 21692e3bfefSLemover val mem_arb = Module(new Arbiter(new L2TlbMemReqBundle(), 2)) 21792e3bfefSLemover mem_arb.io.in(0) <> ptw.io.mem.req 21892e3bfefSLemover mem_arb.io.in(1) <> llptw_mem.req 21992e3bfefSLemover mem_arb.io.out.ready := mem.a.ready && !flush 22092e3bfefSLemover 2211f4a7c0cSLemover // assert, should not send mem access at same addr for twice. 2227797f035SbugGenerator val last_resp_vpn = RegEnable(cache.io.refill.bits.req_info_dup(0).vpn, cache.io.refill.valid) 2237797f035SbugGenerator val last_resp_level = RegEnable(cache.io.refill.bits.level_dup(0), cache.io.refill.valid) 2241f4a7c0cSLemover val last_resp_v = RegInit(false.B) 225dd7fe201SHaoyuan Feng val last_has_invalid = !Cat(cache.io.refill.bits.ptes.asTypeOf(Vec(blockBits/XLEN, UInt(XLEN.W))).map(a => a(0))).andR || cache.io.refill.bits.sel_pte_dup(0).asTypeOf(new PteBundle).isAf() 2261f4a7c0cSLemover when (cache.io.refill.valid) { last_resp_v := !last_has_invalid} 2271f4a7c0cSLemover when (flush) { last_resp_v := false.B } 2281f4a7c0cSLemover XSError(last_resp_v && cache.io.refill.valid && 2297797f035SbugGenerator (cache.io.refill.bits.req_info_dup(0).vpn === last_resp_vpn) && 2307797f035SbugGenerator (cache.io.refill.bits.level_dup(0) === last_resp_level), 2311f4a7c0cSLemover "l2tlb should not access mem at same addr for twice") 2321f4a7c0cSLemover // ATTENTION: this may wronngly assert when: a ptes is l2, last part is valid, 2331f4a7c0cSLemover // but the current part is invalid, so one more mem access happened 2341f4a7c0cSLemover // If this happened, remove the assert. 2351f4a7c0cSLemover 23692e3bfefSLemover val req_addr_low = Reg(Vec(MemReqWidth, UInt((log2Up(l2tlbParams.blockBytes)-log2Up(XLEN/8)).W))) 23792e3bfefSLemover 23892e3bfefSLemover when (llptw.io.in.fire()) { 23992e3bfefSLemover // when enq miss queue, set the req_addr_low to receive the mem resp data part 24092e3bfefSLemover req_addr_low(llptw_mem.enq_ptr) := addr_low_from_vpn(llptw.io.in.bits.req_info.vpn) 24192e3bfefSLemover } 24292e3bfefSLemover when (mem_arb.io.out.fire()) { 24392e3bfefSLemover req_addr_low(mem_arb.io.out.bits.id) := addr_low_from_paddr(mem_arb.io.out.bits.addr) 24492e3bfefSLemover waiting_resp(mem_arb.io.out.bits.id) := true.B 24592e3bfefSLemover } 24692e3bfefSLemover // mem read 24792e3bfefSLemover val memRead = edge.Get( 24892e3bfefSLemover fromSource = mem_arb.io.out.bits.id, 24992e3bfefSLemover // toAddress = memAddr(log2Up(CacheLineSize / 2 / 8) - 1, 0), 25092e3bfefSLemover toAddress = blockBytes_align(mem_arb.io.out.bits.addr), 25192e3bfefSLemover lgSize = log2Up(l2tlbParams.blockBytes).U 25292e3bfefSLemover )._2 25392e3bfefSLemover mem.a.bits := memRead 25492e3bfefSLemover mem.a.valid := mem_arb.io.out.valid && !flush 25592e3bfefSLemover mem.d.ready := true.B 25692e3bfefSLemover // mem -> data buffer 25792e3bfefSLemover val refill_data = Reg(Vec(blockBits / l1BusDataWidth, UInt(l1BusDataWidth.W))) 25892e3bfefSLemover val refill_helper = edge.firstlastHelper(mem.d.bits, mem.d.fire()) 25992e3bfefSLemover val mem_resp_done = refill_helper._3 26092e3bfefSLemover val mem_resp_from_mq = from_missqueue(mem.d.bits.source) 26192e3bfefSLemover when (mem.d.valid) { 26292e3bfefSLemover assert(mem.d.bits.source <= l2tlbParams.llptwsize.U) 26392e3bfefSLemover refill_data(refill_helper._4) := mem.d.bits.data 26492e3bfefSLemover } 2657797f035SbugGenerator // refill_data_tmp is the wire fork of refill_data, but one cycle earlier 2667797f035SbugGenerator val refill_data_tmp = WireInit(refill_data) 2677797f035SbugGenerator refill_data_tmp(refill_helper._4) := mem.d.bits.data 2687797f035SbugGenerator 26992e3bfefSLemover // save only one pte for each id 27092e3bfefSLemover // (miss queue may can't resp to tlb with low latency, it should have highest priority, but diffcult to design cache) 27192e3bfefSLemover val resp_pte = VecInit((0 until MemReqWidth).map(i => 2727797f035SbugGenerator if (i == l2tlbParams.llptwsize) {RegEnable(get_part(refill_data_tmp, req_addr_low(i)), mem_resp_done && !mem_resp_from_mq) } 27392e3bfefSLemover else { DataHoldBypass(get_part(refill_data, req_addr_low(i)), llptw_mem.buffer_it(i)) } 2747797f035SbugGenerator // llptw could not use refill_data_tmp, because enq bypass's result works at next cycle 27592e3bfefSLemover )) 27692e3bfefSLemover 277*63632028SHaoyuan Feng // save eight ptes for each id when sector tlb 278*63632028SHaoyuan Feng // (miss queue may can't resp to tlb with low latency, it should have highest priority, but diffcult to design cache) 279*63632028SHaoyuan Feng val resp_pte_sector = VecInit((0 until MemReqWidth).map(i => 280*63632028SHaoyuan Feng if (i == l2tlbParams.llptwsize) {RegEnable(refill_data_tmp, mem_resp_done && !mem_resp_from_mq) } 281*63632028SHaoyuan Feng else { DataHoldBypass(refill_data, llptw_mem.buffer_it(i)) } 282*63632028SHaoyuan Feng // llptw could not use refill_data_tmp, because enq bypass's result works at next cycle 283*63632028SHaoyuan Feng )) 284*63632028SHaoyuan Feng 28592e3bfefSLemover // mem -> miss queue 28692e3bfefSLemover llptw_mem.resp.valid := mem_resp_done && mem_resp_from_mq 2877797f035SbugGenerator llptw_mem.resp.bits.id := DataHoldBypass(mem.d.bits.source, mem.d.valid) 28892e3bfefSLemover // mem -> ptw 28992e3bfefSLemover ptw.io.mem.req.ready := mem.a.ready 29092e3bfefSLemover ptw.io.mem.resp.valid := mem_resp_done && !mem_resp_from_mq 29192e3bfefSLemover ptw.io.mem.resp.bits := resp_pte.last 29292e3bfefSLemover // mem -> cache 2937797f035SbugGenerator val refill_from_mq = mem_resp_from_mq 2947797f035SbugGenerator val refill_level = Mux(refill_from_mq, 2.U, RegEnable(ptw.io.refill.level, init = 0.U, ptw.io.mem.req.fire())) 2957797f035SbugGenerator val refill_valid = mem_resp_done && !flush && !flush_latch(mem.d.bits.source) 2967797f035SbugGenerator 2977797f035SbugGenerator cache.io.refill.valid := RegNext(refill_valid, false.B) 29892e3bfefSLemover cache.io.refill.bits.ptes := refill_data.asUInt 2997797f035SbugGenerator cache.io.refill.bits.req_info_dup.map(_ := RegEnable(Mux(refill_from_mq, llptw_mem.refill, ptw.io.refill.req_info), refill_valid)) 3007797f035SbugGenerator cache.io.refill.bits.level_dup.map(_ := RegEnable(refill_level, refill_valid)) 3017797f035SbugGenerator cache.io.refill.bits.levelOH(refill_level, refill_valid) 3027797f035SbugGenerator cache.io.refill.bits.sel_pte_dup.map(_ := RegNext(sel_data(refill_data_tmp.asUInt, req_addr_low(mem.d.bits.source)))) 30392e3bfefSLemover 3049c26bab7SHaoyuan Feng if (env.EnableDifftest) { 3059c26bab7SHaoyuan Feng val difftest_ptw_addr = RegInit(VecInit(Seq.fill(MemReqWidth)(0.U(PAddrBits.W)))) 3069c26bab7SHaoyuan Feng when (mem.a.valid) { 3079c26bab7SHaoyuan Feng difftest_ptw_addr(mem.a.bits.source) := mem.a.bits.address 3089c26bab7SHaoyuan Feng } 3099c26bab7SHaoyuan Feng 3109c26bab7SHaoyuan Feng val difftest = Module(new DifftestRefillEvent) 3119c26bab7SHaoyuan Feng difftest.io.clock := clock 3129c26bab7SHaoyuan Feng difftest.io.coreid := p(XSCoreParamsKey).HartId.asUInt 3139c26bab7SHaoyuan Feng difftest.io.cacheid := 2.U 3149c26bab7SHaoyuan Feng difftest.io.valid := cache.io.refill.valid 3159c26bab7SHaoyuan Feng difftest.io.addr := difftest_ptw_addr(RegNext(mem.d.bits.source)) 3169c26bab7SHaoyuan Feng difftest.io.data := refill_data.asTypeOf(difftest.io.data) 3179c26bab7SHaoyuan Feng } 3189c26bab7SHaoyuan Feng 3195ab1b84dSHaoyuan Feng if (env.EnableDifftest) { 3205ab1b84dSHaoyuan Feng for (i <- 0 until PtwWidth) { 3215ab1b84dSHaoyuan Feng val difftest = Module(new DifftestL2TLBEvent) 3225ab1b84dSHaoyuan Feng difftest.io.clock := clock 3235ab1b84dSHaoyuan Feng difftest.io.coreid := p(XSCoreParamsKey).HartId.asUInt 3245ab1b84dSHaoyuan Feng difftest.io.valid := io.tlb(i).resp.fire && !io.tlb(i).resp.bits.af 3255ab1b84dSHaoyuan Feng difftest.io.index := i.U 3265ab1b84dSHaoyuan Feng difftest.io.satp := io.csr.tlb.satp.ppn 327*63632028SHaoyuan Feng difftest.io.vpn := Cat(io.tlb(i).resp.bits.entry.tag, 0.U(sectortlbwidth.W)) 328*63632028SHaoyuan Feng for (j <- 0 until tlbcontiguous) { 329*63632028SHaoyuan Feng difftest.io.ppn(j) := Cat(io.tlb(i).resp.bits.entry.ppn, io.tlb(i).resp.bits.ppn_low(j)) 330*63632028SHaoyuan Feng difftest.io.valididx(j) := io.tlb(i).resp.bits.valididx(j) 331*63632028SHaoyuan Feng } 3325ab1b84dSHaoyuan Feng difftest.io.perm := io.tlb(i).resp.bits.entry.perm.getOrElse(0.U.asTypeOf(new PtePermBundle)).asUInt 3335ab1b84dSHaoyuan Feng difftest.io.level := io.tlb(i).resp.bits.entry.level.getOrElse(0.U.asUInt) 3345ab1b84dSHaoyuan Feng difftest.io.pf := io.tlb(i).resp.bits.pf 3355ab1b84dSHaoyuan Feng } 3365ab1b84dSHaoyuan Feng } 3375ab1b84dSHaoyuan Feng 33892e3bfefSLemover // pmp 33992e3bfefSLemover pmp_check(0).req <> ptw.io.pmp.req 34092e3bfefSLemover ptw.io.pmp.resp <> pmp_check(0).resp 34192e3bfefSLemover pmp_check(1).req <> llptw.io.pmp.req 34292e3bfefSLemover llptw.io.pmp.resp <> pmp_check(1).resp 34392e3bfefSLemover 34492e3bfefSLemover llptw_out.ready := outReady(llptw_out.bits.req_info.source, outArbMqPort) 345*63632028SHaoyuan Feng 346*63632028SHaoyuan Feng // Timing: Maybe need to do some optimization or even add one more cycle 34792e3bfefSLemover for (i <- 0 until PtwWidth) { 348*63632028SHaoyuan Feng mergeArb(i).in(outArbCachePort).valid := cache.io.resp.valid && cache.io.resp.bits.hit && cache.io.resp.bits.req_info.source===i.U 349*63632028SHaoyuan Feng mergeArb(i).in(outArbCachePort).bits := cache.io.resp.bits.toTlb 350*63632028SHaoyuan Feng mergeArb(i).in(outArbFsmPort).valid := ptw.io.resp.valid && ptw.io.resp.bits.source===i.U 351*63632028SHaoyuan Feng mergeArb(i).in(outArbFsmPort).bits := ptw.io.resp.bits.resp 352*63632028SHaoyuan Feng mergeArb(i).in(outArbMqPort).valid := llptw_out.valid && llptw_out.bits.req_info.source===i.U 353*63632028SHaoyuan Feng mergeArb(i).in(outArbMqPort).bits := contiguous_pte_to_merge_ptwResp(resp_pte_sector(llptw_out.bits.id).asUInt, llptw_out.bits.req_info.vpn, llptw_out.bits.af, true) 354*63632028SHaoyuan Feng mergeArb(i).out.ready := outArb(i).in(0).ready 355*63632028SHaoyuan Feng } 356*63632028SHaoyuan Feng 357*63632028SHaoyuan Feng for (i <- 0 until PtwWidth) { 358*63632028SHaoyuan Feng outArb(i).in(0).valid := mergeArb(i).out.valid 359*63632028SHaoyuan Feng outArb(i).in(0).bits := merge_ptwResp_to_sector_ptwResp(mergeArb(i).out.bits) 36092e3bfefSLemover } 36192e3bfefSLemover 36292e3bfefSLemover // io.tlb.map(_.resp) <> outArb.map(_.out) 36392e3bfefSLemover io.tlb.map(_.resp).zip(outArb.map(_.out)).map{ 36492e3bfefSLemover case (resp, out) => resp <> out 36592e3bfefSLemover } 36692e3bfefSLemover 36792e3bfefSLemover // sfence 36892e3bfefSLemover when (flush) { 36992e3bfefSLemover for (i <- 0 until MemReqWidth) { 37092e3bfefSLemover when (waiting_resp(i)) { 37192e3bfefSLemover flush_latch(i) := true.B 37292e3bfefSLemover } 37392e3bfefSLemover } 37492e3bfefSLemover } 37592e3bfefSLemover // mem -> control signal 37692e3bfefSLemover // waiting_resp and sfence_latch will be reset when mem_resp_done 37792e3bfefSLemover when (mem_resp_done) { 37892e3bfefSLemover waiting_resp(mem.d.bits.source) := false.B 37992e3bfefSLemover flush_latch(mem.d.bits.source) := false.B 38092e3bfefSLemover } 38192e3bfefSLemover 38292e3bfefSLemover def block_decoupled[T <: Data](source: DecoupledIO[T], sink: DecoupledIO[T], block_signal: Bool) = { 38392e3bfefSLemover sink.valid := source.valid && !block_signal 38492e3bfefSLemover source.ready := sink.ready && !block_signal 38592e3bfefSLemover sink.bits := source.bits 38692e3bfefSLemover } 38792e3bfefSLemover 38892e3bfefSLemover def get_part(data: Vec[UInt], index: UInt): UInt = { 38992e3bfefSLemover val inner_data = data.asTypeOf(Vec(data.getWidth / XLEN, UInt(XLEN.W))) 39092e3bfefSLemover inner_data(index) 39192e3bfefSLemover } 39292e3bfefSLemover 39392e3bfefSLemover def pte_to_ptwResp(pte: UInt, vpn: UInt, af: Bool, af_first: Boolean) : PtwResp = { 39492e3bfefSLemover val pte_in = pte.asTypeOf(new PteBundle()) 39592e3bfefSLemover val ptw_resp = Wire(new PtwResp()) 39692e3bfefSLemover ptw_resp.entry.ppn := pte_in.ppn 39792e3bfefSLemover ptw_resp.entry.level.map(_ := 2.U) 39892e3bfefSLemover ptw_resp.entry.perm.map(_ := pte_in.getPerm()) 39992e3bfefSLemover ptw_resp.entry.tag := vpn 40092e3bfefSLemover ptw_resp.pf := (if (af_first) !af else true.B) && pte_in.isPf(2.U) 4010d94d540SHaoyuan Feng ptw_resp.af := (if (!af_first) pte_in.isPf(2.U) else true.B) && (af || pte_in.isAf()) 40292e3bfefSLemover ptw_resp.entry.v := !ptw_resp.pf 40392e3bfefSLemover ptw_resp.entry.prefetch := DontCare 40492e3bfefSLemover ptw_resp.entry.asid := satp.asid 40592e3bfefSLemover ptw_resp 40692e3bfefSLemover } 40792e3bfefSLemover 408*63632028SHaoyuan Feng // not_super means that this is a normal page 409*63632028SHaoyuan Feng // valididx(i) will be all true when super page to be convenient for l1 tlb matching 410*63632028SHaoyuan Feng def contiguous_pte_to_merge_ptwResp(pte: UInt, vpn: UInt, af: Bool, af_first: Boolean, not_super: Boolean = true) : PtwMergeResp = { 411*63632028SHaoyuan Feng assert(tlbcontiguous == 8, "Only support tlbcontiguous = 8!") 412*63632028SHaoyuan Feng val ptw_merge_resp = Wire(new PtwMergeResp()) 413*63632028SHaoyuan Feng for (i <- 0 until tlbcontiguous) { 414*63632028SHaoyuan Feng val pte_in = pte(64 * i + 63, 64 * i).asTypeOf(new PteBundle()) 415*63632028SHaoyuan Feng val ptw_resp = Wire(new PtwMergeEntry(tagLen = sectorvpnLen, hasPerm = true, hasLevel = true)) 416*63632028SHaoyuan Feng ptw_resp.ppn := pte_in.ppn(ppnLen - 1, sectortlbwidth) 417*63632028SHaoyuan Feng ptw_resp.ppn_low := pte_in.ppn(sectortlbwidth - 1, 0) 418*63632028SHaoyuan Feng ptw_resp.level.map(_ := 2.U) 419*63632028SHaoyuan Feng ptw_resp.perm.map(_ := pte_in.getPerm()) 420*63632028SHaoyuan Feng ptw_resp.tag := vpn(vpnLen - 1, sectortlbwidth) 421*63632028SHaoyuan Feng ptw_resp.pf := (if (af_first) !af else true.B) && pte_in.isPf(2.U) 422*63632028SHaoyuan Feng ptw_resp.af := (if (!af_first) pte_in.isPf(2.U) else true.B) && (af || pte_in.isAf()) 423*63632028SHaoyuan Feng ptw_resp.v := !ptw_resp.pf 424*63632028SHaoyuan Feng ptw_resp.prefetch := DontCare 425*63632028SHaoyuan Feng ptw_resp.asid := satp.asid 426*63632028SHaoyuan Feng ptw_merge_resp.entry(i) := ptw_resp 427*63632028SHaoyuan Feng } 428*63632028SHaoyuan Feng ptw_merge_resp.pteidx := UIntToOH(vpn(sectortlbwidth - 1, 0)).asBools 429*63632028SHaoyuan Feng ptw_merge_resp.not_super := not_super.B 430*63632028SHaoyuan Feng ptw_merge_resp 431*63632028SHaoyuan Feng } 432*63632028SHaoyuan Feng 433*63632028SHaoyuan Feng def merge_ptwResp_to_sector_ptwResp(pte: PtwMergeResp) : PtwSectorResp = { 434*63632028SHaoyuan Feng assert(tlbcontiguous == 8, "Only support tlbcontiguous = 8!") 435*63632028SHaoyuan Feng val ptw_sector_resp = Wire(new PtwSectorResp) 436*63632028SHaoyuan Feng ptw_sector_resp.entry.tag := pte.entry(OHToUInt(pte.pteidx)).tag 437*63632028SHaoyuan Feng ptw_sector_resp.entry.asid := pte.entry(OHToUInt(pte.pteidx)).asid 438*63632028SHaoyuan Feng ptw_sector_resp.entry.ppn := pte.entry(OHToUInt(pte.pteidx)).ppn 439*63632028SHaoyuan Feng ptw_sector_resp.entry.perm.map(_ := pte.entry(OHToUInt(pte.pteidx)).perm.getOrElse(0.U.asTypeOf(new PtePermBundle))) 440*63632028SHaoyuan Feng ptw_sector_resp.entry.level.map(_ := pte.entry(OHToUInt(pte.pteidx)).level.getOrElse(0.U(2.W))) 441*63632028SHaoyuan Feng ptw_sector_resp.entry.prefetch := pte.entry(OHToUInt(pte.pteidx)).prefetch 442*63632028SHaoyuan Feng ptw_sector_resp.entry.v := pte.entry(OHToUInt(pte.pteidx)).v 443*63632028SHaoyuan Feng ptw_sector_resp.af := pte.entry(OHToUInt(pte.pteidx)).af 444*63632028SHaoyuan Feng ptw_sector_resp.pf := pte.entry(OHToUInt(pte.pteidx)).pf 445*63632028SHaoyuan Feng ptw_sector_resp.addr_low := OHToUInt(pte.pteidx) 446*63632028SHaoyuan Feng for (i <- 0 until tlbcontiguous) { 447*63632028SHaoyuan Feng val ppn_equal = pte.entry(i).ppn === pte.entry(OHToUInt(pte.pteidx)).ppn 448*63632028SHaoyuan Feng val perm_equal = pte.entry(i).perm.getOrElse(0.U.asTypeOf(new PtePermBundle)).asUInt === pte.entry(OHToUInt(pte.pteidx)).perm.getOrElse(0.U.asTypeOf(new PtePermBundle)).asUInt 449*63632028SHaoyuan Feng val v_equal = pte.entry(i).v === pte.entry(OHToUInt(pte.pteidx)).v 450*63632028SHaoyuan Feng val af_equal = pte.entry(i).af === pte.entry(OHToUInt(pte.pteidx)).af 451*63632028SHaoyuan Feng val pf_equal = pte.entry(i).pf === pte.entry(OHToUInt(pte.pteidx)).pf 452*63632028SHaoyuan Feng ptw_sector_resp.valididx(i) := (ppn_equal && perm_equal && v_equal && af_equal && pf_equal) || !pte.not_super 453*63632028SHaoyuan Feng ptw_sector_resp.ppn_low(i) := pte.entry(i).ppn_low 454*63632028SHaoyuan Feng } 455*63632028SHaoyuan Feng ptw_sector_resp.valididx(OHToUInt(pte.pteidx)) := true.B 456*63632028SHaoyuan Feng ptw_sector_resp 457*63632028SHaoyuan Feng } 458*63632028SHaoyuan Feng 45992e3bfefSLemover def outReady(source: UInt, port: Int): Bool = { 46092e3bfefSLemover MuxLookup(source, true.B, 461*63632028SHaoyuan Feng (0 until PtwWidth).map(i => i.U -> mergeArb(i).in(port).ready)) 46292e3bfefSLemover } 46392e3bfefSLemover 46492e3bfefSLemover // debug info 46592e3bfefSLemover for (i <- 0 until PtwWidth) { 46692e3bfefSLemover XSDebug(p"[io.tlb(${i.U})] ${io.tlb(i)}\n") 46792e3bfefSLemover } 4687797f035SbugGenerator XSDebug(p"[sfence] ${io.sfence}\n") 46992e3bfefSLemover XSDebug(p"[io.csr.tlb] ${io.csr.tlb}\n") 47092e3bfefSLemover 47192e3bfefSLemover for (i <- 0 until PtwWidth) { 47292e3bfefSLemover XSPerfAccumulate(s"req_count${i}", io.tlb(i).req(0).fire()) 47392e3bfefSLemover XSPerfAccumulate(s"req_blocked_count_${i}", io.tlb(i).req(0).valid && !io.tlb(i).req(0).ready) 47492e3bfefSLemover } 47592e3bfefSLemover XSPerfAccumulate(s"req_blocked_by_mq", arb1.io.out.valid && missQueue.io.out.valid) 47692e3bfefSLemover for (i <- 0 until (MemReqWidth + 1)) { 47792e3bfefSLemover XSPerfAccumulate(s"mem_req_util${i}", PopCount(waiting_resp) === i.U) 47892e3bfefSLemover } 47992e3bfefSLemover XSPerfAccumulate("mem_cycle", PopCount(waiting_resp) =/= 0.U) 48092e3bfefSLemover XSPerfAccumulate("mem_count", mem.a.fire()) 481dd7fe201SHaoyuan Feng for (i <- 0 until PtwWidth) { 482*63632028SHaoyuan Feng XSPerfAccumulate(s"llptw_ppn_af${i}", mergeArb(i).in(outArbMqPort).valid && mergeArb(i).in(outArbMqPort).bits.entry(OHToUInt(mergeArb(i).in(outArbMqPort).bits.pteidx)).af && !llptw_out.bits.af) 483dd7fe201SHaoyuan Feng XSPerfAccumulate(s"access_fault${i}", io.tlb(i).resp.fire && io.tlb(i).resp.bits.af) 484dd7fe201SHaoyuan Feng } 48592e3bfefSLemover 48692e3bfefSLemover // print configs 487f1fe8698SLemover println(s"${l2tlbParams.name}: a ptw, a llptw with size ${l2tlbParams.llptwsize}, miss queue size ${MissQueueSize} l1:${l2tlbParams.l1Size} fa l2: nSets ${l2tlbParams.l2nSets} nWays ${l2tlbParams.l2nWays} l3: ${l2tlbParams.l3nSets} nWays ${l2tlbParams.l3nWays} blockBytes:${l2tlbParams.blockBytes}") 48892e3bfefSLemover 48992e3bfefSLemover // time out assert 49092e3bfefSLemover for (i <- 0 until MemReqWidth) { 49192e3bfefSLemover TimeOutAssert(waiting_resp(i), timeOutThreshold, s"ptw mem resp time out wait_resp${i}") 49292e3bfefSLemover TimeOutAssert(flush_latch(i), timeOutThreshold, s"ptw mem resp time out flush_latch${i}") 49392e3bfefSLemover } 49492e3bfefSLemover 49592e3bfefSLemover 49692e3bfefSLemover val perfEvents = Seq(llptw, cache, ptw).flatMap(_.getPerfEvents) 49792e3bfefSLemover generatePerfEvent() 4985afdf73cSHaoyuan Feng 4995afdf73cSHaoyuan Feng val L1TlbTable = ChiselDB.createTable("L1Tlb_hart" + p(XSCoreParamsKey).HartId.toString, new L1TlbDB) 5005afdf73cSHaoyuan Feng val ITlbReqDB, DTlbReqDB, ITlbRespDB, DTlbRespDB = Wire(new L1TlbDB) 5015afdf73cSHaoyuan Feng ITlbReqDB.vpn := io.tlb(0).req(0).bits.vpn 5025afdf73cSHaoyuan Feng DTlbReqDB.vpn := io.tlb(1).req(0).bits.vpn 5035afdf73cSHaoyuan Feng ITlbRespDB.vpn := io.tlb(0).resp.bits.entry.tag 5045afdf73cSHaoyuan Feng DTlbRespDB.vpn := io.tlb(1).resp.bits.entry.tag 5055afdf73cSHaoyuan Feng L1TlbTable.log(ITlbReqDB, io.tlb(0).req(0).fire, "ITlbReq", clock, reset) 5065afdf73cSHaoyuan Feng L1TlbTable.log(DTlbReqDB, io.tlb(1).req(0).fire, "DTlbReq", clock, reset) 5075afdf73cSHaoyuan Feng L1TlbTable.log(ITlbRespDB, io.tlb(0).resp.fire, "ITlbResp", clock, reset) 5085afdf73cSHaoyuan Feng L1TlbTable.log(DTlbRespDB, io.tlb(1).resp.fire, "DTlbResp", clock, reset) 5095afdf73cSHaoyuan Feng 5105afdf73cSHaoyuan Feng val PageCacheTable = ChiselDB.createTable("PageCache_hart" + p(XSCoreParamsKey).HartId.toString, new PageCacheDB) 5115afdf73cSHaoyuan Feng val PageCacheDB = Wire(new PageCacheDB) 512*63632028SHaoyuan Feng PageCacheDB.vpn := Cat(cache.io.resp.bits.toTlb.entry(0).tag, OHToUInt(cache.io.resp.bits.toTlb.pteidx)) 5135afdf73cSHaoyuan Feng PageCacheDB.source := cache.io.resp.bits.req_info.source 5145afdf73cSHaoyuan Feng PageCacheDB.bypassed := cache.io.resp.bits.bypassed 5155afdf73cSHaoyuan Feng PageCacheDB.is_first := cache.io.resp.bits.isFirst 516*63632028SHaoyuan Feng PageCacheDB.prefetched := cache.io.resp.bits.toTlb.entry(0).prefetch 5175afdf73cSHaoyuan Feng PageCacheDB.prefetch := cache.io.resp.bits.prefetch 5185afdf73cSHaoyuan Feng PageCacheDB.l2Hit := cache.io.resp.bits.toFsm.l2Hit 5195afdf73cSHaoyuan Feng PageCacheDB.l1Hit := cache.io.resp.bits.toFsm.l1Hit 5205afdf73cSHaoyuan Feng PageCacheDB.hit := cache.io.resp.bits.hit 5215afdf73cSHaoyuan Feng PageCacheTable.log(PageCacheDB, cache.io.resp.fire, "PageCache", clock, reset) 5225afdf73cSHaoyuan Feng 5235afdf73cSHaoyuan Feng val PTWTable = ChiselDB.createTable("PTW_hart" + p(XSCoreParamsKey).HartId.toString, new PTWDB) 5245afdf73cSHaoyuan Feng val PTWReqDB, PTWRespDB, LLPTWReqDB, LLPTWRespDB = Wire(new PTWDB) 5255afdf73cSHaoyuan Feng PTWReqDB.vpn := ptw.io.req.bits.req_info.vpn 5265afdf73cSHaoyuan Feng PTWReqDB.source := ptw.io.req.bits.req_info.source 5275afdf73cSHaoyuan Feng PTWRespDB.vpn := ptw.io.refill.req_info.vpn 5285afdf73cSHaoyuan Feng PTWRespDB.source := ptw.io.refill.req_info.source 5295afdf73cSHaoyuan Feng LLPTWReqDB.vpn := llptw.io.in.bits.req_info.vpn 5305afdf73cSHaoyuan Feng LLPTWReqDB.source := llptw.io.in.bits.req_info.source 5315afdf73cSHaoyuan Feng LLPTWRespDB.vpn := llptw.io.mem.refill.vpn 5325afdf73cSHaoyuan Feng LLPTWRespDB.source := llptw.io.mem.refill.source 5335afdf73cSHaoyuan Feng PTWTable.log(PTWReqDB, ptw.io.req.fire, "PTWReq", clock, reset) 5345afdf73cSHaoyuan Feng PTWTable.log(PTWRespDB, ptw.io.mem.resp.fire, "PTWResp", clock, reset) 5355afdf73cSHaoyuan Feng PTWTable.log(LLPTWReqDB, llptw.io.in.fire, "LLPTWReq", clock, reset) 5365afdf73cSHaoyuan Feng PTWTable.log(LLPTWRespDB, llptw.io.mem.resp.fire, "LLPTWResp", clock, reset) 5375afdf73cSHaoyuan Feng 5385afdf73cSHaoyuan Feng val L2TlbMissQueueTable = ChiselDB.createTable("L2TlbMissQueue_hart" + p(XSCoreParamsKey).HartId.toString, new L2TlbMissQueueDB) 5395afdf73cSHaoyuan Feng val L2TlbMissQueueInDB, L2TlbMissQueueOutDB = Wire(new L2TlbMissQueueDB) 5405afdf73cSHaoyuan Feng L2TlbMissQueueInDB.vpn := missQueue.io.in.bits.vpn 5415afdf73cSHaoyuan Feng L2TlbMissQueueOutDB.vpn := missQueue.io.out.bits.vpn 5425afdf73cSHaoyuan Feng L2TlbMissQueueTable.log(L2TlbMissQueueInDB, missQueue.io.in.fire, "L2TlbMissQueueIn", clock, reset) 5435afdf73cSHaoyuan Feng L2TlbMissQueueTable.log(L2TlbMissQueueOutDB, missQueue.io.out.fire, "L2TlbMissQueueOut", clock, reset) 54492e3bfefSLemover} 54592e3bfefSLemover 5467797f035SbugGenerator/** BlockHelper, block missqueue, not to send too many req to cache 5477797f035SbugGenerator * Parameter: 5487797f035SbugGenerator * enable: enable BlockHelper, mq should not send too many reqs 5497797f035SbugGenerator * start: when miss queue out fire and need, block miss queue's out 5507797f035SbugGenerator * block: block miss queue's out 5517797f035SbugGenerator * latency: last missqueue out's cache access latency 5527797f035SbugGenerator */ 5537797f035SbugGeneratorclass BlockHelper(latency: Int)(implicit p: Parameters) extends XSModule { 5547797f035SbugGenerator val io = IO(new Bundle { 5557797f035SbugGenerator val enable = Input(Bool()) 5567797f035SbugGenerator val start = Input(Bool()) 5577797f035SbugGenerator val block = Output(Bool()) 5587797f035SbugGenerator }) 5597797f035SbugGenerator 5607797f035SbugGenerator val count = RegInit(0.U(log2Ceil(latency).W)) 5617797f035SbugGenerator val valid = RegInit(false.B) 5627797f035SbugGenerator val work = RegInit(true.B) 5637797f035SbugGenerator 5647797f035SbugGenerator io.block := valid 5657797f035SbugGenerator 5667797f035SbugGenerator when (io.start && work) { valid := true.B } 5677797f035SbugGenerator when (valid) { count := count + 1.U } 5687797f035SbugGenerator when (count === (latency.U) || io.enable) { 5697797f035SbugGenerator valid := false.B 5707797f035SbugGenerator work := io.enable 5717797f035SbugGenerator count := 0.U 5727797f035SbugGenerator } 5737797f035SbugGenerator} 5747797f035SbugGenerator 57592e3bfefSLemoverclass PTEHelper() extends ExtModule { 57692e3bfefSLemover val clock = IO(Input(Clock())) 57792e3bfefSLemover val enable = IO(Input(Bool())) 57892e3bfefSLemover val satp = IO(Input(UInt(64.W))) 57992e3bfefSLemover val vpn = IO(Input(UInt(64.W))) 58092e3bfefSLemover val pte = IO(Output(UInt(64.W))) 58192e3bfefSLemover val level = IO(Output(UInt(8.W))) 58292e3bfefSLemover val pf = IO(Output(UInt(8.W))) 58392e3bfefSLemover} 58492e3bfefSLemover 5855afdf73cSHaoyuan Fengclass PTWDelayN[T <: Data](gen: T, n: Int, flush: Bool) extends Module { 5865afdf73cSHaoyuan Feng val io = IO(new Bundle() { 5875afdf73cSHaoyuan Feng val in = Input(gen) 5885afdf73cSHaoyuan Feng val out = Output(gen) 5895afdf73cSHaoyuan Feng val ptwflush = Input(flush.cloneType) 5905afdf73cSHaoyuan Feng }) 5915afdf73cSHaoyuan Feng val out = RegInit(VecInit(Seq.fill(n)(0.U.asTypeOf(gen)))) 5925afdf73cSHaoyuan Feng val t = RegInit(VecInit(Seq.fill(n)(0.U.asTypeOf(gen)))) 5935afdf73cSHaoyuan Feng out(0) := io.in 5945afdf73cSHaoyuan Feng if (n == 1) { 5955afdf73cSHaoyuan Feng io.out := out(0) 5965afdf73cSHaoyuan Feng } else { 5975afdf73cSHaoyuan Feng when (io.ptwflush) { 5985afdf73cSHaoyuan Feng for (i <- 0 until n) { 5995afdf73cSHaoyuan Feng t(i) := 0.U.asTypeOf(gen) 6005afdf73cSHaoyuan Feng out(i) := 0.U.asTypeOf(gen) 6015afdf73cSHaoyuan Feng } 6025afdf73cSHaoyuan Feng io.out := 0.U.asTypeOf(gen) 6035afdf73cSHaoyuan Feng } .otherwise { 6045afdf73cSHaoyuan Feng for (i <- 1 until n) { 6055afdf73cSHaoyuan Feng t(i-1) := out(i-1) 6065afdf73cSHaoyuan Feng out(i) := t(i-1) 6075afdf73cSHaoyuan Feng } 6085afdf73cSHaoyuan Feng io.out := out(n-1) 6095afdf73cSHaoyuan Feng } 6105afdf73cSHaoyuan Feng } 6115afdf73cSHaoyuan Feng} 6125afdf73cSHaoyuan Feng 6135afdf73cSHaoyuan Fengobject PTWDelayN { 6145afdf73cSHaoyuan Feng def apply[T <: Data](in: T, n: Int, flush: Bool): T = { 6155afdf73cSHaoyuan Feng val delay = Module(new PTWDelayN(in.cloneType, n, flush)) 6165afdf73cSHaoyuan Feng delay.io.in := in 6175afdf73cSHaoyuan Feng delay.io.ptwflush := flush 6185afdf73cSHaoyuan Feng delay.io.out 6195afdf73cSHaoyuan Feng } 6205afdf73cSHaoyuan Feng} 6215afdf73cSHaoyuan Feng 62292e3bfefSLemoverclass FakePTW()(implicit p: Parameters) extends XSModule with HasPtwConst { 62392e3bfefSLemover val io = IO(new L2TLBIO) 6245afdf73cSHaoyuan Feng val flush = VecInit(Seq.fill(PtwWidth)(false.B)) 6255afdf73cSHaoyuan Feng flush(0) := DelayN(io.sfence.valid || io.csr.tlb.satp.changed, itlbParams.fenceDelay) 6265afdf73cSHaoyuan Feng flush(1) := DelayN(io.sfence.valid || io.csr.tlb.satp.changed, ldtlbParams.fenceDelay) 62792e3bfefSLemover for (i <- 0 until PtwWidth) { 62892e3bfefSLemover val helper = Module(new PTEHelper()) 62992e3bfefSLemover helper.clock := clock 63092e3bfefSLemover helper.satp := io.csr.tlb.satp.ppn 6315afdf73cSHaoyuan Feng 6325afdf73cSHaoyuan Feng if (coreParams.softPTWDelay == 1) { 6335afdf73cSHaoyuan Feng helper.enable := io.tlb(i).req(0).fire 63492e3bfefSLemover helper.vpn := io.tlb(i).req(0).bits.vpn 6355afdf73cSHaoyuan Feng } else { 6365afdf73cSHaoyuan Feng helper.enable := PTWDelayN(io.tlb(i).req(0).fire, coreParams.softPTWDelay - 1, flush(i)) 6375afdf73cSHaoyuan Feng helper.vpn := PTWDelayN(io.tlb(i).req(0).bits.vpn, coreParams.softPTWDelay - 1, flush(i)) 6385afdf73cSHaoyuan Feng } 6395afdf73cSHaoyuan Feng 64092e3bfefSLemover val pte = helper.pte.asTypeOf(new PteBundle) 64192e3bfefSLemover val level = helper.level 64292e3bfefSLemover val pf = helper.pf 6435afdf73cSHaoyuan Feng val empty = RegInit(true.B) 6445afdf73cSHaoyuan Feng when (io.tlb(i).req(0).fire) { 6455afdf73cSHaoyuan Feng empty := false.B 6465afdf73cSHaoyuan Feng } .elsewhen (io.tlb(i).resp.fire || flush(i)) { 6475afdf73cSHaoyuan Feng empty := true.B 6485afdf73cSHaoyuan Feng } 64992e3bfefSLemover 6505afdf73cSHaoyuan Feng io.tlb(i).req(0).ready := empty || io.tlb(i).resp.fire 6515afdf73cSHaoyuan Feng io.tlb(i).resp.valid := PTWDelayN(io.tlb(i).req(0).fire, coreParams.softPTWDelay, flush(i)) 65292e3bfefSLemover assert(!io.tlb(i).resp.valid || io.tlb(i).resp.ready) 6535afdf73cSHaoyuan Feng io.tlb(i).resp.bits.entry.tag := PTWDelayN(io.tlb(i).req(0).bits.vpn, coreParams.softPTWDelay, flush(i)) 65492e3bfefSLemover io.tlb(i).resp.bits.entry.ppn := pte.ppn 65592e3bfefSLemover io.tlb(i).resp.bits.entry.perm.map(_ := pte.getPerm()) 65692e3bfefSLemover io.tlb(i).resp.bits.entry.level.map(_ := level) 65792e3bfefSLemover io.tlb(i).resp.bits.pf := pf 65892e3bfefSLemover io.tlb(i).resp.bits.af := DontCare // TODO: implement it 6595afdf73cSHaoyuan Feng io.tlb(i).resp.bits.entry.v := !pf 6605afdf73cSHaoyuan Feng io.tlb(i).resp.bits.entry.prefetch := DontCare 6615afdf73cSHaoyuan Feng io.tlb(i).resp.bits.entry.asid := io.csr.tlb.satp.asid 66292e3bfefSLemover } 66392e3bfefSLemover} 66492e3bfefSLemover 66592e3bfefSLemoverclass L2TLBWrapper()(implicit p: Parameters) extends LazyModule with HasXSParameter { 66692e3bfefSLemover val useSoftPTW = coreParams.softPTW 66792e3bfefSLemover val node = if (!useSoftPTW) TLIdentityNode() else null 66892e3bfefSLemover val ptw = if (!useSoftPTW) LazyModule(new L2TLB()) else null 66992e3bfefSLemover if (!useSoftPTW) { 67092e3bfefSLemover node := ptw.node 67192e3bfefSLemover } 67292e3bfefSLemover 67392e3bfefSLemover lazy val module = new LazyModuleImp(this) with HasPerfEvents { 67492e3bfefSLemover val io = IO(new L2TLBIO) 67592e3bfefSLemover val perfEvents = if (useSoftPTW) { 67692e3bfefSLemover val fake_ptw = Module(new FakePTW()) 67792e3bfefSLemover io <> fake_ptw.io 67892e3bfefSLemover Seq() 67992e3bfefSLemover } 68092e3bfefSLemover else { 68192e3bfefSLemover io <> ptw.module.io 68292e3bfefSLemover ptw.module.getPerfEvents 68392e3bfefSLemover } 68492e3bfefSLemover generatePerfEvent() 68592e3bfefSLemover } 68692e3bfefSLemover} 687