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:
Dolu1990 2021-01-30 20:30:21 +01:00
commit 6aa6191240
32 changed files with 1053 additions and 98 deletions

View File

@ -283,7 +283,7 @@ Note that sometimes Eclipse needs to be restarted in order to be able to place n
## Briey SoC ## 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 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 "") ![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: To run the verilator simulation of the Briey SoC, which can then be connected to OpenOCD/GDB, first get these dependencies:
```sh ```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): 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: A prebuild GCC toolsuite can be found here:
- https://www.sifive.com/products/tools/ => SiFive GNU Embedded Toolchain - https://www.sifive.com/software/ => Prebuilt RISCV GCC Toolchain and Emulator
The VexRiscvSocSoftware makefiles are expecting to find this prebuild version in /opt/riscv/__contentOfThisPreBuild__ The VexRiscvSocSoftware makefiles are expecting to find this prebuild version in /opt/riscv/__contentOfThisPreBuild__

View File

@ -13,6 +13,7 @@ regression_random_linux:
cd ../.. cd ../..
export VEXRISCV_REGRESSION_CONFIG_COUNT=3 export VEXRISCV_REGRESSION_CONFIG_COUNT=3
export VEXRISCV_REGRESSION_CONFIG_LINUX_RATE=1.0 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_FREERTOS_COUNT=1
export VEXRISCV_REGRESSION_ZEPHYR_COUNT=2 export VEXRISCV_REGRESSION_ZEPHYR_COUNT=2
export VEXRISCV_REGRESSION_THREAD_COUNT=1 export VEXRISCV_REGRESSION_THREAD_COUNT=1
@ -24,6 +25,7 @@ regression_random_machine_os:
export VEXRISCV_REGRESSION_CONFIG_COUNT=15 export VEXRISCV_REGRESSION_CONFIG_COUNT=15
export VEXRISCV_REGRESSION_CONFIG_LINUX_RATE=0.0 export VEXRISCV_REGRESSION_CONFIG_LINUX_RATE=0.0
export VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE=1.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_FREERTOS_COUNT=1
export VEXRISCV_REGRESSION_ZEPHYR_COUNT=2 export VEXRISCV_REGRESSION_ZEPHYR_COUNT=2
export VEXRISCV_REGRESSION_THREAD_COUNT=1 export VEXRISCV_REGRESSION_THREAD_COUNT=1
@ -34,6 +36,7 @@ regression_random_baremetal:
export VEXRISCV_REGRESSION_CONFIG_COUNT=40 export VEXRISCV_REGRESSION_CONFIG_COUNT=40
export VEXRISCV_REGRESSION_CONFIG_LINUX_RATE=0.0 export VEXRISCV_REGRESSION_CONFIG_LINUX_RATE=0.0
export VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_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_FREERTOS_COUNT=1
export VEXRISCV_REGRESSION_ZEPHYR_COUNT=no export VEXRISCV_REGRESSION_ZEPHYR_COUNT=no
export VEXRISCV_REGRESSION_THREAD_COUNT=1 export VEXRISCV_REGRESSION_THREAD_COUNT=1

View File

@ -163,6 +163,7 @@ object Riscv{
def UCYCLEH = 0xC80 def UCYCLEH = 0xC80
def UTIME = 0xC01 // rdtime def UTIME = 0xC01 // rdtime
def UTIMEH = 0xC81 def UTIMEH = 0xC81
def UINSTRET = 0xC02 // UR Machine instructions-retired counter.
def UINSTRETH = 0xC82 // UR Upper 32 bits of minstret, RV32I only.
} }
} }

View File

@ -72,6 +72,7 @@ case class MemoryTranslatorCmd() extends Bundle{
case class MemoryTranslatorRsp(p : MemoryTranslatorBusParameter) extends Bundle{ case class MemoryTranslatorRsp(p : MemoryTranslatorBusParameter) extends Bundle{
val physicalAddress = UInt(32 bits) val physicalAddress = UInt(32 bits)
val isIoAccess = Bool val isIoAccess = Bool
val isPaging = Bool
val allowRead, allowWrite, allowExecute = Bool val allowRead, allowWrite, allowExecute = Bool
val exception = Bool val exception = Bool
val refilling = Bool val refilling = Bool

View File

@ -147,7 +147,8 @@ object BrieyConfig{
minstretAccess = CsrAccess.NONE, minstretAccess = CsrAccess.NONE,
ecallGen = false, ecallGen = false,
wfiGenAsWait = false, wfiGenAsWait = false,
ucycleAccess = CsrAccess.NONE ucycleAccess = CsrAccess.NONE,
uinstretAccess = CsrAccess.NONE
) )
), ),
new YamlPlugin("cpu0.yaml") new YamlPlugin("cpu0.yaml")

View File

@ -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())
}

View File

