Merge branch 'master' into dev
# Conflicts: # build.sbt # src/main/scala/vexriscv/Riscv.scala # src/main/scala/vexriscv/ip/DataCache.scala # src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala # src/main/scala/vexriscv/plugin/MmuPlugin.scala # src/test/cpp/regression/makefile # src/test/scala/vexriscv/TestIndividualFeatures.scala
This commit is contained in:
commit
6aa6191240
|
@ -283,7 +283,7 @@ Note that sometimes Eclipse needs to be restarted in order to be able to place n
|
|||
|
||||
## Briey SoC
|
||||
As a demonstration, a SoC named Briey is implemented in `src/main/scala/vexriscv/demo/Briey.scala`. This SoC is very similar to
|
||||
the [Pinsec SoC](https://spinalhdl.github.io/SpinalDoc/spinal/lib/pinsec/hardware/):
|
||||
the [Pinsec SoC](https://spinalhdl.github.io/SpinalDoc-RTD/SpinalHDL/Legacy/pinsec/hardware_toplevel.html#):
|
||||
|
||||
![Briey SoC](assets/brieySoc.png?raw=true "")
|
||||
|
||||
|
@ -296,7 +296,7 @@ sbt "runMain vexriscv.demo.Briey"
|
|||
To run the verilator simulation of the Briey SoC, which can then be connected to OpenOCD/GDB, first get these dependencies:
|
||||
|
||||
```sh
|
||||
sudo apt-get install build-essential xorg-dev libudev-dev libts-dev libgl1-mesa-dev libglu1-mesa-dev libasound2-dev libpulse-dev libopenal-dev libogg-dev libvorbis-dev libaudiofile-dev libpng12-dev libfreetype6-dev libusb-dev libdbus-1-dev zlib1g-dev libdirectfb-dev libsdl2-dev
|
||||
sudo apt-get install build-essential xorg-dev libudev-dev libgl1-mesa-dev libglu1-mesa-dev libasound2-dev libpulse-dev libopenal-dev libogg-dev libvorbis-dev libaudiofile-dev libpng12-dev libfreetype6-dev libusb-dev libdbus-1-dev zlib1g-dev libdirectfb-dev libsdl2-dev
|
||||
```
|
||||
|
||||
Then go in `src/test/cpp/briey` and run the simulation with (UART TX is printed in the terminal, VGA is displayed in a GUI):
|
||||
|
@ -412,7 +412,7 @@ Note that VexRiscv can run Linux on both cache full and cache less design.
|
|||
|
||||
A prebuild GCC toolsuite can be found here:
|
||||
|
||||
- https://www.sifive.com/products/tools/ => SiFive GNU Embedded Toolchain
|
||||
- https://www.sifive.com/software/ => Prebuilt RISC‑V GCC Toolchain and Emulator
|
||||
|
||||
The VexRiscvSocSoftware makefiles are expecting to find this prebuild version in /opt/riscv/__contentOfThisPreBuild__
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ regression_random_linux:
|
|||
cd ../..
|
||||
export VEXRISCV_REGRESSION_CONFIG_COUNT=3
|
||||
export VEXRISCV_REGRESSION_CONFIG_LINUX_RATE=1.0
|
||||
export VEXRISCV_REGRESSION_CONFIG_SECURE_RATE = 0.0
|
||||
export VEXRISCV_REGRESSION_FREERTOS_COUNT=1
|
||||
export VEXRISCV_REGRESSION_ZEPHYR_COUNT=2
|
||||
export VEXRISCV_REGRESSION_THREAD_COUNT=1
|
||||
|
@ -24,6 +25,7 @@ regression_random_machine_os:
|
|||
export VEXRISCV_REGRESSION_CONFIG_COUNT=15
|
||||
export VEXRISCV_REGRESSION_CONFIG_LINUX_RATE=0.0
|
||||
export VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE=1.0
|
||||
export VEXRISCV_REGRESSION_CONFIG_SECURE_RATE = 0.0
|
||||
export VEXRISCV_REGRESSION_FREERTOS_COUNT=1
|
||||
export VEXRISCV_REGRESSION_ZEPHYR_COUNT=2
|
||||
export VEXRISCV_REGRESSION_THREAD_COUNT=1
|
||||
|
@ -34,6 +36,7 @@ regression_random_baremetal:
|
|||
export VEXRISCV_REGRESSION_CONFIG_COUNT=40
|
||||
export VEXRISCV_REGRESSION_CONFIG_LINUX_RATE=0.0
|
||||
export VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE=0.0
|
||||
export VEXRISCV_REGRESSION_CONFIG_SECURE_RATE = 0.0
|
||||
export VEXRISCV_REGRESSION_FREERTOS_COUNT=1
|
||||
export VEXRISCV_REGRESSION_ZEPHYR_COUNT=no
|
||||
export VEXRISCV_REGRESSION_THREAD_COUNT=1
|
||||
|
|
|
@ -163,6 +163,7 @@ object Riscv{
|
|||
def UCYCLEH = 0xC80
|
||||
def UTIME = 0xC01 // rdtime
|
||||
def UTIMEH = 0xC81
|
||||
|
||||
def UINSTRET = 0xC02 // UR Machine instructions-retired counter.
|
||||
def UINSTRETH = 0xC82 // UR Upper 32 bits of minstret, RV32I only.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,6 +72,7 @@ case class MemoryTranslatorCmd() extends Bundle{
|
|||
case class MemoryTranslatorRsp(p : MemoryTranslatorBusParameter) extends Bundle{
|
||||
val physicalAddress = UInt(32 bits)
|
||||
val isIoAccess = Bool
|
||||
val isPaging = Bool
|
||||
val allowRead, allowWrite, allowExecute = Bool
|
||||
val exception = Bool
|
||||
val refilling = Bool
|
||||
|
|
|
@ -147,7 +147,8 @@ object BrieyConfig{
|
|||
minstretAccess = CsrAccess.NONE,
|
||||
ecallGen = false,
|
||||
wfiGenAsWait = false,
|
||||
ucycleAccess = CsrAccess.NONE
|
||||
ucycleAccess = CsrAccess.NONE,
|
||||
uinstretAccess = CsrAccess.NONE
|
||||
)
|
||||
),
|
||||
new YamlPlugin("cpu0.yaml")
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
package vexriscv.demo
|
||||
|
||||
import vexriscv.plugin._
|
||||
import vexriscv.ip.{DataCacheConfig, InstructionCacheConfig}
|
||||
import vexriscv.{plugin, VexRiscv, VexRiscvConfig}
|
||||
import spinal.core._
|
||||
|
||||
object GenSecure extends App {
|
||||
def cpu() = new VexRiscv(
|
||||
config = VexRiscvConfig(
|
||||
plugins = List(
|
||||
new IBusCachedPlugin(
|
||||
resetVector = 0x80000000l,
|
||||
prediction = STATIC,
|
||||
config = InstructionCacheConfig(
|
||||
cacheSize = 4096,
|
||||
bytePerLine = 32,
|
||||
wayCount = 1,
|
||||
addressWidth = 32,
|
||||
cpuDataWidth = 32,
|
||||
memDataWidth = 32,
|
||||
catchIllegalAccess = true,
|
||||
catchAccessFault = true,
|
||||
asyncTagMemory = false,
|
||||
twoCycleRam = true,
|
||||
twoCycleCache = true
|
||||
)
|
||||
),
|
||||
new DBusCachedPlugin(
|
||||
config = new DataCacheConfig(
|
||||
cacheSize = 4096,
|
||||
bytePerLine = 32,
|
||||
wayCount = 1,
|
||||
addressWidth = 32,
|
||||
cpuDataWidth = 32,
|
||||
memDataWidth = 32,
|
||||
catchAccessError = true,
|
||||
catchIllegal = true,
|
||||
catchUnaligned = true
|
||||
)
|
||||
),
|
||||
new PmpPlugin(
|
||||
regions = 16,
|
||||
ioRange = _(31 downto 28) === 0xf
|
||||
),
|
||||
new DecoderSimplePlugin(
|
||||
catchIllegalInstruction = true
|
||||
),
|
||||
new RegFilePlugin(
|
||||
regFileReadyKind = plugin.SYNC,
|
||||
zeroBoot = false
|
||||
),
|
||||
new IntAluPlugin,
|
||||
new SrcPlugin(
|
||||
separatedAddSub = false,
|
||||
executeInsertion = true
|
||||
),
|
||||
new FullBarrelShifterPlugin,
|
||||
new HazardSimplePlugin(
|
||||
bypassExecute = true,
|
||||
bypassMemory = true,
|
||||
bypassWriteBack = true,
|
||||
bypassWriteBackBuffer = true,
|
||||
pessimisticUseSrc = false,
|
||||
pessimisticWriteRegFile = false,
|
||||
pessimisticAddressMatch = false
|
||||
),
|
||||
new MulDivIterativePlugin(
|
||||
genMul = true,
|
||||
genDiv = true,
|
||||
mulUnrollFactor = 1,
|
||||
divUnrollFactor = 1
|
||||
),
|
||||
new CsrPlugin(CsrPluginConfig.secure(0x00000020l)),
|
||||
new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
|
||||
new BranchPlugin(
|
||||
earlyBranch = false,
|
||||
catchAddressMisaligned = true
|
||||
),
|
||||
new YamlPlugin("cpu0.yaml")
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
SpinalVerilog(cpu())
|
||||
}
|
|
@ -52,8 +52,8 @@ case class MuraxConfig(coreFrequency : HertzNumber,
|
|||
|
||||
|
||||
object MuraxConfig{
|
||||
def default : MuraxConfig = default(false)
|
||||
def default(withXip : Boolean) = MuraxConfig(
|
||||
def default : MuraxConfig = default(false, false)
|
||||
def default(withXip : Boolean = false, bigEndian : Boolean = false) = MuraxConfig(
|
||||
coreFrequency = 12 MHz,
|
||||
onChipRamSize = 8 kB,
|
||||
onChipRamHexFile = null,
|
||||
|
@ -75,12 +75,14 @@ object MuraxConfig{
|
|||
cmdForkPersistence = withXip, //Required by the Xip controller
|
||||
prediction = NONE,
|
||||
catchAccessFault = false,
|
||||
compressedGen = false
|
||||
compressedGen = false,
|
||||
bigEndian = bigEndian
|
||||
),
|
||||
new DBusSimplePlugin(
|
||||
catchAddressMisaligned = false,
|
||||
catchAccessFault = false,
|
||||
earlyInjection = false
|
||||
earlyInjection = false,
|
||||
bigEndian = bigEndian
|
||||
),
|
||||
new CsrPlugin(CsrPluginConfig.smallest(mtvecInit = if(withXip) 0xE0040020l else 0x80000020l)),
|
||||
new DecoderSimplePlugin(
|
||||
|
@ -214,9 +216,11 @@ case class Murax(config : MuraxConfig) extends Component{
|
|||
dataWidth = 32
|
||||
)
|
||||
|
||||
val bigEndianDBus = config.cpuPlugins.exists(_ match{ case plugin : DBusSimplePlugin => plugin.bigEndian case _ => false})
|
||||
|
||||
//Arbiter of the cpu dBus/iBus to drive the mainBus
|
||||
//Priority to dBus, !! cmd transactions can change on the fly !!
|
||||
val mainBusArbiter = new MuraxMasterArbiter(pipelinedMemoryBusConfig)
|
||||
val mainBusArbiter = new MuraxMasterArbiter(pipelinedMemoryBusConfig, bigEndianDBus)
|
||||
|
||||
//Instanciate the CPU
|
||||
val cpu = new VexRiscv(
|
||||
|
@ -258,7 +262,8 @@ case class Murax(config : MuraxConfig) extends Component{
|
|||
val ram = new MuraxPipelinedMemoryBusRam(
|
||||
onChipRamSize = onChipRamSize,
|
||||
onChipRamHexFile = onChipRamHexFile,
|
||||
pipelinedMemoryBusConfig = pipelinedMemoryBusConfig
|
||||
pipelinedMemoryBusConfig = pipelinedMemoryBusConfig,
|
||||
bigEndian = bigEndianDBus
|
||||
)
|
||||
mainBusMapping += ram.io.bus -> (0x80000000l, onChipRamSize)
|
||||
|
||||
|
|
|
@ -10,10 +10,10 @@ import spinal.lib._
|
|||
import spinal.lib.bus.simple._
|
||||
import vexriscv.plugin.{DBusSimpleBus, IBusSimpleBus}
|
||||
|
||||
class MuraxMasterArbiter(pipelinedMemoryBusConfig : PipelinedMemoryBusConfig) extends Component{
|
||||
class MuraxMasterArbiter(pipelinedMemoryBusConfig : PipelinedMemoryBusConfig, bigEndian : Boolean = false) extends Component{
|
||||
val io = new Bundle{
|
||||
val iBus = slave(IBusSimpleBus(null))
|
||||
val dBus = slave(DBusSimpleBus())
|
||||
val dBus = slave(DBusSimpleBus(bigEndian))
|
||||
val masterBus = master(PipelinedMemoryBus(pipelinedMemoryBusConfig))
|
||||
}
|
||||
|
||||
|
@ -21,11 +21,7 @@ class MuraxMasterArbiter(pipelinedMemoryBusConfig : PipelinedMemoryBusConfig) ex
|
|||
io.masterBus.cmd.write := io.dBus.cmd.valid && io.dBus.cmd.wr
|
||||
io.masterBus.cmd.address := io.dBus.cmd.valid ? io.dBus.cmd.address | io.iBus.cmd.pc
|
||||
io.masterBus.cmd.data := io.dBus.cmd.data
|
||||
io.masterBus.cmd.mask := io.dBus.cmd.size.mux(
|
||||
0 -> B"0001",
|
||||
1 -> B"0011",
|
||||
default -> B"1111"
|
||||
) |<< io.dBus.cmd.address(1 downto 0)
|
||||
io.masterBus.cmd.mask := io.dBus.genMask(io.dBus.cmd)
|
||||
io.iBus.cmd.ready := io.masterBus.cmd.ready && !io.dBus.cmd.valid
|
||||
io.dBus.cmd.ready := io.masterBus.cmd.ready
|
||||
|
||||
|
@ -53,7 +49,7 @@ class MuraxMasterArbiter(pipelinedMemoryBusConfig : PipelinedMemoryBusConfig) ex
|
|||
}
|
||||
|
||||
|
||||
case class MuraxPipelinedMemoryBusRam(onChipRamSize : BigInt, onChipRamHexFile : String, pipelinedMemoryBusConfig : PipelinedMemoryBusConfig) extends Component{
|
||||
case class MuraxPipelinedMemoryBusRam(onChipRamSize : BigInt, onChipRamHexFile : String, pipelinedMemoryBusConfig : PipelinedMemoryBusConfig, bigEndian : Boolean = false) extends Component{
|
||||
val io = new Bundle{
|
||||
val bus = slave(PipelinedMemoryBus(pipelinedMemoryBusConfig))
|
||||
}
|
||||
|
@ -71,6 +67,14 @@ case class MuraxPipelinedMemoryBusRam(onChipRamSize : BigInt, onChipRamHexFile :
|
|||
|
||||
if(onChipRamHexFile != null){
|
||||
HexTools.initRam(ram, onChipRamHexFile, 0x80000000l)
|
||||
if(bigEndian)
|
||||
// HexTools.initRam (incorrectly) assumes little endian byte ordering
|
||||
for((word, wordIndex) <- ram.initialContent.zipWithIndex)
|
||||
ram.initialContent(wordIndex) =
|
||||
((word & 0xffl) << 24) |
|
||||
((word & 0xff00l) << 8) |
|
||||
((word & 0xff0000l) >> 8) |
|
||||
((word & 0xff000000l) >> 24)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -126,7 +126,8 @@ object VexRiscvAhbLite3{
|
|||
minstretAccess = CsrAccess.NONE,
|
||||
ecallGen = false,
|
||||
wfiGenAsWait = false,
|
||||
ucycleAccess = CsrAccess.NONE
|
||||
ucycleAccess = CsrAccess.NONE,
|
||||
uinstretAccess = CsrAccess.NONE
|
||||
)
|
||||
),
|
||||
new YamlPlugin("cpu0.yaml")
|
||||
|
|
|
@ -124,7 +124,8 @@ object VexRiscvAvalonForSim{
|
|||
minstretAccess = CsrAccess.NONE,
|
||||
ecallGen = false,
|
||||
wfiGenAsWait = false,
|
||||
ucycleAccess = CsrAccess.NONE
|
||||
ucycleAccess = CsrAccess.NONE,
|
||||
uinstretAccess = CsrAccess.NONE
|
||||
)
|
||||
),
|
||||
new YamlPlugin("cpu0.yaml")
|
||||
|
|
|
@ -121,7 +121,8 @@ object VexRiscvAvalonWithIntegratedJtag{
|
|||
minstretAccess = CsrAccess.NONE,
|
||||
ecallGen = false,
|
||||
wfiGenAsWait = false,
|
||||
ucycleAccess = CsrAccess.NONE
|
||||
ucycleAccess = CsrAccess.NONE,
|
||||
uinstretAccess = CsrAccess.NONE
|
||||
)
|
||||
),
|
||||
new YamlPlugin("cpu0.yaml")
|
||||
|
|
|
@ -122,7 +122,8 @@ object VexRiscvAxi4WithIntegratedJtag{
|
|||
minstretAccess = CsrAccess.NONE,
|
||||
ecallGen = false,
|
||||
wfiGenAsWait = false,
|
||||
ucycleAccess = CsrAccess.NONE
|
||||
ucycleAccess = CsrAccess.NONE,
|
||||
uinstretAccess = CsrAccess.NONE
|
||||
)
|
||||
),
|
||||
new YamlPlugin("cpu0.yaml")
|
||||
|
|
|
@ -890,12 +890,16 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam
|
|||
dataWriteCmd.way := waysHits
|
||||
}
|
||||
|
||||
val badPermissions = (!mmuRsp.allowWrite && request.wr) || (!mmuRsp.allowRead && (!request.wr || isAmo))
|
||||
val loadStoreFault = io.cpu.writeBack.isValid && (mmuRsp.exception || badPermissions)
|
||||
|
||||
io.cpu.redo := False
|
||||
io.cpu.writeBack.accessError := False
|
||||
io.cpu.writeBack.mmuException := io.cpu.writeBack.isValid && (if(catchIllegal) mmuRsp.exception || (!mmuRsp.allowWrite && request.wr) || (!mmuRsp.allowRead && (!request.wr || isAmo)) else False)
|
||||
io.cpu.writeBack.mmuException := loadStoreFault && (if(catchIllegal) mmuRsp.isPaging else False)
|
||||
io.cpu.writeBack.unalignedAccess := io.cpu.writeBack.isValid && unaligned
|
||||
io.cpu.writeBack.isWrite := request.wr
|
||||
|
||||
|
||||
io.mem.cmd.valid := False
|
||||
io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto cpuWordRange.low) @@ U(0, cpuWordRange.low bits)
|
||||
io.mem.cmd.length := 0
|
||||
|
@ -1002,7 +1006,7 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam
|
|||
if(catchAccessError) io.cpu.writeBack.accessError := !request.wr && isLast && io.mem.rsp.valid && io.mem.rsp.error
|
||||
} otherwise {
|
||||
io.cpu.writeBack.data := dataMux
|
||||
if(catchAccessError) io.cpu.writeBack.accessError := (waysHits & B(tagsReadRsp.map(_.error))) =/= 0
|
||||
if(catchAccessError) io.cpu.writeBack.accessError := (waysHits & B(tagsReadRsp.map(_.error))) =/= 0 || (loadStoreFault && !mmuRsp.isPaging)
|
||||
}
|
||||
|
||||
if(withLrSc) when(request.isLrsc && request.wr){
|
||||
|
|
|
@ -447,9 +447,9 @@ class InstructionCache(p : InstructionCacheConfig, mmuParameter : MemoryTranslat
|
|||
val mmuRsp = io.cpu.fetch.mmuRsp
|
||||
|
||||
io.cpu.fetch.cacheMiss := !hit.valid
|
||||
io.cpu.fetch.error := hit.error
|
||||
io.cpu.fetch.error := hit.error || (!mmuRsp.isPaging && (mmuRsp.exception || !mmuRsp.allowExecute))
|
||||
io.cpu.fetch.mmuRefilling := mmuRsp.refilling
|
||||
io.cpu.fetch.mmuException := !mmuRsp.refilling && (mmuRsp.exception || !mmuRsp.allowExecute)
|
||||
io.cpu.fetch.mmuException := !mmuRsp.refilling && mmuRsp.isPaging && (mmuRsp.exception || !mmuRsp.allowExecute)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -478,9 +478,9 @@ class InstructionCache(p : InstructionCacheConfig, mmuParameter : MemoryTranslat
|
|||
}
|
||||
|
||||
io.cpu.decode.cacheMiss := !hit.valid
|
||||
io.cpu.decode.error := hit.error
|
||||
io.cpu.decode.error := hit.error || (!mmuRsp.isPaging && (mmuRsp.exception || !mmuRsp.allowExecute))
|
||||
io.cpu.decode.mmuRefilling := mmuRsp.refilling
|
||||
io.cpu.decode.mmuException := !mmuRsp.refilling && (mmuRsp.exception || !mmuRsp.allowExecute)
|
||||
io.cpu.decode.mmuException := !mmuRsp.refilling && mmuRsp.isPaging && (mmuRsp.exception || !mmuRsp.allowExecute)
|
||||
io.cpu.decode.physicalAddress := mmuRsp.physicalAddress
|
||||
})
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@ case class CsrPluginConfig(
|
|||
mcycleAccess : CsrAccess,
|
||||
minstretAccess : CsrAccess,
|
||||
ucycleAccess : CsrAccess,
|
||||
uinstretAccess : CsrAccess = CsrAccess.NONE,
|
||||
wfiGenAsWait : Boolean,
|
||||
ecallGen : Boolean,
|
||||
xtvecModeGen : Boolean = false,
|
||||
|
@ -144,6 +145,7 @@ object CsrPluginConfig{
|
|||
mcycleAccess = CsrAccess.NONE,
|
||||
minstretAccess = CsrAccess.NONE,
|
||||
ucycleAccess = CsrAccess.NONE,
|
||||
uinstretAccess = CsrAccess.NONE,
|
||||
wfiGenAsWait = true,
|
||||
ecallGen = true,
|
||||
xtvecModeGen = false,
|
||||
|
@ -184,6 +186,7 @@ object CsrPluginConfig{
|
|||
mcycleAccess = CsrAccess.READ_WRITE,
|
||||
minstretAccess = CsrAccess.READ_WRITE,
|
||||
ucycleAccess = CsrAccess.READ_ONLY,
|
||||
uinstretAccess = CsrAccess.READ_ONLY,
|
||||
wfiGenAsWait = true,
|
||||
ecallGen = true,
|
||||
xtvecModeGen = false,
|
||||
|
@ -224,7 +227,8 @@ object CsrPluginConfig{
|
|||
minstretAccess = CsrAccess.READ_WRITE,
|
||||
ecallGen = true,
|
||||
wfiGenAsWait = true,
|
||||
ucycleAccess = CsrAccess.READ_ONLY
|
||||
ucycleAccess = CsrAccess.READ_ONLY,
|
||||
uinstretAccess = CsrAccess.READ_ONLY
|
||||
)
|
||||
|
||||
def all2(mtvecInit : BigInt) : CsrPluginConfig = CsrPluginConfig(
|
||||
|
@ -246,6 +250,7 @@ object CsrPluginConfig{
|
|||
ecallGen = true,
|
||||
wfiGenAsWait = true,
|
||||
ucycleAccess = CsrAccess.READ_ONLY,
|
||||
uinstretAccess = CsrAccess.READ_ONLY,
|
||||
supervisorGen = true,
|
||||
sscratchGen = true,
|
||||
stvecAccess = CsrAccess.READ_WRITE,
|
||||
|
@ -277,7 +282,8 @@ object CsrPluginConfig{
|
|||
minstretAccess = CsrAccess.NONE,
|
||||
ecallGen = false,
|
||||
wfiGenAsWait = false,
|
||||
ucycleAccess = CsrAccess.NONE
|
||||
ucycleAccess = CsrAccess.NONE,
|
||||
uinstretAccess = CsrAccess.NONE
|
||||
)
|
||||
|
||||
def smallest(mtvecInit : BigInt) = CsrPluginConfig(
|
||||
|
@ -298,7 +304,33 @@ object CsrPluginConfig{
|
|||
minstretAccess = CsrAccess.NONE,
|
||||
ecallGen = false,
|
||||
wfiGenAsWait = false,
|
||||
ucycleAccess = CsrAccess.NONE
|
||||
ucycleAccess = CsrAccess.NONE,
|
||||
uinstretAccess = CsrAccess.NONE
|
||||
)
|
||||
|
||||
def secure(mtvecInit : BigInt) = CsrPluginConfig(
|
||||
catchIllegalAccess = true,
|
||||
mvendorid = 1,
|
||||
marchid = 2,
|
||||
mimpid = 3,
|
||||
mhartid = 0,
|
||||
misaExtensionsInit = 0x101064, // RV32GCFMU
|
||||
misaAccess = CsrAccess.READ_WRITE,
|
||||
mtvecAccess = CsrAccess.READ_WRITE,
|
||||
mtvecInit = mtvecInit,
|
||||
mepcAccess = CsrAccess.READ_WRITE,
|
||||
mscratchGen = true,
|
||||
mcauseAccess = CsrAccess.READ_WRITE,
|
||||
mbadaddrAccess = CsrAccess.READ_WRITE,
|
||||
mcycleAccess = CsrAccess.READ_WRITE,
|
||||
minstretAccess = CsrAccess.READ_WRITE,
|
||||
ucycleAccess = CsrAccess.READ_ONLY,
|
||||
uinstretAccess = CsrAccess.READ_ONLY,
|
||||
wfiGenAsWait = true,
|
||||
ecallGen = true,
|
||||
userGen = true,
|
||||
medelegAccess = CsrAccess.READ_WRITE,
|
||||
midelegAccess = CsrAccess.READ_WRITE
|
||||
)
|
||||
|
||||
}
|
||||
|
@ -641,6 +673,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
|
|||
//User CSR
|
||||
ucycleAccess(CSR.UCYCLE, mcycle(31 downto 0))
|
||||
ucycleAccess(CSR.UCYCLEH, mcycle(63 downto 32))
|
||||
uinstretAccess(CSR.UINSTRET, minstret(31 downto 0))
|
||||
uinstretAccess(CSR.UINSTRETH, minstret(63 downto 32))
|
||||
|
||||
if(utimeAccess != CsrAccess.NONE) {
|
||||
utimeAccess(CSR.UTIME, utime(31 downto 0))
|
||||
|
|
|
@ -355,15 +355,14 @@ class DBusCachedPlugin(val config : DataCacheConfig,
|
|||
exceptionBus.valid := True
|
||||
exceptionBus.code := (input(MEMORY_WR) ? U(7) | U(5)).resized
|
||||
}
|
||||
|
||||
if (catchUnaligned) when(cache.io.cpu.writeBack.unalignedAccess) {
|
||||
exceptionBus.valid := True
|
||||
exceptionBus.code := (input(MEMORY_WR) ? U(6) | U(4)).resized
|
||||
}
|
||||
if(catchIllegal) when (cache.io.cpu.writeBack.mmuException) {
|
||||
exceptionBus.valid := True
|
||||
exceptionBus.code := (input(MEMORY_WR) ? U(15) | U(13)).resized
|
||||
}
|
||||
if (catchUnaligned) when(cache.io.cpu.writeBack.unalignedAccess) {
|
||||
exceptionBus.valid := True
|
||||
exceptionBus.code := (input(MEMORY_WR) ? U(6) | U(4)).resized
|
||||
}
|
||||
|
||||
when(cache.io.cpu.redo) {
|
||||
redoBranch.valid := True
|
||||
|
|
|
@ -87,7 +87,7 @@ object DBusSimpleBus{
|
|||
)
|
||||
}
|
||||
|
||||
case class DBusSimpleBus() extends Bundle with IMasterSlave{
|
||||
case class DBusSimpleBus(bigEndian : Boolean = false) extends Bundle with IMasterSlave{
|
||||
val cmd = Stream(DBusSimpleCmd())
|
||||
val rsp = DBusSimpleRsp()
|
||||
|
||||
|
@ -97,12 +97,27 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{
|
|||
}
|
||||
|
||||
def cmdS2mPipe() : DBusSimpleBus = {
|
||||
val s = DBusSimpleBus()
|
||||
val s = DBusSimpleBus(bigEndian)
|
||||
s.cmd << this.cmd.s2mPipe()
|
||||
this.rsp := s.rsp
|
||||
s
|
||||
}
|
||||
|
||||
def genMask(cmd : DBusSimpleCmd) = {
|
||||
if(bigEndian)
|
||||
cmd.size.mux(
|
||||
U(0) -> B"1000",
|
||||
U(1) -> B"1100",
|
||||
default -> B"1111"
|
||||
) |>> cmd.address(1 downto 0)
|
||||
else
|
||||
cmd.size.mux(
|
||||
U(0) -> B"0001",
|
||||
U(1) -> B"0011",
|
||||
default -> B"1111"
|
||||
) |<< cmd.address(1 downto 0)
|
||||
}
|
||||
|
||||
def toAxi4Shared(stageCmd : Boolean = false, pendingWritesMax : Int = 7): Axi4Shared = {
|
||||
val axi = Axi4Shared(DBusSimpleBus.getAxi4Config())
|
||||
|
||||
|
@ -127,11 +142,7 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{
|
|||
axi.writeData.arbitrationFrom(dataStage)
|
||||
axi.writeData.last := True
|
||||
axi.writeData.data := dataStage.data
|
||||
axi.writeData.strb := (dataStage.size.mux(
|
||||
U(0) -> B"0001",
|
||||
U(1) -> B"0011",
|
||||
default -> B"1111"
|
||||
) << dataStage.address(1 downto 0)).resized
|
||||
axi.writeData.strb := genMask(dataStage).resized
|
||||
|
||||
|
||||
rsp.ready := axi.r.valid
|
||||
|
@ -155,11 +166,7 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{
|
|||
mm.write := cmdStage.valid && cmdStage.wr
|
||||
mm.address := (cmdStage.address >> 2) @@ U"00"
|
||||
mm.writeData := cmdStage.data(31 downto 0)
|
||||
mm.byteEnable := (cmdStage.size.mux (
|
||||
U(0) -> B"0001",
|
||||
U(1) -> B"0011",
|
||||
default -> B"1111"
|
||||
) << cmdStage.address(1 downto 0)).resized
|
||||
mm.byteEnable := genMask(cmdStage).resized
|
||||
|
||||
|
||||
cmdStage.ready := mm.waitRequestn
|
||||
|
@ -178,11 +185,7 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{
|
|||
bus.ADR := cmdStage.address >> 2
|
||||
bus.CTI :=B"000"
|
||||
bus.BTE := "00"
|
||||
bus.SEL := (cmdStage.size.mux (
|
||||
U(0) -> B"0001",
|
||||
U(1) -> B"0011",
|
||||
default -> B"1111"
|
||||
) << cmdStage.address(1 downto 0)).resized
|
||||
bus.SEL := genMask(cmdStage).resized
|
||||
when(!cmdStage.wr) {
|
||||
bus.SEL := "1111"
|
||||
}
|
||||
|
@ -206,11 +209,7 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{
|
|||
bus.cmd.write := cmd.wr
|
||||
bus.cmd.address := cmd.address.resized
|
||||
bus.cmd.data := cmd.data
|
||||
bus.cmd.mask := cmd.size.mux(
|
||||
0 -> B"0001",
|
||||
1 -> B"0011",
|
||||
default -> B"1111"
|
||||
) |<< cmd.address(1 downto 0)
|
||||
bus.cmd.mask := genMask(cmd)
|
||||
cmd.ready := bus.cmd.ready
|
||||
|
||||
rsp.ready := bus.rsp.valid
|
||||
|
@ -262,11 +261,7 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{
|
|||
1 -> U"01",
|
||||
default -> U"11"
|
||||
)
|
||||
bus.cmd.mask := cmd.size.mux(
|
||||
0 -> B"0001",
|
||||
1 -> B"0011",
|
||||
default -> B"1111"
|
||||
) |<< cmd.address(1 downto 0)
|
||||
bus.cmd.mask := genMask(cmd)
|
||||
|
||||
cmd.ready := bus.cmd.ready
|
||||
|
||||
|
@ -286,6 +281,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false,
|
|||
emitCmdInMemoryStage : Boolean = false,
|
||||
onlyLoadWords : Boolean = false,
|
||||
withLrSc : Boolean = false,
|
||||
val bigEndian : Boolean = false,
|
||||
memoryTranslatorPortConfig : Any = null) extends Plugin[VexRiscv] with DBusAccessService {
|
||||
|
||||
var dBus : DBusSimpleBus = null
|
||||
|
@ -391,7 +387,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false,
|
|||
|
||||
object MMU_RSP extends Stageable(MemoryTranslatorRsp(mmuBus.p))
|
||||
|
||||
dBus = master(DBusSimpleBus()).setName("dBus")
|
||||
dBus = master(DBusSimpleBus(bigEndian)).setName("dBus")
|
||||
|
||||
|
||||
decode plug new Area {
|
||||
|
@ -434,11 +430,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false,
|
|||
insert(MEMORY_ADDRESS_LOW) := dBus.cmd.address(1 downto 0)
|
||||
|
||||
//formal
|
||||
val formalMask = dBus.cmd.size.mux(
|
||||
U(0) -> B"0001",
|
||||
U(1) -> B"0011",
|
||||
default -> B"1111"
|
||||
) |<< dBus.cmd.address(1 downto 0)
|
||||
val formalMask = dBus.genMask(dBus.cmd)
|
||||
|
||||
insert(FORMAL_MEM_ADDR) := dBus.cmd.address & U"xFFFFFFFC"
|
||||
insert(FORMAL_MEM_WMASK) := (dBus.cmd.valid && dBus.cmd.wr) ? formalMask | B"0000"
|
||||
|
@ -536,17 +528,32 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false,
|
|||
|
||||
val rspShifted = MEMORY_READ_DATA()
|
||||
rspShifted := input(MEMORY_READ_DATA)
|
||||
switch(input(MEMORY_ADDRESS_LOW)){
|
||||
is(1){rspShifted(7 downto 0) := input(MEMORY_READ_DATA)(15 downto 8)}
|
||||
is(2){rspShifted(15 downto 0) := input(MEMORY_READ_DATA)(31 downto 16)}
|
||||
is(3){rspShifted(7 downto 0) := input(MEMORY_READ_DATA)(31 downto 24)}
|
||||
}
|
||||
if(bigEndian)
|
||||
switch(input(MEMORY_ADDRESS_LOW)){
|
||||
is(1){rspShifted(31 downto 24) := input(MEMORY_READ_DATA)(23 downto 16)}
|
||||
is(2){rspShifted(31 downto 16) := input(MEMORY_READ_DATA)(15 downto 0)}
|
||||
is(3){rspShifted(31 downto 24) := input(MEMORY_READ_DATA)(7 downto 0)}
|
||||
}
|
||||
else
|
||||
switch(input(MEMORY_ADDRESS_LOW)){
|
||||
is(1){rspShifted(7 downto 0) := input(MEMORY_READ_DATA)(15 downto 8)}
|
||||
is(2){rspShifted(15 downto 0) := input(MEMORY_READ_DATA)(31 downto 16)}
|
||||
is(3){rspShifted(7 downto 0) := input(MEMORY_READ_DATA)(31 downto 24)}
|
||||
}
|
||||
|
||||
val rspFormated = input(INSTRUCTION)(13 downto 12).mux(
|
||||
0 -> B((31 downto 8) -> (rspShifted(7) && !input(INSTRUCTION)(14)),(7 downto 0) -> rspShifted(7 downto 0)),
|
||||
1 -> B((31 downto 16) -> (rspShifted(15) && ! input(INSTRUCTION)(14)),(15 downto 0) -> rspShifted(15 downto 0)),
|
||||
default -> rspShifted //W
|
||||
)
|
||||
val rspFormated =
|
||||
if(bigEndian)
|
||||
input(INSTRUCTION)(13 downto 12).mux(
|
||||
0 -> B((31 downto 8) -> (rspShifted(31) && !input(INSTRUCTION)(14)),(7 downto 0) -> rspShifted(31 downto 24)),
|
||||
1 -> B((31 downto 16) -> (rspShifted(31) && ! input(INSTRUCTION)(14)),(15 downto 0) -> rspShifted(31 downto 16)),
|
||||
default -> rspShifted //W
|
||||
)
|
||||
else
|
||||
input(INSTRUCTION)(13 downto 12).mux(
|
||||
0 -> B((31 downto 8) -> (rspShifted(7) && !input(INSTRUCTION)(14)),(7 downto 0) -> rspShifted(7 downto 0)),
|
||||
1 -> B((31 downto 16) -> (rspShifted(15) && ! input(INSTRUCTION)(14)),(15 downto 0) -> rspShifted(15 downto 0)),
|
||||
default -> rspShifted //W
|
||||
)
|
||||
|
||||
when(arbitration.isValid && input(MEMORY_ENABLE)) {
|
||||
output(REGFILE_WRITE_DATA) := (if(!onlyLoadWords) rspFormated else input(MEMORY_READ_DATA))
|
||||
|
|
|
@ -234,7 +234,8 @@ class IBusSimplePlugin( resetVector : BigInt,
|
|||
val singleInstructionPipeline : Boolean = false,
|
||||
val memoryTranslatorPortConfig : Any = null,
|
||||
relaxPredictorAddress : Boolean = true,
|
||||
predictionBuffer : Boolean = true
|
||||
predictionBuffer : Boolean = true,
|
||||
bigEndian : Boolean = false
|
||||
) extends IBusFetcherImpl(
|
||||
resetVector = resetVector,
|
||||
keepPcPlus4 = keepPcPlus4,
|
||||
|
@ -371,6 +372,11 @@ class IBusSimplePlugin( resetVector : BigInt,
|
|||
fetchRsp.pc := stages.last.output.payload
|
||||
fetchRsp.rsp := rspBuffer.output.payload
|
||||
fetchRsp.rsp.error.clearWhen(!rspBuffer.output.valid) //Avoid interference with instruction injection from the debug plugin
|
||||
if(bigEndian){
|
||||
// instructions are stored in little endian byteorder
|
||||
fetchRsp.rsp.inst.allowOverride
|
||||
fetchRsp.rsp.inst := EndiannessSwap(rspBuffer.output.payload.inst)
|
||||
}
|
||||
|
||||
val join = Stream(FetchRsp())
|
||||
val exceptionDetected = False
|
||||
|
|
|
@ -151,6 +151,7 @@ class MmuPlugin(ioRange : UInt => Bool,
|
|||
port.bus.rsp.allowExecute := cacheLine.allowExecute
|
||||
port.bus.rsp.exception := !dirty && cacheHit && (cacheLine.exception || cacheLine.allowUser && privilegeService.isSupervisor() && !csr.status.sum || !cacheLine.allowUser && privilegeService.isUser())
|
||||
port.bus.rsp.refilling := dirty || !cacheHit
|
||||
port.bus.rsp.isPaging := True
|
||||
} otherwise {
|
||||
port.bus.rsp.physicalAddress := port.bus.cmd.last.virtualAddress
|
||||
port.bus.rsp.allowRead := True
|
||||
|
@ -158,6 +159,7 @@ class MmuPlugin(ioRange : UInt => Bool,
|
|||
port.bus.rsp.allowExecute := True
|
||||
port.bus.rsp.exception := False
|
||||
port.bus.rsp.refilling := False
|
||||
port.bus.rsp.isPaging := False
|
||||
}
|
||||
port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress)
|
||||
|
||||
|
|
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Samuel Lindemer <samuel.lindemer@ri.se>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
package vexriscv.plugin
|
||||
|
||||
import vexriscv.{VexRiscv, _}
|
||||
import spinal.core._
|
||||
import spinal.lib._
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
|
||||
/* Each 32-bit pmpcfg# register contains four 8-bit configuration sections.
|
||||
* These section numbers contain flags which apply to regions defined by the
|
||||
* corresponding pmpaddr# register.
|
||||
*
|
||||
* 3 2 1
|
||||
* 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | pmp3cfg | pmp2cfg | pmp1cfg | pmp0cfg | pmpcfg0
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | pmp7cfg | pmp6cfg | pmp5cfg | pmp4cfg | pmpcfg2
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*
|
||||
* 7 6 5 4 3 2 1 0
|
||||
* +-------+-------+-------+-------+-------+-------+-------+-------+
|
||||
* | L | 0 | A | X | W | R | pmp#cfg
|
||||
* +-------+-------+-------+-------+-------+-------+-------+-------+
|
||||
*
|
||||
* L: locks configuration until system reset (including M-mode)
|
||||
* 0: hardwired to zero
|
||||
* A: 0 = OFF (null region / disabled)
|
||||
* 1 = TOR (top of range)
|
||||
* 2 = NA4 (naturally aligned four-byte region)
|
||||
* 3 = NAPOT (naturally aligned power-of-two region, > 7 bytes)
|
||||
* X: execute
|
||||
* W: write
|
||||
* R: read
|
||||
*
|
||||
* TOR: Each 32-bit pmpaddr# register defines the upper bound of the pmp region
|
||||
* right-shifted by two bits. The lower bound of the region is the previous
|
||||
* pmpaddr# register. In the case of pmpaddr0, the lower bound is address 0x0.
|
||||
*
|
||||
* 3 2 1
|
||||
* 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | address[33:2] | pmpaddr#
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*
|
||||
* NAPOT: Each 32-bit pmpaddr# register defines the region address and the size
|
||||
* of the pmp region. The number of concurrent 1s begging at the LSB indicates
|
||||
* the size of the region as a power of two (e.g. 0x...0 = 8-byte, 0x...1 =
|
||||
* 16-byte, 0x...11 = 32-byte, etc.).
|
||||
*
|
||||
* 3 2 1
|
||||
* 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | address[33:2] |0|1|1|1|1| pmpaddr#
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*
|
||||
* NA4: This is essentially an edge case of NAPOT where the entire pmpaddr#
|
||||
* register defines a 4-byte wide region.
|
||||
*/
|
||||
|
||||
case class PmpRegister(previous : PmpRegister) extends Area {
|
||||
|
||||
def OFF = 0
|
||||
def TOR = 1
|
||||
def NA4 = 2
|
||||
def NAPOT = 3
|
||||
|
||||
val state = new Area {
|
||||
val r, w, x = Reg(Bool)
|
||||
val l = RegInit(False)
|
||||
val a = Reg(UInt(2 bits)) init(0)
|
||||
val addr = Reg(UInt(32 bits))
|
||||
}
|
||||
|
||||
// CSR writes connect to these signals rather than the internal state
|
||||
// registers. This makes locking and WARL possible.
|
||||
val csr = new Area {
|
||||
val r, w, x = Bool
|
||||
val l = Bool
|
||||
val a = UInt(2 bits)
|
||||
val addr = UInt(32 bits)
|
||||
}
|
||||
|
||||
// Last valid assignment wins; nothing happens if a user-initiated write did
|
||||
// not occur on this clock cycle.
|
||||
csr.r := state.r
|
||||
csr.w := state.w
|
||||
csr.x := state.x
|
||||
csr.l := state.l
|
||||
csr.a := state.a
|
||||
csr.addr := state.addr
|
||||
|
||||
// Computed PMP region bounds
|
||||
val region = new Area {
|
||||
val valid, locked = Bool
|
||||
val start, end = UInt(32 bits)
|
||||
}
|
||||
|
||||
when(~state.l) {
|
||||
state.r := csr.r
|
||||
state.w := csr.w
|
||||
state.x := csr.x
|
||||
state.l := csr.l
|
||||
state.a := csr.a
|
||||
state.addr := csr.addr
|
||||
|
||||
if (csr.l == True & csr.a == TOR) {
|
||||
previous.state.l := True
|
||||
}
|
||||
}
|
||||
|
||||
val shifted = state.addr |<< 2
|
||||
val mask = state.addr & ~(state.addr + 1)
|
||||
val masked = (state.addr & ~mask) |<< 2
|
||||
|
||||
// PMP changes take effect two clock cycles after the initial CSR write (i.e.,
|
||||
// settings propagate from csr -> state -> region).
|
||||
region.locked := state.l
|
||||
region.valid := True
|
||||
|
||||
switch(csr.a) {
|
||||
is(TOR) {
|
||||
if (previous == null) region.start := 0
|
||||
else region.start := previous.region.end
|
||||
region.end := shifted
|
||||
}
|
||||
is(NA4) {
|
||||
region.start := shifted
|
||||
region.end := shifted + 4
|
||||
}
|
||||
is(NAPOT) {
|
||||
region.start := masked
|
||||
region.end := masked + ((mask + 1) |<< 3)
|
||||
}
|
||||
default {
|
||||
region.start := 0
|
||||
region.end := shifted
|
||||
region.valid := False
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case class ProtectedMemoryTranslatorPort(bus : MemoryTranslatorBus)
|
||||
|
||||
class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] with MemoryTranslator {
|
||||
|
||||
// Each pmpcfg# CSR configures four regions.
|
||||
assert((regions % 4) == 0)
|
||||
|
||||
val pmps = ArrayBuffer[PmpRegister]()
|
||||
val portsInfo = ArrayBuffer[ProtectedMemoryTranslatorPort]()
|
||||
|
||||
override def newTranslationPort(priority : Int, args : Any): MemoryTranslatorBus = {
|
||||
val port = ProtectedMemoryTranslatorPort(MemoryTranslatorBus(new MemoryTranslatorBusParameter(0, 0)))
|
||||
portsInfo += port
|
||||
port.bus
|
||||
}
|
||||
|
||||
override def build(pipeline: VexRiscv): Unit = {
|
||||
import pipeline.config._
|
||||
import pipeline._
|
||||
import Riscv._
|
||||
|
||||
val csrService = pipeline.service(classOf[CsrInterface])
|
||||
val privilegeService = pipeline.service(classOf[PrivilegeService])
|
||||
|
||||
val core = pipeline plug new Area {
|
||||
|
||||
// Instantiate pmpaddr0 ... pmpaddr# CSRs.
|
||||
for (i <- 0 until regions) {
|
||||
if (i == 0) {
|
||||
pmps += PmpRegister(null)
|
||||
} else {
|
||||
pmps += PmpRegister(pmps.last)
|
||||
}
|
||||
csrService.r(0x3b0 + i, pmps(i).state.addr)
|
||||
csrService.w(0x3b0 + i, pmps(i).csr.addr)
|
||||
}
|
||||
|
||||
// Instantiate pmpcfg0 ... pmpcfg# CSRs.
|
||||
for (i <- 0 until (regions / 4)) {
|
||||
csrService.r(0x3a0 + i,
|
||||
31 -> pmps((i * 4) + 3).state.l, 23 -> pmps((i * 4) + 2).state.l,
|
||||
15 -> pmps((i * 4) + 1).state.l, 7 -> pmps((i * 4) ).state.l,
|
||||
27 -> pmps((i * 4) + 3).state.a, 26 -> pmps((i * 4) + 3).state.x,
|
||||
25 -> pmps((i * 4) + 3).state.w, 24 -> pmps((i * 4) + 3).state.r,
|
||||
19 -> pmps((i * 4) + 2).state.a, 18 -> pmps((i * 4) + 2).state.x,
|
||||
17 -> pmps((i * 4) + 2).state.w, 16 -> pmps((i * 4) + 2).state.r,
|
||||
11 -> pmps((i * 4) + 1).state.a, 10 -> pmps((i * 4) + 1).state.x,
|
||||
9 -> pmps((i * 4) + 1).state.w, 8 -> pmps((i * 4) + 1).state.r,
|
||||
3 -> pmps((i * 4) ).state.a, 2 -> pmps((i * 4) ).state.x,
|
||||
1 -> pmps((i * 4) ).state.w, 0 -> pmps((i * 4) ).state.r
|
||||
)
|
||||
csrService.w(0x3a0 + i,
|
||||
31 -> pmps((i * 4) + 3).csr.l, 23 -> pmps((i * 4) + 2).csr.l,
|
||||
15 -> pmps((i * 4) + 1).csr.l, 7 -> pmps((i * 4) ).csr.l,
|
||||
27 -> pmps((i * 4) + 3).csr.a, 26 -> pmps((i * 4) + 3).csr.x,
|
||||
25 -> pmps((i * 4) + 3).csr.w, 24 -> pmps((i * 4) + 3).csr.r,
|
||||
19 -> pmps((i * 4) + 2).csr.a, 18 -> pmps((i * 4) + 2).csr.x,
|
||||
17 -> pmps((i * 4) + 2).csr.w, 16 -> pmps((i * 4) + 2).csr.r,
|
||||
11 -> pmps((i * 4) + 1).csr.a, 10 -> pmps((i * 4) + 1).csr.x,
|
||||
9 -> pmps((i * 4) + 1).csr.w, 8 -> pmps((i * 4) + 1).csr.r,
|
||||
3 -> pmps((i * 4) ).csr.a, 2 -> pmps((i * 4) ).csr.x,
|
||||
1 -> pmps((i * 4) ).csr.w, 0 -> pmps((i * 4) ).csr.r
|
||||
)
|
||||
}
|
||||
|
||||
// Connect memory ports to PMP logic.
|
||||
val ports = for ((port, portId) <- portsInfo.zipWithIndex) yield new Area {
|
||||
|
||||
val address = port.bus.cmd(0).virtualAddress
|
||||
port.bus.rsp.physicalAddress := address
|
||||
|
||||
// Only the first matching PMP region applies.
|
||||
val hits = pmps.map(pmp => pmp.region.valid &
|
||||
pmp.region.start <= address &
|
||||
pmp.region.end > address &
|
||||
(pmp.region.locked | ~privilegeService.isMachine()))
|
||||
|
||||
// M-mode has full access by default, others have none.
|
||||
when(CountOne(hits) === 0) {
|
||||
port.bus.rsp.allowRead := privilegeService.isMachine()
|
||||
port.bus.rsp.allowWrite := privilegeService.isMachine()
|
||||
port.bus.rsp.allowExecute := privilegeService.isMachine()
|
||||
} otherwise {
|
||||
port.bus.rsp.allowRead := MuxOH(OHMasking.first(hits), pmps.map(_.state.r))
|
||||
port.bus.rsp.allowWrite := MuxOH(OHMasking.first(hits), pmps.map(_.state.w))
|
||||
port.bus.rsp.allowExecute := MuxOH(OHMasking.first(hits), pmps.map(_.state.x))
|
||||
}
|
||||
|
||||
port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress)
|
||||
port.bus.rsp.isPaging := False
|
||||
port.bus.rsp.exception := False
|
||||
port.bus.rsp.refilling := False
|
||||
port.bus.busy := False
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,6 +18,7 @@ class RegFilePlugin(regFileReadyKind : RegFileReadKind,
|
|||
writeRfInMemoryStage : Boolean = false,
|
||||
readInExecute : Boolean = false,
|
||||
syncUpdateOnStall : Boolean = true,
|
||||
rv32e : Boolean = false,
|
||||
withShadow : Boolean = false //shadow registers aren't transition hazard free
|
||||
) extends Plugin[VexRiscv] with RegFileService{
|
||||
import Riscv._
|
||||
|
@ -39,8 +40,11 @@ class RegFilePlugin(regFileReadyKind : RegFileReadKind,
|
|||
val readStage = if(readInExecute) execute else decode
|
||||
val writeStage = if(writeRfInMemoryStage) memory else stages.last
|
||||
|
||||
val numRegisters = if(rv32e) 16 else 32
|
||||
def clipRange(that : Range) = if(rv32e) that.tail else that
|
||||
|
||||
val global = pipeline plug new Area{
|
||||
val regFileSize = if(withShadow) 64 else 32
|
||||
val regFileSize = if(withShadow) numRegisters * 2 else numRegisters
|
||||
val regFile = Mem(Bits(32 bits),regFileSize) addAttribute(Verilator.public)
|
||||
if(zeroBoot) regFile.init(List.fill(regFileSize)(B(0, 32 bits)))
|
||||
|
||||
|
@ -59,6 +63,9 @@ class RegFilePlugin(regFileReadyKind : RegFileReadKind,
|
|||
when(decode.input(INSTRUCTION)(rdRange) === 0) {
|
||||
decode.input(REGFILE_WRITE_VALID) := False
|
||||
}
|
||||
if(rv32e) when(decode.input(INSTRUCTION)(rdRange.head)) {
|
||||
decode.input(REGFILE_WRITE_VALID) := False
|
||||
}
|
||||
|
||||
//Read register file
|
||||
readStage plug new Area{
|
||||
|
@ -72,8 +79,8 @@ class RegFilePlugin(regFileReadyKind : RegFileReadKind,
|
|||
}
|
||||
|
||||
def shadowPrefix(that : Bits) = if(withShadow) global.shadow.read ## that else that
|
||||
val regFileReadAddress1 = U(shadowPrefix(srcInstruction(Riscv.rs1Range)))
|
||||
val regFileReadAddress2 = U(shadowPrefix(srcInstruction(Riscv.rs2Range)))
|
||||
val regFileReadAddress1 = U(shadowPrefix(srcInstruction(clipRange(Riscv.rs1Range))))
|
||||
val regFileReadAddress2 = U(shadowPrefix(srcInstruction(clipRange(Riscv.rs2Range))))
|
||||
|
||||
val (rs1Data,rs2Data) = regFileReadyKind match{
|
||||
case `ASYNC` => (global.regFile.readAsync(regFileReadAddress1),global.regFile.readAsync(regFileReadAddress2))
|
||||
|
@ -93,7 +100,7 @@ class RegFilePlugin(regFileReadyKind : RegFileReadKind,
|
|||
def shadowPrefix(that : Bits) = if(withShadow) global.shadow.write ## that else that
|
||||
val regFileWrite = global.regFile.writePort.addAttribute(Verilator.public).setName("lastStageRegFileWrite")
|
||||
regFileWrite.valid := output(REGFILE_WRITE_VALID) && arbitration.isFiring
|
||||
regFileWrite.address := U(shadowPrefix(output(INSTRUCTION)(rdRange)))
|
||||
regFileWrite.address := U(shadowPrefix(output(INSTRUCTION)(clipRange(rdRange))))
|
||||
regFileWrite.data := output(REGFILE_WRITE_DATA)
|
||||
|
||||
//Ensure no boot glitches modify X0
|
||||
|
|
|
@ -31,6 +31,7 @@ class StaticMemoryTranslatorPlugin(ioRange : UInt => Bool) extends Plugin[VexRis
|
|||
port.bus.rsp.allowWrite := True
|
||||
port.bus.rsp.allowExecute := True
|
||||
port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress)
|
||||
port.bus.rsp.isPaging := False
|
||||
port.bus.rsp.exception := False
|
||||
port.bus.rsp.refilling := False
|
||||
port.bus.busy := False
|
||||
|
|
|
@ -0,0 +1,203 @@
|
|||
|
||||
build/pmp.elf: file format elf32-littleriscv
|
||||
|
||||
|
||||
Disassembly of section .crt_section:
|
||||
|
||||
80000000 <_start>:
|
||||
80000000: 00000097 auipc ra,0x0
|
||||
80000004: 01008093 addi ra,ra,16 # 80000010 <trap>
|
||||
80000008: 30509073 csrw mtvec,ra
|
||||
8000000c: 00c0006f j 80000018 <test0>
|
||||
|
||||
80000010 <trap>:
|
||||
80000010: 341f1073 csrw mepc,t5
|
||||
80000014: 30200073 mret
|
||||
|
||||
80000018 <test0>:
|
||||
80000018: 00000e13 li t3,0
|
||||
8000001c: 00000f17 auipc t5,0x0
|
||||
80000020: 27cf0f13 addi t5,t5,636 # 80000298 <fail>
|
||||
80000024: 800000b7 lui ra,0x80000
|
||||
80000028: 80008237 lui tp,0x80008
|
||||
8000002c: deadc137 lui sp,0xdeadc
|
||||
80000030: eef10113 addi sp,sp,-273 # deadbeef <pass+0x5eadbc4b>
|
||||
80000034: 0020a023 sw sp,0(ra) # 80000000 <pass+0xfffffd5c>
|
||||
80000038: 00222023 sw sp,0(tp) # 80008000 <pass+0x7d5c>
|
||||
8000003c: 0000a183 lw gp,0(ra)
|
||||
80000040: 24311c63 bne sp,gp,80000298 <fail>
|
||||
80000044: 00022183 lw gp,0(tp) # 0 <_start-0x80000000>
|
||||
80000048: 24311863 bne sp,gp,80000298 <fail>
|
||||
8000004c: 071202b7 lui t0,0x7120
|
||||
80000050: 3a029073 csrw pmpcfg0,t0
|
||||
80000054: 3a002373 csrr t1,pmpcfg0
|
||||
80000058: 24629063 bne t0,t1,80000298 <fail>
|
||||
8000005c: 191f02b7 lui t0,0x191f0
|
||||
80000060: 30428293 addi t0,t0,772 # 191f0304 <_start-0x66e0fcfc>
|
||||
80000064: 3a129073 csrw pmpcfg1,t0
|
||||
80000068: 000f02b7 lui t0,0xf0
|
||||
8000006c: 50628293 addi t0,t0,1286 # f0506 <_start-0x7ff0fafa>
|
||||
80000070: 3a229073 csrw pmpcfg2,t0
|
||||
80000074: 0f1e22b7 lui t0,0xf1e2
|
||||
80000078: 90028293 addi t0,t0,-1792 # f1e1900 <_start-0x70e1e700>
|
||||
8000007c: 3a329073 csrw pmpcfg3,t0
|
||||
80000080: 200002b7 lui t0,0x20000
|
||||
80000084: 3b029073 csrw pmpaddr0,t0
|
||||
80000088: 3b002373 csrr t1,pmpaddr0
|
||||
8000008c: 20629663 bne t0,t1,80000298 <fail>
|
||||
80000090: fff00293 li t0,-1
|
||||
80000094: 3b129073 csrw pmpaddr1,t0
|
||||
80000098: 200022b7 lui t0,0x20002
|
||||
8000009c: 3b229073 csrw pmpaddr2,t0
|
||||
800000a0: 200042b7 lui t0,0x20004
|
||||
800000a4: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001>
|
||||
800000a8: 3b329073 csrw pmpaddr3,t0
|
||||
800000ac: 200042b7 lui t0,0x20004
|
||||
800000b0: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001>
|
||||
800000b4: 3b429073 csrw pmpaddr4,t0
|
||||
800000b8: 200042b7 lui t0,0x20004
|
||||
800000bc: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001>
|
||||
800000c0: 3b529073 csrw pmpaddr5,t0
|
||||
800000c4: 200022b7 lui t0,0x20002
|
||||
800000c8: fff28293 addi t0,t0,-1 # 20001fff <_start-0x5fffe001>
|
||||
800000cc: 3b629073 csrw pmpaddr6,t0
|
||||
800000d0: 200062b7 lui t0,0x20006
|
||||
800000d4: fff28293 addi t0,t0,-1 # 20005fff <_start-0x5fffa001>
|
||||
800000d8: 3b729073 csrw pmpaddr7,t0
|
||||
800000dc: 2000c2b7 lui t0,0x2000c
|
||||
800000e0: 3b829073 csrw pmpaddr8,t0
|
||||
800000e4: 2000d2b7 lui t0,0x2000d
|
||||
800000e8: 3b929073 csrw pmpaddr9,t0
|
||||
800000ec: fff00293 li t0,-1
|
||||
800000f0: 3ba29073 csrw pmpaddr10,t0
|
||||
800000f4: 00000293 li t0,0
|
||||
800000f8: 3bb29073 csrw pmpaddr11,t0
|
||||
800000fc: 00000293 li t0,0
|
||||
80000100: 3bc29073 csrw pmpaddr12,t0
|
||||
80000104: 00000293 li t0,0
|
||||
80000108: 3bd29073 csrw pmpaddr13,t0
|
||||
8000010c: 00000293 li t0,0
|
||||
80000110: 3be29073 csrw pmpaddr14,t0
|
||||
80000114: 00000293 li t0,0
|
||||
80000118: 3bf29073 csrw pmpaddr15,t0
|
||||
8000011c: 00c10137 lui sp,0xc10
|
||||
80000120: fee10113 addi sp,sp,-18 # c0ffee <_start-0x7f3f0012>
|
||||
80000124: 0020a023 sw sp,0(ra)
|
||||
80000128: 00222023 sw sp,0(tp) # 0 <_start-0x80000000>
|
||||
8000012c: 0000a183 lw gp,0(ra)
|
||||
80000130: 16311463 bne sp,gp,80000298 <fail>
|
||||
80000134: 00000193 li gp,0
|
||||
80000138: 00022183 lw gp,0(tp) # 0 <_start-0x80000000>
|
||||
8000013c: 14311e63 bne sp,gp,80000298 <fail>
|
||||
|
||||
80000140 <test1>:
|
||||
80000140: 00100e13 li t3,1
|
||||
80000144: 00000f17 auipc t5,0x0
|
||||
80000148: 154f0f13 addi t5,t5,340 # 80000298 <fail>
|
||||
8000014c: 079212b7 lui t0,0x7921
|
||||
80000150: 80828293 addi t0,t0,-2040 # 7920808 <_start-0x786df7f8>
|
||||
80000154: 3a029073 csrw pmpcfg0,t0
|
||||
80000158: 3a002373 csrr t1,pmpcfg0
|
||||
8000015c: 12629e63 bne t0,t1,80000298 <fail>
|
||||
80000160: 800080b7 lui ra,0x80008
|
||||
80000164: deadc137 lui sp,0xdeadc
|
||||
80000168: eef10113 addi sp,sp,-273 # deadbeef <pass+0x5eadbc4b>
|
||||
8000016c: 0020a023 sw sp,0(ra) # 80008000 <pass+0x7d5c>
|
||||
80000170: 00000f17 auipc t5,0x0
|
||||
80000174: 010f0f13 addi t5,t5,16 # 80000180 <test2>
|
||||
80000178: 0000a183 lw gp,0(ra)
|
||||
8000017c: 11c0006f j 80000298 <fail>
|
||||
|
||||
80000180 <test2>:
|
||||
80000180: 00200e13 li t3,2
|
||||
80000184: 00000f17 auipc t5,0x0
|
||||
80000188: 114f0f13 addi t5,t5,276 # 80000298 <fail>
|
||||
8000018c: 071202b7 lui t0,0x7120
|
||||
80000190: 3a029073 csrw pmpcfg0,t0
|
||||
80000194: 3a002373 csrr t1,pmpcfg0
|
||||
80000198: 3b205073 csrwi pmpaddr2,0
|
||||
8000019c: 3b202373 csrr t1,pmpaddr2
|
||||
800001a0: 0e030c63 beqz t1,80000298 <fail>
|
||||
800001a4: 0e628a63 beq t0,t1,80000298 <fail>
|
||||
800001a8: 800080b7 lui ra,0x80008
|
||||
800001ac: deadc137 lui sp,0xdeadc
|
||||
800001b0: eef10113 addi sp,sp,-273 # deadbeef <pass+0x5eadbc4b>
|
||||
800001b4: 0020a023 sw sp,0(ra) # 80008000 <pass+0x7d5c>
|
||||
800001b8: 00000f17 auipc t5,0x0
|
||||
800001bc: 010f0f13 addi t5,t5,16 # 800001c8 <test3>
|
||||
800001c0: 0000a183 lw gp,0(ra)
|
||||
800001c4: 0d40006f j 80000298 <fail>
|
||||
|
||||
800001c8 <test3>:
|
||||
800001c8: 00300e13 li t3,3
|
||||
800001cc: 00000f17 auipc t5,0x0
|
||||
800001d0: 0ccf0f13 addi t5,t5,204 # 80000298 <fail>
|
||||
800001d4: 00000117 auipc sp,0x0
|
||||
800001d8: 01010113 addi sp,sp,16 # 800001e4 <test4>
|
||||
800001dc: 34111073 csrw mepc,sp
|
||||
800001e0: 30200073 mret
|
||||
|
||||
800001e4 <test4>:
|
||||
800001e4: 00400e13 li t3,4
|
||||
800001e8: 00000f17 auipc t5,0x0
|
||||
800001ec: 0b0f0f13 addi t5,t5,176 # 80000298 <fail>
|
||||
800001f0: deadc137 lui sp,0xdeadc
|
||||
800001f4: eef10113 addi sp,sp,-273 # deadbeef <pass+0x5eadbc4b>
|
||||
800001f8: 800080b7 lui ra,0x80008
|
||||
800001fc: 0020a023 sw sp,0(ra) # 80008000 <pass+0x7d5c>
|
||||
80000200: 00000f17 auipc t5,0x0
|
||||
80000204: 010f0f13 addi t5,t5,16 # 80000210 <test5>
|
||||
80000208: 0000a183 lw gp,0(ra)
|
||||
8000020c: 08c0006f j 80000298 <fail>
|
||||
|
||||
80000210 <test5>:
|
||||
80000210: 00500e13 li t3,5
|
||||
80000214: deadc137 lui sp,0xdeadc
|
||||
80000218: eef10113 addi sp,sp,-273 # deadbeef <pass+0x5eadbc4b>
|
||||
8000021c: 800000b7 lui ra,0x80000
|
||||
80000220: 0020a023 sw sp,0(ra) # 80000000 <pass+0xfffffd5c>
|
||||
80000224: 0000a183 lw gp,0(ra)
|
||||
80000228: 06311863 bne sp,gp,80000298 <fail>
|
||||
|
||||
8000022c <test6>:
|
||||
8000022c: 00600e13 li t3,6
|
||||
80000230: 800100b7 lui ra,0x80010
|
||||
80000234: 0000a183 lw gp,0(ra) # 80010000 <pass+0xfd5c>
|
||||
80000238: 00000f17 auipc t5,0x0
|
||||
8000023c: 06cf0f13 addi t5,t5,108 # 800002a4 <pass>
|
||||
80000240: 0030a023 sw gp,0(ra)
|
||||
80000244: 0540006f j 80000298 <fail>
|
||||
|
||||
80000248 <test7>:
|
||||
80000248: 00700e13 li t3,7
|
||||
8000024c: 00000f17 auipc t5,0x0
|
||||
80000250: 04cf0f13 addi t5,t5,76 # 80000298 <fail>
|
||||
80000254: deadc137 lui sp,0xdeadc
|
||||
80000258: eef10113 addi sp,sp,-273 # deadbeef <pass+0x5eadbc4b>
|
||||
8000025c: 800300b7 lui ra,0x80030
|
||||
80000260: ff808093 addi ra,ra,-8 # 8002fff8 <pass+0x2fd54>
|
||||
80000264: 00222023 sw sp,0(tp) # 0 <_start-0x80000000>
|
||||
80000268: 00000f17 auipc t5,0x0
|
||||
8000026c: fa8f0f13 addi t5,t5,-88 # 80000210 <test5>
|
||||
80000270: 00022183 lw gp,0(tp) # 0 <_start-0x80000000>
|
||||
80000274: 0240006f j 80000298 <fail>
|
||||
|
||||
80000278 <test8>:
|
||||
80000278: 00800e13 li t3,8
|
||||
8000027c: 800400b7 lui ra,0x80040
|
||||
80000280: ff808093 addi ra,ra,-8 # 8003fff8 <pass+0x3fd54>
|
||||
80000284: 0000a183 lw gp,0(ra)
|
||||
80000288: 00000f17 auipc t5,0x0
|
||||
8000028c: 01cf0f13 addi t5,t5,28 # 800002a4 <pass>
|
||||
80000290: 0030a023 sw gp,0(ra)
|
||||
80000294: 0040006f j 80000298 <fail>
|
||||
|
||||
80000298 <fail>:
|
||||
80000298: f0100137 lui sp,0xf0100
|
||||
8000029c: f2410113 addi sp,sp,-220 # f00fff24 <pass+0x700ffc80>
|
||||
800002a0: 01c12023 sw t3,0(sp)
|
||||
|
||||
800002a4 <pass>:
|
||||
800002a4: f0100137 lui sp,0xf0100
|
||||
800002a8: f2010113 addi sp,sp,-224 # f00fff20 <pass+0x700ffc7c>
|
||||
800002ac: 00012023 sw zero,0(sp)
|
Binary file not shown.
|
@ -0,0 +1,46 @@
|
|||
:0200000480007A
|
||||
:100000009700000093800001739050306F00C00093
|
||||
:1000100073101F3473002030130E0000170F000000
|
||||
:10002000130FCF27B70000803782008037C1ADDEC5
|
||||
:100030001301F1EE23A020002320220083A1000061
|
||||
:10004000631C31248321020063183124B702120794
|
||||
:100050007390023A7323003A63906224B7021F1927
|
||||
:10006000938242307390123AB7020F00938262502B
|
||||
:100070007390223AB7221E0F938202907390323A05
|
||||
:10008000B70200207390023B7323003B639662200B
|
||||
:100090009302F0FF7390123BB72200207390223B33
|
||||
:1000A000B74200209382F2FF7390323BB7420020A8
|
||||
:1000B0009382F2FF7390423BB74200209382F2FF9B
|
||||
:1000C0007390523BB72200209382F2FF7390623B01
|
||||
:1000D000B76200209382F2FF7390723BB7C2002098
|
||||
:1000E0007390823BB7D200207390923B9302F0FF53
|
||||
:1000F0007390A23B930200007390B23B9302000006
|
||||
:100100007390C23B930200007390D23B93020000B5
|
||||
:100110007390E23B930200007390F23B3701C10001
|
||||
:100120001301E1FE23A020002320220083A1000070
|
||||
:10013000631431169301000083210200631E311401
|
||||
:10014000130E1000170F0000130F4F15B712920770
|
||||
:10015000938282807390023A7323003A639E621204
|
||||
:10016000B780008037C1ADDE1301F1EE23A020007F
|
||||
:10017000170F0000130F0F0183A100006F00C011C3
|
||||
:10018000130E2000170F0000130F4F11B7021207B4
|
||||
:100190007390023A7323003A7350203B7323203B41
|
||||
:1001A000630C030E638A620EB780008037C1ADDE38
|
||||
:1001B0001301F1EE23A02000170F0000130F0F0111
|
||||
:1001C00083A100006F00400D130E3000170F0000D8
|
||||
:1001D000130FCF0C1701000013010101731011342C
|
||||
:1001E00073002030130E4000170F0000130F0F0B89
|
||||
:1001F00037C1ADDE1301F1EEB780008023A02000EF
|
||||
:10020000170F0000130F0F0183A100006F00C0083B
|
||||
:10021000130E500037C1ADDE1301F1EEB7000080C0
|
||||
:1002200023A0200083A1000063183106130E600094
|
||||
:10023000B700018083A10000170F0000130FCF0645
|
||||
:1002400023A030006F004005130E7000170F000050
|
||||
:10025000130FCF0437C1ADDE1301F1EEB7000380F9
|
||||
:10026000938080FF23202200170F0000130F8FFAC6
|
||||
:10027000832102006F004002130E8000B70004804B
|
||||
:10028000938080FF83A10000170F0000130FCF01A0
|
||||
:1002900023A030006F004000370110F0130141F23D
|
||||
:1002A0002320C101370110F0130101F223200100C6
|
||||
:040000058000000077
|
||||
:00000001FF
|
|
@ -0,0 +1,35 @@
|
|||
|
||||
Memory Configuration
|
||||
|
||||
Name Origin Length Attributes
|
||||
onChipRam 0x0000000080000000 0x0000000000020000 w !xr
|
||||
*default* 0x0000000000000000 0xffffffffffffffff
|
||||
|
||||
Linker script and memory map
|
||||
|
||||
LOAD build/src/crt.o
|
||||
LOAD /opt/riscv/lib/gcc/riscv64-unknown-elf/10.2.0/libgcc.a
|
||||
START GROUP
|
||||
LOAD /opt/riscv/lib/gcc/riscv64-unknown-elf/10.2.0/../../../../riscv64-unknown-elf/lib/libc.a
|
||||
LOAD /opt/riscv/lib/gcc/riscv64-unknown-elf/10.2.0/../../../../riscv64-unknown-elf/lib/libgloss.a
|
||||
END GROUP
|
||||
LOAD /opt/riscv/lib/gcc/riscv64-unknown-elf/10.2.0/libgcc.a
|
||||
|
||||
.crt_section 0x0000000080000000 0x2b0
|
||||
0x0000000080000000 . = ALIGN (0x4)
|
||||
*crt.o(.text)
|
||||
.text 0x0000000080000000 0x2b0 build/src/crt.o
|
||||
0x0000000080000000 _start
|
||||
0x0000000080000010 trap
|
||||
OUTPUT(build/pmp.elf elf32-littleriscv)
|
||||
|
||||
.data 0x00000000800002b0 0x0
|
||||
.data 0x00000000800002b0 0x0 build/src/crt.o
|
||||
|
||||
.bss 0x00000000800002b0 0x0
|
||||
.bss 0x00000000800002b0 0x0 build/src/crt.o
|
||||
|
||||
.riscv.attributes
|
||||
0x0000000000000000 0x1e
|
||||
.riscv.attributes
|
||||
0x0000000000000000 0x1e build/src/crt.o
|
|
@ -0,0 +1,3 @@
|
|||
PROJ_NAME=pmp
|
||||
|
||||
include ../common/asm.mk
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Samuel Lindemer <samuel.lindemer@ri.se>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#define TEST_ID x28
|
||||
#define TRAP_RA x30
|
||||
|
||||
#define PMPCFG0 0x07120000
|
||||
#define PMPCFG0_ 0x07920808 // locked
|
||||
#define PMPCFG1 0x191f0304
|
||||
#define PMPCFG2 0x000f0506
|
||||
#define PMPCFG3 0x0f1e1900
|
||||
|
||||
#define PMPADDR0 0x20000000 // OFF
|
||||
#define PMPADDR1 0xffffffff // OFF
|
||||
#define PMPADDR2 0x20002000 // NA4 W
|
||||
#define PMPADDR3 0x20003fff // OFF RWX
|
||||
#define PMPADDR4 0x20003fff // OFF X
|
||||
#define PMPADDR5 0x20003fff // OFF RW
|
||||
#define PMPADDR6 0x20001fff // NAPOT RWX
|
||||
#define PMPADDR7 0x20005fff // NAPOT R
|
||||
#define PMPADDR8 0x2000c000 // TOR W
|
||||
#define PMPADDR9 0x2000d000 // TOR R
|
||||
#define PMPADDR10 0xffffffff // TOR RWX
|
||||
#define PMPADDR11 0x00000000 // OFF
|
||||
#define PMPADDR12 0x00000000 // OFF
|
||||
#define PMPADDR13 0x00000000 // NAPOT R
|
||||
#define PMPADDR14 0x00000000 // NAPOT WX
|
||||
#define PMPADDR15 0x00000000 // TOR RWX
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
la x1, trap
|
||||
csrw mtvec, x1
|
||||
j test0
|
||||
|
||||
.global trap
|
||||
trap:
|
||||
csrw mepc, TRAP_RA
|
||||
mret
|
||||
|
||||
// configure PMP, attempt read/write from machine mode
|
||||
test0:
|
||||
li TEST_ID, 0
|
||||
la TRAP_RA, fail
|
||||
|
||||
li x1, 0x80000000
|
||||
li x4, 0x80008000
|
||||
li x2, 0xdeadbeef
|
||||
sw x2, 0x0(x1)
|
||||
sw x2, 0x0(x4)
|
||||
lw x3, 0x0(x1)
|
||||
bne x2, x3, fail
|
||||
lw x3, 0x0(x4)
|
||||
bne x2, x3, fail
|
||||
|
||||
li x5, PMPCFG0
|
||||
csrw pmpcfg0, x5
|
||||
csrr x6, pmpcfg0
|
||||
bne x5, x6, fail
|
||||
li x5, PMPCFG1
|
||||
csrw pmpcfg1, x5
|
||||
li x5, PMPCFG2
|
||||
csrw pmpcfg2, x5
|
||||
li x5, PMPCFG3
|
||||
csrw pmpcfg3, x5
|
||||
li x5, PMPADDR0
|
||||
csrw pmpaddr0, x5
|
||||
csrr x6, pmpaddr0
|
||||
bne x5, x6, fail
|
||||
li x5, PMPADDR1
|
||||
csrw pmpaddr1, x5
|
||||
li x5, PMPADDR2
|
||||
csrw pmpaddr2, x5
|
||||
li x5, PMPADDR3
|
||||
csrw pmpaddr3, x5
|
||||
li x5, PMPADDR4
|
||||
csrw pmpaddr4, x5
|
||||
li x5, PMPADDR5
|
||||
csrw pmpaddr5, x5
|
||||
li x5, PMPADDR6
|
||||
csrw pmpaddr6, x5
|
||||
li x5, PMPADDR7
|
||||
csrw pmpaddr7, x5
|
||||
li x5, PMPADDR8
|
||||
csrw pmpaddr8, x5
|
||||
li x5, PMPADDR9
|
||||
csrw pmpaddr9, x5
|
||||
li x5, PMPADDR10
|
||||
csrw pmpaddr10, x5
|
||||
li x5, PMPADDR11
|
||||
csrw pmpaddr11, x5
|
||||
li x5, PMPADDR12
|
||||
csrw pmpaddr12, x5
|
||||
li x5, PMPADDR13
|
||||
csrw pmpaddr13, x5
|
||||
li x5, PMPADDR14
|
||||
csrw pmpaddr14, x5
|
||||
li x5, PMPADDR15
|
||||
csrw pmpaddr15, x5
|
||||
|
||||
li x2, 0xc0ffee
|
||||
sw x2, 0x0(x1)
|
||||
sw x2, 0x0(x4)
|
||||
lw x3, 0x0(x1)
|
||||
bne x2, x3, fail
|
||||
li x3, 0x0
|
||||
lw x3, 0x0(x4)
|
||||
bne x2, x3, fail
|
||||
|
||||
// lock region 2, attempt read/write from machine mode
|
||||
test1:
|
||||
li TEST_ID, 1
|
||||
la TRAP_RA, fail
|
||||
li x5, PMPCFG0_
|
||||
csrw pmpcfg0, x5 // lock region 2
|
||||
csrr x6, pmpcfg0
|
||||
bne x5, x6, fail
|
||||
li x1, 0x80008000
|
||||
li x2, 0xdeadbeef
|
||||
sw x2, 0x0(x1) // should be OK (write 0x80008000)
|
||||
la TRAP_RA, test2
|
||||
lw x3, 0x0(x1) // should fault (read 0x80008000)
|
||||
j fail
|
||||
|
||||
// "unlock" region 2, attempt read/write from machine mode
|
||||
test2:
|
||||
li TEST_ID, 2
|
||||
la TRAP_RA, fail
|
||||
li x5, PMPCFG0
|
||||
csrw pmpcfg0, x5 // "unlock" region 2
|
||||
csrr x6, pmpcfg0
|
||||
csrwi pmpaddr2, 0x0
|
||||
csrr x6, pmpaddr2
|
||||
beqz x6, fail
|
||||
beq x5, x6, fail
|
||||
li x1, 0x80008000
|
||||
li x2, 0xdeadbeef
|
||||
sw x2, 0x0(x1) // should still be OK (write 0x80008000)
|
||||
la TRAP_RA, test3
|
||||
lw x3, 0x0(x1) // should still fault (read 0x80008000)
|
||||
j fail
|
||||
|
||||
// jump into user mode
|
||||
test3:
|
||||
li TEST_ID, 3
|
||||
la TRAP_RA, fail
|
||||
la x2, test4
|
||||
csrw mepc, x2
|
||||
mret
|
||||
|
||||
// attempt to read/write region 2 from user mode
|
||||
test4:
|
||||
li TEST_ID, 4
|
||||
la TRAP_RA, fail
|
||||
li x2, 0xdeadbeef
|
||||
li x1, 0x80008000
|
||||
sw x2, 0x0(x1) // should be OK (write 0x80008000)
|
||||
la TRAP_RA, test5
|
||||
lw x3, 0x0(x1) // should fault (read 0x80008000)
|
||||
j fail
|
||||
|
||||
// attempt to read/write other regions from user mode
|
||||
test5:
|
||||
li TEST_ID, 5
|
||||
li x2, 0xdeadbeef
|
||||
li x1, 0x80000000
|
||||
sw x2, 0x0(x1)
|
||||
lw x3, 0x0(x1)
|
||||
bne x2, x3, fail // should be OK (read/write 0x80000000)
|
||||
|
||||
test6:
|
||||
li TEST_ID, 6
|
||||
li x1, 0x80010000
|
||||
lw x3, 0x0(x1) // should be OK (read 0x80010000)
|
||||
la TRAP_RA, pass
|
||||
sw x3, 0x0(x1) // should fault (write 0x80010000)
|
||||
j fail
|
||||
|
||||
test7:
|
||||
li TEST_ID, 7
|
||||
la TRAP_RA, fail
|
||||
li x2, 0xdeadbeef
|
||||
li x1, 0x8002fff8
|
||||
sw x2, 0x0(x4) // should be OK (write 0x8002fff8)
|
||||
la TRAP_RA, test5
|
||||
lw x3, 0x0(x4) // should fault (read 0x8002fff8)
|
||||
j fail
|
||||
|
||||
test8:
|
||||
li TEST_ID, 8
|
||||
li x1, 0x8003fff8
|
||||
lw x3, 0x0(x1) // should be OK (read 0x8003fff8)
|
||||
la TRAP_RA, pass
|
||||
sw x3, 0x0(x1) // should fault (write 0x8003fff8)
|
||||
j fail
|
||||
|
||||
fail:
|
||||
li x2, 0xf00fff24
|
||||
sw TEST_ID, 0(x2)
|
||||
|
||||
pass:
|
||||
li x2, 0xf00fff20
|
||||
sw x0, 0(x2)
|
|
@ -0,0 +1,16 @@
|
|||
OUTPUT_ARCH( "riscv" )
|
||||
|
||||
MEMORY {
|
||||
onChipRam (W!RX)/*(RX)*/ : ORIGIN = 0x80000000, LENGTH = 128K
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
|
||||
.crt_section :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*crt.o(.text)
|
||||
} > onChipRam
|
||||
|
||||
}
|
|
@ -4103,6 +4103,10 @@ int main(int argc, char **argv, char **env) {
|
|||
redo(REDO,WorkspaceRegression("lrsc").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../raw/lrsc/build/lrsc.hex")->bootAt(0x00000000u)->run(10e3););
|
||||
#endif
|
||||
|
||||
#ifdef PMP
|
||||
redo(REDO,WorkspaceRegression("pmp").loadHex(string(REGRESSION_PATH) + "../raw/pmp/build/pmp.hex")->bootAt(0x80000000u)->run(10e3););
|
||||
#endif
|
||||
|
||||
#ifdef AMO
|
||||
redo(REDO,WorkspaceRegression("amo").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../raw/amo/build/amo.hex")->bootAt(0x00000000u)->run(10e3););
|
||||
#endif
|
||||
|
|
|
@ -20,6 +20,7 @@ FENCEI?=no
|
|||
MMU?=yes
|
||||
DBUS_EXCLUSIVE?=no
|
||||
DBUS_INVALIDATE?=no
|
||||
PMP?=no
|
||||
SEED?=no
|
||||
LRSC?=no
|
||||
AMO?=no
|
||||
|
@ -251,6 +252,10 @@ ifeq ($(DBUS_INVALIDATE),yes)
|
|||
ADDCFLAGS += -CFLAGS -DDBUS_INVALIDATE
|
||||
endif
|
||||
|
||||
ifeq ($(PMP),yes)
|
||||
ADDCFLAGS += -CFLAGS -DPMP
|
||||
endif
|
||||
|
||||
ifeq ($(MUL),yes)
|
||||
ADDCFLAGS += -CFLAGS -DMUL
|
||||
endif
|
||||
|
|
|
@ -46,8 +46,10 @@ abstract class VexRiscvPosition(name: String) extends ConfigPosition[VexRiscvCo
|
|||
class VexRiscvUniverse extends ConfigUniverse
|
||||
|
||||
object VexRiscvUniverse{
|
||||
val CACHE_ALL = new VexRiscvUniverse
|
||||
val CATCH_ALL = new VexRiscvUniverse
|
||||
val MMU = new VexRiscvUniverse
|
||||
val PMP = new VexRiscvUniverse
|
||||
val FORCE_MULDIV = new VexRiscvUniverse
|
||||
val SUPERVISOR = new VexRiscvUniverse
|
||||
val NO_WRITEBACK = new VexRiscvUniverse
|
||||
|
@ -321,12 +323,11 @@ class IBusDimension(rvcRate : Double) extends VexRiscvDimension("IBus") {
|
|||
|
||||
override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = {
|
||||
val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL)
|
||||
val noMemory = universes.contains(VexRiscvUniverse.NO_MEMORY)
|
||||
val noWriteBack = universes.contains(VexRiscvUniverse.NO_WRITEBACK)
|
||||
val cacheAll = universes.contains(VexRiscvUniverse.CACHE_ALL)
|
||||
|
||||
|
||||
if(r.nextDouble() < 0.5){
|
||||
if(r.nextDouble() < 0.5 && !cacheAll){
|
||||
val mmuConfig = if(universes.contains(VexRiscvUniverse.MMU)) MmuPortConfig( portTlbSize = 4) else null
|
||||
|
||||
val latency = r.nextInt(5) + 1
|
||||
val compressed = r.nextDouble() < rvcRate
|
||||
val injectorStage = r.nextBoolean() || latency == 1
|
||||
|
@ -414,11 +415,11 @@ class DBusDimension extends VexRiscvDimension("DBus") {
|
|||
|
||||
override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = {
|
||||
val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL)
|
||||
val cacheAll = universes.contains(VexRiscvUniverse.CACHE_ALL)
|
||||
val noMemory = universes.contains(VexRiscvUniverse.NO_MEMORY)
|
||||
val noWriteBack = universes.contains(VexRiscvUniverse.NO_WRITEBACK)
|
||||
|
||||
|
||||
if(r.nextDouble() < 0.4 || noMemory){
|
||||
if((r.nextDouble() < 0.4 || noMemory) && !cacheAll){
|
||||
val mmuConfig = if(universes.contains(VexRiscvUniverse.MMU)) MmuPortConfig( portTlbSize = 4, latency = 0) else null
|
||||
val withLrSc = catchAll
|
||||
val earlyInjection = r.nextBoolean() && !universes.contains(VexRiscvUniverse.NO_WRITEBACK)
|
||||
|
@ -490,12 +491,12 @@ class DBusDimension extends VexRiscvDimension("DBus") {
|
|||
}
|
||||
|
||||
|
||||
class MmuDimension extends VexRiscvDimension("DBus") {
|
||||
class MmuPmpDimension extends VexRiscvDimension("DBus") {
|
||||
|
||||
override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = {
|
||||
if(universes.contains(VexRiscvUniverse.MMU)) {
|
||||
new VexRiscvPosition("WithMmu") {
|
||||
override def testParam = "MMU=yes"
|
||||
override def testParam = "MMU=yes PMP=no"
|
||||
|
||||
override def applyOn(config: VexRiscvConfig): Unit = {
|
||||
config.plugins += new MmuPlugin(
|
||||
|
@ -503,9 +504,20 @@ class MmuDimension extends VexRiscvDimension("DBus") {
|
|||
)
|
||||
}
|
||||
}
|
||||
} else if (universes.contains(VexRiscvUniverse.PMP)) {
|
||||
new VexRiscvPosition("WithPmp") {
|
||||
override def testParam = "MMU=no PMP=yes"
|
||||
|
||||
override def applyOn(config: VexRiscvConfig): Unit = {
|
||||
config.plugins += new PmpPlugin(
|
||||
regions = 16,
|
||||
ioRange = _ (31 downto 28) === 0xF
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
new VexRiscvPosition("NoMmu") {
|
||||
override def testParam = "MMU=no"
|
||||
new VexRiscvPosition("NoMemProtect") {
|
||||
override def testParam = "MMU=no PMP=no"
|
||||
|
||||
override def applyOn(config: VexRiscvConfig): Unit = {
|
||||
config.plugins += new StaticMemoryTranslatorPlugin(
|
||||
|
@ -524,6 +536,7 @@ trait CatchAllPosition
|
|||
|
||||
class CsrDimension(freertos : String, zephyr : String, linux : String) extends VexRiscvDimension("Csr") {
|
||||
override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = {
|
||||
val pmp = universes.contains(VexRiscvUniverse.PMP)
|
||||
val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL)
|
||||
val supervisor = universes.contains(VexRiscvUniverse.SUPERVISOR)
|
||||
if(supervisor){
|
||||
|
@ -531,10 +544,15 @@ class CsrDimension(freertos : String, zephyr : String, linux : String) extends V
|
|||
override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.linuxFull(0x80000020l))
|
||||
override def testParam = s"FREERTOS=$freertos ZEPHYR=$zephyr LINUX_REGRESSION=$linux SUPERVISOR=yes"
|
||||
}
|
||||
} else if(pmp){
|
||||
new VexRiscvPosition("Secure") with CatchAllPosition{
|
||||
override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.secure(0x80000020l))
|
||||
override def testParam = s"CSR=yes CSR_SKIP_TEST=yes FREERTOS=$freertos ZEPHYR=$zephyr"
|
||||
}
|
||||
} else if(catchAll){
|
||||
new VexRiscvPosition("MachineOs") with CatchAllPosition{
|
||||
override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.all(0x80000020l))
|
||||
override def testParam = s"CSR=yes FREERTOS=$freertos ZEPHYR=$zephyr"
|
||||
override def testParam = s"CSR=yes CSR_SKIP_TEST=yes FREERTOS=$freertos ZEPHYR=$zephyr"
|
||||
}
|
||||
} else if(r.nextDouble() < 0.3){
|
||||
new VexRiscvPosition("AllNoException") with CatchAllPosition{
|
||||
|
@ -667,6 +685,7 @@ class TestIndividualFeatures extends MultithreadedFunSuite(sys.env.getOrElse("VE
|
|||
val rvcRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_RVC_RATE", "0.5").toDouble
|
||||
val linuxRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_LINUX_RATE", "0.3").toDouble
|
||||
val machineOsRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE", "0.5").toDouble
|
||||
val secureRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_SECURE_RATE", "0.2").toDouble
|
||||
val linuxRegression = sys.env.getOrElse("VEXRISCV_REGRESSION_LINUX_REGRESSION", "yes")
|
||||
val coremarkRegression = sys.env.getOrElse("VEXRISCV_REGRESSION_COREMARK", "yes")
|
||||
val zephyrCount = sys.env.getOrElse("VEXRISCV_REGRESSION_ZEPHYR_COUNT", "4")
|
||||
|
@ -689,7 +708,7 @@ class TestIndividualFeatures extends MultithreadedFunSuite(sys.env.getOrElse("VE
|
|||
new CsrDimension(/*sys.env.getOrElse("VEXRISCV_REGRESSION_FREERTOS_COUNT", "1")*/ "0", zephyrCount, linuxRegression), //Freertos old port software is broken
|
||||
new DecoderDimension,
|
||||
new DebugDimension,
|
||||
new MmuDimension
|
||||
new MmuPmpDimension
|
||||
)
|
||||
|
||||
var clockCounter = 0l
|
||||
|
@ -774,6 +793,13 @@ class TestIndividualFeatures extends MultithreadedFunSuite(sys.env.getOrElse("VE
|
|||
if(demwRate < rand.nextDouble()){
|
||||
universe += VexRiscvUniverse.NO_WRITEBACK
|
||||
}
|
||||
} else if (secureRate > rand.nextDouble()) {
|
||||
universe += VexRiscvUniverse.CACHE_ALL
|
||||
universe += VexRiscvUniverse.CATCH_ALL
|
||||
universe += VexRiscvUniverse.PMP
|
||||
if(demwRate < rand.nextDouble()){
|
||||
universe += VexRiscvUniverse.NO_WRITEBACK
|
||||
}
|
||||
} else {
|
||||
if(machineOsRate > rand.nextDouble()) {
|
||||
universe += VexRiscvUniverse.CATCH_ALL
|
||||
|
|
Loading…
Reference in New Issue