xref: /XiangShan/src/main/scala/xiangshan/cache/mmu/MMUBundle.scala (revision 9e4583a22ed4d6cc995424fb8693c95be0eaef84)
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.rob.RobPtr
25import xiangshan.backend.fu.util.HasCSRConst
26import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp}
27import freechips.rocketchip.tilelink._
28import xiangshan.backend.fu.{PMPReqBundle, PMPConfig}
29
30
31abstract class TlbBundle(implicit p: Parameters) extends XSBundle with HasTlbConst
32abstract class TlbModule(implicit p: Parameters) extends XSModule with HasTlbConst
33
34class VaBundle(implicit p: Parameters) extends TlbBundle {
35  val vpn  = UInt(vpnLen.W)
36  val off  = UInt(offLen.W)
37}
38
39class PtePermBundle(implicit p: Parameters) extends TlbBundle {
40  val d = Bool()
41  val a = Bool()
42  val g = Bool()
43  val u = Bool()
44  val x = Bool()
45  val w = Bool()
46  val r = Bool()
47
48  override def toPrintable: Printable = {
49    p"d:${d} a:${a} g:${g} u:${u} x:${x} w:${w} r:${r}"// +
50    //(if(hasV) (p"v:${v}") else p"")
51  }
52}
53
54class TlbPMBundle(implicit p: Parameters) extends TlbBundle {
55  val r = Bool()
56  val w = Bool()
57  val x = Bool()
58  val c = Bool()
59  val atomic = Bool()
60
61  def assign_ap(pm: PMPConfig) = {
62    r := pm.r
63    w := pm.w
64    x := pm.x
65    c := pm.c
66    atomic := pm.atomic
67  }
68}
69
70class TlbPermBundle(implicit p: Parameters) extends TlbBundle {
71  val pf = Bool() // NOTE: if this is true, just raise pf
72  val af = Bool() // NOTE: if this is true, just raise af
73  // pagetable perm (software defined)
74  val d = Bool()
75  val a = Bool()
76  val g = Bool()
77  val u = Bool()
78  val x = Bool()
79  val w = Bool()
80  val r = Bool()
81
82  val pm = new TlbPMBundle
83
84  override def toPrintable: Printable = {
85    p"pf:${pf} af:${af} d:${d} a:${a} g:${g} u:${u} x:${x} w:${w} r:${r} " +
86    p"pm:${pm}"
87  }
88}
89
90// multi-read && single-write
91// input is data, output is hot-code(not one-hot)
92class CAMTemplate[T <: Data](val gen: T, val set: Int, val readWidth: Int)(implicit p: Parameters) extends TlbModule {
93  val io = IO(new Bundle {
94    val r = new Bundle {
95      val req = Input(Vec(readWidth, gen))
96      val resp = Output(Vec(readWidth, Vec(set, Bool())))
97    }
98    val w = Input(new Bundle {
99      val valid = Bool()
100      val bits = new Bundle {
101        val index = UInt(log2Up(set).W)
102        val data = gen
103      }
104    })
105  })
106
107  val wordType = UInt(gen.getWidth.W)
108  val array = Reg(Vec(set, wordType))
109
110  io.r.resp.zipWithIndex.map{ case (a,i) =>
111    a := array.map(io.r.req(i).asUInt === _)
112  }
113
114  when (io.w.valid) {
115    array(io.w.bits.index) := io.w.bits.data.asUInt
116  }
117}
118
119class TlbSPMeta(implicit p: Parameters) extends TlbBundle {
120  val tag = UInt(vpnLen.W) // tag is vpn
121  val level = UInt(1.W) // 1 for 2MB, 0 for 1GB
122  val asid = UInt(asidLen.W)
123
124  def hit(vpn: UInt, asid: UInt): Bool = {
125    val a = tag(vpnnLen*3-1, vpnnLen*2) === vpn(vpnnLen*3-1, vpnnLen*2)
126    val b = tag(vpnnLen*2-1, vpnnLen*1) === vpn(vpnnLen*2-1, vpnnLen*1)
127    val asid_hit = this.asid === asid
128
129    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")
130    asid_hit && Mux(level.asBool, a&b, a)
131  }
132
133  def apply(vpn: UInt, asid: UInt, level: UInt) = {
134    this.tag := vpn
135    this.asid := asid
136    this.level := level(0)
137
138    this
139  }
140
141}
142
143class TlbData(superpage: Boolean = false)(implicit p: Parameters) extends TlbBundle {
144  val level = if(superpage) Some(UInt(1.W)) else None // /*2 for 4KB,*/ 1 for 2MB, 0 for 1GB
145  val ppn = UInt(ppnLen.W)
146  val perm = new TlbPermBundle
147
148  def genPPN(vpn: UInt): UInt = {
149    if (superpage) {
150      val insideLevel = level.getOrElse(0.U)
151      Mux(insideLevel.asBool, Cat(ppn(ppn.getWidth-1, vpnnLen*1), vpn(vpnnLen*1-1, 0)),
152                              Cat(ppn(ppn.getWidth-1, vpnnLen*2), vpn(vpnnLen*2-1, 0)))
153    } else {
154      ppn
155    }
156  }
157
158  def apply(ppn: UInt, level: UInt, perm: UInt, pf: Bool, af: Bool) = {
159    this.level.map(_ := level(0))
160    this.ppn := ppn
161    // refill pagetable perm
162    val ptePerm = perm.asTypeOf(new PtePermBundle)
163    this.perm.pf:= pf
164    this.perm.af:= af
165    this.perm.d := ptePerm.d
166    this.perm.a := ptePerm.a
167    this.perm.g := ptePerm.g
168    this.perm.u := ptePerm.u
169    this.perm.x := ptePerm.x
170    this.perm.w := ptePerm.w
171    this.perm.r := ptePerm.r
172
173    this
174  }
175
176  override def toPrintable: Printable = {
177    val insideLevel = level.getOrElse(0.U)
178    p"level:${insideLevel} ppn:${Hexadecimal(ppn)} perm:${perm}"
179  }
180
181}
182
183class TlbEntry(pageNormal: Boolean, pageSuper: Boolean)(implicit p: Parameters) extends TlbBundle {
184  require(pageNormal || pageSuper)
185
186  val tag = if (!pageNormal) UInt((vpnLen - vpnnLen).W)
187            else UInt(vpnLen.W)
188  val asid = UInt(asidLen.W)
189  val level = if (!pageNormal) Some(UInt(1.W))
190              else if (!pageSuper) None
191              else Some(UInt(2.W))
192  val ppn = if (!pageNormal) UInt((ppnLen - vpnnLen).W)
193            else UInt(ppnLen.W)
194  val perm = new TlbPermBundle
195
196  /** level usage:
197   *  !PageSuper: page is only normal, level is None, match all the tag
198   *  !PageNormal: page is only super, level is a Bool(), match high 9*2 parts
199   *  bits0  0: need mid 9bits
200   *         1: no need mid 9bits
201   *  PageSuper && PageNormal: page hold all the three type,
202   *  bits0  0: need low 9bits
203   *  bits1  0: need mid 9bits
204   */
205
206  def hit(vpn: UInt, asid: UInt, nSets: Int = 1, ignoreAsid: Boolean = false): Bool = {
207    val asid_hit = if (ignoreAsid) true.B else (this.asid === asid)
208
209    // NOTE: for timing, dont care low set index bits at hit check
210    //       do not need store the low bits actually
211    if (!pageSuper) asid_hit && drop_set_equal(vpn, tag, nSets)
212    else if (!pageNormal) {
213      val tag_match_hi = tag(vpnnLen*2-1, vpnnLen) === vpn(vpnnLen*3-1, vpnnLen*2)
214      val tag_match_mi = tag(vpnnLen-1, 0) === vpn(vpnnLen*2-1, vpnnLen)
215      val tag_match = tag_match_hi && (level.get.asBool() || tag_match_mi)
216      asid_hit && tag_match
217    }
218    else {
219      val tmp_level = level.get
220      val tag_match_hi = tag(vpnnLen*3-1, vpnnLen*2) === vpn(vpnnLen*3-1, vpnnLen*2)
221      val tag_match_mi = tag(vpnnLen*2-1, vpnnLen) === vpn(vpnnLen*2-1, vpnnLen)
222      val tag_match_lo = tag(vpnnLen-1, 0) === vpn(vpnnLen-1, 0) // if pageNormal is false, this will always be false
223      val tag_match = tag_match_hi && (tmp_level(1) || tag_match_mi) && (tmp_level(0) || tag_match_lo)
224      asid_hit && tag_match
225    }
226  }
227
228  def apply(item: PtwResp, asid: UInt, pm: PMPConfig): TlbEntry = {
229    this.tag := {if (pageNormal) item.entry.tag else item.entry.tag(vpnLen-1, vpnnLen)}
230    this.asid := asid
231    val inner_level = item.entry.level.getOrElse(0.U)
232    this.level.map(_ := { if (pageNormal && pageSuper) MuxLookup(inner_level, 0.U, Seq(
233                                                        0.U -> 3.U,
234                                                        1.U -> 1.U,
235                                                        2.U -> 0.U ))
236                          else if (pageSuper) ~inner_level(0)
237                          else 0.U })
238    this.ppn := { if (!pageNormal) item.entry.ppn(ppnLen-1, vpnnLen)
239                  else item.entry.ppn }
240    val ptePerm = item.entry.perm.get.asTypeOf(new PtePermBundle().cloneType)
241    this.perm.pf := item.pf
242    this.perm.af := item.af
243    this.perm.d := ptePerm.d
244    this.perm.a := ptePerm.a
245    this.perm.g := ptePerm.g
246    this.perm.u := ptePerm.u
247    this.perm.x := ptePerm.x
248    this.perm.w := ptePerm.w
249    this.perm.r := ptePerm.r
250
251    this.perm.pm.assign_ap(pm)
252
253    this
254  }
255
256  // 4KB is normal entry, 2MB/1GB is considered as super entry
257  def is_normalentry(): Bool = {
258    if (!pageSuper) { true.B }
259    else if (!pageNormal) { false.B }
260    else { level.get === 0.U }
261  }
262
263  def genPPN(saveLevel: Boolean = false, valid: Bool = false.B)(vpn: UInt) : UInt = {
264    val inner_level = level.getOrElse(0.U)
265    val ppn_res = if (!pageSuper) ppn
266      else if (!pageNormal) Cat(ppn(ppnLen-vpnnLen-1, vpnnLen),
267        Mux(inner_level(0), vpn(vpnnLen*2-1, vpnnLen), ppn(vpnnLen-1,0)),
268        vpn(vpnnLen-1, 0))
269      else Cat(ppn(ppnLen-1, vpnnLen*2),
270        Mux(inner_level(1), vpn(vpnnLen*2-1, vpnnLen), ppn(vpnnLen*2-1, vpnnLen)),
271        Mux(inner_level(0), vpn(vpnnLen-1, 0), ppn(vpnnLen-1, 0)))
272
273    if (saveLevel) Cat(ppn(ppn.getWidth-1, vpnnLen*2), RegEnable(ppn_res(vpnnLen*2-1, 0), valid))
274    else ppn_res
275  }
276
277  override def toPrintable: Printable = {
278    val inner_level = level.getOrElse(2.U)
279    p"asid: ${asid} level:${inner_level} vpn:${Hexadecimal(tag)} ppn:${Hexadecimal(ppn)} perm:${perm}"
280  }
281
282}
283
284object TlbCmd {
285  def read  = "b00".U
286  def write = "b01".U
287  def exec  = "b10".U
288
289  def atom_read  = "b100".U // lr
290  def atom_write = "b101".U // sc / amo
291
292  def apply() = UInt(3.W)
293  def isRead(a: UInt) = a(1,0)===read
294  def isWrite(a: UInt) = a(1,0)===write
295  def isExec(a: UInt) = a(1,0)===exec
296
297  def isAtom(a: UInt) = a(2)
298  def isAmo(a: UInt) = a===atom_write // NOTE: sc mixed
299}
300
301class TlbStorageIO(nSets: Int, nWays: Int, ports: Int)(implicit p: Parameters) extends MMUIOBaseBundle {
302  val r = new Bundle {
303    val req = Vec(ports, Flipped(DecoupledIO(new Bundle {
304      val vpn = Output(UInt(vpnLen.W))
305    })))
306    val resp = Vec(ports, ValidIO(new Bundle{
307      val hit = Output(Bool())
308      val ppn = Output(UInt(ppnLen.W))
309      val perm = Output(new TlbPermBundle())
310    }))
311    val resp_hit_sameCycle = Output(Vec(ports, Bool())) // req hit or not same cycle with req
312  }
313  val w = Flipped(ValidIO(new Bundle {
314    val wayIdx = Output(UInt(log2Up(nWays).W))
315    val data = Output(new PtwResp)
316    val data_replenish = Output(new PMPConfig)
317  }))
318  val victim = new Bundle {
319    val out = ValidIO(Output(new Bundle {
320      val entry = new TlbEntry(pageNormal = true, pageSuper = false)
321    }))
322    val in = Flipped(ValidIO(Output(new Bundle {
323      val entry = new TlbEntry(pageNormal = true, pageSuper = false)
324    })))
325  }
326  val access = Vec(ports, new ReplaceAccessBundle(nSets, nWays))
327
328  def r_req_apply(valid: Bool, vpn: UInt, asid: UInt, i: Int): Unit = {
329    this.r.req(i).valid := valid
330    this.r.req(i).bits.vpn := vpn
331  }
332
333  def r_resp_apply(i: Int) = {
334    (this.r.resp_hit_sameCycle(i), this.r.resp(i).bits.hit, this.r.resp(i).bits.ppn, this.r.resp(i).bits.perm)
335  }
336
337  def w_apply(valid: Bool, wayIdx: UInt, data: PtwResp, data_replenish: PMPConfig): Unit = {
338    this.w.valid := valid
339    this.w.bits.wayIdx := wayIdx
340    this.w.bits.data := data
341    this.w.bits.data_replenish := data_replenish
342  }
343
344}
345
346class ReplaceAccessBundle(nSets: Int, nWays: Int)(implicit p: Parameters) extends TlbBundle {
347  val sets = Output(UInt(log2Up(nSets).W))
348  val touch_ways = ValidIO(Output(UInt(log2Up(nWays).W)))
349
350}
351
352class ReplaceIO(Width: Int, nSets: Int, nWays: Int)(implicit p: Parameters) extends TlbBundle {
353  val access = Vec(Width, Flipped(new ReplaceAccessBundle(nSets, nWays)))
354
355  val refillIdx = Output(UInt(log2Up(nWays).W))
356  val chosen_set = Flipped(Output(UInt(log2Up(nSets).W)))
357
358  def apply_sep(in: Seq[ReplaceIO], vpn: UInt): Unit = {
359    for ((ac_rep, ac_tlb) <- access.zip(in.map(a => a.access.map(b => b)).flatten)) {
360      ac_rep := ac_tlb
361    }
362    this.chosen_set := get_set_idx(vpn, nSets)
363    in.map(a => a.refillIdx := this.refillIdx)
364  }
365}
366
367class TlbReplaceIO(Width: Int, q: TLBParameters)(implicit p: Parameters) extends
368  TlbBundle {
369  val normalPage = new ReplaceIO(Width, q.normalNSets, q.normalNWays)
370  val superPage = new ReplaceIO(Width, q.superNSets, q.superNWays)
371
372  def apply_sep(in: Seq[TlbReplaceIO], vpn: UInt) = {
373    this.normalPage.apply_sep(in.map(_.normalPage), vpn)
374    this.superPage.apply_sep(in.map(_.superPage), vpn)
375  }
376
377}
378
379class TlbReq(implicit p: Parameters) extends TlbBundle {
380  val vaddr = Output(UInt(VAddrBits.W))
381  val cmd = Output(TlbCmd())
382  val size = Output(UInt(log2Ceil(log2Ceil(XLEN/8)+1).W))
383  val robIdx = Output(new RobPtr)
384  val debug = new Bundle {
385    val pc = Output(UInt(XLEN.W))
386    val isFirstIssue = Output(Bool())
387  }
388
389  override def toPrintable: Printable = {
390    p"vaddr:0x${Hexadecimal(vaddr)} cmd:${cmd} pc:0x${Hexadecimal(debug.pc)} robIdx:${robIdx}"
391  }
392}
393
394class TlbExceptionBundle(implicit p: Parameters) extends TlbBundle {
395  val ld = Output(Bool())
396  val st = Output(Bool())
397  val instr = Output(Bool())
398}
399
400class TlbResp(implicit p: Parameters) extends TlbBundle {
401  val paddr = Output(UInt(PAddrBits.W))
402  val miss = Output(Bool())
403  val fast_miss = Output(Bool()) // without sram part for timing optimization
404  val excp = new Bundle {
405    val pf = new TlbExceptionBundle()
406    val af = new TlbExceptionBundle()
407  }
408  val static_pm = Output(Valid(Bool())) // valid for static, bits for mmio result from normal entries
409  val ptwBack = Output(Bool()) // when ptw back, wake up replay rs's state
410
411  override def toPrintable: Printable = {
412    p"paddr:0x${Hexadecimal(paddr)} miss:${miss} excp.pf: ld:${excp.pf.ld} st:${excp.pf.st} instr:${excp.pf.instr} ptwBack:${ptwBack}"
413  }
414}
415
416class TlbRequestIO()(implicit p: Parameters) extends TlbBundle {
417  val req = DecoupledIO(new TlbReq)
418  val resp = Flipped(DecoupledIO(new TlbResp))
419}
420
421class BlockTlbRequestIO()(implicit p: Parameters) extends TlbBundle {
422  val req = DecoupledIO(new TlbReq)
423  val resp = Flipped(DecoupledIO(new TlbResp))
424}
425
426class TlbPtwIO(Width: Int = 1)(implicit p: Parameters) extends TlbBundle {
427  val req = Vec(Width, DecoupledIO(new PtwReq))
428  val resp = Flipped(DecoupledIO(new PtwResp))
429
430
431  override def toPrintable: Printable = {
432    p"req(0):${req(0).valid} ${req(0).ready} ${req(0).bits} | resp:${resp.valid} ${resp.ready} ${resp.bits}"
433  }
434}
435
436class MMUIOBaseBundle(implicit p: Parameters) extends TlbBundle {
437  val sfence = Input(new SfenceBundle)
438  val csr = Input(new TlbCsrBundle)
439}
440
441class TlbIO(Width: Int, q: TLBParameters)(implicit p: Parameters) extends
442  MMUIOBaseBundle {
443  val requestor = Vec(Width, Flipped(new TlbRequestIO))
444  val ptw = new TlbPtwIO(Width)
445  val ptw_replenish = Input(new PMPConfig())
446  val replace = if (q.outReplace) Flipped(new TlbReplaceIO(Width, q)) else null
447  val pmp = Vec(Width, ValidIO(new PMPReqBundle()))
448
449}
450
451class BTlbPtwIO(Width: Int)(implicit p: Parameters) extends TlbBundle {
452  val req = Vec(Width, DecoupledIO(new PtwReq))
453  val resp = Flipped(DecoupledIO(new Bundle {
454    val data = new PtwResp
455    val vector = Output(Vec(Width, Bool()))
456  }))
457
458}
459/****************************  Bridge TLB *******************************/
460
461class BridgeTLBIO(Width: Int)(implicit p: Parameters) extends MMUIOBaseBundle {
462  val requestor = Vec(Width, Flipped(new TlbPtwIO()))
463  val ptw = new BTlbPtwIO(Width)
464
465}
466
467
468/****************************  L2TLB  *************************************/
469abstract class PtwBundle(implicit p: Parameters) extends XSBundle with HasPtwConst
470abstract class PtwModule(outer: L2TLB) extends LazyModuleImp(outer)
471  with HasXSParameter with HasPtwConst
472
473class PteBundle(implicit p: Parameters) extends PtwBundle{
474  val reserved  = UInt(pteResLen.W)
475  val ppn  = UInt(ppnLen.W)
476  val rsw  = UInt(2.W)
477  val perm = new Bundle {
478    val d    = Bool()
479    val a    = Bool()
480    val g    = Bool()
481    val u    = Bool()
482    val x    = Bool()
483    val w    = Bool()
484    val r    = Bool()
485    val v    = Bool()
486  }
487
488  def unaligned(level: UInt) = {
489    isLeaf() && !(level === 2.U ||
490                  level === 1.U && ppn(vpnnLen-1,   0) === 0.U ||
491                  level === 0.U && ppn(vpnnLen*2-1, 0) === 0.U)
492  }
493
494  def isPf(level: UInt) = {
495    !perm.v || (!perm.r && perm.w) || unaligned(level)
496  }
497
498  def isLeaf() = {
499    perm.r || perm.x || perm.w
500  }
501
502  def getPerm() = {
503    val pm = Wire(new PtePermBundle)
504    pm.d := perm.d
505    pm.a := perm.a
506    pm.g := perm.g
507    pm.u := perm.u
508    pm.x := perm.x
509    pm.w := perm.w
510    pm.r := perm.r
511    pm
512  }
513
514  override def toPrintable: Printable = {
515    p"ppn:0x${Hexadecimal(ppn)} perm:b${Binary(perm.asUInt)}"
516  }
517}
518
519class PtwEntry(tagLen: Int, hasPerm: Boolean = false, hasLevel: Boolean = false)(implicit p: Parameters) extends PtwBundle {
520  val tag = UInt(tagLen.W)
521  val asid = UInt(asidLen.W)
522  val ppn = UInt(ppnLen.W)
523  val perm = if (hasPerm) Some(new PtePermBundle) else None
524  val level = if (hasLevel) Some(UInt(log2Up(Level).W)) else None
525  val prefetch = Bool()
526  val v = Bool()
527
528  def is_normalentry(): Bool = {
529    if (!hasLevel) true.B
530    else level.get === 2.U
531  }
532
533  def hit(vpn: UInt, asid: UInt, allType: Boolean = false, ignoreAsid: Boolean = false) = {
534    require(vpn.getWidth == vpnLen)
535//    require(this.asid.getWidth <= asid.getWidth)
536    val asid_hit = if (ignoreAsid) true.B else (this.asid === asid)
537    if (allType) {
538      require(hasLevel)
539      val hit0 = tag(tagLen - 1,    vpnnLen*2) === vpn(tagLen - 1, vpnnLen*2)
540      val hit1 = tag(vpnnLen*2 - 1, vpnnLen)   === vpn(vpnnLen*2 - 1,  vpnnLen)
541      val hit2 = tag(vpnnLen - 1,     0)         === vpn(vpnnLen - 1, 0)
542
543      asid_hit && Mux(level.getOrElse(0.U) === 2.U, hit2 && hit1 && hit0, Mux(level.getOrElse(0.U) === 1.U, hit1 && hit0, hit0))
544    } else if (hasLevel) {
545      val hit0 = tag(tagLen - 1, tagLen - vpnnLen) === vpn(vpnLen - 1, vpnLen - vpnnLen)
546      val hit1 = tag(tagLen - vpnnLen - 1, tagLen - vpnnLen * 2) === vpn(vpnLen - vpnnLen - 1, vpnLen - vpnnLen * 2)
547
548      asid_hit && Mux(level.getOrElse(0.U) === 0.U, hit0, hit0 && hit1)
549    } else {
550      asid_hit && tag === vpn(vpnLen - 1, vpnLen - tagLen)
551    }
552  }
553
554  def refill(vpn: UInt, asid: UInt, pte: UInt, level: UInt = 0.U, prefetch: Bool, valid: Bool = false.B) {
555    require(this.asid.getWidth <= asid.getWidth) // maybe equal is better, but ugly outside
556
557    tag := vpn(vpnLen - 1, vpnLen - tagLen)
558    ppn := pte.asTypeOf(new PteBundle().cloneType).ppn
559    perm.map(_ := pte.asTypeOf(new PteBundle().cloneType).perm)
560    this.asid := asid
561    this.prefetch := prefetch
562    this.v := valid
563    this.level.map(_ := level)
564  }
565
566  def genPtwEntry(vpn: UInt, asid: UInt, pte: UInt, level: UInt = 0.U, prefetch: Bool, valid: Bool = false.B) = {
567    val e = Wire(new PtwEntry(tagLen, hasPerm, hasLevel))
568    e.refill(vpn, asid, pte, level, prefetch, valid)
569    e
570  }
571
572
573  override def toPrintable: Printable = {
574    // p"tag:0x${Hexadecimal(tag)} ppn:0x${Hexadecimal(ppn)} perm:${perm}"
575    p"tag:0x${Hexadecimal(tag)} ppn:0x${Hexadecimal(ppn)} " +
576      (if (hasPerm) p"perm:${perm.getOrElse(0.U.asTypeOf(new PtePermBundle))} " else p"") +
577      (if (hasLevel) p"level:${level.getOrElse(0.U)}" else p"") +
578      p"prefetch:${prefetch}"
579  }
580}
581
582class PtwEntries(num: Int, tagLen: Int, level: Int, hasPerm: Boolean)(implicit p: Parameters) extends PtwBundle {
583  require(log2Up(num)==log2Down(num))
584
585  val tag  = UInt(tagLen.W)
586  val asid = UInt(asidLen.W)
587  val ppns = Vec(num, UInt(ppnLen.W))
588  val vs   = Vec(num, Bool())
589  val perms = if (hasPerm) Some(Vec(num, new PtePermBundle)) else None
590  val prefetch = Bool()
591  // println(s"PtwEntries: tag:1*${tagLen} ppns:${num}*${ppnLen} vs:${num}*1")
592
593  def tagClip(vpn: UInt) = {
594    require(vpn.getWidth == vpnLen)
595    vpn(vpnLen - 1, vpnLen - tagLen)
596  }
597
598  def sectorIdxClip(vpn: UInt, level: Int) = {
599    getVpnClip(vpn, level)(log2Up(num) - 1, 0)
600  }
601
602  def hit(vpn: UInt, asid: UInt, ignoreAsid: Boolean = false) = {
603    val asid_hit = if (ignoreAsid) true.B else (this.asid === asid)
604    asid_hit && tag === tagClip(vpn) && vs(sectorIdxClip(vpn, level)) // TODO: optimize this. don't need to compare each with tag
605  }
606
607  def genEntries(vpn: UInt, asid: UInt, data: UInt, levelUInt: UInt, prefetch: Bool) = {
608    require((data.getWidth / XLEN) == num,
609      s"input data length must be multiple of pte length: data.length:${data.getWidth} num:${num}")
610
611    val ps = Wire(new PtwEntries(num, tagLen, level, hasPerm))
612    ps.tag := tagClip(vpn)
613    ps.asid := asid
614    ps.prefetch := prefetch
615    for (i <- 0 until num) {
616      val pte = data((i+1)*XLEN-1, i*XLEN).asTypeOf(new PteBundle)
617      ps.ppns(i) := pte.ppn
618      ps.vs(i)   := !pte.isPf(levelUInt) && (if (hasPerm) pte.isLeaf() else !pte.isLeaf())
619      ps.perms.map(_(i) := pte.perm)
620    }
621    ps
622  }
623
624  override def toPrintable: Printable = {
625    // require(num == 4, "if num is not 4, please comment this toPrintable")
626    // NOTE: if num is not 4, please comment this toPrintable
627    val permsInner = perms.getOrElse(0.U.asTypeOf(Vec(num, new PtePermBundle)))
628    p"asid: ${Hexadecimal(asid)} tag:0x${Hexadecimal(tag)} ppns:${printVec(ppns)} vs:${Binary(vs.asUInt)} " +
629      (if (hasPerm) p"perms:${printVec(permsInner)}" else p"")
630  }
631}
632
633class PTWEntriesWithEcc(eccCode: Code, num: Int, tagLen: Int, level: Int, hasPerm: Boolean)(implicit p: Parameters) extends PtwBundle {
634  val entries = new PtwEntries(num, tagLen, level, hasPerm)
635
636  val ecc_block = XLEN
637  val ecc_info = get_ecc_info()
638  val ecc = UInt(ecc_info._1.W)
639
640  def get_ecc_info(): (Int, Int, Int, Int) = {
641    val eccBits_per = eccCode.width(ecc_block) - ecc_block
642
643    val data_length = entries.getWidth
644    val data_align_num = data_length / ecc_block
645    val data_not_align = (data_length % ecc_block) != 0 // ugly code
646    val data_unalign_length = data_length - data_align_num * ecc_block
647    val eccBits_unalign = eccCode.width(data_unalign_length) - data_unalign_length
648
649    val eccBits = eccBits_per * data_align_num + eccBits_unalign
650    (eccBits, eccBits_per, data_align_num, data_unalign_length)
651  }
652
653  def encode() = {
654    val data = entries.asUInt()
655    val ecc_slices = Wire(Vec(ecc_info._3, UInt(ecc_info._2.W)))
656    for (i <- 0 until ecc_info._3) {
657      ecc_slices(i) := eccCode.encode(data((i+1)*ecc_block-1, i*ecc_block)) >> ecc_block
658    }
659    if (ecc_info._4 != 0) {
660      val ecc_unaligned = eccCode.encode(data(data.getWidth-1, ecc_info._3*ecc_block)) >> ecc_info._4
661      ecc := Cat(ecc_unaligned, ecc_slices.asUInt())
662    } else { ecc := ecc_slices.asUInt() }
663  }
664
665  def decode(): Bool = {
666    val data = entries.asUInt()
667    val res = Wire(Vec(ecc_info._3 + 1, Bool()))
668    for (i <- 0 until ecc_info._3) {
669      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}
670    }
671    if (ecc_info._2 != 0 && ecc_info._4 != 0) {
672      res(ecc_info._3) := eccCode.decode(
673        Cat(ecc(ecc_info._1-1, ecc_info._2*ecc_info._3), data(data.getWidth-1, ecc_info._3*ecc_block))).error
674    } else { res(ecc_info._3) := false.B }
675
676    Cat(res).orR
677  }
678
679  def gen(vpn: UInt, asid: UInt, data: UInt, levelUInt: UInt, prefetch: Bool) = {
680    this.entries := entries.genEntries(vpn, asid, data, levelUInt, prefetch)
681    this.encode()
682  }
683
684}
685
686class PtwReq(implicit p: Parameters) extends PtwBundle {
687  val vpn = UInt(vpnLen.W)
688
689  override def toPrintable: Printable = {
690    p"vpn:0x${Hexadecimal(vpn)}"
691  }
692}
693
694class PtwResp(implicit p: Parameters) extends PtwBundle {
695  val entry = new PtwEntry(tagLen = vpnLen, hasPerm = true, hasLevel = true)
696  val pf = Bool()
697  val af = Bool()
698
699
700  def apply(pf: Bool, af: Bool, level: UInt, pte: PteBundle, vpn: UInt, asid: UInt) = {
701    this.entry.level.map(_ := level)
702    this.entry.tag := vpn
703    this.entry.perm.map(_ := pte.getPerm())
704    this.entry.ppn := pte.ppn
705    this.entry.prefetch := DontCare
706    this.entry.asid := asid
707    this.entry.v := !pf
708    this.pf := pf
709    this.af := af
710  }
711
712  override def toPrintable: Printable = {
713    p"entry:${entry} pf:${pf} af:${af}"
714  }
715}
716
717class L2TLBIO(implicit p: Parameters) extends PtwBundle {
718  val tlb = Vec(PtwWidth, Flipped(new TlbPtwIO))
719  val sfence = Input(new SfenceBundle)
720  val csr = new Bundle {
721    val tlb = Input(new TlbCsrBundle)
722    val distribute_csr = Flipped(new DistributedCSRIO)
723  }
724}
725
726class L2TlbMemReqBundle(implicit p: Parameters) extends PtwBundle {
727  val addr = UInt(PAddrBits.W)
728  val id = UInt(bMemID.W)
729}
730
731class L2TlbInnerBundle(implicit p: Parameters) extends PtwReq {
732  val source = UInt(bSourceWidth.W)
733}
734