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.experimental.chiselName 22import chisel3.util._ 23import utils._ 24 25@chiselName 26class TLBFA( 27 sameCycle: Boolean, 28 ports: Int, 29 nSets: Int, 30 nWays: Int, 31 sramSinglePort: Boolean, 32 saveLevel: Boolean = false, 33 normalPage: Boolean, 34 superPage: Boolean 35)(implicit p: Parameters) extends TlbModule with HasPerfEvents { 36 require(!(sameCycle && saveLevel)) 37 38 val io = IO(new TlbStorageIO(nSets, nWays, ports)) 39 io.r.req.map(_.ready := true.B) 40 41 val v = RegInit(VecInit(Seq.fill(nWays)(false.B))) 42 val entries = Reg(Vec(nWays, new TlbEntry(normalPage, superPage))) 43 val g = entries.map(_.perm.g) 44 45 for (i <- 0 until ports) { 46 val req = io.r.req(i) 47 val resp = io.r.resp(i) 48 val access = io.access(i) 49 50 val vpn = req.bits.vpn 51 val vpn_reg = if (sameCycle) vpn else RegEnable(vpn, req.fire()) 52 val vpn_gen_ppn = if(sameCycle || saveLevel) vpn else vpn_reg 53 54 val refill_mask = if (sameCycle) 0.U(nWays.W) else Mux(io.w.valid, UIntToOH(io.w.bits.wayIdx), 0.U(nWays.W)) 55 val hitVec = VecInit((entries.zipWithIndex).zip(v zip refill_mask.asBools).map{case (e, m) => e._1.hit(vpn, io.csr.satp.asid) && m._1 && !m._2 }) 56 57 hitVec.suggestName("hitVec") 58 59 val hitVecReg = if (sameCycle) hitVec else RegEnable(hitVec, req.fire()) 60 61 resp.valid := { if (sameCycle) req.valid else RegNext(req.valid) } 62 resp.bits.hit := Cat(hitVecReg).orR 63 if (nWays == 1) { 64 resp.bits.ppn := entries(0).genPPN(saveLevel, req.valid)(vpn_gen_ppn) 65 resp.bits.perm := entries(0).perm 66 } else { 67 resp.bits.ppn := ParallelMux(hitVecReg zip entries.map(_.genPPN(saveLevel, req.valid)(vpn_gen_ppn))) 68 resp.bits.perm := ParallelMux(hitVecReg zip entries.map(_.perm)) 69 } 70 io.r.resp_hit_sameCycle(i) := Cat(hitVec).orR 71 72 access.sets := get_set_idx(vpn_reg, nSets) // no use 73 access.touch_ways.valid := resp.valid && Cat(hitVecReg).orR 74 access.touch_ways.bits := OHToUInt(hitVecReg) 75 76 resp.bits.hit.suggestName("hit") 77 resp.bits.ppn.suggestName("ppn") 78 resp.bits.perm.suggestName("perm") 79 } 80 81 when (io.w.valid) { 82 v(io.w.bits.wayIdx) := true.B 83 entries(io.w.bits.wayIdx).apply(io.w.bits.data, io.csr.satp.asid, io.w.bits.data_replenish) 84 } 85 86 val refill_vpn_reg = RegNext(io.w.bits.data.entry.tag) 87 val refill_wayIdx_reg = RegNext(io.w.bits.wayIdx) 88 when (RegNext(io.w.valid)) { 89 io.access.map { access => 90 access.sets := get_set_idx(refill_vpn_reg, nSets) 91 access.touch_ways.valid := true.B 92 access.touch_ways.bits := refill_wayIdx_reg 93 } 94 } 95 96 val sfence = io.sfence 97 val sfence_vpn = sfence.bits.addr.asTypeOf(new VaBundle().cloneType).vpn 98 val sfenceHit = entries.map(_.hit(sfence_vpn, sfence.bits.asid)) 99 val sfenceHit_noasid = entries.map(_.hit(sfence_vpn, sfence.bits.asid, ignoreAsid = true)) 100 when (io.sfence.valid) { 101 when (sfence.bits.rs1) { // virtual address *.rs1 <- (rs1===0.U) 102 when (sfence.bits.rs2) { // asid, but i do not want to support asid, *.rs2 <- (rs2===0.U) 103 // all addr and all asid 104 v.map(_ := false.B) 105 }.otherwise { 106 // all addr but specific asid 107 v.zipWithIndex.map{ case (a,i) => a := a & (g(i) | !(entries(i).asid === sfence.bits.asid)) } 108 } 109 }.otherwise { 110 when (sfence.bits.rs2) { 111 // specific addr but all asid 112 v.zipWithIndex.map{ case (a,i) => a := a & !sfenceHit_noasid(i) } 113 }.otherwise { 114 // specific addr and specific asid 115 v.zipWithIndex.map{ case (a,i) => a := a & !(sfenceHit(i) && !g(i)) } 116 } 117 } 118 } 119 120 val victim_idx = io.w.bits.wayIdx 121 io.victim.out.valid := v(victim_idx) && io.w.valid && entries(victim_idx).level.getOrElse(3.U) === 2.U 122 io.victim.out.bits.entry := ns_to_n(entries(victim_idx)) 123 124 def ns_to_n(ns: TlbEntry): TlbEntry = { 125 val n = Wire(new TlbEntry(pageNormal = true, pageSuper = false)) 126 n.perm := ns.perm 127 n.ppn := ns.ppn 128 n.tag := ns.tag 129 n.asid := ns.asid 130 n 131 } 132 133 XSPerfAccumulate(s"access", io.r.resp.map(_.valid.asUInt()).fold(0.U)(_ + _)) 134 XSPerfAccumulate(s"hit", io.r.resp.map(a => a.valid && a.bits.hit).fold(0.U)(_.asUInt() + _.asUInt())) 135 136 for (i <- 0 until nWays) { 137 XSPerfAccumulate(s"access${i}", io.r.resp.zip(io.access.map(acc => UIntToOH(acc.touch_ways.bits))).map{ case (a, b) => 138 a.valid && a.bits.hit && b(i)}.fold(0.U)(_.asUInt() + _.asUInt())) 139 } 140 for (i <- 0 until nWays) { 141 XSPerfAccumulate(s"refill${i}", io.w.valid && io.w.bits.wayIdx === i.U) 142 } 143 144 val perfEvents = Seq( 145 ("tlbstore_access", io.r.resp.map(_.valid.asUInt()).fold(0.U)(_ + _) ), 146 ("tlbstore_hit ", io.r.resp.map(a => a.valid && a.bits.hit).fold(0.U)(_.asUInt() + _.asUInt())), 147 ) 148 generatePerfEvent() 149 150 println(s"tlb_fa: nSets${nSets} nWays:${nWays}") 151} 152 153@chiselName 154class TLBSA( 155 sameCycle: Boolean, 156 ports: Int, 157 nSets: Int, 158 nWays: Int, 159 sramSinglePort: Boolean, 160 normalPage: Boolean, 161 superPage: Boolean 162)(implicit p: Parameters) extends TlbModule { 163 require(!superPage, "super page should use reg/fa") 164 require(!sameCycle, "sram needs next cycle") 165 166 val io = IO(new TlbStorageIO(nSets, nWays, ports)) 167 168 io.r.req.map(_.ready := { if (sramSinglePort) !io.w.valid else true.B }) 169 val v = RegInit(VecInit(Seq.fill(nSets)(VecInit(Seq.fill(nWays)(false.B))))) 170 171 for (i <- 0 until ports) { // duplicate sram 172 val entries = Module(new SRAMTemplate( 173 new TlbEntry(normalPage, superPage), 174 set = nSets, 175 way = nWays, 176 singlePort = sramSinglePort 177 )) 178 179 val req = io.r.req(i) 180 val resp = io.r.resp(i) 181 val access = io.access(i) 182 183 val vpn = req.bits.vpn 184 val vpn_reg = RegEnable(vpn, req.fire()) 185 186 val ridx = get_set_idx(vpn, nSets) 187 val vidx = RegNext(Mux(req.fire(), v(ridx), VecInit(Seq.fill(nWays)(false.B)))) 188 entries.io.r.req.valid := req.valid 189 entries.io.r.req.bits.apply(setIdx = ridx) 190 191 val data = entries.io.r.resp.data 192 val hitVec = VecInit(data.zip(vidx).map { case (e, vi) => e.hit(vpn_reg, io.csr.satp.asid, nSets) && vi }) 193 resp.bits.hit := Cat(hitVec).orR && RegNext(req.ready, init = false.B) 194 if (nWays == 1) { 195 resp.bits.ppn := data(0).genPPN()(vpn_reg) 196 resp.bits.perm := data(0).perm 197 } else { 198 resp.bits.ppn := ParallelMux(hitVec zip data.map(_.genPPN()(vpn_reg))) 199 resp.bits.perm := ParallelMux(hitVec zip data.map(_.perm)) 200 } 201 io.r.resp_hit_sameCycle(i) := DontCare 202 203 resp.valid := { 204 if (sramSinglePort) RegNext(req.fire()) else RegNext(req.valid) 205 } 206 resp.bits.hit.suggestName("hit") 207 resp.bits.ppn.suggestName("ppn") 208 resp.bits.perm.suggestName("perm") 209 210 access.sets := get_set_idx(vpn_reg, nSets) // no use 211 access.touch_ways.valid := resp.valid && Cat(hitVec).orR 212 access.touch_ways.bits := OHToUInt(hitVec) 213 214 entries.io.w.apply( 215 valid = io.w.valid || io.victim.in.valid, 216 setIdx = Mux(io.w.valid, 217 get_set_idx(io.w.bits.data.entry.tag, nSets), 218 get_set_idx(io.victim.in.bits.entry.tag, nSets)), 219 data = Mux(io.w.valid, 220 (Wire(new TlbEntry(normalPage, superPage)).apply(io.w.bits.data, io.csr.satp.asid, io.w.bits.data_replenish)), 221 io.victim.in.bits.entry), 222 waymask = UIntToOH(io.w.bits.wayIdx) 223 ) 224 } 225 226 when (io.victim.in.valid) { 227 v(get_set_idx(io.victim.in.bits.entry.tag, nSets))(io.w.bits.wayIdx) := true.B 228 } 229 // w has higher priority than victim 230 when (io.w.valid) { 231 v(get_set_idx(io.w.bits.data.entry.tag, nSets))(io.w.bits.wayIdx) := true.B 232 } 233 234 val refill_vpn_reg = RegNext(Mux(io.victim.in.valid, io.victim.in.bits.entry.tag, io.w.bits.data.entry.tag)) 235 val refill_wayIdx_reg = RegNext(io.w.bits.wayIdx) 236 when (RegNext(io.w.valid || io.victim.in.valid)) { 237 io.access.map { access => 238 access.sets := get_set_idx(refill_vpn_reg, nSets) 239 access.touch_ways.valid := true.B 240 access.touch_ways.bits := refill_wayIdx_reg 241 } 242 } 243 244 val sfence = io.sfence 245 val sfence_vpn = sfence.bits.addr.asTypeOf(new VaBundle().cloneType).vpn 246 when (io.sfence.valid) { 247 when (sfence.bits.rs1) { // virtual address *.rs1 <- (rs1===0.U) 248 v.map(a => a.map(b => b := false.B)) 249 }.otherwise { 250 // specific addr but all asid 251 v(get_set_idx(sfence_vpn, nSets)).map(_ := false.B) 252 } 253 } 254 255 io.victim.out := DontCare 256 257 XSPerfAccumulate(s"access", io.r.req.map(_.valid.asUInt()).fold(0.U)(_ + _)) 258 XSPerfAccumulate(s"hit", io.r.resp.map(a => a.valid && a.bits.hit).fold(0.U)(_.asUInt() + _.asUInt())) 259 260 for (i <- 0 until nSets) { 261 for (j <- 0 until nWays) { 262 XSPerfAccumulate(s"refill${i}_${j}", (io.w.valid || io.victim.in.valid) && 263 (Mux(io.w.valid, get_set_idx(io.w.bits.data.entry.tag, nSets), get_set_idx(io.victim.in.bits.entry.tag, nSets)) === i.U) && 264 (j.U === io.w.bits.wayIdx) 265 ) 266 } 267 } 268 269 for (i <- 0 until nSets) { 270 for (j <- 0 until nWays) { 271 XSPerfAccumulate(s"hit${i}_${j}", io.r.resp.map(_.valid) 272 .zip(io.access.map(a => UIntToOH(a.touch_ways.bits)(j))) 273 .map{case(vi, hi) => vi && hi } 274 .zip(io.r.req.map(a => RegNext(get_set_idx(a.bits.vpn, nSets)) === i.U)) 275 .map{a => (a._1 && a._2).asUInt()} 276 .fold(0.U)(_ + _) 277 ) 278 } 279 } 280 281 for (i <- 0 until nSets) { 282 XSPerfAccumulate(s"access${i}", io.r.resp.map(_.valid) 283 .zip(io.r.req.map(a => RegNext(get_set_idx(a.bits.vpn, nSets)) === i.U)) 284 .map{a => (a._1 && a._2).asUInt()} 285 .fold(0.U)(_ + _) 286 ) 287 } 288 289 println(s"tlb_sa: nSets:${nSets} nWays:${nWays}") 290} 291 292object TlbStorage { 293 def apply 294 ( 295 name: String, 296 associative: String, 297 sameCycle: Boolean, 298 ports: Int, 299 nSets: Int, 300 nWays: Int, 301 sramSinglePort: Boolean, 302 saveLevel: Boolean = false, 303 normalPage: Boolean, 304 superPage: Boolean 305 )(implicit p: Parameters) = { 306 if (associative == "fa") { 307 val storage = Module(new TLBFA(sameCycle, ports, nSets, nWays, sramSinglePort, saveLevel, normalPage, superPage)) 308 storage.suggestName(s"tlb_${name}_fa") 309 storage.io 310 } else { 311 val storage = Module(new TLBSA(sameCycle, ports, nSets, nWays, sramSinglePort, normalPage, superPage)) 312 storage.suggestName(s"tlb_${name}_sa") 313 storage.io 314 } 315 } 316} 317