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