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 xiangshan._ 23import utils._ 24import utility._ 25import xiangshan.backend.rob.RobPtr 26import xiangshan.backend.fu.util.HasCSRConst 27import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp} 28import freechips.rocketchip.tilelink._ 29import xiangshan.backend.fu.{PMPReqBundle, PMPConfig} 30import xiangshan.backend.fu.PMPBundle 31 32 33abstract class TlbBundle(implicit p: Parameters) extends XSBundle with HasTlbConst 34abstract class TlbModule(implicit p: Parameters) extends XSModule with HasTlbConst 35 36 37class PtePermBundle(implicit p: Parameters) extends TlbBundle { 38 val d = Bool() 39 val a = Bool() 40 val g = Bool() 41 val u = Bool() 42 val x = Bool() 43 val w = Bool() 44 val r = Bool() 45 46 override def toPrintable: Printable = { 47 p"d:${d} a:${a} g:${g} u:${u} x:${x} w:${w} r:${r}"// + 48 //(if(hasV) (p"v:${v}") else p"") 49 } 50} 51 52class TlbPMBundle(implicit p: Parameters) extends TlbBundle { 53 val r = Bool() 54 val w = Bool() 55 val x = Bool() 56 val c = Bool() 57 val atomic = Bool() 58 59 def assign_ap(pm: PMPConfig) = { 60 r := pm.r 61 w := pm.w 62 x := pm.x 63 c := pm.c 64 atomic := pm.atomic 65 } 66} 67 68class TlbPermBundle(implicit p: Parameters) extends TlbBundle { 69 val pf = Bool() // NOTE: if this is true, just raise pf 70 val af = Bool() // NOTE: if this is true, just raise af 71 // pagetable perm (software defined) 72 val d = Bool() 73 val a = Bool() 74 val g = Bool() 75 val u = Bool() 76 val x = Bool() 77 val w = Bool() 78 val r = Bool() 79 80 def apply(item: PtwSectorResp) = { 81 val ptePerm = item.entry.perm.get.asTypeOf(new PtePermBundle().cloneType) 82 this.pf := item.pf 83 this.af := item.af 84 this.d := ptePerm.d 85 this.a := ptePerm.a 86 this.g := ptePerm.g 87 this.u := ptePerm.u 88 this.x := ptePerm.x 89 this.w := ptePerm.w 90 this.r := ptePerm.r 91 92 this 93 } 94 95 def applyS2(item: HptwResp) = { 96 val ptePerm = item.entry.perm.get.asTypeOf(new PtePermBundle().cloneType) 97 this.pf := item.gpf 98 this.af := item.gaf 99 this.d := ptePerm.d 100 this.a := ptePerm.a 101 this.g := ptePerm.g 102 this.u := ptePerm.u 103 this.x := ptePerm.x 104 this.w := ptePerm.w 105 this.r := ptePerm.r 106 107 this 108 } 109 110 override def toPrintable: Printable = { 111 p"pf:${pf} af:${af} d:${d} a:${a} g:${g} u:${u} x:${x} w:${w} r:${r} " 112 } 113} 114 115class TlbSectorPermBundle(implicit p: Parameters) extends TlbBundle { 116 val pf = Bool() // NOTE: if this is true, just raise pf 117 val af = Bool() // NOTE: if this is true, just raise af 118 // pagetable perm (software defined) 119 val d = Bool() 120 val a = Bool() 121 val g = Bool() 122 val u = Bool() 123 val x = Bool() 124 val w = Bool() 125 val r = Bool() 126 127 def apply(item: PtwSectorResp) = { 128 val ptePerm = item.entry.perm.get.asTypeOf(new PtePermBundle().cloneType) 129 this.pf := item.pf 130 this.af := item.af 131 this.d := ptePerm.d 132 this.a := ptePerm.a 133 this.g := ptePerm.g 134 this.u := ptePerm.u 135 this.x := ptePerm.x 136 this.w := ptePerm.w 137 this.r := ptePerm.r 138 139 this 140 } 141 override def toPrintable: Printable = { 142 p"pf:${pf} af:${af} d:${d} a:${a} g:${g} u:${u} x:${x} w:${w} r:${r} " 143 } 144} 145 146// multi-read && single-write 147// input is data, output is hot-code(not one-hot) 148class CAMTemplate[T <: Data](val gen: T, val set: Int, val readWidth: Int)(implicit p: Parameters) extends TlbModule { 149 val io = IO(new Bundle { 150 val r = new Bundle { 151 val req = Input(Vec(readWidth, gen)) 152 val resp = Output(Vec(readWidth, Vec(set, Bool()))) 153 } 154 val w = Input(new Bundle { 155 val valid = Bool() 156 val bits = new Bundle { 157 val index = UInt(log2Up(set).W) 158 val data = gen 159 } 160 }) 161 }) 162 163 val wordType = UInt(gen.getWidth.W) 164 val array = Reg(Vec(set, wordType)) 165 166 io.r.resp.zipWithIndex.map{ case (a,i) => 167 a := array.map(io.r.req(i).asUInt === _) 168 } 169 170 when (io.w.valid) { 171 array(io.w.bits.index) := io.w.bits.data.asUInt 172 } 173} 174 175class TlbEntry(pageNormal: Boolean, pageSuper: Boolean)(implicit p: Parameters) extends TlbBundle { 176 require(pageNormal || pageSuper) 177 178 val tag = if (!pageNormal) UInt((vpnLen - vpnnLen).W) 179 else UInt(vpnLen.W) 180 val asid = UInt(asidLen.W) 181 val level = if (!pageNormal) Some(UInt(1.W)) 182 else if (!pageSuper) None 183 else Some(UInt(2.W)) 184 val ppn = if (!pageNormal) UInt((ppnLen - vpnnLen).W) 185 else UInt(ppnLen.W) 186 val perm = new TlbPermBundle 187 188 val g_perm = new TlbPermBundle 189 val vmid = UInt(vmidLen.W) 190 val s2xlate = UInt(2.W) 191 192 /** s2xlate usage: 193 * bits0 0: disable s2xlate 194 * 1: enable s2xlate 195 * bits1 0: stage 1 and stage 2 if bits0 is 1 196 * 1: Only stage 2 if bits0 is 1 197 * */ 198 199 /** level usage: 200 * !PageSuper: page is only normal, level is None, match all the tag 201 * !PageNormal: page is only super, level is a Bool(), match high 9*2 parts 202 * bits0 0: need mid 9bits 203 * 1: no need mid 9bits 204 * PageSuper && PageNormal: page hold all the three type, 205 * bits0 0: need low 9bits 206 * bits1 0: need mid 9bits 207 */ 208 209 210 def hit(vpn: UInt, asid: UInt, nSets: Int = 1, ignoreAsid: Boolean = false, vmid: UInt, hasS2xlate: Bool, onlyS2: Bool): Bool = { 211 val asid_hit = Mux(hasS2xlate && onlyS2, true.B, if (ignoreAsid) true.B else (this.asid === asid)) 212 val vmid_hit = Mux(hasS2xlate, this.vmid === vmid, true.B) 213 214 // NOTE: for timing, dont care low set index bits at hit check 215 // do not need store the low bits actually 216 if (!pageSuper) asid_hit && drop_set_equal(vpn, tag, nSets) && vmid_hit 217 else if (!pageNormal) { 218 val tag_match_hi = tag(vpnnLen*2-1, vpnnLen) === vpn(vpnnLen*3-1, vpnnLen*2) 219 val tag_match_mi = tag(vpnnLen-1, 0) === vpn(vpnnLen*2-1, vpnnLen) 220 val tag_match = tag_match_hi && (level.get.asBool || tag_match_mi) 221 asid_hit && tag_match && vmid_hit 222 } 223 else { 224 val tmp_level = level.get 225 val tag_match_hi = tag(vpnnLen*3-1, vpnnLen*2) === vpn(vpnnLen*3-1, vpnnLen*2) 226 val tag_match_mi = tag(vpnnLen*2-1, vpnnLen) === vpn(vpnnLen*2-1, vpnnLen) 227 val tag_match_lo = tag(vpnnLen-1, 0) === vpn(vpnnLen-1, 0) // if pageNormal is false, this will always be false 228 val tag_match = tag_match_hi && (tmp_level(1) || tag_match_mi) && (tmp_level(0) || tag_match_lo) 229 asid_hit && tag_match && vmid_hit 230 } 231 } 232 233 def apply(item: PtwRespS2, pm: PMPConfig): TlbEntry = { 234 this.asid := item.s1.entry.asid 235 val inner_level = item.s1.entry.level.getOrElse(0.U) max item.s2.entry.level.getOrElse(0.U) 236 this.level.map(_ := { if (pageNormal && pageSuper) MuxLookup(inner_level, 0.U)(Seq( 237 0.U -> 3.U, 238 1.U -> 1.U, 239 2.U -> 0.U )) 240 else if (pageSuper) ~inner_level(0) 241 else 0.U }) 242 val s1tag = {if (pageNormal) Cat(item.s1.entry.tag, OHToUInt(item.s1.pteidx)) else item.s1.entry.tag(sectorvpnLen - 1, vpnnLen - sectortlbwidth)} 243 val s2tag = {if (pageNormal) item.s2.entry.tag else item.s2.entry.tag(vpnLen - 1, vpnnLen)} 244 this.tag := Mux(item.s2xlate === onlyStage2, s2tag, s1tag) 245 246 val s1ppn = { 247 if (!pageNormal) item.s1.entry.ppn(sectorppnLen - 1, vpnnLen - sectortlbwidth) 248 else Cat(item.s1.entry.ppn, item.s1.ppn_low(OHToUInt(item.s1.pteidx))) 249 } 250 val s2ppn = { 251 if (!pageNormal) item.s2.entry.ppn(ppnLen - 1, vpnnLen) 252 else item.s2.entry.ppn 253 } 254 this.ppn := Mux(item.s2xlate === noS2xlate || item.s2xlate === onlyStage1, s1ppn, s2ppn) 255 this.perm.apply(item.s1) 256 this.vmid := item.s1.entry.vmid.getOrElse(0.U) 257 this.g_perm.applyS2(item.s2) 258 this.s2xlate := item.s2xlate 259 this 260 } 261 262 // 4KB is normal entry, 2MB/1GB is considered as super entry 263 def is_normalentry(): Bool = { 264 if (!pageSuper) { true.B } 265 else if (!pageNormal) { false.B } 266 else { level.get === 0.U } 267 } 268 269 270 def genPPN(saveLevel: Boolean = false, valid: Bool = false.B)(vpn: UInt) : UInt = { 271 val inner_level = level.getOrElse(0.U) 272 val ppn_res = if (!pageSuper) ppn 273 else if (!pageNormal) Cat(ppn(ppnLen-vpnnLen-1, vpnnLen), 274 Mux(inner_level(0), vpn(vpnnLen*2-1, vpnnLen), ppn(vpnnLen-1,0)), 275 vpn(vpnnLen-1, 0)) 276 else Cat(ppn(ppnLen-1, vpnnLen*2), 277 Mux(inner_level(1), vpn(vpnnLen*2-1, vpnnLen), ppn(vpnnLen*2-1, vpnnLen)), 278 Mux(inner_level(0), vpn(vpnnLen-1, 0), ppn(vpnnLen-1, 0))) 279 280 if (saveLevel) Cat(ppn(ppn.getWidth-1, vpnnLen*2), RegEnable(ppn_res(vpnnLen*2-1, 0), valid)) 281 else ppn_res 282 } 283 284 override def toPrintable: Printable = { 285 val inner_level = level.getOrElse(2.U) 286 p"asid: ${asid} level:${inner_level} vpn:${Hexadecimal(tag)} ppn:${Hexadecimal(ppn)} perm:${perm}" 287 } 288 289} 290 291class TlbSectorEntry(pageNormal: Boolean, pageSuper: Boolean)(implicit p: Parameters) extends TlbBundle { 292 require(pageNormal || pageSuper) 293 294 val tag = if (!pageNormal) UInt((vpnLen - vpnnLen).W) 295 else UInt(sectorvpnLen.W) 296 val asid = UInt(asidLen.W) 297 val level = if (!pageNormal) Some(UInt(1.W)) 298 else if (!pageSuper) None 299 else Some(UInt(2.W)) 300 val ppn = if (!pageNormal) UInt((ppnLen - vpnnLen).W) 301 else UInt(sectorppnLen.W) //only used when disable s2xlate 302 val perm = new TlbSectorPermBundle 303 val valididx = Vec(tlbcontiguous, Bool()) 304 val pteidx = Vec(tlbcontiguous, Bool()) 305 val ppn_low = Vec(tlbcontiguous, UInt(sectortlbwidth.W)) 306 307 val g_perm = new TlbPermBundle 308 val vmid = UInt(vmidLen.W) 309 val s2xlate = UInt(2.W) 310 311 /** s2xlate usage: 312 * bits0 0: disable s2xlate 313 * 1: enable s2xlate 314 * bits1 0: stage 1 and stage 2 if bits0 is 1 315 * 1: Only stage 2 if bits0 is 1 316 * */ 317 318 /** level usage: 319 * !PageSuper: page is only normal, level is None, match all the tag 320 * !PageNormal: page is only super, level is a Bool(), match high 9*2 parts 321 * bits0 0: need mid 9bits 322 * 1: no need mid 9bits 323 * PageSuper && PageNormal: page hold all the three type, 324 * bits0 0: need low 9bits 325 * bits1 0: need mid 9bits 326 */ 327 328 def hit(vpn: UInt, asid: UInt, nSets: Int = 1, ignoreAsid: Boolean = false, vmid: UInt, hasS2xlate: Bool, onlyS2: Bool = false.B, onlyS1: Bool = false.B): Bool = { 329 val asid_hit = Mux(hasS2xlate && onlyS2, true.B, if (ignoreAsid) true.B else (this.asid === asid)) 330 val addr_low_hit = valididx(vpn(2, 0)) 331 val vmid_hit = Mux(hasS2xlate, this.vmid === vmid, true.B) 332 val isPageSuper = !(level.getOrElse(0.U) === 0.U) 333 val pteidx_hit = Mux(hasS2xlate && !isPageSuper && !onlyS1, pteidx(vpn(2, 0)), true.B) 334 // NOTE: for timing, dont care low set index bits at hit check 335 // do not need store the low bits actually 336 if (!pageSuper) asid_hit && drop_set_equal(vpn(vpn.getWidth - 1, sectortlbwidth), tag, nSets) && addr_low_hit && vmid_hit && pteidx_hit 337 else if (!pageNormal) { 338 val tag_match_hi = tag(vpnnLen * 2 - 1, vpnnLen) === vpn(vpnnLen * 3 - 1, vpnnLen * 2) 339 val tag_match_mi = tag(vpnnLen - 1, 0) === vpn(vpnnLen * 2 - 1, vpnnLen) 340 val tag_match = tag_match_hi && (level.get.asBool || tag_match_mi) 341 asid_hit && tag_match && addr_low_hit && vmid_hit && pteidx_hit 342 } 343 else { 344 val tmp_level = level.get 345 val tag_match_hi = tag(vpnnLen * 3 - sectortlbwidth - 1, vpnnLen * 2 - sectortlbwidth) === vpn(vpnnLen * 3 - 1, vpnnLen * 2) 346 val tag_match_mi = tag(vpnnLen * 2 - sectortlbwidth - 1, vpnnLen - sectortlbwidth) === vpn(vpnnLen * 2 - 1, vpnnLen) 347 val tag_match_lo = tag(vpnnLen - sectortlbwidth - 1, 0) === vpn(vpnnLen - 1, sectortlbwidth) // if pageNormal is false, this will always be false 348 val tag_match = tag_match_hi && (tmp_level(1) || tag_match_mi) && (tmp_level(0) || tag_match_lo) 349 asid_hit && tag_match && addr_low_hit && vmid_hit && pteidx_hit 350 } 351 } 352 353 def wbhit(data: PtwRespS2, asid: UInt, nSets: Int = 1, ignoreAsid: Boolean = false, s2xlate: UInt): Bool = { 354 val s1vpn = data.s1.entry.tag 355 val s2vpn = data.s2.entry.tag(vpnLen - 1, sectortlbwidth) 356 val wb_vpn = Mux(s2xlate === onlyStage2, s2vpn, s1vpn) 357 val vpn = Cat(wb_vpn, 0.U(sectortlbwidth.W)) 358 val asid_hit = if (ignoreAsid) true.B else (this.asid === asid) 359 val vpn_hit = Wire(Bool()) 360 val index_hit = Wire(Vec(tlbcontiguous, Bool())) 361 val wb_valididx = Wire(Vec(tlbcontiguous, Bool())) 362 //for onlystage2 entry, every valididx is true 363 wb_valididx := Mux(s2xlate === onlyStage2, VecInit(UIntToOH(data.s2.entry.tag(sectortlbwidth - 1, 0)).asBools), data.s1.valididx) 364 val s2xlate_hit = s2xlate === this.s2xlate 365 // NOTE: for timing, dont care low set index bits at hit check 366 // do not need store the low bits actually 367 if (!pageSuper) { 368 vpn_hit := asid_hit && drop_set_equal(vpn(vpn.getWidth - 1, sectortlbwidth), tag, nSets) 369 } 370 else if (!pageNormal) { 371 val tag_match_hi = tag(vpnnLen * 2 - 1, vpnnLen - sectortlbwidth) === vpn(vpnnLen * 3 - 1, vpnnLen * 2) 372 val tag_match_mi = tag(vpnnLen - 1, 0) === vpn(vpnnLen * 2 - 1, vpnnLen) 373 val tag_match = tag_match_hi && (level.get.asBool || tag_match_mi) 374 vpn_hit := asid_hit && tag_match 375 } 376 else { 377 val tmp_level = level.get 378 val tag_match_hi = tag(vpnnLen * 3 - sectortlbwidth - 1, vpnnLen * 2 - sectortlbwidth) === vpn(vpnnLen * 3 - 1, vpnnLen * 2) 379 val tag_match_mi = tag(vpnnLen * 2 - sectortlbwidth - 1, vpnnLen - sectortlbwidth) === vpn(vpnnLen * 2 - 1, vpnnLen) 380 val tag_match_lo = tag(vpnnLen - sectortlbwidth - 1, 0) === vpn(vpnnLen - 1, sectortlbwidth) // if pageNormal is false, this will always be false 381 val tag_match = tag_match_hi && (tmp_level(1) || tag_match_mi) && (tmp_level(0) || tag_match_lo) 382 vpn_hit := asid_hit && tag_match 383 } 384 385 for (i <- 0 until tlbcontiguous) { 386 index_hit(i) := wb_valididx(i) && valididx(i) 387 } 388 389 // For example, tlb req to page cache with vpn 0x10 390 // At this time, 0x13 has not been paged, so page cache only resp 0x10 391 // When 0x13 refill to page cache, previous item will be flushed 392 // Now 0x10 and 0x13 are both valid in page cache 393 // However, when 0x13 refill to tlb, will trigger multi hit 394 // So will only trigger multi-hit when PopCount(data.valididx) = 1 395 vpn_hit && index_hit.reduce(_ || _) && PopCount(wb_valididx) === 1.U && s2xlate_hit 396 } 397 398 def apply(item: PtwRespS2): TlbSectorEntry = { 399 this.asid := item.s1.entry.asid 400 val inner_level = MuxLookup(item.s2xlate, 2.U, Seq( 401 onlyStage1 -> item.s1.entry.level.getOrElse(0.U), 402 onlyStage2 -> item.s2.entry.level.getOrElse(0.U), 403 allStage -> (item.s1.entry.level.getOrElse(0.U) max item.s2.entry.level.getOrElse(0.U)), 404 noS2xlate -> item.s1.entry.level.getOrElse(0.U) 405 )) 406 this.level.map(_ := { if (pageNormal && pageSuper) MuxLookup(inner_level, 0.U)(Seq( 407 0.U -> 3.U, 408 1.U -> 1.U, 409 2.U -> 0.U )) 410 else if (pageSuper) ~inner_level(0) 411 else 0.U }) 412 this.perm.apply(item.s1) 413 414 val s2page_pageSuper = item.s2.entry.level.getOrElse(0.U) =/= 2.U 415 this.pteidx := Mux(item.s2xlate === onlyStage2, VecInit(UIntToOH(item.s2.entry.tag(sectortlbwidth - 1, 0)).asBools), item.s1.pteidx) 416 val s2_valid = Mux(s2page_pageSuper, VecInit(Seq.fill(tlbcontiguous)(true.B)), VecInit(UIntToOH(item.s2.entry.tag(sectortlbwidth - 1, 0)).asBools)) 417 this.valididx := Mux(item.s2xlate === onlyStage2, s2_valid, item.s1.valididx) 418 419 val s1tag = {if (pageNormal) item.s1.entry.tag else item.s1.entry.tag(sectorvpnLen - 1, vpnnLen - sectortlbwidth)} 420 val s2tag = {if (pageNormal) item.s2.entry.tag(vpnLen - 1, sectortlbwidth) else item.s2.entry.tag(vpnLen - 1, vpnnLen)} 421 this.tag := Mux(item.s2xlate === onlyStage2, s2tag, s1tag) 422 423 val s1ppn = { 424 if (!pageNormal) item.s1.entry.ppn(sectorppnLen - 1, vpnnLen - sectortlbwidth) else item.s1.entry.ppn 425 } 426 val s1ppn_low = item.s1.ppn_low 427 val s2ppn = { 428 if (!pageNormal) item.s2.entry.ppn(ppnLen - 1, vpnnLen) else item.s2.entry.ppn(ppnLen - 1, sectortlbwidth) 429 } 430 val s2ppn_low = VecInit(Seq.fill(tlbcontiguous)(item.s2.entry.ppn(sectortlbwidth - 1, 0))) 431 this.ppn := Mux(item.s2xlate === noS2xlate || item.s2xlate === onlyStage1, s1ppn, s2ppn) 432 this.ppn_low := Mux(item.s2xlate === noS2xlate || item.s2xlate === onlyStage1, s1ppn_low, s2ppn_low) 433 this.vmid := item.s1.entry.vmid.getOrElse(0.U) 434 this.g_perm.applyS2(item.s2) 435 this.s2xlate := item.s2xlate 436 this 437 } 438 439 // 4KB is normal entry, 2MB/1GB is considered as super entry 440 def is_normalentry(): Bool = { 441 if (!pageSuper) { true.B } 442 else if (!pageNormal) { false.B } 443 else { level.get === 0.U } 444 } 445 446 447 def genPPN(saveLevel: Boolean = false, valid: Bool = false.B)(vpn: UInt) : UInt = { 448 val inner_level = level.getOrElse(0.U) 449 val ppn_res = if (!pageSuper) Cat(ppn, ppn_low(vpn(sectortlbwidth - 1, 0))) 450 else if (!pageNormal) Cat(ppn(ppnLen - vpnnLen - 1, vpnnLen), 451 Mux(inner_level(0), vpn(vpnnLen * 2 - 1, vpnnLen), ppn(vpnnLen - 1,0)), 452 vpn(vpnnLen - 1, 0)) 453 else Cat(ppn(sectorppnLen - 1, vpnnLen * 2 - sectortlbwidth), 454 Mux(inner_level(1), vpn(vpnnLen * 2 - 1, vpnnLen), ppn(vpnnLen * 2 - sectortlbwidth - 1, vpnnLen - sectortlbwidth)), 455 Mux(inner_level(0), vpn(vpnnLen - 1, 0), Cat(ppn(vpnnLen - sectortlbwidth - 1, 0), ppn_low(vpn(sectortlbwidth - 1, 0))))) 456 457 if (saveLevel) { 458 if (ppn.getWidth == ppnLen - vpnnLen) { 459 Cat(ppn(ppn.getWidth - 1, vpnnLen * 2), RegEnable(ppn_res(vpnnLen * 2 - 1, 0), valid)) 460 } else { 461 require(ppn.getWidth == sectorppnLen) 462 Cat(ppn(ppn.getWidth - 1, vpnnLen * 2 - sectortlbwidth), RegEnable(ppn_res(vpnnLen * 2 - 1, 0), valid)) 463 } 464 } 465 else ppn_res 466 } 467 468 def hasS2xlate(): Bool = { 469 this.s2xlate =/= noS2xlate 470 } 471 472 override def toPrintable: Printable = { 473 val inner_level = level.getOrElse(2.U) 474 p"asid: ${asid} level:${inner_level} vpn:${Hexadecimal(tag)} ppn:${Hexadecimal(ppn)} perm:${perm}" 475 } 476 477} 478 479object TlbCmd { 480 def read = "b00".U 481 def write = "b01".U 482 def exec = "b10".U 483 484 def atom_read = "b100".U // lr 485 def atom_write = "b101".U // sc / amo 486 487 def apply() = UInt(3.W) 488 def isRead(a: UInt) = a(1,0)===read 489 def isWrite(a: UInt) = a(1,0)===write 490 def isExec(a: UInt) = a(1,0)===exec 491 492 def isAtom(a: UInt) = a(2) 493 def isAmo(a: UInt) = a===atom_write // NOTE: sc mixed 494} 495 496class TlbStorageIO(nSets: Int, nWays: Int, ports: Int, nDups: Int = 1)(implicit p: Parameters) extends MMUIOBaseBundle { 497 val r = new Bundle { 498 val req = Vec(ports, Flipped(DecoupledIO(new Bundle { 499 val vpn = Output(UInt(vpnLen.W)) 500 val s2xlate = Output(UInt(2.W)) // 0 bit: has s2xlate, 1 bit: Only valid when 0 bit is 1. If 0, all stage; if 1, only stage 2 501 }))) 502 val resp = Vec(ports, ValidIO(new Bundle{ 503 val hit = Output(Bool()) 504 val ppn = Vec(nDups, Output(UInt(ppnLen.W))) 505 val perm = Vec(nDups, Output(new TlbSectorPermBundle())) 506 val g_perm = Vec(nDups, Output(new TlbPermBundle())) 507 val s2xlate = Vec(nDups, Output(UInt(2.W))) 508 })) 509 } 510 val w = Flipped(ValidIO(new Bundle { 511 val wayIdx = Output(UInt(log2Up(nWays).W)) 512 val data = Output(new PtwRespS2) 513 })) 514 val access = Vec(ports, new ReplaceAccessBundle(nSets, nWays)) 515 516 def r_req_apply(valid: Bool, vpn: UInt, i: Int, s2xlate:UInt): Unit = { 517 this.r.req(i).valid := valid 518 this.r.req(i).bits.vpn := vpn 519 this.r.req(i).bits.s2xlate := s2xlate 520 521 } 522 523 def r_resp_apply(i: Int) = { 524 (this.r.resp(i).bits.hit, this.r.resp(i).bits.ppn, this.r.resp(i).bits.perm, this.r.resp(i).bits.g_perm) 525 } 526 527 def w_apply(valid: Bool, wayIdx: UInt, data: PtwRespS2): Unit = { 528 this.w.valid := valid 529 this.w.bits.wayIdx := wayIdx 530 this.w.bits.data := data 531 } 532 533} 534 535class TlbStorageWrapperIO(ports: Int, q: TLBParameters, nDups: Int = 1)(implicit p: Parameters) extends MMUIOBaseBundle { 536 val r = new Bundle { 537 val req = Vec(ports, Flipped(DecoupledIO(new Bundle { 538 val vpn = Output(UInt(vpnLen.W)) 539 val s2xlate = Output(UInt(2.W)) 540 }))) 541 val resp = Vec(ports, ValidIO(new Bundle{ 542 val hit = Output(Bool()) 543 val ppn = Vec(nDups, Output(UInt(ppnLen.W))) 544 val perm = Vec(nDups, Output(new TlbPermBundle())) 545 val g_perm = Vec(nDups, Output(new TlbPermBundle())) 546 val s2xlate = Vec(nDups, Output(UInt(2.W))) 547 })) 548 } 549 val w = Flipped(ValidIO(new Bundle { 550 val data = Output(new PtwRespS2) 551 })) 552 val replace = if (q.outReplace) Flipped(new TlbReplaceIO(ports, q)) else null 553 554 def r_req_apply(valid: Bool, vpn: UInt, i: Int, s2xlate: UInt): Unit = { 555 this.r.req(i).valid := valid 556 this.r.req(i).bits.vpn := vpn 557 this.r.req(i).bits.s2xlate := s2xlate 558 } 559 560 def r_resp_apply(i: Int) = { 561 (this.r.resp(i).bits.hit, this.r.resp(i).bits.ppn, this.r.resp(i).bits.perm, 562 this.r.resp(i).bits.super_hit, this.r.resp(i).bits.super_ppn, this.r.resp(i).bits.spm, 563 this.r.resp(i).bits.g_perm, this.r.resp(i).bits.s2xlate) 564 } 565 566 def w_apply(valid: Bool, data: PtwRespS2): Unit = { 567 this.w.valid := valid 568 this.w.bits.data := data 569 } 570} 571 572class ReplaceAccessBundle(nSets: Int, nWays: Int)(implicit p: Parameters) extends TlbBundle { 573 val sets = Output(UInt(log2Up(nSets).W)) 574 val touch_ways = ValidIO(Output(UInt(log2Up(nWays).W))) 575} 576 577class ReplaceIO(Width: Int, nSets: Int, nWays: Int)(implicit p: Parameters) extends TlbBundle { 578 val access = Vec(Width, Flipped(new ReplaceAccessBundle(nSets, nWays))) 579 580 val refillIdx = Output(UInt(log2Up(nWays).W)) 581 val chosen_set = Flipped(Output(UInt(log2Up(nSets).W))) 582 583 def apply_sep(in: Seq[ReplaceIO], vpn: UInt): Unit = { 584 for ((ac_rep, ac_tlb) <- access.zip(in.map(a => a.access.map(b => b)).flatten)) { 585 ac_rep := ac_tlb 586 } 587 this.chosen_set := get_set_idx(vpn, nSets) 588 in.map(a => a.refillIdx := this.refillIdx) 589 } 590} 591 592class TlbReplaceIO(Width: Int, q: TLBParameters)(implicit p: Parameters) extends 593 TlbBundle { 594 val page = new ReplaceIO(Width, q.NSets, q.NWays) 595 596 def apply_sep(in: Seq[TlbReplaceIO], vpn: UInt) = { 597 this.page.apply_sep(in.map(_.page), vpn) 598 } 599 600} 601 602class MemBlockidxBundle(implicit p: Parameters) extends TlbBundle { 603 val is_ld = Bool() 604 val is_st = Bool() 605 val idx = 606 if (VirtualLoadQueueSize >= StoreQueueSize) { 607 val idx = UInt(log2Ceil(VirtualLoadQueueSize).W) 608 idx 609 } else { 610 val idx = UInt(log2Ceil(StoreQueueSize).W) 611 idx 612 } 613} 614 615class TlbReq(implicit p: Parameters) extends TlbBundle { 616 val vaddr = Output(UInt(VAddrBits.W)) 617 val cmd = Output(TlbCmd()) 618 val hyperinst = Output(Bool()) 619 val hlvx = Output(Bool()) 620 val size = Output(UInt(log2Ceil(log2Ceil(XLEN/8)+1).W)) 621 val kill = Output(Bool()) // Use for blocked tlb that need sync with other module like icache 622 val memidx = Output(new MemBlockidxBundle) 623 // do not translate, but still do pmp/pma check 624 val no_translate = Output(Bool()) 625 val debug = new Bundle { 626 val pc = Output(UInt(XLEN.W)) 627 val robIdx = Output(new RobPtr) 628 val isFirstIssue = Output(Bool()) 629 } 630 631 // Maybe Block req needs a kill: for itlb, itlb and icache may not sync, itlb should wait icache to go ahead 632 override def toPrintable: Printable = { 633 p"vaddr:0x${Hexadecimal(vaddr)} cmd:${cmd} kill:${kill} pc:0x${Hexadecimal(debug.pc)} robIdx:${debug.robIdx}" 634 } 635} 636 637class TlbExceptionBundle(implicit p: Parameters) extends TlbBundle { 638 val ld = Output(Bool()) 639 val st = Output(Bool()) 640 val instr = Output(Bool()) 641} 642 643class TlbResp(nDups: Int = 1)(implicit p: Parameters) extends TlbBundle { 644 val paddr = Vec(nDups, Output(UInt(PAddrBits.W))) 645 val gpaddr = Vec(nDups, Output(UInt(GPAddrBits.W))) 646 val miss = Output(Bool()) 647 val excp = Vec(nDups, new Bundle { 648 val gpf = new TlbExceptionBundle() 649 val pf = new TlbExceptionBundle() 650 val af = new TlbExceptionBundle() 651 }) 652 val ptwBack = Output(Bool()) // when ptw back, wake up replay rs's state 653 val memidx = Output(new MemBlockidxBundle) 654 655 val debug = new Bundle { 656 val robIdx = Output(new RobPtr) 657 val isFirstIssue = Output(Bool()) 658 } 659 override def toPrintable: Printable = { 660 p"paddr:0x${Hexadecimal(paddr(0))} miss:${miss} excp.pf: ld:${excp(0).pf.ld} st:${excp(0).pf.st} instr:${excp(0).pf.instr} ptwBack:${ptwBack}" 661 } 662} 663 664class TlbRequestIO(nRespDups: Int = 1)(implicit p: Parameters) extends TlbBundle { 665 val req = DecoupledIO(new TlbReq) 666 val req_kill = Output(Bool()) 667 val resp = Flipped(DecoupledIO(new TlbResp(nRespDups))) 668} 669 670class TlbPtwIO(Width: Int = 1)(implicit p: Parameters) extends TlbBundle { 671 val req = Vec(Width, DecoupledIO(new PtwReq)) 672 val resp = Flipped(DecoupledIO(new PtwRespS2)) 673 674 675 override def toPrintable: Printable = { 676 p"req(0):${req(0).valid} ${req(0).ready} ${req(0).bits} | resp:${resp.valid} ${resp.ready} ${resp.bits}" 677 } 678} 679 680class TlbPtwIOwithMemIdx(Width: Int = 1)(implicit p: Parameters) extends TlbBundle { 681 val req = Vec(Width, DecoupledIO(new PtwReqwithMemIdx)) 682 val resp = Flipped(DecoupledIO(new PtwRespS2withMemIdx())) 683 684 685 override def toPrintable: Printable = { 686 p"req(0):${req(0).valid} ${req(0).ready} ${req(0).bits} | resp:${resp.valid} ${resp.ready} ${resp.bits}" 687 } 688} 689 690class TlbHintReq(implicit p: Parameters) extends TlbBundle { 691 val id = Output(UInt(log2Up(loadfiltersize).W)) 692 val full = Output(Bool()) 693} 694 695class TLBHintResp(implicit p: Parameters) extends TlbBundle { 696 val id = Output(UInt(log2Up(loadfiltersize).W)) 697 // When there are multiple matching entries for PTW resp in filter 698 // e.g. vaddr 0, 0x80000000. vaddr 1, 0x80010000 699 // these two vaddrs are not in a same 4K Page, so will send to ptw twice 700 // However, when ptw resp, if they are in a 1G or 2M huge page 701 // The two entries will both hit, and both need to replay 702 val replay_all = Output(Bool()) 703} 704 705class TlbHintIO(implicit p: Parameters) extends TlbBundle { 706 val req = Vec(exuParameters.LduCnt, new TlbHintReq) 707 val resp = ValidIO(new TLBHintResp) 708} 709 710class MMUIOBaseBundle(implicit p: Parameters) extends TlbBundle { 711 val sfence = Input(new SfenceBundle) 712 val csr = Input(new TlbCsrBundle) 713 714 def base_connect(sfence: SfenceBundle, csr: TlbCsrBundle): Unit = { 715 this.sfence <> sfence 716 this.csr <> csr 717 } 718 719 // overwrite satp. write satp will cause flushpipe but csr.priv won't 720 // satp will be dealyed several cycles from writing, but csr.priv won't 721 // so inside mmu, these two signals should be divided 722 def base_connect(sfence: SfenceBundle, csr: TlbCsrBundle, satp: TlbSatpBundle) = { 723 this.sfence <> sfence 724 this.csr <> csr 725 this.csr.satp := satp 726 } 727} 728 729class TlbRefilltoMemIO()(implicit p: Parameters) extends TlbBundle { 730 val valid = Bool() 731 val memidx = new MemBlockidxBundle 732} 733 734class TlbIO(Width: Int, nRespDups: Int = 1, q: TLBParameters)(implicit p: Parameters) extends 735 MMUIOBaseBundle { 736 val hartId = Input(UInt(hartIdLen.W)) 737 val requestor = Vec(Width, Flipped(new TlbRequestIO(nRespDups))) 738 val flushPipe = Vec(Width, Input(Bool())) 739 val ptw = new TlbPtwIOwithMemIdx(Width) 740 val refill_to_mem = Output(new TlbRefilltoMemIO()) 741 val replace = if (q.outReplace) Flipped(new TlbReplaceIO(Width, q)) else null 742 val pmp = Vec(Width, ValidIO(new PMPReqBundle())) 743 val tlbreplay = Vec(Width, Output(Bool())) 744} 745 746class VectorTlbPtwIO(Width: Int)(implicit p: Parameters) extends TlbBundle { 747 val req = Vec(Width, DecoupledIO(new PtwReqwithMemIdx())) 748 val resp = Flipped(DecoupledIO(new Bundle { 749 val data = new PtwRespS2withMemIdx 750 val vector = Output(Vec(Width, Bool())) 751 })) 752 753 def connect(normal: TlbPtwIOwithMemIdx): Unit = { 754 req <> normal.req 755 resp.ready := normal.resp.ready 756 normal.resp.bits := resp.bits.data 757 normal.resp.valid := resp.valid 758 } 759} 760 761/**************************** L2TLB *************************************/ 762abstract class PtwBundle(implicit p: Parameters) extends XSBundle with HasPtwConst 763abstract class PtwModule(outer: L2TLB) extends LazyModuleImp(outer) 764 with HasXSParameter with HasPtwConst 765 766class PteBundle(implicit p: Parameters) extends PtwBundle{ 767 val reserved = UInt(pteResLen.W) 768 val ppn_high = UInt(ppnHignLen.W) 769 val ppn = UInt(ppnLen.W) 770 val rsw = UInt(2.W) 771 val perm = new Bundle { 772 val d = Bool() 773 val a = Bool() 774 val g = Bool() 775 val u = Bool() 776 val x = Bool() 777 val w = Bool() 778 val r = Bool() 779 val v = Bool() 780 } 781 782 def unaligned(level: UInt) = { 783 isLeaf() && !(level === 2.U || 784 level === 1.U && ppn(vpnnLen-1, 0) === 0.U || 785 level === 0.U && ppn(vpnnLen*2-1, 0) === 0.U) 786 } 787 788 def isPf(level: UInt) = { 789 !perm.v || (!perm.r && perm.w) || unaligned(level) 790 } 791 792 // paddr of Xiangshan is 36 bits but ppn of sv39 is 44 bits 793 // access fault will be raised when ppn >> ppnLen is not zero 794 def isAf() = { 795 !(ppn_high === 0.U) 796 } 797 798 def isLeaf() = { 799 perm.r || perm.x || perm.w 800 } 801 802 def getPerm() = { 803 val pm = Wire(new PtePermBundle) 804 pm.d := perm.d 805 pm.a := perm.a 806 pm.g := perm.g 807 pm.u := perm.u 808 pm.x := perm.x 809 pm.w := perm.w 810 pm.r := perm.r 811 pm 812 } 813 814 override def toPrintable: Printable = { 815 p"ppn:0x${Hexadecimal(ppn)} perm:b${Binary(perm.asUInt)}" 816 } 817} 818 819class PtwEntry(tagLen: Int, hasPerm: Boolean = false, hasLevel: Boolean = false)(implicit p: Parameters) extends PtwBundle { 820 val tag = UInt(tagLen.W) 821 val asid = UInt(asidLen.W) 822 val vmid = if (HasHExtension) Some(UInt(vmidLen.W)) else None 823 val ppn = UInt(ppnLen.W) 824 val perm = if (hasPerm) Some(new PtePermBundle) else None 825 val level = if (hasLevel) Some(UInt(log2Up(Level).W)) else None 826 val prefetch = Bool() 827 val v = Bool() 828 829 def is_normalentry(): Bool = { 830 if (!hasLevel) true.B 831 else level.get === 2.U 832 } 833 834 def genPPN(vpn: UInt): UInt = { 835 if (!hasLevel) ppn 836 else MuxLookup(level.get, 0.U)(Seq( 837 0.U -> Cat(ppn(ppn.getWidth-1, vpnnLen*2), vpn(vpnnLen*2-1, 0)), 838 1.U -> Cat(ppn(ppn.getWidth-1, vpnnLen), vpn(vpnnLen-1, 0)), 839 2.U -> ppn) 840 ) 841 } 842 843 //s2xlate control whether compare vmid or not 844 def hit(vpn: UInt, asid: UInt, vmid: UInt, allType: Boolean = false, ignoreAsid: Boolean = false, s2xlate: Bool) = { 845 require(vpn.getWidth == vpnLen) 846// require(this.asid.getWidth <= asid.getWidth) 847 val asid_hit = if (ignoreAsid) true.B else (this.asid === asid) 848 val vmid_hit = Mux(s2xlate, (this.vmid.getOrElse(0.U) === vmid), true.B) 849 if (allType) { 850 require(hasLevel) 851 val hit0 = tag(tagLen - 1, vpnnLen*2) === vpn(tagLen - 1, vpnnLen*2) 852 val hit1 = tag(vpnnLen*2 - 1, vpnnLen) === vpn(vpnnLen*2 - 1, vpnnLen) 853 val hit2 = tag(vpnnLen - 1, 0) === vpn(vpnnLen - 1, 0) 854 855 asid_hit && vmid_hit && Mux(level.getOrElse(0.U) === 2.U, hit2 && hit1 && hit0, Mux(level.getOrElse(0.U) === 1.U, hit1 && hit0, hit0)) 856 } else if (hasLevel) { 857 val hit0 = tag(tagLen - 1, tagLen - vpnnLen - extendVpnnBits) === vpn(vpnLen - 1, vpnLen - vpnnLen - extendVpnnBits) 858 val hit1 = tag(tagLen - vpnnLen - extendVpnnBits - 1, tagLen - vpnnLen * 2 - extendVpnnBits) === vpn(vpnLen - vpnnLen - extendVpnnBits - 1, vpnLen - vpnnLen * 2 - extendVpnnBits) 859 860 asid_hit && vmid_hit && Mux(level.getOrElse(0.U) === 0.U, hit0, hit0 && hit1) 861 } else { 862 asid_hit && vmid_hit && tag === vpn(vpnLen - 1, vpnLen - tagLen) 863 } 864 } 865 866 def refill(vpn: UInt, asid: UInt, vmid: UInt, pte: UInt, level: UInt = 0.U, prefetch: Bool, valid: Bool = false.B) { 867 require(this.asid.getWidth <= asid.getWidth) // maybe equal is better, but ugly outside 868 869 tag := vpn(vpnLen - 1, vpnLen - tagLen) 870 ppn := pte.asTypeOf(new PteBundle().cloneType).ppn 871 perm.map(_ := pte.asTypeOf(new PteBundle().cloneType).perm) 872 this.asid := asid 873 this.vmid.map(_ := vmid) 874 this.prefetch := prefetch 875 this.v := valid 876 this.level.map(_ := level) 877 } 878 879 def genPtwEntry(vpn: UInt, asid: UInt, pte: UInt, level: UInt = 0.U, prefetch: Bool, valid: Bool = false.B) = { 880 val e = Wire(new PtwEntry(tagLen, hasPerm, hasLevel)) 881 e.refill(vpn, asid, pte, level, prefetch, valid) 882 e 883 } 884 885 886 887 override def toPrintable: Printable = { 888 // p"tag:0x${Hexadecimal(tag)} ppn:0x${Hexadecimal(ppn)} perm:${perm}" 889 p"tag:0x${Hexadecimal(tag)} ppn:0x${Hexadecimal(ppn)} " + 890 (if (hasPerm) p"perm:${perm.getOrElse(0.U.asTypeOf(new PtePermBundle))} " else p"") + 891 (if (hasLevel) p"level:${level.getOrElse(0.U)}" else p"") + 892 p"prefetch:${prefetch}" 893 } 894} 895 896class PtwSectorEntry(tagLen: Int, hasPerm: Boolean = false, hasLevel: Boolean = false)(implicit p: Parameters) extends PtwEntry(tagLen, hasPerm, hasLevel) { 897 override val ppn = UInt(sectorppnLen.W) 898} 899 900class PtwMergeEntry(tagLen: Int, hasPerm: Boolean = false, hasLevel: Boolean = false)(implicit p: Parameters) extends PtwSectorEntry(tagLen, hasPerm, hasLevel) { 901 val ppn_low = UInt(sectortlbwidth.W) 902 val af = Bool() 903 val pf = Bool() 904} 905 906class HptwMergeEntry(tagLen: Int, hasPerm: Boolean = false, hasLevel: Boolean = false)(implicit p: Parameters) extends PtwMergeEntry(tagLen, hasPerm, hasLevel) 907 908class PtwEntries(num: Int, tagLen: Int, level: Int, hasPerm: Boolean)(implicit p: Parameters) extends PtwBundle { 909 require(log2Up(num)==log2Down(num)) 910 // NOTE: hasPerm means that is leaf or not. 911 912 val tag = UInt(tagLen.W) 913 val asid = UInt(asidLen.W) 914 val vmid = if (HasHExtension) Some(UInt(vmidLen.W)) else None 915 val ppns = if (HasHExtension) Vec(num, UInt((vpnLen.max(ppnLen)).W)) else Vec(num, UInt(ppnLen.W)) 916 val vs = Vec(num, Bool()) 917 val perms = if (hasPerm) Some(Vec(num, new PtePermBundle)) else None 918 val prefetch = Bool() 919 // println(s"PtwEntries: tag:1*${tagLen} ppns:${num}*${ppnLen} vs:${num}*1") 920 // NOTE: vs is used for different usage: 921 // for l3, which store the leaf(leaves), vs is page fault or not. 922 // for l2, which shoule not store leaf, vs is valid or not, that will anticipate in hit check 923 // Because, l2 should not store leaf(no perm), it doesn't store perm. 924 // If l2 hit a leaf, the perm is still unavailble. Should still page walk. Complex but nothing helpful. 925 // TODO: divide vs into validVec and pfVec 926 // for l2: may valid but pf, so no need for page walk, return random pte with pf. 927 928 def tagClip(vpn: UInt) = { 929 require(vpn.getWidth == vpnLen) 930 vpn(vpnLen - 1, vpnLen - tagLen) 931 } 932 933 def sectorIdxClip(vpn: UInt, level: Int) = { 934 getVpnClip(vpn, level)(log2Up(num) - 1, 0) 935 } 936 937 def hit(vpn: UInt, asid: UInt, vmid:UInt, ignoreAsid: Boolean = false, s2xlate: Bool) = { 938 val asid_hit = if (ignoreAsid) true.B else (this.asid === asid) 939 val vmid_hit = Mux(s2xlate, this.vmid.getOrElse(0.U) === vmid, true.B) 940 asid_hit && vmid_hit && tag === tagClip(vpn) && (if (hasPerm) true.B else vs(sectorIdxClip(vpn, level))) 941 } 942 943 def genEntries(vpn: UInt, asid: UInt, vmid: UInt, data: UInt, levelUInt: UInt, prefetch: Bool) = { 944 require((data.getWidth / XLEN) == num, 945 s"input data length must be multiple of pte length: data.length:${data.getWidth} num:${num}") 946 947 val ps = Wire(new PtwEntries(num, tagLen, level, hasPerm)) 948 ps.tag := tagClip(vpn) 949 ps.asid := asid 950 ps.vmid.map(_ := vmid) 951 ps.prefetch := prefetch 952 for (i <- 0 until num) { 953 val pte = data((i+1)*XLEN-1, i*XLEN).asTypeOf(new PteBundle) 954 ps.ppns(i) := pte.ppn 955 ps.vs(i) := !pte.isPf(levelUInt) && (if (hasPerm) pte.isLeaf() else !pte.isLeaf()) 956 ps.perms.map(_(i) := pte.perm) 957 } 958 ps 959 } 960 961 override def toPrintable: Printable = { 962 // require(num == 4, "if num is not 4, please comment this toPrintable") 963 // NOTE: if num is not 4, please comment this toPrintable 964 val permsInner = perms.getOrElse(0.U.asTypeOf(Vec(num, new PtePermBundle))) 965 p"asid: ${Hexadecimal(asid)} tag:0x${Hexadecimal(tag)} ppns:${printVec(ppns)} vs:${Binary(vs.asUInt)} " + 966 (if (hasPerm) p"perms:${printVec(permsInner)}" else p"") 967 } 968} 969 970class PTWEntriesWithEcc(eccCode: Code, num: Int, tagLen: Int, level: Int, hasPerm: Boolean)(implicit p: Parameters) extends PtwBundle { 971 val entries = new PtwEntries(num, tagLen, level, hasPerm) 972 973 val ecc_block = XLEN 974 val ecc_info = get_ecc_info() 975 val ecc = UInt(ecc_info._1.W) 976 977 def get_ecc_info(): (Int, Int, Int, Int) = { 978 val eccBits_per = eccCode.width(ecc_block) - ecc_block 979 980 val data_length = entries.getWidth 981 val data_align_num = data_length / ecc_block 982 val data_not_align = (data_length % ecc_block) != 0 // ugly code 983 val data_unalign_length = data_length - data_align_num * ecc_block 984 val eccBits_unalign = eccCode.width(data_unalign_length) - data_unalign_length 985 986 val eccBits = eccBits_per * data_align_num + eccBits_unalign 987 (eccBits, eccBits_per, data_align_num, data_unalign_length) 988 } 989 990 def encode() = { 991 val data = entries.asUInt 992 val ecc_slices = Wire(Vec(ecc_info._3, UInt(ecc_info._2.W))) 993 for (i <- 0 until ecc_info._3) { 994 ecc_slices(i) := eccCode.encode(data((i+1)*ecc_block-1, i*ecc_block)) >> ecc_block 995 } 996 if (ecc_info._4 != 0) { 997 val ecc_unaligned = eccCode.encode(data(data.getWidth-1, ecc_info._3*ecc_block)) >> ecc_info._4 998 ecc := Cat(ecc_unaligned, ecc_slices.asUInt) 999 } else { ecc := ecc_slices.asUInt } 1000 } 1001 1002 def decode(): Bool = { 1003 val data = entries.asUInt 1004 val res = Wire(Vec(ecc_info._3 + 1, Bool())) 1005 for (i <- 0 until ecc_info._3) { 1006 res(i) := {if (ecc_info._2 != 0) eccCode.decode(Cat(ecc((i+1)*ecc_info._2-1, i*ecc_info._2), data((i+1)*ecc_block-1, i*ecc_block))).error else false.B} 1007 } 1008 if (ecc_info._2 != 0 && ecc_info._4 != 0) { 1009 res(ecc_info._3) := eccCode.decode( 1010 Cat(ecc(ecc_info._1-1, ecc_info._2*ecc_info._3), data(data.getWidth-1, ecc_info._3*ecc_block))).error 1011 } else { res(ecc_info._3) := false.B } 1012 1013 Cat(res).orR 1014 } 1015 1016 def gen(vpn: UInt, asid: UInt, vmid: UInt, data: UInt, levelUInt: UInt, prefetch: Bool) = { 1017 this.entries := entries.genEntries(vpn, asid, vmid, data, levelUInt, prefetch) 1018 this.encode() 1019 } 1020} 1021 1022class PtwReq(implicit p: Parameters) extends PtwBundle { 1023 val vpn = UInt(vpnLen.W) //vpn or gvpn 1024 val s2xlate = UInt(2.W) 1025 def hasS2xlate(): Bool = { 1026 this.s2xlate =/= noS2xlate 1027 } 1028 def isOnlyStage2(): Bool = { 1029 this.s2xlate === onlyStage2 1030 } 1031 override def toPrintable: Printable = { 1032 p"vpn:0x${Hexadecimal(vpn)}" 1033 } 1034} 1035 1036class PtwReqwithMemIdx(implicit p: Parameters) extends PtwReq { 1037 val memidx = new MemBlockidxBundle 1038} 1039 1040class PtwResp(implicit p: Parameters) extends PtwBundle { 1041 val entry = new PtwEntry(tagLen = vpnLen, hasPerm = true, hasLevel = true) 1042 val pf = Bool() 1043 val af = Bool() 1044 1045 def apply(pf: Bool, af: Bool, level: UInt, pte: PteBundle, vpn: UInt, asid: UInt) = { 1046 this.entry.level.map(_ := level) 1047 this.entry.tag := vpn 1048 this.entry.perm.map(_ := pte.getPerm()) 1049 this.entry.ppn := pte.ppn 1050 this.entry.prefetch := DontCare 1051 this.entry.asid := asid 1052 this.entry.v := !pf 1053 this.pf := pf 1054 this.af := af 1055 } 1056 1057 override def toPrintable: Printable = { 1058 p"entry:${entry} pf:${pf} af:${af}" 1059 } 1060} 1061 1062class HptwResp(implicit p: Parameters) extends PtwBundle { 1063 val entry = new PtwEntry(tagLen = vpnLen, hasPerm = true, hasLevel = true) 1064 val gpf = Bool() 1065 val gaf = Bool() 1066 1067 def apply(gpf: Bool, gaf: Bool, level: UInt, pte: PteBundle, vpn: UInt, vmid: UInt) = { 1068 this.entry.level.map(_ := level) 1069 this.entry.tag := vpn 1070 this.entry.perm.map(_ := pte.getPerm()) 1071 this.entry.ppn := pte.ppn 1072 this.entry.prefetch := DontCare 1073 this.entry.asid := DontCare 1074 this.entry.vmid.map(_ := vmid) 1075 this.entry.v := !gpf 1076 this.gpf := gpf 1077 this.gaf := gaf 1078 } 1079 1080 // def genPPNS2(): UInt = { 1081 // MuxLookup(entry.level.get, 0.U, Seq( 1082 // 0.U -> Cat(entry.ppn(entry.ppn.getWidth - 1, vpnnLen * 2), entry.tag(vpnnLen * 2 - 1, 0)), 1083 // 1.U -> Cat(entry.ppn(entry.ppn.getWidth - 1, vpnnLen), entry.tag(vpnnLen - 1, 0)), 1084 // 2.U -> Cat(entry.ppn(entry.ppn.getWidth - 1, 0)) 1085 // )) 1086 // } 1087 1088 def genPPNS2(vpn: UInt): UInt = { 1089 MuxLookup(entry.level.get, 0.U, Seq( 1090 0.U -> Cat(entry.ppn(entry.ppn.getWidth - 1, vpnnLen * 2), vpn(vpnnLen * 2 - 1, 0)), 1091 1.U -> Cat(entry.ppn(entry.ppn.getWidth - 1, vpnnLen), vpn(vpnnLen - 1, 0)), 1092 2.U -> Cat(entry.ppn(entry.ppn.getWidth - 1, 0)) 1093 )) 1094 } 1095 1096 def hit(gvpn: UInt, vmid: UInt): Bool = { 1097 val vmid_hit = this.entry.vmid.getOrElse(0.U) === vmid 1098 val hit0 = entry.tag(vpnLen - 1, vpnnLen * 2) === gvpn(vpnLen - 1, vpnnLen * 2) 1099 val hit1 = entry.tag(vpnnLen * 2 - 1, vpnnLen) === gvpn(vpnnLen * 2 - 1, vpnnLen) 1100 val hit2 = entry.tag(vpnnLen - 1, 0) === gvpn(vpnnLen - 1, 0) 1101 vmid_hit && Mux(entry.level.getOrElse(0.U) === 2.U, hit2 && hit1 && hit0, Mux(entry.level.getOrElse(0.U) === 1.U, hit1 && hit0, hit0)) 1102 } 1103} 1104 1105class PtwResptomerge (implicit p: Parameters) extends PtwBundle { 1106 val entry = UInt(blockBits.W) 1107 val vpn = UInt(vpnLen.W) 1108 val level = UInt(log2Up(Level).W) 1109 val pf = Bool() 1110 val af = Bool() 1111 val asid = UInt(asidLen.W) 1112 1113 def apply(pf: Bool, af: Bool, level: UInt, pte: UInt, vpn: UInt, asid: UInt) = { 1114 this.entry := pte 1115 this.pf := pf 1116 this.af := af 1117 this.level := level 1118 this.vpn := vpn 1119 this.asid := asid 1120 } 1121 1122 override def toPrintable: Printable = { 1123 p"entry:${entry} pf:${pf} af:${af}" 1124 } 1125} 1126 1127class PtwRespwithMemIdx(implicit p: Parameters) extends PtwResp { 1128 val memidx = new MemBlockidxBundle 1129} 1130 1131class PtwSectorRespwithMemIdx(implicit p: Parameters) extends PtwSectorResp { 1132 val memidx = new MemBlockidxBundle 1133} 1134 1135class PtwSectorResp(implicit p: Parameters) extends PtwBundle { 1136 val entry = new PtwSectorEntry(tagLen = sectorvpnLen, hasPerm = true, hasLevel = true) 1137 val addr_low = UInt(sectortlbwidth.W) 1138 val ppn_low = Vec(tlbcontiguous, UInt(sectortlbwidth.W)) 1139 val valididx = Vec(tlbcontiguous, Bool()) 1140 val pteidx = Vec(tlbcontiguous, Bool()) 1141 val pf = Bool() 1142 val af = Bool() 1143 1144 1145 def genPPN(vpn: UInt): UInt = { 1146 MuxLookup(entry.level.get, 0.U)(Seq( 1147 0.U -> Cat(entry.ppn(entry.ppn.getWidth-1, vpnnLen * 2 - sectortlbwidth), vpn(vpnnLen*2-1, 0)), 1148 1.U -> Cat(entry.ppn(entry.ppn.getWidth-1, vpnnLen - sectortlbwidth), vpn(vpnnLen-1, 0)), 1149 2.U -> Cat(entry.ppn(entry.ppn.getWidth-1, 0), ppn_low(vpn(sectortlbwidth - 1, 0)))) 1150 ) 1151 } 1152 1153 def hit(vpn: UInt, asid: UInt, vmid: UInt, allType: Boolean = false, ignoreAsid: Boolean = false, s2xlate: Bool): Bool = { 1154 require(vpn.getWidth == vpnLen) 1155 // require(this.asid.getWidth <= asid.getWidth) 1156 val asid_hit = if (ignoreAsid) true.B else (this.entry.asid === asid) 1157 val vmid_hit = Mux(s2xlate, this.entry.vmid.getOrElse(0.U) === vmid, true.B) 1158 if (allType) { 1159 val hit0 = entry.tag(sectorvpnLen - 1, vpnnLen * 2 - sectortlbwidth) === vpn(vpnLen - 1, vpnnLen * 2) 1160 val hit1 = entry.tag(vpnnLen * 2 - sectortlbwidth - 1, vpnnLen - sectortlbwidth) === vpn(vpnnLen * 2 - 1, vpnnLen) 1161 val hit2 = entry.tag(vpnnLen - sectortlbwidth - 1, 0) === vpn(vpnnLen - 1, sectortlbwidth) 1162 val addr_low_hit = valididx(vpn(sectortlbwidth - 1, 0)) 1163 1164 asid_hit && vmid_hit && Mux(entry.level.getOrElse(0.U) === 2.U, hit2 && hit1 && hit0, Mux(entry.level.getOrElse(0.U) === 1.U, hit1 && hit0, hit0)) && addr_low_hit 1165 } else { 1166 val hit0 = entry.tag(sectorvpnLen - 1, sectorvpnLen - vpnnLen) === vpn(vpnLen - 1, vpnLen - vpnnLen) 1167 val hit1 = entry.tag(sectorvpnLen - vpnnLen - 1, sectorvpnLen - vpnnLen * 2) === vpn(vpnLen - vpnnLen - 1, vpnLen - vpnnLen * 2) 1168 val addr_low_hit = valididx(vpn(sectortlbwidth - 1, 0)) 1169 1170 asid_hit && vmid_hit && Mux(entry.level.getOrElse(0.U) === 0.U, hit0, hit0 && hit1) && addr_low_hit 1171 } 1172 } 1173} 1174 1175class PtwMergeResp(implicit p: Parameters) extends PtwBundle { 1176 val entry = Vec(tlbcontiguous, new PtwMergeEntry(tagLen = sectorvpnLen, hasPerm = true, hasLevel = true)) 1177 val pteidx = Vec(tlbcontiguous, Bool()) 1178 val not_super = Bool() 1179 1180 def apply(pf: Bool, af: Bool, level: UInt, pte: PteBundle, vpn: UInt, asid: UInt, vmid:UInt, addr_low : UInt, not_super : Boolean = true) = { 1181 assert(tlbcontiguous == 8, "Only support tlbcontiguous = 8!") 1182 1183 val ptw_resp = Wire(new PtwMergeEntry(tagLen = sectorvpnLen, hasPerm = true, hasLevel = true)) 1184 ptw_resp.ppn := pte.ppn(ppnLen - 1, sectortlbwidth) 1185 ptw_resp.ppn_low := pte.ppn(sectortlbwidth - 1, 0) 1186 ptw_resp.level.map(_ := level) 1187 ptw_resp.perm.map(_ := pte.getPerm()) 1188 ptw_resp.tag := vpn(vpnLen - 1, sectortlbwidth) 1189 ptw_resp.pf := pf 1190 ptw_resp.af := af 1191 ptw_resp.v := !pf 1192 ptw_resp.prefetch := DontCare 1193 ptw_resp.asid := asid 1194 ptw_resp.vmid.map(_ := vmid) 1195 this.pteidx := UIntToOH(addr_low).asBools 1196 this.not_super := not_super.B 1197 1198 1199 for (i <- 0 until tlbcontiguous) { 1200 this.entry(i) := ptw_resp 1201 } 1202 } 1203 1204 def genPPN(): UInt = { 1205 val idx = OHToUInt(pteidx) 1206 val tag = Cat(entry(idx).tag, idx(sectortlbwidth - 1, 0)) 1207 MuxLookup(entry(idx).level.get, 0.U, Seq( 1208 0.U -> Cat(entry(idx).ppn(entry(idx).ppn.getWidth - 1, vpnnLen * 2 - sectortlbwidth), tag(vpnnLen * 2 - 1, 0)), 1209 1.U -> Cat(entry(idx).ppn(entry(idx).ppn.getWidth - 1, vpnnLen - sectortlbwidth), tag(vpnnLen - 1, 0)), 1210 2.U -> Cat(entry(idx).ppn(entry(idx).ppn.getWidth - 1, 0), entry(idx).ppn_low)) 1211 ) 1212 } 1213} 1214 1215class HptwMergeResp(implicit p: Parameters) extends PtwBundle { 1216 val entry = Vec(tlbcontiguous, new HptwMergeEntry(tagLen = sectorvpnLen, hasPerm = true, hasLevel = true)) 1217 val pteidx = Vec(tlbcontiguous, Bool()) 1218 val not_super = Bool() 1219 1220 def genPPN(): UInt = { 1221 val idx = OHToUInt(pteidx) 1222 MuxLookup(entry(idx).level.get, 0.U, Seq( 1223 0.U -> Cat(entry(idx).ppn(entry(idx).ppn.getWidth - 1, vpnnLen * 2 - sectortlbwidth), entry(idx).tag(vpnnLen * 2 - 1, 0)), 1224 1.U -> Cat(entry(idx).ppn(entry(idx).ppn.getWidth - 1, vpnnLen - sectortlbwidth), entry(idx).tag(vpnnLen - 1, 0)), 1225 2.U -> Cat(entry(idx).ppn(entry(idx).ppn.getWidth - 1, 0), entry(idx).ppn_low)) 1226 ) 1227 } 1228 1229 def isAf(): Bool = { 1230 val idx = OHToUInt(pteidx) 1231 entry(idx).af 1232 } 1233 1234 def isPf(): Bool = { 1235 val idx = OHToUInt(pteidx) 1236 entry(idx).pf 1237 } 1238 1239 def MergeRespToPte(): PteBundle = { 1240 val idx = OHToUInt(pteidx) 1241 val resp = Wire(new PteBundle()) 1242 resp.ppn := Cat(entry(idx).ppn, entry(idx).ppn_low) 1243 resp.perm := entry(idx).perm.getOrElse(0.U) 1244 resp 1245 } 1246 1247 def apply(pf: Bool, af: Bool, level: UInt, pte: PteBundle, vpn: UInt, vmid: UInt, addr_low: UInt, not_super: Boolean = true) = { 1248 assert(tlbcontiguous == 8, "Only support tlbcontiguous = 8!") 1249 1250 val ptw_resp = Wire(new HptwMergeEntry(tagLen = sectorvpnLen, hasPerm = true, hasLevel = true)) 1251 ptw_resp.ppn := pte.ppn(ppnLen - 1, sectortlbwidth) 1252 ptw_resp.ppn_low := pte.ppn(sectortlbwidth - 1, 0) 1253 ptw_resp.level.map(_ := level) 1254 ptw_resp.perm.map(_ := pte.getPerm()) 1255 ptw_resp.tag := vpn(vpnLen - 1, sectortlbwidth) 1256 ptw_resp.pf := pf 1257 ptw_resp.af := af 1258 ptw_resp.v := !pf 1259 ptw_resp.prefetch := DontCare 1260 ptw_resp.vmid.map(_ := vmid) 1261 this.pteidx := UIntToOH(addr_low).asBools 1262 this.not_super := not_super.B 1263 1264 1265 for (i <- 0 until tlbcontiguous) { 1266 this.entry(i) := ptw_resp 1267 } 1268 } 1269} 1270 1271class PtwRespS2(implicit p: Parameters) extends PtwBundle { 1272 val s2xlate = UInt(2.W) 1273 val s1 = new PtwSectorResp() 1274 val s2 = new HptwResp() 1275 1276 def hasS2xlate(): Bool = { 1277 this.s2xlate =/= noS2xlate 1278 } 1279 1280 def isOnlyStage2(): Bool = { 1281 this.s2xlate === onlyStage2 1282 } 1283 1284 def getVpn: UInt = { 1285 val s1_tag = Cat(s1.entry.tag, s1.ppn_low(OHToUInt(s1.pteidx))) 1286 val s2_tag = s2.entry.tag 1287 Mux(s2xlate === onlyStage2, s2_tag, s1_tag) 1288 } 1289} 1290 1291class PtwRespS2withMemIdx(implicit p: Parameters) extends PtwRespS2 { 1292 val memidx = new MemBlockidxBundle() 1293} 1294 1295class L2TLBIO(implicit p: Parameters) extends PtwBundle { 1296 val hartId = Input(UInt(hartIdLen.W)) 1297 val tlb = Vec(PtwWidth, Flipped(new TlbPtwIO)) 1298 val sfence = Input(new SfenceBundle) 1299 val csr = new Bundle { 1300 val tlb = Input(new TlbCsrBundle) 1301 val distribute_csr = Flipped(new DistributedCSRIO) 1302 } 1303} 1304 1305class L2TlbMemReqBundle(implicit p: Parameters) extends PtwBundle { 1306 val addr = UInt(PAddrBits.W) 1307 val id = UInt(bMemID.W) 1308} 1309 1310class L2TlbInnerBundle(implicit p: Parameters) extends PtwReq { 1311 val source = UInt(bSourceWidth.W) 1312} 1313 1314 1315object ValidHoldBypass{ 1316 def apply(infire: Bool, outfire: Bool, flush: Bool = false.B) = { 1317 val valid = RegInit(false.B) 1318 when (infire) { valid := true.B } 1319 when (outfire) { valid := false.B } // ATTENTION: order different with ValidHold 1320 when (flush) { valid := false.B } // NOTE: the flush will flush in & out, is that ok? 1321 valid || infire 1322 } 1323} 1324 1325class L1TlbDB(implicit p: Parameters) extends TlbBundle { 1326 val vpn = UInt(vpnLen.W) 1327} 1328 1329class PageCacheDB(implicit p: Parameters) extends TlbBundle with HasPtwConst { 1330 val vpn = UInt(vpnLen.W) 1331 val source = UInt(bSourceWidth.W) 1332 val bypassed = Bool() 1333 val is_first = Bool() 1334 val prefetched = Bool() 1335 val prefetch = Bool() 1336 val l2Hit = Bool() 1337 val l1Hit = Bool() 1338 val hit = Bool() 1339} 1340 1341class PTWDB(implicit p: Parameters) extends TlbBundle with HasPtwConst { 1342 val vpn = UInt(vpnLen.W) 1343 val source = UInt(bSourceWidth.W) 1344} 1345 1346class L2TlbPrefetchDB(implicit p: Parameters) extends TlbBundle { 1347 val vpn = UInt(vpnLen.W) 1348} 1349 1350class L2TlbMissQueueDB(implicit p: Parameters) extends TlbBundle { 1351 val vpn = UInt(vpnLen.W) 1352} 1353