rocket: separate page faults from physical memory access exceptions
This commit is contained in:
parent
ea0714bfcb
commit
069858a20c
@ -1 +1 @@
|
|||||||
Subproject commit 4f430b184ed07890cd30ad144ded6d7cb07dcdf0
|
Subproject commit 89d487023c1e59ff574872e2f51ee479cda380ab
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user