diff --git a/ext/NaxSoftware b/ext/NaxSoftware index 4b0d359..f9f2681 160000 --- a/ext/NaxSoftware +++ b/ext/NaxSoftware @@ -1 +1 @@ -Subproject commit 4b0d359a4fe366cf977b07b3aad7deb53c3bdc48 +Subproject commit f9f2681ae03ce28f973d41574996fca5552f9af1 diff --git a/src/main/scala/vexiiriscv/Param.scala b/src/main/scala/vexiiriscv/Param.scala index d07c407..49462e4 100644 --- a/src/main/scala/vexiiriscv/Param.scala +++ b/src/main/scala/vexiiriscv/Param.scala @@ -172,7 +172,25 @@ class ParamSimple(){ withNapot = true ) - var fetchPmpParam = new PmpPortParameter( + 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, @@ -181,7 +199,7 @@ class ParamSimple(){ rspAt = 2 ) - var lsuPmpParam = new PmpPortParameter( + var lsuL1PmpParam = new PmpPortParameter( napotMatchAt = 1, napotHitsAt = 1, torCmpAt = 1, @@ -497,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 } @@ -616,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 @@ -644,7 +664,7 @@ class ParamSimple(){ case false => null case true => fetchTpp }, - pmpPortParameter = fetchPmpParam + pmpPortParameter = fetchL1PmpParam ) fetchL1Prefetch match { @@ -711,6 +731,7 @@ class ParamSimple(){ forkAt = lsuForkAt+0, joinAt = lsuForkAt+1, wbAt = 2, //TODO + pmpPortParameter = lsuNoL1PmpParam, translationStorageParameter = lsuTsp, translationPortParameter = withMmu match { case false => null @@ -730,7 +751,7 @@ class ParamSimple(){ storeBufferSlots = lsuStoreBufferSlots, storeBufferOps = lsuStoreBufferOps, softwarePrefetch = lsuSoftwarePrefetch, - pmpPortParameter = fetchPmpParam, + pmpPortParameter = fetchL1PmpParam, translationStorageParameter = lsuTsp, translationPortParameter = withMmu match { case false => null diff --git a/src/main/scala/vexiiriscv/execute/lsu/LsuCachelessPlugin.scala b/src/main/scala/vexiiriscv/execute/lsu/LsuCachelessPlugin.scala index 8847ff3..2984cf0 100644 --- a/src/main/scala/vexiiriscv/execute/lsu/LsuCachelessPlugin.scala +++ b/src/main/scala/vexiiriscv/execute/lsu/LsuCachelessPlugin.scala @@ -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._ @@ -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, @@ -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() @@ -138,6 +140,8 @@ class LsuCachelessPlugin(var layer : LaneLayer, } } + + val onAddress = new addressCtrl.Area{ val RAW_ADDRESS = insert(srcp.ADD_SUB.asUInt) @@ -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)) @@ -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 diff --git a/src/main/scala/vexiiriscv/fetch/FetchCachelessPlugin.scala b/src/main/scala/vexiiriscv/fetch/FetchCachelessPlugin.scala index bd58d33..09fa109 100644 --- a/src/main/scala/vexiiriscv/fetch/FetchCachelessPlugin.scala +++ b/src/main/scala/vexiiriscv/fetch/FetchCachelessPlugin.scala @@ -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 @@ -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, @@ -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() @@ -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 @@ -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 diff --git a/src/main/scala/vexiiriscv/memory/PmpPlugin.scala b/src/main/scala/vexiiriscv/memory/PmpPlugin.scala index c8f354b..98aec9a 100644 --- a/src/main/scala/vexiiriscv/memory/PmpPlugin.scala +++ b/src/main/scala/vexiiriscv/memory/PmpPlugin.scala @@ -129,7 +129,7 @@ class PmpPlugin(val p : PmpParam) extends FiberPlugin with PmpService{ val isNapot = RegNext(cfg.kind(1)) val isTor = RegNext(cfg.kind === 1) - val napot = Napot(address.dropHigh(1)).dropLow(extraBit.toInt) //TODO drop high ? + val napot = Napot(address.dropHigh(1)).dropLow(extraBit.toInt) if(granularity == 4) when(!cfgNext.kind(0)){ napot.setAll() } val mask = RegNext(napot) diff --git a/src/main/scala/vexiiriscv/tester/TestBench.scala b/src/main/scala/vexiiriscv/tester/TestBench.scala index c334b38..e485692 100644 --- a/src/main/scala/vexiiriscv/tester/TestBench.scala +++ b/src/main/scala/vexiiriscv/tester/TestBench.scala @@ -219,6 +219,7 @@ class TestOptions{ probe.enabled = withProbe probe.trace = false +// delayed(1000){ simFailure() } // Things to enable when we want to collect traces val tracerFile = traceRvlsLog.option(new FileBackend(new File(currentTestPath(), "tracer.log"))) onTrace { diff --git a/src/test/scala/vexiiriscv/tester/Regression.scala b/src/test/scala/vexiiriscv/tester/Regression.scala index 9e8f223..d09b37b 100644 --- a/src/test/scala/vexiiriscv/tester/Regression.scala +++ b/src/test/scala/vexiiriscv/tester/Regression.scala @@ -5,7 +5,7 @@ import spinal.core._ import spinal.core.sim._ import spinal.lib.misc.plugin.Hostable import spinal.lib.misc.test.{AsyncJob, MultithreadedFunSuite} -import vexiiriscv.memory.MmuPlugin +import vexiiriscv.memory.{MmuPlugin, PmpPlugin} import vexiiriscv.misc.{EmbeddedRiscvJtag, PrivilegedPlugin} import vexiiriscv.riscv.Riscv import vexiiriscv.{Global, ParamSimple, VexiiRiscv} @@ -52,6 +52,7 @@ class RegressionSingle(compiled : SimCompiled[VexiiRiscv], val xlen = dut.database(Riscv.XLEN) val priv = dut.host.get[PrivilegedPlugin] val mmu = dut.host.get[MmuPlugin] + val pmp = dut.host.get[PmpPlugin] val rvm = dut.database(Riscv.RVM) val rvc = dut.database(Riscv.RVC) @@ -351,6 +352,7 @@ class RegressionSingle(compiled : SimCompiled[VexiiRiscv], priv.filter(_.p.withSupervisor).foreach(_ => regulars ++= List("supervisor")) if(mmu.nonEmpty) regulars ++= List(s"mmu_sv${if(xlen == 32) 32 else 39}") + if(pmp.get.p.pmpSize > 4 && priv.get.p.withSupervisor) regulars ++= List(s"pmp") if(config.regular) for(name <- regulars){ val args = newArgs() @@ -627,6 +629,7 @@ class Regression extends MultithreadedFunSuite(sys.env.getOrElse("VEXIIRISCV_REG return List("", "--with-rvf", "--with-rvf --with-rvd").randomPick(random) } } + addDim("pmp", List("", "--pmp-size=8")) // addTest(default)