1
0

rocket: separate page faults from physical memory access exceptions

This commit is contained in:
Andrew Waterman 2017-03-26 18:18:35 -07:00
parent ea0714bfcb
commit 069858a20c
11 changed files with 120 additions and 73 deletions

@ -1 +1 @@
Subproject commit 4f430b184ed07890cd30ad144ded6d7cb07dcdf0 Subproject commit 89d487023c1e59ff574872e2f51ee479cda380ab

View File

@ -119,10 +119,15 @@ object CSR
def R = UInt(5,SZ) def R = UInt(5,SZ)
val ADDRSZ = 12 val ADDRSZ = 12
def debugIntCause = new MIP().getWidth def debugIntCause = {
val res = 14
require(res >= new MIP().getWidth)
res
}
def debugTriggerCause = { def debugTriggerCause = {
require(debugIntCause >= Causes.all.max) val res = 14
debugIntCause require(!(Causes.all contains res))
res
} }
val firstCtr = CSRs.cycle val firstCtr = CSRs.cycle
@ -224,10 +229,10 @@ class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Param
} }
val delegable_exceptions = UInt(Seq( val delegable_exceptions = UInt(Seq(
Causes.misaligned_fetch, Causes.misaligned_fetch,
Causes.fault_fetch, Causes.fetch_page_fault,
Causes.breakpoint, Causes.breakpoint,
Causes.fault_load, Causes.load_page_fault,
Causes.fault_store, Causes.store_page_fault,
Causes.user_ecall).map(1 << _).sum) Causes.user_ecall).map(1 << _).sum)
val reg_debug = Reg(init=Bool(false)) val reg_debug = Reg(init=Bool(false))
@ -483,7 +488,9 @@ class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Param
val write_badaddr = cause isOneOf (Causes.breakpoint, val write_badaddr = cause isOneOf (Causes.breakpoint,
Causes.misaligned_load, Causes.misaligned_store, Causes.misaligned_fetch, Causes.misaligned_load, Causes.misaligned_store, Causes.misaligned_fetch,
Causes.fault_load, Causes.fault_store, Causes.fault_fetch) Causes.load_access, Causes.store_access, Causes.fetch_access,
Causes.load_page_fault, Causes.store_page_fault, Causes.fetch_page_fault
)
when (trapToDebug) { when (trapToDebug) {
reg_debug := true reg_debug := true

View File

@ -185,8 +185,10 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
val no_xcpt = Bool(usingDataScratchpad) && s1_req.phys /* slave port */ && s1_hit_state.isValid() val no_xcpt = Bool(usingDataScratchpad) && s1_req.phys /* slave port */ && s1_hit_state.isValid()
io.cpu.xcpt.ma.ld := !no_xcpt && s1_read && s1_storegen.misaligned io.cpu.xcpt.ma.ld := !no_xcpt && s1_read && s1_storegen.misaligned
io.cpu.xcpt.ma.st := !no_xcpt && s1_write && s1_storegen.misaligned io.cpu.xcpt.ma.st := !no_xcpt && s1_write && s1_storegen.misaligned
io.cpu.xcpt.pf.ld := !no_xcpt && s1_read && tlb.io.resp.xcpt_ld io.cpu.xcpt.pf.ld := !no_xcpt && s1_read && tlb.io.resp.pf.ld
io.cpu.xcpt.pf.st := !no_xcpt && s1_write && tlb.io.resp.xcpt_st io.cpu.xcpt.pf.st := !no_xcpt && s1_write && tlb.io.resp.pf.st
io.cpu.xcpt.ae.ld := !no_xcpt && s1_read && tlb.io.resp.ae.ld
io.cpu.xcpt.ae.st := !no_xcpt && s1_write && tlb.io.resp.ae.st
// load reservations // load reservations
val s2_lr = Bool(usingAtomics) && s2_req.cmd === M_XLR val s2_lr = Bool(usingAtomics) && s2_req.cmd === M_XLR

View File

@ -22,7 +22,8 @@ class FrontendResp(implicit p: Parameters) extends CoreBundle()(p) {
val pc = UInt(width = vaddrBitsExtended) // ID stage PC val pc = UInt(width = vaddrBitsExtended) // ID stage PC
val data = UInt(width = fetchWidth * coreInstBits) val data = UInt(width = fetchWidth * coreInstBits)
val mask = Bits(width = fetchWidth) val mask = Bits(width = fetchWidth)
val xcpt_if = Bool() val pf = Bool()
val ae = Bool()
val replay = Bool() val replay = Bool()
} }
@ -72,9 +73,12 @@ class FrontendModule(outer: Frontend) extends LazyModuleImp(outer)
val s2_pc = Reg(init=io.resetVector) val s2_pc = Reg(init=io.resetVector)
val s2_btb_resp_valid = Reg(init=Bool(false)) val s2_btb_resp_valid = Reg(init=Bool(false))
val s2_btb_resp_bits = Reg(new BTBResp) val s2_btb_resp_bits = Reg(new BTBResp)
val s2_maybe_xcpt_if = Reg(init=Bool(false)) val s2_maybe_pf = Reg(init=Bool(false))
val s2_maybe_ae = Reg(init=Bool(false))
val s2_tlb_miss = Reg(Bool()) val s2_tlb_miss = Reg(Bool())
val s2_xcpt_if = s2_maybe_xcpt_if && !s2_tlb_miss val s2_pf = s2_maybe_pf && !s2_tlb_miss
val s2_ae = s2_maybe_ae && !s2_tlb_miss
val s2_xcpt = s2_pf || s2_ae
val s2_speculative = Reg(init=Bool(false)) val s2_speculative = Reg(init=Bool(false))
val s2_cacheable = Reg(init=Bool(false)) val s2_cacheable = Reg(init=Bool(false))
@ -101,7 +105,8 @@ class FrontendModule(outer: Frontend) extends LazyModuleImp(outer)
s2_pc := s1_pc s2_pc := s1_pc
s2_speculative := s1_speculative s2_speculative := s1_speculative
s2_cacheable := tlb.io.resp.cacheable s2_cacheable := tlb.io.resp.cacheable
s2_maybe_xcpt_if := tlb.io.resp.xcpt_if s2_maybe_pf := tlb.io.resp.pf.inst
s2_maybe_ae := tlb.io.resp.ae.inst
s2_tlb_miss := tlb.io.resp.miss s2_tlb_miss := tlb.io.resp.miss
} }
} }
@ -144,18 +149,19 @@ class FrontendModule(outer: Frontend) extends LazyModuleImp(outer)
icache.io.invalidate := io.cpu.flush_icache icache.io.invalidate := io.cpu.flush_icache
icache.io.s1_paddr := tlb.io.resp.paddr icache.io.s1_paddr := tlb.io.resp.paddr
icache.io.s1_kill := io.cpu.req.valid || tlb.io.resp.miss || icmiss icache.io.s1_kill := io.cpu.req.valid || tlb.io.resp.miss || icmiss
icache.io.s2_kill := s2_speculative && !s2_cacheable || s2_xcpt_if icache.io.s2_kill := s2_speculative && !s2_cacheable || s2_xcpt
icache.io.resp.ready := !stall && !s1_same_block icache.io.resp.ready := !stall && !s1_same_block
io.cpu.resp.valid := s2_valid && (icache.io.resp.valid || icache.io.s2_kill || s2_xcpt_if) io.cpu.resp.valid := s2_valid && (icache.io.resp.valid || icache.io.s2_kill || s2_xcpt)
io.cpu.resp.bits.pc := s2_pc io.cpu.resp.bits.pc := s2_pc
io.cpu.npc := Mux(io.cpu.req.valid, io.cpu.req.bits.pc, npc) io.cpu.npc := Mux(io.cpu.req.valid, io.cpu.req.bits.pc, npc)
require(fetchWidth * coreInstBytes <= rowBytes && isPow2(fetchWidth)) require(fetchWidth * coreInstBytes <= rowBytes && isPow2(fetchWidth))
io.cpu.resp.bits.data := icache.io.resp.bits.datablock >> (s2_pc.extract(log2Ceil(rowBytes)-1,log2Ceil(fetchWidth*coreInstBytes)) << log2Ceil(fetchWidth*coreInstBits)) io.cpu.resp.bits.data := icache.io.resp.bits.datablock >> (s2_pc.extract(log2Ceil(rowBytes)-1,log2Ceil(fetchWidth*coreInstBytes)) << log2Ceil(fetchWidth*coreInstBits))
io.cpu.resp.bits.mask := UInt((1 << fetchWidth)-1) << s2_pc.extract(log2Ceil(fetchWidth)+log2Ceil(coreInstBytes)-1, log2Ceil(coreInstBytes)) io.cpu.resp.bits.mask := UInt((1 << fetchWidth)-1) << s2_pc.extract(log2Ceil(fetchWidth)+log2Ceil(coreInstBytes)-1, log2Ceil(coreInstBytes))
io.cpu.resp.bits.xcpt_if := s2_xcpt_if io.cpu.resp.bits.pf := s2_pf
io.cpu.resp.bits.replay := icache.io.s2_kill && !icache.io.resp.valid && !s2_xcpt_if io.cpu.resp.bits.ae := s2_ae
io.cpu.resp.bits.replay := icache.io.s2_kill && !icache.io.resp.valid && !s2_xcpt
io.cpu.resp.bits.btb.valid := s2_btb_resp_valid io.cpu.resp.bits.btb.valid := s2_btb_resp_valid
io.cpu.resp.bits.btb.bits := s2_btb_resp_bits io.cpu.resp.bits.btb.bits := s2_btb_resp_bits