@ -52,8 +52,8 @@ case class MuraxConfig(coreFrequency : HertzNumber,
object MuraxConfig{ object MuraxConfig{
def default : MuraxConfig = default(false) def default : MuraxConfig = default(false, false)
def default(withXip : Boolean) = MuraxConfig( def default(withXip : Boolean = false, bigEndian : Boolean = false) = MuraxConfig(
coreFrequency = 12 MHz, coreFrequency = 12 MHz,
onChipRamSize = 8 kB, onChipRamSize = 8 kB,
onChipRamHexFile = null, onChipRamHexFile = null,
@ -75,12 +75,14 @@ object MuraxConfig{
cmdForkPersistence = withXip, //Required by the Xip controller cmdForkPersistence = withXip, //Required by the Xip controller
prediction = NONE, prediction = NONE,
catchAccessFault = false, catchAccessFault = false,
compressedGen = false compressedGen = false,
bigEndian = bigEndian
), ),
new DBusSimplePlugin( new DBusSimplePlugin(
catchAddressMisaligned = false, catchAddressMisaligned = false,
catchAccessFault = false, catchAccessFault = false,
earlyInjection = false earlyInjection = false,
bigEndian = bigEndian
), ),
new CsrPlugin(CsrPluginConfig.smallest(mtvecInit = if(withXip) 0xE0040020l else 0x80000020l)), new CsrPlugin(CsrPluginConfig.smallest(mtvecInit = if(withXip) 0xE0040020l else 0x80000020l)),
new DecoderSimplePlugin( new DecoderSimplePlugin(
@ -214,9 +216,11 @@ case class Murax(config : MuraxConfig) extends Component{
dataWidth = 32 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 //Arbiter of the cpu dBus/iBus to drive the mainBus
//Priority to dBus, !! cmd transactions can change on the fly !! //Priority to dBus, !! cmd transactions can change on the fly !!
val mainBusArbiter = new MuraxMasterArbiter(pipelinedMemoryBusConfig) val mainBusArbiter = new MuraxMasterArbiter(pipelinedMemoryBusConfig, bigEndianDBus)
//Instanciate the CPU //Instanciate the CPU
val cpu = new VexRiscv( val cpu = new VexRiscv(
@ -258,7 +262,8 @@ case class Murax(config : MuraxConfig) extends Component{
val ram = new MuraxPipelinedMemoryBusRam( val ram = new MuraxPipelinedMemoryBusRam(
onChipRamSize = onChipRamSize, onChipRamSize = onChipRamSize,
onChipRamHexFile = onChipRamHexFile, onChipRamHexFile = onChipRamHexFile,
pipelinedMemoryBusConfig = pipelinedMemoryBusConfig pipelinedMemoryBusConfig = pipelinedMemoryBusConfig,
bigEndian = bigEndianDBus
) )
mainBusMapping += ram.io.bus -> (0x80000000l, onChipRamSize) mainBusMapping += ram.io.bus -> (0x80000000l, onChipRamSize)

View File

@ -10,10 +10,10 @@ import spinal.lib._
import spinal.lib.bus.simple._ import spinal.lib.bus.simple._
import vexriscv.plugin.{DBusSimpleBus, IBusSimpleBus} 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 io = new Bundle{
val iBus = slave(IBusSimpleBus(null)) val iBus = slave(IBusSimpleBus(null))
val dBus = slave(DBusSimpleBus()) val dBus = slave(DBusSimpleBus(bigEndian))
val masterBus = master(PipelinedMemoryBus(pipelinedMemoryBusConfig)) 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.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.address := io.dBus.cmd.valid ? io.dBus.cmd.address | io.iBus.cmd.pc
io.masterBus.cmd.data := io.dBus.cmd.data io.masterBus.cmd.data := io.dBus.cmd.data
io.masterBus.cmd.mask := io.dBus.cmd.size.mux( io.masterBus.cmd.mask := io.dBus.genMask(io.dBus.cmd)
0 -> B"0001",
1 -> B"0011",
default -> B"1111"
) |<< io.dBus.cmd.address(1 downto 0)
io.iBus.cmd.ready := io.masterBus.cmd.ready && !io.dBus.cmd.valid io.iBus.cmd.ready := io.masterBus.cmd.ready && !io.dBus.cmd.valid
io.dBus.cmd.ready := io.masterBus.cmd.ready 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 io = new Bundle{
val bus = slave(PipelinedMemoryBus(pipelinedMemoryBusConfig)) val bus = slave(PipelinedMemoryBus(pipelinedMemoryBusConfig))
} }
@ -71,6 +67,14 @@ case class MuraxPipelinedMemoryBusRam(onChipRamSize : BigInt, onChipRamHexFile :
if(onChipRamHexFile != null){ if(onChipRamHexFile != null){
HexTools.initRam(ram, onChipRamHexFile, 0x80000000l) 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)
} }
} }

View File

@ -126,7 +126,8 @@ object VexRiscvAhbLite3{
minstretAccess = CsrAccess.NONE, minstretAccess = CsrAccess.NONE,
ecallGen = false, ecallGen = false,
wfiGenAsWait = false, wfiGenAsWait = false,
ucycleAccess = CsrAccess.NONE ucycleAccess = CsrAccess.NONE,
uinstretAccess = CsrAccess.NONE
) )
), ),
new YamlPlugin("cpu0.yaml") new YamlPlugin("cpu0.yaml")

View File

@ -124,7 +124,8 @@ object VexRiscvAvalonForSim{
minstretAccess = CsrAccess.NONE, minstretAccess = CsrAccess.NONE,
ecallGen = false, ecallGen = false,
wfiGenAsWait = false, wfiGenAsWait = false,
ucycleAccess = CsrAccess.NONE ucycleAccess = CsrAccess.NONE,
uinstretAccess = CsrAccess.NONE
) )
), ),
new YamlPlugin("cpu0.yaml") new YamlPlugin("cpu0.yaml")

View File

@ -121,7 +121,8 @@ object VexRiscvAvalonWithIntegratedJtag{
minstretAccess = CsrAccess.NONE, minstretAccess = CsrAccess.NONE,
ecallGen = false, ecallGen = false,
wfiGenAsWait = false, wfiGenAsWait = false,
ucycleAccess = CsrAccess.NONE ucycleAccess = CsrAccess.NONE,
uinstretAccess = CsrAccess.NONE
) )
), ),
new YamlPlugin("cpu0.yaml") new YamlPlugin("cpu0.yaml")

