1/*************************************************************************************** 2* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences 3* Copyright (c) 2020-2021 Peng Cheng Laboratory 4* 5* XiangShan is licensed under Mulan PSL v2. 6* You can use this software according to the terms and conditions of the Mulan PSL v2. 7* You may obtain a copy of Mulan PSL v2 at: 8* http://license.coscl.org.cn/MulanPSL2 9* 10* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 11* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 12* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 13* 14* See the Mulan PSL v2 for more details. 15***************************************************************************************/ 16 17package xiangshan.cache.mmu 18 19import chipsalliance.rocketchip.config.Parameters 20import chisel3._ 21import chisel3.internal.naming.chiselName 22import chisel3.util._ 23import freechips.rocketchip.util.SRAMAnnotation 24import xiangshan._ 25import utils._ 26import xiangshan.backend.fu.{PMPChecker, PMPReqBundle} 27import xiangshan.backend.rob.RobPtr 28import xiangshan.backend.fu.util.HasCSRConst 29 30 31@chiselName 32class TLB(Width: Int, q: TLBParameters)(implicit p: Parameters) extends TlbModule with HasCSRConst with HasPerfEvents { 33 val io = IO(new TlbIO(Width, q)) 34 35 require(q.superAssociative == "fa") 36 if (q.sameCycle || q.missSameCycle) { 37 require(q.normalAssociative == "fa") 38 } 39 40 val req = io.requestor.map(_.req) 41 val resp = io.requestor.map(_.resp) 42 val ptw = io.ptw 43 val pmp = io.pmp 44 45 val sfence = io.sfence 46 val csr = io.csr 47 val satp = csr.satp 48 val priv = csr.priv 49 val ifecth = if (q.fetchi) true.B else false.B 50 val mode = if (q.useDmode) priv.dmode else priv.imode 51 // val vmEnable = satp.mode === 8.U // && (mode < ModeM) // FIXME: fix me when boot xv6/linux... 52 val vmEnable = if (EnbaleTlbDebug) (satp.mode === 8.U) 53 else (satp.mode === 8.U && (mode < ModeM)) 54 55 val reqAddr = req.map(_.bits.vaddr.asTypeOf(new VaBundle)) 56 val vpn = reqAddr.map(_.vpn) 57 val cmd = req.map(_.bits.cmd) 58 val valid = req.map(_.valid) 59 60 def widthMapSeq[T <: Seq[Data]](f: Int => T) = (0 until Width).map(f) 61 62 def widthMap[T <: Data](f: Int => T) = (0 until Width).map(f) 63 64 // Normal page && Super page 65 val normalPage = TlbStorage( 66 name = "normal", 67 associative = q.normalAssociative, 68 sameCycle = q.sameCycle, 69 ports = Width, 70 nSets = q.normalNSets, 71 nWays = q.normalNWays, 72 sramSinglePort = sramSinglePort, 73 saveLevel = q.saveLevel, 74 normalPage = true, 75 superPage = false 76 ) 77 val superPage = TlbStorage( 78 name = "super", 79 associative = q.superAssociative, 80 sameCycle = q.sameCycle, 81 ports = Width, 82 nSets = q.superNSets, 83 nWays = q.superNWays, 84 sramSinglePort = sramSinglePort, 85 saveLevel = q.saveLevel, 86 normalPage = q.normalAsVictim, 87 superPage = true, 88 ) 89 90 91 for (i <- 0 until Width) { 92 normalPage.r_req_apply( 93 valid = io.requestor(i).req.valid, 94 vpn = vpn(i), 95 asid = csr.satp.asid, 96 i = i 97 ) 98 superPage.r_req_apply( 99 valid = io.requestor(i).req.valid, 100 vpn = vpn(i), 101 asid = csr.satp.asid, 102 i = i 103 ) 104 } 105 106 normalPage.victim.in <> superPage.victim.out 107 normalPage.victim.out <> superPage.victim.in 108 normalPage.sfence <> io.sfence 109 superPage.sfence <> io.sfence 110 normalPage.csr <> io.csr 111 superPage.csr <> io.csr 112 113 def TLBNormalRead(i: Int) = { 114 val (n_hit_sameCycle, normal_hit, normal_ppn, normal_perm) = normalPage.r_resp_apply(i) 115 val (s_hit_sameCycle, super_hit, super_ppn, super_perm) = superPage.r_resp_apply(i) 116 // assert(!(normal_hit && super_hit && vmEnable && RegNext(req(i).valid, init = false.B))) 117 118 val hit = normal_hit || super_hit 119 val hit_sameCycle = n_hit_sameCycle || s_hit_sameCycle 120 val ppn = Mux(super_hit, super_ppn, normal_ppn) 121 val perm = Mux(super_hit, super_perm, normal_perm) 122 123 val pf = perm.pf 124 val af = perm.af 125 val cmdReg = if (!q.sameCycle) RegNext(cmd(i)) else cmd(i) 126 val validReg = if (!q.sameCycle) RegNext(valid(i)) else valid(i) 127 val offReg = if (!q.sameCycle) RegNext(reqAddr(i).off) else reqAddr(i).off 128 val sizeReg = if (!q.sameCycle) RegNext(req(i).bits.size) else req(i).bits.size 129 130 /** *************** next cycle when two cycle is false******************* */ 131 val miss = !hit && vmEnable 132 val fast_miss = !super_hit && vmEnable 133 val miss_sameCycle = !hit_sameCycle && vmEnable 134 hit.suggestName(s"hit_${i}") 135 miss.suggestName(s"miss_${i}") 136 137 XSDebug(validReg, p"(${i.U}) hit:${hit} miss:${miss} ppn:${Hexadecimal(ppn)} perm:${perm}\n") 138 139 val paddr = Cat(ppn, offReg) 140 val vaddr = SignExt(req(i).bits.vaddr, PAddrBits) 141 val refill_reg = RegNext(io.ptw.resp.valid) 142 req(i).ready := resp(i).ready 143 resp(i).valid := validReg 144 resp(i).bits.paddr := Mux(vmEnable, paddr, if (!q.sameCycle) RegNext(vaddr) else vaddr) 145 resp(i).bits.miss := { if (q.missSameCycle) miss_sameCycle else (miss || refill_reg) } 146 resp(i).bits.fast_miss := fast_miss || refill_reg 147 resp(i).bits.ptwBack := io.ptw.resp.fire() 148 149 // for timing optimization, pmp check is divided into dynamic and static 150 // dynamic: superpage (or full-connected reg entries) -> check pmp when translation done 151 // static: 4K pages (or sram entries) -> check pmp with pre-checked results 152 val pmp_paddr = Mux(vmEnable, Cat(super_ppn, offReg), if (!q.sameCycle) RegNext(vaddr) else vaddr) 153 pmp(i).valid := resp(i).valid 154 pmp(i).bits.addr := pmp_paddr 155 pmp(i).bits.size := sizeReg 156 pmp(i).bits.cmd := cmdReg 157 158 val ldUpdate = !perm.a && TlbCmd.isRead(cmdReg) && !TlbCmd.isAmo(cmdReg) // update A/D through exception 159 val stUpdate = (!perm.a || !perm.d) && (TlbCmd.isWrite(cmdReg) || TlbCmd.isAmo(cmdReg)) // update A/D through exception 160 val instrUpdate = !perm.a && TlbCmd.isExec(cmdReg) // update A/D through exception 161 val modeCheck = !(mode === ModeU && !perm.u || mode === ModeS && perm.u && (!priv.sum || ifecth)) 162 val ldPermFail = !(modeCheck && (perm.r || priv.mxr && perm.x)) 163 val stPermFail = !(modeCheck && perm.w) 164 val instrPermFail = !(modeCheck && perm.x) 165 val ldPf = (ldPermFail || pf) && (TlbCmd.isRead(cmdReg) && !TlbCmd.isAmo(cmdReg)) 166 val stPf = (stPermFail || pf) && (TlbCmd.isWrite(cmdReg) || TlbCmd.isAmo(cmdReg)) 167 val instrPf = (instrPermFail || pf) && TlbCmd.isExec(cmdReg) 168 val fault_valid = vmEnable 169 resp(i).bits.excp.pf.ld := (ldPf || ldUpdate) && fault_valid && !af 170 resp(i).bits.excp.pf.st := (stPf || stUpdate) && fault_valid && !af 171 resp(i).bits.excp.pf.instr := (instrPf || instrUpdate) && fault_valid && !af 172 // NOTE: pf need && with !af, page fault has higher priority than access fault 173 // but ptw may also have access fault, then af happens, the translation is wrong. 174 // In this case, pf has lower priority than af 175 176 val spm = normal_perm.pm // static physical memory protection or attribute 177 val spm_v = !super_hit && vmEnable && q.partialStaticPMP.B // static pm valid; do not use normal_hit, it's too long. 178 // for tlb without sram, tlb will miss, pm should be ignored outsize 179 resp(i).bits.excp.af.ld := (af || (spm_v && !spm.r)) && TlbCmd.isRead(cmdReg) && fault_valid 180 resp(i).bits.excp.af.st := (af || (spm_v && !spm.w)) && TlbCmd.isWrite(cmdReg) && fault_valid 181 resp(i).bits.excp.af.instr := (af || (spm_v && !spm.x)) && TlbCmd.isExec(cmdReg) && fault_valid 182 resp(i).bits.static_pm.valid := spm_v && fault_valid // ls/st unit should use this mmio, not the result from pmp 183 resp(i).bits.static_pm.bits := !spm.c 184 185 (hit, miss, validReg) 186 } 187 188 val readResult = (0 until Width).map(TLBNormalRead(_)) 189 val hitVec = readResult.map(_._1) 190 val missVec = readResult.map(_._2) 191 val validRegVec = readResult.map(_._3) 192 193 // replacement 194 def get_access(one_hot: UInt, valid: Bool): Valid[UInt] = { 195 val res = Wire(Valid(UInt(log2Up(one_hot.getWidth).W))) 196 res.valid := Cat(one_hot).orR && valid 197 res.bits := OHToUInt(one_hot) 198 res 199 } 200 201 val normal_refill_idx = if (q.outReplace) { 202 io.replace.normalPage.access <> normalPage.access 203 io.replace.normalPage.chosen_set := get_set_idx(io.ptw.resp.bits.entry.tag, q.normalNSets) 204 io.replace.normalPage.refillIdx 205 } else if (q.normalAssociative == "fa") { 206 val re = ReplacementPolicy.fromString(q.normalReplacer, q.normalNWays) 207 re.access(normalPage.access.map(_.touch_ways)) // normalhitVecVec.zipWithIndex.map{ case (hv, i) => get_access(hv, validRegVec(i))}) 208 re.way 209 } else { // set-acco && plru 210 val re = ReplacementPolicy.fromString(q.normalReplacer, q.normalNSets, q.normalNWays) 211 re.access(normalPage.access.map(_.sets), normalPage.access.map(_.touch_ways)) 212 re.way(get_set_idx(io.ptw.resp.bits.entry.tag, q.normalNSets)) 213 } 214 215 val super_refill_idx = if (q.outReplace) { 216 io.replace.superPage.access <> superPage.access 217 io.replace.superPage.chosen_set := DontCare 218 io.replace.superPage.refillIdx 219 } else { 220 val re = ReplacementPolicy.fromString(q.superReplacer, q.superNWays) 221 re.access(superPage.access.map(_.touch_ways)) 222 re.way 223 } 224 225 val refill = ptw.resp.fire() && !sfence.valid && !satp.changed 226 normalPage.w_apply( 227 valid = { if (q.normalAsVictim) false.B 228 else refill && ptw.resp.bits.entry.level.get === 2.U }, 229 wayIdx = normal_refill_idx, 230 data = ptw.resp.bits, 231 data_replenish = io.ptw_replenish 232 ) 233 superPage.w_apply( 234 valid = { if (q.normalAsVictim) refill 235 else refill && ptw.resp.bits.entry.level.get =/= 2.U }, 236 wayIdx = super_refill_idx, 237 data = ptw.resp.bits, 238 data_replenish = io.ptw_replenish 239 ) 240 241 // if sameCycle, just req.valid 242 // if !sameCycle, add one more RegNext based on !sameCycle's RegNext 243 // because sram is too slow and dtlb is too distant from dtlbRepeater 244 for (i <- 0 until Width) { 245 io.ptw.req(i).valid := need_RegNextInit(!q.sameCycle, validRegVec(i) && missVec(i), false.B) && 246 !RegNext(refill, init = false.B) && 247 param_choose(!q.sameCycle, !RegNext(RegNext(refill, init = false.B), init = false.B), true.B) 248 io.ptw.req(i).bits.vpn := need_RegNext(!q.sameCycle, need_RegNext(!q.sameCycle, reqAddr(i).vpn)) 249 } 250 io.ptw.resp.ready := true.B 251 252 def need_RegNext[T <: Data](need: Boolean, data: T): T = { 253 if (need) RegNext(data) 254 else data 255 } 256 def need_RegNextInit[T <: Data](need: Boolean, data: T, init_value: T): T = { 257 if (need) RegNext(data, init = init_value) 258 else data 259 } 260 261 def param_choose[T <: Data](need: Boolean, truedata: T, falsedata: T): T = { 262 if (need) truedata 263 else falsedata 264 } 265 266 if (!q.shouldBlock) { 267 for (i <- 0 until Width) { 268 XSPerfAccumulate("first_access" + Integer.toString(i, 10), validRegVec(i) && vmEnable && RegNext(req(i).bits.debug.isFirstIssue)) 269 XSPerfAccumulate("access" + Integer.toString(i, 10), validRegVec(i) && vmEnable) 270 } 271 for (i <- 0 until Width) { 272 XSPerfAccumulate("first_miss" + Integer.toString(i, 10), validRegVec(i) && vmEnable && missVec(i) && RegNext(req(i).bits.debug.isFirstIssue)) 273 XSPerfAccumulate("miss" + Integer.toString(i, 10), validRegVec(i) && vmEnable && missVec(i)) 274 } 275 } else { 276 // NOTE: ITLB is blocked, so every resp will be valid only when hit 277 // every req will be ready only when hit 278 for (i <- 0 until Width) { 279 XSPerfAccumulate(s"access${i}", io.requestor(i).req.fire() && vmEnable) 280 XSPerfAccumulate(s"miss${i}", ptw.req(i).fire()) 281 } 282 283 } 284 //val reqCycleCnt = Reg(UInt(16.W)) 285 //reqCycleCnt := reqCycleCnt + BoolStopWatch(ptw.req(0).fire(), ptw.resp.fire || sfence.valid) 286 //XSPerfAccumulate("ptw_req_count", ptw.req.fire()) 287 //XSPerfAccumulate("ptw_req_cycle", Mux(ptw.resp.fire(), reqCycleCnt, 0.U)) 288 XSPerfAccumulate("ptw_resp_count", ptw.resp.fire()) 289 XSPerfAccumulate("ptw_resp_pf_count", ptw.resp.fire() && ptw.resp.bits.pf) 290 291 // Log 292 for(i <- 0 until Width) { 293 XSDebug(req(i).valid, p"req(${i.U}): (${req(i).valid} ${req(i).ready}) ${req(i).bits}\n") 294 XSDebug(resp(i).valid, p"resp(${i.U}): (${resp(i).valid} ${resp(i).ready}) ${resp(i).bits}\n") 295 } 296 297 XSDebug(sfence.valid, p"Sfence: ${sfence}\n") 298 XSDebug(ParallelOR(valid)|| ptw.resp.valid, p"CSR: ${csr}\n") 299 XSDebug(ParallelOR(valid) || ptw.resp.valid, p"vmEnable:${vmEnable} hit:${Binary(VecInit(hitVec).asUInt)} miss:${Binary(VecInit(missVec).asUInt)}\n") 300 for (i <- ptw.req.indices) { 301 XSDebug(ptw.req(i).fire(), p"L2TLB req:${ptw.req(i).bits}\n") 302 } 303 XSDebug(ptw.resp.valid, p"L2TLB resp:${ptw.resp.bits} (v:${ptw.resp.valid}r:${ptw.resp.ready}) \n") 304 305 println(s"${q.name}: normal page: ${q.normalNWays} ${q.normalAssociative} ${q.normalReplacer.get} super page: ${q.superNWays} ${q.superAssociative} ${q.superReplacer.get}") 306 307// // NOTE: just for simple tlb debug, comment it after tlb's debug 308 // assert(!io.ptw.resp.valid || io.ptw.resp.bits.entry.tag === io.ptw.resp.bits.entry.ppn, "Simple tlb debug requires vpn === ppn") 309 310 val perfEvents = if(!q.shouldBlock) { 311 Seq( 312 ("access", PopCount((0 until Width).map(i => vmEnable && validRegVec(i))) ), 313 ("miss ", PopCount((0 until Width).map(i => vmEnable && validRegVec(i) && missVec(i)))), 314 ) 315 } else { 316 Seq( 317 ("access", PopCount((0 until Width).map(i => io.requestor(i).req.fire()))), 318 ("miss ", PopCount((0 until Width).map(i => ptw.req(i).fire())) ), 319 ) 320 } 321 generatePerfEvent() 322} 323 324class TlbReplace(Width: Int, q: TLBParameters)(implicit p: Parameters) extends TlbModule { 325 val io = IO(new TlbReplaceIO(Width, q)) 326 327 if (q.normalAssociative == "fa") { 328 val re = ReplacementPolicy.fromString(q.normalReplacer, q.normalNWays) 329 re.access(io.normalPage.access.map(_.touch_ways)) 330 io.normalPage.refillIdx := re.way 331 } else { // set-acco && plru 332 val re = ReplacementPolicy.fromString(q.normalReplacer, q.normalNSets, q.normalNWays) 333 re.access(io.normalPage.access.map(_.sets), io.normalPage.access.map(_.touch_ways)) 334 io.normalPage.refillIdx := { if (q.normalNWays == 1) 0.U else re.way(io.normalPage.chosen_set) } 335 } 336 337 if (q.superAssociative == "fa") { 338 val re = ReplacementPolicy.fromString(q.superReplacer, q.superNWays) 339 re.access(io.superPage.access.map(_.touch_ways)) 340 io.superPage.refillIdx := re.way 341 } else { // set-acco && plru 342 val re = ReplacementPolicy.fromString(q.superReplacer, q.superNSets, q.superNWays) 343 re.access(io.superPage.access.map(_.sets), io.superPage.access.map(_.touch_ways)) 344 io.superPage.refillIdx := { if (q.superNWays == 1) 0.U else re.way(io.superPage.chosen_set) } 345 } 346} 347 348object TLB { 349 def apply 350 ( 351 in: Seq[BlockTlbRequestIO], 352 sfence: SfenceBundle, 353 csr: TlbCsrBundle, 354 width: Int, 355 shouldBlock: Boolean, 356 q: TLBParameters 357 )(implicit p: Parameters) = { 358 require(in.length == width) 359 360 val tlb = Module(new TLB(width, q)) 361 362 tlb.io.sfence <> sfence 363 tlb.io.csr <> csr 364 tlb.suggestName(s"tlb_${q.name}") 365 366 if (!shouldBlock) { // dtlb 367 for (i <- 0 until width) { 368 tlb.io.requestor(i) <> in(i) 369 // tlb.io.requestor(i).req.valid := in(i).req.valid 370 // tlb.io.requestor(i).req.bits := in(i).req.bits 371 // in(i).req.ready := tlb.io.requestor(i).req.ready 372 373 // in(i).resp.valid := tlb.io.requestor(i).resp.valid 374 // in(i).resp.bits := tlb.io.requestor(i).resp.bits 375 // tlb.io.requestor(i).resp.ready := in(i).resp.ready 376 } 377 } else { // itlb 378 //require(width == 1) 379 (0 until width).map{ i => 380 tlb.io.requestor(i).req.valid := in(i).req.valid 381 tlb.io.requestor(i).req.bits := in(i).req.bits 382 in(i).req.ready := !tlb.io.requestor(i).resp.bits.miss && in(i).resp.ready && tlb.io.requestor(i).req.ready 383 384 require(q.missSameCycle || q.sameCycle) 385 // NOTE: the resp.valid seems to be useless, it must be true when need 386 // But don't know what happens when true but not need, so keep it correct value, not just true.B 387 if (q.missSameCycle && !q.sameCycle) { 388 in(i).resp.valid := tlb.io.requestor(i).resp.valid && !RegNext(tlb.io.requestor(i).resp.bits.miss) 389 } else { 390 in(i).resp.valid := tlb.io.requestor(i).resp.valid && !tlb.io.requestor(i).resp.bits.miss 391 } 392 in(i).resp.bits := tlb.io.requestor(i).resp.bits 393 tlb.io.requestor(i).resp.ready := in(i).resp.ready 394 } 395 tlb.io.ptw_replenish <> DontCare // itlb only use reg, so no static pmp/pma 396 } 397 tlb.io.ptw 398 } 399} 400