ptw.scala 12.5 KB
Newer Older
1
package xiangshan.cache
Z
ZhangZifei 已提交
2 3 4 5 6 7 8 9

import chisel3._
import chisel3.util._
import xiangshan._
import utils._
import chisel3.util.experimental.BoringUtils
import xiangshan.backend.decode.XSTrap
import xiangshan.mem._
Z
ZhangZifei 已提交
10
import chisel3.ExcitingUtils._
Z
ZhangZifei 已提交
11

12
trait HasPtwConst extends HasTlbConst with MemoryOpConstants{
Z
ZhangZifei 已提交
13 14 15 16
  val PtwWidth = 2
}

abstract class PtwBundle extends XSBundle with HasPtwConst
17
abstract class PtwModule extends XSModule with HasPtwConst 
Z
ZhangZifei 已提交
18

Z
ZhangZifei 已提交
19 20 21 22 23
class PteBundle extends PtwBundle{
  val reserved  = UInt(pteResLen.W)
  val ppn  = UInt(ppnLen.W)
  val rsw  = UInt(2.W)
  val perm = new Bundle {
Z
ZhangZifei 已提交
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
    val d    = Bool()
    val a    = Bool()
    val g    = Bool()
    val u    = Bool()
    val x    = Bool()
    val w    = Bool()
    val r    = Bool()
    val v    = Bool()
  }

  def isPf() = {
    !perm.v || (!perm.r && perm.w)
  }

  def isLeaf() = {
    !isPf() && (perm.r || perm.x)
Z
ZhangZifei 已提交
40
  }
Z
ZhangZifei 已提交
41 42 43 44

  override def toPrintable: Printable = {
    p"ppn:0x${Hexadecimal(ppn)} perm:b${Binary(perm.asUInt)}"
  }
Z
ZhangZifei 已提交
45 46
}

47
class PtwEntry(tagLen: Int) extends PtwBundle {
Z
ZhangZifei 已提交
48 49 50
  val tag = UInt(tagLen.W)
  val ppn = UInt(ppnLen.W)
  val perm = new PermBundle
51 52 53 54 55 56

  // TODO: add superpage
  def hit(addr: UInt) = {
    require(addr.getWidth >= PAddrBits)
    tag === addr(PAddrBits-1, PAddrBits-tagLen)
  }
Z
ZhangZifei 已提交
57 58 59 60 61 62 63 64

  def refill(addr: UInt, pte: UInt) {
    tag := addr(PAddrBits-1, PAddrBits-tagLen)
    ppn := pte.asTypeOf(pteBundle).ppn
    perm := pte.asTypeOf(pteBundle).perm
  }

  def genPtwEntry(addr: UInt, pte: UInt) = {
65
    val e = Wire(new PtwEntry(tagLen))
Z
ZhangZifei 已提交
66 67 68 69 70
    e.tag := addr(PAddrBits-1, PAddrBits-tagLen)
    e.ppn := pte.asTypeOf(pteBundle).ppn
    e.perm := pte.asTypeOf(pteBundle).perm
    e
  }
71 72

  override def cloneType: this.type = (new PtwEntry(tagLen)).asInstanceOf[this.type]
Z
ZhangZifei 已提交
73 74 75 76

  override def toPrintable: Printable = {
    p"tag:0x${Hexadecimal(tag)} ppn:0x${Hexadecimal(ppn)} perm:${perm}"
  }
Z
ZhangZifei 已提交
77 78 79
}

class PtwReq extends PtwBundle {
Z
ZhangZifei 已提交
80
  val vpn = UInt(vpnLen.W)
Z
ZhangZifei 已提交
81
  val idx = UInt(RoqIdxWidth.W) // itlb could ignore it
Z
ZhangZifei 已提交
82 83 84 85

  override def toPrintable: Printable = {
    p"vpn:0x${Hexadecimal(vpn)} idx:${idx}"
  }
Z
ZhangZifei 已提交
86 87
}

Z
ZhangZifei 已提交
88 89 90 91
class PtwResp extends PtwBundle {
  val entry = new TlbEntry
  val idx = UInt(RoqIdxWidth.W)
  val pf  = Bool() // simple pf no matter cmd
Z
ZhangZifei 已提交
92 93 94 95

  override def toPrintable: Printable = {
    p"entry:${entry} idx:${idx} pf:${pf}"
  }
Z
ZhangZifei 已提交
96
}
Z
ZhangZifei 已提交
97

