Simplify pmpcfg encoding

This commit is contained in:
Samuel Lindemer 2021-05-27 14:34:51 +02:00
parent a5f66623b7
commit 6471014131
2 changed files with 86 additions and 60 deletions

View File

@ -1147,6 +1147,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
val readEnable = readInstruction && !arbitration.isStuck
csrMapping.hazardFree := !blockedBySideEffects
val READDATASIGNAL = csrMapping.readDataSignal
val readToWriteData = CombInit(readData)
writeData := (if(noCsrAlu) writeSrc else input(INSTRUCTION)(13).mux(
False -> writeSrc,

View File

@ -11,6 +11,7 @@ import vexriscv.plugin.MemoryTranslatorPort.{_}
import spinal.core._
import spinal.lib._
import spinal.lib.fsm._
import javax.net.ssl.TrustManager
/* Each 32-bit pmpcfg# register contains four 8-bit configuration sections.
* These section numbers contain flags which apply to regions defined by the
@ -121,20 +122,17 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend
val privilegeService = pipeline.service(classOf[PrivilegeService])
val pmpaddr = Mem(UInt(xlen bits), regions)
val pmpcfg = Reg(Bits(8 * regions bits)) init(0)
val base, mask = Mem(UInt(xlen - grain bits), regions)
val cfgRegion = pmpcfg.subdivideIn(8 bits)
val cfgRegister = pmpcfg.subdivideIn(xlen bits)
val lockMask = Reg(Bits(4 bits)) init(B"4'0")
val pmpcfg = Vector.fill(regions)(Reg(Bits(8 bits)) init(0))
val base, mask = Vector.fill(regions)(Reg(UInt(xlen - grain bits)))
object PMPCFG extends Stageable(Bool)
object PMPADDR extends Stageable(Bool)
// object PMPCFG extends Stageable(Bool)
// object PMPADDR extends Stageable(Bool)
decode plug new Area {
import decode._
insert(PMPCFG) := input(INSTRUCTION)(31 downto 24) === 0x3a
insert(PMPADDR) := input(INSTRUCTION)(31 downto 24) === 0x3b
}
// decode plug new Area {
// import decode._
// insert(PMPCFG) := input(INSTRUCTION)(31 downto 24) === 0x3a
// insert(PMPADDR) := input(INSTRUCTION)(31 downto 24) === 0x3b
// }
execute plug new Area {
import execute._
@ -171,64 +169,91 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend
val base13 = base(U"4'xd")
val base14 = base(U"4'xe")
val base15 = base(U"4'xf")
val pmpcfg0 = pmpcfg(0)
val pmpcfg1 = pmpcfg(1)
val pmpcfg2 = pmpcfg(2)
val pmpcfg3 = pmpcfg(3)
val pmpcfg4 = pmpcfg(4)
val pmpcfg5 = pmpcfg(5)
val pmpcfg6 = pmpcfg(6)
val pmpcfg7 = pmpcfg(7)
val pmpcfg8 = pmpcfg(8)
val pmpcfg9 = pmpcfg(9)
val pmpcfg10 = pmpcfg(10)
val pmpcfg11 = pmpcfg(11)
val pmpcfg12 = pmpcfg(12)
val pmpcfg13 = pmpcfg(13)
val pmpcfg14 = pmpcfg(14)
val pmpcfg15 = pmpcfg(15)
val csrAddress = input(INSTRUCTION)(csrRange)
val pmpIndex = csrAddress(log2Up(regions) - 1 downto 0).asUInt
val pmpIndexReg = Reg(UInt(log2Up(regions) bits))
val pmpSelect = pmpIndex(log2Up(regions) - 3 downto 0)
val writeData = csrService.writeData()
val enable = RegInit(False)
for (i <- 0 until regions) csrService.allow(0x3b0 + i)
for (i <- 0 until (regions / 4)) csrService.allow(0x3a0 + i)
val pmpSelectReg = Reg(UInt(log2Up(regions) - 2 bits))
val pmpAccessCfg = RegInit(False)
val pmpAccessAddr = RegInit(False)
val writeData = Reg(Bits(xlen bits))
val pending = RegInit(False)
val hazardFree = csrService.isHazardFree()
csrService.duringAnyRead {
when (input(PMPCFG)) { csrService.readData().assignFromBits(cfgRegister(pmpSelect)) }
when (input(PMPADDR)) { csrService.readData() := pmpaddr.readAsync(pmpIndex).asBits }
def reconfigure() = {
pending := True
writeData := csrService.writeData()
pmpIndexReg := pmpIndex
pmpSelectReg := pmpSelect
pmpAccessCfg := input(INSTRUCTION)(31 downto 24) === 0x3a
pmpAccessAddr := input(INSTRUCTION)(31 downto 24) === 0x3b
}
csrService.duringAnyWrite {
when (input(PMPCFG) | input(PMPADDR)) { enable := True }
for (i <- 0 until regions) {
csrService.onRead(0x3b0 + i) {
csrService.readData() := pmpaddr.readAsync(pmpIndex).asBits
}
csrService.onWrite(0x3b0 + i) { reconfigure() }
}
for (i <- 0 until (regions / 4)) {
csrService.onRead(0x3a0 + i) {
csrService.readData() := pmpcfg(i * 4 + 3) ## pmpcfg(i * 4 + 2) ## pmpcfg(i * 4 + 1) ## pmpcfg(i * 4)
}
csrService.onWrite(0x3a0 + i) { reconfigure() }
}
val writer = new Area {
when (enable & csrService.isHazardFree()) {
when (input(PMPCFG)) {
switch(pmpSelect) {
for (i <- 0 until (regions / 4)) {
is(i) {
for (j <- Range(0, xlen, 8)) {
val bitRange = j + xlen * i + lBit downto j + xlen * i
val overwrite = writeData.subdivideIn(8 bits)(j / 8)
val locked = cfgRegister(i).subdivideIn(8 bits)(j / 8)(lBit)
lockMask(j / 8) := locked
when (~locked) {
pmpcfg(bitRange).assignFromBits(overwrite)
}
}
}
when (pending) {
arbitration.haltItself := True
when (hazardFree & pmpAccessCfg) {
val overwrite = writeData.subdivideIn(8 bits)
for (i <- 0 until 4) {
when (~pmpcfg(pmpSelectReg @@ U(i, 2 bits))(lBit)) {
pmpcfg(pmpSelectReg @@ U(i, 2 bits)).assignFromBits(overwrite(i))
}
}
}
}
val locked = cfgRegion(pmpIndex)(lBit)
pmpaddr.write(pmpIndex, writeData.asUInt, ~locked & input(PMPADDR) & enable & csrService.isHazardFree())
val locked = pmpcfg(pmpIndex)(lBit)
pmpaddr.write(pmpIndex, writeData.asUInt, ~locked & pmpAccessAddr & pending & hazardFree)
}
val controller = new StateMachine {
val enable = RegInit(False)
val counter = Reg(UInt(log2Up(regions) bits)) init(0)
val stateIdle : State = new State with EntryPoint {
onEntry {
lockMask := B"4'x0"
enable := False
counter := 0
}
onExit (arbitration.haltItself := True)
onExit {
enable := True
pending := False
arbitration.haltItself := True
}
whenIsActive {
when (enable & csrService.isHazardFree()) {
when (input(PMPCFG)) {
when (pending & hazardFree) {
when (pmpAccessCfg) {
goto(stateCfg)
}.elsewhen (input(PMPADDR)) {
}.elsewhen (pmpAccessAddr) {
goto(stateAddr)
}
}
@ -236,7 +261,7 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend
}
val stateCfg : State = new State {
onEntry (counter := pmpIndex(log2Up(regions) - 3 downto 0) @@ U"2'00")
onEntry (counter := pmpSelectReg @@ U(0, 2 bits))
whenIsActive {
counter := counter + 1
when (counter(1 downto 0) === 3) {
@ -248,23 +273,17 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend
}
val stateAddr : State = new State {
onEntry (counter := pmpIndex)
onEntry (counter := pmpIndexReg)
whenIsActive (goto(stateIdle))
}
when (input(PMPCFG)) {
setter.io.addr := pmpaddr(counter)
when (pmpAccessAddr) {
setter.io.addr := writeData.asUInt
} otherwise {
when (counter === pmpIndex) {
setter.io.addr := writeData.asUInt
} otherwise {
setter.io.addr := pmpaddr(counter)
}
setter.io.addr := pmpaddr.readAsync(counter)
}
when (enable & csrService.isHazardFree() &
((input(PMPCFG) & ~lockMask(counter(1 downto 0))) |
(input(PMPADDR) & ~cfgRegion(counter)(lBit)))) {
when (enable & ~pmpcfg(counter)(lBit)) {
base(counter) := setter.io.base
mask(counter) := setter.io.mask
}
@ -272,13 +291,18 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend
}
pipeline plug new Area {
def getHits(address : UInt) = {
(0 until regions).map(i =>
((address & mask(U(i, log2Up(regions) bits))) === base(U(i, log2Up(regions) bits))) &
(cfgRegion(i)(lBit) | ~privilegeService.isMachine()) & cfgRegion(i)(aBits) === NAPOT
(pmpcfg(i)(lBit) | ~privilegeService.isMachine()) & pmpcfg(i)(aBits) === NAPOT
)
}
def getPermission(hits : IndexedSeq[Bool], bit : Int) = {
(hits zip pmpcfg).map({ case (i, cfg) => i & cfg(bit) }).orR
}
val dGuard = new Area {
val address = dPort.bus.cmd(0).virtualAddress
dPort.bus.rsp.physicalAddress := address
@ -295,8 +319,8 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend
dPort.bus.rsp.allowRead := privilegeService.isMachine()
dPort.bus.rsp.allowWrite := privilegeService.isMachine()
} otherwise {
dPort.bus.rsp.allowRead := (hits zip cfgRegion).map({ case (i, cfg) => i & cfg(rBit) }).orR
dPort.bus.rsp.allowWrite := (hits zip cfgRegion).map({ case (i, cfg) => i & cfg(wBit) }).orR
dPort.bus.rsp.allowRead := getPermission(hits, rBit)
dPort.bus.rsp.allowWrite := getPermission(hits, wBit)
}
}
@ -316,7 +340,7 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend
when(~hits.orR) {
iPort.bus.rsp.allowExecute := privilegeService.isMachine()
} otherwise {
iPort.bus.rsp.allowExecute := (hits zip cfgRegion).map({ case (i, cfg) => i & cfg(xBit) }).orR
iPort.bus.rsp.allowExecute := getPermission(hits, xBit)
}
}
}