View File

@ -122,7 +122,8 @@ object VexRiscvAxi4WithIntegratedJtag{
minstretAccess = CsrAccess.NONE, minstretAccess = CsrAccess.NONE,
ecallGen = false, ecallGen = false,
wfiGenAsWait = false, wfiGenAsWait = false,
ucycleAccess = CsrAccess.NONE ucycleAccess = CsrAccess.NONE,
uinstretAccess = CsrAccess.NONE
) )
), ),
new YamlPlugin("cpu0.yaml") new YamlPlugin("cpu0.yaml")

View File

@ -890,12 +890,16 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam
dataWriteCmd.way := waysHits 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.redo := False
io.cpu.writeBack.accessError := 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.unalignedAccess := io.cpu.writeBack.isValid && unaligned
io.cpu.writeBack.isWrite := request.wr io.cpu.writeBack.isWrite := request.wr
io.mem.cmd.valid := False io.mem.cmd.valid := False
io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto cpuWordRange.low) @@ U(0, cpuWordRange.low bits) io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto cpuWordRange.low) @@ U(0, cpuWordRange.low bits)
io.mem.cmd.length := 0 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 if(catchAccessError) io.cpu.writeBack.accessError := !request.wr && isLast && io.mem.rsp.valid && io.mem.rsp.error
} otherwise { } otherwise {
io.cpu.writeBack.data := dataMux 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){ if(withLrSc) when(request.isLrsc && request.wr){

View File

@ -447,9 +447,9 @@ class InstructionCache(p : InstructionCacheConfig, mmuParameter : MemoryTranslat
val mmuRsp = io.cpu.fetch.mmuRsp val mmuRsp = io.cpu.fetch.mmuRsp
io.cpu.fetch.cacheMiss := !hit.valid 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.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.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.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 io.cpu.decode.physicalAddress := mmuRsp.physicalAddress
}) })
} }

View File

