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