View File

@ -113,6 +113,7 @@ class AlignmentExceptions extends Bundle {
class HellaCacheExceptions extends Bundle { class HellaCacheExceptions extends Bundle {
val ma = new AlignmentExceptions val ma = new AlignmentExceptions
val pf = new AlignmentExceptions val pf = new AlignmentExceptions
val ae = new AlignmentExceptions
} }
// interface between D$ and processor/DTLB // interface between D$ and processor/DTLB

View File

@ -11,6 +11,8 @@ import util._
class Instruction(implicit val p: Parameters) extends ParameterizedBundle with HasCoreParameters { class Instruction(implicit val p: Parameters) extends ParameterizedBundle with HasCoreParameters {
val pf0 = Bool() // page fault on first half of instruction val pf0 = Bool() // page fault on first half of instruction
val pf1 = Bool() // page fault on second half of instruction val pf1 = Bool() // page fault on second half of instruction
val ae0 = Bool() // access exception on first half of instruction
val ae1 = Bool() // access exception on second half of instruction
val replay = Bool() val replay = Bool()
val btb_hit = Bool() val btb_hit = Bool()
val rvc = Bool() val rvc = Bool()
@ -78,7 +80,8 @@ class IBuf(implicit p: Parameters) extends CoreModule {
val valid = (UIntToOH(nValid) - 1)(fetchWidth-1, 0) val valid = (UIntToOH(nValid) - 1)(fetchWidth-1, 0)
val bufMask = UIntToOH(nBufValid) - 1 val bufMask = UIntToOH(nBufValid) - 1
val xcpt_if = valid & (Mux(buf.xcpt_if, bufMask, UInt(0)) | Mux(io.imem.bits.xcpt_if, ~bufMask, UInt(0))) val pf = valid & (Mux(buf.pf, bufMask, UInt(0)) | Mux(io.imem.bits.pf, ~bufMask, UInt(0)))
val ae = valid & (Mux(buf.ae, bufMask, UInt(0)) | Mux(io.imem.bits.ae, ~bufMask, UInt(0)))
val ic_replay = valid & (Mux(buf.replay, bufMask, UInt(0)) | Mux(io.imem.bits.replay, ~bufMask, UInt(0))) val ic_replay = valid & (Mux(buf.replay, bufMask, UInt(0)) | Mux(io.imem.bits.replay, ~bufMask, UInt(0)))
val ibufBTBHitMask = Mux(ibufBTBHit, UIntToOH(ibufBTBResp.bridx), UInt(0)) val ibufBTBHitMask = Mux(ibufBTBHit, UIntToOH(ibufBTBResp.bridx), UInt(0))
assert(!io.imem.bits.btb.valid || io.imem.bits.btb.bits.bridx >= pcWordBits) assert(!io.imem.bits.btb.valid || io.imem.bits.btb.bits.bridx >= pcWordBits)
@ -97,9 +100,11 @@ class IBuf(implicit p: Parameters) extends CoreModule {
if (usingCompressed) { if (usingCompressed) {
val replay = ic_replay(j) || (!exp.io.rvc && (btbHitMask(j) || ic_replay(j+1))) val replay = ic_replay(j) || (!exp.io.rvc && (btbHitMask(j) || ic_replay(j+1)))
io.inst(i).valid := valid(j) && (exp.io.rvc || valid(j+1) || xcpt_if(j+1) || replay) io.inst(i).valid := valid(j) && (exp.io.rvc || valid(j+1) || pf(j+1) || ae(j+1) || replay)
io.inst(i).bits.pf0 := xcpt_if(j) io.inst(i).bits.pf0 := pf(j)
io.inst(i).bits.pf1 := !exp.io.rvc && xcpt_if(j+1) io.inst(i).bits.pf1 := !exp.io.rvc && pf(j+1)
io.inst(i).bits.ae0 := ae(j)
io.inst(i).bits.ae1 := !exp.io.rvc && ae(j+1)
io.inst(i).bits.replay := replay io.inst(i).bits.replay := replay
io.inst(i).bits.btb_hit := btbHitMask(j) || (!exp.io.rvc && btbHitMask(j+1)) io.inst(i).bits.btb_hit := btbHitMask(j) || (!exp.io.rvc && btbHitMask(j+1))
io.inst(i).bits.rvc := exp.io.rvc io.inst(i).bits.rvc := exp.io.rvc
@ -110,8 +115,10 @@ class IBuf(implicit p: Parameters) extends CoreModule {
} else { } else {
when (io.inst(i).ready) { nReady := i+1 } when (io.inst(i).ready) { nReady := i+1 }
io.inst(i).valid := valid(i) io.inst(i).valid := valid(i)
io.inst(i).bits.pf0 := xcpt_if(i) io.inst(i).bits.pf0 := pf(i)
io.inst(i).bits.pf1 := false io.inst(i).bits.pf1 := false
io.inst(i).bits.ae0 := ae(i)
io.inst(i).bits.ae1 := false
io.inst(i).bits.replay := ic_replay(i) io.inst(i).bits.replay := ic_replay(i)
io.inst(i).bits.rvc := false io.inst(i).bits.rvc := false
io.inst(i).bits.btb_hit := btbHitMask(i) io.inst(i).bits.btb_hit := btbHitMask(i)

View File

@ -216,31 +216,37 @@ object Instructions {
} }
object Causes { object Causes {
val misaligned_fetch = 0x0 val misaligned_fetch = 0x0
val fault_fetch = 0x1 val fetch_access = 0x1
val illegal_instruction = 0x2 val illegal_instruction = 0x2
val breakpoint = 0x3 val breakpoint = 0x3
val misaligned_load = 0x4 val misaligned_load = 0x4
val fault_load = 0x5 val load_access = 0x5
val misaligned_store = 0x6 val misaligned_store = 0x6
val fault_store = 0x7 val store_access = 0x7
val user_ecall = 0x8 val user_ecall = 0x8
val supervisor_ecall = 0x9 val supervisor_ecall = 0x9
val hypervisor_ecall = 0xa val hypervisor_ecall = 0xa
val machine_ecall = 0xb val machine_ecall = 0xb
val fetch_page_fault = 0xc
val load_page_fault = 0xd
val store_page_fault = 0xf
val all = { val all = {
val res = collection.mutable.ArrayBuffer[Int]() val res = collection.mutable.ArrayBuffer[Int]()
res += misaligned_fetch res += misaligned_fetch
res += fault_fetch res += fetch_access
res += illegal_instruction res += illegal_instruction
res += breakpoint res += breakpoint
res += misaligned_load res += misaligned_load
res += fault_load res += load_access
res += misaligned_store res += misaligned_store
res += fault_store res += store_access
res += user_ecall res += user_ecall
res += supervisor_ecall res += supervisor_ecall
res += hypervisor_ecall res += hypervisor_ecall
res += machine_ecall res += machine_ecall
res += fetch_page_fault
res += load_page_fault
res += store_page_fault
res.toArray res.toArray
} }
} }

View File

@ -745,8 +745,10 @@ class NonBlockingDCacheModule(outer: NonBlockingDCache) extends HellaCacheModule
val misaligned = new StoreGen(s1_req.typ, s1_req.addr, UInt(0), wordBytes).misaligned val misaligned = new StoreGen(s1_req.typ, s1_req.addr, UInt(0), wordBytes).misaligned
io.cpu.xcpt.ma.ld := s1_read && misaligned io.cpu.xcpt.ma.ld := s1_read && misaligned
io.cpu.xcpt.ma.st := s1_write && misaligned io.cpu.xcpt.ma.st := s1_write && misaligned
io.cpu.xcpt.pf.ld := s1_read && dtlb.io.resp.xcpt_ld io.cpu.xcpt.pf.ld := s1_read && dtlb.io.resp.pf.ld
io.cpu.xcpt.pf.st := s1_write && dtlb.io.resp.xcpt_st io.cpu.xcpt.pf.st := s1_write && dtlb.io.resp.pf.st
io.cpu.xcpt.ae.ld := s1_read && dtlb.io.resp.ae.ld
io.cpu.xcpt.ae.st := s1_write && dtlb.io.resp.ae.st
// tags // tags
def onReset = L1Metadata(UInt(0), ClientMetadata.onReset) def onReset = L1Metadata(UInt(0), ClientMetadata.onReset)

View File

@ -19,6 +19,7 @@ class PTWReq(implicit p: Parameters) extends CoreBundle()(p) {
} }
class PTWResp(implicit p: Parameters) extends CoreBundle()(p) { class PTWResp(implicit p: Parameters) extends CoreBundle()(p) {
val ae = Bool()
val pte = new PTE val pte = new PTE
val level = UInt(width = log2Ceil(pgLevels)) val level = UInt(width = log2Ceil(pgLevels))
val homogeneous = Bool() val homogeneous = Bool()
@ -77,7 +78,7 @@ class PTW(n: Int)(implicit edge: TLEdgeOut, p: Parameters) extends CoreModule()(
val count = Reg(UInt(width = log2Up(pgLevels))) val count = Reg(UInt(width = log2Up(pgLevels)))
val s1_kill = Reg(next = Bool(false)) val s1_kill = Reg(next = Bool(false))
val resp_valid = Reg(next = Vec.fill(io.requestor.size)(Bool(false))) val resp_valid = Reg(next = Vec.fill(io.requestor.size)(Bool(false)))
val exception = Reg(next = io.mem.xcpt.pf.ld) val ae = Reg(next = io.mem.xcpt.ae.ld)
val r_req = Reg(new PTWReq) val r_req = Reg(new PTWReq)
val r_req_dest = Reg(Bits()) val r_req_dest = Reg(Bits())
@ -90,14 +91,15 @@ class PTW(n: Int)(implicit edge: TLEdgeOut, p: Parameters) extends CoreModule()(
arb.io.in <> io.requestor.map(_.req) arb.io.in <> io.requestor.map(_.req)
arb.io.out.ready := state === s_ready arb.io.out.ready := state === s_ready
val pte = { val (pte, invalid_paddr) = {
val tmp = new PTE().fromBits(io.mem.resp.bits.data) val tmp = new PTE().fromBits(io.mem.resp.bits.data)
val res = Wire(init = new PTE().fromBits(io.mem.resp.bits.data)) val res = Wire(init = new PTE().fromBits(io.mem.resp.bits.data))
res.ppn := tmp.ppn(ppnBits-1, 0) res.ppn := tmp.ppn(ppnBits-1, 0)
when ((tmp.ppn >> ppnBits) =/= 0) { res.v := false } (res, (tmp.ppn >> ppnBits) =/= 0)
res
} }
val traverse = pte.table() && !invalid_paddr && count < pgLevels-1
val pte_addr = Cat(r_pte.ppn, vpn_idx) << log2Ceil(xLen/8) val pte_addr = Cat(r_pte.ppn, vpn_idx) << log2Ceil(xLen/8)
val resp_ae = Reg(next = ae || invalid_paddr)
when (arb.io.out.fire()) { when (arb.io.out.fire()) {
r_req := arb.io.out.bits r_req := arb.io.out.bits
@ -114,7 +116,7 @@ class PTW(n: Int)(implicit edge: TLEdgeOut, p: Parameters) extends CoreModule()(
val hits = tags.map(_ === pte_addr).asUInt & valid val hits = tags.map(_ === pte_addr).asUInt & valid
val hit = hits.orR val hit = hits.orR
when (io.mem.resp.valid && pte.table() && !hit) { when (io.mem.resp.valid && traverse && !hit) {
val r = Mux(valid.andR, plru.replace, PriorityEncoder(~valid)) val r = Mux(valid.andR, plru.replace, PriorityEncoder(~valid))
valid := valid | UIntToOH(r) valid := valid | UIntToOH(r)
tags(r) := pte_addr tags(r) := pte_addr
@ -142,6 +144,7 @@ class PTW(n: Int)(implicit edge: TLEdgeOut, p: Parameters) extends CoreModule()(
for (i <- 0 until io.requestor.size) { for (i <- 0 until io.requestor.size) {
io.requestor(i).resp.valid := resp_valid(i) io.requestor(i).resp.valid := resp_valid(i)
io.requestor(i).resp.bits.ae := resp_ae
io.requestor(i).resp.bits.pte := r_pte io.requestor(i).resp.bits.pte := r_pte
io.requestor(i).resp.bits.level := count io.requestor(i).resp.bits.level := count
io.requestor(i).resp.bits.pte.ppn := pte_addr >> pgIdxBits io.requestor(i).resp.bits.pte.ppn := pte_addr >> pgIdxBits
@ -177,16 +180,17 @@ class PTW(n: Int)(implicit edge: TLEdgeOut, p: Parameters) extends CoreModule()(
} }
when (io.mem.resp.valid) { when (io.mem.resp.valid) {
r_pte := pte r_pte := pte
when (pte.table() && count < pgLevels-1) { when (traverse) {
state := s_req state := s_req
count := count + 1 count := count + 1
}.otherwise { }.otherwise {
resp_ae := invalid_paddr
state := s_ready state := s_ready
resp_valid(r_req_dest) := true resp_valid(r_req_dest) := true
} }
} }
when (exception) { when (ae) {
r_pte.v := false resp_ae := true
state := s_ready state := s_ready
resp_valid(r_req_dest) := true resp_valid(r_req_dest) := true
} }

View File

@ -225,12 +225,14 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p)
bpu.io.pc := ibuf.io.pc bpu.io.pc := ibuf.io.pc
bpu.io.ea := mem_reg_wdata bpu.io.ea := mem_reg_wdata
val id_xcpt_if = ibuf.io.inst(0).bits.pf0 || ibuf.io.inst(0).bits.pf1 val id_xcpt_pf = ibuf.io.inst(0).bits.pf0 || ibuf.io.inst(0).bits.pf1
val id_xcpt_ae = ibuf.io.inst(0).bits.ae0 || ibuf.io.inst(0).bits.ae1
val (id_xcpt, id_cause) = checkExceptions(List( val (id_xcpt, id_cause) = checkExceptions(List(
(csr.io.interrupt, csr.io.interrupt_cause), (csr.io.interrupt, csr.io.interrupt_cause),
(bpu.io.debug_if, UInt(CSR.debugTriggerCause)), (bpu.io.debug_if, UInt(CSR.debugTriggerCause)),
(bpu.io.xcpt_if, UInt(Causes.breakpoint)), (bpu.io.xcpt_if, UInt(Causes.breakpoint)),
(id_xcpt_if, UInt(Causes.fault_fetch)), (id_xcpt_pf, UInt(Causes.fetch_page_fault)),
(id_xcpt_ae, UInt(Causes.fetch_access)),
(id_illegal_insn, UInt(Causes.illegal_instruction)))) (id_illegal_insn, UInt(Causes.illegal_instruction))))
val dcache_bypass_data = val dcache_bypass_data =
@ -423,8 +425,10 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p)
val (wb_xcpt, wb_cause) = checkExceptions(List( val (wb_xcpt, wb_cause) = checkExceptions(List(
(wb_reg_xcpt, wb_reg_cause), (wb_reg_xcpt, wb_reg_cause),
(wb_reg_valid && wb_ctrl.mem && RegEnable(io.dmem.xcpt.pf.st, mem_pc_valid), UInt(Causes.fault_store)), (wb_reg_valid && wb_ctrl.mem && RegEnable(io.dmem.xcpt.pf.st, mem_pc_valid), UInt(Causes.store_page_fault)),
(wb_reg_valid && wb_ctrl.mem && RegEnable(io.dmem.xcpt.pf.ld, mem_pc_valid), UInt(Causes.fault_load)) (wb_reg_valid && wb_ctrl.mem && RegEnable(io.dmem.xcpt.pf.ld, mem_pc_valid), UInt(Causes.load_page_fault)),
(wb_reg_valid && wb_ctrl.mem && RegEnable(io.dmem.xcpt.ae.st, mem_pc_valid), UInt(Causes.store_access)),
(wb_reg_valid && wb_ctrl.mem && RegEnable(io.dmem.xcpt.ae.ld, mem_pc_valid), UInt(Causes.load_access))
)) ))
val wb_wxd = wb_reg_valid && wb_ctrl.wxd val wb_wxd = wb_reg_valid && wb_ctrl.wxd

View File

@ -33,20 +33,25 @@ class TLBReq(lgMaxSize: Int)(implicit p: Parameters) extends CoreBundle()(p) {
override def cloneType = new TLBReq(lgMaxSize).asInstanceOf[this.type] override def cloneType = new TLBReq(lgMaxSize).asInstanceOf[this.type]
} }
class TLBExceptions extends Bundle {
val ld = Bool()
val st = Bool()
val inst = Bool()
}
class TLBResp(implicit p: Parameters) extends CoreBundle()(p) { class TLBResp(implicit p: Parameters) extends CoreBundle()(p) {
// lookup responses // lookup responses
val miss = Bool(OUTPUT) val miss = Bool()
val paddr = UInt(OUTPUT, paddrBits) val paddr = UInt(width = paddrBits)
val xcpt_ld = Bool(OUTPUT) val pf = new TLBExceptions
val xcpt_st = Bool(OUTPUT) val ae = new TLBExceptions
val xcpt_if = Bool(OUTPUT) val cacheable = Bool()
val cacheable = Bool(OUTPUT)
} }
class TLB(lgMaxSize: Int, nEntries: Int)(implicit edge: TLEdgeOut, p: Parameters) extends CoreModule()(p) { class TLB(lgMaxSize: Int, nEntries: Int)(implicit edge: TLEdgeOut, p: Parameters) extends CoreModule()(p) {
val io = new Bundle { val io = new Bundle {
val req = Decoupled(new TLBReq(lgMaxSize)).flip val req = Decoupled(new TLBReq(lgMaxSize)).flip
val resp = new TLBResp val resp = new TLBResp().asOutput
val ptw = new TLBPTWIO val ptw = new TLBPTWIO
} }
@ -59,8 +64,10 @@ class TLB(lgMaxSize: Int, nEntries: Int)(implicit edge: TLEdgeOut, p: Parameters
val sw = Bool() val sw = Bool()
val sx = Bool() val sx = Bool()
val sr = Bool() val sr = Bool()
val xr = Bool() val pw = Bool()
val cacheable = Bool() val px = Bool()
val pr = Bool()
val c = Bool()
} }
val totalEntries = nEntries + 1 val totalEntries = nEntries + 1
@ -101,7 +108,7 @@ class TLB(lgMaxSize: Int, nEntries: Int)(implicit edge: TLEdgeOut, p: Parameters
val prot_w = fastCheck(_.supportsPutFull) && pmp.io.w val prot_w = fastCheck(_.supportsPutFull) && pmp.io.w
val prot_x = fastCheck(_.executable) && pmp.io.x val prot_x = fastCheck(_.executable) && pmp.io.x
val cacheable = fastCheck(_.supportsAcquireB) val cacheable = fastCheck(_.supportsAcquireB)
val isSpecial = !io.ptw.resp.bits.homogeneous val isSpecial = !(io.ptw.resp.bits.homogeneous || io.ptw.resp.bits.ae)
val lookup_tag = Cat(io.ptw.ptbr.asid, vpn(vpnBits-1,0)) val lookup_tag = Cat(io.ptw.ptbr.asid, vpn(vpnBits-1,0))
val hitsVec = (0 until totalEntries).map { i => vm_enabled && { val hitsVec = (0 until totalEntries).map { i => vm_enabled && {
@ -123,13 +130,6 @@ class TLB(lgMaxSize: Int, nEntries: Int)(implicit edge: TLEdgeOut, p: Parameters
} }
// permission bit arrays // permission bit arrays
val u_array = Reg(Vec(totalEntries, Bool())) // user permission
val g_array = Reg(Vec(totalEntries, Bool())) // global mapping
val sw_array = Reg(Vec(totalEntries, Bool())) // write permission
val sx_array = Reg(Vec(totalEntries, Bool())) // execute permission
val sr_array = Reg(Vec(totalEntries, Bool())) // read permission
val xr_array = Reg(Vec(totalEntries, Bool())) // read permission to executable page
val cash_array = Reg(Vec(normalEntries, Bool())) // cacheable
when (do_refill && !invalidate_refill) { when (do_refill && !invalidate_refill) {
val waddr = Mux(isSpecial, specialEntry.U, r_refill_waddr) val waddr = Mux(isSpecial, specialEntry.U, r_refill_waddr)
val pte = io.ptw.resp.bits.pte val pte = io.ptw.resp.bits.pte
@ -137,13 +137,15 @@ class TLB(lgMaxSize: Int, nEntries: Int)(implicit edge: TLEdgeOut, p: Parameters
newEntry.ppn := pte.ppn newEntry.ppn := pte.ppn
newEntry.tag := r_refill_tag newEntry.tag := r_refill_tag
newEntry.level := io.ptw.resp.bits.level newEntry.level := io.ptw.resp.bits.level
newEntry.c := cacheable
newEntry.u := pte.u newEntry.u := pte.u
newEntry.g := pte.g newEntry.g := pte.g
newEntry.sw := pte.sw() && (isSpecial || prot_w) newEntry.sr := pte.sr()
newEntry.sx := pte.sx() && (isSpecial || prot_x) newEntry.sw := pte.sw()
newEntry.sr := pte.sr() && (isSpecial || prot_r) newEntry.sx := pte.sx()
newEntry.xr := pte.sx() && (isSpecial || prot_r) newEntry.pr := prot_r && !io.ptw.resp.bits.ae
newEntry.cacheable := isSpecial || cacheable newEntry.pw := prot_w && !io.ptw.resp.bits.ae
newEntry.px := prot_x && !io.ptw.resp.bits.ae
valid := valid | UIntToOH(waddr) valid := valid | UIntToOH(waddr)
reg_entries(waddr) := newEntry.asUInt reg_entries(waddr) := newEntry.asUInt
@ -153,10 +155,13 @@ class TLB(lgMaxSize: Int, nEntries: Int)(implicit edge: TLEdgeOut, p: Parameters
val repl_waddr = Mux(!valid(normalEntries-1, 0).andR, PriorityEncoder(~valid(normalEntries-1, 0)), plru.replace) val repl_waddr = Mux(!valid(normalEntries-1, 0).andR, PriorityEncoder(~valid(normalEntries-1, 0)), plru.replace)
val priv_ok = Mux(priv_s, ~Mux(io.ptw.status.sum, UInt(0), entries.map(_.u).asUInt), entries.map(_.u).asUInt) val priv_ok = Mux(priv_s, ~Mux(io.ptw.status.sum, UInt(0), entries.map(_.u).asUInt), entries.map(_.u).asUInt)
val w_array = Cat(prot_w, priv_ok & ~(~prot_w << specialEntry) & entries.map(_.sw).asUInt) val r_array = Cat(true.B, priv_ok & (entries.map(_.sr).asUInt | Mux(io.ptw.status.mxr, entries.map(_.sx).asUInt, UInt(0))))
val x_array = Cat(prot_x, priv_ok & ~(~prot_x << specialEntry) & entries.map(_.sx).asUInt) val w_array = Cat(true.B, priv_ok & entries.map(_.sw).asUInt)
val r_array = Cat(prot_r, priv_ok & ~(~prot_r << specialEntry) & (entries.map(_.sr).asUInt | Mux(io.ptw.status.mxr, entries.map(_.xr).asUInt, UInt(0)))) val x_array = Cat(true.B, priv_ok & entries.map(_.sx).asUInt)
val c_array = Cat(cacheable, ~(~cacheable << specialEntry) & entries.map(_.cacheable).asUInt) val pr_array = Cat(Fill(2, prot_r), entries.init.map(_.pr).asUInt)
val pw_array = Cat(Fill(2, prot_w), entries.init.map(_.pw).asUInt)
val px_array = Cat(Fill(2, prot_x), entries.init.map(_.px).asUInt)
val c_array = Cat(Fill(2, cacheable), entries.init.map(_.c).asUInt)
val bad_va = val bad_va =
if (vpnBits == vpnBitsExtended) Bool(false) if (vpnBits == vpnBitsExtended) Bool(false)
@ -176,9 +181,12 @@ class TLB(lgMaxSize: Int, nEntries: Int)(implicit edge: TLEdgeOut, p: Parameters
val multipleHits = PopCountAtLeast(hits(totalEntries-1, 0), 2) val multipleHits = PopCountAtLeast(hits(totalEntries-1, 0), 2)
io.req.ready := state === s_ready io.req.ready := state === s_ready
io.resp.xcpt_ld := bad_va || (~r_array & hits).orR io.resp.pf.ld := bad_va || (~r_array & hits).orR
io.resp.xcpt_st := bad_va || (~w_array & hits).orR io.resp.pf.st := bad_va || (~w_array & hits).orR
io.resp.xcpt_if := bad_va || (~x_array & hits).orR io.resp.pf.inst := bad_va || (~x_array & hits).orR
io.resp.ae.ld := (~pr_array & hits).orR
io.resp.ae.st := (~pw_array & hits).orR
io.resp.ae.inst := (~px_array & hits).orR
io.resp.cacheable := (c_array & hits).orR io.resp.cacheable := (c_array & hits).orR
io.resp.miss := do_refill || tlb_miss || multipleHits io.resp.miss := do_refill || tlb_miss || multipleHits
io.resp.paddr := Cat(ppn, pgOffset) io.resp.paddr := Cat(ppn, pgOffset)
@ -208,7 +216,7 @@ class TLB(lgMaxSize: Int, nEntries: Int)(implicit edge: TLEdgeOut, p: Parameters
when (sfence) { when (sfence) {
valid := Mux(io.req.bits.sfence.bits.rs1, valid & ~hits(totalEntries-1, 0), valid := Mux(io.req.bits.sfence.bits.rs1, valid & ~hits(totalEntries-1, 0),
Mux(io.req.bits.sfence.bits.rs2, valid & g_array.asUInt, 0)) Mux(io.req.bits.sfence.bits.rs2, valid & entries.map(_.g).asUInt, 0))
} }
when (multipleHits) { when (multipleHits) {
valid := 0 valid := 0