@ -50,6 +50,7 @@ case class CsrPluginConfig(
mcycleAccess : CsrAccess, mcycleAccess : CsrAccess,
minstretAccess : CsrAccess, minstretAccess : CsrAccess,
ucycleAccess : CsrAccess, ucycleAccess : CsrAccess,
uinstretAccess : CsrAccess = CsrAccess.NONE,
wfiGenAsWait : Boolean, wfiGenAsWait : Boolean,
ecallGen : Boolean, ecallGen : Boolean,
xtvecModeGen : Boolean = false, xtvecModeGen : Boolean = false,
@ -144,6 +145,7 @@ object CsrPluginConfig{
mcycleAccess = CsrAccess.NONE, mcycleAccess = CsrAccess.NONE,
minstretAccess = CsrAccess.NONE, minstretAccess = CsrAccess.NONE,
ucycleAccess = CsrAccess.NONE, ucycleAccess = CsrAccess.NONE,
uinstretAccess = CsrAccess.NONE,
wfiGenAsWait = true, wfiGenAsWait = true,
ecallGen = true, ecallGen = true,
xtvecModeGen = false, xtvecModeGen = false,
@ -184,6 +186,7 @@ object CsrPluginConfig{
mcycleAccess = CsrAccess.READ_WRITE, mcycleAccess = CsrAccess.READ_WRITE,
minstretAccess = CsrAccess.READ_WRITE, minstretAccess = CsrAccess.READ_WRITE,
ucycleAccess = CsrAccess.READ_ONLY, ucycleAccess = CsrAccess.READ_ONLY,
uinstretAccess = CsrAccess.READ_ONLY,
wfiGenAsWait = true, wfiGenAsWait = true,
ecallGen = true, ecallGen = true,
xtvecModeGen = false, xtvecModeGen = false,
@ -224,7 +227,8 @@ object CsrPluginConfig{
minstretAccess = CsrAccess.READ_WRITE, minstretAccess = CsrAccess.READ_WRITE,
ecallGen = true, ecallGen = true,
wfiGenAsWait = true, wfiGenAsWait = true,
ucycleAccess = CsrAccess.READ_ONLY ucycleAccess = CsrAccess.READ_ONLY,
uinstretAccess = CsrAccess.READ_ONLY
) )
def all2(mtvecInit : BigInt) : CsrPluginConfig = CsrPluginConfig( def all2(mtvecInit : BigInt) : CsrPluginConfig = CsrPluginConfig(
@ -246,6 +250,7 @@ object CsrPluginConfig{
ecallGen = true, ecallGen = true,
wfiGenAsWait = true, wfiGenAsWait = true,
ucycleAccess = CsrAccess.READ_ONLY, ucycleAccess = CsrAccess.READ_ONLY,
uinstretAccess = CsrAccess.READ_ONLY,
supervisorGen = true, supervisorGen = true,
sscratchGen = true, sscratchGen = true,
stvecAccess = CsrAccess.READ_WRITE, stvecAccess = CsrAccess.READ_WRITE,
@ -277,7 +282,8 @@ object CsrPluginConfig{
minstretAccess = CsrAccess.NONE, minstretAccess = CsrAccess.NONE,
ecallGen = false, ecallGen = false,
wfiGenAsWait = false, wfiGenAsWait = false,
ucycleAccess = CsrAccess.NONE ucycleAccess = CsrAccess.NONE,
uinstretAccess = CsrAccess.NONE
) )
def smallest(mtvecInit : BigInt) = CsrPluginConfig( def smallest(mtvecInit : BigInt) = CsrPluginConfig(
@ -298,7 +304,33 @@ object CsrPluginConfig{
minstretAccess = CsrAccess.NONE, minstretAccess = CsrAccess.NONE,
ecallGen = false, ecallGen = false,
wfiGenAsWait = 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 //User CSR
ucycleAccess(CSR.UCYCLE, mcycle(31 downto 0)) ucycleAccess(CSR.UCYCLE, mcycle(31 downto 0))
ucycleAccess(CSR.UCYCLEH, mcycle(63 downto 32)) 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) { if(utimeAccess != CsrAccess.NONE) {
utimeAccess(CSR.UTIME, utime(31 downto 0)) utimeAccess(CSR.UTIME, utime(31 downto 0))

View File

@ -355,15 +355,14 @@ class DBusCachedPlugin(val config : DataCacheConfig,
exceptionBus.valid := True exceptionBus.valid := True
exceptionBus.code := (input(MEMORY_WR) ? U(7) | U(5)).resized 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) { if(catchIllegal) when (cache.io.cpu.writeBack.mmuException) {
exceptionBus.valid := True exceptionBus.valid := True
exceptionBus.code := (input(MEMORY_WR) ? U(15) | U(13)).resized 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) { when(cache.io.cpu.redo) {
redoBranch.valid := True redoBranch.valid := True

View File

@ -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 cmd = Stream(DBusSimpleCmd())
val rsp = DBusSimpleRsp() val rsp = DBusSimpleRsp()
@ -97,12 +97,27 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{
} }
def cmdS2mPipe() : DBusSimpleBus = { def cmdS2mPipe() : DBusSimpleBus = {
val s = DBusSimpleBus() val s = DBusSimpleBus(bigEndian)
s.cmd << this.cmd.s2mPipe() s.cmd << this.cmd.s2mPipe()
this.rsp := s.rsp this.rsp := s.rsp
s 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 = { def toAxi4Shared(stageCmd : Boolean = false, pendingWritesMax : Int = 7): Axi4Shared = {
val axi = Axi4Shared(DBusSimpleBus.getAxi4Config()) val axi = Axi4Shared(DBusSimpleBus.getAxi4Config())
@ -127,11 +142,7 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{
axi.writeData.arbitrationFrom(dataStage) axi.writeData.arbitrationFrom(dataStage)
axi.writeData.last := True axi.writeData.last := True
axi.writeData.data := dataStage.data axi.writeData.data := dataStage.data
axi.writeData.strb := (dataStage.size.mux( axi.writeData.strb := genMask(dataStage).resized
U(0) -> B"0001",
U(1) -> B"0011",
default -> B"1111"
) << dataStage.address(1 downto 0)).resized
rsp.ready := axi.r.valid rsp.ready := axi.r.valid
@ -155,11 +166,7 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{
mm.write := cmdStage.valid && cmdStage.wr mm.write := cmdStage.valid && cmdStage.wr
mm.address := (cmdStage.address >> 2) @@ U"00" mm.address := (cmdStage.address >> 2) @@ U"00"
mm.writeData := cmdStage.data(31 downto 0) mm.writeData := cmdStage.data(31 downto 0)
mm.byteEnable := (cmdStage.size.mux ( mm.byteEnable := genMask(cmdStage).resized
U(0) -> B"0001",
U(1) -> B"0011",
default -> B"1111"
) << cmdStage.address(1 downto 0)).resized
cmdStage.ready := mm.waitRequestn cmdStage.ready := mm.waitRequestn
@ -178,11 +185,7 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{
bus.ADR := cmdStage.address >> 2 bus.ADR := cmdStage.address >> 2
bus.CTI :=B"000" bus.CTI :=B"000"
bus.BTE := "00" bus.BTE := "00"
bus.SEL := (cmdStage.size.mux ( bus.SEL := genMask(cmdStage).resized
U(0) -> B"0001",
U(1) -> B"0011",
default -> B"1111"
) << cmdStage.address(1 downto 0)).resized
when(!cmdStage.wr) { when(!cmdStage.wr) {
bus.SEL := "1111" bus.SEL := "1111"
} }
@ -206,11 +209,7 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{
bus.cmd.write := cmd.wr bus.cmd.write := cmd.wr
bus.cmd.address := cmd.address.resized bus.cmd.address := cmd.address.resized
bus.cmd.data := cmd.data bus.cmd.data := cmd.data
bus.cmd.mask := cmd.size.mux( bus.cmd.mask := genMask(cmd)
0 -> B"0001",
1 -> B"0011",
default -> B"1111"
) |<< cmd.address(1 downto 0)
cmd.ready := bus.cmd.ready cmd.ready := bus.cmd.ready
rsp.ready := bus.rsp.valid rsp.ready := bus.rsp.valid
@ -262,11 +261,7 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{
1 -> U"01", 1 -> U"01",
default -> U"11" default -> U"11"
) )
bus.cmd.mask := cmd.size.mux( bus.cmd.mask := genMask(cmd)
0 -> B"0001",
1 -> B"0011",
default -> B"1111"
) |<< cmd.address(1 downto 0)
cmd.ready := bus.cmd.ready cmd.ready := bus.cmd.ready
@ -286,6 +281,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false,
emitCmdInMemoryStage : Boolean = false, emitCmdInMemoryStage : Boolean = false,
onlyLoadWords : Boolean = false, onlyLoadWords : Boolean = false,
withLrSc : Boolean = false, withLrSc : Boolean = false,
val bigEndian : Boolean = false,
memoryTranslatorPortConfig : Any = null) extends Plugin[VexRiscv] with DBusAccessService { memoryTranslatorPortConfig : Any = null) extends Plugin[VexRiscv] with DBusAccessService {
var dBus : DBusSimpleBus = null var dBus : DBusSimpleBus = null
@ -391,7 +387,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false,
object MMU_RSP extends Stageable(MemoryTranslatorRsp(mmuBus.p)) object MMU_RSP extends Stageable(MemoryTranslatorRsp(mmuBus.p))
dBus = master(DBusSimpleBus()).setName("dBus") dBus = master(DBusSimpleBus(bigEndian)).setName("dBus")
decode plug new Area { decode plug new Area {
@ -434,11 +430,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false,
insert(MEMORY_ADDRESS_LOW) := dBus.cmd.address(1 downto 0) insert(MEMORY_ADDRESS_LOW) := dBus.cmd.address(1 downto 0)
//formal //formal
val formalMask = dBus.cmd.size.mux( val formalMask = dBus.genMask(dBus.cmd)
U(0) -> B"0001",
U(1) -> B"0011",
default -> B"1111"
) |<< dBus.cmd.address(1 downto 0)
insert(FORMAL_MEM_ADDR) := dBus.cmd.address & U"xFFFFFFFC" insert(FORMAL_MEM_ADDR) := dBus.cmd.address & U"xFFFFFFFC"
insert(FORMAL_MEM_WMASK) := (dBus.cmd.valid && dBus.cmd.wr) ? formalMask | B"0000" insert(FORMAL_MEM_WMASK) := (dBus.cmd.valid && dBus.cmd.wr) ? formalMask | B"0000"
@ -536,13 +528,28 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false,
val rspShifted = MEMORY_READ_DATA() val rspShifted = MEMORY_READ_DATA()
rspShifted := input(MEMORY_READ_DATA) rspShifted := input(MEMORY_READ_DATA)
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)){ switch(input(MEMORY_ADDRESS_LOW)){
is(1){rspShifted(7 downto 0) := input(MEMORY_READ_DATA)(15 downto 8)} 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(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)} is(3){rspShifted(7 downto 0) := input(MEMORY_READ_DATA)(31 downto 24)}
} }
val rspFormated = input(INSTRUCTION)(13 downto 12).mux( 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)), 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)), 1 -> B((31 downto 16) -> (rspShifted(15) && ! input(INSTRUCTION)(14)),(15 downto 0) -> rspShifted(15 downto 0)),
default -> rspShifted //W default -> rspShifted //W

View File

@ -234,7 +234,8 @@ class IBusSimplePlugin( resetVector : BigInt,
val singleInstructionPipeline : Boolean = false, val singleInstructionPipeline : Boolean = false,
val memoryTranslatorPortConfig : Any = null, val memoryTranslatorPortConfig : Any = null,
relaxPredictorAddress : Boolean = true, relaxPredictorAddress : Boolean = true,
predictionBuffer : Boolean = true predictionBuffer : Boolean = true,
bigEndian : Boolean = false
) extends IBusFetcherImpl( ) extends IBusFetcherImpl(
resetVector = resetVector, resetVector = resetVector,
keepPcPlus4 = keepPcPlus4, keepPcPlus4 = keepPcPlus4,
@ -371,6 +372,11 @@ class IBusSimplePlugin( resetVector : BigInt,
fetchRsp.pc := stages.last.output.payload fetchRsp.pc := stages.last.output.payload
fetchRsp.rsp := rspBuffer.output.payload fetchRsp.rsp := rspBuffer.output.payload
fetchRsp.rsp.error.clearWhen(!rspBuffer.output.valid) //Avoid interference with instruction injection from the debug plugin 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 join = Stream(FetchRsp())
val exceptionDetected = False val exceptionDetected = False

View File

@ -151,6 +151,7 @@ class MmuPlugin(ioRange : UInt => Bool,
port.bus.rsp.allowExecute := cacheLine.allowExecute 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.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.refilling := dirty || !cacheHit
port.bus.rsp.isPaging := True
} otherwise { } otherwise {
port.bus.rsp.physicalAddress := port.bus.cmd.last.virtualAddress port.bus.rsp.physicalAddress := port.bus.cmd.last.virtualAddress
port.bus.rsp.allowRead := True port.bus.rsp.allowRead := True
@ -158,6 +159,7 @@ class MmuPlugin(ioRange : UInt => Bool,
port.bus.rsp.allowExecute := True port.bus.rsp.allowExecute := True
port.bus.rsp.exception := False port.bus.rsp.exception := False
port.bus.rsp.refilling := False port.bus.rsp.refilling := False
port.bus.rsp.isPaging := False
} }
port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress) port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress)

View File

@ -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
}
}
}
}

View File

@ -18,6 +18,7 @@ class RegFilePlugin(regFileReadyKind : RegFileReadKind,
writeRfInMemoryStage : Boolean = false, writeRfInMemoryStage : Boolean = false,
readInExecute : Boolean = false, readInExecute : Boolean = false,
syncUpdateOnStall : Boolean = true, syncUpdateOnStall : Boolean = true,
rv32e : Boolean = false,
withShadow : Boolean = false //shadow registers aren't transition hazard free withShadow : Boolean = false //shadow registers aren't transition hazard free
) extends Plugin[VexRiscv] with RegFileService{ ) extends Plugin[VexRiscv] with RegFileService{
import Riscv._ import Riscv._
@ -39,8 +40,11 @@ class RegFilePlugin(regFileReadyKind : RegFileReadKind,
val readStage = if(readInExecute) execute else decode val readStage = if(readInExecute) execute else decode
val writeStage = if(writeRfInMemoryStage) memory else stages.last 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 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) val regFile = Mem(Bits(32 bits),regFileSize) addAttribute(Verilator.public)
if(zeroBoot) regFile.init(List.fill(regFileSize)(B(0, 32 bits))) 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) { when(decode.input(INSTRUCTION)(rdRange) === 0) {
decode.input(REGFILE_WRITE_VALID) := False decode.input(REGFILE_WRITE_VALID) := False
} }
if(rv32e) when(decode.input(INSTRUCTION)(rdRange.head)) {
decode.input(REGFILE_WRITE_VALID) := False
}
//Read register file //Read register file
readStage plug new Area{ readStage plug new Area{
@ -72,8 +79,8 @@ class RegFilePlugin(regFileReadyKind : RegFileReadKind,
} }
def shadowPrefix(that : Bits) = if(withShadow) global.shadow.read ## that else that def shadowPrefix(that : Bits) = if(withShadow) global.shadow.read ## that else that
val regFileReadAddress1 = U(shadowPrefix(srcInstruction(Riscv.rs1Range))) val regFileReadAddress1 = U(shadowPrefix(srcInstruction(clipRange(Riscv.rs1Range))))
val regFileReadAddress2 = U(shadowPrefix(srcInstruction(Riscv.rs2Range))) val regFileReadAddress2 = U(shadowPrefix(srcInstruction(clipRange(Riscv.rs2Range))))
val (rs1Data,rs2Data) = regFileReadyKind match{ val (rs1Data,rs2Data) = regFileReadyKind match{
case `ASYNC` => (global.regFile.readAsync(regFileReadAddress1),global.regFile.readAsync(regFileReadAddress2)) 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 def shadowPrefix(that : Bits) = if(withShadow) global.shadow.write ## that else that
val regFileWrite = global.regFile.writePort.addAttribute(Verilator.public).setName("lastStageRegFileWrite") val regFileWrite = global.regFile.writePort.addAttribute(Verilator.public).setName("lastStageRegFileWrite")
regFileWrite.valid := output(REGFILE_WRITE_VALID) && arbitration.isFiring 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) regFileWrite.data := output(REGFILE_WRITE_DATA)
//Ensure no boot glitches modify X0 //Ensure no boot glitches modify X0

View File

@ -31,6 +31,7 @@ class StaticMemoryTranslatorPlugin(ioRange : UInt => Bool) extends Plugin[VexRis
port.bus.rsp.allowWrite := True port.bus.rsp.allowWrite := True
port.bus.rsp.allowExecute := True port.bus.rsp.allowExecute := True
port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress) port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress)
port.bus.rsp.isPaging := False
port.bus.rsp.exception := False port.bus.rsp.exception := False
port.bus.rsp.refilling := False port.bus.rsp.refilling := False
port.bus.busy := False port.bus.busy := False

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,3 @@
PROJ_NAME=pmp
include ../common/asm.mk

View File

@ -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)

View File

@ -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
}

View File

@ -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);); redo(REDO,WorkspaceRegression("lrsc").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../raw/lrsc/build/lrsc.hex")->bootAt(0x00000000u)->run(10e3););
#endif #endif
#ifdef PMP
redo(REDO,WorkspaceRegression("pmp").loadHex(string(REGRESSION_PATH) + "../raw/pmp/build/pmp.hex")->bootAt(0x80000000u)->run(10e3););
#endif
#ifdef AMO #ifdef AMO
redo(REDO,WorkspaceRegression("amo").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../raw/amo/build/amo.hex")->bootAt(0x00000000u)->run(10e3);); redo(REDO,WorkspaceRegression("amo").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../raw/amo/build/amo.hex")->bootAt(0x00000000u)->run(10e3););
#endif #endif

View File

@ -20,6 +20,7 @@ FENCEI?=no
MMU?=yes MMU?=yes
DBUS_EXCLUSIVE?=no DBUS_EXCLUSIVE?=no
DBUS_INVALIDATE?=no DBUS_INVALIDATE?=no
PMP?=no
SEED?=no SEED?=no
LRSC?=no LRSC?=no
AMO?=no AMO?=no
@ -251,6 +252,10 @@ ifeq ($(DBUS_INVALIDATE),yes)
ADDCFLAGS += -CFLAGS -DDBUS_INVALIDATE ADDCFLAGS += -CFLAGS -DDBUS_INVALIDATE
endif endif
ifeq ($(PMP),yes)
ADDCFLAGS += -CFLAGS -DPMP
endif
ifeq ($(MUL),yes) ifeq ($(MUL),yes)
ADDCFLAGS += -CFLAGS -DMUL ADDCFLAGS += -CFLAGS -DMUL
endif endif

View File

@ -46,8 +46,10 @@ abstract class VexRiscvPosition(name: String) extends ConfigPosition[VexRiscvCo
class VexRiscvUniverse extends ConfigUniverse class VexRiscvUniverse extends ConfigUniverse
object VexRiscvUniverse{ object VexRiscvUniverse{
val CACHE_ALL = new VexRiscvUniverse
val CATCH_ALL = new VexRiscvUniverse val CATCH_ALL = new VexRiscvUniverse
val MMU = new VexRiscvUniverse val MMU = new VexRiscvUniverse
val PMP = new VexRiscvUniverse
val FORCE_MULDIV = new VexRiscvUniverse val FORCE_MULDIV = new VexRiscvUniverse
val SUPERVISOR = new VexRiscvUniverse val SUPERVISOR = new VexRiscvUniverse
val NO_WRITEBACK = 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) = { override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = {
val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL)
val noMemory = universes.contains(VexRiscvUniverse.NO_MEMORY) val cacheAll = universes.contains(VexRiscvUniverse.CACHE_ALL)
val noWriteBack = universes.contains(VexRiscvUniverse.NO_WRITEBACK)
if(r.nextDouble() < 0.5 && !cacheAll){
if(r.nextDouble() < 0.5){
val mmuConfig = if(universes.contains(VexRiscvUniverse.MMU)) MmuPortConfig( portTlbSize = 4) else null val mmuConfig = if(universes.contains(VexRiscvUniverse.MMU)) MmuPortConfig( portTlbSize = 4) else null
val latency = r.nextInt(5) + 1 val latency = r.nextInt(5) + 1
val compressed = r.nextDouble() < rvcRate val compressed = r.nextDouble() < rvcRate
val injectorStage = r.nextBoolean() || latency == 1 val injectorStage = r.nextBoolean() || latency == 1
@ -414,11 +415,11 @@ class DBusDimension extends VexRiscvDimension("DBus") {
override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = {
val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL)
val cacheAll = universes.contains(VexRiscvUniverse.CACHE_ALL)
val noMemory = universes.contains(VexRiscvUniverse.NO_MEMORY) val noMemory = universes.contains(VexRiscvUniverse.NO_MEMORY)
val noWriteBack = universes.contains(VexRiscvUniverse.NO_WRITEBACK) val noWriteBack = universes.contains(VexRiscvUniverse.NO_WRITEBACK)
if((r.nextDouble() < 0.4 || noMemory) && !cacheAll){
if(r.nextDouble() < 0.4 || noMemory){
val mmuConfig = if(universes.contains(VexRiscvUniverse.MMU)) MmuPortConfig( portTlbSize = 4, latency = 0) else null val mmuConfig = if(universes.contains(VexRiscvUniverse.MMU)) MmuPortConfig( portTlbSize = 4, latency = 0) else null
val withLrSc = catchAll val withLrSc = catchAll
val earlyInjection = r.nextBoolean() && !universes.contains(VexRiscvUniverse.NO_WRITEBACK) 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) = { override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = {
if(universes.contains(VexRiscvUniverse.MMU)) { if(universes.contains(VexRiscvUniverse.MMU)) {
new VexRiscvPosition("WithMmu") { new VexRiscvPosition("WithMmu") {
override def testParam = "MMU=yes" override def testParam = "MMU=yes PMP=no"
override def applyOn(config: VexRiscvConfig): Unit = { override def applyOn(config: VexRiscvConfig): Unit = {
config.plugins += new MmuPlugin( 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 { } else {
new VexRiscvPosition("NoMmu") { new VexRiscvPosition("NoMemProtect") {
override def testParam = "MMU=no" override def testParam = "MMU=no PMP=no"
override def applyOn(config: VexRiscvConfig): Unit = { override def applyOn(config: VexRiscvConfig): Unit = {
config.plugins += new StaticMemoryTranslatorPlugin( config.plugins += new StaticMemoryTranslatorPlugin(
@ -524,6 +536,7 @@ trait CatchAllPosition
class CsrDimension(freertos : String, zephyr : String, linux : String) extends VexRiscvDimension("Csr") { class CsrDimension(freertos : String, zephyr : String, linux : String) extends VexRiscvDimension("Csr") {
override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = {
val pmp = universes.contains(VexRiscvUniverse.PMP)
val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL)
val supervisor = universes.contains(VexRiscvUniverse.SUPERVISOR) val supervisor = universes.contains(VexRiscvUniverse.SUPERVISOR)
if(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 applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.linuxFull(0x80000020l))
override def testParam = s"FREERTOS=$freertos ZEPHYR=$zephyr LINUX_REGRESSION=$linux SUPERVISOR=yes" 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){ } else if(catchAll){
new VexRiscvPosition("MachineOs") with CatchAllPosition{ new VexRiscvPosition("MachineOs") with CatchAllPosition{
override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.all(0x80000020l)) 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){ } else if(r.nextDouble() < 0.3){
new VexRiscvPosition("AllNoException") with CatchAllPosition{ 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 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 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 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 linuxRegression = sys.env.getOrElse("VEXRISCV_REGRESSION_LINUX_REGRESSION", "yes")
val coremarkRegression = sys.env.getOrElse("VEXRISCV_REGRESSION_COREMARK", "yes") val coremarkRegression = sys.env.getOrElse("VEXRISCV_REGRESSION_COREMARK", "yes")
val zephyrCount = sys.env.getOrElse("VEXRISCV_REGRESSION_ZEPHYR_COUNT", "4") 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 CsrDimension(/*sys.env.getOrElse("VEXRISCV_REGRESSION_FREERTOS_COUNT", "1")*/ "0", zephyrCount, linuxRegression), //Freertos old port software is broken
new DecoderDimension, new DecoderDimension,
new DebugDimension, new DebugDimension,
new MmuDimension new MmuPmpDimension
) )
var clockCounter = 0l var clockCounter = 0l
@ -774,6 +793,13 @@ class TestIndividualFeatures extends MultithreadedFunSuite(sys.env.getOrElse("VE
if(demwRate < rand.nextDouble()){ if(demwRate < rand.nextDouble()){
universe += VexRiscvUniverse.NO_WRITEBACK 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 { } else {
if(machineOsRate > rand.nextDouble()) { if(machineOsRate > rand.nextDouble()) {
universe += VexRiscvUniverse.CATCH_ALL universe += VexRiscvUniverse.CATCH_ALL