搭了下itlb的框架

This commit is contained in:
Liphen 2024-01-13 17:09:01 +08:00
parent 6ca4ffcd86
commit 07490e0f13
10 changed files with 228 additions and 94 deletions

View File

@ -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 {

View File

@ -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)

View File

@ -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("----------------------------------------")

View File

@ -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路命中时值为10路命中时值为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 * //

View File

@ -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=0S模式内存访问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))
}

View File

@ -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

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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) :=

View File

@ -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) {