From 3a3680fb02f0caf1920e9fb54aa830aba1ddd3a5 Mon Sep 17 00:00:00 2001 From: Liphen Date: Sun, 14 Jan 2024 17:20:16 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0ptw=E7=9A=84=E5=A4=A7?= =?UTF-8?q?=E8=87=B4=E6=A1=86=E6=9E=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- chisel/playground/src/cache/DCache.scala | 203 ++++++++++++++++-- chisel/playground/src/cache/mmu/Tlb.scala | 95 ++++---- chisel/playground/src/defines/Bundles.scala | 6 +- .../playground/src/defines/TlbBundles.scala | 22 +- 4 files changed, 261 insertions(+), 65 deletions(-) diff --git a/chisel/playground/src/cache/DCache.scala b/chisel/playground/src/cache/DCache.scala index afbe256..391e62c 100644 --- a/chisel/playground/src/cache/DCache.scala +++ b/chisel/playground/src/cache/DCache.scala @@ -7,6 +7,7 @@ import cpu.CacheConfig import cpu.defines._ import cpu.CpuConfig import cpu.defines.Const._ +import icache.mmu.AccessType /* 整个宽度为PADDR_WID的地址 @@ -50,7 +51,7 @@ class WriteBufferUnit extends Bundle { val size = UInt(AXI_SIZE_WID.W) } -class DCache(cacheConfig: CacheConfig)(implicit cpuConfig: CpuConfig) extends Module { +class DCache(cacheConfig: CacheConfig)(implicit cpuConfig: CpuConfig) extends Module with Sv39Const with HasCSRConst { val nway = cacheConfig.nway val nindex = cacheConfig.nindex val nbank = cacheConfig.nbank @@ -73,10 +74,16 @@ class DCache(cacheConfig: CacheConfig)(implicit cpuConfig: CpuConfig) extends Mo val axi = new DCache_AXIInterface() }) - // * fsm * // + // dcache的状态机 val s_idle :: s_uncached :: s_fence :: s_replace :: s_wait :: s_tlb_refill :: Nil = Enum(6) val state = RegInit(s_idle) + // ptw的状态机 + val s_handshake :: s_send :: s_receive :: s_check :: s_set :: Nil = Enum(5) + val ptw_state = RegInit(s_handshake) + + io.cpu.tlb.ptw.vpn.ready := false.B + // ========================================================== // | tag | index | offset | // | | | bank index | bank offset | @@ -190,7 +197,8 @@ class DCache(cacheConfig: CacheConfig)(implicit cpuConfig: CpuConfig) extends Mo io.cpu.rdata := Mux(state === s_wait, saved_rdata, data(bank_index)(select_way)) - io.cpu.tlb.addr := io.cpu.addr + io.cpu.tlb.addr := io.cpu.addr + io.cpu.tlb.access_type := Mux(io.cpu.en && io.cpu.wen.orR, AccessType.store, AccessType.load) val bank_raddr = Mux(state === s_fence, dirty_index, Mux(use_next_addr, exe_index, replace_index)) val tag_raddr = Mux(state === s_fence, dirty_index, tag_rindex) @@ -334,16 +342,19 @@ class DCache(cacheConfig: CacheConfig)(implicit cpuConfig: CpuConfig) extends Mo } } } - }.elsewhen(io.cpu.fence_i) { - // fence.i 需要将所有脏位为true的行写回 - when(dirty.asUInt.orR) { - when(!writeFifo_busy) { - state := s_fence - fence_data_ready := false.B // bank读数据要两拍 + }.otherwise { + io.cpu.tlb.ptw.vpn.ready := ptw_state === s_handshake + when(io.cpu.fence_i) { + // fence.i 需要将所有脏位为true的行写回 + when(dirty.asUInt.orR) { + when(!writeFifo_busy) { + state := s_fence + fence_data_ready := false.B // bank读数据要两拍 + } + }.otherwise { + // 当所有脏位为fault时,fence.i可以直接完成 + state := s_wait } - }.otherwise { - // 当所有脏位为fault时,fence.i可以直接完成 - state := s_wait } } } @@ -351,7 +362,8 @@ class DCache(cacheConfig: CacheConfig)(implicit cpuConfig: CpuConfig) extends Mo when(arvalid && io.axi.ar.ready) { arvalid := false.B } - when(io.axi.r.valid) { + when(io.axi.r.fire) { + rready := false.B saved_rdata := io.axi.r.bits.data acc_err := io.axi.r.bits.resp =/= RESP_OKEY.U state := s_wait @@ -483,7 +495,170 @@ class DCache(cacheConfig: CacheConfig)(implicit cpuConfig: CpuConfig) extends Mo } } is(s_tlb_refill) { - // TODO + io.cpu.tlb.ptw.vpn.ready := ptw_state === s_handshake + } + } + + // ========================================================== + // 实现页表访问,回填tlb + val satp = io.cpu.tlb.csr.satp.asTypeOf(satpBundle) + val mstatus = io.cpu.tlb.csr.mstatus.asTypeOf(new Mstatus) + val mode = io.cpu.tlb.csr.mode + val sum = mstatus.sum + val mxr = mstatus.mxr + val vpn = io.cpu.tlb.ptw.vpn.bits.asTypeOf(vpnBundle) + val access_type = io.cpu.tlb.access_type + val ppn = RegInit(0.U(ppnLen.W)) + val vpn_index = RegInit(0.U(log2Up(level).W)) // 页表访问的层级 + val pte = RegInit(0.U.asTypeOf(pteBundle)) // 页表项 + + io.cpu.tlb.ptw.pte.valid := false.B + io.cpu.tlb.ptw.pte.bits := DontCare + io.cpu.tlb.ptw.pte.bits.access_fault := false.B + io.cpu.tlb.ptw.pte.bits.page_fault := false.B + require(AXI_DATA_WID == XLEN) // 目前只考虑了AXI_DATA_WID == XLEN的情况 + + def raisePageFault(): Unit = { + io.cpu.tlb.ptw.pte.valid := true.B + io.cpu.tlb.ptw.pte.bits.page_fault := true.B + ptw_state := s_handshake + } + + def modeCheck(): Unit = { + switch(mode) { + is(ModeS) { + when(pte.flag.u && !sum) { + raisePageFault() + }.otherwise { + ptw_state := s_set + } + } + is(ModeU) { + when(!pte.flag.u) { + raisePageFault() + }.otherwise { + ptw_state := s_set + } + } + } + } + + switch(ptw_state) { + is(s_handshake) { + // 页表访问虚地址握手 + when(io.cpu.tlb.ptw.vpn.valid) { + vpn_index := (level - 1).U + ppn := satp.ppn + ptw_state := s_send + } + } + is(s_send) { + arvalid := true.B + val vpnn = Mux1H( + Seq( + (vpn_index === 0.U) -> vpn.vpn0, + (vpn_index === 1.U) -> vpn.vpn1, + (vpn_index === 2.U) -> vpn.vpn2 + ) + ) + ar.addr := paddrApply(ppn, vpnn) + ar.size := log2Ceil(AXI_DATA_WID / 8).U // 一个pte的大小是8字节 + ar.len := 0.U // 读一拍即可 + ptw_state := s_receive + rready := true.B + } + is(s_receive) { + when(io.axi.ar.fire) { + arvalid := false.B + } + when(io.axi.r.fire) { + rready := false.B + val pte_temp = io.axi.r.bits.data.asTypeOf(pteBundle) + when(!pte_temp.flag.v || !pte_temp.flag.r && pte_temp.flag.w) { + raisePageFault() + }.otherwise { + when(pte_temp.flag.r || pte_temp.flag.x) { + // 找到了叶子页 + pte := pte_temp + ptw_state := s_check + }.otherwise { + // 该pte指向下一个页表 + vpn_index := vpn_index - 1.U + when(vpn_index - 1.U < 0.U) { + raisePageFault() + }.otherwise { + ppn := pte_temp.ppn + ptw_state := s_send + } + } + } + } + } + is(s_check) { + // 检查权限 + switch(access_type) { + is(AccessType.load) { + when(mxr) { + when(!pte.flag.r && !pte.flag.x) { + raisePageFault() + }.otherwise { + modeCheck() + } + }.otherwise { + when(!pte.flag.r) { + raisePageFault() + }.otherwise { + modeCheck() + } + } + } + is(AccessType.store) { + when(!pte.flag.w) { + raisePageFault() + }.otherwise { + modeCheck() + } + } + is(AccessType.fetch) { + when(!pte.flag.x) { + raisePageFault() + }.otherwise { + modeCheck() + } + } + } + } + is(s_set) { + when( + vpn_index > 0.U && ( + vpn_index === 1.U && pte.ppn(0) || + vpn_index === 2.U && pte.ppn(1, 0).orR + ) + ) { + raisePageFault() + }.elsewhen(!pte.flag.a || access_type === AccessType.store && !pte.flag.d) { + raisePageFault() // 使用软件的方式设置脏位以及访问位 + }.otherwise { + // 翻译成功 + io.cpu.tlb.ptw.pte.valid := true.B + io.cpu.tlb.ptw.pte.bits.addr := ar.addr + io.cpu.tlb.ptw.pte.bits.entry := pte + val ppn_set = WireInit(ppnBundle) + when(vpn_index === 2.U) { + ppn_set.ppn2 := pte.ppn.asTypeOf(ppnBundle).ppn2 + ppn_set.ppn1 := vpn.vpn1 + ppn_set.ppn0 := vpn.vpn0 + }.elsewhen(vpn_index === 1.U) { + ppn_set.ppn2 := pte.ppn.asTypeOf(ppnBundle).ppn2 + ppn_set.ppn1 := pte.ppn.asTypeOf(ppnBundle).ppn1 + ppn_set.ppn0 := vpn.vpn0 + }.otherwise { + ppn_set := pte.ppn.asTypeOf(ppnBundle) + } + io.cpu.tlb.ptw.pte.bits.entry.ppn := ppn_set.asUInt + + ptw_state := s_handshake + } } } diff --git a/chisel/playground/src/cache/mmu/Tlb.scala b/chisel/playground/src/cache/mmu/Tlb.scala index 919161d..cee1a7b 100644 --- a/chisel/playground/src/cache/mmu/Tlb.scala +++ b/chisel/playground/src/cache/mmu/Tlb.scala @@ -8,7 +8,25 @@ import cpu.CacheConfig import cpu.pipeline.execute.CsrTlb import cpu.CpuConfig -class Tlb_Cache extends Bundle with Sv39Const { +object AccessType { + def apply() = UInt(2.W) + def fetch = "b00".U + def load = "b01".U + def store = "b10".U +} + +class Tlb_Ptw extends Bundle with Sv39Const { + val vpn = Decoupled(UInt(vpnLen.W)) + val access_type = Output(AccessType()) + 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_ICache extends Bundle with Sv39Const { val addr = Input(UInt(XLEN.W)) val complete_single_request = Input(Bool()) @@ -20,22 +38,17 @@ class Tlb_Cache extends Bundle with Sv39Const { val page_fault = Output(Bool()) } -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_DCache extends Tlb_ICache { + val ptw = new Tlb_Ptw() + val access_type = Input(AccessType()) + val csr = new CsrTlb() } class Tlb extends Module with HasTlbConst with HasCSRConst { val io = IO(new Bundle { - val icache = new Tlb_Cache() - val dcache = new Tlb_Cache() + val icache = new Tlb_ICache() + val dcache = new Tlb_DCache() 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) @@ -93,23 +106,13 @@ class Tlb extends Module with HasTlbConst with HasCSRConst { // 使用随机的方法替换TLB条目 val replace_index = new Counter(cpuConfig.tlbEntries) + replace_index.inc() 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))) @@ -118,8 +121,8 @@ class Tlb extends Module with HasTlbConst with HasCSRConst { // 我们默认优先发送数据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) { + when(io.dcache.ptw.vpn.valid) { + when(io.dcache.ptw.vpn.ready) { ar_sel_lock := false.B }.otherwise { ar_sel_lock := true.B @@ -127,6 +130,20 @@ class Tlb extends Module with HasTlbConst with HasCSRConst { } } + 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 + + // 将ptw模块集成到dcache中,ptw通过dcache的axi进行内存访问 + io.dcache.ptw.vpn.valid := false.B + io.dcache.ptw.access_type := Mux(ar_sel === 0.U, AccessType.fetch, io.dcache.access_type) + io.dcache.ptw.vpn.bits := Mux(ar_sel === 0.U, ivpn, dvpn) + io.dcache.ptw.pte.ready := true.B // 恒为true + io.dcache.csr <> io.csr + // 指令虚实地址转换 switch(immu_state) { is(search_l1) { @@ -167,24 +184,22 @@ class Tlb extends Module with HasTlbConst with HasCSRConst { is(search_l2) { when(il2_hit_vec.asUInt.orR) { immu_state := search_l1 - itlb := tlbl2(il2_hit_vec.indexWhere(_ === true.B)) + itlb := tlbl2(PriorityEncoder(il2_hit_vec)) }.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 + when(ar_sel === 0.U && io.dcache.ptw.vpn.ready) { + io.dcache.ptw.vpn.valid := true.B + 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) { + io.dcache.ptw.vpn.valid := true.B + when(io.dcache.ptw.pte.valid) { + when(io.dcache.ptw.pte.bits.access_fault) { + iaccess_fault := true.B + immu_state := search_fault + }.elsewhen(io.dcache.ptw.pte.bits.page_fault) { ipage_fault := true.B immu_state := search_fault }.otherwise { @@ -192,9 +207,9 @@ class Tlb extends Module with HasTlbConst with HasCSRConst { 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 + replace_entry.flag := io.dcache.ptw.pte.bits.entry.flag + replace_entry.ppn := io.dcache.ptw.pte.bits.entry.ppn + replace_entry.pteaddr := io.dcache.ptw.pte.bits.addr tlbl2(replace_index.value) := replace_entry itlb := replace_entry immu_state := search_l1 diff --git a/chisel/playground/src/defines/Bundles.scala b/chisel/playground/src/defines/Bundles.scala index a83d99d..aa41c12 100644 --- a/chisel/playground/src/defines/Bundles.scala +++ b/chisel/playground/src/defines/Bundles.scala @@ -5,7 +5,7 @@ import chisel3.util._ import cpu.defines._ import cpu.defines.Const._ import cpu.CpuConfig -import icache.mmu.Tlb_Cache +import icache.mmu.{Tlb_DCache, Tlb_ICache} class ExceptionInfo extends Bundle { val exception = Vec(EXC_WID, Bool()) @@ -121,7 +121,7 @@ class Cache_ICache(implicit val cpuConfig: CpuConfig) extends Bundle { val icache_stall = Input(Bool()) // icache_stall // tlb - val tlb = new Tlb_Cache() + val tlb = new Tlb_ICache() } // cpu to dcache @@ -140,7 +140,7 @@ class Cache_DCache extends Bundle { val acc_err = Input(Bool()) val dcache_ready = Input(Bool()) - val tlb = new Tlb_Cache() + val tlb = new Tlb_DCache() } // axi diff --git a/chisel/playground/src/defines/TlbBundles.scala b/chisel/playground/src/defines/TlbBundles.scala index 404cbf4..2a6a73f 100644 --- a/chisel/playground/src/defines/TlbBundles.scala +++ b/chisel/playground/src/defines/TlbBundles.scala @@ -66,6 +66,12 @@ trait Sv39Const extends CoreParameter { val offset = UInt(pageOffsetLen.W) } + def ppnBundle = new Bundle { + val ppn2 = UInt(ppn2Len.W) + val ppn1 = UInt(ppn1Len.W) + val ppn0 = UInt(ppn0Len.W) + } + def paddrApply(ppn: UInt, vpnn: UInt): UInt = { Cat(Cat(ppn, vpnn), 0.U(3.W)) } @@ -75,14 +81,14 @@ trait Sv39Const extends CoreParameter { val ppn = UInt(ppnLen.W) val rsw = UInt(2.W) val flag = new Bundle { - val d = UInt(1.W) - val a = UInt(1.W) - val g = UInt(1.W) - val u = UInt(1.W) - val x = UInt(1.W) - val w = UInt(1.W) - val r = UInt(1.W) - val v = UInt(1.W) + val d = Bool() + val a = Bool() + val g = Bool() + val u = Bool() + val x = Bool() + val w = Bool() + val r = Bool() + val v = Bool() } }