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

import chisel3._
import chisel3.util._
import xiangshan._
import utils._
import chisel3.util.experimental.BoringUtils
import xiangshan.backend.decode.XSTrap
import xiangshan.mem._
import xiangshan.mem.pipeline._
import bus.simplebus._

13
trait HasPtwConst extends HasTlbConst{
Z
ZhangZifei 已提交
14 15 16 17 18 19
  val PtwWidth = 2
}

abstract class PtwBundle extends XSBundle with HasPtwConst
abstract class PtwModule extends XSModule with HasPtwConst

Z
ZhangZifei 已提交
20 21 22 23 24
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 已提交
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
    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 已提交
41
  }
Z
ZhangZifei 已提交
42 43 44 45

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

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

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

  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) = {
66
    val e = Wire(new PtwEntry(tagLen))
Z
ZhangZifei 已提交
67 68 69 70 71
    e.tag := addr(PAddrBits-1, PAddrBits-tagLen)
    e.ppn := pte.asTypeOf(pteBundle).ppn
    e.perm := pte.asTypeOf(pteBundle).perm
    e
  }
72 73

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

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

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

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

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

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

Z
ZhangZifei 已提交
99
class PtwIO extends PtwBundle {
100
  val tlb = Vec(PtwWidth, Flipped(new TlbPtwIO))
Z
ZhangZifei 已提交
101
  val mem = new SimpleBusUC(addrBits = PAddrBits) // Use Dcache temp
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(io.tlb(0).req.bits.cloneType, PtwWidth))
  arb.io.in <> 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
  
  val valid = ValidHold(arb.io.out.fire(), resp(arbChosen).fire())
Z
ZhangZifei 已提交
134
  val validOneCycle = OneCycleValid(arb.io.out.fire())
135 136 137
  arb.io.out.ready := !valid || resp(arbChosen).fire()

  val mem    = io.mem
138 139 140 141 142 143
  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 已提交
144

145
  val memRdata = mem.resp.bits.rdata
Z
ZhangZifei 已提交
146 147 148 149 150 151 152

  // 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 已提交
153 154
  val tagLen1 = PAddrBits - log2Up(XLEN/8)
  val tagLen2 = PAddrBits - log2Up(XLEN/8) - log2Up(PtwL2EntrySize)
155
  val tlbl2 = SyncReadMem(TlbL2EntrySize, new TlbEntry)
156
  val tlbv  = RegInit(0.U(TlbL2EntrySize.W))
Z
ZhangZifei 已提交
157
  val ptwl1 = Reg(Vec(PtwL1EntrySize, new PtwEntry(tagLen = tagLen1)))
158
  val l1v   = RegInit(0.U(PtwL1EntrySize.W))
Z
ZhangZifei 已提交
159
  val ptwl2 = SyncReadMem(PtwL2EntrySize, new PtwEntry(tagLen = tagLen2)) // NOTE: the Mem could be only single port(r&w)
160 161 162 163 164 165 166
  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
  val latch = Reg(resp(0).bits.cloneType)
Z
ZhangZifei 已提交
167 168 169 170 171

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

178 179
  def MakeAddr(ppn: UInt, off: UInt) = {
    require(off.getWidth == 9)
180
    Cat(ppn, off, 0.U(log2Up(XLEN/8).W))(PAddrBits-1, 0)
181 182 183 184
  }

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

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

198
  // ptwl2
199 200
  val l1MemBack = mem.resp.fire() && state===state_wait_resp && level===0.U
  val l1Res = Mux(l1Hit, l1HitData.ppn, RegEnable(memRdata.asTypeOf(pteBundle).ppn, l1MemBack))
201 202
  val l2addr = MakeAddr(l1Res, getVpnn(req.vpn, 1))
  val (l2Hit, l2HitData) = { // TODO: add excp
203 204 205 206
    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)
207
    (ramData.hit(l2addr), ramData) // TODO: optimize tag
Z
ZhangZifei 已提交
208 209
  }

210 211 212 213 214
  // ptwl3
  /* ptwl3 has not cache
   * ptwl3 may be functional conflict with l2-tlb
   * if l2-tlb does not hit, ptwl3 would not hit (mostly)
   */
215 216
  val l2MemBack = mem.resp.fire() && state===state_wait_resp && level===1.U
  val l2Res = Mux(l2Hit, l2HitData.ppn, RegEnable(memRdata.asTypeOf(pteBundle).ppn, l1MemBack))
217 218
  val l3addr = MakeAddr(l2Res, getVpnn(req.vpn, 0))

