Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PMP support #34

Merged
merged 10 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ext/riscv-isa-sim
61 changes: 56 additions & 5 deletions src/main/scala/vexiiriscv/Param.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import vexiiriscv.decode.DecoderPlugin
import vexiiriscv.execute._
import vexiiriscv.execute.lsu._
import vexiiriscv.fetch.{FetchCachelessPlugin, FetchL1Plugin, PrefetcherNextLinePlugin}
import vexiiriscv.memory.{MmuPortParameter, MmuSpec, MmuStorageLevel, MmuStorageParameter}
import vexiiriscv.memory.{MmuPortParameter, MmuSpec, MmuStorageLevel, MmuStorageParameter, PmpParam, PmpPlugin, PmpPortParameter}
import vexiiriscv.misc._
import vexiiriscv.prediction.{LearnCmd, LearnPlugin}
import vexiiriscv.riscv.{FloatRegFile, IntRegFile}
Expand Down Expand Up @@ -165,6 +165,49 @@ class ParamSimple(){
priority = 0
)

var pmpParam = new PmpParam(
pmpSize = 0,
granularity = 4096,
withTor = true,
withNapot = true
)

var fetchNoL1PmpParam = new PmpPortParameter(
napotMatchAt = 0,
napotHitsAt = 1,
torCmpAt = 0,
torHitsAt = 1,
hitsAt = 1,
rspAt = 1
)

var lsuNoL1PmpParam = new PmpPortParameter(
napotMatchAt = 0,
napotHitsAt = 0,
torCmpAt = 0,
torHitsAt = 0,
hitsAt = 0,
rspAt = 0
)

var fetchL1PmpParam = new PmpPortParameter(
napotMatchAt = 1,
napotHitsAt = 1,
torCmpAt = 1,
torHitsAt = 2,
hitsAt = 2,
rspAt = 2
)

var lsuL1PmpParam = new PmpPortParameter(
napotMatchAt = 1,
napotHitsAt = 1,
torCmpAt = 1,
torHitsAt = 2,
hitsAt = 2,
rspAt = 2
)