Z
ZhangZifei 已提交
98
class PtwIO extends PtwBundle {
99
  val tlb = Vec(PtwWidth, Flipped(new TlbPtwIO))
100 101
  //val mem = new SimpleBusUC(addrBits = PAddrBits) // Use Dcache temp
  val mem = new DCacheLoadIO
Z
ZhangZifei 已提交
102 103
}

Z
ZhangZifei 已提交
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
object ValidHold {
  def apply(infire: Bool, outfire: Bool, flush: Bool = false.B ) = {
    val valid = RegInit(false.B)
    when (outfire) { valid := false.B }
    when (infire) { valid := true.B }
    when (flush) { valid := false.B } // NOTE: the flush will flush in & out, is that ok?
    valid
  }
}

object OneCycleValid {
  def apply(fire: Bool, flush: Bool = false.B) = {
    val valid = RegInit(false.B)
    when (valid) { valid := false.B }
    when (fire) { valid := true.B }
    when (false.B) { valid := false.B }
    valid
  }
}

Z
ZhangZifei 已提交
124
class PTW extends PtwModule {
Z
ZhangZifei 已提交
125 126
  val io = IO(new PtwIO)

127 128
  val arb = Module(new Arbiter(new PtwReq, PtwWidth))
  arb.io.in <> VecInit(io.tlb.map(_.req))
Z
ZhangZifei 已提交
129 130
  val arbChosen = RegEnable(arb.io.chosen, arb.io.out.fire())
  val req = RegEnable(arb.io.out.bits, arb.io.out.fire())
131
  val resp  = VecInit(io.tlb.map(_.resp))
132 133


134
  val valid = ValidHold(arb.io.out.fire(), resp(arbChosen).fire())
Z
ZhangZifei 已提交
135
  val validOneCycle = OneCycleValid(arb.io.out.fire())
136 137 138
  arb.io.out.ready := !valid || resp(arbChosen).fire()

  val mem    = io.mem
139 140 141 142 143 144
  val sfence = WireInit(0.U.asTypeOf(new SfenceBundle))
  val csr    = WireInit(0.U.asTypeOf(new TlbCsrBundle))
  val satp   = csr.satp
  val priv   = csr.priv
  BoringUtils.addSink(sfence, "SfenceBundle")
  BoringUtils.addSink(csr, "TLBCSRIO")
Z
ZhangZifei 已提交
145

146 147
  val memRdata = mem.resp.bits.data
  val memPte = memRdata.asTypeOf(new PteBundle)
Z
ZhangZifei 已提交
148 149 150 151 152 153 154

  // two level: l2-tlb-cache && pde/pte-cache
  // l2-tlb-cache is ram-larger-edition tlb
  // pde/pte-cache is cache of page-table, speeding up ptw

  // may seperate valid bits to speed up sfence's flush
  // Reg/Mem/SyncReadMem is not sure now
Z
ZhangZifei 已提交
155 156
  val tagLen1 = PAddrBits - log2Up(XLEN/8)
  val tagLen2 = PAddrBits - log2Up(XLEN/8) - log2Up(PtwL2EntrySize)
157
  val tlbl2 = SyncReadMem(TlbL2EntrySize, new TlbEntry)
158
  val tlbv  = RegInit(0.U(TlbL2EntrySize.W))
Z
ZhangZifei 已提交
159
  val ptwl1 = Reg(Vec(PtwL1EntrySize, new PtwEntry(tagLen = tagLen1)))
160
  val l1v   = RegInit(0.U(PtwL1EntrySize.W))
Z
ZhangZifei 已提交
161
  val ptwl2 = SyncReadMem(PtwL2EntrySize, new PtwEntry(tagLen = tagLen2)) // NOTE: the Mem could be only single port(r&w)
162 163 164 165 166 167
  val l2v   = RegInit(0.U(PtwL2EntrySize.W))

