From aace5268579b1f3ff9b96e751c2d9c90e4eaf308 Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Wed, 15 Mar 2017 01:18:39 -0700 Subject: [PATCH] WIP on PMP --- src/main/scala/rocket/CSR.scala | 25 +++++++++ src/main/scala/rocket/Instructions.scala | 40 ++++++++++++++ src/main/scala/rocket/PMP.scala | 66 ++++++++++++++++++++++++ src/main/scala/rocket/PTW.scala | 9 +++- src/main/scala/rocket/Rocket.scala | 3 ++ src/main/scala/rocket/TLB.scala | 11 ++-- src/main/scala/tile/Core.scala | 2 +- 7 files changed, 150 insertions(+), 6 deletions(-) create mode 100644 src/main/scala/rocket/PMP.scala diff --git a/src/main/scala/rocket/CSR.scala b/src/main/scala/rocket/CSR.scala index 4db8d2d6..c78bea27 100644 --- a/src/main/scala/rocket/CSR.scala +++ b/src/main/scala/rocket/CSR.scala @@ -185,6 +185,7 @@ class CSRFileIO(implicit p: Parameters) extends CoreBundle val interrupt = Bool(OUTPUT) val interrupt_cause = UInt(OUTPUT, xLen) val bp = Vec(nBreakpoints, new BP).asOutput + val pmp = Vec(nPMPs, new PMP).asOutput val counters = Vec(nPerfCounters, new PerfCounterIO) } @@ -237,6 +238,7 @@ class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Param val reg_tselect = Reg(UInt(width = log2Up(nBreakpoints))) val reg_bp = Reg(Vec(1 << log2Up(nBreakpoints), new BP)) + val reg_pmp = Reg(Vec(nPMPs, new PMP)) val reg_mie = Reg(UInt(width = xLen)) val reg_mideleg = Reg(UInt(width = xLen)) @@ -286,6 +288,7 @@ class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Param io.interrupt := all_interrupts.orR && !reg_debug && !io.singleStep || reg_singleStepped io.interrupt_cause := interruptCause io.bp := reg_bp take nBreakpoints + io.pmp := reg_pmp // debug interrupts are only masked by being in debug mode when (Bool(usingDebug) && reg_dcsr.debugint && !reg_debug) { @@ -395,6 +398,13 @@ class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Param } } + val pmpCfgPerCSR = xLen / new PMPConfig().getWidth + def pmpCfgIndex(i: Int) = (xLen / 32) * (i / pmpCfgPerCSR) + for (i <- 0 until reg_pmp.size by pmpCfgPerCSR) + read_mapping += (CSRs.pmpcfg0 + pmpCfgIndex(i)) -> reg_pmp.map(_.cfg).slice(i, i + pmpCfgPerCSR).asUInt + for ((pmp, i) <- reg_pmp zipWithIndex) + read_mapping += (CSRs.pmpaddr0 + i) -> pmp.addr + for (i <- 0 until nCustomMrwCsrs) { val addr = 0xff0 + i require(addr < (1 << CSR.ADDRSZ)) @@ -653,6 +663,15 @@ class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Param when (decoded_addr(CSRs.tdata2)) { bp.address := wdata } } } + for (((pmp, next), i) <- (reg_pmp zip (reg_pmp.tail :+ reg_pmp.last)) zipWithIndex) { + require(xLen % pmp.cfg.getWidth == 0) + when (decoded_addr(CSRs.pmpcfg0 + pmpCfgIndex(i)) && !pmp.locked) { + pmp.cfg := new PMPConfig().fromBits(wdata >> ((i * pmp.cfg.getWidth) % xLen)) + } + when (decoded_addr(CSRs.pmpaddr0 + i) && !pmp.addrLocked(next)) { + pmp.addr := wdata + } + } } reg_mip <> io.interrupts @@ -691,6 +710,12 @@ class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Param } for (bp <- reg_bp drop nBreakpoints) bp := new BP().fromBits(0) + if (reg_pmp.nonEmpty) { + for (pmp <- reg_pmp) { + if (!usingUser) pmp.cfg.m := true + when (reset) { pmp.cfg.p := 0 } + } + } def legalizePrivilege(priv: UInt): UInt = if (usingVM) Mux(priv === PRV.H, PRV.U, priv) diff --git a/src/main/scala/rocket/Instructions.scala b/src/main/scala/rocket/Instructions.scala index aef4c910..5ac87564 100644 --- a/src/main/scala/rocket/Instructions.scala +++ b/src/main/scala/rocket/Instructions.scala @@ -302,6 +302,26 @@ object CSRs { val mcause = 0x342 val mbadaddr = 0x343 val mip = 0x344 + val pmpcfg0 = 0x3a0 + val pmpcfg1 = 0x3a1 + val pmpcfg2 = 0x3a2 + val pmpcfg3 = 0x3a3 + val pmpaddr0 = 0x3b0 + val pmpaddr1 = 0x3b1 + val pmpaddr2 = 0x3b2 + val pmpaddr3 = 0x3b3 + val pmpaddr4 = 0x3b4 + val pmpaddr5 = 0x3b5 + val pmpaddr6 = 0x3b6 + val pmpaddr7 = 0x3b7 + val pmpaddr8 = 0x3b8 + val pmpaddr9 = 0x3b9 + val pmpaddr10 = 0x3ba + val pmpaddr11 = 0x3bb + val pmpaddr12 = 0x3bc + val pmpaddr13 = 0x3bd + val pmpaddr14 = 0x3be + val pmpaddr15 = 0x3bf val tselect = 0x7a0 val tdata1 = 0x7a1 val tdata2 = 0x7a2 @@ -495,6 +515,26 @@ object CSRs { res += mcause res += mbadaddr res += mip + res += pmpcfg0 + res += pmpcfg1 + res += pmpcfg2 + res += pmpcfg3 + res += pmpaddr0 + res += pmpaddr1 + res += pmpaddr2 + res += pmpaddr3 + res += pmpaddr4 + res += pmpaddr5 + res += pmpaddr6 + res += pmpaddr7 + res += pmpaddr8 + res += pmpaddr9 + res += pmpaddr10 + res += pmpaddr11 + res += pmpaddr12 + res += pmpaddr13 + res += pmpaddr14 + res += pmpaddr15 res += tselect res += tdata1 res += tdata2 diff --git a/src/main/scala/rocket/PMP.scala b/src/main/scala/rocket/PMP.scala new file mode 100644 index 00000000..89968dc2 --- /dev/null +++ b/src/main/scala/rocket/PMP.scala @@ -0,0 +1,66 @@ +// See LICENSE.SiFive for license details. + +package rocket + +import Chisel._ +import Chisel.ImplicitConversions._ +import config._ +import tile._ +import util._ + +class PMPConfig extends Bundle { + val p = UInt(width = 2) + val a = UInt(width = 2) + val m = Bool() + val x = Bool() + val w = Bool() + val r = Bool() +} + +class PMP(implicit p: Parameters) extends CoreBundle()(p) { + val cfg = new PMPConfig + val addr = UInt(width = paddrBits - lgAlign) + + def enabled(prv: UInt) = cfg.p.orR && (cfg.m || prv <= PRV.S) + def locked = cfg.p.andR + def addrLocked(next: PMP) = locked || next.locked && next.cfg.a(1) + + private def lgAlign = 2 + private def mask = (0 until paddrBits - lgAlign).scanLeft(cfg.a(0))((m, i) => m && addr(i)).asUInt + + def pow2AddressMatch(x: UInt, lgSize: UInt, lgMaxSize: Int) = { + val m = mask + def checkOne(a: UInt) = (~(a >> lgAlign) | m) === (~addr | m) + var res = checkOne(x) + for (i <- (1 << lgAlign) until (1 << lgMaxSize) by (1 << lgAlign)) + res = res || (lgSize > log2Ceil(i) && checkOne(x | i)) + res + } + + def hit(prv: UInt, x: UInt, lgSize: UInt, lgMaxSize: Int) = { + enabled(prv) && pow2AddressMatch(x, lgSize, lgMaxSize) + } +} + +class PMPChecker(lgMaxSize: Int)(implicit p: Parameters) extends CoreModule()(p) + with HasRocketCoreParameters { + val io = new Bundle { + val prv = UInt(INPUT, PRV.SZ) + val pmp = Vec(nPMPs, new PMP).asInput + val addr = UInt(INPUT, paddrBits) + val size = UInt(INPUT, log2Ceil(lgMaxSize + 1)) + val xcpt_if = Bool(OUTPUT) + val xcpt_ld = Bool(OUTPUT) + val xcpt_st = Bool(OUTPUT) + } + + def hits = io.pmp.map(_.hit(io.prv, io.addr, io.size, lgMaxSize)) + val default = io.prv > PRV.S + val (r, w, x, _) = ((default, default, default, 0.U) /: (io.pmp zip hits).reverse) { case ((r, w, x, pri), (pmp, hit)) => + MuxT(hit && pmp.cfg.p >= pri, (pmp.cfg.r, pmp.cfg.w, pmp.cfg.x, pmp.cfg.p), (r, w, x, pri)) + } + + io.xcpt_if := !x + io.xcpt_ld := !r + io.xcpt_st := !w +} diff --git a/src/main/scala/rocket/PTW.scala b/src/main/scala/rocket/PTW.scala index 0fb65186..72dfcc45 100644 --- a/src/main/scala/rocket/PTW.scala +++ b/src/main/scala/rocket/PTW.scala @@ -26,17 +26,21 @@ class PTWResp(implicit p: Parameters) extends CoreBundle()(p) { val level = UInt(width = log2Ceil(pgLevels)) } -class TLBPTWIO(implicit p: Parameters) extends CoreBundle()(p) { +class TLBPTWIO(implicit p: Parameters) extends CoreBundle()(p) + with HasRocketCoreParameters { val req = Decoupled(new PTWReq) val resp = Valid(new PTWResp).flip val ptbr = new PTBR().asInput val status = new MStatus().asInput + val pmp = Vec(nPMPs, new PMP).asInput } -class DatapathPTWIO(implicit p: Parameters) extends CoreBundle()(p) { +class DatapathPTWIO(implicit p: Parameters) extends CoreBundle()(p) + with HasRocketCoreParameters { val ptbr = new PTBR().asInput val invalidate = Bool(INPUT) val status = new MStatus().asInput + val pmp = Vec(nPMPs, new PMP).asInput } class PTE(implicit p: Parameters) extends CoreBundle()(p) { @@ -138,6 +142,7 @@ class PTW(n: Int)(implicit p: Parameters) extends CoreModule()(p) { io.requestor(i).resp.bits.pte.ppn := pte_addr >> pgIdxBits io.requestor(i).ptbr := io.dpath.ptbr io.requestor(i).status := io.dpath.status + io.requestor(i).pmp := io.dpath.pmp } // control state machine diff --git a/src/main/scala/rocket/Rocket.scala b/src/main/scala/rocket/Rocket.scala index e8fa4f2b..fba8d185 100644 --- a/src/main/scala/rocket/Rocket.scala +++ b/src/main/scala/rocket/Rocket.scala @@ -18,6 +18,7 @@ case class RocketCoreParams( useAtomics: Boolean = true, useCompressed: Boolean = true, nBreakpoints: Int = 1, + nPMPs: Int = 16, nPerfCounters: Int = 0, nCustomMRWCSRs: Int = 0, mtvecInit: Option[BigInt] = Some(BigInt(0)), @@ -42,6 +43,7 @@ trait HasRocketCoreParameters extends HasCoreParameters { val fastLoadByte = rocketParams.fastLoadByte val fastJAL = rocketParams.fastJAL val nBreakpoints = rocketParams.nBreakpoints + val nPMPs = rocketParams.nPMPs val nPerfCounters = rocketParams.nPerfCounters val nCustomMrwCsrs = rocketParams.nCustomMRWCSRs val mtvecInit = rocketParams.mtvecInit @@ -483,6 +485,7 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p) csr.io.badaddr := encodeVirtualAddress(wb_reg_wdata, wb_reg_wdata) io.ptw.ptbr := csr.io.ptbr io.ptw.status := csr.io.status + io.ptw.pmp := csr.io.pmp csr.io.rw.addr := wb_reg_inst(31,20) csr.io.rw.cmd := Mux(wb_reg_valid, wb_ctrl.csr, CSR.N) csr.io.rw.wdata := wb_reg_wdata diff --git a/src/main/scala/rocket/TLB.scala b/src/main/scala/rocket/TLB.scala index 8f93b785..101c6c22 100644 --- a/src/main/scala/rocket/TLB.scala +++ b/src/main/scala/rocket/TLB.scala @@ -74,12 +74,17 @@ class TLB(entries: Int)(implicit edge: TLEdgeOut, p: Parameters) extends CoreMod val mpu_ppn = Mux(do_refill, refill_ppn, Mux(vm_enabled, ppns.last, vpn(ppnBits-1, 0))) val mpu_physaddr = Cat(mpu_ppn, io.req.bits.vaddr(pgIdxBits-1, 0)) + val pmp = Module(new PMPChecker(8)) + pmp.io.addr := mpu_physaddr + pmp.io.size := 2 + pmp.io.pmp := io.ptw.pmp + pmp.io.prv := priv val legal_address = edge.manager.findSafe(mpu_physaddr).reduce(_||_) def fastCheck(member: TLManagerParameters => Boolean) = legal_address && Mux1H(edge.manager.findFast(mpu_physaddr), edge.manager.managers.map(m => Bool(member(m)))) - val prot_r = fastCheck(_.supportsGet) - val prot_w = fastCheck(_.supportsPutFull) - val prot_x = fastCheck(_.executable) + val prot_r = fastCheck(_.supportsGet) && !pmp.io.xcpt_ld + val prot_w = fastCheck(_.supportsPutFull) && !pmp.io.xcpt_st + val prot_x = fastCheck(_.executable) && !pmp.io.xcpt_if val cacheable = fastCheck(_.supportsAcquireB) val isSpecial = { val homogeneous = Wire(init = false.B) diff --git a/src/main/scala/tile/Core.scala b/src/main/scala/tile/Core.scala index 66068474..7646ce20 100644 --- a/src/main/scala/tile/Core.scala +++ b/src/main/scala/tile/Core.scala @@ -43,7 +43,7 @@ trait HasCoreParameters extends HasTileParameters { val coreInstBits = coreParams.instBits val coreInstBytes = coreInstBits/8 - val coreDataBits = xLen + val coreDataBits = xLen max fLen val coreDataBytes = coreDataBits/8 val coreDCacheReqTagBits = 6