1/*************************************************************************************** 2* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences 3* Copyright (c) 2020-2021 Peng Cheng Laboratory 4* 5* XiangShan is licensed under Mulan PSL v2. 6* You can use this software according to the terms and conditions of the Mulan PSL v2. 7* You may obtain a copy of Mulan PSL v2 at: 8* http://license.coscl.org.cn/MulanPSL2 9* 10* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 11* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 12* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 13* 14* See the Mulan PSL v2 for more details. 15***************************************************************************************/ 16 17package xiangshan.cache.mmu 18 19import chipsalliance.rocketchip.config.Parameters 20import chisel3._ 21import chisel3.util._ 22import xiangshan._ 23import utils._ 24import xiangshan.backend.roq.RoqPtr 25import xiangshan.backend.fu.util.HasCSRConst 26import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp} 27import freechips.rocketchip.tilelink._ 28 29abstract class TlbBundle(implicit p: Parameters) extends XSBundle with HasTlbConst 30abstract class TlbModule(implicit p: Parameters) extends XSModule with HasTlbConst 31 32class PtePermBundle(implicit p: Parameters) extends TlbBundle { 33 val d = Bool() 34 val a = Bool() 35 val g = Bool() 36 val u = Bool() 37 val x = Bool() 38 val w = Bool() 39 val r = Bool() 40 41 override def toPrintable: Printable = { 42 p"d:${d} a:${a} g:${g} u:${u} x:${x} w:${w} r:${r}"// + 43 //(if(hasV) (p"v:${v}") else p"") 44 } 45} 46 47class TlbPermBundle(implicit p: Parameters) extends TlbBundle { 48 val pf = Bool() // NOTE: if this is true, just raise pf 49 // pagetable perm (software defined) 50 val d = Bool() 51 val a = Bool() 52 val g = Bool() 53 val u = Bool() 54 val x = Bool() 55 val w = Bool() 56 val r = Bool() 57 // pma perm (hardwired) 58 val pr = Bool() //readable 59 val pw = Bool() //writeable 60 val pe = Bool() //executable 61 val pa = Bool() //atom op permitted 62 val pi = Bool() //icacheable 63 val pd = Bool() //dcacheable 64 65 override def toPrintable: Printable = { 66 p"pf:${pf} d:${d} a:${a} g:${g} u:${u} x:${x} w:${w} r:${r}" 67 } 68} 69 70// multi-read && single-write 71// input is data, output is hot-code(not one-hot) 72class CAMTemplate[T <: Data](val gen: T, val set: Int, val readWidth: Int)(implicit p: Parameters) extends TlbModule { 73 val io = IO(new Bundle { 74 val r = new Bundle { 75 val req = Input(Vec(readWidth, gen)) 76 val resp = Output(Vec(readWidth, Vec(set, Bool()))) 77 } 78 val w = Input(new Bundle { 79 val valid = Bool() 80 val bits = new Bundle { 81 val index = UInt(log2Up(set).W) 82 val data = gen 83 } 84 }) 85 }) 86 87 val wordType = UInt(gen.getWidth.W) 88 val array = Reg(Vec(set, wordType)) 89 90 io.r.resp.zipWithIndex.map{ case (a,i) => 91 a := array.map(io.r.req(i).asUInt === _) 92 } 93 94 when (io.w.valid) { 95 array(io.w.bits.index) := io.w.bits.data 96 } 97} 98 99class TlbSPMeta(implicit p: Parameters) extends TlbBundle { 100 val tag = UInt(vpnLen.W) // tag is vpn 101 val level = UInt(1.W) // 1 for 2MB, 0 for 1GB 102 103 def hit(vpn: UInt): Bool = { 104 val a = tag(vpnnLen*3-1, vpnnLen*2) === vpn(vpnnLen*3-1, vpnnLen*2) 105 val b = tag(vpnnLen*2-1, vpnnLen*1) === vpn(vpnnLen*2-1, vpnnLen*1) 106 XSDebug(Mux(level.asBool, a&b, a), p"Hit superpage: hit:${Mux(level.asBool, a&b, a)} tag:${Hexadecimal(tag)} level:${level} a:${a} b:${b} vpn:${Hexadecimal(vpn)}\n") 107 Mux(level.asBool, a&b, a) 108 } 109 110 def apply(vpn: UInt, level: UInt) = { 111 this.tag := vpn 112 this.level := level(0) 113 114 this 115 } 116 117} 118 119class TlbData(superpage: Boolean = false)(implicit p: Parameters) extends TlbBundle { 120 val level = if(superpage) Some(UInt(1.W)) else None // /*2 for 4KB,*/ 1 for 2MB, 0 for 1GB 121 val ppn = UInt(ppnLen.W) 122 val perm = new TlbPermBundle 123 124 def genPPN(vpn: UInt): UInt = { 125 if (superpage) { 126 val insideLevel = level.getOrElse(0.U) 127 Mux(insideLevel.asBool, Cat(ppn(ppn.getWidth-1, vpnnLen*1), vpn(vpnnLen*1-1, 0)), 128 Cat(ppn(ppn.getWidth-1, vpnnLen*2), vpn(vpnnLen*2-1, 0))) 129 } else { 130 ppn 131 } 132 } 133 134 def apply(ppn: UInt, level: UInt, perm: UInt, pf: Bool) = { 135 this.level.map(_ := level(0)) 136 this.ppn := ppn 137 // refill pagetable perm 138 val ptePerm = perm.asTypeOf(new PtePermBundle) 139 this.perm.pf:= pf 140 this.perm.d := ptePerm.d 141 this.perm.a := ptePerm.a 142 this.perm.g := ptePerm.g 143 this.perm.u := ptePerm.u 144 this.perm.x := ptePerm.x 145 this.perm.w := ptePerm.w 146 this.perm.r := ptePerm.r 147 148 // get pma perm 149 val (pmaMode, accessWidth) = AddressSpace.memmapAddrMatch(Cat(ppn, 0.U(12.W))) 150 this.perm.pr := PMAMode.read(pmaMode) 151 this.perm.pw := PMAMode.write(pmaMode) 152 this.perm.pe := PMAMode.execute(pmaMode) 153 this.perm.pa := PMAMode.atomic(pmaMode) 154 this.perm.pi := PMAMode.icache(pmaMode) 155 this.perm.pd := PMAMode.dcache(pmaMode) 156 157 this 158 } 159 160 override def toPrintable: Printable = { 161 val insideLevel = level.getOrElse(0.U) 162 p"level:${insideLevel} ppn:${Hexadecimal(ppn)} perm:${perm}" 163 } 164 165 override def cloneType: this.type = (new TlbData(superpage)).asInstanceOf[this.type] 166} 167 168object TlbCmd { 169 def read = "b00".U 170 def write = "b01".U 171 def exec = "b10".U 172 173 def atom_read = "b100".U // lr 174 def atom_write = "b101".U // sc / amo 175 176 def apply() = UInt(3.W) 177 def isRead(a: UInt) = a(1,0)===read 178 def isWrite(a: UInt) = a(1,0)===write 179 def isExec(a: UInt) = a(1,0)===exec 180 181 def isAtom(a: UInt) = a(2) 182} 183 184class TlbReq(implicit p: Parameters) extends TlbBundle { 185 val vaddr = UInt(VAddrBits.W) 186 val cmd = TlbCmd() 187 val roqIdx = new RoqPtr 188 val debug = new Bundle { 189 val pc = UInt(XLEN.W) 190 val isFirstIssue = Bool() 191 } 192 193 override def toPrintable: Printable = { 194 p"vaddr:0x${Hexadecimal(vaddr)} cmd:${cmd} pc:0x${Hexadecimal(debug.pc)} roqIdx:${roqIdx}" 195 } 196} 197 198class TlbResp(implicit p: Parameters) extends TlbBundle { 199 val paddr = UInt(PAddrBits.W) 200 val miss = Bool() 201 val mmio = Bool() 202 val excp = new Bundle { 203 val pf = new Bundle { 204 val ld = Bool() 205 val st = Bool() 206 val instr = Bool() 207 } 208 val af = new Bundle { 209 val ld = Bool() 210 val st = Bool() 211 val instr = Bool() 212 } 213 } 214 val ptwBack = Bool() // when ptw back, wake up replay rs's state 215 216 override def toPrintable: Printable = { 217 p"paddr:0x${Hexadecimal(paddr)} miss:${miss} excp.pf: ld:${excp.pf.ld} st:${excp.pf.st} instr:${excp.pf.instr} ptwBack:${ptwBack}" 218 } 219} 220 221class TlbRequestIO()(implicit p: Parameters) extends TlbBundle { 222 val req = DecoupledIO(new TlbReq) 223 val resp = Flipped(DecoupledIO(new TlbResp)) 224} 225 226class BlockTlbRequestIO()(implicit p: Parameters) extends TlbBundle { 227 val req = DecoupledIO(new TlbReq) 228 val resp = Flipped(DecoupledIO(new TlbResp)) 229} 230 231class TlbPtwIO(Width: Int = 1)(implicit p: Parameters) extends TlbBundle { 232 val req = Vec(Width, DecoupledIO(new PtwReq)) 233 val resp = Flipped(DecoupledIO(new PtwResp)) 234 235 override def cloneType: this.type = (new TlbPtwIO(Width)).asInstanceOf[this.type] 236 237 override def toPrintable: Printable = { 238 p"req(0):${req(0).valid} ${req(0).ready} ${req(0).bits} | resp:${resp.valid} ${resp.ready} ${resp.bits}" 239 } 240} 241 242class TlbIO(Width: Int)(implicit p: Parameters) extends TlbBundle { 243 val requestor = Vec(Width, Flipped(new TlbRequestIO)) 244 val ptw = new TlbPtwIO(Width) 245 val sfence = Input(new SfenceBundle) 246 val csr = Input(new TlbCsrBundle) 247 248 override def cloneType: this.type = (new TlbIO(Width)).asInstanceOf[this.type] 249} 250 251 252/**************************** PTW *************************************/ 253abstract class PtwBundle(implicit p: Parameters) extends XSBundle with HasPtwConst 254abstract class PtwModule(outer: PTW) extends LazyModuleImp(outer) 255 with HasXSParameter with HasPtwConst 256 257class PteBundle(implicit p: Parameters) extends PtwBundle{ 258 val reserved = UInt(pteResLen.W) 259 val ppn = UInt(ppnLen.W) 260 val rsw = UInt(2.W) 261 val perm = new Bundle { 262 val d = Bool() 263 val a = Bool() 264 val g = Bool() 265 val u = Bool() 266 val x = Bool() 267 val w = Bool() 268 val r = Bool() 269 val v = Bool() 270 } 271 272 def unaligned(level: UInt) = { 273 isLeaf() && !(level === 2.U || 274 level === 1.U && ppn(vpnnLen-1, 0) === 0.U || 275 level === 0.U && ppn(vpnnLen*2-1, 0) === 0.U) 276 } 277 278 def isPf(level: UInt) = { 279 !perm.v || (!perm.r && perm.w) || unaligned(level) 280 } 281 282 def isLeaf() = { 283 perm.r || perm.x || perm.w 284 } 285 286 def getPerm() = { 287 val pm = Wire(new PtePermBundle) 288 pm.d := perm.d 289 pm.a := perm.a 290 pm.g := perm.g 291 pm.u := perm.u 292 pm.x := perm.x 293 pm.w := perm.w 294 pm.r := perm.r 295 pm 296 } 297 298 override def toPrintable: Printable = { 299 p"ppn:0x${Hexadecimal(ppn)} perm:b${Binary(perm.asUInt)}" 300 } 301} 302 303class PtwEntry(tagLen: Int, hasPerm: Boolean = false, hasLevel: Boolean = false)(implicit p: Parameters) extends PtwBundle { 304 val tag = UInt(tagLen.W) 305 val ppn = UInt(ppnLen.W) 306 val perm = if (hasPerm) Some(new PtePermBundle) else None 307 val level = if (hasLevel) Some(UInt(log2Up(Level).W)) else None 308 309 def hit(vpn: UInt, allType: Boolean = false) = { 310 require(vpn.getWidth == vpnLen) 311 if (allType) { 312 require(hasLevel) 313 val hit0 = tag(tagLen - 1, vpnnLen*2) === vpn(tagLen - 1, vpnnLen*2) 314 val hit1 = tag(vpnnLen*2 - 1, vpnnLen) === vpn(vpnnLen*2 - 1, vpnnLen) 315 val hit2 = tag(vpnnLen - 1, 0) === vpn(vpnnLen - 1, 0) 316 Mux(level.getOrElse(0.U) === 2.U, hit2 && hit1 && hit0, Mux(level.getOrElse(0.U) === 1.U, hit1 && hit0, hit0)) 317 } else if (hasLevel) { 318 val hit0 = tag(tagLen - 1, tagLen - vpnnLen) === vpn(vpnLen - 1, vpnLen - vpnnLen) 319 val hit1 = tag(tagLen - vpnnLen - 1, tagLen - vpnnLen * 2) === vpn(vpnLen - vpnnLen - 1, vpnLen - vpnnLen * 2) 320 Mux(level.getOrElse(0.U) === 0.U, hit0, hit0 && hit1) 321 } else { 322 tag === vpn(vpnLen - 1, vpnLen - tagLen) 323 } 324 } 325 326 def refill(vpn: UInt, pte: UInt, level: UInt = 0.U) { 327 tag := vpn(vpnLen - 1, vpnLen - tagLen) 328 ppn := pte.asTypeOf(pteBundle).ppn 329 perm.map(_ := pte.asTypeOf(pteBundle).perm) 330 this.level.map(_ := level) 331 } 332 333 def genPtwEntry(vpn: UInt, pte: UInt, level: UInt = 0.U) = { 334 val e = Wire(new PtwEntry(tagLen, hasPerm, hasLevel)) 335 e.refill(vpn, pte, level) 336 e 337 } 338 339 override def cloneType: this.type = (new PtwEntry(tagLen, hasPerm, hasLevel)).asInstanceOf[this.type] 340 341 override def toPrintable: Printable = { 342 // p"tag:0x${Hexadecimal(tag)} ppn:0x${Hexadecimal(ppn)} perm:${perm}" 343 p"tag:0x${Hexadecimal(tag)} ppn:0x${Hexadecimal(ppn)} " + 344 (if (hasPerm) p"perm:${perm.getOrElse(0.U.asTypeOf(new PtePermBundle))} " else p"") + 345 (if (hasLevel) p"level:${level.getOrElse(0.U)}" else p"") 346 } 347} 348 349class PtwEntries(num: Int, tagLen: Int, level: Int, hasPerm: Boolean)(implicit p: Parameters) extends PtwBundle { 350 require(log2Up(num)==log2Down(num)) 351 352 val tag = UInt(tagLen.W) 353 val ppns = Vec(num, UInt(ppnLen.W)) 354 val vs = Vec(num, Bool()) 355 val perms = if (hasPerm) Some(Vec(num, new PtePermBundle)) else None 356 // println(s"PtwEntries: tag:1*${tagLen} ppns:${num}*${ppnLen} vs:${num}*1") 357 358 def tagClip(vpn: UInt) = { 359 require(vpn.getWidth == vpnLen) 360 vpn(vpnLen - 1, vpnLen - tagLen) 361 } 362 363 def sectorIdxClip(vpn: UInt, level: Int) = { 364 getVpnClip(vpn, level)(log2Up(num) - 1, 0) 365 } 366 367 def hit(vpn: UInt) = { 368 tag === tagClip(vpn) && vs(sectorIdxClip(vpn, level)) // TODO: optimize this. don't need to compare each with tag 369 } 370 371 def genEntries(vpn: UInt, data: UInt, levelUInt: UInt) = { 372 require((data.getWidth / XLEN) == num, 373 "input data length must be multiple of pte length") 374 375 val ps = Wire(new PtwEntries(num, tagLen, level, hasPerm)) 376 ps.tag := tagClip(vpn) 377 for (i <- 0 until num) { 378 val pte = data((i+1)*XLEN-1, i*XLEN).asTypeOf(new PteBundle) 379 ps.ppns(i) := pte.ppn 380 ps.vs(i) := !pte.isPf(levelUInt) && (if (hasPerm) pte.isLeaf() else !pte.isLeaf()) 381 ps.perms.map(_(i) := pte.perm) 382 } 383 ps 384 } 385 386 override def cloneType: this.type = (new PtwEntries(num, tagLen, level, hasPerm)).asInstanceOf[this.type] 387 override def toPrintable: Printable = { 388 // require(num == 4, "if num is not 4, please comment this toPrintable") 389 // NOTE: if num is not 4, please comment this toPrintable 390 val permsInner = perms.getOrElse(0.U.asTypeOf(Vec(num, new PtePermBundle))) 391 p"tag:0x${Hexadecimal(tag)} ppns:${printVec(ppns)} vs:${Binary(vs.asUInt)} " + 392 (if (hasPerm) p"perms:${printVec(permsInner)}" else p"") 393 } 394} 395 396class PtwReq(implicit p: Parameters) extends PtwBundle { 397 val vpn = UInt(vpnLen.W) 398 399 override def toPrintable: Printable = { 400 p"vpn:0x${Hexadecimal(vpn)}" 401 } 402} 403 404class PtwResp(implicit p: Parameters) extends PtwBundle { 405 val entry = new PtwEntry(tagLen = vpnLen, hasPerm = true, hasLevel = true) 406 val pf = Bool() 407 408 override def toPrintable: Printable = { 409 p"entry:${entry} pf:${pf}" 410 } 411} 412 413class PtwIO(implicit p: Parameters) extends PtwBundle { 414 val tlb = Vec(PtwWidth, Flipped(new TlbPtwIO)) 415 val sfence = Input(new SfenceBundle) 416 val csr = Input(new TlbCsrBundle) 417} 418 419object ValidHold { 420 def apply(infire: Bool, outfire: Bool, flush: Bool = false.B ) = { 421 val valid = RegInit(false.B) 422 when (outfire) { valid := false.B } 423 when (infire) { valid := true.B } 424 when (flush) { valid := false.B } // NOTE: the flush will flush in & out, is that ok? 425 valid 426 } 427} 428 429object OneCycleValid { 430 def apply(fire: Bool, flush: Bool = false.B) = { 431 val valid = RegInit(false.B) 432 when (valid) { valid := false.B } 433 when (fire) { valid := true.B } 434 when (flush) { valid := false.B } 435 valid 436 } 437}