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