Flush pipeline after PMP CSR writes

This commit is contained in:
Samuel Lindemer 2020-11-25 12:28:16 +01:00
parent 97fe279f7b
commit 2d0ebf1ef5
2 changed files with 51 additions and 32 deletions

View File

@ -40,7 +40,7 @@ object GenZephyr extends App{
), ),
new PmpPlugin( new PmpPlugin(
regions = 16, regions = 16,
ioRange = _(31 downto 28) === 0xF ioRange = _(31 downto 28) === 0xf
), ),
new DecoderSimplePlugin( new DecoderSimplePlugin(
catchIllegalInstruction = true catchIllegalInstruction = true

View File

@ -65,30 +65,32 @@ import scala.collection.mutable.ArrayBuffer
case class PmpRegister() extends Area { case class PmpRegister() extends Area {
// Addressing options // Addressing options (TOR not supported)
def TOR = 1
def NA4 = 2 def NA4 = 2
def NAPOT = 3 def NAPOT = 3
// Software-accessible CSR interface
val csr = new Area { val csr = new Area {
val r, w, x, l = RegInit(False) val r, w, x = Reg(Bool)
val l = RegInit(False)
val a = Reg(UInt(2 bits)) init(0) val a = Reg(UInt(2 bits)) init(0)
val addr = Reg(UInt(32 bits)) val addr = Reg(UInt(32 bits))
} }
// Active region bounds and permissions (internal)
val region = new Area { val region = new Area {
val r, w, x = Reg(Bool) val r, w, x = Reg(Bool)
val l = RegInit(False) val lock, valid = RegInit(False)
val start = Reg(UInt(32 bits)) val start, end = Reg(UInt(32 bits))
val end = Reg(UInt(32 bits))
val valid = RegInit(False)
} }
// Internal CSR state is locked until reset if L-bit set // Internal PMP state is locked until reset once the L-bit is set.
when(~region.l) { when(~region.lock) {
region.r := csr.r region.r := csr.r
region.w := csr.w region.w := csr.w
region.x := csr.x region.x := csr.x
region.l := csr.l region.lock := csr.l
switch(csr.a) { switch(csr.a) {
is(NA4) { is(NA4) {
@ -123,6 +125,7 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv]
val pmps = ArrayBuffer[PmpRegister]() val pmps = ArrayBuffer[PmpRegister]()
val portsInfo = ArrayBuffer[ProtectedMemoryTranslatorPort]() val portsInfo = ArrayBuffer[ProtectedMemoryTranslatorPort]()
var redoInterface : Flow[UInt] = null
override def newTranslationPort(priority : Int, args : Any): MemoryTranslatorBus = { override def newTranslationPort(priority : Int, args : Any): MemoryTranslatorBus = {
val port = ProtectedMemoryTranslatorPort(MemoryTranslatorBus()) val port = ProtectedMemoryTranslatorPort(MemoryTranslatorBus())
@ -131,35 +134,51 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv]
} }
override def build(pipeline: VexRiscv): Unit = { override def build(pipeline: VexRiscv): Unit = {
import pipeline._
import pipeline.config._ import pipeline.config._
import pipeline._
import Riscv._ import Riscv._
val csrService = pipeline.service(classOf[CsrInterface]) val csrService = pipeline.service(classOf[CsrInterface])
val privilegeService = pipeline.service(classOf[PrivilegeService]) val privilegeService = pipeline.service(classOf[PrivilegeService])
var pcManagerService = pipeline.service(classOf[JumpService])
// Flush proceeding instructions and replay them after any CSR write.
redoInterface = pcManagerService.createJumpInterface(pipeline.execute, -1)
redoInterface.valid := False
redoInterface.payload := decode.input(PC)
val core = pipeline plug new Area { val core = pipeline plug new Area {
redoInterface.valid := False
// Instantiate pmpaddr0 ... pmpaddr# CSRs. // Instantiate pmpaddr0 ... pmpaddr# CSRs.
for (n <- 0 until regions) { for (i <- 0 until regions) {
pmps += PmpRegister() pmps += PmpRegister()
csrService.rw(0x3B0 + n, pmps(n).csr.addr) csrService.rw(0x3b0 + i, pmps(i).csr.addr)
csrService.onWrite(0x3b0 + i) {
execute.arbitration.flushNext := True
redoInterface.valid := True
}
} }
// Instantiate pmpcfg0 ... pmpcfg# CSRs. // Instantiate pmpcfg0 ... pmpcfg# CSRs.
for (n <- 0 until (regions / 4)) { for (i <- 0 until (regions / 4)) {
csrService.rw(0x3A0 + n, csrService.rw(0x3a0 + i,
31 -> pmps((n * 4) + 3).csr.l, 23 -> pmps((n * 4) + 2).csr.l, 31 -> pmps((i * 4) + 3).csr.l, 23 -> pmps((i * 4) + 2).csr.l,
15 -> pmps((n * 4) + 1).csr.l, 7 -> pmps((n * 4) ).csr.l, 15 -> pmps((i * 4) + 1).csr.l, 7 -> pmps((i * 4) ).csr.l,
27 -> pmps((n * 4) + 3).csr.a, 26 -> pmps((n * 4) + 3).csr.x, 27 -> pmps((i * 4) + 3).csr.a, 26 -> pmps((i * 4) + 3).csr.x,
25 -> pmps((n * 4) + 3).csr.w, 24 -> pmps((n * 4) + 3).csr.r, 25 -> pmps((i * 4) + 3).csr.w, 24 -> pmps((i * 4) + 3).csr.r,
19 -> pmps((n * 4) + 2).csr.a, 18 -> pmps((n * 4) + 2).csr.x, 19 -> pmps((i * 4) + 2).csr.a, 18 -> pmps((i * 4) + 2).csr.x,
17 -> pmps((n * 4) + 2).csr.w, 16 -> pmps((n * 4) + 2).csr.r, 17 -> pmps((i * 4) + 2).csr.w, 16 -> pmps((i * 4) + 2).csr.r,
11 -> pmps((n * 4) + 1).csr.a, 10 -> pmps((n * 4) + 1).csr.x, 11 -> pmps((i * 4) + 1).csr.a, 10 -> pmps((i * 4) + 1).csr.x,
9 -> pmps((n * 4) + 1).csr.w, 8 -> pmps((n * 4) + 1).csr.r, 9 -> pmps((i * 4) + 1).csr.w, 8 -> pmps((i * 4) + 1).csr.r,
3 -> pmps((n * 4) ).csr.a, 2 -> pmps((n * 4) ).csr.x, 3 -> pmps((i * 4) ).csr.a, 2 -> pmps((i * 4) ).csr.x,
1 -> pmps((n * 4) ).csr.w, 0 -> pmps((n * 4) ).csr.r 1 -> pmps((i * 4) ).csr.w, 0 -> pmps((i * 4) ).csr.r
) )
csrService.onWrite(0x3a0 + i) {
execute.arbitration.flushNext := True
redoInterface.valid := True
}
} }
// Connect memory ports to PMP logic. // Connect memory ports to PMP logic.
@ -168,13 +187,13 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv]
val address = port.bus.cmd.virtualAddress val address = port.bus.cmd.virtualAddress
port.bus.rsp.physicalAddress := address port.bus.rsp.physicalAddress := address
// Only the first matching PMP region is applied. // Only the first matching PMP region applies.
val hits = pmps.map(pmp => pmp.region.valid && val hits = pmps.map(pmp => pmp.region.valid &&
pmp.region.start <= address && pmp.region.start <= address &&
pmp.region.end > address && pmp.region.end > address &&
(pmp.region.l || ~privilegeService.isMachine())) (pmp.region.lock || ~privilegeService.isMachine()))
// M-mode has full access by default. All others have none by default. // M-mode has full access by default, others have none.
when(CountOne(hits) === 0) { when(CountOne(hits) === 0) {
port.bus.rsp.allowRead := privilegeService.isMachine() port.bus.rsp.allowRead := privilegeService.isMachine()
port.bus.rsp.allowWrite := privilegeService.isMachine() port.bus.rsp.allowWrite := privilegeService.isMachine()