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._ 27*3c02ee8fSwakafaimport 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 32*3c02ee8fSwakafaimport utility.ChiselDB 3392e3bfefSLemover 3492e3bfefSLemoverclass L2TLB()(implicit p: Parameters) extends LazyModule with HasPtwConst { 3592e3bfefSLemover 3692e3bfefSLemover val node = TLClientNode(Seq(TLMasterPortParameters.v1( 3792e3bfefSLemover clients = Seq(TLMasterParameters.v1( 3892e3bfefSLemover "ptw", 3992e3bfefSLemover sourceId = IdRange(0, MemReqWidth) 4092e3bfefSLemover )) 4192e3bfefSLemover ))) 4292e3bfefSLemover 4392e3bfefSLemover lazy val module = new L2TLBImp(this) 4492e3bfefSLemover} 4592e3bfefSLemover 4692e3bfefSLemover@chiselName 4792e3bfefSLemoverclass L2TLBImp(outer: L2TLB)(implicit p: Parameters) extends PtwModule(outer) with HasCSRConst with HasPerfEvents { 4892e3bfefSLemover 4992e3bfefSLemover val (mem, edge) = outer.node.out.head 5092e3bfefSLemover 5192e3bfefSLemover val io = IO(new L2TLBIO) 5292e3bfefSLemover val difftestIO = IO(new Bundle() { 5392e3bfefSLemover val ptwResp = Output(Bool()) 5492e3bfefSLemover val ptwAddr = Output(UInt(64.W)) 5592e3bfefSLemover val ptwData = Output(Vec(4, UInt(64.W))) 5692e3bfefSLemover }) 5792e3bfefSLemover 5892e3bfefSLemover /* Ptw processes multiple requests 5992e3bfefSLemover * Divide Ptw procedure into two stages: cache access ; mem access if cache miss 6092e3bfefSLemover * miss queue itlb dtlb 6192e3bfefSLemover * | | | 6292e3bfefSLemover * ------arbiter------ 6392e3bfefSLemover * | 6492e3bfefSLemover * l1 - l2 - l3 - sp 6592e3bfefSLemover * | 6692e3bfefSLemover * ------------------------------------------- 6792e3bfefSLemover * miss | queue | hit 6892e3bfefSLemover * [][][][][][] | 6992e3bfefSLemover * | | 7092e3bfefSLemover * state machine accessing mem | 7192e3bfefSLemover * | | 7292e3bfefSLemover * ---------------arbiter--------------------- 7392e3bfefSLemover * | | 7492e3bfefSLemover * itlb dtlb 7592e3bfefSLemover */ 7692e3bfefSLemover 7792e3bfefSLemover difftestIO <> DontCare 7892e3bfefSLemover 797797f035SbugGenerator val sfence_tmp = DelayN(io.sfence, 1) 807797f035SbugGenerator val csr_tmp = DelayN(io.csr.tlb, 1) 817797f035SbugGenerator val sfence_dup = Seq.fill(8)(RegNext(sfence_tmp)) 827797f035SbugGenerator val csr_dup = Seq.fill(7)(RegNext(csr_tmp)) 837797f035SbugGenerator val satp = csr_dup(0).satp 847797f035SbugGenerator val priv = csr_dup(0).priv 857797f035SbugGenerator val flush = sfence_dup(0).valid || satp.changed 8692e3bfefSLemover 8792e3bfefSLemover val pmp = Module(new PMP()) 8892e3bfefSLemover val pmp_check = VecInit(Seq.fill(2)(Module(new PMPChecker(lgMaxSize = 3, sameCycle = true)).io)) 8992e3bfefSLemover pmp.io.distribute_csr := io.csr.distribute_csr 9092e3bfefSLemover pmp_check.foreach(_.check_env.apply(ModeS, pmp.io.pmp, pmp.io.pma)) 9192e3bfefSLemover 9292e3bfefSLemover val missQueue = Module(new L2TlbMissQueue) 9392e3bfefSLemover val cache = Module(new PtwCache) 9492e3bfefSLemover val ptw = Module(new PTW) 9592e3bfefSLemover val llptw = Module(new LLPTW) 967797f035SbugGenerator val blockmq = Module(new BlockHelper(3)) 9792e3bfefSLemover val arb1 = Module(new Arbiter(new PtwReq, PtwWidth)) 9892e3bfefSLemover val arb2 = Module(new Arbiter(new Bundle { 9992e3bfefSLemover val vpn = UInt(vpnLen.W) 10092e3bfefSLemover val source = UInt(bSourceWidth.W) 1019c503409SLemover }, if (l2tlbParams.enablePrefetch) 4 else 3)) 10292e3bfefSLemover val outArb = (0 until PtwWidth).map(i => Module(new Arbiter(new PtwResp, 3)).io) 10392e3bfefSLemover val outArbCachePort = 0 10492e3bfefSLemover val outArbFsmPort = 1 10592e3bfefSLemover val outArbMqPort = 2 10692e3bfefSLemover 1079c503409SLemover // arb2 input port 1089c503409SLemover val InArbPTWPort = 0 1099c503409SLemover val InArbMissQueuePort = 1 1109c503409SLemover val InArbTlbPort = 2 1119c503409SLemover val InArbPrefetchPort = 3 11292e3bfefSLemover // NOTE: when cache out but miss and ptw doesnt accept, 11392e3bfefSLemover arb1.io.in <> VecInit(io.tlb.map(_.req(0))) 1149c503409SLemover arb1.io.out.ready := arb2.io.in(InArbTlbPort).ready 11592e3bfefSLemover 1169c503409SLemover arb2.io.in(InArbPTWPort).valid := ptw.io.llptw.valid 1179c503409SLemover arb2.io.in(InArbPTWPort).bits.vpn := ptw.io.llptw.bits.req_info.vpn 1189c503409SLemover arb2.io.in(InArbPTWPort).bits.source := ptw.io.llptw.bits.req_info.source 1199c503409SLemover ptw.io.llptw.ready := arb2.io.in(InArbPTWPort).ready 12092e3bfefSLemover block_decoupled(missQueue.io.out, arb2.io.in(InArbMissQueuePort), !ptw.io.req.ready) 1217797f035SbugGenerator 12292e3bfefSLemover arb2.io.in(InArbTlbPort).valid := arb1.io.out.valid 12392e3bfefSLemover arb2.io.in(InArbTlbPort).bits.vpn := arb1.io.out.bits.vpn 12492e3bfefSLemover arb2.io.in(InArbTlbPort).bits.source := arb1.io.chosen 12592e3bfefSLemover if (l2tlbParams.enablePrefetch) { 12692e3bfefSLemover val prefetch = Module(new L2TlbPrefetch()) 12792e3bfefSLemover val recv = cache.io.resp 12892e3bfefSLemover // NOTE: 1. prefetch doesn't gen prefetch 2. req from mq doesn't gen prefetch 12992e3bfefSLemover // NOTE: 1. miss req gen prefetch 2. hit but prefetched gen prefetch 13092e3bfefSLemover prefetch.io.in.valid := recv.fire() && !from_pre(recv.bits.req_info.source) && (!recv.bits.hit || 13192e3bfefSLemover recv.bits.prefetch) && recv.bits.isFirst 13292e3bfefSLemover prefetch.io.in.bits.vpn := recv.bits.req_info.vpn 1337797f035SbugGenerator prefetch.io.sfence := sfence_dup(0) 1347797f035SbugGenerator prefetch.io.csr := csr_dup(0) 13592e3bfefSLemover arb2.io.in(InArbPrefetchPort) <> prefetch.io.out 1365afdf73cSHaoyuan Feng 1375afdf73cSHaoyuan Feng val L2TlbPrefetchTable = ChiselDB.createTable("L2TlbPrefetch_hart" + p(XSCoreParamsKey).HartId.toString, new L2TlbPrefetchDB) 1385afdf73cSHaoyuan Feng val L2TlbPrefetchDB = Wire(new L2TlbPrefetchDB) 1395afdf73cSHaoyuan Feng L2TlbPrefetchDB.vpn := prefetch.io.out.bits.vpn 1405afdf73cSHaoyuan Feng L2TlbPrefetchTable.log(L2TlbPrefetchDB, prefetch.io.out.fire, "L2TlbPrefetch", clock, reset) 14192e3bfefSLemover } 14292e3bfefSLemover arb2.io.out.ready := cache.io.req.ready 14392e3bfefSLemover 1447797f035SbugGenerator 1457797f035SbugGenerator val mq_arb = Module(new Arbiter(new L2TlbInnerBundle, 2)) 1467797f035SbugGenerator mq_arb.io.in(0).valid := cache.io.resp.valid && !cache.io.resp.bits.hit && 1477797f035SbugGenerator (!cache.io.resp.bits.toFsm.l2Hit || cache.io.resp.bits.bypassed) && 1487797f035SbugGenerator !from_pre(cache.io.resp.bits.req_info.source) && 1497797f035SbugGenerator (cache.io.resp.bits.bypassed || cache.io.resp.bits.isFirst || !ptw.io.req.ready) 1507797f035SbugGenerator mq_arb.io.in(0).bits := cache.io.resp.bits.req_info 1517797f035SbugGenerator mq_arb.io.in(1) <> llptw.io.cache 1527797f035SbugGenerator missQueue.io.in <> mq_arb.io.out 1537797f035SbugGenerator missQueue.io.sfence := sfence_dup(6) 1547797f035SbugGenerator missQueue.io.csr := csr_dup(5) 1557797f035SbugGenerator 1567797f035SbugGenerator blockmq.io.start := missQueue.io.out.fire 1577797f035SbugGenerator blockmq.io.enable := ptw.io.req.fire() 1587797f035SbugGenerator 1599c503409SLemover llptw.io.in.valid := cache.io.resp.valid && !cache.io.resp.bits.hit && cache.io.resp.bits.toFsm.l2Hit && !cache.io.resp.bits.bypassed 1609c503409SLemover llptw.io.in.bits.req_info := cache.io.resp.bits.req_info 1619c503409SLemover llptw.io.in.bits.ppn := cache.io.resp.bits.toFsm.ppn 1627797f035SbugGenerator llptw.io.sfence := sfence_dup(1) 1637797f035SbugGenerator llptw.io.csr := csr_dup(1) 16492e3bfefSLemover 16592e3bfefSLemover cache.io.req.valid := arb2.io.out.valid 16692e3bfefSLemover cache.io.req.bits.req_info.vpn := arb2.io.out.bits.vpn 16792e3bfefSLemover cache.io.req.bits.req_info.source := arb2.io.out.bits.source 16892e3bfefSLemover cache.io.req.bits.isFirst := arb2.io.chosen =/= InArbMissQueuePort.U 1691f4a7c0cSLemover cache.io.req.bits.bypassed.map(_ := false.B) 1707797f035SbugGenerator cache.io.sfence := sfence_dup(2) 1717797f035SbugGenerator cache.io.csr := csr_dup(2) 1727797f035SbugGenerator cache.io.sfence_dup.zip(sfence_dup.drop(2).take(4)).map(s => s._1 := s._2) 1737797f035SbugGenerator cache.io.csr_dup.zip(csr_dup.drop(2).take(3)).map(c => c._1 := c._2) 17492e3bfefSLemover cache.io.resp.ready := Mux(cache.io.resp.bits.hit, 17592e3bfefSLemover outReady(cache.io.resp.bits.req_info.source, outArbCachePort), 1769c503409SLemover Mux(cache.io.resp.bits.toFsm.l2Hit && !cache.io.resp.bits.bypassed, llptw.io.in.ready, 1777797f035SbugGenerator 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))) 17892e3bfefSLemover 17992e3bfefSLemover // NOTE: missQueue req has higher priority 1807797f035SbugGenerator ptw.io.req.valid := cache.io.resp.valid && !cache.io.resp.bits.hit && !cache.io.resp.bits.toFsm.l2Hit && 1817797f035SbugGenerator !cache.io.resp.bits.bypassed && 1827797f035SbugGenerator !cache.io.resp.bits.isFirst 18392e3bfefSLemover ptw.io.req.bits.req_info := cache.io.resp.bits.req_info 18492e3bfefSLemover ptw.io.req.bits.l1Hit := cache.io.resp.bits.toFsm.l1Hit 18592e3bfefSLemover ptw.io.req.bits.ppn := cache.io.resp.bits.toFsm.ppn 1867797f035SbugGenerator ptw.io.sfence := sfence_dup(7) 1877797f035SbugGenerator ptw.io.csr := csr_dup(6) 18892e3bfefSLemover ptw.io.resp.ready := outReady(ptw.io.resp.bits.source, outArbFsmPort) 18992e3bfefSLemover 19092e3bfefSLemover // mem req 19192e3bfefSLemover def blockBytes_align(addr: UInt) = { 19292e3bfefSLemover Cat(addr(PAddrBits - 1, log2Up(l2tlbParams.blockBytes)), 0.U(log2Up(l2tlbParams.blockBytes).W)) 19392e3bfefSLemover } 19492e3bfefSLemover def addr_low_from_vpn(vpn: UInt) = { 19592e3bfefSLemover vpn(log2Ceil(l2tlbParams.blockBytes)-log2Ceil(XLEN/8)-1, 0) 19692e3bfefSLemover } 19792e3bfefSLemover def addr_low_from_paddr(paddr: UInt) = { 19892e3bfefSLemover paddr(log2Up(l2tlbParams.blockBytes)-1, log2Up(XLEN/8)) 19992e3bfefSLemover } 20092e3bfefSLemover def from_missqueue(id: UInt) = { 20192e3bfefSLemover (id =/= l2tlbParams.llptwsize.U) 20292e3bfefSLemover } 20392e3bfefSLemover val waiting_resp = RegInit(VecInit(Seq.fill(MemReqWidth)(false.B))) 20492e3bfefSLemover val flush_latch = RegInit(VecInit(Seq.fill(MemReqWidth)(false.B))) 20592e3bfefSLemover for (i <- waiting_resp.indices) { 20692e3bfefSLemover assert(!flush_latch(i) || waiting_resp(i)) // when sfence_latch wait for mem resp, waiting_resp should be true 20792e3bfefSLemover } 20892e3bfefSLemover 20992e3bfefSLemover val llptw_out = llptw.io.out 21092e3bfefSLemover val llptw_mem = llptw.io.mem 21192e3bfefSLemover llptw_mem.req_mask := waiting_resp.take(l2tlbParams.llptwsize) 21292e3bfefSLemover ptw.io.mem.mask := waiting_resp.last 21392e3bfefSLemover 21492e3bfefSLemover val mem_arb = Module(new Arbiter(new L2TlbMemReqBundle(), 2)) 21592e3bfefSLemover mem_arb.io.in(0) <> ptw.io.mem.req 21692e3bfefSLemover mem_arb.io.in(1) <> llptw_mem.req 21792e3bfefSLemover mem_arb.io.out.ready := mem.a.ready && !flush 21892e3bfefSLemover 2191f4a7c0cSLemover // assert, should not send mem access at same addr for twice. 2207797f035SbugGenerator val last_resp_vpn = RegEnable(cache.io.refill.bits.req_info_dup(0).vpn, cache.io.refill.valid) 2217797f035SbugGenerator val last_resp_level = RegEnable(cache.io.refill.bits.level_dup(0), cache.io.refill.valid) 2221f4a7c0cSLemover val last_resp_v = RegInit(false.B) 2231f4a7c0cSLemover val last_has_invalid = !Cat(cache.io.refill.bits.ptes.asTypeOf(Vec(blockBits/XLEN, UInt(XLEN.W))).map(a => a(0))).andR 2241f4a7c0cSLemover when (cache.io.refill.valid) { last_resp_v := !last_has_invalid} 2251f4a7c0cSLemover when (flush) { last_resp_v := false.B } 2261f4a7c0cSLemover XSError(last_resp_v && cache.io.refill.valid && 2277797f035SbugGenerator (cache.io.refill.bits.req_info_dup(0).vpn === last_resp_vpn) && 2287797f035SbugGenerator (cache.io.refill.bits.level_dup(0) === last_resp_level), 2291f4a7c0cSLemover "l2tlb should not access mem at same addr for twice") 2301f4a7c0cSLemover // ATTENTION: this may wronngly assert when: a ptes is l2, last part is valid, 2311f4a7c0cSLemover // but the current part is invalid, so one more mem access happened 2321f4a7c0cSLemover // If this happened, remove the assert. 2331f4a7c0cSLemover 23492e3bfefSLemover val req_addr_low = Reg(Vec(MemReqWidth, UInt((log2Up(l2tlbParams.blockBytes)-log2Up(XLEN/8)).W))) 23592e3bfefSLemover 23692e3bfefSLemover when (llptw.io.in.fire()) { 23792e3bfefSLemover // when enq miss queue, set the req_addr_low to receive the mem resp data part 23892e3bfefSLemover req_addr_low(llptw_mem.enq_ptr) := addr_low_from_vpn(llptw.io.in.bits.req_info.vpn) 23992e3bfefSLemover } 24092e3bfefSLemover when (mem_arb.io.out.fire()) { 24192e3bfefSLemover req_addr_low(mem_arb.io.out.bits.id) := addr_low_from_paddr(mem_arb.io.out.bits.addr) 24292e3bfefSLemover waiting_resp(mem_arb.io.out.bits.id) := true.B 24392e3bfefSLemover } 24492e3bfefSLemover // mem read 24592e3bfefSLemover val memRead = edge.Get( 24692e3bfefSLemover fromSource = mem_arb.io.out.bits.id, 24792e3bfefSLemover // toAddress = memAddr(log2Up(CacheLineSize / 2 / 8) - 1, 0), 24892e3bfefSLemover toAddress = blockBytes_align(mem_arb.io.out.bits.addr), 24992e3bfefSLemover lgSize = log2Up(l2tlbParams.blockBytes).U 25092e3bfefSLemover )._2 25192e3bfefSLemover mem.a.bits := memRead 25292e3bfefSLemover mem.a.valid := mem_arb.io.out.valid && !flush 25392e3bfefSLemover mem.d.ready := true.B 25492e3bfefSLemover // mem -> data buffer 25592e3bfefSLemover val refill_data = Reg(Vec(blockBits / l1BusDataWidth, UInt(l1BusDataWidth.W))) 25692e3bfefSLemover val refill_helper = edge.firstlastHelper(mem.d.bits, mem.d.fire()) 25792e3bfefSLemover val mem_resp_done = refill_helper._3 25892e3bfefSLemover val mem_resp_from_mq = from_missqueue(mem.d.bits.source) 25992e3bfefSLemover when (mem.d.valid) { 26092e3bfefSLemover assert(mem.d.bits.source <= l2tlbParams.llptwsize.U) 26192e3bfefSLemover refill_data(refill_helper._4) := mem.d.bits.data 26292e3bfefSLemover } 2637797f035SbugGenerator // refill_data_tmp is the wire fork of refill_data, but one cycle earlier 2647797f035SbugGenerator val refill_data_tmp = WireInit(refill_data) 2657797f035SbugGenerator refill_data_tmp(refill_helper._4) := mem.d.bits.data 2667797f035SbugGenerator 26792e3bfefSLemover // save only one pte for each id 26892e3bfefSLemover // (miss queue may can't resp to tlb with low latency, it should have highest priority, but diffcult to design cache) 26992e3bfefSLemover val resp_pte = VecInit((0 until MemReqWidth).map(i => 2707797f035SbugGenerator if (i == l2tlbParams.llptwsize) {RegEnable(get_part(refill_data_tmp, req_addr_low(i)), mem_resp_done && !mem_resp_from_mq) } 27192e3bfefSLemover else { DataHoldBypass(get_part(refill_data, req_addr_low(i)), llptw_mem.buffer_it(i)) } 2727797f035SbugGenerator // llptw could not use refill_data_tmp, because enq bypass's result works at next cycle 27392e3bfefSLemover )) 27492e3bfefSLemover 27592e3bfefSLemover // mem -> miss queue 27692e3bfefSLemover llptw_mem.resp.valid := mem_resp_done && mem_resp_from_mq 2777797f035SbugGenerator llptw_mem.resp.bits.id := DataHoldBypass(mem.d.bits.source, mem.d.valid) 27892e3bfefSLemover // mem -> ptw 27992e3bfefSLemover ptw.io.mem.req.ready := mem.a.ready 28092e3bfefSLemover ptw.io.mem.resp.valid := mem_resp_done && !mem_resp_from_mq 28192e3bfefSLemover ptw.io.mem.resp.bits := resp_pte.last 28292e3bfefSLemover // mem -> cache 2837797f035SbugGenerator val refill_from_mq = mem_resp_from_mq 2847797f035SbugGenerator val refill_level = Mux(refill_from_mq, 2.U, RegEnable(ptw.io.refill.level, init = 0.U, ptw.io.mem.req.fire())) 2857797f035SbugGenerator val refill_valid = mem_resp_done && !flush && !flush_latch(mem.d.bits.source) 2867797f035SbugGenerator 2877797f035SbugGenerator cache.io.refill.valid := RegNext(refill_valid, false.B) 28892e3bfefSLemover cache.io.refill.bits.ptes := refill_data.asUInt 2897797f035SbugGenerator cache.io.refill.bits.req_info_dup.map(_ := RegEnable(Mux(refill_from_mq, llptw_mem.refill, ptw.io.refill.req_info), refill_valid)) 2907797f035SbugGenerator cache.io.refill.bits.level_dup.map(_ := RegEnable(refill_level, refill_valid)) 2917797f035SbugGenerator cache.io.refill.bits.levelOH(refill_level, refill_valid) 2927797f035SbugGenerator cache.io.refill.bits.sel_pte_dup.map(_ := RegNext(sel_data(refill_data_tmp.asUInt, req_addr_low(mem.d.bits.source)))) 29392e3bfefSLemover 29492e3bfefSLemover // pmp 29592e3bfefSLemover pmp_check(0).req <> ptw.io.pmp.req 29692e3bfefSLemover ptw.io.pmp.resp <> pmp_check(0).resp 29792e3bfefSLemover pmp_check(1).req <> llptw.io.pmp.req 29892e3bfefSLemover llptw.io.pmp.resp <> pmp_check(1).resp 29992e3bfefSLemover 30092e3bfefSLemover llptw_out.ready := outReady(llptw_out.bits.req_info.source, outArbMqPort) 30192e3bfefSLemover for (i <- 0 until PtwWidth) { 30292e3bfefSLemover outArb(i).in(outArbCachePort).valid := cache.io.resp.valid && cache.io.resp.bits.hit && cache.io.resp.bits.req_info.source===i.U 30392e3bfefSLemover outArb(i).in(outArbCachePort).bits.entry := cache.io.resp.bits.toTlb 30492e3bfefSLemover outArb(i).in(outArbCachePort).bits.pf := !cache.io.resp.bits.toTlb.v 30592e3bfefSLemover outArb(i).in(outArbCachePort).bits.af := false.B 30692e3bfefSLemover outArb(i).in(outArbFsmPort).valid := ptw.io.resp.valid && ptw.io.resp.bits.source===i.U 30792e3bfefSLemover outArb(i).in(outArbFsmPort).bits := ptw.io.resp.bits.resp 30892e3bfefSLemover outArb(i).in(outArbMqPort).valid := llptw_out.valid && llptw_out.bits.req_info.source===i.U 30992e3bfefSLemover 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) 31092e3bfefSLemover } 31192e3bfefSLemover 31292e3bfefSLemover // io.tlb.map(_.resp) <> outArb.map(_.out) 31392e3bfefSLemover io.tlb.map(_.resp).zip(outArb.map(_.out)).map{ 31492e3bfefSLemover case (resp, out) => resp <> out 31592e3bfefSLemover } 31692e3bfefSLemover 31792e3bfefSLemover // sfence 31892e3bfefSLemover when (flush) { 31992e3bfefSLemover for (i <- 0 until MemReqWidth) { 32092e3bfefSLemover when (waiting_resp(i)) { 32192e3bfefSLemover flush_latch(i) := true.B 32292e3bfefSLemover } 32392e3bfefSLemover } 32492e3bfefSLemover } 32592e3bfefSLemover // mem -> control signal 32692e3bfefSLemover // waiting_resp and sfence_latch will be reset when mem_resp_done 32792e3bfefSLemover when (mem_resp_done) { 32892e3bfefSLemover waiting_resp(mem.d.bits.source) := false.B 32992e3bfefSLemover flush_latch(mem.d.bits.source) := false.B 33092e3bfefSLemover } 33192e3bfefSLemover 33292e3bfefSLemover def block_decoupled[T <: Data](source: DecoupledIO[T], sink: DecoupledIO[T], block_signal: Bool) = { 33392e3bfefSLemover sink.valid := source.valid && !block_signal 33492e3bfefSLemover source.ready := sink.ready && !block_signal 33592e3bfefSLemover sink.bits := source.bits 33692e3bfefSLemover } 33792e3bfefSLemover 33892e3bfefSLemover def get_part(data: Vec[UInt], index: UInt): UInt = { 33992e3bfefSLemover val inner_data = data.asTypeOf(Vec(data.getWidth / XLEN, UInt(XLEN.W))) 34092e3bfefSLemover inner_data(index) 34192e3bfefSLemover } 34292e3bfefSLemover 34392e3bfefSLemover def pte_to_ptwResp(pte: UInt, vpn: UInt, af: Bool, af_first: Boolean) : PtwResp = { 34492e3bfefSLemover val pte_in = pte.asTypeOf(new PteBundle()) 34592e3bfefSLemover val ptw_resp = Wire(new PtwResp()) 34692e3bfefSLemover ptw_resp.entry.ppn := pte_in.ppn 34792e3bfefSLemover ptw_resp.entry.level.map(_ := 2.U) 34892e3bfefSLemover ptw_resp.entry.perm.map(_ := pte_in.getPerm()) 34992e3bfefSLemover ptw_resp.entry.tag := vpn 35092e3bfefSLemover ptw_resp.pf := (if (af_first) !af else true.B) && pte_in.isPf(2.U) 35192e3bfefSLemover ptw_resp.af := (if (!af_first) pte_in.isPf(2.U) else true.B) && af 35292e3bfefSLemover ptw_resp.entry.v := !ptw_resp.pf 35392e3bfefSLemover ptw_resp.entry.prefetch := DontCare 35492e3bfefSLemover ptw_resp.entry.asid := satp.asid 35592e3bfefSLemover ptw_resp 35692e3bfefSLemover } 35792e3bfefSLemover 35892e3bfefSLemover def outReady(source: UInt, port: Int): Bool = { 35992e3bfefSLemover MuxLookup(source, true.B, 36092e3bfefSLemover (0 until PtwWidth).map(i => i.U -> outArb(i).in(port).ready)) 36192e3bfefSLemover } 36292e3bfefSLemover 36392e3bfefSLemover // debug info 36492e3bfefSLemover for (i <- 0 until PtwWidth) { 36592e3bfefSLemover XSDebug(p"[io.tlb(${i.U})] ${io.tlb(i)}\n") 36692e3bfefSLemover } 3677797f035SbugGenerator XSDebug(p"[sfence] ${io.sfence}\n") 36892e3bfefSLemover XSDebug(p"[io.csr.tlb] ${io.csr.tlb}\n") 36992e3bfefSLemover 37092e3bfefSLemover for (i <- 0 until PtwWidth) { 37192e3bfefSLemover XSPerfAccumulate(s"req_count${i}", io.tlb(i).req(0).fire()) 37292e3bfefSLemover XSPerfAccumulate(s"req_blocked_count_${i}", io.tlb(i).req(0).valid && !io.tlb(i).req(0).ready) 37392e3bfefSLemover } 37492e3bfefSLemover XSPerfAccumulate(s"req_blocked_by_mq", arb1.io.out.valid && missQueue.io.out.valid) 37592e3bfefSLemover for (i <- 0 until (MemReqWidth + 1)) { 37692e3bfefSLemover XSPerfAccumulate(s"mem_req_util${i}", PopCount(waiting_resp) === i.U) 37792e3bfefSLemover } 37892e3bfefSLemover XSPerfAccumulate("mem_cycle", PopCount(waiting_resp) =/= 0.U) 37992e3bfefSLemover XSPerfAccumulate("mem_count", mem.a.fire()) 38092e3bfefSLemover 38192e3bfefSLemover // print configs 382f1fe8698SLemover 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}") 38392e3bfefSLemover 38492e3bfefSLemover // time out assert 38592e3bfefSLemover for (i <- 0 until MemReqWidth) { 38692e3bfefSLemover TimeOutAssert(waiting_resp(i), timeOutThreshold, s"ptw mem resp time out wait_resp${i}") 38792e3bfefSLemover TimeOutAssert(flush_latch(i), timeOutThreshold, s"ptw mem resp time out flush_latch${i}") 38892e3bfefSLemover } 38992e3bfefSLemover 39092e3bfefSLemover 39192e3bfefSLemover val perfEvents = Seq(llptw, cache, ptw).flatMap(_.getPerfEvents) 39292e3bfefSLemover generatePerfEvent() 3935afdf73cSHaoyuan Feng 3945afdf73cSHaoyuan Feng val L1TlbTable = ChiselDB.createTable("L1Tlb_hart" + p(XSCoreParamsKey).HartId.toString, new L1TlbDB) 3955afdf73cSHaoyuan Feng val ITlbReqDB, DTlbReqDB, ITlbRespDB, DTlbRespDB = Wire(new L1TlbDB) 3965afdf73cSHaoyuan Feng ITlbReqDB.vpn := io.tlb(0).req(0).bits.vpn 3975afdf73cSHaoyuan Feng DTlbReqDB.vpn := io.tlb(1).req(0).bits.vpn 3985afdf73cSHaoyuan Feng ITlbRespDB.vpn := io.tlb(0).resp.bits.entry.tag 3995afdf73cSHaoyuan Feng DTlbRespDB.vpn := io.tlb(1).resp.bits.entry.tag 4005afdf73cSHaoyuan Feng L1TlbTable.log(ITlbReqDB, io.tlb(0).req(0).fire, "ITlbReq", clock, reset) 4015afdf73cSHaoyuan Feng L1TlbTable.log(DTlbReqDB, io.tlb(1).req(0).fire, "DTlbReq", clock, reset) 4025afdf73cSHaoyuan Feng L1TlbTable.log(ITlbRespDB, io.tlb(0).resp.fire, "ITlbResp", clock, reset) 4035afdf73cSHaoyuan Feng L1TlbTable.log(DTlbRespDB, io.tlb(1).resp.fire, "DTlbResp", clock, reset) 4045afdf73cSHaoyuan Feng 4055afdf73cSHaoyuan Feng val PageCacheTable = ChiselDB.createTable("PageCache_hart" + p(XSCoreParamsKey).HartId.toString, new PageCacheDB) 4065afdf73cSHaoyuan Feng val PageCacheDB = Wire(new PageCacheDB) 4075afdf73cSHaoyuan Feng PageCacheDB.vpn := cache.io.resp.bits.toTlb.tag 4085afdf73cSHaoyuan Feng PageCacheDB.source := cache.io.resp.bits.req_info.source 4095afdf73cSHaoyuan Feng PageCacheDB.bypassed := cache.io.resp.bits.bypassed 4105afdf73cSHaoyuan Feng PageCacheDB.is_first := cache.io.resp.bits.isFirst 4115afdf73cSHaoyuan Feng PageCacheDB.prefetched := cache.io.resp.bits.toTlb.prefetch 4125afdf73cSHaoyuan Feng PageCacheDB.prefetch := cache.io.resp.bits.prefetch 4135afdf73cSHaoyuan Feng PageCacheDB.l2Hit := cache.io.resp.bits.toFsm.l2Hit 4145afdf73cSHaoyuan Feng PageCacheDB.l1Hit := cache.io.resp.bits.toFsm.l1Hit 4155afdf73cSHaoyuan Feng PageCacheDB.hit := cache.io.resp.bits.hit 4165afdf73cSHaoyuan Feng PageCacheTable.log(PageCacheDB, cache.io.resp.fire, "PageCache", clock, reset) 4175afdf73cSHaoyuan Feng 4185afdf73cSHaoyuan Feng val PTWTable = ChiselDB.createTable("PTW_hart" + p(XSCoreParamsKey).HartId.toString, new PTWDB) 4195afdf73cSHaoyuan Feng val PTWReqDB, PTWRespDB, LLPTWReqDB, LLPTWRespDB = Wire(new PTWDB) 4205afdf73cSHaoyuan Feng PTWReqDB.vpn := ptw.io.req.bits.req_info.vpn 4215afdf73cSHaoyuan Feng PTWReqDB.source := ptw.io.req.bits.req_info.source 4225afdf73cSHaoyuan Feng PTWRespDB.vpn := ptw.io.refill.req_info.vpn 4235afdf73cSHaoyuan Feng PTWRespDB.source := ptw.io.refill.req_info.source 4245afdf73cSHaoyuan Feng LLPTWReqDB.vpn := llptw.io.in.bits.req_info.vpn 4255afdf73cSHaoyuan Feng LLPTWReqDB.source := llptw.io.in.bits.req_info.source 4265afdf73cSHaoyuan Feng LLPTWRespDB.vpn := llptw.io.mem.refill.vpn 4275afdf73cSHaoyuan Feng LLPTWRespDB.source := llptw.io.mem.refill.source 4285afdf73cSHaoyuan Feng PTWTable.log(PTWReqDB, ptw.io.req.fire, "PTWReq", clock, reset) 4295afdf73cSHaoyuan Feng PTWTable.log(PTWRespDB, ptw.io.mem.resp.fire, "PTWResp", clock, reset) 4305afdf73cSHaoyuan Feng PTWTable.log(LLPTWReqDB, llptw.io.in.fire, "LLPTWReq", clock, reset) 4315afdf73cSHaoyuan Feng PTWTable.log(LLPTWRespDB, llptw.io.mem.resp.fire, "LLPTWResp", clock, reset) 4325afdf73cSHaoyuan Feng 4335afdf73cSHaoyuan Feng val L2TlbMissQueueTable = ChiselDB.createTable("L2TlbMissQueue_hart" + p(XSCoreParamsKey).HartId.toString, new L2TlbMissQueueDB) 4345afdf73cSHaoyuan Feng val L2TlbMissQueueInDB, L2TlbMissQueueOutDB = Wire(new L2TlbMissQueueDB) 4355afdf73cSHaoyuan Feng L2TlbMissQueueInDB.vpn := missQueue.io.in.bits.vpn 4365afdf73cSHaoyuan Feng L2TlbMissQueueOutDB.vpn := missQueue.io.out.bits.vpn 4375afdf73cSHaoyuan Feng L2TlbMissQueueTable.log(L2TlbMissQueueInDB, missQueue.io.in.fire, "L2TlbMissQueueIn", clock, reset) 4385afdf73cSHaoyuan Feng L2TlbMissQueueTable.log(L2TlbMissQueueOutDB, missQueue.io.out.fire, "L2TlbMissQueueOut", clock, reset) 43992e3bfefSLemover} 44092e3bfefSLemover 4417797f035SbugGenerator/** BlockHelper, block missqueue, not to send too many req to cache 4427797f035SbugGenerator * Parameter: 4437797f035SbugGenerator * enable: enable BlockHelper, mq should not send too many reqs 4447797f035SbugGenerator * start: when miss queue out fire and need, block miss queue's out 4457797f035SbugGenerator * block: block miss queue's out 4467797f035SbugGenerator * latency: last missqueue out's cache access latency 4477797f035SbugGenerator */ 4487797f035SbugGeneratorclass BlockHelper(latency: Int)(implicit p: Parameters) extends XSModule { 4497797f035SbugGenerator val io = IO(new Bundle { 4507797f035SbugGenerator val enable = Input(Bool()) 4517797f035SbugGenerator val start = Input(Bool()) 4527797f035SbugGenerator val block = Output(Bool()) 4537797f035SbugGenerator }) 4547797f035SbugGenerator 4557797f035SbugGenerator val count = RegInit(0.U(log2Ceil(latency).W)) 4567797f035SbugGenerator val valid = RegInit(false.B) 4577797f035SbugGenerator val work = RegInit(true.B) 4587797f035SbugGenerator 4597797f035SbugGenerator io.block := valid 4607797f035SbugGenerator 4617797f035SbugGenerator when (io.start && work) { valid := true.B } 4627797f035SbugGenerator when (valid) { count := count + 1.U } 4637797f035SbugGenerator when (count === (latency.U) || io.enable) { 4647797f035SbugGenerator valid := false.B 4657797f035SbugGenerator work := io.enable 4667797f035SbugGenerator count := 0.U 4677797f035SbugGenerator } 4687797f035SbugGenerator} 4697797f035SbugGenerator 47092e3bfefSLemoverclass PTEHelper() extends ExtModule { 47192e3bfefSLemover val clock = IO(Input(Clock())) 47292e3bfefSLemover val enable = IO(Input(Bool())) 47392e3bfefSLemover val satp = IO(Input(UInt(64.W))) 47492e3bfefSLemover val vpn = IO(Input(UInt(64.W))) 47592e3bfefSLemover val pte = IO(Output(UInt(64.W))) 47692e3bfefSLemover val level = IO(Output(UInt(8.W))) 47792e3bfefSLemover val pf = IO(Output(UInt(8.W))) 47892e3bfefSLemover} 47992e3bfefSLemover 4805afdf73cSHaoyuan Fengclass PTWDelayN[T <: Data](gen: T, n: Int, flush: Bool) extends Module { 4815afdf73cSHaoyuan Feng val io = IO(new Bundle() { 4825afdf73cSHaoyuan Feng val in = Input(gen) 4835afdf73cSHaoyuan Feng val out = Output(gen) 4845afdf73cSHaoyuan Feng val ptwflush = Input(flush.cloneType) 4855afdf73cSHaoyuan Feng }) 4865afdf73cSHaoyuan Feng val out = RegInit(VecInit(Seq.fill(n)(0.U.asTypeOf(gen)))) 4875afdf73cSHaoyuan Feng val t = RegInit(VecInit(Seq.fill(n)(0.U.asTypeOf(gen)))) 4885afdf73cSHaoyuan Feng out(0) := io.in 4895afdf73cSHaoyuan Feng if (n == 1) { 4905afdf73cSHaoyuan Feng io.out := out(0) 4915afdf73cSHaoyuan Feng } else { 4925afdf73cSHaoyuan Feng when (io.ptwflush) { 4935afdf73cSHaoyuan Feng for (i <- 0 until n) { 4945afdf73cSHaoyuan Feng t(i) := 0.U.asTypeOf(gen) 4955afdf73cSHaoyuan Feng out(i) := 0.U.asTypeOf(gen) 4965afdf73cSHaoyuan Feng } 4975afdf73cSHaoyuan Feng io.out := 0.U.asTypeOf(gen) 4985afdf73cSHaoyuan Feng } .otherwise { 4995afdf73cSHaoyuan Feng for (i <- 1 until n) { 5005afdf73cSHaoyuan Feng t(i-1) := out(i-1) 5015afdf73cSHaoyuan Feng out(i) := t(i-1) 5025afdf73cSHaoyuan Feng } 5035afdf73cSHaoyuan Feng io.out := out(n-1) 5045afdf73cSHaoyuan Feng } 5055afdf73cSHaoyuan Feng } 5065afdf73cSHaoyuan Feng} 5075afdf73cSHaoyuan Feng 5085afdf73cSHaoyuan Fengobject PTWDelayN { 5095afdf73cSHaoyuan Feng def apply[T <: Data](in: T, n: Int, flush: Bool): T = { 5105afdf73cSHaoyuan Feng val delay = Module(new PTWDelayN(in.cloneType, n, flush)) 5115afdf73cSHaoyuan Feng delay.io.in := in 5125afdf73cSHaoyuan Feng delay.io.ptwflush := flush 5135afdf73cSHaoyuan Feng delay.io.out 5145afdf73cSHaoyuan Feng } 5155afdf73cSHaoyuan Feng} 5165afdf73cSHaoyuan Feng 51792e3bfefSLemoverclass FakePTW()(implicit p: Parameters) extends XSModule with HasPtwConst { 51892e3bfefSLemover val io = IO(new L2TLBIO) 5195afdf73cSHaoyuan Feng val flush = VecInit(Seq.fill(PtwWidth)(false.B)) 5205afdf73cSHaoyuan Feng flush(0) := DelayN(io.sfence.valid || io.csr.tlb.satp.changed, itlbParams.fenceDelay) 5215afdf73cSHaoyuan Feng flush(1) := DelayN(io.sfence.valid || io.csr.tlb.satp.changed, ldtlbParams.fenceDelay) 52292e3bfefSLemover for (i <- 0 until PtwWidth) { 52392e3bfefSLemover val helper = Module(new PTEHelper()) 52492e3bfefSLemover helper.clock := clock 52592e3bfefSLemover helper.satp := io.csr.tlb.satp.ppn 5265afdf73cSHaoyuan Feng 5275afdf73cSHaoyuan Feng if (coreParams.softPTWDelay == 1) { 5285afdf73cSHaoyuan Feng helper.enable := io.tlb(i).req(0).fire 52992e3bfefSLemover helper.vpn := io.tlb(i).req(0).bits.vpn 5305afdf73cSHaoyuan Feng } else { 5315afdf73cSHaoyuan Feng helper.enable := PTWDelayN(io.tlb(i).req(0).fire, coreParams.softPTWDelay - 1, flush(i)) 5325afdf73cSHaoyuan Feng helper.vpn := PTWDelayN(io.tlb(i).req(0).bits.vpn, coreParams.softPTWDelay - 1, flush(i)) 5335afdf73cSHaoyuan Feng } 5345afdf73cSHaoyuan Feng 53592e3bfefSLemover val pte = helper.pte.asTypeOf(new PteBundle) 53692e3bfefSLemover val level = helper.level 53792e3bfefSLemover val pf = helper.pf 5385afdf73cSHaoyuan Feng val empty = RegInit(true.B) 5395afdf73cSHaoyuan Feng when (io.tlb(i).req(0).fire) { 5405afdf73cSHaoyuan Feng empty := false.B 5415afdf73cSHaoyuan Feng } .elsewhen (io.tlb(i).resp.fire || flush(i)) { 5425afdf73cSHaoyuan Feng empty := true.B 5435afdf73cSHaoyuan Feng } 54492e3bfefSLemover 5455afdf73cSHaoyuan Feng io.tlb(i).req(0).ready := empty || io.tlb(i).resp.fire 5465afdf73cSHaoyuan Feng io.tlb(i).resp.valid := PTWDelayN(io.tlb(i).req(0).fire, coreParams.softPTWDelay, flush(i)) 54792e3bfefSLemover assert(!io.tlb(i).resp.valid || io.tlb(i).resp.ready) 5485afdf73cSHaoyuan Feng io.tlb(i).resp.bits.entry.tag := PTWDelayN(io.tlb(i).req(0).bits.vpn, coreParams.softPTWDelay, flush(i)) 54992e3bfefSLemover io.tlb(i).resp.bits.entry.ppn := pte.ppn 55092e3bfefSLemover io.tlb(i).resp.bits.entry.perm.map(_ := pte.getPerm()) 55192e3bfefSLemover io.tlb(i).resp.bits.entry.level.map(_ := level) 55292e3bfefSLemover io.tlb(i).resp.bits.pf := pf 55392e3bfefSLemover io.tlb(i).resp.bits.af := DontCare // TODO: implement it 5545afdf73cSHaoyuan Feng io.tlb(i).resp.bits.entry.v := !pf 5555afdf73cSHaoyuan Feng io.tlb(i).resp.bits.entry.prefetch := DontCare 5565afdf73cSHaoyuan Feng io.tlb(i).resp.bits.entry.asid := io.csr.tlb.satp.asid 55792e3bfefSLemover } 55892e3bfefSLemover} 55992e3bfefSLemover 56092e3bfefSLemoverclass L2TLBWrapper()(implicit p: Parameters) extends LazyModule with HasXSParameter { 56192e3bfefSLemover val useSoftPTW = coreParams.softPTW 56292e3bfefSLemover val node = if (!useSoftPTW) TLIdentityNode() else null 56392e3bfefSLemover val ptw = if (!useSoftPTW) LazyModule(new L2TLB()) else null 56492e3bfefSLemover if (!useSoftPTW) { 56592e3bfefSLemover node := ptw.node 56692e3bfefSLemover } 56792e3bfefSLemover 56892e3bfefSLemover lazy val module = new LazyModuleImp(this) with HasPerfEvents { 56992e3bfefSLemover val io = IO(new L2TLBIO) 57092e3bfefSLemover val perfEvents = if (useSoftPTW) { 57192e3bfefSLemover val fake_ptw = Module(new FakePTW()) 57292e3bfefSLemover io <> fake_ptw.io 57392e3bfefSLemover Seq() 57492e3bfefSLemover } 57592e3bfefSLemover else { 57692e3bfefSLemover io <> ptw.module.io 57792e3bfefSLemover ptw.module.getPerfEvents 57892e3bfefSLemover } 57992e3bfefSLemover generatePerfEvent() 58092e3bfefSLemover } 58192e3bfefSLemover} 582