Z
ZhangZifei 已提交
219 220 221
  // mem Resp
  val memPte = mem.resp.bits.rdata.asTypeOf(new PteBundle)

Z
ZhangZifei 已提交
222
  // fsm
Z
ZhangZifei 已提交
223 224
  assert(!(level===3.U))
  assert(!(tlbHit && (mem.req.valid || state===state_wait_resp))) // when tlb hit, should not req/resp.valid
Z
ZhangZifei 已提交
225 226 227 228

  switch (state) {
    is (state_idle) {
      when (valid) {
Z
ZhangZifei 已提交
229 230
        state := state_req
        level := 0.U
Z
ZhangZifei 已提交
231 232 233
      }
    }

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

Z
ZhangZifei 已提交
249
    is (state_wait_resp) {
Z
ZhangZifei 已提交
250
      when (mem.resp.fire()) {
Z
ZhangZifei 已提交
251 252 253 254 255 256 257 258 259 260 261 262
        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 已提交
263 264 265
      }
    }

Z
ZhangZifei 已提交
266 267
    is (state_wait_ready) {
      when (resp(arbChosen).ready) {
Z
ZhangZifei 已提交
268 269 270 271 272 273
        state := state_idle
      }
    }
  }

  // mem:
Z
ZhangZifei 已提交
274
  io.mem.req.valid := state === state_req && 
275
                      ((level===0.U && !tlbHit && !l1Hit) ||
276
                      (level===1.U && !l2Hit) ||
277
                      (level===2.U))
278
  io.mem.req.bits.apply(
Z
ZhangZifei 已提交
279 280 281
    addr = Mux(level===0.U, l1addr/*when l1Hit, dontcare, when l1miss, l1addr*/,
           Mux(level===1.U, Mux(l2Hit, l3addr, l2addr)/*when l2Hit, l3addr, when l2miss, l2addr*/,
           l3addr)),
282 283 284 285 286 287
    cmd  = SimpleBusCmd.read,
    size = "b11".U,
    wdata= 0.U,
    wmask= 0.U,
    user = 0.U
  )
288
  io.mem.resp.ready := true.B
289
  assert(!io.mem.resp.valid || state===state_wait_resp, "mem.resp.valid:%d state:%d", io.mem.resp.valid, state)
Z
ZhangZifei 已提交
290

Z
ZhangZifei 已提交
291
  // resp
Z
ZhangZifei 已提交
292
  val ptwFinish = (state===state_req && tlbHit && level===0.U) || ((memPte.isLeaf() || memPte.isPf()) && mem.resp.fire()) || state===state_wait_ready
Z
ZhangZifei 已提交
293
  for(i <- 0 until PtwWidth) {
Z
ZhangZifei 已提交
294
    resp(i).valid := valid && arbChosen===i.U && ptwFinish // TODO: add resp valid logic
295 296
    resp(i).bits.entry := Mux(tlbHit, tlbHitData,
      Mux(state===state_wait_ready, latch.entry, new TlbEntry().genTlbEntry(memRdata, level, req.vpn)))
Z
ZhangZifei 已提交
297 298
    resp(i).bits.idx := req.idx
    resp(i).bits.pf  := Mux(state===state_wait_ready, latch.pf, memPte.isPf())
Z
ZhangZifei 已提交
299
  }
Z
ZhangZifei 已提交
300 301 302 303 304 305 306 307

  // 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
  when (sfence.valid) {
    tlbv := 0.U
    l1v := 0.U
    l2v := 0.U
308 309 310
  }

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

  def PrintFlag(en: Bool, flag: Bool, nameEnable: String, nameDisable: String): Unit = {
    when(flag) {
      XSDebug(false, en, nameEnable)
    }.otherwise {
      XSDebug(false, en, nameDisable)
    }
  }

339
  XSDebug(validOneCycle, "**New Ptw Req from ")
340
  PrintFlag(validOneCycle, arbChosen===0.U, "DTLB**:", "ITLB**:")
341
  XSDebug(false, validOneCycle, p"(v:${validOneCycle} r:${arb.io.out.ready}) vpn:0x${Hexadecimal(req.vpn)} (roq)idx:${req.idx}\n")
342 343
  XSDebug(resp(arbChosen).fire(), "**Ptw Resp to ")
  PrintFlag(resp(arbChosen).fire(), arbChosen===0.U, "DTLB**:\n", "ITLB**\n")
Z
ZhangZifei 已提交
344 345 346 347 348
  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")

349
  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")
350
  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:${io.mem.req.valid} r:${io.mem.req.ready})\n")
Z
ZhangZifei 已提交
351 352 353

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