var lsuTsp = MmuStorageParameter(
levels = List(
MmuStorageLevel(
Expand Down Expand Up @@ -472,6 +515,7 @@ class ParamSimple(){
opt[Unit]("with-dispatcher-buffer") action { (v, c) => withDispatcherBuffer = true }
opt[Unit]("with-supervisor") action { (v, c) => privParam.withSupervisor = true; privParam.withUser = true; withMmu = true }
opt[Unit]("with-user") action { (v, c) => privParam.withUser = true }
opt[Unit]("without-mmu") action { (v, c) => withMmu = false }
opt[Unit]("without-mul") action { (v, c) => withMul = false }
opt[Unit]("without-div") action { (v, c) => withDiv = false }
opt[Unit]("with-mul") action { (v, c) => withMul = true }
Expand Down Expand Up @@ -524,9 +568,10 @@ class ParamSimple(){
opt[Unit]("with-boot-mem-init") action { (v, c) => bootMemClear = true }
opt[Int]("physical-width") action { (v, c) => physicalWidth = v }
opt[Unit]("mul-keep-src") action { (v, c) => mulKeepSrc = true }
opt[Unit]("mmu-sync-read") action { (v, c) =>
withMmuSyncRead()
}
opt[Unit]("mmu-sync-read") action { (v, c) => withMmuSyncRead() }
opt[Int]("pmp-size") action { (v, c) => pmpParam.pmpSize = v }
opt[Int]("pmp-granularity") action { (v, c) => pmpParam.granularity = v }
opt[Unit]("pmp-tor-disable") action { (v, c) => pmpParam.withTor = false }
}

def plugins(hartId : Int = 0) = pluginsArea(hartId).plugins
Expand All @@ -545,6 +590,8 @@ class ParamSimple(){
)
}

plugins += new PmpPlugin(pmpParam)

plugins += new misc.PipelineBuilderPlugin()
plugins += new schedule.ReschedulePlugin()

Expand Down Expand Up @@ -588,6 +635,7 @@ class ParamSimple(){
forkAt = fetchForkAt,
joinAt = fetchForkAt+1, //You can for instance allow the external memory to have more latency by changing this
wordWidth = fetchMemDataWidth,
pmpPortParameter = fetchNoL1PmpParam,
translationStorageParameter = fetchTsp,
translationPortParameter = withMmu match {
case false => null
Expand Down Expand Up @@ -615,7 +663,8 @@ class ParamSimple(){
translationPortParameter = withMmu match {
case false => null
case true => fetchTpp
}
},
pmpPortParameter = fetchL1PmpParam
)

fetchL1Prefetch match {
Expand Down Expand Up @@ -682,6 +731,7 @@ class ParamSimple(){
forkAt = lsuForkAt+0,
joinAt = lsuForkAt+1,
wbAt = 2, //TODO
pmpPortParameter = lsuNoL1PmpParam,
translationStorageParameter = lsuTsp,
translationPortParameter = withMmu match {
case false => null
Expand All @@ -701,6 +751,7 @@ class ParamSimple(){
storeBufferSlots = lsuStoreBufferSlots,
storeBufferOps = lsuStoreBufferOps,
softwarePrefetch = lsuSoftwarePrefetch,
pmpPortParameter = fetchL1PmpParam,
translationStorageParameter = lsuTsp,
translationPortParameter = withMmu match {
case false => null
Expand Down
20 changes: 17 additions & 3 deletions src/main/scala/vexiiriscv/execute/lsu/LsuCachelessPlugin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import spinal.core.fiber.{Handle, Retainer}
import spinal.core.sim.SimDataPimper
import vexiiriscv.decode.Decode
import vexiiriscv.fetch.FetchPipelinePlugin
import vexiiriscv.memory.{AddressTranslationPortUsage, AddressTranslationService, DBusAccessService, PmaLoad, PmaLogic, PmaPort, PmaStore}
import vexiiriscv.memory.{AddressTranslationPortUsage, AddressTranslationService, DBusAccessService, PmaLoad, PmaLogic, PmaPort, PmaStore, PmpService}
import vexiiriscv.misc.{AddressToMask, LsuTriggerService, PerformanceCounterService, TrapArg, TrapReason, TrapService}
import vexiiriscv.riscv.Riscv.{FLEN, LSLEN, XLEN}
import spinal.lib.misc.pipeline._
Expand All @@ -27,6 +27,7 @@ class LsuCachelessPlugin(var layer : LaneLayer,
var withSpeculativeLoadFlush : Boolean, //WARNING, the fork cmd may be flushed out of existance before firing if any plugin doesn't flush from the first cycle after !freeze
var translationStorageParameter: Any,
var translationPortParameter: Any,
var pmpPortParameter : Any,
var addressAt: Int = 0,
var triggerAt: Int = 0,
var pmaAt : Int = 0,
Expand Down Expand Up @@ -55,9 +56,10 @@ class LsuCachelessPlugin(var layer : LaneLayer,
val fpwbp = host.findOption[WriteBackPlugin](p => p.lane == layer.lane && p.rf == FloatRegFile)
val srcp = host.find[SrcPlugin](_.layer == layer)
val ats = host[AddressTranslationService]
val ps = host[PmpService]
val ts = host[TrapService]
val ss = host[ScheduleService]
val buildBefore = retains(elp.pipelineLock, ats.portsLock)
val buildBefore = retains(elp.pipelineLock, ats.portsLock, ps.portsLock)
val atsStorageLock = retains(ats.storageLock)
val retainer = retains(List(elp.uopLock, srcp.elaborationLock, ifp.elaborationLock, ts.trapLock, ss.elaborationLock) ++ fpwbp.map(_.elaborationLock))
awaitBuild()
Expand Down Expand Up @@ -138,6 +140,8 @@ class LsuCachelessPlugin(var layer : LaneLayer,
}
}



val onAddress = new addressCtrl.Area{
val RAW_ADDRESS = insert(srcp.ADD_SUB.asUInt)

Expand All @@ -152,6 +156,16 @@ class LsuCachelessPlugin(var layer : LaneLayer,
val MISS_ALIGNED = insert((1 to log2Up(LSLEN / 8)).map(i => SIZE === i && RAW_ADDRESS(i - 1 downto 0) =/= 0).orR) //TODO remove from speculLoad and handle it with trap
}
val tpk = onAddress.translationPort.keys
val pmpPort = ps.createPmpPort(
nodes = List.tabulate(forkAt+1)(elp.execute(_).down),
physicalAddress = tpk.TRANSLATED,
forceCheck = _ => False,
read = _(LOAD),
write = _(STORE),
execute = _ => False,
portSpec = pmpPortParameter,
storageSpec = null
)

val onPma = new elp.Execute(pmaAt){
val port = new PmaPort(Global.PHYSICAL_WIDTH, (0 to log2Up(Riscv.LSLEN / 8)).map(1 << _), List(PmaLoad, PmaStore))
Expand Down Expand Up @@ -233,7 +247,7 @@ class LsuCachelessPlugin(var layer : LaneLayer,
trapPort.code := TrapReason.REDO
}

when(tpk.ACCESS_FAULT || onPma.RSP.fault) {
when(tpk.ACCESS_FAULT || onPma.RSP.fault || pmpPort.ACCESS_FAULT) {
skip := True
trapPort.exception := True
trapPort.code := CSR.MCAUSE_ENUM.LOAD_ACCESS_FAULT
Expand Down
30 changes: 21 additions & 9 deletions src/main/scala/vexiiriscv/execute/lsu/LsuPlugin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import spinal.lib.misc.plugin.FiberPlugin
import spinal.lib.system.tag.PmaRegion
import vexiiriscv.decode.Decode
import vexiiriscv.decode.Decode.UOP
import vexiiriscv.memory.{AddressTranslationPortUsage, AddressTranslationService, DBusAccessService, PmaLoad, PmaLogic, PmaPort, PmaStore}
import vexiiriscv.memory.{AddressTranslationPortUsage, AddressTranslationService, DBusAccessService, PmaLoad, PmaLogic, PmaPort, PmaStore, PmpService}
import vexiiriscv.misc.{AddressToMask, LsuTriggerService, PerformanceCounterService, TrapArg, TrapReason, TrapService}
import vexiiriscv.riscv.Riscv.{FLEN, LSLEN, XLEN}
import vexiiriscv.riscv._
Expand Down Expand Up @@ -48,6 +48,7 @@ class LsuPlugin(var layer : LaneLayer,
var withRva : Boolean,
var translationStorageParameter: Any,
var translationPortParameter: Any,
var pmpPortParameter : Any,
var softwarePrefetch: Boolean,
var addressAt: Int = 0,
var triggerAt : Int = 1,
Expand Down Expand Up @@ -95,12 +96,13 @@ class LsuPlugin(var layer : LaneLayer,
val ifp = host.find[IntFormatPlugin](_.lane == layer.lane)
val srcp = host.find[SrcPlugin](_.layer == layer)
val ats = host[AddressTranslationService]
val ps = host[PmpService]
val ts = host[TrapService]
val ss = host[ScheduleService]
val pcs = host.get[PerformanceCounterService]
val hp = host.get[PrefetcherPlugin]
val fpwbp = host.findOption[WriteBackPlugin](p => p.lane == layer.lane && p.rf == FloatRegFile)
val buildBefore = retains(elp.pipelineLock, ats.portsLock)
val buildBefore = retains(elp.pipelineLock, ats.portsLock, ps.portsLock)
val earlyLock = retains(List(ats.storageLock) ++ pcs.map(_.elaborationLock).toList)
val retainer = retains(List(elp.uopLock, srcp.elaborationLock, ifp.elaborationLock, ts.trapLock, ss.elaborationLock) ++ fpwbp.map(_.elaborationLock))
awaitBuild()
Expand Down Expand Up @@ -437,7 +439,16 @@ class LsuPlugin(var layer : LaneLayer,

val tpk = onAddress0.translationPort.keys


val pmpPort = ps.createPmpPort(
nodes = List.tabulate(ctrlAt+1)(elp.execute(_).down),
physicalAddress = tpk.TRANSLATED,
forceCheck = _(FROM_ACCESS),
read = _(LOAD),
write = _(STORE),
execute = _ => False,
portSpec = pmpPortParameter,
storageSpec = null
)

val onAddress1 = new elp.Execute(addressAt+1) {
l1.PHYSICAL_ADDRESS := tpk.TRANSLATED
Expand Down Expand Up @@ -626,7 +637,7 @@ class LsuPlugin(var layer : LaneLayer,
trapPort.code.assignDontCare()
trapPort.arg.allowOverride() := 0

val accessFault = (onPma.CACHED_RSP.fault).mux[Bool](io.rsp.valid && io.rsp.error || l1.ATOMIC, l1.FAULT)
val accessFault = (onPma.CACHED_RSP.fault).mux[Bool](io.rsp.valid && io.rsp.error || l1.ATOMIC, l1.FAULT) || pmpPort.ACCESS_FAULT
when(accessFault) {
lsuTrap := True
trapPort.exception := True
Expand Down Expand Up @@ -745,12 +756,12 @@ class LsuPlugin(var layer : LaneLayer,
abords += !l1.FLUSH && onPma.CACHED_RSP.fault
abords += FROM_LSU && (!isValid || isCancel)
abords += mmuNeeded && MMU_FAILURE
if(withStoreBuffer) abords += wb.loadHazard || !FROM_WB && fenceTrap.valid
if(withStoreBuffer) abords += wb.loadHazard || !FROM_WB && fenceTrap.valid || wb.selfHazard

skipsWrite += l1.MISS || l1.MISS_UNIQUE
skipsWrite += l1.FAULT
skipsWrite += l1.FAULT || pmpPort.ACCESS_FAULT
skipsWrite += preCtrl.MISS_ALIGNED
skipsWrite += FROM_LSU && onTrigger.HIT
skipsWrite += FROM_LSU && (onTrigger.HIT || pmpPort.ACCESS_FAULT)
skipsWrite += FROM_PREFETCH
if(Riscv.RVA) skipsWrite += l1.ATOMIC && !l1.LOAD && scMiss
if (withStoreBuffer) skipsWrite += wb.selfHazard || !FROM_WB && wb.hit
Expand All @@ -776,12 +787,13 @@ class LsuPlugin(var layer : LaneLayer,
}
}

//TODO what happen if used for IO access ?
val access = dbusAccesses.nonEmpty generate new Area {
assert(dbusAccesses.size == 1)
val rsp = dbusAccesses.head.rsp
rsp.valid := l1.SEL && FROM_ACCESS && !elp.isFreezed()
rsp.data := loadData.RESULT.resized //loadData.RESULT instead of l1.READ_DATA (because it rv32fd
rsp.error := l1.FAULT
rsp.data := loadData.RESULT.resized //loadData.RESULT instead of l1.READ_DATA (because it rv32fd)
rsp.error := l1.FAULT || pmpPort.ACCESS_FAULT
rsp.redo := traps.l1Failed
rsp.waitSlot := 0
rsp.waitAny := False //TODO
Expand Down
19 changes: 16 additions & 3 deletions src/main/scala/vexiiriscv/fetch/FetchCachelessPlugin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import spinal.lib.bus.tilelink.DebugId
import spinal.lib.system.tag.{MappedTransfers, PmaRegion}
import vexiiriscv._
import vexiiriscv.Global._
import vexiiriscv.memory.{AddressTranslationPortUsage, AddressTranslationService, PmaLoad, PmaLogic, PmaPort}
import vexiiriscv.memory.{AddressTranslationPortUsage, AddressTranslationService, PmaLoad, PmaLogic, PmaPort, PmpService}
import vexiiriscv.misc.{PerformanceCounterService, TrapArg, TrapReason, TrapService}
import vexiiriscv.riscv.CSR

Expand All @@ -27,6 +27,7 @@ object FetchCachelessPlugin{
class FetchCachelessPlugin(var wordWidth : Int,
var translationStorageParameter: Any,
var translationPortParameter: Any,
var pmpPortParameter : Any,
var addressAt: Int = 0,
var pmaAt: Int = 0,
var forkAt : Int = 0,
Expand All @@ -36,9 +37,10 @@ class FetchCachelessPlugin(var wordWidth : Int,

val logic = during setup new Area{
val pp = host[FetchPipelinePlugin]
val ps = host[PmpService]
val ts = host[TrapService]
val ats = host[AddressTranslationService]
val buildBefore = retains(pp.elaborationLock, ats.portsLock)
val buildBefore = retains(pp.elaborationLock, ats.portsLock, ps.portsLock)
val atsStorageLock = retains(ats.storageLock)
val trapLock = ts.trapLock()
awaitBuild()
Expand Down Expand Up @@ -93,6 +95,17 @@ class FetchCachelessPlugin(var wordWidth : Int,
}
val tpk = onAddress.translationPort.keys

val pmpPort = ps.createPmpPort(
nodes = List.tabulate(joinAt+1)(pp.fetch(_).down),
physicalAddress = tpk.TRANSLATED,
forceCheck = _ => False,
read = _ => False,
write = _ => False,
execute = _ => True,
portSpec = pmpPortParameter,
storageSpec = null
)

val onPma = new pp.Fetch(pmaAt) {
val port = new PmaPort(Global.PHYSICAL_WIDTH, List(Fetch.WORD_WIDTH / 8), List(PmaLoad))
port.cmd.address := tpk.TRANSLATED
Expand Down Expand Up @@ -152,7 +165,7 @@ class FetchCachelessPlugin(var wordWidth : Int,
trapPort.code.assignDontCare()
trapPort.arg.allowOverride() := 0

when(rsp.error || fork.PMA_FAULT){
when(rsp.error || fork.PMA_FAULT || pmpPort.ACCESS_FAULT){
TRAP := True
trapPort.exception := True
trapPort.code := CSR.MCAUSE_ENUM.INSTRUCTION_ACCESS_FAULT
Expand Down
Loading
Loading