xref: /XiangShan/src/main/scala/xiangshan/cache/mmu/TLB.scala (revision 7a2fc509e2d355879c4db3dc3f17a6ccacd3d09e)
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.internal.naming.chiselName
22import chisel3.util._
23import freechips.rocketchip.util.SRAMAnnotation
24import xiangshan._
25import utils._
26import xiangshan.backend.fu.{PMPChecker, PMPReqBundle}
27import xiangshan.backend.rob.RobPtr
28import xiangshan.backend.fu.util.HasCSRConst
29
30
31@chiselName
32class TLB(Width: Int, q: TLBParameters)(implicit p: Parameters) extends TlbModule with HasCSRConst with HasPerfEvents {
33  val io = IO(new TlbIO(Width, q))
34
35  require(q.superAssociative == "fa")
36  if (q.sameCycle || q.missSameCycle) {
37    require(q.normalAssociative == "fa")
38  }
39
40  val req = io.requestor.map(_.req)
41  val resp = io.requestor.map(_.resp)
42  val ptw = io.ptw
43  val pmp = io.pmp
44
45  val sfence = io.sfence
46  val csr = io.csr
47  val satp = csr.satp
48  val priv = csr.priv
49  val ifecth = if (q.fetchi) true.B else false.B
50  val mode = if (q.useDmode) priv.dmode else priv.imode
51  // val vmEnable = satp.mode === 8.U // && (mode < ModeM) // FIXME: fix me when boot xv6/linux...
52  val vmEnable = if (EnbaleTlbDebug) (satp.mode === 8.U)
53  else (satp.mode === 8.U && (mode < ModeM))
54
55  val reqAddr = req.map(_.bits.vaddr.asTypeOf(new VaBundle))
56  val vpn = reqAddr.map(_.vpn)
57  val cmd = req.map(_.bits.cmd)
58  val valid = req.map(_.valid)
59
60  def widthMapSeq[T <: Seq[Data]](f: Int => T) = (0 until Width).map(f)
61
62  def widthMap[T <: Data](f: Int => T) = (0 until Width).map(f)
63
64  // Normal page && Super page
65  val normalPage = TlbStorage(
66    name = "normal",
67    associative = q.normalAssociative,
68    sameCycle = q.sameCycle,
69    ports = Width,
70    nSets = q.normalNSets,
71    nWays = q.normalNWays,
72    sramSinglePort = sramSinglePort,
73    saveLevel = q.saveLevel,
74    normalPage = true,
75    superPage = false
76  )
77  val superPage = TlbStorage(
78    name = "super",
79    associative = q.superAssociative,
80    sameCycle = q.sameCycle,
81    ports = Width,
82    nSets = q.superNSets,
83    nWays = q.superNWays,
84    sramSinglePort = sramSinglePort,
85    saveLevel = q.saveLevel,
86    normalPage = q.normalAsVictim,
87    superPage = true,
88  )
89
90
91  for (i <- 0 until Width) {
92    normalPage.r_req_apply(
93      valid = io.requestor(i).req.valid,
94      vpn = vpn(i),
95      asid = csr.satp.asid,
96      i = i
97    )
98    superPage.r_req_apply(
99      valid = io.requestor(i).req.valid,
100      vpn = vpn(i),
101      asid = csr.satp.asid,
102      i = i
103    )
104  }
105
106  normalPage.victim.in <> superPage.victim.out
107  normalPage.victim.out <> superPage.victim.in
108  normalPage.sfence <> io.sfence
109  superPage.sfence <> io.sfence
110  normalPage.csr <> io.csr
111  superPage.csr <> io.csr
112
113  def TLBNormalRead(i: Int) = {
114    val (n_hit_sameCycle, normal_hit, normal_ppn, normal_perm) = normalPage.r_resp_apply(i)
115    val (s_hit_sameCycle, super_hit, super_ppn, super_perm) = superPage.r_resp_apply(i)
116    // assert(!(normal_hit && super_hit && vmEnable && RegNext(req(i).valid, init = false.B)))
117
118    val hit = normal_hit || super_hit
119    val hit_sameCycle = n_hit_sameCycle || s_hit_sameCycle
120    val ppn = Mux(super_hit, super_ppn, normal_ppn)
121    val perm = Mux(super_hit, super_perm, normal_perm)
122
123    val pf = perm.pf
124    val af = perm.af
125    val cmdReg = if (!q.sameCycle) RegNext(cmd(i)) else cmd(i)
126    val validReg = if (!q.sameCycle) RegNext(valid(i)) else valid(i)
127    val offReg = if (!q.sameCycle) RegNext(reqAddr(i).off) else reqAddr(i).off
128    val sizeReg = if (!q.sameCycle) RegNext(req(i).bits.size) else req(i).bits.size
129
130    /** *************** next cycle when two cycle is false******************* */
131    val miss = !hit && vmEnable
132    val fast_miss = !super_hit && vmEnable
133    val miss_sameCycle = !hit_sameCycle && vmEnable
134    hit.suggestName(s"hit_${i}")
135    miss.suggestName(s"miss_${i}")
136
137    XSDebug(validReg, p"(${i.U}) hit:${hit} miss:${miss} ppn:${Hexadecimal(ppn)} perm:${perm}\n")
138
139    val paddr = Cat(ppn, offReg)
140    val vaddr = SignExt(req(i).bits.vaddr, PAddrBits)
141    val refill_reg = RegNext(io.ptw.resp.valid)
142    req(i).ready := resp(i).ready
143    resp(i).valid := validReg
144    resp(i).bits.paddr := Mux(vmEnable, paddr, if (!q.sameCycle) RegNext(vaddr) else vaddr)
145    resp(i).bits.miss := { if (q.missSameCycle) miss_sameCycle else (miss || refill_reg) }
146    resp(i).bits.fast_miss := fast_miss || refill_reg
147    resp(i).bits.ptwBack := io.ptw.resp.fire()
148
149    // for timing optimization, pmp check is divided into dynamic and static
150    // dynamic: superpage (or full-connected reg entries) -> check pmp when translation done
151    // static: 4K pages (or sram entries) -> check pmp with pre-checked results
152    val pmp_paddr = Mux(vmEnable, Cat(super_ppn, offReg), if (!q.sameCycle) RegNext(vaddr) else vaddr)
153    pmp(i).valid := resp(i).valid
154    pmp(i).bits.addr := pmp_paddr
155    pmp(i).bits.size := sizeReg
156    pmp(i).bits.cmd := cmdReg
157
158    val ldUpdate = !perm.a && TlbCmd.isRead(cmdReg) && !TlbCmd.isAmo(cmdReg) // update A/D through exception
159    val stUpdate = (!perm.a || !perm.d) && (TlbCmd.isWrite(cmdReg) || TlbCmd.isAmo(cmdReg)) // update A/D through exception
160    val instrUpdate = !perm.a && TlbCmd.isExec(cmdReg) // update A/D through exception
161    val modeCheck = !(mode === ModeU && !perm.u || mode === ModeS && perm.u && (!priv.sum || ifecth))
162    val ldPermFail = !(modeCheck && (perm.r || priv.mxr && perm.x))
163    val stPermFail = !(modeCheck && perm.w)
164    val instrPermFail = !(modeCheck && perm.x)
165    val ldPf = (ldPermFail || pf) && (TlbCmd.isRead(cmdReg) && !TlbCmd.isAmo(cmdReg))
166    val stPf = (stPermFail || pf) && (TlbCmd.isWrite(cmdReg) || TlbCmd.isAmo(cmdReg))
167    val instrPf = (instrPermFail || pf) && TlbCmd.isExec(cmdReg)
168    val fault_valid = vmEnable
169    resp(i).bits.excp.pf.ld := (ldPf || ldUpdate) && fault_valid && !af
170    resp(i).bits.excp.pf.st := (stPf || stUpdate) && fault_valid && !af
171    resp(i).bits.excp.pf.instr := (instrPf || instrUpdate) && fault_valid && !af
172    // NOTE: pf need && with !af, page fault has higher priority than access fault
173    // but ptw may also have access fault, then af happens, the translation is wrong.
174    // In this case, pf has lower priority than af
175
176    val spm = normal_perm.pm // static physical memory protection or attribute
177    val spm_v = !super_hit && vmEnable && q.partialStaticPMP.B // static pm valid; do not use normal_hit, it's too long.
178    // for tlb without sram, tlb will miss, pm should be ignored outsize
179    resp(i).bits.excp.af.ld    := (af || (spm_v && !spm.r)) && TlbCmd.isRead(cmdReg) && fault_valid
180    resp(i).bits.excp.af.st    := (af || (spm_v && !spm.w)) && TlbCmd.isWrite(cmdReg) && fault_valid
181    resp(i).bits.excp.af.instr := (af || (spm_v && !spm.x)) && TlbCmd.isExec(cmdReg) && fault_valid
182    resp(i).bits.static_pm.valid := spm_v && fault_valid // ls/st unit should use this mmio, not the result from pmp
183    resp(i).bits.static_pm.bits := !spm.c
184
185    (hit, miss, validReg)
186  }
187
188  val readResult = (0 until Width).map(TLBNormalRead(_))
189  val hitVec = readResult.map(_._1)
190  val missVec = readResult.map(_._2)
191  val validRegVec = readResult.map(_._3)
192
193  // replacement
194  def get_access(one_hot: UInt, valid: Bool): Valid[UInt] = {
195    val res = Wire(Valid(UInt(log2Up(one_hot.getWidth).W)))
196    res.valid := Cat(one_hot).orR && valid
197    res.bits := OHToUInt(one_hot)
198    res
199  }
200
201  val normal_refill_idx = if (q.outReplace) {
202    io.replace.normalPage.access <> normalPage.access
203    io.replace.normalPage.chosen_set := get_set_idx(io.ptw.resp.bits.entry.tag, q.normalNSets)
204    io.replace.normalPage.refillIdx
205  } else if (q.normalAssociative == "fa") {
206    val re = ReplacementPolicy.fromString(q.normalReplacer, q.normalNWays)
207    re.access(normalPage.access.map(_.touch_ways)) // normalhitVecVec.zipWithIndex.map{ case (hv, i) => get_access(hv, validRegVec(i))})
208    re.way
209  } else { // set-acco && plru
210    val re = ReplacementPolicy.fromString(q.normalReplacer, q.normalNSets, q.normalNWays)
211    re.access(normalPage.access.map(_.sets), normalPage.access.map(_.touch_ways))
212    re.way(get_set_idx(io.ptw.resp.bits.entry.tag, q.normalNSets))
213  }
214
215  val super_refill_idx = if (q.outReplace) {
216    io.replace.superPage.access <> superPage.access
217    io.replace.superPage.chosen_set := DontCare
218    io.replace.superPage.refillIdx
219  } else {
220    val re = ReplacementPolicy.fromString(q.superReplacer, q.superNWays)
221    re.access(superPage.access.map(_.touch_ways))
222    re.way
223  }
224
225  val refill = ptw.resp.fire() && !sfence.valid && !satp.changed
226  normalPage.w_apply(
227    valid = { if (q.normalAsVictim) false.B
228    else refill && ptw.resp.bits.entry.level.get === 2.U },
229    wayIdx = normal_refill_idx,
230    data = ptw.resp.bits,
231    data_replenish = io.ptw_replenish
232  )
233  superPage.w_apply(
234    valid = { if (q.normalAsVictim) refill
235    else refill && ptw.resp.bits.entry.level.get =/= 2.U },
236    wayIdx = super_refill_idx,
237    data = ptw.resp.bits,
238    data_replenish = io.ptw_replenish
239  )
240
241  // if sameCycle, just req.valid
242  // if !sameCycle, add one more RegNext based on !sameCycle's RegNext
243  // because sram is too slow and dtlb is too distant from dtlbRepeater
244  for (i <- 0 until Width) {
245    io.ptw.req(i).valid :=  need_RegNextInit(!q.sameCycle, validRegVec(i) && missVec(i), false.B) &&
246      !RegNext(refill, init = false.B) &&
247      param_choose(!q.sameCycle, !RegNext(RegNext(refill, init = false.B), init = false.B), true.B)
248    io.ptw.req(i).bits.vpn := need_RegNext(!q.sameCycle, need_RegNext(!q.sameCycle, reqAddr(i).vpn))
249  }
250  io.ptw.resp.ready := true.B
251
252  def need_RegNext[T <: Data](need: Boolean, data: T): T = {
253    if (need) RegNext(data)
254    else data
255  }
256  def need_RegNextInit[T <: Data](need: Boolean, data: T, init_value: T): T = {
257    if (need) RegNext(data, init = init_value)
258    else data
259  }
260
261  def param_choose[T <: Data](need: Boolean, truedata: T, falsedata: T): T = {
262    if (need) truedata
263    else falsedata
264  }
265
266  if (!q.shouldBlock) {
267    for (i <- 0 until Width) {
268      XSPerfAccumulate("first_access" + Integer.toString(i, 10), validRegVec(i) && vmEnable && RegNext(req(i).bits.debug.isFirstIssue))
269      XSPerfAccumulate("access" + Integer.toString(i, 10), validRegVec(i) && vmEnable)
270    }
271    for (i <- 0 until Width) {
272      XSPerfAccumulate("first_miss" + Integer.toString(i, 10), validRegVec(i) && vmEnable && missVec(i) && RegNext(req(i).bits.debug.isFirstIssue))
273      XSPerfAccumulate("miss" + Integer.toString(i, 10), validRegVec(i) && vmEnable && missVec(i))
274    }
275  } else {
276    // NOTE: ITLB is blocked, so every resp will be valid only when hit
277    // every req will be ready only when hit
278    for (i <- 0 until Width) {
279      XSPerfAccumulate(s"access${i}", io.requestor(i).req.fire() && vmEnable)
280      XSPerfAccumulate(s"miss${i}", ptw.req(i).fire())
281    }
282
283  }
284  //val reqCycleCnt = Reg(UInt(16.W))
285  //reqCycleCnt := reqCycleCnt + BoolStopWatch(ptw.req(0).fire(), ptw.resp.fire || sfence.valid)
286  //XSPerfAccumulate("ptw_req_count", ptw.req.fire())
287  //XSPerfAccumulate("ptw_req_cycle", Mux(ptw.resp.fire(), reqCycleCnt, 0.U))
288  XSPerfAccumulate("ptw_resp_count", ptw.resp.fire())
289  XSPerfAccumulate("ptw_resp_pf_count", ptw.resp.fire() && ptw.resp.bits.pf)
290
291  // Log
292  for(i <- 0 until Width) {
293    XSDebug(req(i).valid, p"req(${i.U}): (${req(i).valid} ${req(i).ready}) ${req(i).bits}\n")
294    XSDebug(resp(i).valid, p"resp(${i.U}): (${resp(i).valid} ${resp(i).ready}) ${resp(i).bits}\n")
295  }
296
297  XSDebug(sfence.valid, p"Sfence: ${sfence}\n")
298  XSDebug(ParallelOR(valid)|| ptw.resp.valid, p"CSR: ${csr}\n")
299  XSDebug(ParallelOR(valid) || ptw.resp.valid, p"vmEnable:${vmEnable} hit:${Binary(VecInit(hitVec).asUInt)} miss:${Binary(VecInit(missVec).asUInt)}\n")
300  for (i <- ptw.req.indices) {
301    XSDebug(ptw.req(i).fire(), p"L2TLB req:${ptw.req(i).bits}\n")
302  }
303  XSDebug(ptw.resp.valid, p"L2TLB resp:${ptw.resp.bits} (v:${ptw.resp.valid}r:${ptw.resp.ready}) \n")
304
305  println(s"${q.name}: normal page: ${q.normalNWays} ${q.normalAssociative} ${q.normalReplacer.get} super page: ${q.superNWays} ${q.superAssociative} ${q.superReplacer.get}")
306
307//   // NOTE: just for simple tlb debug, comment it after tlb's debug
308  // assert(!io.ptw.resp.valid || io.ptw.resp.bits.entry.tag === io.ptw.resp.bits.entry.ppn, "Simple tlb debug requires vpn === ppn")
309
310  val perfEvents = if(!q.shouldBlock) {
311    Seq(
312      ("access", PopCount((0 until Width).map(i => vmEnable && validRegVec(i)))              ),
313      ("miss  ", PopCount((0 until Width).map(i => vmEnable && validRegVec(i) && missVec(i)))),
314    )
315  } else {
316    Seq(
317      ("access", PopCount((0 until Width).map(i => io.requestor(i).req.fire()))),
318      ("miss  ", PopCount((0 until Width).map(i => ptw.req(i).fire()))         ),
319    )
320  }
321  generatePerfEvent()
322}
323
324class TlbReplace(Width: Int, q: TLBParameters)(implicit p: Parameters) extends TlbModule {
325  val io = IO(new TlbReplaceIO(Width, q))
326
327  if (q.normalAssociative == "fa") {
328    val re = ReplacementPolicy.fromString(q.normalReplacer, q.normalNWays)
329    re.access(io.normalPage.access.map(_.touch_ways))
330    io.normalPage.refillIdx := re.way
331  } else { // set-acco && plru
332    val re = ReplacementPolicy.fromString(q.normalReplacer, q.normalNSets, q.normalNWays)
333    re.access(io.normalPage.access.map(_.sets), io.normalPage.access.map(_.touch_ways))
334    io.normalPage.refillIdx := { if (q.normalNWays == 1) 0.U else re.way(io.normalPage.chosen_set) }
335  }
336
337  if (q.superAssociative == "fa") {
338    val re = ReplacementPolicy.fromString(q.superReplacer, q.superNWays)
339    re.access(io.superPage.access.map(_.touch_ways))
340    io.superPage.refillIdx := re.way
341  } else { // set-acco && plru
342    val re = ReplacementPolicy.fromString(q.superReplacer, q.superNSets, q.superNWays)
343    re.access(io.superPage.access.map(_.sets), io.superPage.access.map(_.touch_ways))
344    io.superPage.refillIdx := { if (q.superNWays == 1) 0.U else re.way(io.superPage.chosen_set) }
345  }
346}
347
348object TLB {
349  def apply
350  (
351    in: Seq[BlockTlbRequestIO],
352    sfence: SfenceBundle,
353    csr: TlbCsrBundle,
354    width: Int,
355    shouldBlock: Boolean,
356    q: TLBParameters
357  )(implicit p: Parameters) = {
358    require(in.length == width)
359
360    val tlb = Module(new TLB(width, q))
361
362    tlb.io.sfence <> sfence
363    tlb.io.csr <> csr
364    tlb.suggestName(s"tlb_${q.name}")
365
366    if (!shouldBlock) { // dtlb
367      for (i <- 0 until width) {
368        tlb.io.requestor(i) <> in(i)
369        // tlb.io.requestor(i).req.valid := in(i).req.valid
370        // tlb.io.requestor(i).req.bits := in(i).req.bits
371        // in(i).req.ready := tlb.io.requestor(i).req.ready
372
373        // in(i).resp.valid := tlb.io.requestor(i).resp.valid
374        // in(i).resp.bits := tlb.io.requestor(i).resp.bits
375        // tlb.io.requestor(i).resp.ready := in(i).resp.ready
376      }
377    } else { // itlb
378      //require(width == 1)
379      (0 until width).map{ i =>
380        tlb.io.requestor(i).req.valid := in(i).req.valid
381        tlb.io.requestor(i).req.bits := in(i).req.bits
382        in(i).req.ready := !tlb.io.requestor(i).resp.bits.miss && in(i).resp.ready && tlb.io.requestor(i).req.ready
383
384        require(q.missSameCycle || q.sameCycle)
385        // NOTE: the resp.valid seems to be useless, it must be true when need
386        //       But don't know what happens when true but not need, so keep it correct value, not just true.B
387        if (q.missSameCycle && !q.sameCycle) {
388          in(i).resp.valid := tlb.io.requestor(i).resp.valid && !RegNext(tlb.io.requestor(i).resp.bits.miss)
389        } else {
390          in(i).resp.valid := tlb.io.requestor(i).resp.valid && !tlb.io.requestor(i).resp.bits.miss
391        }
392        in(i).resp.bits := tlb.io.requestor(i).resp.bits
393        tlb.io.requestor(i).resp.ready := in(i).resp.ready
394      }
395      tlb.io.ptw_replenish <> DontCare // itlb only use reg, so no static pmp/pma
396    }
397    tlb.io.ptw
398  }
399}
400