1*6d5ddbceSLemover/*************************************************************************************** 2*6d5ddbceSLemover* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences 3*6d5ddbceSLemover* 4*6d5ddbceSLemover* XiangShan is licensed under Mulan PSL v2. 5*6d5ddbceSLemover* You can use this software according to the terms and conditions of the Mulan PSL v2. 6*6d5ddbceSLemover* You may obtain a copy of Mulan PSL v2 at: 7*6d5ddbceSLemover* http://license.coscl.org.cn/MulanPSL2 8*6d5ddbceSLemover* 9*6d5ddbceSLemover* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10*6d5ddbceSLemover* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11*6d5ddbceSLemover* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12*6d5ddbceSLemover* 13*6d5ddbceSLemover* See the Mulan PSL v2 for more details. 14*6d5ddbceSLemover***************************************************************************************/ 15*6d5ddbceSLemover 16*6d5ddbceSLemoverpackage xiangshan.cache.mmu 17*6d5ddbceSLemover 18*6d5ddbceSLemoverimport chipsalliance.rocketchip.config.Parameters 19*6d5ddbceSLemoverimport chisel3._ 20*6d5ddbceSLemoverimport chisel3.util._ 21*6d5ddbceSLemoverimport xiangshan._ 22*6d5ddbceSLemoverimport xiangshan.cache.{HasDCacheParameters, MemoryOpConstants} 23*6d5ddbceSLemoverimport utils._ 24*6d5ddbceSLemoverimport freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp} 25*6d5ddbceSLemoverimport freechips.rocketchip.tilelink._ 26*6d5ddbceSLemover 27*6d5ddbceSLemover/* ptw finite state machine, the actual page table walker 28*6d5ddbceSLemover */ 29*6d5ddbceSLemoverclass PtwFsmIO()(implicit p: Parameters) extends PtwBundle { 30*6d5ddbceSLemover val req = Flipped(DecoupledIO(new Bundle { 31*6d5ddbceSLemover val source = UInt(bPtwWidth.W) 32*6d5ddbceSLemover val l1Hit = Bool() 33*6d5ddbceSLemover val l2Hit = Bool() 34*6d5ddbceSLemover val vpn = UInt(vpnLen.W) 35*6d5ddbceSLemover val ppn = UInt(ppnLen.W) 36*6d5ddbceSLemover })) 37*6d5ddbceSLemover val resp = DecoupledIO(new Bundle { 38*6d5ddbceSLemover val source = UInt(bPtwWidth.W) 39*6d5ddbceSLemover val resp = new PtwResp 40*6d5ddbceSLemover }) 41*6d5ddbceSLemover 42*6d5ddbceSLemover val mem = new Bundle { 43*6d5ddbceSLemover val req = DecoupledIO(new Bundle { 44*6d5ddbceSLemover val addr = UInt(PAddrBits.W) 45*6d5ddbceSLemover }) 46*6d5ddbceSLemover val resp = Flipped(ValidIO(new Bundle { 47*6d5ddbceSLemover val data = UInt(MemBandWidth.W) 48*6d5ddbceSLemover })) 49*6d5ddbceSLemover } 50*6d5ddbceSLemover 51*6d5ddbceSLemover val csr = Input(new TlbCsrBundle) 52*6d5ddbceSLemover val sfence = Input(new SfenceBundle) 53*6d5ddbceSLemover val sfenceLatch = Output(Bool()) 54*6d5ddbceSLemover val refill = Output(new Bundle { 55*6d5ddbceSLemover val vpn = UInt(vpnLen.W) 56*6d5ddbceSLemover val level = UInt(log2Up(Level).W) 57*6d5ddbceSLemover val memAddr = UInt(PAddrBits.W) 58*6d5ddbceSLemover }) 59*6d5ddbceSLemover} 60*6d5ddbceSLemover 61*6d5ddbceSLemoverclass PtwFsm()(implicit p: Parameters) extends XSModule with HasPtwConst { 62*6d5ddbceSLemover val io = IO(new PtwFsmIO) 63*6d5ddbceSLemover 64*6d5ddbceSLemover val sfence = io.sfence 65*6d5ddbceSLemover val mem = io.mem 66*6d5ddbceSLemover val satp = io.csr.satp 67*6d5ddbceSLemover 68*6d5ddbceSLemover val s_idle :: s_mem_req :: s_mem_resp :: s_resp :: Nil = Enum(4) 69*6d5ddbceSLemover val state = RegInit(s_idle) 70*6d5ddbceSLemover val level = RegInit(0.U(log2Up(Level).W)) 71*6d5ddbceSLemover val ppn = Reg(UInt(ppnLen.W)) 72*6d5ddbceSLemover val vpn = Reg(UInt(vpnLen.W)) 73*6d5ddbceSLemover val levelNext = level + 1.U 74*6d5ddbceSLemover 75*6d5ddbceSLemover val sfenceLatch = RegEnable(false.B, init = false.B, mem.resp.valid) // NOTE: store sfence to disable mem.resp.fire(), but not stall other ptw req 76*6d5ddbceSLemover val memAddrReg = RegEnable(mem.req.bits.addr, mem.req.fire()) 77*6d5ddbceSLemover val l1Hit = Reg(Bool()) 78*6d5ddbceSLemover val l2Hit = Reg(Bool()) 79*6d5ddbceSLemover 80*6d5ddbceSLemover val memRdata = mem.resp.bits.data 81*6d5ddbceSLemover val memSelData = memRdata.asTypeOf(Vec(MemBandWidth/XLEN, UInt(XLEN.W)))(memAddrReg(log2Up(l1BusDataWidth/8) - 1, log2Up(XLEN/8))) 82*6d5ddbceSLemover val memPtes = (0 until PtwL3SectorSize).map(i => memRdata((i+1)*XLEN-1, i*XLEN).asTypeOf(new PteBundle)) 83*6d5ddbceSLemover val memPte = memSelData.asTypeOf(new PteBundle) 84*6d5ddbceSLemover val memPteReg = RegEnable(memPte, mem.resp.fire()) 85*6d5ddbceSLemover 86*6d5ddbceSLemover val notFound = WireInit(false.B) 87*6d5ddbceSLemover switch (state) { 88*6d5ddbceSLemover is (s_idle) { 89*6d5ddbceSLemover when (io.req.fire()) { 90*6d5ddbceSLemover val req = io.req.bits 91*6d5ddbceSLemover state := s_mem_req 92*6d5ddbceSLemover level := Mux(req.l2Hit, 2.U, Mux(req.l1Hit, 1.U, 0.U)) 93*6d5ddbceSLemover ppn := Mux(req.l2Hit || req.l1Hit, io.req.bits.ppn, satp.ppn) 94*6d5ddbceSLemover vpn := io.req.bits.vpn 95*6d5ddbceSLemover l1Hit := req.l1Hit 96*6d5ddbceSLemover l2Hit := req.l2Hit 97*6d5ddbceSLemover } 98*6d5ddbceSLemover } 99*6d5ddbceSLemover 100*6d5ddbceSLemover is (s_mem_req) { 101*6d5ddbceSLemover when (mem.req.fire()) { 102*6d5ddbceSLemover state := s_mem_resp 103*6d5ddbceSLemover } 104*6d5ddbceSLemover } 105*6d5ddbceSLemover 106*6d5ddbceSLemover is (s_mem_resp) { 107*6d5ddbceSLemover when (mem.resp.fire()) { 108*6d5ddbceSLemover when (memPte.isLeaf() || memPte.isPf(level)) { 109*6d5ddbceSLemover state := s_resp 110*6d5ddbceSLemover notFound := memPte.isPf(level) 111*6d5ddbceSLemover }.otherwise { 112*6d5ddbceSLemover when (level =/= 2.U) { 113*6d5ddbceSLemover level := levelNext 114*6d5ddbceSLemover state := s_mem_req 115*6d5ddbceSLemover }.otherwise { 116*6d5ddbceSLemover state := s_resp 117*6d5ddbceSLemover notFound := true.B 118*6d5ddbceSLemover } 119*6d5ddbceSLemover } 120*6d5ddbceSLemover } 121*6d5ddbceSLemover } 122*6d5ddbceSLemover 123*6d5ddbceSLemover is (s_resp) { 124*6d5ddbceSLemover when (io.resp.fire()) { 125*6d5ddbceSLemover state := s_idle 126*6d5ddbceSLemover } 127*6d5ddbceSLemover } 128*6d5ddbceSLemover } 129*6d5ddbceSLemover 130*6d5ddbceSLemover when (sfence.valid) { 131*6d5ddbceSLemover state := s_idle 132*6d5ddbceSLemover when (state === s_mem_resp && !mem.resp.fire() || state === s_mem_req && mem.req.fire()) { 133*6d5ddbceSLemover sfenceLatch := true.B 134*6d5ddbceSLemover } 135*6d5ddbceSLemover } 136*6d5ddbceSLemover 137*6d5ddbceSLemover val finish = mem.resp.fire() && (memPte.isLeaf() || memPte.isPf(level) || level === 2.U) 138*6d5ddbceSLemover val resp = Reg(io.resp.bits.cloneType) 139*6d5ddbceSLemover when (finish && !sfenceLatch) { 140*6d5ddbceSLemover resp.source := RegEnable(io.req.bits.source, io.req.fire()) 141*6d5ddbceSLemover resp.resp.pf := level === 3.U || notFound 142*6d5ddbceSLemover resp.resp.entry.tag := vpn 143*6d5ddbceSLemover resp.resp.entry.ppn := memPte.ppn 144*6d5ddbceSLemover resp.resp.entry.perm.map(_ := memPte.getPerm()) 145*6d5ddbceSLemover resp.resp.entry.level.map(_ := level) 146*6d5ddbceSLemover } 147*6d5ddbceSLemover io.resp.valid := state === s_resp 148*6d5ddbceSLemover io.resp.bits := resp 149*6d5ddbceSLemover io.req.ready := state === s_idle 150*6d5ddbceSLemover 151*6d5ddbceSLemover val l1addr = MakeAddr(satp.ppn, getVpnn(vpn, 2)) 152*6d5ddbceSLemover val l2addr = MakeAddr(Mux(l1Hit, ppn, memPteReg.ppn), getVpnn(vpn, 1)) 153*6d5ddbceSLemover val l3addr = MakeAddr(Mux(l2Hit, ppn, memPteReg.ppn), getVpnn(vpn, 0)) 154*6d5ddbceSLemover mem.req.valid := state === s_mem_req && !sfenceLatch 155*6d5ddbceSLemover mem.req.bits.addr := Mux(level === 0.U, l1addr, Mux(level === 1.U, l2addr, l3addr)) 156*6d5ddbceSLemover 157*6d5ddbceSLemover io.refill.vpn := vpn 158*6d5ddbceSLemover io.refill.level := level 159*6d5ddbceSLemover io.refill.memAddr := memAddrReg 160*6d5ddbceSLemover io.sfenceLatch := sfenceLatch 161*6d5ddbceSLemover 162*6d5ddbceSLemover XSDebug(p"[fsm] state:${state} level:${level} sfenceLatch:${sfenceLatch} notFound:${notFound}\n") 163*6d5ddbceSLemover 164*6d5ddbceSLemover // perf 165*6d5ddbceSLemover XSPerfAccumulate("fsm_count", io.req.fire()) 166*6d5ddbceSLemover for (i <- 0 until PtwWidth) { 167*6d5ddbceSLemover XSPerfAccumulate(s"fsm_count_source${i}", io.req.fire() && io.req.bits.source === i.U) 168*6d5ddbceSLemover } 169*6d5ddbceSLemover XSPerfAccumulate("fsm_busy", state =/= s_idle) 170*6d5ddbceSLemover XSPerfAccumulate("fsm_idle", state === s_idle) 171*6d5ddbceSLemover XSPerfAccumulate("resp_blocked", io.resp.valid && !io.resp.ready) 172*6d5ddbceSLemover XSPerfAccumulate("mem_count", mem.req.fire()) 173*6d5ddbceSLemover XSPerfAccumulate("mem_cycle", BoolStopWatch(mem.req.fire, mem.resp.fire(), true)) 174*6d5ddbceSLemover XSPerfAccumulate("mem_blocked", mem.req.valid && !mem.req.ready) 175*6d5ddbceSLemover}