  // fsm
  val state_idle :: state_req :: state_wait_resp :: state_wait_ready :: Nil = Enum(4)
  val state = RegInit(state_idle)
  val level = RegInit(0.U(2.W)) // 0/1/2
168
  val latch = Reg(new PtwResp)
Z
ZhangZifei 已提交
169

Z
ZhangZifei 已提交
170 171 172
  /*
   * tlbl2
   */
Z
ZhangZifei 已提交
173 174 175
  val (tlbHit, tlbHitData) = {
    // tlbl2 is by addr
    // TODO: optimize tlbl2'l2 tag len
176
    val ramData = tlbl2.read(req.vpn(log2Up(TlbL2EntrySize)-1, 0), validOneCycle)
177 178
    val vidx = RegEnable(tlbv(req.vpn(log2Up(TlbL2EntrySize)-1, 0)), validOneCycle)
    (ramData.hit(req.vpn) && vidx, ramData) // TODO: optimize tag
Z
ZhangZifei 已提交
179 180 181
    // TODO: add exception and refill
  }

182 183
  def MakeAddr(ppn: UInt, off: UInt) = {
    require(off.getWidth == 9)
184
    Cat(ppn, off, 0.U(log2Up(XLEN/8).W))(PAddrBits-1, 0)
185 186 187 188
  }

  def getVpnn(vpn: UInt, idx: Int) = {
    vpn(vpnnLen*(idx+1)-1, vpnnLen*idx)
Z
ZhangZifei 已提交
189 190
  }

Z
ZhangZifei 已提交
191 192 193
  /*
   * ptwl1
   */
194
  val l1addr = MakeAddr(satp.ppn, getVpnn(req.vpn, 2))
195 196
  val (l1Hit, l1HitData) = { // TODO: add excp
    // 16 terms may casue long latency, so divide it into 2 stage, like l2tlb
197
    val hitVecT = ptwl1.zipWithIndex.map{case (a,b) => a.hit(l1addr) && l1v(b) }
198
    val hitVec  = hitVecT.map(RegEnable(_, validOneCycle)) // TODO: could have useless init value
199 200 201
    val hitData = ParallelMux(hitVec zip ptwl1)
    val hit     = ParallelOR(hitVec).asBool
    (hit, hitData)
Z
ZhangZifei 已提交
202 203
  }

Z
ZhangZifei 已提交
204 205 206
  /*
   * ptwl2
   */
207
  val l1MemBack = mem.resp.fire() && state===state_wait_resp && level===0.U
208
  val l1Res = Mux(l1Hit, l1HitData.ppn, RegEnable(memPte.ppn, l1MemBack))
209 210
  val l2addr = MakeAddr(l1Res, getVpnn(req.vpn, 1))
  val (l2Hit, l2HitData) = { // TODO: add excp
211 212 213 214
    val readRam = (l1Hit && level===0.U && state===state_req) || (mem.resp.fire() && state===state_wait_resp && level===0.U)
    val ridx = l2addr(log2Up(PtwL2EntrySize)-1+log2Up(XLEN/8), log2Up(XLEN/8))
    val ramData = ptwl2.read(ridx, readRam)
    val vidx = RegEnable(l2v(ridx), readRam)
215
    (ramData.hit(l2addr), ramData) // TODO: optimize tag
Z
ZhangZifei 已提交
216 217
  }

Z
ZhangZifei 已提交
218 219
  /* ptwl3
   * ptwl3 has not cache
220 221 222
   * ptwl3 may be functional conflict with l2-tlb
   * if l2-tlb does not hit, ptwl3 would not hit (mostly)
   */
223
  val l2MemBack = mem.resp.fire() && state===state_wait_resp && level===1.U
224
  val l2Res = Mux(l2Hit, l2HitData.ppn, RegEnable(memPte.ppn, l1MemBack))
225 226
  val l3addr = MakeAddr(l2Res, getVpnn(req.vpn, 0))

Z
ZhangZifei 已提交
227 228 229
  /*
   * fsm
   */
Z
ZhangZifei 已提交
230 231
  assert(!(level===3.U))
  assert(!(tlbHit && (mem.req.valid || state===state_wait_resp))) // when tlb hit, should not req/resp.valid
Z
ZhangZifei 已提交
232 233 234 235

