From 07490e0f13c8af69acf986b630d125b00abf9bb8 Mon Sep 17 00:00:00 2001 From: Liphen Date: Sat, 13 Jan 2024 17:09:01 +0800 Subject: [PATCH] =?UTF-8?q?=E6=90=AD=E4=BA=86=E4=B8=8Bitlb=E7=9A=84?= =?UTF-8?q?=E6=A1=86=E6=9E=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- chisel/playground/src/CpuConfig.scala | 8 +- .../src/cache/CacheAXIInterface.scala | 2 +- chisel/playground/src/cache/DCache.scala | 9 +- chisel/playground/src/cache/ICache.scala | 8 +- chisel/playground/src/cache/mmu/Tlb.scala | 218 +++++++++++++++--- chisel/playground/src/defines/Bundles.scala | 7 +- .../playground/src/defines/CsrBundles.scala | 16 +- .../playground/src/defines/TlbBundles.scala | 45 +--- .../src/pipeline/execute/fu/Csr.scala | 6 +- chisel/playground/test/src/TestMain.scala | 3 +- 10 files changed, 228 insertions(+), 94 deletions(-) diff --git a/chisel/playground/src/CpuConfig.scala b/chisel/playground/src/CpuConfig.scala index 6288343..103a0d2 100644 --- a/chisel/playground/src/CpuConfig.scala +++ b/chisel/playground/src/CpuConfig.scala @@ -21,7 +21,8 @@ case class CpuConfig( val instFifoDepth: Int = 8, // 指令缓存深度 val mulClockNum: Int = 2, // 乘法器的时钟周期数 val divClockNum: Int = 8, // 除法器的时钟周期数 - val branchPredictor: String = "adaptive" // adaptive, global + val branchPredictor: String = "adaptive", // adaptive, global + val tlbEntries: Int = 16 // TLB的条目数 ) /* BPU 的配置文件 */ @@ -29,11 +30,6 @@ case class BranchPredictorConfig( val bhtDepth: Int = 5, val phtDepth: Int = 6) -/* TLB L2 的配置文件 */ -case class TLBConfig( - nindex: Int = 16, - nway: Int = 2) - case class CacheConfig( cacheType: String = "icache" // icache, dcache ) extends Sv39Const { diff --git a/chisel/playground/src/cache/CacheAXIInterface.scala b/chisel/playground/src/cache/CacheAXIInterface.scala index 15af6a7..1c6e444 100644 --- a/chisel/playground/src/cache/CacheAXIInterface.scala +++ b/chisel/playground/src/cache/CacheAXIInterface.scala @@ -53,8 +53,8 @@ class CacheAXIInterface extends Module { ar_sel_lock := true.B ar_sel_val := ar_sel } - } + io.axi.ar.bits.id := Cat(0.U(3.W), ar_sel) io.axi.ar.bits.addr := Mux(ar_sel, io.dcache.ar.bits.addr, io.icache.ar.bits.addr) io.axi.ar.bits.len := Mux(ar_sel, io.dcache.ar.bits.len, io.icache.ar.bits.len) diff --git a/chisel/playground/src/cache/DCache.scala b/chisel/playground/src/cache/DCache.scala index 17bb9fe..afbe256 100644 --- a/chisel/playground/src/cache/DCache.scala +++ b/chisel/playground/src/cache/DCache.scala @@ -179,7 +179,7 @@ class DCache(cacheConfig: CacheConfig)(implicit cpuConfig: CpuConfig) extends Mo state === s_idle, Mux( io.cpu.en, - (cached_stall || mmio_read_stall || mmio_write_stall || !io.cpu.tlb.l1_hit), + (cached_stall || mmio_read_stall || mmio_write_stall || !io.cpu.tlb.hit), io.cpu.fence_i || fence ), state =/= s_wait @@ -223,7 +223,7 @@ class DCache(cacheConfig: CacheConfig)(implicit cpuConfig: CpuConfig) extends Mo tag_compare_valid(i) := tag(i) === io.cpu.tlb.ptag && // tag相同 valid(replace_index)(i) && // cache行有效位为真 - io.cpu.tlb.l1_hit // 页表有效 + io.cpu.tlb.hit // 页表有效 replace_wstrb(j)(i) := Mux( tag_compare_valid(i) && io.cpu.en && io.cpu.wen.orR && !io.cpu.tlb.uncached && state === s_idle, @@ -290,7 +290,7 @@ class DCache(cacheConfig: CacheConfig)(implicit cpuConfig: CpuConfig) extends Mo when(io.cpu.en) { when(addr_err) { acc_err := true.B - }.elsewhen(!io.cpu.tlb.l1_hit) { + }.elsewhen(!io.cpu.tlb.hit) { state := s_tlb_refill }.elsewhen(io.cpu.tlb.uncached) { when(io.cpu.wen.orR) { @@ -482,6 +482,9 @@ class DCache(cacheConfig: CacheConfig)(implicit cpuConfig: CpuConfig) extends Mo state := s_idle } } + is(s_tlb_refill) { + // TODO + } } println("----------------------------------------") diff --git a/chisel/playground/src/cache/ICache.scala b/chisel/playground/src/cache/ICache.scala index 51b65f8..d1591a6 100644 --- a/chisel/playground/src/cache/ICache.scala +++ b/chisel/playground/src/cache/ICache.scala @@ -109,7 +109,7 @@ class ICache(cacheConfig: CacheConfig)(implicit cpuConfig: CpuConfig) extends Mo // * cache hit * // val tag_compare_valid = VecInit(Seq.tabulate(nway)(i => tag(i) === io.cpu.tlb.ptag && valid(i)(replace_index))) val cache_hit = tag_compare_valid.contains(true.B) - val cache_hit_available = cache_hit && io.cpu.tlb.l1_hit && !io.cpu.tlb.uncached + val cache_hit_available = cache_hit && io.cpu.tlb.hit && !io.cpu.tlb.uncached val select_way = tag_compare_valid(1) // 1路命中时值为1,0路命中时值为0 //TODO:支持更多路数 // 将一个 bank 中的指令分成 instFetchNum 份,每份 INST_WID bit @@ -213,7 +213,7 @@ class ICache(cacheConfig: CacheConfig)(implicit cpuConfig: CpuConfig) extends Mo state := s_wait rdata_in_wait(0).inst := 0.U rdata_in_wait(0).valid := true.B - }.elsewhen(!io.cpu.tlb.l1_hit) { + }.elsewhen(!io.cpu.tlb.hit) { state := s_tlb_refill }.elsewhen(io.cpu.tlb.uncached) { state := s_uncached @@ -293,7 +293,9 @@ class ICache(cacheConfig: CacheConfig)(implicit cpuConfig: CpuConfig) extends Mo state := s_idle } } - is(s_tlb_refill) {} + is(s_tlb_refill) { + // TODO: + } } // * fence * // diff --git a/chisel/playground/src/cache/mmu/Tlb.scala b/chisel/playground/src/cache/mmu/Tlb.scala index 893ea5a..919161d 100644 --- a/chisel/playground/src/cache/mmu/Tlb.scala +++ b/chisel/playground/src/cache/mmu/Tlb.scala @@ -6,50 +6,216 @@ import cpu.defines._ import cpu.defines.Const._ import cpu.CacheConfig import cpu.pipeline.execute.CsrTlb +import cpu.CpuConfig -class Tlb_ICache extends Bundle { - val cacheConfig = CacheConfig("icache") - val addr = Input(UInt(XLEN.W)) +class Tlb_Cache extends Bundle with Sv39Const { + val addr = Input(UInt(XLEN.W)) + val complete_single_request = Input(Bool()) - val uncached = Output(Bool()) - val l1_hit = Output(Bool()) - val ptag = Output(UInt(cacheConfig.tagWidth.W)) - val paddr = Output(UInt(PADDR_WID.W)) + val uncached = Output(Bool()) + val hit = Output(Bool()) + val ptag = Output(UInt(cacheTagLen.W)) + val paddr = Output(UInt(PADDR_WID.W)) + val access_fault = Output(Bool()) + val page_fault = Output(Bool()) } -class Tlb_DCache extends Bundle { - val cacheConfig = CacheConfig("dcache") - val addr = Input(UInt(XLEN.W)) - - val uncached = Output(Bool()) - val l1_hit = Output(Bool()) - val ptag = Output(UInt(cacheConfig.tagWidth.W)) - val paddr = Output(UInt(PADDR_WID.W)) +class Tlb_Ptw extends Bundle with Sv39Const { + val vpn = Decoupled(UInt(vpnLen.W)) + val pte = Flipped(Decoupled(new Bundle { + val access_fault = Bool() + val page_fault = Bool() + val entry = pteBundle + val addr = UInt(PADDR_WID.W) + })) } class Tlb extends Module with HasTlbConst with HasCSRConst { val io = IO(new Bundle { - val icache = new Tlb_ICache() - val dcache = new Tlb_DCache() + val icache = new Tlb_Cache() + val dcache = new Tlb_Cache() val csr = Flipped(new CsrTlb()) + val ptw = new Tlb_Ptw() + val fence_vma = Input(new Bundle { + val src1 = UInt(XLEN.W) + val src2 = UInt(XLEN.W) + }) }) - val satp = WireInit(io.csr.satp) - val mode = WireInit(io.csr.mode) + val satp = io.csr.satp.asTypeOf(satpBundle) + val mstatus = io.csr.mstatus.asTypeOf(new Mstatus) + val mode = io.csr.mode + // 当SUM=0时,S模式内存访问U模式可访问的页面(U=1)将出现故障。 + // 当SUM=1时,这些访问是允许的。当基于页面的虚拟内存不生效时,SUM无效。 + // 请注意,虽然SUM通常在不在S模式下执行时被忽略,但当MPRV=1和MPP=S时,SUM有效。 + val sum_valid = (mode === ModeS) || mstatus.mprv && mstatus.mpp === ModeS + val sum = mstatus.sum + // 当MXR=0时,只有标记为可读的页面(R=1)的加载才会成功。 + // 当MXR=1时,标记为可读或可执行的页面(R=1或X=1)的加载才会成功。 + // 当基于页面的虚拟内存无效时,MXR无效。 + val mxr = mstatus.mxr - val vm_enabled = (satp.asTypeOf(satpBundle).mode === 8.U) && (mode < ModeM) - val itlb = RegInit(0.U.asTypeOf(tlbBundle)) + // 只有当satp.mode为8且当前模式低于M模式时,才启用虚拟内存 + val vm_enabled = (satp.mode === 8.U) && (mode < ModeM) - val l1_hit = itlb.asid === satp.asTypeOf(satpBundle).asid + val itlb = RegInit(0.U.asTypeOf(tlbBundle)) + val dtlb = RegInit(0.U.asTypeOf(tlbBundle)) + val tlbl2 = RegInit(VecInit(Seq.fill(cpuConfig.tlbEntries)(0.U.asTypeOf(tlbBundle)))) + + val ivpn = io.icache.addr(VADDR_WID - 1, pageOffsetLen) + val dvpn = io.dcache.addr(VADDR_WID - 1, pageOffsetLen) + + // 当(VPN一致)且(ASID一致或PTE.G为1时)且(PTE.V为1)时,TLB命中 + val itlbl1_hit = itlb.vpn === ivpn && + (itlb.asid === satp.asid || itlb.flag.g) && + itlb.flag.v + val dtlbl1_hit = dtlb.vpn === dvpn && + (dtlb.asid === satp.asid || dtlb.flag.g) && + dtlb.flag.v + + val il2_hit_vec = VecInit( + tlbl2.map(tlb => + tlb.vpn === ivpn && + (tlb.asid === satp.asid || tlb.flag.g) && + tlb.flag.v + ) + ) + val dl2_hit_vec = VecInit( + tlbl2.map(tlb => + tlb.vpn === dvpn && + (tlb.asid === satp.asid || tlb.flag.g) && + tlb.flag.v + ) + ) + + val search_l1 :: search_l2 :: search_pte :: search_fault :: Nil = Enum(4) + val immu_state = RegInit(search_l1) + + // 使用随机的方法替换TLB条目 + val replace_index = new Counter(cpuConfig.tlbEntries) + + val ipage_fault = RegInit(false.B) + val dpage_fault = RegInit(false.B) + val iaccess_fault = RegInit(false.B) + val daccess_fault = RegInit(false.B) + + io.icache.hit := false.B + io.dcache.hit := false.B + io.icache.access_fault := iaccess_fault + io.dcache.access_fault := daccess_fault + io.icache.page_fault := ipage_fault + io.dcache.page_fault := dpage_fault + + io.ptw.vpn.valid := false.B + io.ptw.vpn.bits := DontCare + io.ptw.pte.ready := true.B + + // ptw的请求标志,0位为指令tlb请求,1位为数据tlb请求 + val req_ptw = WireInit(VecInit(Seq.fill(2)(false.B))) + + val ar_sel_lock = RegInit(false.B) + val ar_sel_val = RegInit(false.B) + // 我们默认优先发送数据tlb的请求 + val ar_sel = Mux(ar_sel_lock, ar_sel_val, !req_ptw(0) && req_ptw(1)) + + when(io.ptw.vpn.valid) { + when(io.ptw.vpn.ready) { + ar_sel_lock := false.B + }.otherwise { + ar_sel_lock := true.B + ar_sel_val := ar_sel + } + } + + // 指令虚实地址转换 + switch(immu_state) { + is(search_l1) { + // TODO:在这里实现访问tlb的pma和pmp权限检查 + ipage_fault := false.B + iaccess_fault := false.B + when(!vm_enabled) { + io.icache.hit := true.B + }.elsewhen(itlbl1_hit) { + // 在这里进行取指需要的所有的权限检查 + // 0. X位检查,只有可执行的页面才能取指 + // 1. M模式,不可能到这里,因为vm_enabled为false + // 2. S模式,如果U位为1,需要检查SUM + // 3. U模式,必须保证U位为1 + io.icache.hit := false.B // 只有权限检查通过后可以置为true + when(!itlb.flag.x) { + ipage_fault := true.B + immu_state := search_fault + }.elsewhen(mode === ModeS) { + when(itlb.flag.u && sum === 0.U) { + ipage_fault := true.B + immu_state := search_fault + }.otherwise { + io.icache.hit := true.B + } + }.elsewhen(mode === ModeU) { + when(!itlb.flag.u) { + ipage_fault := true.B + immu_state := search_fault + }.otherwise { + io.icache.hit := true.B + } + } + }.otherwise { + immu_state := search_l2 + } + } + is(search_l2) { + when(il2_hit_vec.asUInt.orR) { + immu_state := search_l1 + itlb := tlbl2(il2_hit_vec.indexWhere(_ === true.B)) + }.otherwise { + req_ptw(0) := true.B + when(ar_sel === 0.U) { + io.ptw.vpn.valid := true.B + io.ptw.vpn.bits := ivpn + immu_state := search_pte + } + } + } + is(search_pte) { + io.ptw.vpn.valid := true.B + io.ptw.vpn.bits := ivpn + when(io.ptw.pte.valid) { + when(io.ptw.pte.bits.access_fault) { + io.icache.access_fault := true.B + immu_state := search_fault + }.elsewhen(io.ptw.pte.bits.page_fault) { + ipage_fault := true.B + immu_state := search_fault + }.otherwise { + // 在内存中找寻到了页表,将其写入TLB + val replace_entry = Wire(tlbBundle) + replace_entry.vpn := ivpn + replace_entry.asid := satp.asid + replace_entry.flag := io.ptw.pte.bits.entry.flag + replace_entry.ppn := io.ptw.pte.bits.entry.ppn + replace_entry.pteaddr := io.ptw.pte.bits.addr + tlbl2(replace_index.value) := replace_entry + itlb := replace_entry + immu_state := search_l1 + } + } + } + is(search_fault) { + when(io.icache.complete_single_request) { + ipage_fault := false.B + iaccess_fault := false.B + immu_state := search_l1 + } + } + } io.icache.uncached := AddressSpace.isMMIO(io.icache.addr) - io.icache.l1_hit := !vm_enabled - io.icache.ptag := Mux(vm_enabled, DontCare, io.icache.addr(PADDR_WID - 1, pageOffsetLen)) + io.icache.ptag := Mux(vm_enabled, itlb.ppn, io.icache.addr(PADDR_WID - 1, pageOffsetLen)) io.icache.paddr := Cat(io.icache.ptag, io.icache.addr(pageOffsetLen - 1, 0)) io.dcache.uncached := AddressSpace.isMMIO(io.dcache.addr) - io.dcache.l1_hit := !vm_enabled - io.dcache.ptag := Mux(vm_enabled, DontCare, io.dcache.addr(PADDR_WID - 1, pageOffsetLen)) + io.dcache.ptag := Mux(vm_enabled, dtlb.ppn, io.dcache.addr(PADDR_WID - 1, pageOffsetLen)) io.dcache.paddr := Cat(io.dcache.ptag, io.dcache.addr(pageOffsetLen - 1, 0)) } diff --git a/chisel/playground/src/defines/Bundles.scala b/chisel/playground/src/defines/Bundles.scala index 280fc6d..a83d99d 100644 --- a/chisel/playground/src/defines/Bundles.scala +++ b/chisel/playground/src/defines/Bundles.scala @@ -5,8 +5,7 @@ import chisel3.util._ import cpu.defines._ import cpu.defines.Const._ import cpu.CpuConfig -import icache.mmu.Tlb_ICache -import icache.mmu.Tlb_DCache +import icache.mmu.Tlb_Cache class ExceptionInfo extends Bundle { val exception = Vec(EXC_WID, Bool()) @@ -122,7 +121,7 @@ class Cache_ICache(implicit val cpuConfig: CpuConfig) extends Bundle { val icache_stall = Input(Bool()) // icache_stall // tlb - val tlb = new Tlb_ICache() + val tlb = new Tlb_Cache() } // cpu to dcache @@ -141,7 +140,7 @@ class Cache_DCache extends Bundle { val acc_err = Input(Bool()) val dcache_ready = Input(Bool()) - val tlb = new Tlb_DCache() + val tlb = new Tlb_Cache() } // axi diff --git a/chisel/playground/src/defines/CsrBundles.scala b/chisel/playground/src/defines/CsrBundles.scala index 62ee752..d324025 100644 --- a/chisel/playground/src/defines/CsrBundles.scala +++ b/chisel/playground/src/defines/CsrBundles.scala @@ -5,24 +5,24 @@ import chisel3.util._ import cpu.defines.Const._ class Mstatus extends Bundle { - val sd = Output(UInt(1.W)) + val sd = Output(Bool()) val pad1 = if (XLEN == 64) Output(UInt(27.W)) else null val sxl = if (XLEN == 64) Output(UInt(2.W)) else null val uxl = if (XLEN == 64) Output(UInt(2.W)) else null val pad0 = if (XLEN == 64) Output(UInt(9.W)) else Output(UInt(8.W)) - val tsr = Output(UInt(1.W)) - val tw = Output(UInt(1.W)) - val tvm = Output(UInt(1.W)) - val mxr = Output(UInt(1.W)) - val sum = Output(UInt(1.W)) - val mprv = Output(UInt(1.W)) + val tsr = Output(Bool()) + val tw = Output(Bool()) + val tvm = Output(Bool()) + val mxr = Output(Bool()) + val sum = Output(Bool()) + val mprv = Output(Bool()) val xs = Output(UInt(2.W)) val fs = Output(UInt(2.W)) val mpp = Output(UInt(2.W)) val hpp = Output(UInt(2.W)) - val spp = Output(UInt(1.W)) + val spp = Output(Bool()) val pie = new Priv val ie = new Priv } diff --git a/chisel/playground/src/defines/TlbBundles.scala b/chisel/playground/src/defines/TlbBundles.scala index 3f0edb7..404cbf4 100644 --- a/chisel/playground/src/defines/TlbBundles.scala +++ b/chisel/playground/src/defines/TlbBundles.scala @@ -4,7 +4,7 @@ import chisel3._ import chisel3.util._ import cpu.defines.Const._ import cpu.CacheConfig -import cpu.TLBConfig +import cpu.CpuConfig trait Sv39Const extends CoreParameter { val PAddrBits = PADDR_WID // 32 @@ -28,6 +28,9 @@ trait Sv39Const extends CoreParameter { val satpResLen = XLEN - ppnLen - satpModeLen - asidLen val pteResLen = XLEN - ppnLen - 2 - flagLen + val cacheTagLen = PADDR_WID - pageOffsetLen + require(ppnLen == cacheTagLen) + def vaBundle = new Bundle { val vpn2 = UInt(vpn2Len.W) val vpn1 = UInt(vpn1Len.W) @@ -112,50 +115,12 @@ trait Sv39Const extends CoreParameter { } trait HasTlbConst extends Sv39Const { - val tlbConfig = TLBConfig() - - val maskLen = vpn0Len + vpn1Len // 18 - val metaLen = vpnLen + asidLen + maskLen + flagLen // 27 + 16 + 18 + 8 = 69, is asid necessary - val dataLen = ppnLen + PAddrBits // 20 + 32 = 52 - val tlbLen = metaLen + dataLen - val nway = tlbConfig.nway - val nindex = tlbConfig.nindex - val indexWid = log2Up(nindex) - val tagWid = vpnLen - indexWid - - def vaddrTlbBundle = new Bundle { - val tag = UInt(tagWid.W) - val index = UInt(indexWid.W) - val off = UInt(pageOffsetLen.W) - } - - def metaBundle = new Bundle { - val vpn = UInt(vpnLen.W) - val asid = UInt(asidLen.W) - val mask = UInt(maskLen.W) // to support super page - val flag = UInt(flagLen.W) - } - - def dataBundle = new Bundle { - val ppn = UInt(ppnLen.W) - val pteaddr = UInt(PAddrBits.W) // pte addr, used to write back pte when flag changes (flag.d, flag.v) - } - def tlbBundle = new Bundle { val vpn = UInt(vpnLen.W) val asid = UInt(asidLen.W) - val mask = UInt(maskLen.W) - val flag = UInt(flagLen.W) + val flag = flagBundle val ppn = UInt(ppnLen.W) val pteaddr = UInt(PAddrBits.W) } - def tlbBundle2 = new Bundle { - val meta = UInt(metaLen.W) - val data = UInt(dataLen.W) - } - - def getIndex(vaddr: UInt): UInt = { - vaddr.asTypeOf(vaddrTlbBundle).index - } } diff --git a/chisel/playground/src/pipeline/execute/fu/Csr.scala b/chisel/playground/src/pipeline/execute/fu/Csr.scala index 62a67dc..aea621f 100644 --- a/chisel/playground/src/pipeline/execute/fu/Csr.scala +++ b/chisel/playground/src/pipeline/execute/fu/Csr.scala @@ -48,8 +48,9 @@ class CsrDecodeUnit extends Bundle { } class CsrTlb extends Bundle { - val satp = Output(UInt(XLEN.W)) - val mode = Output(Priv()) + val satp = Output(UInt(XLEN.W)) + val mstatus = Output(UInt(XLEN.W)) + val mode = Output(Priv()) } class Csr(implicit val cpuConfig: CpuConfig) extends Module with HasCSRConst { @@ -415,6 +416,7 @@ class Csr(implicit val cpuConfig: CpuConfig) extends Module with HasCSRConst { io.tlb.mode := mode io.tlb.satp := satp + io.tlb.mstatus := mstatus io.decodeUnit.mode := mode io.executeUnit.out.ex := io.executeUnit.in.ex io.executeUnit.out.ex.exception(illegalInstr) := diff --git a/chisel/playground/test/src/TestMain.scala b/chisel/playground/test/src/TestMain.scala index 08a0b47..88b43bf 100644 --- a/chisel/playground/test/src/TestMain.scala +++ b/chisel/playground/test/src/TestMain.scala @@ -3,11 +3,12 @@ import circt.stage._ import cpu.pipeline.execute.Csr import cache.DCache +import icache.mmu.Tlb object TestMain extends App { implicit val cpuConfig = new CpuConfig() implicit val dCacheConfig = CacheConfig(cacheType = "dcache") - def top = new DCache(dCacheConfig) + def top = new Tlb val useMFC = false // use MLIR-based firrtl compiler val generator = Seq(chisel3.stage.ChiselGeneratorAnnotation(() => top)) if (useMFC) {