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 org.chipsalliance.cde.config.Parameters 20import chisel3._ 21import chisel3.util._ 22import utils._ 23import utility._ 24import freechips.rocketchip.formal.PropertyClass 25import xiangshan.backend.fu.util.HasCSRConst 26 27import scala.math.min 28 29// For Direct-map TLBs, we do not use it now 30class BankedAsyncDataModuleTemplateWithDup[T <: Data]( 31 gen: T, 32 numEntries: Int, 33 numRead: Int, 34 numDup: Int, 35 numBanks: Int 36) extends Module { 37 val io = IO(new Bundle { 38 val raddr = Vec(numRead, Input(UInt(log2Ceil(numEntries).W))) 39 val rdata = Vec(numRead, Vec(numDup, Output(gen))) 40 val wen = Input(Bool()) 41 val waddr = Input(UInt(log2Ceil(numEntries).W)) 42 val wdata = Input(gen) 43 }) 44 require(numBanks > 1) 45 require(numEntries > numBanks) 46 47 val numBankEntries = numEntries / numBanks 48 def bankOffset(address: UInt): UInt = { 49 address(log2Ceil(numBankEntries) - 1, 0) 50 } 51 52 def bankIndex(address: UInt): UInt = { 53 address(log2Ceil(numEntries) - 1, log2Ceil(numBankEntries)) 54 } 55 56 val dataBanks = Seq.tabulate(numBanks)(i => { 57 val bankEntries = if (i < numBanks - 1) numBankEntries else (numEntries - (i * numBankEntries)) 58 Mem(bankEntries, gen) 59 }) 60 61 // async read, but regnext 62 for (i <- 0 until numRead) { 63 val data_read = Reg(Vec(numDup, Vec(numBanks, gen))) 64 val bank_index = Reg(Vec(numDup, UInt(numBanks.W))) 65 for (j <- 0 until numDup) { 66 bank_index(j) := UIntToOH(bankIndex(io.raddr(i))) 67 for (k <- 0 until numBanks) { 68 data_read(j)(k) := Mux(io.wen && (io.waddr === io.raddr(i)), 69 io.wdata, dataBanks(k)(bankOffset(io.raddr(i)))) 70 } 71 } 72 // next cycle 73 for (j <- 0 until numDup) { 74 io.rdata(i)(j) := Mux1H(bank_index(j), data_read(j)) 75 } 76 } 77 78 // write 79 for (i <- 0 until numBanks) { 80 when (io.wen && (bankIndex(io.waddr) === i.U)) { 81 dataBanks(i)(bankOffset(io.waddr)) := io.wdata 82 } 83 } 84} 85 86class TLBFA( 87 parentName: String, 88 ports: Int, 89 nDups: Int, 90 nSets: Int, 91 nWays: Int, 92 saveLevel: Boolean = false, 93 normalPage: Boolean, 94 superPage: Boolean 95)(implicit p: Parameters) extends TlbModule with HasPerfEvents { 96 97 val io = IO(new TlbStorageIO(nSets, nWays, ports, nDups)) 98 io.r.req.map(_.ready := true.B) 99 100 val v = RegInit(VecInit(Seq.fill(nWays)(false.B))) 101 val entries = Reg(Vec(nWays, new TlbSectorEntry(normalPage, superPage))) 102 val g = entries.map(_.perm.g) 103 104 for (i <- 0 until ports) { 105 val req = io.r.req(i) 106 val resp = io.r.resp(i) 107 val access = io.access(i) 108 109 val vpn = req.bits.vpn 110 val vpn_reg = RegEnable(vpn, req.fire) 111 val hasS2xlate = req.bits.s2xlate =/= noS2xlate 112 val OnlyS2 = req.bits.s2xlate === onlyStage2 113 val OnlyS1 = req.bits.s2xlate === onlyStage1 114 val refill_mask = Mux(io.w.valid, UIntToOH(io.w.bits.wayIdx), 0.U(nWays.W)) 115 val hitVec = VecInit((entries.zipWithIndex).zip(v zip refill_mask.asBools).map{ 116 case (e, m) => { 117 val s2xlate_hit = e._1.s2xlate === req.bits.s2xlate 118 val hit = e._1.hit(vpn, Mux(hasS2xlate, io.csr.vsatp.asid, io.csr.satp.asid), vmid = io.csr.hgatp.vmid, hasS2xlate = hasS2xlate, onlyS2 = OnlyS2, onlyS1 = OnlyS1) 119 s2xlate_hit && hit && m._1 && !m._2 120 } 121 }) 122 123 hitVec.suggestName("hitVec") 124 125 val hitVecReg = RegEnable(hitVec, req.fire) 126 // Sector tlb may trigger multi-hit, see def "wbhit" 127 XSPerfAccumulate(s"port${i}_multi_hit", !(!resp.valid || (PopCount(hitVecReg) === 0.U || PopCount(hitVecReg) === 1.U))) 128 129 resp.valid := GatedValidRegNext(req.valid) 130 resp.bits.hit := Cat(hitVecReg).orR 131 val reqVpn = RegEnable(vpn, 0.U, req.fire) 132 val pbmt = entries.map(_.pbmt) 133 val gpbmt = entries.map(_.g_pbmt) 134 val perm = entries.map(_.perm) 135 val gPerm = entries.map(_.g_perm) 136 val s2xLate = entries.map(_.s2xlate) 137 if (nWays == 1) { 138 for (d <- 0 until nDups) { 139 resp.bits.ppn(d) := entries(0).genPPN(saveLevel, resp.valid)(reqVpn) 140 resp.bits.pbmt(d) := pbmt(0) 141 resp.bits.g_pbmt(d) := gpbmt(0) 142 resp.bits.perm(d) := perm(0) 143 resp.bits.g_perm(d) := gPerm(0) 144 resp.bits.s2xlate(d) := s2xLate(0) 145 } 146 } else { 147 for (d <- 0 until nDups) { 148 resp.bits.ppn(d) := Mux1H(hitVecReg zip entries.map(_.genPPN(saveLevel, resp.valid)(reqVpn))) 149 resp.bits.pbmt(d) := Mux1H(hitVecReg zip pbmt) 150 resp.bits.g_pbmt(d) := Mux1H(hitVecReg zip gpbmt) 151 resp.bits.perm(d) := Mux1H(hitVecReg zip perm) 152 resp.bits.g_perm(d) := Mux1H(hitVecReg zip gPerm) 153 resp.bits.s2xlate(d) := Mux1H(hitVecReg zip s2xLate) 154 } 155 } 156 157 access.sets := get_set_idx(vpn_reg(vpn_reg.getWidth - 1, sectortlbwidth), nSets) // no use 158 access.touch_ways.valid := resp.valid && Cat(hitVecReg).orR 159 access.touch_ways.bits := OHToUInt(hitVecReg) 160 161 resp.bits.hit.suggestName("hit") 162 resp.bits.ppn.suggestName("ppn") 163 resp.bits.pbmt.suggestName("pbmt") 164 resp.bits.g_pbmt.suggestName("g_pbmt") 165 resp.bits.perm.suggestName("perm") 166 resp.bits.g_perm.suggestName("g_perm") 167 } 168 169 when (io.w.valid) { 170 v(io.w.bits.wayIdx) := true.B 171 entries(io.w.bits.wayIdx).apply(io.w.bits.data) 172 } 173 // write assert, should not duplicate with the existing entries 174 val w_hit_vec = VecInit(entries.zip(v).map{case (e, vi) => e.wbhit(io.w.bits.data, Mux(io.w.bits.data.s2xlate =/= noS2xlate, io.csr.vsatp.asid, io.csr.satp.asid), io.csr.hgatp.vmid, s2xlate = io.w.bits.data.s2xlate) && vi }) 175 XSError(io.w.valid && Cat(w_hit_vec).orR, s"${parentName} refill, duplicate with existing entries") 176 177 val refill_vpn_reg = RegEnable(io.w.bits.data.s1.entry.tag, io.w.valid) 178 val refill_wayIdx_reg = RegEnable(io.w.bits.wayIdx, io.w.valid) 179 when (GatedValidRegNext(io.w.valid)) { 180 io.access.map { access => 181 access.sets := get_set_idx(refill_vpn_reg, nSets) 182 access.touch_ways.valid := true.B 183 access.touch_ways.bits := refill_wayIdx_reg 184 } 185 } 186 187 val sfence = io.sfence 188 val sfence_valid = sfence.valid && !sfence.bits.hg && !sfence.bits.hv 189 val sfence_vpn = sfence.bits.addr(VAddrBits - 1, offLen) 190 val sfenceHit = entries.map(_.hit(sfence_vpn, sfence.bits.id, vmid = io.csr.hgatp.vmid, hasS2xlate = io.csr.priv.virt)) 191 val sfenceHit_noasid = entries.map(_.hit(sfence_vpn, sfence.bits.id, ignoreAsid = true, vmid = io.csr.hgatp.vmid, hasS2xlate = io.csr.priv.virt)) 192 // Sfence will flush all sectors of an entry when hit 193 when (sfence_valid) { 194 when (sfence.bits.rs1) { // virtual address *.rs1 <- (rs1===0.U) 195 when (sfence.bits.rs2) { // asid, but i do not want to support asid, *.rs2 <- (rs2===0.U) 196 // all addr and all asid 197 v.zipWithIndex.map{ case(a, i) => a := a && !((io.csr.priv.virt === false.B && entries(i).s2xlate === noS2xlate) || 198 (io.csr.priv.virt && entries(i).s2xlate =/= noS2xlate && entries(i).vmid === io.csr.hgatp.vmid))} 199 }.otherwise { 200 // all addr but specific asid 201 v.zipWithIndex.map{ case (a, i) => a := a && !(!g(i) && ((!io.csr.priv.virt && entries(i).s2xlate === noS2xlate && entries(i).asid === sfence.bits.id) || 202 (io.csr.priv.virt && entries(i).s2xlate =/= noS2xlate && entries(i).asid === sfence.bits.id && entries(i).vmid === io.csr.hgatp.vmid)))} 203 } 204 }.otherwise { 205 when (sfence.bits.rs2) { 206 // specific addr but all asid 207 v.zipWithIndex.map{ case (a, i) => a := a & !sfenceHit_noasid(i) } 208 }.otherwise { 209 // specific addr and specific asid 210 v.zipWithIndex.map{ case (a, i) => a := a & !(sfenceHit(i) && !g(i)) } 211 } 212 } 213 } 214 215 val hfencev_valid = sfence.valid && sfence.bits.hv 216 val hfenceg_valid = sfence.valid && sfence.bits.hg 217 val hfencev = io.sfence 218 val hfencev_vpn = sfence_vpn 219 val hfencevHit = entries.map(_.hit(hfencev_vpn, hfencev.bits.id, vmid = io.csr.hgatp.vmid, hasS2xlate = true.B)) 220 val hfencevHit_noasid = entries.map(_.hit(hfencev_vpn, 0.U, ignoreAsid = true, vmid = io.csr.hgatp.vmid, hasS2xlate = true.B)) 221 when (hfencev_valid) { 222 when (hfencev.bits.rs1) { 223 when (hfencev.bits.rs2) { 224 v.zipWithIndex.map { case (a, i) => a := a && !(entries(i).s2xlate =/= noS2xlate && entries(i).vmid === io.csr.hgatp.vmid)} 225 }.otherwise { 226 v.zipWithIndex.map { case (a, i) => a := a && !(!g(i) && (entries(i).s2xlate =/= noS2xlate && entries(i).asid === sfence.bits.id && entries(i).vmid === io.csr.hgatp.vmid)) 227 } 228 } 229 }.otherwise { 230 when (hfencev.bits.rs2) { 231 v.zipWithIndex.map{ case (a, i) => a := a && !hfencevHit_noasid(i) } 232 }.otherwise { 233 v.zipWithIndex.map{ case (a, i) => a := a && !(hfencevHit(i) && !g(i)) } 234 } 235 } 236 } 237 238 239 val hfenceg = io.sfence 240 val hfenceg_gvpn = (sfence.bits.addr << 2)(VAddrBits - 1, offLen) 241 when (hfenceg_valid) { 242 when(hfenceg.bits.rs2) { 243 v.zipWithIndex.map { case (a, i) => a := a && !(entries(i).s2xlate =/= noS2xlate) } 244 }.otherwise { 245 v.zipWithIndex.map { case (a, i) => a := a && !(entries(i).s2xlate =/= noS2xlate && entries(i).vmid === sfence.bits.id) } 246 } 247 } 248 249 XSPerfAccumulate(s"access", io.r.resp.map(_.valid.asUInt).fold(0.U)(_ + _)) 250 XSPerfAccumulate(s"hit", io.r.resp.map(a => a.valid && a.bits.hit).fold(0.U)(_.asUInt + _.asUInt)) 251 252 for (i <- 0 until nWays) { 253 XSPerfAccumulate(s"access${i}", io.r.resp.zip(io.access.map(acc => UIntToOH(acc.touch_ways.bits))).map{ case (a, b) => 254 a.valid && a.bits.hit && b(i)}.fold(0.U)(_.asUInt + _.asUInt)) 255 } 256 for (i <- 0 until nWays) { 257 XSPerfAccumulate(s"refill${i}", io.w.valid && io.w.bits.wayIdx === i.U) 258 } 259 260 val perfEvents = Seq( 261 ("tlbstore_access", io.r.resp.map(_.valid.asUInt).fold(0.U)(_ + _) ), 262 ("tlbstore_hit ", io.r.resp.map(a => a.valid && a.bits.hit).fold(0.U)(_.asUInt + _.asUInt)), 263 ) 264 generatePerfEvent() 265 266 println(s"${parentName} tlb_fa: nSets${nSets} nWays:${nWays}") 267} 268 269class TLBFakeFA( 270 ports: Int, 271 nDups: Int, 272 nSets: Int, 273 nWays: Int, 274 useDmode: Boolean = false 275 )(implicit p: Parameters) extends TlbModule with HasCSRConst{ 276 277 val io = IO(new TlbStorageIO(nSets, nWays, ports, nDups)) 278 io.r.req.map(_.ready := true.B) 279 val mode = if (useDmode) io.csr.priv.dmode else io.csr.priv.imode 280 val vmEnable = if (EnbaleTlbDebug) (io.csr.satp.mode === 8.U) 281 else (io.csr.satp.mode === 8.U && (mode < ModeM)) 282 283 for (i <- 0 until ports) { 284 val req = io.r.req(i) 285 val resp = io.r.resp(i) 286 287 val helper = Module(new PTEHelper()) 288 helper.clock := clock 289 helper.satp := io.csr.satp.ppn 290 helper.enable := req.fire && vmEnable 291 helper.vpn := req.bits.vpn 292 293 val pte = helper.pte.asTypeOf(new PteBundle) 294 val ppn = pte.ppn 295 val vpn_reg = RegEnable(req.bits.vpn, req.valid) 296 val pf = helper.pf 297 val level = helper.level 298 299 resp.valid := GatedValidRegNext(req.valid) 300 resp.bits.hit := true.B 301 for (d <- 0 until nDups) { 302 resp.bits.perm(d).pf := pf 303 resp.bits.perm(d).af := false.B 304 resp.bits.perm(d).d := pte.perm.d 305 resp.bits.perm(d).a := pte.perm.a 306 resp.bits.perm(d).g := pte.perm.g 307 resp.bits.perm(d).u := pte.perm.u 308 resp.bits.perm(d).x := pte.perm.x 309 resp.bits.perm(d).w := pte.perm.w 310 resp.bits.perm(d).r := pte.perm.r 311 resp.bits.pbmt(d) := pte.pbmt 312 resp.bits.ppn(d) := MuxLookup(level, 0.U)(Seq( 313 0.U -> Cat(ppn(ppn.getWidth-1, vpnnLen*2), vpn_reg(vpnnLen*2-1, 0)), 314 1.U -> Cat(ppn(ppn.getWidth-1, vpnnLen), vpn_reg(vpnnLen-1, 0)), 315 2.U -> ppn) 316 ) 317 } 318 } 319 320 io.access := DontCare 321} 322 323object TlbStorage { 324 def apply 325 ( 326 parentName: String, 327 associative: String, 328 ports: Int, 329 nDups: Int = 1, 330 nSets: Int, 331 nWays: Int, 332 saveLevel: Boolean = false, 333 normalPage: Boolean, 334 superPage: Boolean, 335 useDmode: Boolean, 336 SoftTLB: Boolean 337 )(implicit p: Parameters) = { 338 if (SoftTLB) { 339 val storage = Module(new TLBFakeFA(ports, nDups, nSets, nWays, useDmode)) 340 storage.suggestName(s"${parentName}_fake_fa") 341 storage.io 342 } else { 343 val storage = Module(new TLBFA(parentName, ports, nDups, nSets, nWays, saveLevel, normalPage, superPage)) 344 storage.suggestName(s"${parentName}_fa") 345 storage.io 346 } 347 } 348} 349 350class TlbStorageWrapper(ports: Int, q: TLBParameters, nDups: Int = 1)(implicit p: Parameters) extends TlbModule { 351 val io = IO(new TlbStorageWrapperIO(ports, q, nDups)) 352 353 val page = TlbStorage( 354 parentName = q.name + "_storage", 355 associative = q.Associative, 356 ports = ports, 357 nDups = nDups, 358 nSets = q.NSets, 359 nWays = q.NWays, 360 normalPage = true, 361 superPage = true, 362 useDmode = q.useDmode, 363 SoftTLB = coreParams.softTLB 364 ) 365 366 for (i <- 0 until ports) { 367 page.r_req_apply( 368 valid = io.r.req(i).valid, 369 vpn = io.r.req(i).bits.vpn, 370 i = i, 371 s2xlate = io.r.req(i).bits.s2xlate 372 ) 373 } 374 375 for (i <- 0 until ports) { 376 val q = page.r.req(i) 377 val p = page.r.resp(i) 378 val rq = io.r.req(i) 379 val rp = io.r.resp(i) 380 rq.ready := q.ready // actually, not used 381 rp.valid := p.valid // actually, not used 382 rp.bits.hit := p.bits.hit 383 for (d <- 0 until nDups) { 384 rp.bits.ppn(d) := p.bits.ppn(d) 385 rp.bits.perm(d).pf := p.bits.perm(d).pf 386 rp.bits.perm(d).af := p.bits.perm(d).af 387 rp.bits.perm(d).v := p.bits.perm(d).v 388 rp.bits.perm(d).d := p.bits.perm(d).d 389 rp.bits.perm(d).a := p.bits.perm(d).a 390 rp.bits.perm(d).g := p.bits.perm(d).g 391 rp.bits.perm(d).u := p.bits.perm(d).u 392 rp.bits.perm(d).x := p.bits.perm(d).x 393 rp.bits.perm(d).w := p.bits.perm(d).w 394 rp.bits.perm(d).r := p.bits.perm(d).r 395 rp.bits.s2xlate(d) := p.bits.s2xlate(d) 396 rp.bits.g_perm(d) := p.bits.g_perm(d) 397 rp.bits.pbmt(d) := p.bits.pbmt(d) 398 rp.bits.g_pbmt(d) := p.bits.g_pbmt(d) 399 } 400 } 401 402 page.sfence <> io.sfence 403 page.csr <> io.csr 404 405 val refill_idx = if (q.outReplace) { 406 io.replace.page.access <> page.access 407 io.replace.page.chosen_set := DontCare 408 io.replace.page.refillIdx 409 } else { 410 val re = ReplacementPolicy.fromString(q.Replacer, q.NWays) 411 re.access(page.access.map(_.touch_ways)) 412 re.way 413 } 414 415 page.w_apply( 416 valid = io.w.valid, 417 wayIdx = refill_idx, 418 data = io.w.bits.data 419 ) 420 421 // replacement 422 def get_access(one_hot: UInt, valid: Bool): Valid[UInt] = { 423 val res = Wire(Valid(UInt(log2Up(one_hot.getWidth).W))) 424 res.valid := Cat(one_hot).orR && valid 425 res.bits := OHToUInt(one_hot) 426 res 427 } 428} 429