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 33*9c26bab7SHaoyuan 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)) 10392e3bfefSLemover val outArb = (0 until PtwWidth).map(i => Module(new Arbiter(new PtwResp, 3)).io) 10492e3bfefSLemover val outArbCachePort = 0 10592e3bfefSLemover val outArbFsmPort = 1 10692e3bfefSLemover val outArbMqPort = 2 10792e3bfefSLemover 1089c503409SLemover // arb2 input port 1099c503409SLemover val InArbPTWPort = 0 1109c503409SLemover val InArbMissQueuePort = 1 1119c503409SLemover val InArbTlbPort = 2 1129c503409SLemover val InArbPrefetchPort = 3 11392e3bfefSLemover // NOTE: when cache out but miss and ptw doesnt accept, 11492e3bfefSLemover arb1.io.in <> VecInit(io.tlb.map(_.req(0))) 1159c503409SLemover arb1.io.out.ready := arb2.io.in(InArbTlbPort).ready 11692e3bfefSLemover 1179c503409SLemover arb2.io.in(InArbPTWPort).valid := ptw.io.llptw.valid 1189c503409SLemover arb2.io.in(InArbPTWPort).bits.vpn := ptw.io.llptw.bits.req_info.vpn 1199c503409SLemover arb2.io.in(InArbPTWPort).bits.source := ptw.io.llptw.bits.req_info.source 1209c503409SLemover ptw.io.llptw.ready := arb2.io.in(InArbPTWPort).ready 12192e3bfefSLemover block_decoupled(missQueue.io.out, arb2.io.in(InArbMissQueuePort), !ptw.io.req.ready) 1227797f035SbugGenerator 12392e3bfefSLemover arb2.io.in(InArbTlbPort).valid := arb1.io.out.valid 12492e3bfefSLemover arb2.io.in(InArbTlbPort).bits.vpn := arb1.io.out.bits.vpn 12592e3bfefSLemover arb2.io.in(InArbTlbPort).bits.source := arb1.io.chosen 12692e3bfefSLemover if (l2tlbParams.enablePrefetch) { 12792e3bfefSLemover val prefetch = Module(new L2TlbPrefetch()) 12892e3bfefSLemover val recv = cache.io.resp 12992e3bfefSLemover // NOTE: 1. prefetch doesn't gen prefetch 2. req from mq doesn't gen prefetch 13092e3bfefSLemover // NOTE: 1. miss req gen prefetch 2. hit but prefetched gen prefetch 13192e3bfefSLemover prefetch.io.in.valid := recv.fire() && !from_pre(recv.bits.req_info.source) && (!recv.bits.hit || 13292e3bfefSLemover recv.bits.prefetch) && recv.bits.isFirst 13392e3bfefSLemover prefetch.io.in.bits.vpn := recv.bits.req_info.vpn 1347797f035SbugGenerator prefetch.io.sfence := sfence_dup(0) 1357797f035SbugGenerator prefetch.io.csr := csr_dup(0) 13692e3bfefSLemover arb2.io.in(InArbPrefetchPort) <> prefetch.io.out 1375afdf73cSHaoyuan Feng 1385afdf73cSHaoyuan Feng val L2TlbPrefetchTable = ChiselDB.createTable("L2TlbPrefetch_hart" + p(XSCoreParamsKey).HartId.toString, new L2TlbPrefetchDB) 1395afdf73cSHaoyuan Feng val L2TlbPrefetchDB = Wire(new L2TlbPrefetchDB) 1405afdf73cSHaoyuan Feng L2TlbPrefetchDB.vpn := prefetch.io.out.bits.vpn 1415afdf73cSHaoyuan Feng L2TlbPrefetchTable.log(L2TlbPrefetchDB, prefetch.io.out.fire, "L2TlbPrefetch", clock, reset) 14292e3bfefSLemover } 14392e3bfefSLemover arb2.io.out.ready := cache.io.req.ready 14492e3bfefSLemover 1457797f035SbugGenerator 1467797f035SbugGenerator val mq_arb = Module(new Arbiter(new L2TlbInnerBundle, 2)) 1477797f035SbugGenerator mq_arb.io.in(0).valid := cache.io.resp.valid && !cache.io.resp.bits.hit && 1487797f035SbugGenerator (!cache.io.resp.bits.toFsm.l2Hit || cache.io.resp.bits.bypassed) && 1497797f035SbugGenerator !from_pre(cache.io.resp.bits.req_info.source) && 1507797f035SbugGenerator (cache.io.resp.bits.bypassed || cache.io.resp.bits.isFirst || !ptw.io.req.ready) 1517797f035SbugGenerator mq_arb.io.in(0).bits := cache.io.resp.bits.req_info 1527797f035SbugGenerator mq_arb.io.in(1) <> llptw.io.cache 1537797f035SbugGenerator missQueue.io.in <> mq_arb.io.out 1547797f035SbugGenerator missQueue.io.sfence := sfence_dup(6) 1557797f035SbugGenerator missQueue.io.csr := csr_dup(5) 1567797f035SbugGenerator 1577797f035SbugGenerator blockmq.io.start := missQueue.io.out.fire 1587797f035SbugGenerator blockmq.io.enable := ptw.io.req.fire() 1597797f035SbugGenerator 1609c503409SLemover llptw.io.in.valid := cache.io.resp.valid && !cache.io.resp.bits.hit && cache.io.resp.bits.toFsm.l2Hit && !cache.io.resp.bits.bypassed 1619c503409SLemover llptw.io.in.bits.req_info := cache.io.resp.bits.req_info 1629c503409SLemover llptw.io.in.bits.ppn := cache.io.resp.bits.toFsm.ppn 1637797f035SbugGenerator llptw.io.sfence := sfence_dup(1) 1647797f035SbugGenerator llptw.io.csr := csr_dup(1) 16592e3bfefSLemover 16692e3bfefSLemover cache.io.req.valid := arb2.io.out.valid 16792e3bfefSLemover cache.io.req.bits.req_info.vpn := arb2.io.out.bits.vpn 16892e3bfefSLemover cache.io.req.bits.req_info.source := arb2.io.out.bits.source 16992e3bfefSLemover cache.io.req.bits.isFirst := arb2.io.chosen =/= InArbMissQueuePort.U 1701f4a7c0cSLemover cache.io.req.bits.bypassed.map(_ := false.B) 1717797f035SbugGenerator cache.io.sfence := sfence_dup(2) 1727797f035SbugGenerator cache.io.csr := csr_dup(2) 1737797f035SbugGenerator cache.io.sfence_dup.zip(sfence_dup.drop(2).take(4)).map(s => s._1 := s._2) 1747797f035SbugGenerator cache.io.csr_dup.zip(csr_dup.drop(2).take(3)).map(c => c._1 := c._2) 17592e3bfefSLemover cache.io.resp.ready := Mux(cache.io.resp.bits.hit, 17692e3bfefSLemover outReady(cache.io.resp.bits.req_info.source, outArbCachePort), 1779c503409SLemover Mux(cache.io.resp.bits.toFsm.l2Hit && !cache.io.resp.bits.bypassed, llptw.io.in.ready, 1787797f035SbugGenerator 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))) 17992e3bfefSLemover 18092e3bfefSLemover // NOTE: missQueue req has higher priority 1817797f035SbugGenerator ptw.io.req.valid := cache.io.resp.valid && !cache.io.resp.bits.hit && !cache.io.resp.bits.toFsm.l2Hit && 1827797f035SbugGenerator !cache.io.resp.bits.bypassed && 1837797f035SbugGenerator !cache.io.resp.bits.isFirst 18492e3bfefSLemover ptw.io.req.bits.req_info := cache.io.resp.bits.req_info 18592e3bfefSLemover ptw.io.req.bits.l1Hit := cache.io.resp.bits.toFsm.l1Hit 18692e3bfefSLemover ptw.io.req.bits.ppn := cache.io.resp.bits.toFsm.ppn 1877797f035SbugGenerator ptw.io.sfence := sfence_dup(7) 1887797f035SbugGenerator ptw.io.csr := csr_dup(6) 18992e3bfefSLemover ptw.io.resp.ready := outReady(ptw.io.resp.bits.source, outArbFsmPort) 19092e3bfefSLemover 19192e3bfefSLemover // mem req 19292e3bfefSLemover def blockBytes_align(addr: UInt) = { 19392e3bfefSLemover Cat(addr(PAddrBits - 1, log2Up(l2tlbParams.blockBytes)), 0.U(log2Up(l2tlbParams.blockBytes).W)) 19492e3bfefSLemover } 19592e3bfefSLemover def addr_low_from_vpn(vpn: UInt) = { 19692e3bfefSLemover vpn(log2Ceil(l2tlbParams.blockBytes)-log2Ceil(XLEN/8)-1, 0) 19792e3bfefSLemover } 19892e3bfefSLemover def addr_low_from_paddr(paddr: UInt) = { 19992e3bfefSLemover paddr(log2Up(l2tlbParams.blockBytes)-1, log2Up(XLEN/8)) 20092e3bfefSLemover } 20192e3bfefSLemover def from_missqueue(id: UInt) = { 20292e3bfefSLemover (id =/= l2tlbParams.llptwsize.U) 20392e3bfefSLemover } 20492e3bfefSLemover val waiting_resp = RegInit(VecInit(Seq.fill(MemReqWidth)(false.B))) 20592e3bfefSLemover val flush_latch = RegInit(VecInit(Seq.fill(MemReqWidth)(false.B))) 20692e3bfefSLemover for (i <- waiting_resp.indices) { 20792e3bfefSLemover assert(!flush_latch(i) || waiting_resp(i)) // when sfence_latch wait for mem resp, waiting_resp should be true 20892e3bfefSLemover } 20992e3bfefSLemover 21092e3bfefSLemover val llptw_out = llptw.io.out 21192e3bfefSLemover val llptw_mem = llptw.io.mem 21292e3bfefSLemover llptw_mem.req_mask := waiting_resp.take(l2tlbParams.llptwsize) 21392e3bfefSLemover ptw.io.mem.mask := waiting_resp.last 21492e3bfefSLemover 21592e3bfefSLemover val mem_arb = Module(new Arbiter(new L2TlbMemReqBundle(), 2)) 21692e3bfefSLemover mem_arb.io.in(0) <> ptw.io.mem.req 21792e3bfefSLemover mem_arb.io.in(1) <> llptw_mem.req 21892e3bfefSLemover mem_arb.io.out.ready := mem.a.ready && !flush 21992e3bfefSLemover 2201f4a7c0cSLemover // assert, should not send mem access at same addr for twice. 2217797f035SbugGenerator val last_resp_vpn = RegEnable(cache.io.refill.bits.req_info_dup(0).vpn, cache.io.refill.valid) 2227797f035SbugGenerator val last_resp_level = RegEnable(cache.io.refill.bits.level_dup(0), cache.io.refill.valid) 2231f4a7c0cSLemover val last_resp_v = RegInit(false.B) 2241f4a7c0cSLemover val last_has_invalid = !Cat(cache.io.refill.bits.ptes.asTypeOf(Vec(blockBits/XLEN, UInt(XLEN.W))).map(a => a(0))).andR 2251f4a7c0cSLemover when (cache.io.refill.valid) { last_resp_v := !last_has_invalid} 2261f4a7c0cSLemover when (flush) { last_resp_v := false.B } 2271f4a7c0cSLemover XSError(last_resp_v && cache.io.refill.valid && 2287797f035SbugGenerator (cache.io.refill.bits.req_info_dup(0).vpn === last_resp_vpn) && 2297797f035SbugGenerator (cache.io.refill.bits.level_dup(0) === last_resp_level), 2301f4a7c0cSLemover "l2tlb should not access mem at same addr for twice") 2311f4a7c0cSLemover // ATTENTION: this may wronngly assert when: a ptes is l2, last part is valid, 2321f4a7c0cSLemover // but the current part is invalid, so one more mem access happened 2331f4a7c0cSLemover // If this happened, remove the assert. 2341f4a7c0cSLemover 23592e3bfefSLemover val req_addr_low = Reg(Vec(MemReqWidth, UInt((log2Up(l2tlbParams.blockBytes)-log2Up(XLEN/8)).W))) 23692e3bfefSLemover 23792e3bfefSLemover when (llptw.io.in.fire()) { 23892e3bfefSLemover // when enq miss queue, set the req_addr_low to receive the mem resp data part 23992e3bfefSLemover req_addr_low(llptw_mem.enq_ptr) := addr_low_from_vpn(llptw.io.in.bits.req_info.vpn) 24092e3bfefSLemover } 24192e3bfefSLemover when (mem_arb.io.out.fire()) { 24292e3bfefSLemover req_addr_low(mem_arb.io.out.bits.id) := addr_low_from_paddr(mem_arb.io.out.bits.addr) 24392e3bfefSLemover waiting_resp(mem_arb.io.out.bits.id) := true.B 24492e3bfefSLemover } 24592e3bfefSLemover // mem read 24692e3bfefSLemover val memRead = edge.Get( 24792e3bfefSLemover fromSource = mem_arb.io.out.bits.id, 24892e3bfefSLemover // toAddress = memAddr(log2Up(CacheLineSize / 2 / 8) - 1, 0), 24992e3bfefSLemover toAddress = blockBytes_align(mem_arb.io.out.bits.addr), 25092e3bfefSLemover lgSize = log2Up(l2tlbParams.blockBytes).U 25192e3bfefSLemover )._2 25292e3bfefSLemover mem.a.bits := memRead 25392e3bfefSLemover mem.a.valid := mem_arb.io.out.valid && !flush 25492e3bfefSLemover mem.d.ready := true.B 25592e3bfefSLemover // mem -> data buffer 25692e3bfefSLemover val refill_data = Reg(Vec(blockBits / l1BusDataWidth, UInt(l1BusDataWidth.W))) 25792e3bfefSLemover val refill_helper = edge.firstlastHelper(mem.d.bits, mem.d.fire()) 25892e3bfefSLemover val mem_resp_done = refill_helper._3 25992e3bfefSLemover val mem_resp_from_mq = from_missqueue(mem.d.bits.source) 26092e3bfefSLemover when (mem.d.valid) { 26192e3bfefSLemover assert(mem.d.bits.source <= l2tlbParams.llptwsize.U) 26292e3bfefSLemover refill_data(refill_helper._4) := mem.d.bits.data 26392e3bfefSLemover } 2647797f035SbugGenerator // refill_data_tmp is the wire fork of refill_data, but one cycle earlier 2657797f035SbugGenerator val refill_data_tmp = WireInit(refill_data) 2667797f035SbugGenerator refill_data_tmp(refill_helper._4) := mem.d.bits.data 2677797f035SbugGenerator 26892e3bfefSLemover // save only one pte for each id 26992e3bfefSLemover // (miss queue may can't resp to tlb with low latency, it should have highest priority, but diffcult to design cache) 27092e3bfefSLemover val resp_pte = VecInit((0 until MemReqWidth).map(i => 2717797f035SbugGenerator if (i == l2tlbParams.llptwsize) {RegEnable(get_part(refill_data_tmp, req_addr_low(i)), mem_resp_done && !mem_resp_from_mq) } 27292e3bfefSLemover else { DataHoldBypass(get_part(refill_data, req_addr_low(i)), llptw_mem.buffer_it(i)) } 2737797f035SbugGenerator // llptw could not use refill_data_tmp, because enq bypass's result works at next cycle 27492e3bfefSLemover )) 27592e3bfefSLemover 27692e3bfefSLemover // mem -> miss queue 27792e3bfefSLemover llptw_mem.resp.valid := mem_resp_done && mem_resp_from_mq 2787797f035SbugGenerator llptw_mem.resp.bits.id := DataHoldBypass(mem.d.bits.source, mem.d.valid) 27992e3bfefSLemover // mem -> ptw 28092e3bfefSLemover ptw.io.mem.req.ready := mem.a.ready 28192e3bfefSLemover ptw.io.mem.resp.valid := mem_resp_done && !mem_resp_from_mq 28292e3bfefSLemover ptw.io.mem.resp.bits := resp_pte.last 28392e3bfefSLemover // mem -> cache 2847797f035SbugGenerator val refill_from_mq = mem_resp_from_mq 2857797f035SbugGenerator val refill_level = Mux(refill_from_mq, 2.U, RegEnable(ptw.io.refill.level, init = 0.U, ptw.io.mem.req.fire())) 2867797f035SbugGenerator val refill_valid = mem_resp_done && !flush && !flush_latch(mem.d.bits.source) 2877797f035SbugGenerator 2887797f035SbugGenerator cache.io.refill.valid := RegNext(refill_valid, false.B) 28992e3bfefSLemover cache.io.refill.bits.ptes := refill_data.asUInt 2907797f035SbugGenerator cache.io.refill.bits.req_info_dup.map(_ := RegEnable(Mux(refill_from_mq, llptw_mem.refill, ptw.io.refill.req_info), refill_valid)) 2917797f035SbugGenerator cache.io.refill.bits.level_dup.map(_ := RegEnable(refill_level, refill_valid)) 2927797f035SbugGenerator cache.io.refill.bits.levelOH(refill_level, refill_valid) 2937797f035SbugGenerator cache.io.refill.bits.sel_pte_dup.map(_ := RegNext(sel_data(refill_data_tmp.asUInt, req_addr_low(mem.d.bits.source)))) 29492e3bfefSLemover 295*9c26bab7SHaoyuan Feng if (env.EnableDifftest) { 296*9c26bab7SHaoyuan Feng val difftest_ptw_addr = RegInit(VecInit(Seq.fill(MemReqWidth)(0.U(PAddrBits.W)))) 297*9c26bab7SHaoyuan Feng when (mem.a.valid) { 298*9c26bab7SHaoyuan Feng difftest_ptw_addr(mem.a.bits.source) := mem.a.bits.address 299*9c26bab7SHaoyuan Feng } 300*9c26bab7SHaoyuan Feng 301*9c26bab7SHaoyuan Feng val difftest = Module(new DifftestRefillEvent) 302*9c26bab7SHaoyuan Feng difftest.io.clock := clock 303*9c26bab7SHaoyuan Feng difftest.io.coreid := p(XSCoreParamsKey).HartId.asUInt 304*9c26bab7SHaoyuan Feng difftest.io.cacheid := 2.U 305*9c26bab7SHaoyuan Feng difftest.io.valid := cache.io.refill.valid 306*9c26bab7SHaoyuan Feng difftest.io.addr := difftest_ptw_addr(RegNext(mem.d.bits.source)) 307*9c26bab7SHaoyuan Feng difftest.io.data := refill_data.asTypeOf(difftest.io.data) 308*9c26bab7SHaoyuan Feng } 309*9c26bab7SHaoyuan Feng 31092e3bfefSLemover // pmp 31192e3bfefSLemover pmp_check(0).req <> ptw.io.pmp.req 31292e3bfefSLemover ptw.io.pmp.resp <> pmp_check(0).resp 31392e3bfefSLemover pmp_check(1).req <> llptw.io.pmp.req 31492e3bfefSLemover llptw.io.pmp.resp <> pmp_check(1).resp 31592e3bfefSLemover 31692e3bfefSLemover llptw_out.ready := outReady(llptw_out.bits.req_info.source, outArbMqPort) 31792e3bfefSLemover for (i <- 0 until PtwWidth) { 31892e3bfefSLemover outArb(i).in(outArbCachePort).valid := cache.io.resp.valid && cache.io.resp.bits.hit && cache.io.resp.bits.req_info.source===i.U 31992e3bfefSLemover outArb(i).in(outArbCachePort).bits.entry := cache.io.resp.bits.toTlb 32092e3bfefSLemover outArb(i).in(outArbCachePort).bits.pf := !cache.io.resp.bits.toTlb.v 32192e3bfefSLemover outArb(i).in(outArbCachePort).bits.af := false.B 32292e3bfefSLemover outArb(i).in(outArbFsmPort).valid := ptw.io.resp.valid && ptw.io.resp.bits.source===i.U 32392e3bfefSLemover outArb(i).in(outArbFsmPort).bits := ptw.io.resp.bits.resp 32492e3bfefSLemover outArb(i).in(outArbMqPort).valid := llptw_out.valid && llptw_out.bits.req_info.source===i.U 32592e3bfefSLemover outArb(i).in(outArbMqPort).bits := pte_to_ptwResp(resp_pte(llptw_out.bits.id), llptw_out.bits.req_info.vpn, llptw_out.bits.af, true) 32692e3bfefSLemover } 32792e3bfefSLemover 32892e3bfefSLemover // io.tlb.map(_.resp) <> outArb.map(_.out) 32992e3bfefSLemover io.tlb.map(_.resp).zip(outArb.map(_.out)).map{ 33092e3bfefSLemover case (resp, out) => resp <> out 33192e3bfefSLemover } 33292e3bfefSLemover 33392e3bfefSLemover // sfence 33492e3bfefSLemover when (flush) { 33592e3bfefSLemover for (i <- 0 until MemReqWidth) { 33692e3bfefSLemover when (waiting_resp(i)) { 33792e3bfefSLemover flush_latch(i) := true.B 33892e3bfefSLemover } 33992e3bfefSLemover } 34092e3bfefSLemover } 34192e3bfefSLemover // mem -> control signal 34292e3bfefSLemover // waiting_resp and sfence_latch will be reset when mem_resp_done 34392e3bfefSLemover when (mem_resp_done) { 34492e3bfefSLemover waiting_resp(mem.d.bits.source) := false.B 34592e3bfefSLemover flush_latch(mem.d.bits.source) := false.B 34692e3bfefSLemover } 34792e3bfefSLemover 34892e3bfefSLemover def block_decoupled[T <: Data](source: DecoupledIO[T], sink: DecoupledIO[T], block_signal: Bool) = { 34992e3bfefSLemover sink.valid := source.valid && !block_signal 35092e3bfefSLemover source.ready := sink.ready && !block_signal 35192e3bfefSLemover sink.bits := source.bits 35292e3bfefSLemover } 35392e3bfefSLemover 35492e3bfefSLemover def get_part(data: Vec[UInt], index: UInt): UInt = { 35592e3bfefSLemover val inner_data = data.asTypeOf(Vec(data.getWidth / XLEN, UInt(XLEN.W))) 35692e3bfefSLemover inner_data(index) 35792e3bfefSLemover } 35892e3bfefSLemover 35992e3bfefSLemover def pte_to_ptwResp(pte: UInt, vpn: UInt, af: Bool, af_first: Boolean) : PtwResp = { 36092e3bfefSLemover val pte_in = pte.asTypeOf(new PteBundle()) 36192e3bfefSLemover val ptw_resp = Wire(new PtwResp()) 36292e3bfefSLemover ptw_resp.entry.ppn := pte_in.ppn 36392e3bfefSLemover ptw_resp.entry.level.map(_ := 2.U) 36492e3bfefSLemover ptw_resp.entry.perm.map(_ := pte_in.getPerm()) 36592e3bfefSLemover ptw_resp.entry.tag := vpn 36692e3bfefSLemover ptw_resp.pf := (if (af_first) !af else true.B) && pte_in.isPf(2.U) 36792e3bfefSLemover ptw_resp.af := (if (!af_first) pte_in.isPf(2.U) else true.B) && af 36892e3bfefSLemover ptw_resp.entry.v := !ptw_resp.pf 36992e3bfefSLemover ptw_resp.entry.prefetch := DontCare 37092e3bfefSLemover ptw_resp.entry.asid := satp.asid 37192e3bfefSLemover ptw_resp 37292e3bfefSLemover } 37392e3bfefSLemover 37492e3bfefSLemover def outReady(source: UInt, port: Int): Bool = { 37592e3bfefSLemover MuxLookup(source, true.B, 37692e3bfefSLemover (0 until PtwWidth).map(i => i.U -> outArb(i).in(port).ready)) 37792e3bfefSLemover } 37892e3bfefSLemover 37992e3bfefSLemover // debug info 38092e3bfefSLemover for (i <- 0 until PtwWidth) { 38192e3bfefSLemover XSDebug(p"[io.tlb(${i.U})] ${io.tlb(i)}\n") 38292e3bfefSLemover } 3837797f035SbugGenerator XSDebug(p"[sfence] ${io.sfence}\n") 38492e3bfefSLemover XSDebug(p"[io.csr.tlb] ${io.csr.tlb}\n") 38592e3bfefSLemover 38692e3bfefSLemover for (i <- 0 until PtwWidth) { 38792e3bfefSLemover XSPerfAccumulate(s"req_count${i}", io.tlb(i).req(0).fire()) 38892e3bfefSLemover XSPerfAccumulate(s"req_blocked_count_${i}", io.tlb(i).req(0).valid && !io.tlb(i).req(0).ready) 38992e3bfefSLemover } 39092e3bfefSLemover XSPerfAccumulate(s"req_blocked_by_mq", arb1.io.out.valid && missQueue.io.out.valid) 39192e3bfefSLemover for (i <- 0 until (MemReqWidth + 1)) { 39292e3bfefSLemover XSPerfAccumulate(s"mem_req_util${i}", PopCount(waiting_resp) === i.U) 39392e3bfefSLemover } 39492e3bfefSLemover XSPerfAccumulate("mem_cycle", PopCount(waiting_resp) =/= 0.U) 39592e3bfefSLemover XSPerfAccumulate("mem_count", mem.a.fire()) 39692e3bfefSLemover 39792e3bfefSLemover // print configs 398f1fe8698SLemover 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}") 39992e3bfefSLemover 40092e3bfefSLemover // time out assert 40192e3bfefSLemover for (i <- 0 until MemReqWidth) { 40292e3bfefSLemover TimeOutAssert(waiting_resp(i), timeOutThreshold, s"ptw mem resp time out wait_resp${i}") 40392e3bfefSLemover TimeOutAssert(flush_latch(i), timeOutThreshold, s"ptw mem resp time out flush_latch${i}") 40492e3bfefSLemover } 40592e3bfefSLemover 40692e3bfefSLemover 40792e3bfefSLemover val perfEvents = Seq(llptw, cache, ptw).flatMap(_.getPerfEvents) 40892e3bfefSLemover generatePerfEvent() 4095afdf73cSHaoyuan Feng 4105afdf73cSHaoyuan Feng val L1TlbTable = ChiselDB.createTable("L1Tlb_hart" + p(XSCoreParamsKey).HartId.toString, new L1TlbDB) 4115afdf73cSHaoyuan Feng val ITlbReqDB, DTlbReqDB, ITlbRespDB, DTlbRespDB = Wire(new L1TlbDB) 4125afdf73cSHaoyuan Feng ITlbReqDB.vpn := io.tlb(0).req(0).bits.vpn 4135afdf73cSHaoyuan Feng DTlbReqDB.vpn := io.tlb(1).req(0).bits.vpn 4145afdf73cSHaoyuan Feng ITlbRespDB.vpn := io.tlb(0).resp.bits.entry.tag 4155afdf73cSHaoyuan Feng DTlbRespDB.vpn := io.tlb(1).resp.bits.entry.tag 4165afdf73cSHaoyuan Feng L1TlbTable.log(ITlbReqDB, io.tlb(0).req(0).fire, "ITlbReq", clock, reset) 4175afdf73cSHaoyuan Feng L1TlbTable.log(DTlbReqDB, io.tlb(1).req(0).fire, "DTlbReq", clock, reset) 4185afdf73cSHaoyuan Feng L1TlbTable.log(ITlbRespDB, io.tlb(0).resp.fire, "ITlbResp", clock, reset) 4195afdf73cSHaoyuan Feng L1TlbTable.log(DTlbRespDB, io.tlb(1).resp.fire, "DTlbResp", clock, reset) 4205afdf73cSHaoyuan Feng 4215afdf73cSHaoyuan Feng val PageCacheTable = ChiselDB.createTable("PageCache_hart" + p(XSCoreParamsKey).HartId.toString, new PageCacheDB) 4225afdf73cSHaoyuan Feng val PageCacheDB = Wire(new PageCacheDB) 4235afdf73cSHaoyuan Feng PageCacheDB.vpn := cache.io.resp.bits.toTlb.tag 4245afdf73cSHaoyuan Feng PageCacheDB.source := cache.io.resp.bits.req_info.source 4255afdf73cSHaoyuan Feng PageCacheDB.bypassed := cache.io.resp.bits.bypassed 4265afdf73cSHaoyuan Feng PageCacheDB.is_first := cache.io.resp.bits.isFirst 4275afdf73cSHaoyuan Feng PageCacheDB.prefetched := cache.io.resp.bits.toTlb.prefetch 4285afdf73cSHaoyuan Feng PageCacheDB.prefetch := cache.io.resp.bits.prefetch 4295afdf73cSHaoyuan Feng PageCacheDB.l2Hit := cache.io.resp.bits.toFsm.l2Hit 4305afdf73cSHaoyuan Feng PageCacheDB.l1Hit := cache.io.resp.bits.toFsm.l1Hit 4315afdf73cSHaoyuan Feng PageCacheDB.hit := cache.io.resp.bits.hit 4325afdf73cSHaoyuan Feng PageCacheTable.log(PageCacheDB, cache.io.resp.fire, "PageCache", clock, reset) 4335afdf73cSHaoyuan Feng 4345afdf73cSHaoyuan Feng val PTWTable = ChiselDB.createTable("PTW_hart" + p(XSCoreParamsKey).HartId.toString, new PTWDB) 4355afdf73cSHaoyuan Feng val PTWReqDB, PTWRespDB, LLPTWReqDB, LLPTWRespDB = Wire(new PTWDB) 4365afdf73cSHaoyuan Feng PTWReqDB.vpn := ptw.io.req.bits.req_info.vpn 4375afdf73cSHaoyuan Feng PTWReqDB.source := ptw.io.req.bits.req_info.source 4385afdf73cSHaoyuan Feng PTWRespDB.vpn := ptw.io.refill.req_info.vpn 4395afdf73cSHaoyuan Feng PTWRespDB.source := ptw.io.refill.req_info.source 4405afdf73cSHaoyuan Feng LLPTWReqDB.vpn := llptw.io.in.bits.req_info.vpn 4415afdf73cSHaoyuan Feng LLPTWReqDB.source := llptw.io.in.bits.req_info.source 4425afdf73cSHaoyuan Feng LLPTWRespDB.vpn := llptw.io.mem.refill.vpn 4435afdf73cSHaoyuan Feng LLPTWRespDB.source := llptw.io.mem.refill.source 4445afdf73cSHaoyuan Feng PTWTable.log(PTWReqDB, ptw.io.req.fire, "PTWReq", clock, reset) 4455afdf73cSHaoyuan Feng PTWTable.log(PTWRespDB, ptw.io.mem.resp.fire, "PTWResp", clock, reset) 4465afdf73cSHaoyuan Feng PTWTable.log(LLPTWReqDB, llptw.io.in.fire, "LLPTWReq", clock, reset) 4475afdf73cSHaoyuan Feng PTWTable.log(LLPTWRespDB, llptw.io.mem.resp.fire, "LLPTWResp", clock, reset) 4485afdf73cSHaoyuan Feng 4495afdf73cSHaoyuan Feng val L2TlbMissQueueTable = ChiselDB.createTable("L2TlbMissQueue_hart" + p(XSCoreParamsKey).HartId.toString, new L2TlbMissQueueDB) 4505afdf73cSHaoyuan Feng val L2TlbMissQueueInDB, L2TlbMissQueueOutDB = Wire(new L2TlbMissQueueDB) 4515afdf73cSHaoyuan Feng L2TlbMissQueueInDB.vpn := missQueue.io.in.bits.vpn 4525afdf73cSHaoyuan Feng L2TlbMissQueueOutDB.vpn := missQueue.io.out.bits.vpn 4535afdf73cSHaoyuan Feng L2TlbMissQueueTable.log(L2TlbMissQueueInDB, missQueue.io.in.fire, "L2TlbMissQueueIn", clock, reset) 4545afdf73cSHaoyuan Feng L2TlbMissQueueTable.log(L2TlbMissQueueOutDB, missQueue.io.out.fire, "L2TlbMissQueueOut", clock, reset) 45592e3bfefSLemover} 45692e3bfefSLemover 4577797f035SbugGenerator/** BlockHelper, block missqueue, not to send too many req to cache 4587797f035SbugGenerator * Parameter: 4597797f035SbugGenerator * enable: enable BlockHelper, mq should not send too many reqs 4607797f035SbugGenerator * start: when miss queue out fire and need, block miss queue's out 4617797f035SbugGenerator * block: block miss queue's out 4627797f035SbugGenerator * latency: last missqueue out's cache access latency 4637797f035SbugGenerator */ 4647797f035SbugGeneratorclass BlockHelper(latency: Int)(implicit p: Parameters) extends XSModule { 4657797f035SbugGenerator val io = IO(new Bundle { 4667797f035SbugGenerator val enable = Input(Bool()) 4677797f035SbugGenerator val start = Input(Bool()) 4687797f035SbugGenerator val block = Output(Bool()) 4697797f035SbugGenerator }) 4707797f035SbugGenerator 4717797f035SbugGenerator val count = RegInit(0.U(log2Ceil(latency).W)) 4727797f035SbugGenerator val valid = RegInit(false.B) 4737797f035SbugGenerator val work = RegInit(true.B) 4747797f035SbugGenerator 4757797f035SbugGenerator io.block := valid 4767797f035SbugGenerator 4777797f035SbugGenerator when (io.start && work) { valid := true.B } 4787797f035SbugGenerator when (valid) { count := count + 1.U } 4797797f035SbugGenerator when (count === (latency.U) || io.enable) { 4807797f035SbugGenerator valid := false.B 4817797f035SbugGenerator work := io.enable 4827797f035SbugGenerator count := 0.U 4837797f035SbugGenerator } 4847797f035SbugGenerator} 4857797f035SbugGenerator 48692e3bfefSLemoverclass PTEHelper() extends ExtModule { 48792e3bfefSLemover val clock = IO(Input(Clock())) 48892e3bfefSLemover val enable = IO(Input(Bool())) 48992e3bfefSLemover val satp = IO(Input(UInt(64.W))) 49092e3bfefSLemover val vpn = IO(Input(UInt(64.W))) 49192e3bfefSLemover val pte = IO(Output(UInt(64.W))) 49292e3bfefSLemover val level = IO(Output(UInt(8.W))) 49392e3bfefSLemover val pf = IO(Output(UInt(8.W))) 49492e3bfefSLemover} 49592e3bfefSLemover 4965afdf73cSHaoyuan Fengclass PTWDelayN[T <: Data](gen: T, n: Int, flush: Bool) extends Module { 4975afdf73cSHaoyuan Feng val io = IO(new Bundle() { 4985afdf73cSHaoyuan Feng val in = Input(gen) 4995afdf73cSHaoyuan Feng val out = Output(gen) 5005afdf73cSHaoyuan Feng val ptwflush = Input(flush.cloneType) 5015afdf73cSHaoyuan Feng }) 5025afdf73cSHaoyuan Feng val out = RegInit(VecInit(Seq.fill(n)(0.U.asTypeOf(gen)))) 5035afdf73cSHaoyuan Feng val t = RegInit(VecInit(Seq.fill(n)(0.U.asTypeOf(gen)))) 5045afdf73cSHaoyuan Feng out(0) := io.in 5055afdf73cSHaoyuan Feng if (n == 1) { 5065afdf73cSHaoyuan Feng io.out := out(0) 5075afdf73cSHaoyuan Feng } else { 5085afdf73cSHaoyuan Feng when (io.ptwflush) { 5095afdf73cSHaoyuan Feng for (i <- 0 until n) { 5105afdf73cSHaoyuan Feng t(i) := 0.U.asTypeOf(gen) 5115afdf73cSHaoyuan Feng out(i) := 0.U.asTypeOf(gen) 5125afdf73cSHaoyuan Feng } 5135afdf73cSHaoyuan Feng io.out := 0.U.asTypeOf(gen) 5145afdf73cSHaoyuan Feng } .otherwise { 5155afdf73cSHaoyuan Feng for (i <- 1 until n) { 5165afdf73cSHaoyuan Feng t(i-1) := out(i-1) 5175afdf73cSHaoyuan Feng out(i) := t(i-1) 5185afdf73cSHaoyuan Feng } 5195afdf73cSHaoyuan Feng io.out := out(n-1) 5205afdf73cSHaoyuan Feng } 5215afdf73cSHaoyuan Feng } 5225afdf73cSHaoyuan Feng} 5235afdf73cSHaoyuan Feng 5245afdf73cSHaoyuan Fengobject PTWDelayN { 5255afdf73cSHaoyuan Feng def apply[T <: Data](in: T, n: Int, flush: Bool): T = { 5265afdf73cSHaoyuan Feng val delay = Module(new PTWDelayN(in.cloneType, n, flush)) 5275afdf73cSHaoyuan Feng delay.io.in := in 5285afdf73cSHaoyuan Feng delay.io.ptwflush := flush 5295afdf73cSHaoyuan Feng delay.io.out 5305afdf73cSHaoyuan Feng } 5315afdf73cSHaoyuan Feng} 5325afdf73cSHaoyuan Feng 53392e3bfefSLemoverclass FakePTW()(implicit p: Parameters) extends XSModule with HasPtwConst { 53492e3bfefSLemover val io = IO(new L2TLBIO) 5355afdf73cSHaoyuan Feng val flush = VecInit(Seq.fill(PtwWidth)(false.B)) 5365afdf73cSHaoyuan Feng flush(0) := DelayN(io.sfence.valid || io.csr.tlb.satp.changed, itlbParams.fenceDelay) 5375afdf73cSHaoyuan Feng flush(1) := DelayN(io.sfence.valid || io.csr.tlb.satp.changed, ldtlbParams.fenceDelay) 53892e3bfefSLemover for (i <- 0 until PtwWidth) { 53992e3bfefSLemover val helper = Module(new PTEHelper()) 54092e3bfefSLemover helper.clock := clock 54192e3bfefSLemover helper.satp := io.csr.tlb.satp.ppn 5425afdf73cSHaoyuan Feng 5435afdf73cSHaoyuan Feng if (coreParams.softPTWDelay == 1) { 5445afdf73cSHaoyuan Feng helper.enable := io.tlb(i).req(0).fire 54592e3bfefSLemover helper.vpn := io.tlb(i).req(0).bits.vpn 5465afdf73cSHaoyuan Feng } else { 5475afdf73cSHaoyuan Feng helper.enable := PTWDelayN(io.tlb(i).req(0).fire, coreParams.softPTWDelay - 1, flush(i)) 5485afdf73cSHaoyuan Feng helper.vpn := PTWDelayN(io.tlb(i).req(0).bits.vpn, coreParams.softPTWDelay - 1, flush(i)) 5495afdf73cSHaoyuan Feng } 5505afdf73cSHaoyuan Feng 55192e3bfefSLemover val pte = helper.pte.asTypeOf(new PteBundle) 55292e3bfefSLemover val level = helper.level 55392e3bfefSLemover val pf = helper.pf 5545afdf73cSHaoyuan Feng val empty = RegInit(true.B) 5555afdf73cSHaoyuan Feng when (io.tlb(i).req(0).fire) { 5565afdf73cSHaoyuan Feng empty := false.B 5575afdf73cSHaoyuan Feng } .elsewhen (io.tlb(i).resp.fire || flush(i)) { 5585afdf73cSHaoyuan Feng empty := true.B 5595afdf73cSHaoyuan Feng } 56092e3bfefSLemover 5615afdf73cSHaoyuan Feng io.tlb(i).req(0).ready := empty || io.tlb(i).resp.fire 5625afdf73cSHaoyuan Feng io.tlb(i).resp.valid := PTWDelayN(io.tlb(i).req(0).fire, coreParams.softPTWDelay, flush(i)) 56392e3bfefSLemover assert(!io.tlb(i).resp.valid || io.tlb(i).resp.ready) 5645afdf73cSHaoyuan Feng io.tlb(i).resp.bits.entry.tag := PTWDelayN(io.tlb(i).req(0).bits.vpn, coreParams.softPTWDelay, flush(i)) 56592e3bfefSLemover io.tlb(i).resp.bits.entry.ppn := pte.ppn 56692e3bfefSLemover io.tlb(i).resp.bits.entry.perm.map(_ := pte.getPerm()) 56792e3bfefSLemover io.tlb(i).resp.bits.entry.level.map(_ := level) 56892e3bfefSLemover io.tlb(i).resp.bits.pf := pf 56992e3bfefSLemover io.tlb(i).resp.bits.af := DontCare // TODO: implement it 5705afdf73cSHaoyuan Feng io.tlb(i).resp.bits.entry.v := !pf 5715afdf73cSHaoyuan Feng io.tlb(i).resp.bits.entry.prefetch := DontCare 5725afdf73cSHaoyuan Feng io.tlb(i).resp.bits.entry.asid := io.csr.tlb.satp.asid 57392e3bfefSLemover } 57492e3bfefSLemover} 57592e3bfefSLemover 57692e3bfefSLemoverclass L2TLBWrapper()(implicit p: Parameters) extends LazyModule with HasXSParameter { 57792e3bfefSLemover val useSoftPTW = coreParams.softPTW 57892e3bfefSLemover val node = if (!useSoftPTW) TLIdentityNode() else null 57992e3bfefSLemover val ptw = if (!useSoftPTW) LazyModule(new L2TLB()) else null 58092e3bfefSLemover if (!useSoftPTW) { 58192e3bfefSLemover node := ptw.node 58292e3bfefSLemover } 58392e3bfefSLemover 58492e3bfefSLemover lazy val module = new LazyModuleImp(this) with HasPerfEvents { 58592e3bfefSLemover val io = IO(new L2TLBIO) 58692e3bfefSLemover val perfEvents = if (useSoftPTW) { 58792e3bfefSLemover val fake_ptw = Module(new FakePTW()) 58892e3bfefSLemover io <> fake_ptw.io 58992e3bfefSLemover Seq() 59092e3bfefSLemover } 59192e3bfefSLemover else { 59292e3bfefSLemover io <> ptw.module.io 59392e3bfefSLemover ptw.module.getPerfEvents 59492e3bfefSLemover } 59592e3bfefSLemover generatePerfEvent() 59692e3bfefSLemover } 59792e3bfefSLemover} 598