  switch (state) {
    is (state_idle) {
      when (valid) {
Z
ZhangZifei 已提交
236 237
        state := state_req
        level := 0.U
Z
ZhangZifei 已提交
238 239 240
      }
    }

Z
ZhangZifei 已提交
241
    is (state_req) {
Z
ZhangZifei 已提交
242
      when (tlbHit) {
243 244 245 246 247
        when (resp(arbChosen).ready) {
          state := state_idle
        }.otherwise {
          state := state_wait_ready
        }
Z
ZhangZifei 已提交
248
      }.elsewhen (l1Hit && level===0.U || l2Hit && level===1.U) {
249
        level := level + 1.U // TODO: consider superpage
250
      }.elsewhen (mem.req.ready) {
Z
ZhangZifei 已提交
251 252
        state := state_wait_resp
        assert(!(level === 3.U)) // NOTE: pte is not found after 3 layers(software system is wrong)
Z
ZhangZifei 已提交
253 254 255
      }
    }

Z
ZhangZifei 已提交
256
    is (state_wait_resp) {
Z
ZhangZifei 已提交
257
      when (mem.resp.fire()) {
Z
ZhangZifei 已提交
258 259 260 261 262 263 264 265 266 267 268 269
        when (memPte.isLeaf() || memPte.isPf()) {
          when (resp(arbChosen).ready) {
            state := state_idle
          }.otherwise {
            state := state_wait_ready
            latch.entry := new TlbEntry().genTlbEntry(memRdata, level, req.vpn)
            latch.pf := memPte.isPf()
          }
        }.otherwise {
          state := state_req
          level := level + 1.U
        }
Z
ZhangZifei 已提交
270 271 272
      }
    }

Z
ZhangZifei 已提交
273 274
    is (state_wait_ready) {
      when (resp(arbChosen).ready) {
Z
ZhangZifei 已提交
275 276 277 278 279
        state := state_idle
      }
    }
  }

Z
ZhangZifei 已提交
280 281 282
  /*
   * mem
   */
283
  mem.req.valid := state === state_req && 
284
                      ((level===0.U && !tlbHit && !l1Hit) ||
285
                      (level===1.U && !l2Hit) ||
286
                      (level===2.U))
287 288
  mem.req.bits.cmd := M_XRD
  mem.req.bits.addr := Mux(level===0.U, l1addr/*when l1Hit, DontCare, when l1miss, l1addr*/,
Z
ZhangZifei 已提交
289
           Mux(level===1.U, Mux(l2Hit, l3addr, l2addr)/*when l2Hit, l3addr, when l2miss, l2addr*/,
290 291 292 293 294 295
           l3addr))
  mem.req.bits.data := DontCare
  mem.req.bits.mask := VecInit(Fill(mem.req.bits.mask.getWidth, true.B)).asUInt
  mem.req.bits.meta := DontCare // TODO: check it
  mem.resp.ready := true.B // TODO: mem.resp.ready := state===state_wait_resp
  assert(!mem.resp.valid || state===state_wait_resp, "mem.resp.valid:%d state:%d", mem.resp.valid, state)
296
  mem.s1_kill := false.B // NOTE: shoud not use it. for ptw will change to TL later
Z
ZhangZifei 已提交
297

Z
ZhangZifei 已提交
298 299 300
  /*
   * resp
   */
Z
ZhangZifei 已提交
301
  val ptwFinish = (state===state_req && tlbHit && level===0.U) || ((memPte.isLeaf() || memPte.isPf()) && mem.resp.fire()) || state===state_wait_ready
Z
ZhangZifei 已提交
302
  for(i <- 0 until PtwWidth) {
Z
ZhangZifei 已提交
303
    resp(i).valid := valid && arbChosen===i.U && ptwFinish // TODO: add resp valid logic
304 305
    resp(i).bits.entry := Mux(tlbHit, tlbHitData,
      Mux(state===state_wait_ready, latch.entry, new TlbEntry().genTlbEntry(memRdata, level, req.vpn)))
Z
ZhangZifei 已提交
306
    resp(i).bits.idx := req.idx
307 308
    resp(i).bits.pf  := Mux(tlbHit, false.B, Mux(state===state_wait_ready, latch.pf, memPte.isPf())) 
    // TODO: the pf must not be correct, check it
Z
ZhangZifei 已提交
309
  }
Z
ZhangZifei 已提交
310

Z
ZhangZifei 已提交
311 312 313 314
  /* sfence
   * for ram is syncReadMem, so could not flush conditionally
   * l3 may be conflict with l2tlb??, may be we could combine l2-tlb with l3-ptw
   */
Z
ZhangZifei 已提交
315 316 317 318
  when (sfence.valid) {
    tlbv := 0.U
    l1v := 0.U
    l2v := 0.U
319 320
  }

Z
ZhangZifei 已提交
321 322 323
  /*
   * refill
   */
Z
ZhangZifei 已提交
324 325
  assert(!mem.resp.fire() || state===state_wait_resp)
  when (mem.resp.fire() && !memPte.isPf()) {
326
    when (state===state_wait_resp && level===0.U && !memPte.isPf) {
Z
ZhangZifei 已提交
327
      val refillIdx = LFSR64()(log2Up(PtwL1EntrySize)-1,0) // TODO: may be LRU
328
      ptwl1(refillIdx).refill(l1addr, memRdata)
329
      l1v := l1v | UIntToOH(refillIdx)
330
    }
331
    when (state===state_wait_resp && level===1.U && !memPte.isPf) {
Z
ZhangZifei 已提交
332
      val l2addrStore = RegEnable(l2addr, mem.req.fire() && state===state_req && level===1.U)
Z
ZhangZifei 已提交
333
      val refillIdx = getVpnn(req.vpn, 1)(log2Up(PtwL2EntrySize)-1, 0)
334
      ptwl2.write(refillIdx, new PtwEntry(tagLen2).genPtwEntry(l2addrStore, memRdata))
335
      l2v := l2v | UIntToOH(refillIdx)
336
    }
337
    when (state===state_wait_resp && memPte.isLeaf() && !memPte.isPf) {
Z
ZhangZifei 已提交
338
      val refillIdx = getVpnn(req.vpn, 0)(log2Up(TlbL2EntrySize)-1, 0)
339
      tlbl2.write(refillIdx, new TlbEntry().genTlbEntry(memRdata, level, req.vpn))
340
      tlbv := tlbv | UIntToOH(refillIdx)
341
    }
Z
ZhangZifei 已提交
342
  }
Z
ZhangZifei 已提交
343

Z
ZhangZifei 已提交
344 345 346 347 348 349
  if (!env.FPGAPlatform) {
    ExcitingUtils.addSource(validOneCycle, "perfCntPtwReqCnt", Perf)
    ExcitingUtils.addSource(valid, "perfCntPtwCycleCnt", Perf)
    ExcitingUtils.addSource(valid && tlbHit && state===state_req && level===0.U, "perfCntPtwL2TlbHit", Perf)
  }

Z
ZhangZifei 已提交
350 351 352 353 354 355 356 357
  def PrintFlag(en: Bool, flag: Bool, nameEnable: String, nameDisable: String): Unit = {
    when(flag) {
      XSDebug(false, en, nameEnable)
    }.otherwise {
      XSDebug(false, en, nameDisable)
    }
  }

358
  XSDebug(validOneCycle, "**New Ptw Req from ")
359
  PrintFlag(validOneCycle, arbChosen===0.U, "DTLB**:", "ITLB**:")
360
  XSDebug(false, validOneCycle, p"(v:${validOneCycle} r:${arb.io.out.ready}) vpn:0x${Hexadecimal(req.vpn)} (roq)idx:${req.idx}\n")
361 362
  XSDebug(resp(arbChosen).fire(), "**Ptw Resp to ")
  PrintFlag(resp(arbChosen).fire(), arbChosen===0.U, "DTLB**:\n", "ITLB**\n")
Z
ZhangZifei 已提交
363 364 365 366 367
  XSDebug(resp(arbChosen).fire(), p"(v:${resp(arbChosen).valid} r:${resp(arbChosen).ready}) entry:${resp(arbChosen).bits.entry} (roq)idx:${resp(arbChosen).bits.idx} pf:${resp(arbChosen).bits.pf}\n")

  XSDebug(sfence.valid, p"Sfence: sfence instr here ${sfence.bits}\n")
  XSDebug(valid, p"CSR: ${csr}\n")

368
  XSDebug(valid, p"vpn2:0x${Hexadecimal(getVpnn(req.vpn, 2))} vpn1:0x${Hexadecimal(getVpnn(req.vpn, 1))} vpn0:0x${Hexadecimal(getVpnn(req.vpn, 0))}\n")
369
  XSDebug(valid, p"state:${state} level:${level} tlbHit:${tlbHit} l1addr:0x${Hexadecimal(l1addr)} l1Hit:${l1Hit} l2addr:0x${Hexadecimal(l2addr)} l2Hit:${l2Hit}  l3addr:0x${Hexadecimal(l3addr)} memReq(v:${mem.req.valid} r:${mem.req.ready})\n")
Z
ZhangZifei 已提交
370

371 372
  XSDebug(mem.req.fire(), p"mem req fire addr:0x${Hexadecimal(mem.req.bits.addr)}\n")
  XSDebug(mem.resp.fire(), p"mem resp fire rdata:0x${Hexadecimal(mem.resp.bits.data)} Pte:${memPte}\n")
Z
ZhangZifei 已提交
373
}