Merge remote-tracking branch 'origin/reworkFetcher'

This commit is contained in:
Dolu1990 2018-08-17 21:26:00 +02:00
commit f8c8643aa5
251 changed files with 226887 additions and 156498 deletions

1
.gitignore vendored
View file

@ -45,3 +45,4 @@ obj_dir
simWorkspace/
tmp/
/archive.tar.gz

View file

@ -11,6 +11,8 @@ scala:
sbt_args: -no-colors -J-Xss2m
script:
- export VEXRISCV_REGRESSION_CONFIG_COUNT=100
- export VEXRISCV_REGRESSION_FREERTOS_COUNT=no
- sbt -jvm-opts travis/jvmopts.compile compile
- sbt -jvm-opts travis/jvmopts.test test
@ -31,22 +33,22 @@ before_install:
- cd ..
# Verilator
#- sudo apt-get install git make autoconf g++ flex bison -y # First time prerequisites
#- git clone http://git.veripool.org/git/verilator # Only first time
#- unset VERILATOR_ROOT # For bash
#- cd verilator
#- git pull # Make sure we're up-to-date
#- git checkout verilator_3_916
#- autoconf # Create ./configure script
#- ./configure
#- make -j$(nproc)
#- sudo make install
#- cd ..
- sudo apt-get install git make autoconf g++ flex bison -y # First time prerequisites
- git clone http://git.veripool.org/git/verilator # Only first time
- unset VERILATOR_ROOT # For bash
- cd verilator
- git pull # Make sure we're up-to-date
- git checkout verilator_3_916
- autoconf # Create ./configure script
- ./configure
- make -j$(nproc)
- sudo make install
- cd ..
- cd VexRiscv
- curl -T README.md -udolu1990:$BINTRAY_KEY https://api.bintray.com/content/spinalhdl/VexRiscv/test/0.0.4/README.md
- curl -X POST -udolu1990:$BINTRAY_KEY https://api.bintray.com/content/spinalhdl/VexRiscv/test/0.0.4/publish
- sbt compile
#- curl -T README.md -udolu1990:$BINTRAY_KEY https://api.bintray.com/content/spinalhdl/VexRiscv/test/0.0.4/README.md
#- curl -X POST -udolu1990:$BINTRAY_KEY https://api.bintray.com/content/spinalhdl/VexRiscv/test/0.0.4/publish
#- sbt compile
before_cache:

View file

@ -333,17 +333,19 @@ You can find multiple software examples and demos here: https://github.com/Spina
Here are some timing and area measurements of the Murax SoC:
```
Murax interlocked stages (0.45 DMIPS/Mhz) ->
Artix 7 -> 305 Mhz 1004 LUT 1297 FF
Cyclone V -> 160 Mhz 744 ALMs
Cyclone IV -> 148 Mhz 1,522 LUT 1,255 FF
ICE40-HX -> 51 Mhz 2402 LC (icestorm)
Murax interlocked stages (0.45 DMIPS/Mhz, 8 bits GPIO) ->
Artix 7 -> 299 Mhz 984 LUT 1186 FF
Cyclone V -> 175 Mhz 710 ALMs
Cyclone IV -> 137 Mhz 1,436 LUT 1,193 FF
iCE40 -> 48 Mhz 2337 LC (icestorm)
iCE40Ultra -> 20 Mhz 2337 LC (icestorm)
MuraxFast bypassed stages (0.65 DMIPS/Mhz) ->
Artix 7 -> 312 Mhz 1240 LUT 1330 FF
Cyclone V -> 159 Mhz 884 ALMs
Cyclone IV -> 142 Mhz 1,755 LUT 1,289 FF
ICE40-HX -> 50 Mhz, 2787 LC (icestorm)
MuraxFast bypassed stages (0.65 DMIPS/Mhz, 8 bits GPIO) ->
Artix 7 -> 294 Mhz 1128 LUT 1219 FF
Cyclone V -> 165 Mhz 840 ALMs
Cyclone IV -> 141 Mhz 1,680 LUT 1,227 FF
iCE40 -> 48 Mhz 2702 LC (icestorm)
iCE40Ultra -> 22 Mhz 2702 LC (icestorm)
```
Some scripts to generate the SoC and call the icestorm toolchain can be found here: `scripts/Murax/`
@ -418,14 +420,10 @@ val cpu = new VexRiscv(
config = VexRiscvConfig(
//Provide a list of plugins which will futher add their logic into the CPU
plugins = List(
new PcManagerSimplePlugin(
new IBusSimplePlugin(
resetVector = 0x00000000l,
relaxedPcCalculation = true
),
new IBusSimplePlugin(
interfaceKeepData = false,
catchAccessFault = false
),
new DBusSimplePlugin(
catchAddressMisaligned = false,
catchAccessFault = false
@ -451,8 +449,7 @@ val cpu = new VexRiscv(
),
new BranchPlugin(
earlyBranch = false,
catchAddressMisaligned = false,
prediction = NONE
catchAddressMisaligned = false
),
new YamlPlugin("cpu0.yaml")
)
@ -625,7 +622,6 @@ as everything else, including the program counter is added into the CPU via plug
This chapter describes plugins currently implemented.
- [PcManagerSimplePlugin](#pcmanagersimpleplugin)
- [IBusSimplePlugin](#ibussimpleplugin)
- [IBusCachedPlugin](#ibuscachedplugin)
- [DecoderSimplePlugin](#decodersimpleplugin)
@ -655,27 +651,27 @@ This plugin implements the program counter and a jump service to all plugins.
| Parameters | type | description |
| ------ | ----------- | ------ |
| resetVector | BigInt | Address of the program counter after the reset |
| relaxedPcCalculation | Boolean | By default, jumps have an asynchronous immediate effect on the program counter, which reduces the branch penalty by one cycle but could reduce the FMax as it will combinatorialy drive the instruction bus address signal. To avoid this you can set this parameter to true, which will make the jump affecting the programm counter in a sequancial way, which will cut the combinatorial path but add one additional cycle of penalty when a jump occur. |
| relaxedPcCalculation | Boolean | By default jump have an asynchronous immediate effect on the program counter, which allow to reduce the branch penalties by one cycle but could reduce the FMax as it will combinatorialy drive the instruction bus address signal. To avoid this you can set this parameter to true, which will make the jump affecting the programm counter in a sequancial way, which will cut the combinatorial path but add one additional cycle of penalty when a jump occur. |
The jump interface implemented by this plugin allows all other plugins to request jumps. The stage argument specifies from which stage the jump is asked,
which allows the PcManagerSimplePlugin plugin to manage priorities between jump requests.
```scala
trait JumpService{
def createJumpInterface(stage : Stage) : Flow[UInt]
}
```
This plugin operates on the prefetch stage.
#### IBusSimplePlugin
This plugin fetches instructions via a very simple and neutral memory interface going outside the CPU.
This plugin implement the CPU frontend (instruction fetch) via a very simple and neutral memory interface going outside the CPU.
| Parameters | type | description |
| ------ | ----------- | ------ |
| interfaceKeepData | Boolean | Specifies if the read/response interface keeps the data until the next one, or if it's only present a single cycle.|
| catchAccessFault | Boolean | When the read response specifies a read error and this parameter is true, it will generate a CPU exception trap |
| ------ | ----------- | ------ |
| catchAccessFault | Boolean | If an the read response specify an read error and this parameter is true, it will generate an CPU exception trap |
| resetVector | BigInt | Address of the program counter after the reset |
| relaxedPcCalculation | Boolean | By default jump have an asynchronous immediate effect on the program counter, which allow to reduce the branch penalties by one cycle but could reduce the FMax as it will combinatorialy drive the instruction bus address signal. To avoid this you can set this parameter to true, which will make the jump affecting the programm counter in a sequancial way, which will cut the combinatorial path but add one additional cycle of penalty when a jump occur. |
| relaxedBusCmdValid | Boolean | Same than relaxedPcCalculation, but for the iBus.cmd.valid pin. |
| compressedGen | Boolean | Enable RVC support |
| busLatencyMin | Int | Specify the minimal latency between the iBus.cmd and iBus.rsp, which will add the corresponding number of stages into the frontend to keep the IPC to 1.|
| injectorStage | Boolean | Add a stage between the frontend and the decode stage of the CPU to improve FMax. (busLatencyMin + injectorStage) should be at least two. |
| prediction | BranchPrediction | Can be set to NONE/STATIC/DYNAMIC/DYNAMIC_TARGET to specify the branch predictor implementation, see bellow for more descriptions |
| historyRamSizeLog2 | Int | Specify the number of entries in the direct mapped prediction cache of DYNAMIC/DYNAMIC_TARGET implementation. 2 pow historyRamSizeLog2 entries |
Here is the SimpleBus interface definition
@ -705,11 +701,18 @@ case class IBusSimpleBus(interfaceKeepData : Boolean) extends Bundle with IMaste
}
```
There is at least one cycle latency between a cmd and the corresponding rsp. The rsp.ready flag should be false after a cmd until the rsp is present.
There is at least one cycle latency between que cmd and the rsp. the rsp.ready flag should be false after a cmd until the rsp is present.
Note that bridges are available to convert this interface into AXI4 and Avalon.
Note that bridges are implemented to convert this interface into AXI4 and Avalon
The jump interface implemented by this plugin allow all other plugin to request jumps. The stage argument specify from which stage the jump is asked, which will allow the PcManagerSimplePlugin plugin to manage priorities between jump requests.
```scala
trait JumpService{
def createJumpInterface(stage : Stage) : Flow[UInt]
}
```
This plugin fits in the fetch stage.
#### IBusCachedPlugin
@ -728,6 +731,11 @@ Simple and light multi-way instruction cache.
| catchIllegalAccess | Boolean | Catch when a memory access is done on non valid memory address (MMU) |
| catchAccessFault | Boolean | Catch when the memeory bus is responding with an error |
| catchMemoryTranslationMiss | Boolean | Catch when the MMU miss a TLB |
| resetVector | BigInt | Address of the program counter after the reset |
| relaxedPcCalculation | Boolean | By default jump have an asynchronous immediate effect on the program counter, which allow to reduce the branch penalties by one cycle but could reduce the FMax as it will combinatorialy drive the instruction bus address signal. To avoid this you can set this parameter to true, which will make the jump affecting the programm counter in a sequancial way, which will cut the combinatorial path but add one additional cycle of penalty when a jump occur. |
| compressedGen | Boolean | Enable RVC support |
| prediction | BranchPrediction | Can be set to NONE/STATIC/DYNAMIC/DYNAMIC_TARGET to specify the branch predictor implementation, see bellow for more descriptions |
| historyRamSizeLog2 | Int | Specify the number of entries in the direct mapped prediction cache of DYNAMIC/DYNAMIC_TARGET implementation. 2 pow historyRamSizeLog2 entries |
Note: If you enable the twoCycleRam option and if wayCount is bigger than one, then the register file plugin should be configured to read the regFile in a asynchronous manner.
@ -823,17 +831,14 @@ Implements SLL/SRL/SRA instructions by using a full barrel shifter, so it execut
#### BranchPlugin
This plugin implements all branch/jump instructions (JAL/JALR/BEQ/BNE/BLT/BGE/BLTU/BGEU) with some optional branch prediction. Each of these branch predictions could have been implemented
as separate plugin.
This plugin implement all branch/jump instructions (JAL/JALR/BEQ/BNE/BLT/BGE/BLTU/BGEU) with primitives used by the cpu frontend plugins to implement branch prediction. The prediction implementation is set in the frontend plugins (IBusX)
| Parameters | type | description |
| ------ | ----------- | ------ |
| earlyBranch | Boolean | By default the branch is done in the Memory stage to relax timings, but if this option is set it's done in the Execute stage|
| catchAddressMisaligned | Boolean | If a jump/branch is done in an unaligned PC address, it will fire a trap exception |
| prediction | BranchPrediction | Can be set to NONE/STATIC/DYNAMIC/DYNAMIC_TARGET to specify the branch predictor implementation, see below for more descriptions |
| historyRamSizeLog2 | Int | Specify the number of entries in the direct mapped prediction cache of DYNAMIC/DYNAMIC_TARGET implementation. 2 pow historyRamSizeLog2 entries |
| catchAddressMisaligned | Boolean | If a jump/branch is done in an unaligned PC address, it will fire an trap exception |
Each mispredicted jump will produce between 2 and 4 penalty cycles depending the `earlyBranch` and the `PcManagerSimplePlugin.relaxedPcCalculation` configurations.
Each miss predicted jumps will produce between 2 and 4 cycles penalty depending the `earlyBranch` and the `PcManagerSimplePlugin.relaxedPcCalculation` configurations
##### Prediction NONE

View file

@ -9,11 +9,14 @@ scalaVersion := "2.11.6"
EclipseKeys.withSource := true
libraryDependencies ++= Seq(
"com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.1.5",
"com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.1.5",
"com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.1.6",
"com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.1.6",
"org.scalatest" % "scalatest_2.11" % "2.2.1",
"org.yaml" % "snakeyaml" % "1.8"
)
addCompilerPlugin("org.scala-lang.plugins" % "scala-continuations-plugin_2.11.6" % "1.0.2")
scalacOptions += "-P:continuations:enable"
fork := true

View file

@ -0,0 +1,58 @@
package spinal.lib.misc
import spinal.core._
import scala.collection.mutable.ArrayBuffer
object HexTools{
def readHexFile(path : String, hexOffset : Int, callback : (Int, Int) => Unit) : Unit ={
import scala.io.Source
def hToI(that : String, start : Int, size : Int) = Integer.parseInt(that.substring(start,start + size), 16)
var offset = 0
for (line <- Source.fromFile(path).getLines) {
if (line.charAt(0) == ':'){
val byteCount = hToI(line, 1, 2)
val nextAddr = hToI(line, 3, 4) + offset
val key = hToI(line, 7, 2)
key match {
case 0 =>
for(i <- 0 until byteCount){
callback(nextAddr + i - hexOffset, hToI(line, 9 + i * 2, 2))
}
case 2 =>
offset = hToI(line, 9, 4) << 4
case 4 =>
offset = hToI(line, 9, 4) << 16
case 3 =>
case 5 =>
case 1 =>
}
}
}
}
def readHexFile(path : String, hexOffset : Int): Array[BigInt] ={
var onChipRomSize = 0
readHexFile(path, hexOffset ,(address, _) => {
onChipRomSize = Math.max((address).toInt, onChipRomSize) + 1
})
val initContent = Array.fill[BigInt]((onChipRomSize+3)/4)(0)
readHexFile(path, hexOffset,(address,data) => {
val addressWithoutOffset = (address).toInt
if(addressWithoutOffset < onChipRomSize)
initContent(addressWithoutOffset >> 2) |= BigInt(data) << ((addressWithoutOffset & 3)*8)
})
initContent
}
def initRam[T <: Data](ram : Mem[T], onChipRamHexFile : String, hexOffset : BigInt): Unit ={
val initContent = Array.fill[BigInt](ram.wordCount)(0)
HexTools.readHexFile(onChipRamHexFile, 0,(address,data) => {
val addressWithoutOffset = (address - hexOffset).toInt
initContent(addressWithoutOffset >> 2) |= BigInt(data) << ((addressWithoutOffset & 3)*8)
})
ram.initBigInt(initContent)
}
}

View file

@ -7,12 +7,14 @@ import spinal.lib._
import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
trait PipelineConfig[T]
trait Pipeline {
type T <: Pipeline
val plugins = ArrayBuffer[Plugin[T]]()
var stages = ArrayBuffer[Stage]()
var unremovableStages = mutable.Set[Stage]()
val configs = mutable.HashMap[PipelineConfig[_], Any]()
// val services = ArrayBuffer[Any]()
def indexOf(stage : Stage) = stages.indexOf(stage)
@ -28,6 +30,9 @@ trait Pipeline {
filtered.length != 0
}
def update[T](that : PipelineConfig[T], value : T) : Unit = configs(that) = value
def apply[T](that : PipelineConfig[T]) : T = configs(that).asInstanceOf[T]
def build(): Unit ={
plugins.foreach(_.pipeline = this.asInstanceOf[T])
plugins.foreach(_.setup(this.asInstanceOf[T]))
@ -117,7 +122,7 @@ trait Pipeline {
}
for(stageIndex <- 0 until stages.length; stage = stages(stageIndex)){
stage.arbitration.isStuckByOthers := stage.arbitration.haltByOther || stages.takeRight(stages.length - stageIndex - 1).map(s => s.arbitration.haltItself/* && !s.arbitration.removeIt*/).foldLeft(False)(_ || _)
stage.arbitration.isStuckByOthers := stage.arbitration.haltByOther || stages.takeRight(stages.length - stageIndex - 1).map(s => s.arbitration.isStuck/* && !s.arbitration.removeIt*/).foldLeft(False)(_ || _)
stage.arbitration.isStuck := stage.arbitration.haltItself || stage.arbitration.isStuckByOthers
stage.arbitration.isMoving := !stage.arbitration.isStuck && !stage.arbitration.removeIt
stage.arbitration.isFiring := stage.arbitration.isValid && !stage.arbitration.isStuck && !stage.arbitration.removeIt
@ -126,7 +131,7 @@ trait Pipeline {
for(stageIndex <- 1 until stages.length){
val stageBefore = stages(stageIndex - 1)
val stage = stages(stageIndex)
stage.arbitration.isValid.setAsReg() init(False)
when(!stage.arbitration.isStuck || stage.arbitration.removeIt) {
stage.arbitration.isValid := False
}

View file

@ -62,14 +62,14 @@ object Riscv{
def LR = M"00010--00000-----010-----0101111"
def SC = M"00011------------010-----0101111"
def BEQ = M"-----------------000-----1100011"
def BNE = M"-----------------001-----1100011"
def BLT = M"-----------------100-----1100011"
def BGE = M"-----------------101-----1100011"
def BLTU = M"-----------------110-----1100011"
def BGEU = M"-----------------111-----1100011"
def BEQ (rvc : Boolean) = if(rvc) M"-----------------000-----1100011" else M"-----------------000---0-1100011"
def BNE (rvc : Boolean) = if(rvc) M"-----------------001-----1100011" else M"-----------------001---0-1100011"
def BLT (rvc : Boolean) = if(rvc) M"-----------------100-----1100011" else M"-----------------100---0-1100011"
def BGE (rvc : Boolean) = if(rvc) M"-----------------101-----1100011" else M"-----------------101---0-1100011"
def BLTU(rvc : Boolean) = if(rvc) M"-----------------110-----1100011" else M"-----------------110---0-1100011"
def BGEU(rvc : Boolean) = if(rvc) M"-----------------111-----1100011" else M"-----------------111---0-1100011"
def JALR = M"-----------------000-----1100111"
def JAL = M"-------------------------1101111"
def JAL(rvc : Boolean) = if(rvc) M"-------------------------1101111" else M"----------0--------------1101111"
def LUI = M"-------------------------0110111"
def AUIPC = M"-------------------------0010111"

View file

@ -11,6 +11,15 @@ trait JumpService{
def createJumpInterface(stage : Stage, priority : Int = 0) : Flow[UInt]
}
trait IBusFetcher{
def haltIt() : Unit
def flushIt() : Unit
def incoming() : Bool
def pcValid(stage : Stage) : Bool
def getInjectionPort() : Stream[Bits]
}
trait DecoderService{
def add(key : MaskedLiteral,values : Seq[(Stageable[_ <: BaseType],Any)])
def add(encoding :Seq[(MaskedLiteral,Seq[(Stageable[_ <: BaseType],Any)])])
@ -48,20 +57,22 @@ case class MemoryTranslatorRsp() extends Bundle{
val isIoAccess = Bool
val allowRead, allowWrite, allowExecute, allowUser = Bool
val miss = Bool
val hit = Bool
}
case class MemoryTranslatorBus() extends Bundle with IMasterSlave{
val cmd = MemoryTranslatorCmd()
val rsp = MemoryTranslatorRsp()
val end = Bool
override def asMaster() : Unit = {
out(cmd)
out(cmd, end)
in(rsp)
}
}
trait MemoryTranslator{
def newTranslationPort(stage : Stage, args : Any) : MemoryTranslatorBus
def newTranslationPort(priority : Int, args : Any) : MemoryTranslatorBus
}

View file

@ -49,7 +49,7 @@ class Stage() extends Area{
val removeIt = False //When settable, unschedule the instruction as if it was never executed (no side effect)
val flushAll = False //When settable, unschedule instructions in the current stage and all prior ones
val redoIt = False //Allow to notify that a given instruction in a pipeline is rescheduled
val isValid = RegInit(False) //Inform if a instruction is in the current stage
val isValid = Bool //Inform if a instruction is in the current stage
val isStuck = Bool //Inform if the instruction is stuck (haltItself || haltByOther)
val isStuckByOthers = Bool //Inform if the instruction is stuck by sombody else
def isRemoved = removeIt //Inform if the instruction is going to be unschedule the current cycle

View file

@ -31,32 +31,40 @@ object TestsWorkspace {
SpinalConfig(mergeAsyncProcess = false).generateVerilog {
val configFull = VexRiscvConfig(
plugins = List(
new PcManagerSimplePlugin(
new IBusSimplePlugin(
resetVector = 0x80000000l,
relaxedPcCalculation = false
relaxedPcCalculation = false,
relaxedBusCmdValid = false,
prediction = NONE,
historyRamSizeLog2 = 10,
catchAccessFault = true,
compressedGen = true,
busLatencyMin = 1,
injectorStage = true
),
// new IBusSimplePlugin(
// interfaceKeepData = false,
// catchAccessFault = true
// new IBusCachedPlugin(
// resetVector = 0x80000000l,
// compressedGen = true,
// prediction = DYNAMIC_TARGET,
// injectorStage = true,
// config = InstructionCacheConfig(
// cacheSize = 1024*16,
// bytePerLine = 32,
// wayCount = 1,
// addressWidth = 32,
// cpuDataWidth = 32,
// memDataWidth = 32,
// catchIllegalAccess = true,
// catchAccessFault = true,
// catchMemoryTranslationMiss = true,
// asyncTagMemory = false,
// twoCycleRam = false,
// twoCycleCache = true
// ),
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
// portTlbSize = 4
// )
// ),
new IBusCachedPlugin(
config = InstructionCacheConfig(
cacheSize = 1024*16,
bytePerLine = 32,
wayCount = 1,
addressWidth = 32,
cpuDataWidth = 32,
memDataWidth = 32,
catchIllegalAccess = true,
catchAccessFault = true,
catchMemoryTranslationMiss = true,
asyncTagMemory = false,
twoCycleRam = false
),
memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
portTlbSize = 4
)
),
// new DBusSimplePlugin(
// catchAddressMisaligned = true,
// catchAccessFault = true,
@ -94,13 +102,13 @@ object TestsWorkspace {
),
new RegFilePlugin(
regFileReadyKind = plugin.ASYNC,
zeroBoot = false
zeroBoot = true
),
new IntAluPlugin,
new SrcPlugin(
separatedAddSub = false
),
new FullBarrelShifterPlugin(earlyInjection = true),
new FullBarrelShifterPlugin(earlyInjection = false),
// new LightShifterPlugin,
new HazardSimplePlugin(
bypassExecute = true,
@ -113,9 +121,9 @@ object TestsWorkspace {
),
// new HazardSimplePlugin(false, true, false, true),
// new HazardSimplePlugin(false, false, false, false),
// new MulPlugin,
new MulPlugin,
new MulDivIterativePlugin(
genMul = true,
genMul = false,
genDiv = true,
mulUnrollFactor = 32,
divUnrollFactor = 1
@ -124,113 +132,14 @@ object TestsWorkspace {
new CsrPlugin(CsrPluginConfig.all(0x80000020l).copy(deterministicInteruptionEntry = false)),
new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
new BranchPlugin(
earlyBranch = true,
catchAddressMisaligned = true,
prediction = DYNAMIC_TARGET,
historyRamSizeLog2 = 8
earlyBranch = false,
catchAddressMisaligned = true
),
new YamlPlugin("cpu0.yaml")
)
)
val configLight = VexRiscvConfig(
plugins = List(
new PcManagerSimplePlugin(0x00000000l, false),
new IBusSimplePlugin(
interfaceKeepData = true,
catchAccessFault = false
),
new DBusSimplePlugin(
catchAddressMisaligned = false,
catchAccessFault = false
),
new DecoderSimplePlugin(
catchIllegalInstruction = false
),
new RegFilePlugin(
regFileReadyKind = plugin.ASYNC,
zeroBoot = false
),
new IntAluPlugin,
new SrcPlugin(
separatedAddSub = false
),
// new FullBarrelShifterPlugin,
new LightShifterPlugin,
// new HazardSimplePlugin(true, true, true, true),
// new HazardSimplePlugin(false, true, false, true),
new HazardSimplePlugin(
bypassExecute = false,
bypassMemory = false,
bypassWriteBack = false,
bypassWriteBackBuffer = false,
pessimisticUseSrc = false,
pessimisticWriteRegFile = false,
pessimisticAddressMatch = false
),
// new HazardPessimisticPlugin,
new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
// new MulPlugin,
// new DivPlugin,
// new MachineCsr(csrConfig),
new BranchPlugin(
earlyBranch = false,
catchAddressMisaligned = false,
prediction = NONE
)
)
)
val configTest = VexRiscvConfig(
plugins = List(
new PcManagerSimplePlugin(0x00000000l, true),
new IBusSimplePlugin(
interfaceKeepData = true,
catchAccessFault = true
),
new DBusSimplePlugin(
catchAddressMisaligned = true,
catchAccessFault = true
),
new CsrPlugin(CsrPluginConfig.small(0x80000020l)),
new DecoderSimplePlugin(
catchIllegalInstruction = true
),
new RegFilePlugin(
regFileReadyKind = plugin.SYNC,
zeroBoot = false
),
new IntAluPlugin,
new SrcPlugin(
separatedAddSub = false
),
new FullBarrelShifterPlugin,
// new LightShifterPlugin,
// new HazardSimplePlugin(true, true, true, true),
// new HazardSimplePlugin(false, true, false, true),
new HazardSimplePlugin(
bypassExecute = false,
bypassMemory = false,
bypassWriteBack = false,
bypassWriteBackBuffer = false,
pessimisticUseSrc = false,
pessimisticWriteRegFile = false,
pessimisticAddressMatch = false
),
// new MulPlugin,
// new DivPlugin,
// new MachineCsr(csrConfig),
new BranchPlugin(
earlyBranch = false,
catchAddressMisaligned = true,
prediction = NONE
)
)
)
val toplevel = new VexRiscv(configFull)
// val toplevel = new VexRiscv(configLight)
@ -298,4 +207,4 @@ object TestsWorkspace {
//TODO MulPlugin doesn't fit well on Artix (FMAX)
//TODO PcReg design is unoptimized by Artix synthesis
//TODO FMAX SRC mux + bipass mux prioriti
//TODO FMAX, isFiring is to pesimisstinc in some cases(include removeIt flushed ..)
//TODO FMAX, isFiring is to pesimisstinc in some cases(include removeIt flushed ..)

View file

@ -3,9 +3,21 @@ package vexriscv
import vexriscv.plugin._
import spinal.core._
case class VexRiscvConfig(plugins : Seq[Plugin[VexRiscv]]){
import scala.collection.mutable.ArrayBuffer
object VexRiscvConfig{
def apply(plugins : Seq[Plugin[VexRiscv]]) : VexRiscvConfig = {
val config = VexRiscvConfig()
config.plugins ++= plugins
config
}
}
case class VexRiscvConfig(){
val plugins = ArrayBuffer[Plugin[VexRiscv]]()
//Default Stageables
object IS_RVC extends Stageable(Bool)
object BYPASSABLE_EXECUTE_STAGE extends Stageable(Bool)
object BYPASSABLE_MEMORY_STAGE extends Stageable(Bool)
object RS1 extends Stageable(Bits(32 bits))
@ -22,6 +34,7 @@ case class VexRiscvConfig(plugins : Seq[Plugin[VexRiscv]]){
object REGFILE_WRITE_VALID extends Stageable(Bool)
object REGFILE_WRITE_DATA extends Stageable(Bits(32 bits))
object SRC1 extends Stageable(Bits(32 bits))
object SRC2 extends Stageable(Bits(32 bits))
object SRC_ADD_SUB extends Stageable(Bits(32 bits))
@ -39,10 +52,11 @@ case class VexRiscvConfig(plugins : Seq[Plugin[VexRiscv]]){
object FORMAL_MEM_WMASK extends Stageable(Bits(4 bits))
object FORMAL_MEM_RDATA extends Stageable(Bits(32 bits))
object FORMAL_MEM_WDATA extends Stageable(Bits(32 bits))
object FORMAL_INSTRUCTION extends Stageable(Bits(32 bits))
object Src1CtrlEnum extends SpinalEnum(binarySequential){
val RS, IMU, FOUR = newElement() //IMU, IMZ IMJB
val RS, IMU, PC_INCREMENT = newElement() //IMU, IMZ IMJB
}
object Src2CtrlEnum extends SpinalEnum(binarySequential){
@ -54,12 +68,13 @@ case class VexRiscvConfig(plugins : Seq[Plugin[VexRiscv]]){
object RVC_GEN extends PipelineConfig[Boolean]
class VexRiscv(val config : VexRiscvConfig) extends Component with Pipeline{
type T = VexRiscv
import config._
stages ++= List.fill(6)(new Stage())
val prefetch :: fetch :: decode :: execute :: memory :: writeBack :: Nil = stages.toList
stages ++= List.fill(4)(new Stage())
val /*prefetch :: fetch :: */decode :: execute :: memory :: writeBack :: Nil = stages.toList
plugins ++= config.plugins
//regression usage
@ -75,6 +90,8 @@ class VexRiscv(val config : VexRiscvConfig) extends Component with Pipeline{
decode.arbitration.removeIt.noBackendCombMerge //Verilator perf
memory.arbitration.removeIt.noBackendCombMerge
execute.arbitration.flushAll.noBackendCombMerge
this(RVC_GEN) = false
}

View file

@ -9,13 +9,14 @@ import spinal.lib._
import spinal.lib.bus.amba3.apb._
import spinal.lib.bus.amba4.axi._
import spinal.lib.com.jtag.Jtag
import spinal.lib.com.uart.{Uart, UartCtrlGenerics, UartCtrlMemoryMappedConfig, Apb3UartCtrl}
import spinal.lib.com.uart.{Apb3UartCtrl, Uart, UartCtrlGenerics, UartCtrlMemoryMappedConfig}
import spinal.lib.graphic.RgbConfig
import spinal.lib.graphic.vga.{Vga, Axi4VgaCtrlGenerics, Axi4VgaCtrl}
import spinal.lib.graphic.vga.{Axi4VgaCtrl, Axi4VgaCtrlGenerics, Vga}
import spinal.lib.io.TriStateArray
import spinal.lib.memory.sdram._
import spinal.lib.soc.pinsec.{PinsecTimerCtrlExternal, PinsecTimerCtrl}
import spinal.lib.system.debugger.{SystemDebugger, JtagBridge, JtagAxi4SharedDebugger, SystemDebuggerConfig}
import spinal.lib.misc.HexTools
import spinal.lib.soc.pinsec.{PinsecTimerCtrl, PinsecTimerCtrlExternal}
import spinal.lib.system.debugger.{JtagAxi4SharedDebugger, JtagBridge, SystemDebugger, SystemDebuggerConfig}
import scala.collection.mutable.ArrayBuffer
@ -53,6 +54,8 @@ object BrieyConfig{
// catchAccessFault = true
// ),
new IBusCachedPlugin(
resetVector = 0x80000000l,
prediction = STATIC,
config = InstructionCacheConfig(
cacheSize = 4096,
bytePerLine =32,
@ -64,7 +67,8 @@ object BrieyConfig{
catchAccessFault = true,
catchMemoryTranslationMiss = true,
asyncTagMemory = false,
twoCycleRam = true
twoCycleRam = true,
twoCycleCache = true
)
// askMemoryTranslation = true,
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
@ -122,8 +126,7 @@ object BrieyConfig{
),
new BranchPlugin(
earlyBranch = false,
catchAddressMisaligned = true,
prediction = STATIC
catchAddressMisaligned = true
),
new CsrPlugin(
config = CsrPluginConfig(

View file

@ -13,13 +13,12 @@ object FormalSimple extends App{
plugins = List(
new FormalPlugin,
new HaltOnExceptionPlugin,
new PcManagerSimplePlugin(
resetVector = 0x00000000l,
relaxedPcCalculation = false
),
new IBusSimplePlugin(
interfaceKeepData = false,
catchAccessFault = false
resetVector = 0x00000000l,
relaxedPcCalculation = false,
prediction = DYNAMIC_TARGET,
catchAccessFault = false,
compressedGen = true
),
new DBusSimplePlugin(
catchAddressMisaligned = true,
@ -50,8 +49,7 @@ object FormalSimple extends App{
),
new BranchPlugin(
earlyBranch = false,
catchAddressMisaligned = true,
prediction = NONE
catchAddressMisaligned = true
),
new YamlPlugin("cpu0.yaml")
)

View file

@ -16,13 +16,12 @@ object GenCustomCsr extends App{
new CustomCsrDemoPlugin,
new CsrPlugin(CsrPluginConfig.small),
new CustomCsrDemoGpioPlugin,
new PcManagerSimplePlugin(
resetVector = 0x00000000l,
relaxedPcCalculation = false
),
new IBusSimplePlugin(
interfaceKeepData = false,
catchAccessFault = false
resetVector = 0x00000000l,
relaxedPcCalculation = false,
prediction = NONE,
catchAccessFault = false,
compressedGen = false
),
new DBusSimplePlugin(
catchAddressMisaligned = false,
@ -52,8 +51,7 @@ object GenCustomCsr extends App{
),
new BranchPlugin(
earlyBranch = false,
catchAddressMisaligned = false,
prediction = NONE
catchAddressMisaligned = false
),
new YamlPlugin("cpu0.yaml")
)

View file

@ -12,13 +12,12 @@ object GenCustomSimdAdd extends App{
config = VexRiscvConfig(
plugins = List(
new SimdAddPlugin,
new PcManagerSimplePlugin(
resetVector = 0x00000000l,
relaxedPcCalculation = false
),
new IBusSimplePlugin(
interfaceKeepData = false,
catchAccessFault = false
resetVector = 0x00000000l,
relaxedPcCalculation = false,
prediction = NONE,
catchAccessFault = false,
compressedGen = false
),
new DBusSimplePlugin(
catchAddressMisaligned = false,
@ -48,8 +47,7 @@ object GenCustomSimdAdd extends App{
),
new BranchPlugin(
earlyBranch = false,
catchAddressMisaligned = false,
prediction = NONE
catchAddressMisaligned = false
),
new YamlPlugin("cpu0.yaml")
)

View file

@ -11,13 +11,12 @@ object GenDeterministicVex extends App{
def cpu() = new VexRiscv(
config = VexRiscvConfig(
plugins = List(
new PcManagerSimplePlugin(
resetVector = 0x80000000l,
relaxedPcCalculation = false
),
new IBusSimplePlugin(
interfaceKeepData = false,
catchAccessFault = true
resetVector = 0x80000000l,
relaxedPcCalculation = false,
prediction = STATIC,
catchAccessFault = true,
compressedGen = false
),
new DBusSimplePlugin(
catchAddressMisaligned = true,
@ -55,8 +54,7 @@ object GenDeterministicVex extends App{
new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
new BranchPlugin(
earlyBranch = true,
catchAddressMisaligned = true,
prediction = STATIC
catchAddressMisaligned = true
),
new YamlPlugin("cpu0.yaml")
)

View file

@ -17,6 +17,7 @@ object GenFull extends App{
relaxedPcCalculation = false
),
new IBusCachedPlugin(
prediction = DYNAMIC,
config = InstructionCacheConfig(
cacheSize = 4096,
bytePerLine =32,
@ -28,7 +29,8 @@ object GenFull extends App{
catchAccessFault = true,
catchMemoryTranslationMiss = true,
asyncTagMemory = false,
twoCycleRam = true
twoCycleRam = true,
twoCycleCache = true
),
memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
portTlbSize = 4
@ -84,8 +86,7 @@ object GenFull extends App{
new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
new BranchPlugin(
earlyBranch = false,
catchAddressMisaligned = true,
prediction = DYNAMIC
catchAddressMisaligned = true
),
new YamlPlugin("cpu0.yaml")
)

View file

@ -17,6 +17,7 @@ object GenFullNoMmu extends App{
relaxedPcCalculation = false
),
new IBusCachedPlugin(
prediction = STATIC,
config = InstructionCacheConfig(
cacheSize = 4096,
bytePerLine =32,
@ -28,7 +29,8 @@ object GenFullNoMmu extends App{
catchAccessFault = true,
catchMemoryTranslationMiss = true,
asyncTagMemory = false,
twoCycleRam = true
twoCycleRam = true,
twoCycleCache = true
)
),
new DBusCachedPlugin(
@ -76,8 +78,7 @@ object GenFullNoMmu extends App{
new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
new BranchPlugin(
earlyBranch = false,
catchAddressMisaligned = true,
prediction = STATIC
catchAddressMisaligned = true
),
new YamlPlugin("cpu0.yaml")
)

View file

@ -17,6 +17,8 @@ object GenFullNoMmuMaxPerf extends App{
relaxedPcCalculation = false
),
new IBusCachedPlugin(
prediction = DYNAMIC_TARGET,
historyRamSizeLog2 = 8,
config = InstructionCacheConfig(
cacheSize = 4096*4,
bytePerLine =32,
@ -28,7 +30,8 @@ object GenFullNoMmuMaxPerf extends App{
catchAccessFault = true,
catchMemoryTranslationMiss = false,
asyncTagMemory = false,
twoCycleRam = true
twoCycleRam = true,
twoCycleCache = true
)
),
new DBusCachedPlugin(
@ -76,9 +79,7 @@ object GenFullNoMmuMaxPerf extends App{
new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
new BranchPlugin(
earlyBranch = true,
catchAddressMisaligned = true,
prediction = DYNAMIC_TARGET,
historyRamSizeLog2 = 8
catchAddressMisaligned = true
),
new YamlPlugin("cpu0.yaml")
)

View file

@ -12,13 +12,12 @@ object GenFullNoMmuNoCache extends App{
def cpu() = new VexRiscv(
config = VexRiscvConfig(
plugins = List(
new PcManagerSimplePlugin(
resetVector = 0x00000000l,
relaxedPcCalculation = false
),
new IBusSimplePlugin(
interfaceKeepData = false,
catchAccessFault = false
resetVector = 0x00000000l,
relaxedPcCalculation = false,
prediction = STATIC,
catchAccessFault = false,
compressedGen = false
),
new DBusSimplePlugin(
catchAddressMisaligned = false,
@ -52,8 +51,7 @@ object GenFullNoMmuNoCache extends App{
new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
new BranchPlugin(
earlyBranch = false,
catchAddressMisaligned = true,
prediction = STATIC
catchAddressMisaligned = true
),
new YamlPlugin("cpu0.yaml")
)

View file

@ -12,13 +12,13 @@ object GenNoCacheNoMmuMaxPerf extends App{
def cpu() = new VexRiscv(
config = VexRiscvConfig(
plugins = List(
new PcManagerSimplePlugin(
resetVector = 0x80000000l,
relaxedPcCalculation = false
),
new IBusSimplePlugin(
interfaceKeepData = false,
catchAccessFault = true
resetVector = 0x80000000l,
relaxedPcCalculation = false,
prediction = DYNAMIC_TARGET,
historyRamSizeLog2 = 8,
catchAccessFault = true,
compressedGen = false
),
new DBusSimplePlugin(
catchAddressMisaligned = true,
@ -56,9 +56,7 @@ object GenNoCacheNoMmuMaxPerf extends App{
new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
new BranchPlugin(
earlyBranch = true,
catchAddressMisaligned = true,
prediction = DYNAMIC_TARGET,
historyRamSizeLog2 = 8
catchAddressMisaligned = true
),
new YamlPlugin("cpu0.yaml")
)

View file

@ -11,13 +11,12 @@ object GenSmallAndProductive extends App{
def cpu() = new VexRiscv(
config = VexRiscvConfig(
plugins = List(
new PcManagerSimplePlugin(
resetVector = 0x00000000l,
relaxedPcCalculation = false
),
new IBusSimplePlugin(
interfaceKeepData = false,
catchAccessFault = false
resetVector = 0x00000000l,
relaxedPcCalculation = false,
prediction = NONE,
catchAccessFault = false,
compressedGen = false
),
new DBusSimplePlugin(
catchAddressMisaligned = false,
@ -48,8 +47,7 @@ object GenSmallAndProductive extends App{
),
new BranchPlugin(
earlyBranch = false,
catchAddressMisaligned = false,
prediction = NONE
catchAddressMisaligned = false
),
new YamlPlugin("cpu0.yaml")
)

View file

@ -28,7 +28,8 @@ object GenSmallAndProductiveICache extends App{
catchAccessFault = false,
catchMemoryTranslationMiss = false,
asyncTagMemory = false,
twoCycleRam = false
twoCycleRam = false,
twoCycleCache = true
)
),
new DBusSimplePlugin(
@ -60,8 +61,7 @@ object GenSmallAndProductiveICache extends App{
),
new BranchPlugin(
earlyBranch = false,
catchAddressMisaligned = false,
prediction = NONE
catchAddressMisaligned = false
),
new YamlPlugin("cpu0.yaml")
)

View file

@ -11,13 +11,12 @@ object GenSmallest extends App{
def cpu() = new VexRiscv(
config = VexRiscvConfig(
plugins = List(
new PcManagerSimplePlugin(
resetVector = 0x00000000l,
relaxedPcCalculation = false
),
new IBusSimplePlugin(
interfaceKeepData = false,
catchAccessFault = false
resetVector = 0x00000000l,
relaxedPcCalculation = false,
prediction = NONE,
catchAccessFault = false,
compressedGen = false
),
new DBusSimplePlugin(
catchAddressMisaligned = false,
@ -48,8 +47,7 @@ object GenSmallest extends App{
),
new BranchPlugin(
earlyBranch = false,
catchAddressMisaligned = false,
prediction = NONE
catchAddressMisaligned = false
),
new YamlPlugin("cpu0.yaml")
)

View file

@ -11,24 +11,30 @@ object GenSmallestNoCsr extends App{
def cpu() = new VexRiscv(
config = VexRiscvConfig(
plugins = List(
new PcManagerSimplePlugin(
resetVector = 0x00000000l,
relaxedPcCalculation = false
),
// new PcManagerSimplePlugin(
// resetVector = 0x00000000l,
// relaxedPcCalculation = false
// ),
new IBusSimplePlugin(
interfaceKeepData = false,
catchAccessFault = false
resetVector = 0x00000000l,
relaxedPcCalculation = false,
prediction = NONE,
catchAccessFault = false,
compressedGen = false
),
new DBusSimplePlugin(
catchAddressMisaligned = false,
catchAccessFault = false
catchAccessFault = false,
earlyInjection = false
),
new DecoderSimplePlugin(
catchIllegalInstruction = false
),
new RegFilePlugin(
regFileReadyKind = plugin.SYNC,
zeroBoot = false
zeroBoot = false,
writeRfInMemoryStage = false
),
new IntAluPlugin,
new SrcPlugin(
@ -47,8 +53,7 @@ object GenSmallestNoCsr extends App{
),
new BranchPlugin(
earlyBranch = false,
catchAddressMisaligned = false,
prediction = NONE
catchAddressMisaligned = false
),
new YamlPlugin("cpu0.yaml")
)

View file

@ -52,13 +52,12 @@ object MuraxConfig{
pipelineApbBridge = true,
gpioWidth = 32,
cpuPlugins = ArrayBuffer( //DebugPlugin added by the toplevel
new PcManagerSimplePlugin(
resetVector = 0x80000000l,
relaxedPcCalculation = true
),
new IBusSimplePlugin(
interfaceKeepData = false,
catchAccessFault = false
resetVector = 0x80000000l,
relaxedPcCalculation = true,
prediction = NONE,
catchAccessFault = false,
compressedGen = true
),
new DBusSimplePlugin(
catchAddressMisaligned = false,
@ -90,8 +89,7 @@ object MuraxConfig{
),
new BranchPlugin(
earlyBranch = false,
catchAddressMisaligned = false,
prediction = NONE
catchAddressMisaligned = false
),
new YamlPlugin("cpu0.yaml")
),
@ -310,8 +308,14 @@ object MuraxDhrystoneReadyMulDivStatic{
config.cpuPlugins.remove(config.cpuPlugins.indexWhere(_.isInstanceOf[BranchPlugin]))
config.cpuPlugins +=new BranchPlugin(
earlyBranch = false,
catchAddressMisaligned = false,
prediction = STATIC
catchAddressMisaligned = false
)
config.cpuPlugins += new IBusSimplePlugin(
resetVector = 0x80000000l,
relaxedPcCalculation = true,
prediction = STATIC,
catchAccessFault = false,
compressedGen = false
)
config.cpuPlugins.remove(config.cpuPlugins.indexWhere(_.isInstanceOf[LightShifterPlugin]))
config.cpuPlugins += new FullBarrelShifterPlugin

View file

@ -3,7 +3,7 @@ package vexriscv.demo
import spinal.core._
import spinal.lib.bus.amba3.apb.{Apb3, Apb3Config, Apb3SlaveFactory}
import spinal.lib.bus.misc.SizeMapping
import spinal.lib.misc.{InterruptCtrl, Prescaler, Timer}
import spinal.lib.misc.{HexTools, InterruptCtrl, Prescaler, Timer}
import spinal.lib._
import vexriscv.plugin.{DBusSimpleBus, IBusSimpleBus}
@ -64,7 +64,7 @@ class MuraxMasterArbiter(simpleBusConfig : SimpleBusConfig) extends Component{
io.masterBus.cmd.valid := False
}
io.iBus.rsp.ready := io.masterBus.rsp.valid && !rspTarget
io.iBus.rsp.valid := io.masterBus.rsp.valid && !rspTarget
io.iBus.rsp.inst := io.masterBus.rsp.data
io.iBus.rsp.error := False
@ -73,45 +73,6 @@ class MuraxMasterArbiter(simpleBusConfig : SimpleBusConfig) extends Component{
io.dBus.rsp.error := False
}
object HexTools{
def readHexFile(path : String, callback : (Int, Int) => Unit): Unit ={
import scala.io.Source
def hToI(that : String, start : Int, size : Int) = Integer.parseInt(that.substring(start,start + size), 16)
var offset = 0
for (line <- Source.fromFile(path).getLines) {
if (line.charAt(0) == ':'){
val byteCount = hToI(line, 1, 2)
val nextAddr = hToI(line, 3, 4) + offset
val key = hToI(line, 7, 2)
key match {
case 0 =>
for(i <- 0 until byteCount){
callback(nextAddr + i, hToI(line, 9 + i * 2, 2))
}
case 2 =>
offset = hToI(line, 9, 4) << 4
case 4 =>
offset = hToI(line, 9, 4) << 16
case 3 =>
case 5 =>
case 1 =>
}
}
}
}
def initRam[T <: Data](ram : Mem[T], onChipRamHexFile : String, ramOffset : BigInt): Unit ={
val initContent = Array.fill[BigInt](ram.wordCount)(0)
HexTools.readHexFile(onChipRamHexFile,(address,data) => {
val addressWithoutOffset = (address - ramOffset).toInt
initContent(addressWithoutOffset >> 2) |= BigInt(data) << ((addressWithoutOffset & 3)*8)
})
ram.initBigInt(initContent)
}
}
class MuraxSimpleBusRam(onChipRamSize : BigInt, onChipRamHexFile : String, simpleBusConfig : SimpleBusConfig) extends Component{
val io = new Bundle{

View file

@ -101,17 +101,17 @@ object VexRiscvSynthesisBench {
}
val rtls = List(smallestNoCsr, smallest, smallAndProductive, smallAndProductiveWithICache, fullNoMmuNoCache, noCacheNoMmuMaxPerf, fullNoMmuMaxPerf, fullNoMmu, full)
// val rtls = List(noCacheNoMmuMaxPerf, fullNoMmuMaxPerf)
// val rtls = List(smallestNoCsr, smallest, smallAndProductive, smallAndProductiveWithICache, fullNoMmuNoCache, noCacheNoMmuMaxPerf, fullNoMmuMaxPerf, fullNoMmu, full)
val rtls = List(smallestNoCsr)
// val rtls = List(smallAndProductive, smallAndProductiveWithICache, fullNoMmuMaxPerf, fullNoMmu, full)
// val rtls = List(smallAndProductive, full)
val targets = XilinxStdTargets(
val targets = /*XilinxStdTargets(
vivadoArtix7Path = "/eda/Xilinx/Vivado/2017.2/bin"
) ++ AlteraStdTargets(
quartusCycloneIVPath = "/eda/intelFPGA_lite/17.0/quartus/bin",
quartusCycloneVPath = "/eda/intelFPGA_lite/17.0/quartus/bin"
) ++ IcestormStdTargets()
) ++ */IcestormStdTargets()
// val targets = IcestormStdTargets()
Bench(rtls, targets, "/eda/tmp/")

View file

@ -26,10 +26,12 @@ object VexRiscvAvalonForSim{
//CPU configuration
val cpuConfig = VexRiscvConfig(
plugins = List(
new PcManagerSimplePlugin(0x00000000l, false),
new IBusSimplePlugin(
interfaceKeepData = false,
catchAccessFault = false
resetVector = 0x00000000l,
relaxedPcCalculation = false,
prediction = STATIC,
catchAccessFault = false,
compressedGen = false
),
new DBusSimplePlugin(
catchAddressMisaligned = false,
@ -102,8 +104,7 @@ object VexRiscvAvalonForSim{
new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
new BranchPlugin(
earlyBranch = false,
catchAddressMisaligned = true,
prediction = STATIC
catchAddressMisaligned = true
),
new CsrPlugin(
config = CsrPluginConfig(

View file

@ -34,6 +34,7 @@ object VexRiscvAvalonWithIntegratedJtag{
// catchAccessFault = false
// ),
new IBusCachedPlugin(
prediction = STATIC,
config = InstructionCacheConfig(
cacheSize = 4096,
bytePerLine =32,
@ -45,7 +46,8 @@ object VexRiscvAvalonWithIntegratedJtag{
catchAccessFault = true,
catchMemoryTranslationMiss = true,
asyncTagMemory = false,
twoCycleRam = true
twoCycleRam = true,
twoCycleCache = true
)
// askMemoryTranslation = true,
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
@ -100,8 +102,7 @@ object VexRiscvAvalonWithIntegratedJtag{
new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
new BranchPlugin(
earlyBranch = false,
catchAddressMisaligned = true,
prediction = STATIC
catchAddressMisaligned = true
),
new CsrPlugin(
config = CsrPluginConfig(

View file

@ -35,6 +35,7 @@ object VexRiscvAxi4WithIntegratedJtag{
// catchAccessFault = false
// ),
new IBusCachedPlugin(
prediction = STATIC,
config = InstructionCacheConfig(
cacheSize = 4096,
bytePerLine =32,
@ -46,7 +47,8 @@ object VexRiscvAxi4WithIntegratedJtag{
catchAccessFault = true,
catchMemoryTranslationMiss = true,
asyncTagMemory = false,
twoCycleRam = true
twoCycleRam = true,
twoCycleCache = true
)
// askMemoryTranslation = true,
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
@ -101,8 +103,7 @@ object VexRiscvAxi4WithIntegratedJtag{
new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
new BranchPlugin(
earlyBranch = false,
catchAddressMisaligned = true,
prediction = STATIC
catchAddressMisaligned = true
),
new CsrPlugin(
config = CsrPluginConfig(

View file

@ -34,6 +34,7 @@ object VexRiscvCachedWishboneForSim{
// catchAccessFault = false
// ),
new IBusCachedPlugin(
prediction = STATIC,
config = InstructionCacheConfig(
cacheSize = 4096,
bytePerLine =32,
@ -100,8 +101,7 @@ object VexRiscvCachedWishboneForSim{
// new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
new BranchPlugin(
earlyBranch = false,
catchAddressMisaligned = true,
prediction = STATIC
catchAddressMisaligned = true
),
new CsrPlugin(
config = CsrPluginConfig.small(mtvecInit = 0x80000020l)

View file

@ -568,6 +568,7 @@ class DataCache(p : DataCacheConfig) extends Component{
io.cpu.memory.mmuBus.cmd.isValid := io.cpu.memory.isValid && request.kind === MEMORY //TODO filter request kind
io.cpu.memory.mmuBus.cmd.virtualAddress := request.address
io.cpu.memory.mmuBus.cmd.bypassTranslation := request.way
io.cpu.memory.mmuBus.end := !io.cpu.memory.isStuck || io.cpu.memory.isRemoved
cpuMemoryStageNeedReadData := io.cpu.memory.isValid && request.kind === MEMORY && !request.wr
}

View file

@ -18,10 +18,12 @@ case class InstructionCacheConfig( cacheSize : Int,
catchAccessFault : Boolean,
catchMemoryTranslationMiss : Boolean,
asyncTagMemory : Boolean,
twoCycleCache : Boolean = true,
twoCycleRam : Boolean = false,
preResetFlush : Boolean = false){
def dataOnDecode = twoCycleRam && wayCount > 1
assert(!(twoCycleRam && !twoCycleCache))
def burstSize = bytePerLine*8/memDataWidth
def catchSomething = catchAccessFault || catchMemoryTranslationMiss || catchIllegalAccess
@ -72,36 +74,46 @@ case class InstructionCacheCpuPrefetch(p : InstructionCacheConfig) extends Bundl
}
}
case class InstructionCacheCpuFetch(p : InstructionCacheConfig) extends Bundle with IMasterSlave {
trait InstructionCacheCommons{
val isValid : Bool
val isStuck : Bool
val pc : UInt
val physicalAddress : UInt
val data : Bits
val cacheMiss, error, mmuMiss, illegalAccess,isUser : Bool
}
case class InstructionCacheCpuFetch(p : InstructionCacheConfig) extends Bundle with IMasterSlave with InstructionCacheCommons {
val isValid = Bool
val isStuck = Bool
val isRemoved = Bool
val pc = UInt(p.addressWidth bits)
val data = Bits(p.cpuDataWidth bits)
val mmuBus = MemoryTranslatorBus()
val physicalAddress = UInt(p.addressWidth bits)
val cacheMiss, error, mmuMiss, illegalAccess,isUser = ifGen(!p.twoCycleCache)(Bool)
override def asMaster(): Unit = {
out(isValid, isStuck, pc)
inWithNull(data)
out(isValid, isStuck, isRemoved, pc)
inWithNull(error,mmuMiss,illegalAccess,data, cacheMiss,physicalAddress)
outWithNull(isUser)
slaveWithNull(mmuBus)
}
}
case class InstructionCacheCpuDecode(p : InstructionCacheConfig) extends Bundle with IMasterSlave {
case class InstructionCacheCpuDecode(p : InstructionCacheConfig) extends Bundle with IMasterSlave with InstructionCacheCommons {
val isValid = Bool
val isUser = Bool
val isStuck = Bool
val pc = UInt(p.addressWidth bits)
val cacheMiss = Bool
val data = ifGen(p.dataOnDecode) (Bits(p.cpuDataWidth bits))
val error = Bool
val mmuMiss = Bool
val illegalAccess =Bool
val physicalAddress = UInt(p.addressWidth bits)
val data = Bits(p.cpuDataWidth bits)
val cacheMiss, error, mmuMiss, illegalAccess, isUser = ifGen(p.twoCycleCache)(Bool)
override def asMaster(): Unit = {
out(isValid, isUser, isStuck, pc)
in(cacheMiss)
inWithNull(error,mmuMiss,illegalAccess,data)
out(isValid, isStuck, pc)
outWithNull(isUser)
inWithNull(error,mmuMiss,illegalAccess,data, cacheMiss, physicalAddress)
}
}
@ -109,9 +121,10 @@ case class InstructionCacheCpuBus(p : InstructionCacheConfig) extends Bundle wit
val prefetch = InstructionCacheCpuPrefetch(p)
val fetch = InstructionCacheCpuFetch(p)
val decode = InstructionCacheCpuDecode(p)
val fill = Flow(UInt(p.addressWidth bits))
override def asMaster(): Unit = {
master(prefetch, fetch, decode)
master(prefetch, fetch, decode, fill)
}
}
@ -263,6 +276,11 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{
val address = Reg(UInt(addressWidth bits))
val hadError = RegInit(False) clearWhen(fire)
when(io.cpu.fill.valid){
valid := True
address := io.cpu.fill.payload
}
io.cpu.prefetch.haltIt setWhen(valid)
val flushCounter = Reg(UInt(log2Up(wayLineCount) + 1 bit)) init(if(preResetFlush) wayLineCount else 0)
@ -347,6 +365,9 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{
val data = read.waysValues.map(_.data).read(id)
val word = data.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(memWordToCpuWordRange))
io.cpu.fetch.data := word
if(twoCycleCache){
io.cpu.decode.data := RegNextWhen(io.cpu.fetch.data,!io.cpu.decode.isStuck)
}
} else null
if(twoCycleRam && wayCount == 1){
@ -356,10 +377,23 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{
io.cpu.fetch.mmuBus.cmd.isValid := io.cpu.fetch.isValid
io.cpu.fetch.mmuBus.cmd.virtualAddress := io.cpu.fetch.pc
io.cpu.fetch.mmuBus.cmd.bypassTranslation := False
io.cpu.fetch.mmuBus.end := !io.cpu.fetch.isStuck || io.cpu.fetch.isRemoved
io.cpu.fetch.physicalAddress := io.cpu.fetch.mmuBus.rsp.physicalAddress
val resolution = ifGen(!twoCycleCache)( new Area{
// def stage[T <: Data](that : T) = RegNextWhen(that,!io.cpu.decode.isStuck)
val mmuRsp = io.cpu.fetch.mmuBus.rsp
io.cpu.fetch.cacheMiss := !hit.valid
io.cpu.fetch.error := hit.error
io.cpu.fetch.mmuMiss := mmuRsp.miss
io.cpu.fetch.illegalAccess := !mmuRsp.allowExecute || (io.cpu.fetch.isUser && !mmuRsp.allowUser)
})
}
val decodeStage = new Area{
val decodeStage = ifGen(twoCycleCache) (new Area{
def stage[T <: Data](that : T) = RegNextWhen(that,!io.cpu.decode.isStuck)
val mmuRsp = stage(io.cpu.fetch.mmuBus.rsp)
@ -372,23 +406,23 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{
val valid = Cat(hits).orR
val id = OHToUInt(hits)
val error = tags(id).error
if(dataOnDecode) {
val data = fetchStage.read.waysValues.map(way => stage(way.data)).read(id)
val word = data.subdivideIn(cpuDataWidth bits).read(io.cpu.decode.pc(memWordToCpuWordRange))
io.cpu.decode.data := word
}
val data = fetchStage.read.waysValues.map(way => stage(way.data)).read(id)
val word = data.subdivideIn(cpuDataWidth bits).read(io.cpu.decode.pc(memWordToCpuWordRange))
io.cpu.decode.data := word
}
io.cpu.decode.cacheMiss := !hit.valid
when( io.cpu.decode.isValid && io.cpu.decode.cacheMiss){
io.cpu.prefetch.haltIt := True
lineLoader.valid := True
lineLoader.address := mmuRsp.physicalAddress //Could be optimise if mmu not used
}
// when( io.cpu.decode.isValid && io.cpu.decode.cacheMiss){
// io.cpu.prefetch.haltIt := True
// lineLoader.valid := True
// lineLoader.address := mmuRsp.physicalAddress //Could be optimise if mmu not used
// }
// when(io.cpu)
io.cpu.decode.error := hit.error
io.cpu.decode.mmuMiss := mmuRsp.miss
io.cpu.decode.illegalAccess := !mmuRsp.allowExecute || (io.cpu.decode.isUser && !mmuRsp.allowUser)
}
io.cpu.decode.physicalAddress := mmuRsp.physicalAddress
})
}

View file

@ -11,25 +11,74 @@ object STATIC extends BranchPrediction
object DYNAMIC extends BranchPrediction
object DYNAMIC_TARGET extends BranchPrediction
class BranchPlugin(earlyBranch : Boolean,
catchAddressMisaligned : Boolean,
prediction : BranchPrediction,
historyRamSizeLog2 : Int = 10,
historyWidth : Int = 2) extends Plugin[VexRiscv]{
object BranchCtrlEnum extends SpinalEnum(binarySequential){
val INC,B,JAL,JALR = newElement()
}
object BranchCtrlEnum extends SpinalEnum(binarySequential){
val INC,B,JAL,JALR = newElement()
}
object BRANCH_CTRL extends Stageable(BranchCtrlEnum())
case class DecodePredictionCmd() extends Bundle {
val hadBranch = Bool
}
case class DecodePredictionRsp(stage : Stage) extends Bundle {
val wasWrong = Bool
}
case class DecodePredictionBus(stage : Stage) extends Bundle {
val cmd = DecodePredictionCmd()
val rsp = DecodePredictionRsp(stage)
}
case class FetchPredictionCmd() extends Bundle{
val hadBranch = Bool
val targetPc = UInt(32 bits)
}
case class FetchPredictionRsp() extends Bundle{
val wasRight = Bool
val finalPc = UInt(32 bits)
val sourceLastWord = UInt(32 bits)
}
case class FetchPredictionBus(stage : Stage) extends Bundle {
val cmd = FetchPredictionCmd()
val rsp = FetchPredictionRsp()
}
trait PredictionInterface{
def askFetchPrediction() : FetchPredictionBus
def askDecodePrediction() : DecodePredictionBus
}
class BranchPlugin(earlyBranch : Boolean,
catchAddressMisaligned : Boolean) extends Plugin[VexRiscv] with PredictionInterface{
lazy val branchStage = if(earlyBranch) pipeline.execute else pipeline.memory
object BRANCH_CTRL extends Stageable(BranchCtrlEnum())
object BRANCH_CALC extends Stageable(UInt(32 bits))
object BRANCH_DO extends Stageable(Bool)
object BRANCH_COND_RESULT extends Stageable(Bool)
// object PREDICTION_HAD_BRANCHED extends Stageable(Bool)
var jumpInterface : Flow[UInt] = null
var predictionJumpInterface : Flow[UInt] = null
var predictionExceptionPort : Flow[ExceptionCause] = null
var branchExceptionPort : Flow[ExceptionCause] = null
var decodePrediction : DecodePredictionBus = null
var fetchPrediction : FetchPredictionBus = null
override def askFetchPrediction() = {
fetchPrediction = FetchPredictionBus(branchStage)
fetchPrediction
}
override def askDecodePrediction() = {
decodePrediction = DecodePredictionBus(branchStage)
decodePrediction
}
override def setup(pipeline: VexRiscv): Unit = {
import Riscv._
import pipeline.config._
@ -45,7 +94,7 @@ class BranchPlugin(earlyBranch : Boolean,
)
val jActions = List[(Stageable[_ <: BaseType],Any)](
SRC1_CTRL -> Src1CtrlEnum.FOUR,
SRC1_CTRL -> Src1CtrlEnum.PC_INCREMENT,
SRC2_CTRL -> Src2CtrlEnum.PC,
SRC_USE_SUB_LESS -> False,
REGFILE_WRITE_VALID -> True
@ -54,42 +103,34 @@ class BranchPlugin(earlyBranch : Boolean,
import IntAluPlugin._
decoderService.addDefault(BRANCH_CTRL, BranchCtrlEnum.INC)
val rvc = pipeline(RVC_GEN)
decoderService.add(List(
JAL -> (jActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.JAL, ALU_CTRL -> AluCtrlEnum.ADD_SUB)),
JALR -> (jActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.JALR, ALU_CTRL -> AluCtrlEnum.ADD_SUB, RS1_USE -> True)),
BEQ -> (bActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.B)),
BNE -> (bActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.B)),
BLT -> (bActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.B, SRC_LESS_UNSIGNED -> False)),
BGE -> (bActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.B, SRC_LESS_UNSIGNED -> False)),
BLTU -> (bActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.B, SRC_LESS_UNSIGNED -> True)),
BGEU -> (bActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.B, SRC_LESS_UNSIGNED -> True))
JAL(rvc) -> (jActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.JAL, ALU_CTRL -> AluCtrlEnum.ADD_SUB)),
JALR -> (jActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.JALR, ALU_CTRL -> AluCtrlEnum.ADD_SUB, RS1_USE -> True)),
BEQ(rvc) -> (bActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.B)),
BNE(rvc) -> (bActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.B)),
BLT(rvc) -> (bActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.B, SRC_LESS_UNSIGNED -> False)),
BGE(rvc) -> (bActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.B, SRC_LESS_UNSIGNED -> False)),
BLTU(rvc) -> (bActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.B, SRC_LESS_UNSIGNED -> True)),
BGEU(rvc) -> (bActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.B, SRC_LESS_UNSIGNED -> True))
))
val pcManagerService = pipeline.service(classOf[JumpService])
jumpInterface = pcManagerService.createJumpInterface(if(earlyBranch) pipeline.execute else pipeline.memory)
jumpInterface = pcManagerService.createJumpInterface(branchStage)
prediction match {
case NONE =>
case STATIC | DYNAMIC => predictionJumpInterface = pcManagerService.createJumpInterface(pipeline.decode)
case DYNAMIC_TARGET => predictionJumpInterface = pcManagerService.createJumpInterface(pipeline.fetch)
}
if (catchAddressMisaligned) {
val exceptionService = pipeline.service(classOf[ExceptionService])
branchExceptionPort = exceptionService.newExceptionPort(if (earlyBranch) pipeline.execute else pipeline.memory)
prediction match {
case NONE =>
case STATIC | DYNAMIC => predictionExceptionPort = exceptionService.newExceptionPort(pipeline.decode)
case DYNAMIC_TARGET =>
}
branchExceptionPort = exceptionService.newExceptionPort(branchStage)
}
}
override def build(pipeline: VexRiscv): Unit = prediction match {
case `NONE` => buildWithoutPrediction(pipeline)
case `STATIC` => buildWithPrediction(pipeline)
case `DYNAMIC` => buildWithPrediction(pipeline)
case `DYNAMIC_TARGET` => buildDynamicTargetPrediction(pipeline)
override def build(pipeline: VexRiscv): Unit = (fetchPrediction,decodePrediction) match {
case (null, null) => buildWithoutPrediction(pipeline)
case (_ , null) => buildFetchPrediction(pipeline)
case (null, _) => buildDecodePrediction(pipeline)
// case `DYNAMIC` => buildWithPrediction(pipeline)
// case `DYNAMIC_TARGET` => buildDynamicTargetPrediction(pipeline)
}
def buildWithoutPrediction(pipeline: VexRiscv): Unit = {
@ -128,7 +169,6 @@ class BranchPlugin(earlyBranch : Boolean,
}
//Apply branchs (JAL,JALR, Bxx)
val branchStage = if(earlyBranch) execute else memory
branchStage plug new Area {
import branchStage._
jumpInterface.valid := arbitration.isFiring && input(BRANCH_DO)
@ -139,7 +179,7 @@ class BranchPlugin(earlyBranch : Boolean,
}
if(catchAddressMisaligned) { //TODO conflict with instruction cache two stage
branchExceptionPort.valid := arbitration.isValid && input(BRANCH_DO) && jumpInterface.payload(1 downto 0) =/= 0
branchExceptionPort.valid := arbitration.isValid && input(BRANCH_DO) && (if(pipeline(RVC_GEN)) jumpInterface.payload(0 downto 0) =/= 0 else jumpInterface.payload(1 downto 0) =/= 0)
branchExceptionPort.code := 0
branchExceptionPort.badAddr := jumpInterface.payload
}
@ -147,54 +187,16 @@ class BranchPlugin(earlyBranch : Boolean,
}
def buildWithPrediction(pipeline: VexRiscv): Unit = {
case class BranchPredictorLine() extends Bundle{
val history = SInt(historyWidth bits)
}
def buildDecodePrediction(pipeline: VexRiscv): Unit = {
object PREDICTION_HAD_BRANCHED extends Stageable(Bool)
object HISTORY_LINE extends Stageable(BranchPredictorLine())
import pipeline._
import pipeline.config._
val historyCache = if(prediction == DYNAMIC) Mem(BranchPredictorLine(), 1 << historyRamSizeLog2) setName("branchCache") else null
val historyCacheWrite = if(prediction == DYNAMIC) historyCache.writePort else null
//Read historyCache
if(prediction == DYNAMIC) fetch plug new Area{
val readAddress = prefetch.output(PC)(2, historyRamSizeLog2 bits)
fetch.insert(HISTORY_LINE) := historyCache.readSync(readAddress,!prefetch.arbitration.isStuckByOthers)
//WriteFirst bypass TODO long combinatorial path
// val writePortReg = RegNext(historyCacheWrite)
// when(writePortReg.valid && writePortReg.address === readAddress){
// fetch.insert(HISTORY_LINE) := writePortReg.data
// }
}
//Branch JAL, predict Bxx and branch it
decode plug new Area{
decode plug new Area {
import decode._
val imm = IMM(input(INSTRUCTION))
val conditionalBranchPrediction = (prediction match {
case `STATIC` => imm.b_sext.msb
case `DYNAMIC` => input(HISTORY_LINE).history.msb
})
insert(PREDICTION_HAD_BRANCHED) := input(BRANCH_CTRL) === BranchCtrlEnum.JAL || (input(BRANCH_CTRL) === BranchCtrlEnum.B && conditionalBranchPrediction)
predictionJumpInterface.valid := input(PREDICTION_HAD_BRANCHED) && arbitration.isFiring //TODO OH Doublon de priorité
predictionJumpInterface.payload := input(PC) + ((input(BRANCH_CTRL) === BranchCtrlEnum.JAL) ? imm.j_sext | imm.b_sext).asUInt
when(predictionJumpInterface.valid) {
fetch.arbitration.flushAll := True
}
if(catchAddressMisaligned) {
predictionExceptionPort.valid := input(INSTRUCTION_READY) && input(PREDICTION_HAD_BRANCHED) && arbitration.isValid && predictionJumpInterface.payload(1 downto 0) =/= 0
predictionExceptionPort.code := 0
predictionExceptionPort.badAddr := predictionJumpInterface.payload
}
insert(PREDICTION_HAD_BRANCHED) := decodePrediction.cmd.hadBranch
}
//Do real branch calculation
@ -228,7 +230,7 @@ class BranchPlugin(earlyBranch : Boolean,
}
default{
branch_src1 := input(PC)
branch_src2 := (input(PREDICTION_HAD_BRANCHED) ? B(4) | imm.b_sext).asUInt
branch_src2 := (input(PREDICTION_HAD_BRANCHED) ? (if(pipeline(RVC_GEN)) Mux(input(IS_RVC), B(2), B(4)) else B(4)).resized | imm.b_sext).asUInt
}
}
val branchAdder = branch_src1 + branch_src2
@ -248,67 +250,27 @@ class BranchPlugin(earlyBranch : Boolean,
}
if(catchAddressMisaligned) {
branchExceptionPort.valid := input(INSTRUCTION_READY) && arbitration.isValid && input(BRANCH_DO) && jumpInterface.payload(1 downto 0) =/= 0
val unalignedJump = input(BRANCH_DO) && (if(pipeline(RVC_GEN)) input(BRANCH_CALC)(0 downto 0) =/= 0 else input(BRANCH_CALC)(1 downto 0) =/= 0)
branchExceptionPort.valid := arbitration.isValid && unalignedJump
branchExceptionPort.code := 0
branchExceptionPort.badAddr := jumpInterface.payload
branchExceptionPort.badAddr := input(BRANCH_CALC) //pipeline.stages(pipeline.indexOf(branchStage)-1).input
}
}
//Update historyCache
if(prediction == DYNAMIC) branchStage plug new Area {
import branchStage._
val newHistory = input(HISTORY_LINE).history.resize(historyWidth + 1) + Mux(input(BRANCH_COND_RESULT),S(-1),S(1))
val noOverflow = newHistory(newHistory.high downto newHistory.high - 1) =/= S"10" && newHistory(newHistory.high downto newHistory.high - 1) =/= S"01"
historyCacheWrite.valid := arbitration.isFiring && input(BRANCH_CTRL) === BranchCtrlEnum.B && noOverflow
historyCacheWrite.address := input(PC)(2, historyRamSizeLog2 bits)
historyCacheWrite.data.history := newHistory.resized
}
decodePrediction.rsp.wasWrong := jumpInterface.valid
}
def buildDynamicTargetPrediction(pipeline: VexRiscv): Unit = {
def buildFetchPrediction(pipeline: VexRiscv): Unit = {
import pipeline._
import pipeline.config._
case class BranchPredictorLine() extends Bundle{
val source = Bits(31 - historyRamSizeLog2 bits)
val confidence = UInt(2 bits)
val target = UInt(32 bits)
}
object PREDICTION_WRITE_HAZARD extends Stageable(Bool)
object PREDICTION extends Stageable(BranchPredictorLine())
object PREDICTION_HIT extends Stageable(Bool)
val history = Mem(BranchPredictorLine(), 1 << historyRamSizeLog2)
val historyWrite = history.writePort
fetch plug new Area{
import fetch._
val line = history.readSync((prefetch.output(PC) >> 2).resized, prefetch.arbitration.isFiring)
// val line = history.readAsync((fetch.output(PC) >> 2).resized)
val hit = line.source === (input(PC).asBits >> 1 + historyRamSizeLog2)
//Avoid write to read hazard
val historyWriteLast = RegNext(historyWrite)
val hazard = historyWriteLast.valid && historyWriteLast.address === (output(PC) >> 2).resized
insert(PREDICTION_WRITE_HAZARD) := hazard
predictionJumpInterface.valid := line.confidence.msb && hit && arbitration.isFiring && !hazard
predictionJumpInterface.payload := line.target
insert(PREDICTION) := line
insert(PREDICTION_HIT) := hit
}
//Do branch calculations (conditions + target PC)
object NEXT_PC extends Stageable(UInt(32 bits))
execute plug new Area {
import execute._
@ -337,6 +299,7 @@ class BranchPlugin(earlyBranch : Boolean,
val branchAdder = branch_src1 + branch_src2
insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ ((input(BRANCH_CTRL) === BranchCtrlEnum.JALR) ? False | branchAdder(0))
insert(NEXT_PC) := input(PC) + (if(pipeline(RVC_GEN)) ((input(IS_RVC)) ? U(2) | U(4)) else 4)
}
//Apply branchs (JAL,JALR, Bxx)
@ -344,42 +307,18 @@ class BranchPlugin(earlyBranch : Boolean,
branchStage plug new Area {
import branchStage._
val predictionMissmatch = input(PREDICTION).confidence.msb =/= input(BRANCH_DO) || (input(BRANCH_DO) && input(PREDICTION).target =/= input(BRANCH_CALC))
historyWrite.valid := False
historyWrite.address := (branchStage.output(PC) >> 2).resized
historyWrite.data.source := input(PC).asBits >> 1 + historyRamSizeLog2
historyWrite.data.target := input(BRANCH_CALC)
jumpInterface.valid := False
jumpInterface.payload := input(BRANCH_CALC)
when(!input(BRANCH_DO)){
historyWrite.valid := arbitration.isFiring && input(PREDICTION_HIT)
historyWrite.data.confidence := input(PREDICTION).confidence - (input(PREDICTION).confidence =/= 0).asUInt
historyWrite.data.target := input(BRANCH_CALC)
jumpInterface.valid := input(PREDICTION_HIT) && input(PREDICTION).confidence.msb && !input(PREDICTION_WRITE_HAZARD) && arbitration.isFiring
jumpInterface.payload := input(PC) + 4
} otherwise{
when(!input(PREDICTION_HIT) || input(PREDICTION_WRITE_HAZARD)){
jumpInterface.valid := arbitration.isFiring
historyWrite.valid := arbitration.isFiring
historyWrite.data.confidence := "10"
} otherwise {
historyWrite.valid := arbitration.isFiring
historyWrite.data.confidence := input(PREDICTION).confidence + (input(PREDICTION).confidence =/= 3).asUInt
when(!input(PREDICTION).confidence.msb || input(PREDICTION).target =/= input(BRANCH_CALC)){
jumpInterface.valid := arbitration.isFiring
}
}
val predictionMissmatch = fetchPrediction.cmd.hadBranch =/= input(BRANCH_DO) || (input(BRANCH_DO) && fetchPrediction.cmd.targetPc =/= input(BRANCH_CALC))
fetchPrediction.rsp.wasRight := ! predictionMissmatch
fetchPrediction.rsp.finalPc := input(BRANCH_CALC)
fetchPrediction.rsp.sourceLastWord := {
if(pipeline(RVC_GEN))
((!input(IS_RVC) && input(PC)(1)) ? input(NEXT_PC) | input(PC))
else
input(PC)
}
//Prevent rewriting an history which already had hazard
historyWrite.valid clearWhen(input(PREDICTION_WRITE_HAZARD))
jumpInterface.valid := arbitration.isFiring && predictionMissmatch //Probably just isValid instead of isFiring is better
jumpInterface.payload := (input(BRANCH_DO) ? input(BRANCH_CALC) | input(NEXT_PC))
when(jumpInterface.valid) {
@ -387,21 +326,9 @@ class BranchPlugin(earlyBranch : Boolean,
}
if(catchAddressMisaligned) {
branchExceptionPort.valid := arbitration.isValid && input(BRANCH_DO) && jumpInterface.payload(1 downto 0) =/= 0
branchExceptionPort.valid := arbitration.isValid && input(BRANCH_DO) && (if(pipeline(RVC_GEN)) input(BRANCH_CALC)(0 downto 0) =/= 0 else input(BRANCH_CALC)(1 downto 0) =/= 0)
branchExceptionPort.code := 0
branchExceptionPort.badAddr := jumpInterface.payload
}
}
//Init History
val historyInit = pipeline plug new Area{
val counter = Reg(UInt(historyRamSizeLog2 + 1 bits)) init(0)
when(!counter.msb){
prefetch.arbitration.haltByOther := True
historyWrite.valid := True
historyWrite.address := counter.resized
historyWrite.data.confidence := 0
counter := counter + 1
branchExceptionPort.badAddr := input(BRANCH_CALC)
}
}
}

View file

@ -54,6 +54,8 @@ case class CsrPluginConfig(
){
assert(!ucycleAccess.canWrite)
def noException = this.copy(ecallGen = false, catchIllegalAccess = false)
}
object CsrPluginConfig{
@ -260,7 +262,7 @@ class CsrPlugin(config : CsrPluginConfig) extends Plugin[VexRiscv] with Exceptio
if(ecallGen) decoderService.add(ECALL, defaultEnv ++ List(ENV_CTRL -> EnvCtrlEnum.ECALL))
val pcManagerService = pipeline.service(classOf[JumpService])
jumpInterface = pcManagerService.createJumpInterface(pipeline.execute)
jumpInterface = pcManagerService.createJumpInterface(pipeline.writeBack)
jumpInterface.valid := False
jumpInterface.payload.assignDontCare()
@ -291,7 +293,7 @@ class CsrPlugin(config : CsrPluginConfig) extends Plugin[VexRiscv] with Exceptio
override def build(pipeline: VexRiscv): Unit = {
import pipeline._
import pipeline.config._
val fetcher = service(classOf[IBusFetcher])
pipeline plug new Area{
//Define CSR mapping utilities
@ -372,13 +374,15 @@ class CsrPlugin(config : CsrPluginConfig) extends Plugin[VexRiscv] with Exceptio
minstret := minstret + 1
}
val mepcCaptureStage = if(exceptionPortsInfos.nonEmpty) writeBack else decode
//Used to make the pipeline empty softly (for interrupts)
val pipelineLiberator = new Area{
val enable = False.noBackendCombMerge //Verilator Perf
prefetch.arbitration.haltByOther setWhen(enable)
val done = ! List(fetch, decode, execute, memory, writeBack).map(_.arbitration.isValid).orR
when(enable && decode.arbitration.isValid){
decode.arbitration.haltByOther := True
}
val done = !List(execute, memory, writeBack).map(_.arbitration.isValid).orR && fetcher.pcValid(mepcCaptureStage)
}
@ -386,12 +390,9 @@ class CsrPlugin(config : CsrPluginConfig) extends Plugin[VexRiscv] with Exceptio
//Aggregate all exception port and remove required instructions
val exceptionPortCtrl = if(exceptionPortsInfos.nonEmpty) new Area{
val firstStageIndexWithExceptionPort = exceptionPortsInfos.map(i => indexOf(i.stage)).min
val exceptionValids = Vec(Bool,stages.length)
val exceptionValidsRegs = Vec(Reg(Bool) init(False), stages.length).allowUnsetRegToAvoidLatch
val exceptionValids = Vec(stages.map(s => Bool().setPartialName(s.getName())))
val exceptionValidsRegs = Vec(stages.map(s => Reg(Bool).init(False).setPartialName(s.getName()))).allowUnsetRegToAvoidLatch
val exceptionContext = Reg(ExceptionCause())
val pipelineHasException = exceptionValids.orR //TODO FMAX maybe could be partialy pipelined
pipelineLiberator.enable setWhen(pipelineHasException)
val groupedByStage = exceptionPortsInfos.map(_.stage).distinct.map(s => {
val stagePortsInfos = exceptionPortsInfos.filter(_.stage == s).sortWith(_.priority > _.priority)
@ -410,28 +411,36 @@ class CsrPlugin(config : CsrPluginConfig) extends Plugin[VexRiscv] with Exceptio
})
val sortedByStage = groupedByStage.sortWith((a, b) => pipeline.indexOf(a.stage) < pipeline.indexOf(b.stage))
sortedByStage.zipWithIndex.foreach(e => e._1.port.setName(e._1.stage.getName() + "_exception_agregat"))
exceptionValids := exceptionValidsRegs
for(portInfo <- sortedByStage; port = portInfo.port ; stage = portInfo.stage; stageId = indexOf(portInfo.stage)) {
when(port.valid) {
stages(indexOf(stage) - 1).arbitration.flushAll := True
// if(indexOf(stage) != 0) stages(indexOf(stage) - 1).arbitration.flushAll := True
stage.arbitration.removeIt := True
exceptionValids(stageId) := True
exceptionContext := port.payload
when(!exceptionValidsRegs.takeRight(stages.length-stageId-1).fold(False)(_ || _)) {
exceptionContext := port.payload
}
}
}
for(stageId <- firstStageIndexWithExceptionPort until stages.length; stage = stages(stageId) ){
when(stage.arbitration.isFlushed){
exceptionValids(stageId) := False
}
val previousStage = if(stageId == firstStageIndexWithExceptionPort) stage else stages(stageId-1)
when(!stage.arbitration.isStuck){
exceptionValidsRegs(stageId) := (if(stageId != firstStageIndexWithExceptionPort) exceptionValids(stageId-1) else False)
exceptionValidsRegs(stageId) := (if(stageId != firstStageIndexWithExceptionPort) exceptionValids(stageId-1) && !previousStage.arbitration.isStuck else False)
}otherwise{
exceptionValidsRegs(stageId) := exceptionValids(stageId)
}
if(stageId != 0){
when(exceptionValidsRegs(stageId)){
stages(stageId-1).arbitration.haltByOther := True
}
}
}
} else null
@ -483,17 +492,16 @@ class CsrPlugin(config : CsrPluginConfig) extends Plugin[VexRiscv] with Exceptio
//Interrupt/Exception entry logic
pipelineLiberator.enable setWhen(interrupt)
when(exception || (interrupt && pipelineLiberator.done)){
jumpInterface.valid := True
jumpInterface.payload := mtvec
memory.arbitration.flushAll := True
if(exceptionPortCtrl != null) exceptionPortCtrl.exceptionValidsRegs.last := False
mstatus.MIE := False
mstatus.MPIE := mstatus.MIE
mstatus.MPP := privilege
mepc := exception mux(
True -> writeBack.input(PC),
False -> (writeBackWasWfi ? writeBack.input(PC) | prefetch.input(PC_CALC_WITHOUT_JUMP))
)
mepc := mepcCaptureStage.input(PC)
mcause.interrupt := interrupt
mcause.exceptionCode := ((mip.MEIP && mie.MEIE) ? U(11) | ((mip.MSIP && mie.MSIE) ? U(3) | U(7)))
}
@ -505,12 +513,13 @@ class CsrPlugin(config : CsrPluginConfig) extends Plugin[VexRiscv] with Exceptio
//Manage MRET instructions
when(memory.input(ENV_CTRL) === EnvCtrlEnum.MRET) {
memory.arbitration.haltItself := writeBack.arbitration.isValid
when(memory.arbitration.isFiring) {
when(execute.arbitration.isValid && execute.input(ENV_CTRL) === EnvCtrlEnum.MRET) {
when(memory.arbitration.isValid || writeBack.arbitration.isValid){
execute.arbitration.haltItself := True
} otherwise {
jumpInterface.valid := True
jumpInterface.payload := mepc
execute.arbitration.flushAll := True
decode.arbitration.flushAll := True
mstatus.MIE := mstatus.MPIE
privilege := mstatus.MPP
}
@ -526,7 +535,6 @@ class CsrPlugin(config : CsrPluginConfig) extends Plugin[VexRiscv] with Exceptio
if(wfiGen) when(execute.arbitration.isValid && execute.input(ENV_CTRL) === EnvCtrlEnum.WFI){
when(!interrupt){
execute.arbitration.haltItself := True
decode.arbitration.flushAll := True
}
}

View file

@ -97,7 +97,7 @@ class DBusCachedPlugin(config : DataCacheConfig,
MEMORY_MANAGMENT -> True
))
mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(pipeline.memory,memoryTranslatorPortConfig)
mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(MemoryTranslatorPort.PRIORITY_DATA ,memoryTranslatorPortConfig)
if(catchSomething)
exceptionBus = pipeline.service(classOf[ExceptionService]).newExceptionPort(pipeline.writeBack)
@ -173,6 +173,7 @@ class DBusCachedPlugin(config : DataCacheConfig,
arbitration.haltItself setWhen(cache.io.cpu.memory.haltIt)
cache.io.cpu.memory.mmuBus <> mmuBus
arbitration.haltItself setWhen (mmuBus.cmd.isValid && !mmuBus.rsp.hit && !mmuBus.rsp.miss)
}
writeBack plug new Area{

View file

@ -242,10 +242,10 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean, catchAccessFault : Bool
memoryExceptionPort.code := (input(INSTRUCTION)(5) ? U(6) | U(4)).resized
memoryExceptionPort.valid := input(ALIGNEMENT_FAULT)
} else if(!catchAddressMisaligned){
memoryExceptionPort.valid := dBus.rsp.ready && dBus.rsp.error
memoryExceptionPort.valid := dBus.rsp.ready && dBus.rsp.error && !input(INSTRUCTION)(5)
memoryExceptionPort.code := 5
} else {
memoryExceptionPort.valid := dBus.rsp.ready && dBus.rsp.error
memoryExceptionPort.valid := dBus.rsp.ready && dBus.rsp.error && !input(INSTRUCTION)(5)
memoryExceptionPort.code := 5
when(input(ALIGNEMENT_FAULT)){
memoryExceptionPort.code := (input(INSTRUCTION)(5) ? U(6) | U(4)).resized
@ -287,7 +287,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean, catchAccessFault : Bool
}
if(!earlyInjection)
assert(!(arbitration.isValid && input(MEMORY_ENABLE) && !input(INSTRUCTION)(5) && arbitration.isStuck),"DBusSimplePlugin doesn't allow memory stage stall when read happend")
assert(!(arbitration.isValid && input(MEMORY_ENABLE) && !input(INSTRUCTION)(5) && arbitration.isStuck),"DBusSimplePlugin doesn't allow writeback stage stall when read happend")
//formal
insert(FORMAL_MEM_RDATA) := input(MEMORY_READ_DATA)

View file

@ -95,17 +95,13 @@ case class DebugExtensionIo() extends Bundle with IMasterSlave{
}
//Allow to avoid instruction cache plugin to be confused by new instruction poping in the pipeline
trait InstructionInjector{
def isInjecting(stage : Stage) : Bool
}
class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] with InstructionInjector {
class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] {
var io : DebugExtensionIo = null
val injectionAsks = ArrayBuffer[(Stage, Bool)]()
var isInjectingOnDecode : Bool = null
override def isInjecting(stage: Stage) : Bool = if(stage == pipeline.decode) isInjectingOnDecode else False
var injectionPort : Stream[Bits] = null
object IS_EBREAK extends Stageable(Bool)
override def setup(pipeline: VexRiscv): Unit = {
@ -125,22 +121,23 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] w
ALU_CTRL -> AluCtrlEnum.ADD_SUB //Used to get the PC value in busReadDataReg
))
isInjectingOnDecode = Bool()
injectionPort = pipeline.service(classOf[IBusFetcher]).getInjectionPort()
}
override def build(pipeline: VexRiscv): Unit = {
import pipeline._
import pipeline.config._
val logic = debugClockDomain {pipeline plug new Area{
val insertDecodeInstruction = False
val iBusFetcher = service(classOf[IBusFetcher])
val firstCycle = RegNext(False) setWhen (io.bus.cmd.ready)
val secondCycle = RegNext(firstCycle)
val resetIt = RegInit(False)
val haltIt = RegInit(False)
val stepIt = RegInit(False)
val isPipActive = RegNext(List(fetch, decode, execute, memory, writeBack).map(_.arbitration.isValid).orR)
val isPipActive = RegNext(List(decode,execute, memory, writeBack).map(_.arbitration.isValid).orR)
val isPipBusy = isPipActive || RegNext(isPipActive)
val haltedByBreak = RegInit(False)
@ -159,6 +156,9 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] w
io.bus.rsp.data(4) := stepIt
}
injectionPort.valid := False
injectionPort.payload := io.bus.cmd.data
when(io.bus.cmd.valid) {
switch(io.bus.cmd.address(2 downto 2)) {
is(0) {
@ -171,52 +171,70 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] w
}
is(1) {
when(io.bus.cmd.wr) {
insertDecodeInstruction := True
decode.arbitration.isValid setWhen (firstCycle)
decode.arbitration.haltItself setWhen (secondCycle)
io.bus.cmd.ready := !(firstCycle || secondCycle || decode.arbitration.isValid)
injectionPort.valid := True
io.bus.cmd.ready := injectionPort.ready
}
}
}
}
Component.current.addPrePopTask(() => {
//Check if the decode instruction is driven by a register
val instructionDriver = try {decode.input(INSTRUCTION).getDrivingReg} catch { case _ : Throwable => null}
if(instructionDriver != null){ //If yes =>
//Insert the instruction by writing the "fetch to decode instruction register",
// Work even if it need to cross some hierarchy (caches)
instructionDriver.component.rework {
when(insertDecodeInstruction.pull()) {
instructionDriver := io.bus.cmd.data.pull()
}
}
} else{
//Insert the instruction via a mux in the decode stage
when(RegNext(insertDecodeInstruction)){
decode.input(INSTRUCTION) := RegNext(io.bus.cmd.data)
}
// Component.current.addPrePopTask(() => {
// //Check if the decode instruction is driven by a register
// val instructionDriver = try {decode.input(INSTRUCTION).getDrivingReg} catch { case _ : Throwable => null}
// if(instructionDriver != null){ //If yes =>
// //Insert the instruction by writing the "fetch to decode instruction register",
// // Work even if it need to cross some hierarchy (caches)
// instructionDriver.component.rework {
// when(insertDecodeInstruction.pull()) {
// instructionDriver := io.bus.cmd.data.pull()
// }
// }
// } else{
// //Insert the instruction via a mux in the decode stage
// when(RegNext(insertDecodeInstruction)){
// decode.input(INSTRUCTION) := RegNext(io.bus.cmd.data)
// }
// }
// })
//
when(execute.input(IS_EBREAK)){
when(execute.arbitration.isValid ) {
iBusFetcher.flushIt()
iBusFetcher.haltIt()
decode.arbitration.flushAll := True
}
when(execute.arbitration.isFiring) {
haltIt := True
haltedByBreak := True
}
})
when(execute.arbitration.isFiring && execute.input(IS_EBREAK)) {
prefetch.arbitration.haltByOther := True
decode.arbitration.flushAll := True
haltIt := True
haltedByBreak := True
}
when(haltIt) {
prefetch.arbitration.haltByOther := True
iBusFetcher.haltIt()
// decode.arbitration.haltByOther := True
}
when(stepIt && prefetch.arbitration.isFiring) {
haltIt := True
when(stepIt && iBusFetcher.incoming()) {
iBusFetcher.haltIt()
when(decode.arbitration.isValid) {
haltIt := True
}
}
when(stepIt && Cat(pipeline.stages.map(_.arbitration.redoIt)).asBits.orR) {
haltIt := False
}
//Avoid having two C instruction executed in a single step
if(pipeline(RVC_GEN)){
val cleanStep = RegNext(stepIt && decode.arbitration.isFiring) init(False)
decode.arbitration.removeIt setWhen(cleanStep)
}
io.resetOut := RegNext(resetIt)
if(serviceExist(classOf[InterruptionInhibitor])) {
@ -230,8 +248,5 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] w
}
}
}}
isInjectingOnDecode := RegNext(logic.insertDecodeInstruction) init(False)
}
}

View file

@ -278,6 +278,8 @@ object SymplifyBit{
}
def getPrimeImplicantsByTrue(trueTerms: Seq[Masked], inputWidth : Int) : Seq[Masked] = getPrimeImplicantsByTrueAndDontCare(trueTerms, Nil, inputWidth)
// Return primes implicants for the trueTerms, default value is False.
// You can insert don't care values by adding non-prime implicants in the trueTerms
// Will simplify the trueTerms from the most constrained ones to the least constrained ones

View file

@ -3,7 +3,7 @@ package vexriscv.plugin
import spinal.core._
import vexriscv.VexRiscv
class ExternalInterruptArrayPlugin(arrayWidth : Int = 32) extends Plugin[VexRiscv]{
class ExternalInterruptArrayPlugin(arrayWidth : Int = 32, maskCsrId : Int = 0xBC0, pendingsCsrId : Int = 0xFC0) extends Plugin[VexRiscv]{
var externalInterruptArray : Bits = null
override def setup(pipeline: VexRiscv): Unit = {
@ -15,7 +15,7 @@ class ExternalInterruptArrayPlugin(arrayWidth : Int = 32) extends Plugin[VexRisc
val mask = Reg(Bits(arrayWidth bits)) init(0)
val pendings = mask & RegNext(externalInterruptArray)
csr.externalInterrupt.asDirectionLess() := pendings.orR
csr.rw(0x330, mask)
csr.r(0x360, pendings)
csr.rw(maskCsrId, mask)
csr.r(pendingsCsrId, pendings)
}
}

View file

@ -0,0 +1,609 @@
package vexriscv.plugin
import vexriscv._
import spinal.core._
import spinal.lib._
import vexriscv.Riscv.IMM
import StreamVexPimper._
import scala.collection.mutable.ArrayBuffer
//TODO val killLastStage = jump.pcLoad.valid || decode.arbitration.isRemoved
// DBUSSimple check memory halt execute optimization
abstract class IBusFetcherImpl(val catchAccessFault : Boolean,
val resetVector : BigInt,
val keepPcPlus4 : Boolean,
val decodePcGen : Boolean,
val compressedGen : Boolean,
val cmdToRspStageCount : Int,
val injectorReadyCutGen : Boolean,
val relaxedPcCalculation : Boolean,
val prediction : BranchPrediction,
val historyRamSizeLog2 : Int,
val injectorStage : Boolean) extends Plugin[VexRiscv] with JumpService with IBusFetcher{
var prefetchExceptionPort : Flow[ExceptionCause] = null
var decodePrediction : DecodePredictionBus = null
var fetchPrediction : FetchPredictionBus = null
var dynamicTargetFailureCorrection : Flow[UInt] = null
var externalResetVector : UInt = null
assert(cmdToRspStageCount >= 1)
assert(!(cmdToRspStageCount == 1 && !injectorStage))
assert(!(compressedGen && !decodePcGen))
var fetcherHalt : Bool = null
var fetcherflushIt : Bool = null
lazy val pcValids = Vec(Bool, 4)
def pcValid(stage : Stage) = pcValids(pipeline.indexOf(stage))
var incomingInstruction : Bool = null
override def incoming() = incomingInstruction
var injectionPort : Stream[Bits] = null
override def getInjectionPort() = {
injectionPort = Stream(Bits(32 bits))
injectionPort
}
var predictionJumpInterface : Flow[UInt] = null
override def haltIt(): Unit = fetcherHalt := True
override def flushIt(): Unit = fetcherflushIt := True
case class JumpInfo(interface : Flow[UInt], stage: Stage, priority : Int)
val jumpInfos = ArrayBuffer[JumpInfo]()
override def createJumpInterface(stage: Stage, priority : Int = 0): Flow[UInt] = {
val interface = Flow(UInt(32 bits))
jumpInfos += JumpInfo(interface,stage, priority)
interface
}
// var decodeExceptionPort : Flow[ExceptionCause] = null
override def setup(pipeline: VexRiscv): Unit = {
fetcherHalt = False
fetcherflushIt = False
incomingInstruction = False
if(catchAccessFault) {
val exceptionService = pipeline.service(classOf[ExceptionService])
}
if(resetVector == null) externalResetVector = in(UInt(32 bits).setName("externalResetVector"))
pipeline(RVC_GEN) = compressedGen
prediction match {
case NONE =>
case STATIC | DYNAMIC => {
predictionJumpInterface = createJumpInterface(pipeline.decode)
decodePrediction = pipeline.service(classOf[PredictionInterface]).askDecodePrediction()
}
case DYNAMIC_TARGET => {
fetchPrediction = pipeline.service(classOf[PredictionInterface]).askFetchPrediction()
if(compressedGen && cmdToRspStageCount > 1){
dynamicTargetFailureCorrection = createJumpInterface(pipeline.decode)
}
}
}
}
class FetchArea(pipeline : VexRiscv) extends Area {
import pipeline._
import pipeline.config._
//JumpService hardware implementation
val jump = new Area {
val sortedByStage = jumpInfos.sortWith((a, b) => {
(pipeline.indexOf(a.stage) > pipeline.indexOf(b.stage)) ||
(pipeline.indexOf(a.stage) == pipeline.indexOf(b.stage) && a.priority > b.priority)
})
val valids = sortedByStage.map(_.interface.valid)
val pcs = sortedByStage.map(_.interface.payload)
val pcLoad = Flow(UInt(32 bits))
pcLoad.valid := jumpInfos.map(_.interface.valid).orR
pcLoad.payload := MuxOH(OHMasking.first(valids.asBits), pcs)
}
def flush = jump.pcLoad.valid || fetcherflushIt
class PcFetch extends Area{
val preOutput = Stream(UInt(32 bits))
val output = preOutput.haltWhen(fetcherHalt)
val predictionPcLoad = ifGen(prediction == DYNAMIC_TARGET) (Flow(UInt(32 bits)))
}
val fetchPc = if(relaxedPcCalculation) new PcFetch {
//PC calculation without Jump
val pcReg = Reg(UInt(32 bits)) init(if(resetVector != null) resetVector else externalResetVector) addAttribute(Verilator.public)
val pcPlus4 = pcReg + 4
if (keepPcPlus4) KeepAttribute(pcPlus4)
when(preOutput.fire) {
pcReg := pcPlus4
}
//Realign
if(compressedGen){
when(preOutput.fire){
pcReg(1 downto 0) := 0
}
}
preOutput.valid := RegNext(True) init (False) // && !jump.pcLoad.valid
preOutput.payload := pcReg
//application of the selected jump request
if(predictionPcLoad != null) {
when(predictionPcLoad.valid) {
pcReg := predictionPcLoad.payload
preOutput.valid := False
}
}
when(jump.pcLoad.valid) {
pcReg := jump.pcLoad.payload
}
} else new PcFetch{
//PC calculation without Jump
val pcReg = Reg(UInt(32 bits)) init(if(resetVector != null) resetVector else externalResetVector) addAttribute(Verilator.public)
val inc = RegInit(False)
val pc = pcReg + (inc ## B"00").asUInt
val samplePcNext = False
if(predictionPcLoad != null) {
when(predictionPcLoad.valid) {
inc := False
samplePcNext := True
pc := predictionPcLoad.payload
}
}
when(jump.pcLoad.valid) {
inc := False
samplePcNext := True
pc := jump.pcLoad.payload
}
when(preOutput.fire){
inc := True
samplePcNext := True
}
when(samplePcNext) {
pcReg := pc
}
if(compressedGen) {
when(preOutput.fire) {
pcReg(1 downto 0) := 0
when(pc(1)){
inc := True
}
}
}
preOutput.valid := RegNext(True) init (False)
preOutput.payload := pc
}
val decodePc = ifGen(decodePcGen)(new Area {
//PC calculation without Jump
val pcReg = Reg(UInt(32 bits)) init(if(resetVector != null) resetVector else externalResetVector) addAttribute(Verilator.public)
val pcPlus = if(compressedGen)
pcReg + ((decode.input(IS_RVC)) ? U(2) | U(4))
else
pcReg + 4
if (keepPcPlus4) KeepAttribute(pcPlus)
val injectedDecode = False
when(decode.arbitration.isFiring && !injectedDecode) {
pcReg := pcPlus
}
val predictionPcLoad = ifGen(prediction == DYNAMIC_TARGET) (Flow(UInt(32 bits)))
if(prediction == DYNAMIC_TARGET) {
when(predictionPcLoad.valid) {
pcReg := predictionPcLoad.payload
}
}
//application of the selected jump request
when(jump.pcLoad.valid) {
pcReg := jump.pcLoad.payload
}
})
// val iBusCmd = new Area {
// def input = fetchPc.output
//
// // ...
//
// val output = Stream(UInt(32 bits))
// }
case class FetchRsp() extends Bundle {
val pc = UInt(32 bits)
val rsp = IBusSimpleRsp()
val isRvc = Bool
}
val iBusRsp = new Area {
val input = Stream(UInt(32 bits))
val inputPipeline = Vec(Stream(UInt(32 bits)), cmdToRspStageCount)
val inputPipelineHalt = Vec(False, cmdToRspStageCount-1)
for(i <- 0 until cmdToRspStageCount) {
// val doFlush = if(i == cmdToRspStageCount- 1 && ???) killLastStage else flush
inputPipeline(i) << {i match {
case 0 => input.m2sPipeWithFlush(flush, relaxedPcCalculation, collapsBubble = false)
case _ => inputPipeline(i-1).haltWhen(inputPipelineHalt(i-1)).m2sPipeWithFlush(flush,collapsBubble = false)
}}
}
// ...
val readyForError = True
val output = Stream(FetchRsp())
incomingInstruction setWhen(inputPipeline.map(_.valid).orR)
}
val decompressor = ifGen(decodePcGen)(new Area{
def input = iBusRsp.output
val output = Stream(FetchRsp())
val bufferValid = RegInit(False)
val bufferData = Reg(Bits(16 bits))
val raw = Mux(
sel = bufferValid,
whenTrue = input.rsp.inst(15 downto 0) ## bufferData,
whenFalse = input.rsp.inst(31 downto 16) ## (input.pc(1) ? input.rsp.inst(31 downto 16) | input.rsp.inst(15 downto 0))
)
val isRvc = raw(1 downto 0) =/= 3
val decompressed = RvcDecompressor(raw(15 downto 0))
output.valid := (isRvc ? (bufferValid || input.valid) | (input.valid && (bufferValid || !input.pc(1))))
output.pc := input.pc
output.isRvc := isRvc
output.rsp.inst := isRvc ? decompressed | raw
// input.ready := (bufferValid ? (!isRvc && output.ready) | (input.pc(1) || output.ready))
input.ready := !output.valid || !(!output.ready || (isRvc && !input.pc(1) && input.rsp.inst(16, 2 bits) =/= 3) || (!isRvc && bufferValid && input.rsp.inst(16, 2 bits) =/= 3))
addPrePopTask(() => {
when(!input.ready && output.fire && !flush /* && ((isRvc && !bufferValid && !input.pc(1)) || (!isRvc && bufferValid && input.rsp.inst(16, 2 bits) =/= 3))*/) {
input.pc.getDrivingReg(1) := True
}
})
bufferValid clearWhen(output.fire)
when(input.fire){
// bufferValid := !(!isRvc && !input.pc(1) && !bufferValid) && !(isRvc && input.pc(1) && output.ready)
bufferValid := !(!isRvc && !input.pc(1) && !bufferValid) && !(isRvc && input.pc(1) && output.ready)
bufferData := input.rsp.inst(31 downto 16)
}
bufferValid.clearWhen(flush)
iBusRsp.readyForError.clearWhen(bufferValid && isRvc)
incomingInstruction setWhen(bufferValid && bufferData(1 downto 0) =/= 3)
})
def condApply[T](that : T, cond : Boolean)(func : (T) => T) = if(cond)func(that) else that
val injector = new Area {
val inputBeforeStage = condApply(if (decodePcGen) decompressor.output else iBusRsp.output, injectorReadyCutGen)(_.s2mPipe(flush))
if (injectorReadyCutGen) {
iBusRsp.readyForError.clearWhen(inputBeforeStage.valid)
incomingInstruction setWhen (inputBeforeStage.valid)
}
val decodeInput = (if (injectorStage) {
val decodeInput = inputBeforeStage.m2sPipeWithFlush(flush, collapsBubble = false)
decode.insert(INSTRUCTION_ANTICIPATED) := Mux(decode.arbitration.isStuck, decode.input(INSTRUCTION), inputBeforeStage.rsp.inst)
iBusRsp.readyForError.clearWhen(decodeInput.valid)
incomingInstruction setWhen (decodeInput.valid)
decodeInput
} else {
inputBeforeStage
})
def pcUpdatedGen(input : Bool, stucks : Seq[Bool], relaxedInput : Boolean) : Seq[Bool] = {
stucks.scanLeft(input)((i, stuck) => {
val reg = RegInit(False)
if(!relaxedInput) when(flush) {
reg := False
}
when(!stuck) {
reg := i
}
if(relaxedInput || i != input) when(flush) {
reg := False
}
reg
}).tail
}
val nextPcCalc = if (decodePcGen) {
val valids = pcUpdatedGen(True, False :: List(execute, memory, writeBack).map(_.arbitration.isStuck), true)
pcValids := Vec(valids.takeRight(4))
} else new Area{
val valids = pcUpdatedGen(True, iBusRsp.inputPipeline.map(!_.ready) ++ (if (injectorStage) List(!decodeInput.ready) else Nil) ++ List(execute, memory, writeBack).map(_.arbitration.isStuck), relaxedPcCalculation)
if(relaxedPcCalculation && fetchPrediction != null) when(fetchPc.predictionPcLoad.valid){
valids(0).getDrivingReg := False
}
pcValids := Vec(valids.takeRight(4))
}
val decodeRemoved = RegInit(False) setWhen(decode.arbitration.isRemoved) clearWhen(flush) //!decode.arbitration.isStuck || decode.arbitration.isFlushed
decodeInput.ready := !decode.arbitration.isStuck
decode.arbitration.isValid := decodeInput.valid && !decodeRemoved
decode.insert(PC) := (if (decodePcGen) decodePc.pcReg else decodeInput.pc)
decode.insert(INSTRUCTION) := decodeInput.rsp.inst
decode.insert(INSTRUCTION_READY) := True
if (compressedGen) decode.insert(IS_RVC) := decodeInput.isRvc
if (injectionPort != null) {
Component.current.addPrePopTask(() => {
val state = RegInit(U"000")
injectionPort.ready := False
if(decodePcGen){
decodePc.injectedDecode setWhen(state =/= 0)
}
switch(state) {
is(0) { //request pipelining
when(injectionPort.valid) {
state := 1
}
}
is(1) { //Give time to propagate the payload
state := 2
}
is(2){ //read regfile delay
decode.arbitration.isValid := True
decode.arbitration.haltItself := True
state := 3
}
is(3){ //Do instruction
decode.arbitration.isValid := True
when(!decode.arbitration.isStuck) {
state := 4
}
}
is(4){ //request pipelining
injectionPort.ready := True
state := 0
}
}
//Check if the decode instruction is driven by a register
val instructionDriver = try {
decode.input(INSTRUCTION).getDrivingReg
} catch {
case _: Throwable => null
}
if (instructionDriver != null) { //If yes =>
//Insert the instruction by writing the "fetch to decode instruction register",
// Work even if it need to cross some hierarchy (caches)
instructionDriver.component.rework {
when(state.pull() =/= 0) {
instructionDriver := injectionPort.payload.pull()
}
}
} else {
//Insert the instruction via a mux in the decode stage
when(state =/= 0) {
decode.input(INSTRUCTION) := RegNext(injectionPort.payload)
}
}
})
}
//Formal verification signals generation, miss prediction stuff ?
val formal = new Area {
val raw = if(compressedGen) decompressor.raw else inputBeforeStage.rsp.inst
val rawInDecode = Delay(raw, if(injectorStage) 1 else 0, when = decodeInput.ready)
decode.insert(FORMAL_INSTRUCTION) := rawInDecode
decode.insert(FORMAL_PC_NEXT) := (if (compressedGen)
decode.input(PC) + ((decode.input(IS_RVC)) ? U(2) | U(4))
else
decode.input(PC) + 4)
if(decodePc != null && decodePc.predictionPcLoad != null){
when(decodePc.predictionPcLoad.valid){
decode.insert(FORMAL_PC_NEXT) := decodePc.predictionPcLoad.payload
}
}
jumpInfos.foreach(info => {
when(info.interface.valid) {
info.stage.output(FORMAL_PC_NEXT) := info.interface.payload
}
})
}
}
def stage1ToInjectorPipe[T <: Data](input : T): (T,T) ={
val iBusRspContext = iBusRsp.inputPipeline.tail.foldLeft(input)((data,stream) => RegNextWhen(data, stream.ready))
// val decompressorContext = ifGen(compressedGen)(new Area{
// val lastContext = RegNextWhen(iBusRspContext, decompressor.input.fire)
// val output = decompressor.bufferValid ? lastContext | iBusRspContext
// })
val decompressorContext = cloneOf(input)
decompressorContext := iBusRspContext
val injectorContext = Delay(if(compressedGen) decompressorContext else iBusRspContext, cycleCount=if(injectorStage) 1 else 0, when=injector.decodeInput.ready)
val injectorContextWire = cloneOf(input) //Allow combinatorial override
injectorContextWire := injectorContext
(ifGen(compressedGen)(decompressorContext), injectorContextWire)
}
val predictor = prediction match {
case NONE =>
case STATIC | DYNAMIC => {
def historyWidth = 2
val dynamic = ifGen(prediction == DYNAMIC) (new Area {
case class BranchPredictorLine() extends Bundle{
val history = SInt(historyWidth bits)
}
val historyCache = Mem(BranchPredictorLine(), 1 << historyRamSizeLog2)
val historyWrite = historyCache.writePort
val historyWriteLast = RegNextWhen(historyWrite, iBusRsp.inputPipeline(0).ready)
val hazard = historyWriteLast.valid && historyWriteLast.address === (iBusRsp.inputPipeline(0).payload >> 2).resized
case class DynamicContext() extends Bundle{
val hazard = Bool
val line = BranchPredictorLine()
}
val fetchContext = DynamicContext()
fetchContext.hazard := hazard
fetchContext.line := historyCache.readSync((fetchPc.output.payload >> 2).resized, iBusRsp.inputPipeline(0).ready || flush)
object PREDICTION_CONTEXT extends Stageable(DynamicContext())
decode.insert(PREDICTION_CONTEXT) := stage1ToInjectorPipe(fetchContext)._2
val decodeContextPrediction = decode.input(PREDICTION_CONTEXT).line.history.msb
val branchStage = decodePrediction.stage
val branchContext = branchStage.input(PREDICTION_CONTEXT)
val moreJump = decodePrediction.rsp.wasWrong ^ branchContext.line.history.msb
historyWrite.address := branchStage.input(PC)(2, historyRamSizeLog2 bits) + (if(pipeline(RVC_GEN))
((!branchStage.input(IS_RVC) && branchStage.input(PC)(1)) ? U(1) | U(0))
else
U(0))
historyWrite.data.history := branchContext.line.history + (moreJump ? S(-1) | S(1))
val sat = (branchContext.line.history === (moreJump ? S(branchContext.line.history.minValue) | S(branchContext.line.history.maxValue)))
historyWrite.valid := !branchContext.hazard && branchStage.arbitration.isFiring && branchStage.input(BRANCH_CTRL) === BranchCtrlEnum.B && !sat
})
val imm = IMM(decode.input(INSTRUCTION))
val conditionalBranchPrediction = prediction match {
case STATIC => imm.b_sext.msb
case DYNAMIC => dynamic.decodeContextPrediction
}
decodePrediction.cmd.hadBranch := decode.input(BRANCH_CTRL) === BranchCtrlEnum.JAL || (decode.input(BRANCH_CTRL) === BranchCtrlEnum.B && conditionalBranchPrediction)
predictionJumpInterface.valid := decodePrediction.cmd.hadBranch && decode.arbitration.isFiring //TODO OH Doublon de priorité
predictionJumpInterface.payload := decode.input(PC) + ((decode.input(BRANCH_CTRL) === BranchCtrlEnum.JAL) ? imm.j_sext | imm.b_sext).asUInt
// when(predictionJumpInterface.payload((if(pipeline(RVC_GEN)) 0 else 1) downto 0) =/= 0){
// decodePrediction.cmd.hadBranch := False
// }
}
case DYNAMIC_TARGET => new Area{
// assert(!compressedGen || cmdToRspStageCount == 1, "Can't combine DYNAMIC_TARGET and RVC as it could stop the instruction fetch mid-air")
case class BranchPredictorLine() extends Bundle{
val source = Bits(30 - historyRamSizeLog2 bits)
val branchWish = UInt(2 bits)
val target = UInt(32 bits)
val unaligned = ifGen(compressedGen)(Bool)
}
val history = Mem(BranchPredictorLine(), 1 << historyRamSizeLog2)
val historyWrite = history.writePort
val line = history.readSync((fetchPc.output.payload >> 2).resized, iBusRsp.inputPipeline(0).ready || flush)
val hit = line.source === (iBusRsp.inputPipeline(0).payload.asBits >> 2 + historyRamSizeLog2) && (if(compressedGen)(!(!line.unaligned && iBusRsp.inputPipeline(0).payload(1))) else True)
//Avoid stoping instruction fetch in the middle patch
if(compressedGen && cmdToRspStageCount == 1){
hit clearWhen(!decompressor.output.valid)
}
//Avoid write to read hazard
val historyWriteLast = RegNextWhen(historyWrite, iBusRsp.inputPipeline(0).ready)
val hazard = historyWriteLast.valid && historyWriteLast.address === (iBusRsp.inputPipeline(0).payload >> 2).resized
fetchPc.predictionPcLoad.valid := line.branchWish.msb && hit && !hazard && iBusRsp.inputPipeline(0).fire //XXX && !(!line.unaligned && iBusRsp.inputPipeline(0).payload(1))
fetchPc.predictionPcLoad.payload := line.target
case class PredictionResult() extends Bundle{
val hazard = Bool
val hit = Bool
val line = BranchPredictorLine()
}
val fetchContext = PredictionResult()
fetchContext.hazard := hazard
fetchContext.hit := hit
fetchContext.line := line
val (decompressorContext, injectorContext) = stage1ToInjectorPipe(fetchContext)
if(compressedGen) {
//prediction hit on the right instruction into words
decompressorContext.hit clearWhen(decompressorContext.line.unaligned && (decompressor.bufferValid || (decompressor.isRvc && !decompressor.input.pc(1))))
// if(compressedGen) injectorContext.hit clearWhen(decodePc.pcReg(1) =/= injectorContext.line.unaligned)
decodePc.predictionPcLoad.valid := injectorContext.line.branchWish.msb && injectorContext.hit && !injectorContext.hazard && injector.decodeInput.fire
decodePc.predictionPcLoad.payload := injectorContext.line.target
when(decompressorContext.line.branchWish.msb && decompressorContext.hit && !decompressorContext.hazard && decompressor.output.fire){
decompressor.bufferValid := False
decompressor.input.ready := True
}
}
object PREDICTION_CONTEXT extends Stageable(PredictionResult())
pipeline.decode.insert(PREDICTION_CONTEXT) := injectorContext
val branchStage = fetchPrediction.stage
val branchContext = branchStage.input(PREDICTION_CONTEXT)
fetchPrediction.cmd.hadBranch := branchContext.hit && !branchContext.hazard && branchContext.line.branchWish.msb
fetchPrediction.cmd.targetPc := branchContext.line.target
historyWrite.valid := False
historyWrite.address := fetchPrediction.rsp.sourceLastWord(2, historyRamSizeLog2 bits)
historyWrite.data.source := fetchPrediction.rsp.sourceLastWord.asBits >> 2 + historyRamSizeLog2
historyWrite.data.target := fetchPrediction.rsp.finalPc
if(compressedGen) historyWrite.data.unaligned := !fetchPrediction.stage.input(PC)(1) ^ fetchPrediction.stage.input(IS_RVC)
when(fetchPrediction.rsp.wasRight) {
historyWrite.valid := branchContext.hit
historyWrite.data.branchWish := branchContext.line.branchWish + (branchContext.line.branchWish === 2).asUInt - (branchContext.line.branchWish === 1).asUInt
} otherwise {
when(branchContext.hit) {
historyWrite.valid := True
historyWrite.data.branchWish := branchContext.line.branchWish - (branchContext.line.branchWish.msb).asUInt + (!branchContext.line.branchWish.msb).asUInt
} otherwise {
historyWrite.valid := True
historyWrite.data.branchWish := "10"
}
}
historyWrite.valid clearWhen(branchContext.hazard || !branchStage.arbitration.isFiring)
val predictionFailure = ifGen(compressedGen && cmdToRspStageCount > 1)(new Area{
val decompressorFailure = RegInit(False)
when(decompressor.input.fire){
decompressorFailure := decompressorContext.hit && !decompressorContext.hazard && !decompressor.output.valid && decompressorContext.line.branchWish(1)
}
decompressorFailure clearWhen(flush || decompressor.output.fire)
val injectorFailure = Delay(decompressorFailure, cycleCount=if(injectorStage) 1 else 0, when=injector.decodeInput.ready)
dynamicTargetFailureCorrection.valid := False
dynamicTargetFailureCorrection.payload := decode.input(PC)
when(injector.decodeInput.valid && injectorFailure){
historyWrite.valid := True
historyWrite.address := (decode.input(PC) >> 2).resized
historyWrite.data.branchWish := 0
decode.arbitration.isValid := False
dynamicTargetFailureCorrection.valid := True
}
})
}
}
}
}

View file

@ -87,7 +87,7 @@ class FormalPlugin extends Plugin[VexRiscv]{
rvfi.valid := arbitration.isFiring
rvfi.order := order
rvfi.insn := output(INSTRUCTION)
rvfi.insn := output(FORMAL_INSTRUCTION)
rvfi.trap := False
rvfi.halt := False
rvfi.intr := False

View file

@ -1,19 +1,41 @@
package vexriscv.plugin
import vexriscv._
import vexriscv.{plugin, _}
import vexriscv.ip._
import spinal.core._
import spinal.lib._
class IBusCachedPlugin(config : InstructionCacheConfig, memoryTranslatorPortConfig : Any = null) extends Plugin[VexRiscv] {
//class IBusCachedPlugin(config : InstructionCacheConfig, memoryTranslatorPortConfig : Any = null) extends Plugin[VexRiscv] {
// var iBus : InstructionCacheMemBus = null
// override def build(pipeline: VexRiscv): Unit = ???
//}
class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
relaxedPcCalculation : Boolean = false,
prediction : BranchPrediction = NONE,
historyRamSizeLog2 : Int = 10,
compressedGen : Boolean = false,
keepPcPlus4 : Boolean = false,
config : InstructionCacheConfig,
memoryTranslatorPortConfig : Any = null,
injectorStage : Boolean = false) extends IBusFetcherImpl(
catchAccessFault = config.catchAccessFault,
resetVector = resetVector,
keepPcPlus4 = keepPcPlus4,
decodePcGen = compressedGen,
compressedGen = compressedGen,
cmdToRspStageCount = (if(config.twoCycleCache) 2 else 1),
injectorReadyCutGen = false,
relaxedPcCalculation = relaxedPcCalculation,
prediction = prediction,
historyRamSizeLog2 = historyRamSizeLog2,
injectorStage = !config.twoCycleCache || injectorStage){
import config._
var iBus : InstructionCacheMemBus = null
var mmuBus : MemoryTranslatorBus = null
var decodeExceptionPort : Flow[ExceptionCause] = null
var privilegeService : PrivilegeService = null
var redoBranch : Flow[UInt] = null
var decodeExceptionPort : Flow[ExceptionCause] = null
object FLUSH_ALL extends Stageable(Bool)
object IBUS_ACCESS_ERROR extends Stageable(Bool)
@ -23,6 +45,8 @@ class IBusCachedPlugin(config : InstructionCacheConfig, memoryTranslatorPortConf
import Riscv._
import pipeline.config._
super.setup(pipeline)
def MANAGEMENT = M"-----------------100-----0001111"
val decoderService = pipeline.service(classOf[DecoderService])
@ -40,7 +64,7 @@ class IBusCachedPlugin(config : InstructionCacheConfig, memoryTranslatorPortConf
}
if(pipeline.serviceExist(classOf[MemoryTranslator]))
mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(pipeline.fetch, memoryTranslatorPortConfig)
mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(MemoryTranslatorPort.PRIORITY_INSTRUCTION, memoryTranslatorPortConfig)
if(pipeline.serviceExist(classOf[PrivilegeService]))
privilegeService = pipeline.service(classOf[PrivilegeService])
@ -65,84 +89,147 @@ class IBusCachedPlugin(config : InstructionCacheConfig, memoryTranslatorPortConf
}
}
override def build(pipeline: VexRiscv): Unit = {
import pipeline._
import pipeline.config._
// val debugAddressOffset = 28
val cache = new InstructionCache(this.config)
iBus = master(new InstructionCacheMemBus(this.config)).setName("iBus")
iBus <> cache.io.mem
iBus.cmd.address.allowOverride := cache.io.mem.cmd.address // - debugAddressOffset
//Connect prefetch cache side
cache.io.cpu.prefetch.isValid := prefetch.arbitration.isValid
cache.io.cpu.prefetch.pc := prefetch.output(PC)// + debugAddressOffset
prefetch.arbitration.haltItself setWhen(cache.io.cpu.prefetch.haltIt)
pipeline plug new FetchArea(pipeline) {
val cache = new InstructionCache(IBusCachedPlugin.this.config)
iBus = master(new InstructionCacheMemBus(IBusCachedPlugin.this.config)).setName("iBus")
iBus <> cache.io.mem
iBus.cmd.address.allowOverride := cache.io.mem.cmd.address // - debugAddressOffset
//Connect fetch cache side
cache.io.cpu.fetch.isValid := fetch.arbitration.isValid
cache.io.cpu.fetch.isStuck := fetch.arbitration.isStuck
cache.io.cpu.fetch.pc := fetch.output(PC) // + debugAddressOffset
//Connect prefetch cache side
cache.io.cpu.prefetch.isValid := fetchPc.output.valid
cache.io.cpu.prefetch.pc := fetchPc.output.payload
iBusRsp.input << fetchPc.output.haltWhen(cache.io.cpu.prefetch.haltIt)
if (mmuBus != null) {
cache.io.cpu.fetch.mmuBus <> mmuBus
} else {
cache.io.cpu.fetch.mmuBus.rsp.physicalAddress := cache.io.cpu.fetch.mmuBus.cmd.virtualAddress //- debugAddressOffset
cache.io.cpu.fetch.mmuBus.rsp.allowExecute := True
cache.io.cpu.fetch.mmuBus.rsp.allowRead := True
cache.io.cpu.fetch.mmuBus.rsp.allowWrite := True
cache.io.cpu.fetch.mmuBus.rsp.allowUser := True
cache.io.cpu.fetch.mmuBus.rsp.isIoAccess := False
cache.io.cpu.fetch.mmuBus.rsp.miss := False
}
if(dataOnDecode){
decode.insert(INSTRUCTION) := cache.io.cpu.decode.data
}else{
fetch.insert(INSTRUCTION) := cache.io.cpu.fetch.data
decode.insert(INSTRUCTION_ANTICIPATED) := Mux(decode.arbitration.isStuck,decode.input(INSTRUCTION),fetch.output(INSTRUCTION))
}
decode.insert(INSTRUCTION_READY) := True
cache.io.cpu.fetch.isRemoved := flush
val iBusRspOutputHalt = False
if (mmuBus != null) {
cache.io.cpu.fetch.mmuBus <> mmuBus
(if(twoCycleCache) iBusRsp.inputPipelineHalt(0) else iBusRspOutputHalt) setWhen(mmuBus.cmd.isValid && !mmuBus.rsp.hit && !mmuBus.rsp.miss)
} else {
cache.io.cpu.fetch.mmuBus.rsp.physicalAddress := cache.io.cpu.fetch.mmuBus.cmd.virtualAddress
cache.io.cpu.fetch.mmuBus.rsp.allowExecute := True
cache.io.cpu.fetch.mmuBus.rsp.allowRead := True
cache.io.cpu.fetch.mmuBus.rsp.allowWrite := True
cache.io.cpu.fetch.mmuBus.rsp.allowUser := True
cache.io.cpu.fetch.mmuBus.rsp.isIoAccess := False
cache.io.cpu.fetch.mmuBus.rsp.miss := False
cache.io.cpu.fetch.mmuBus.rsp.hit := False
}
cache.io.cpu.decode.pc := decode.output(PC)
//Connect fetch cache side
cache.io.cpu.fetch.isValid := iBusRsp.inputPipeline(0).valid
cache.io.cpu.fetch.isStuck := !iBusRsp.inputPipeline(0).ready
cache.io.cpu.fetch.pc := iBusRsp.inputPipeline(0).payload
val ownDecode = pipeline.plugins.filter(_.isInstanceOf[InstructionInjector]).foldLeft(True)(_ && !_.asInstanceOf[InstructionInjector].isInjecting(decode))
cache.io.cpu.decode.isValid := decode.arbitration.isValid && ownDecode
cache.io.cpu.decode.isStuck := decode.arbitration.isStuck
cache.io.cpu.decode.isUser := (if(privilegeService != null) privilegeService.isUser(decode) else False)
// cache.io.cpu.decode.pc := decode.input(PC)
redoBranch.valid := decode.arbitration.isValid && ownDecode && cache.io.cpu.decode.cacheMiss && !cache.io.cpu.decode.mmuMiss && !cache.io.cpu.decode.illegalAccess
redoBranch.payload := decode.input(PC)
when(redoBranch.valid){
decode.arbitration.redoIt := True
decode.arbitration.flushAll := True
}
if(twoCycleCache){
cache.io.cpu.decode.isValid := iBusRsp.inputPipeline(1).valid
cache.io.cpu.decode.isStuck := !iBusRsp.inputPipeline(1).ready
cache.io.cpu.decode.pc := iBusRsp.inputPipeline(1).payload
cache.io.cpu.decode.isUser := (if (privilegeService != null) privilegeService.isUser(decode) else False)
// val redo = RegInit(False) clearWhen(decode.arbitration.isValid) setWhen(redoBranch.valid)
// when(redoBranch.valid || redo){
// service(classOf[InterruptionInhibitor]).inhibateInterrupts()
// }
if((!twoCycleRam || wayCount == 1) && !compressedGen && !injectorStage){
decode.insert(INSTRUCTION_ANTICIPATED) := Mux(decode.arbitration.isStuck, decode.input(INSTRUCTION), cache.io.cpu.fetch.data)
}
} else {
cache.io.cpu.fetch.isUser := (if (privilegeService != null) privilegeService.isUser(decode) else False)
}
if(catchSomething){
val accessFault = if(catchAccessFault) cache.io.cpu.decode.error else False
val mmuMiss = if(catchMemoryTranslationMiss) cache.io.cpu.decode.mmuMiss else False
val illegalAccess = if(catchIllegalAccess) cache.io.cpu.decode.illegalAccess else False
decodeExceptionPort.valid := decode.arbitration.isValid && ownDecode && (accessFault || mmuMiss || illegalAccess)
decodeExceptionPort.code := mmuMiss ? U(14) | 1
decodeExceptionPort.badAddr := decode.input(PC)
}
memory plug new Area{
import memory._
cache.io.flush.cmd.valid := False
when(arbitration.isValid && input(FLUSH_ALL)){
cache.io.flush.cmd.valid := True
decode.arbitration.flushAll := True
// val missHalt = cache.io.cpu.fetch.isValid && cache.io.cpu.fetch.cacheMiss
val cacheRsp = if(twoCycleCache) cache.io.cpu.decode else cache.io.cpu.fetch
val cacheRspArbitration = iBusRsp.inputPipeline(if(twoCycleCache) 1 else 0)
var issueDetected = False
val redoFetch = False //RegNext(False) init(False)
when(cacheRsp.isValid && cacheRsp.cacheMiss && !issueDetected){
issueDetected \= True
redoFetch := iBusRsp.readyForError
}
when(!cache.io.flush.cmd.ready){
arbitration.haltItself := True
assert(decodePcGen == compressedGen)
cache.io.cpu.fill.valid := redoFetch
redoBranch.valid := redoFetch
redoBranch.payload := (if(decodePcGen) decode.input(PC) else cacheRsp.pc)
cache.io.cpu.fill.payload := cacheRsp.physicalAddress
if(catchSomething){
val accessFault = if (catchAccessFault) cacheRsp.error else False
val mmuMiss = if (catchMemoryTranslationMiss) cacheRsp.mmuMiss else False
val illegalAccess = if (catchIllegalAccess) cacheRsp.illegalAccess else False
decodeExceptionPort.valid := False
decodeExceptionPort.code := mmuMiss ? U(14) | 1
decodeExceptionPort.badAddr := cacheRsp.pc
when(cacheRsp.isValid && (accessFault || mmuMiss || illegalAccess) && !issueDetected){
issueDetected \= True
decodeExceptionPort.valid := iBusRsp.readyForError
}
}
iBusRsp.output.arbitrationFrom(cacheRspArbitration.haltWhen(issueDetected || iBusRspOutputHalt))
iBusRsp.output.rsp.inst := cacheRsp.data
iBusRsp.output.pc := cacheRspArbitration.payload
// if (dataOnDecode) {
// decode.insert(INSTRUCTION) := cache.io.cpu.decode.data
// } else {
// iBusRsp.outputBeforeStage.arbitrationFrom(iBusRsp.inputPipeline(0))
// iBusRsp.outputBeforeStage.rsp.inst := cache.io.cpu.fetch.data
// iBusRsp.outputBeforeStage.pc := iBusRsp.inputPipeline(0).payload
// }
//
// cache.io.cpu.decode.pc := injector.inputBeforeHalt.pc
//
// val ownDecode = pipeline.plugins.filter(_.isInstanceOf[InstructionInjector]).foldLeft(True)(_ && !_.asInstanceOf[InstructionInjector].isInjecting(decode))
// cache.io.cpu.decode.isValid := decode.arbitration.isValid && ownDecode
// cache.io.cpu.decode.isStuck := !injector.inputBeforeHalt.ready
// cache.io.cpu.decode.isUser := (if (privilegeService != null) privilegeService.isUser(decode) else False)
// // cache.io.cpu.decode.pc := decode.input(PC)
//
// redoBranch.valid := decode.arbitration.isValid && ownDecode && cache.io.cpu.decode.cacheMiss && !cache.io.cpu.decode.mmuMiss && !cache.io.cpu.decode.illegalAccess
// redoBranch.payload := decode.input(PC)
// when(redoBranch.valid) {
// decode.arbitration.redoIt := True
// decode.arbitration.flushAll := True
// }
// val redo = RegInit(False) clearWhen(decode.arbitration.isValid) setWhen(redoBranch.valid)
// when(redoBranch.valid || redo){
// service(classOf[InterruptionInhibitor]).inhibateInterrupts()
// }
// if (catchSomething) {
// val accessFault = if (catchAccessFault) cache.io.cpu.decode.error else False
// val mmuMiss = if (catchMemoryTranslationMiss) cache.io.cpu.decode.mmuMiss else False
// val illegalAccess = if (catchIllegalAccess) cache.io.cpu.decode.illegalAccess else False
// decodeExceptionPort.valid := decode.arbitration.isValid && ownDecode && (accessFault || mmuMiss || illegalAccess)
// decodeExceptionPort.code := mmuMiss ? U(14) | 1
// decodeExceptionPort.badAddr := decode.input(PC)
// }
memory plug new Area {
import memory._
cache.io.flush.cmd.valid := False
when(arbitration.isValid && input(FLUSH_ALL)) {
cache.io.flush.cmd.valid := True
decode.arbitration.flushAll := True
when(!cache.io.flush.cmd.ready) {
arbitration.haltItself := True
}
}
}
}

View file

@ -1,10 +1,11 @@
package vexriscv.plugin
import vexriscv.{Stageable, ExceptionService, ExceptionCause, VexRiscv}
import vexriscv._
import spinal.core._
import spinal.lib._
import spinal.lib.bus.amba4.axi._
import spinal.lib.bus.avalon.{AvalonMMConfig, AvalonMM}
import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig}
case class IBusSimpleCmd() extends Bundle{
@ -12,15 +13,15 @@ case class IBusSimpleCmd() extends Bundle{
}
case class IBusSimpleRsp() extends Bundle with IMasterSlave{
val ready = Bool
val error = Bool
val inst = Bits(32 bits)
override def asMaster(): Unit = {
out(ready,error,inst)
out(error,inst)
}
}
object IBusSimpleBus{
def getAxi4Config() = Axi4Config(
addressWidth = 32,
@ -40,12 +41,14 @@ object IBusSimpleBus{
dataWidth = 32
).getReadOnlyConfig.copy(
useResponse = true,
maximumPendingReadTransactions = 1
maximumPendingReadTransactions = 8
)
}
case class IBusSimpleBus(interfaceKeepData : Boolean) extends Bundle with IMasterSlave{
case class IBusSimpleBus(interfaceKeepData : Boolean) extends Bundle with IMasterSlave {
var cmd = Stream(IBusSimpleCmd())
var rsp = IBusSimpleRsp()
var rsp = Flow(IBusSimpleRsp())
override def asMaster(): Unit = {
master(cmd)
@ -64,7 +67,7 @@ case class IBusSimpleBus(interfaceKeepData : Boolean) extends Bundle with IMaste
cmd.ready := axi.ar.ready
rsp.ready := axi.r.valid
rsp.valid := axi.r.valid
rsp.inst := axi.r.data
rsp.error := !axi.r.isOKAY()
axi.r.ready := True
@ -87,7 +90,7 @@ case class IBusSimpleBus(interfaceKeepData : Boolean) extends Bundle with IMaste
mm.address := (cmd.pc >> 2) @@ U"00"
cmd.ready := mm.waitRequestn
rsp.ready := mm.readDataValid
rsp.valid := mm.readDataValid
rsp.inst := mm.readData
rsp.error := mm.response =/= AvalonMM.Response.OKAY
@ -95,12 +98,44 @@ case class IBusSimpleBus(interfaceKeepData : Boolean) extends Bundle with IMaste
}
}
class IBusSimplePlugin(interfaceKeepData : Boolean, catchAccessFault : Boolean) extends Plugin[VexRiscv]{
var iBus : IBusSimpleBus = null
object IBUS_ACCESS_ERROR extends Stageable(Bool)
class IBusSimplePlugin(resetVector : BigInt,
catchAccessFault : Boolean = false,
relaxedPcCalculation : Boolean = false,
prediction : BranchPrediction = NONE,
historyRamSizeLog2 : Int = 10,
keepPcPlus4 : Boolean = false,
compressedGen : Boolean = false,
busLatencyMin : Int = 1,
pendingMax : Int = 7,
injectorStage : Boolean = true,
relaxedBusCmdValid : Boolean = false
) extends IBusFetcherImpl(
catchAccessFault = catchAccessFault,
resetVector = resetVector,
keepPcPlus4 = keepPcPlus4,
decodePcGen = compressedGen,
compressedGen = compressedGen,
cmdToRspStageCount = busLatencyMin,
injectorReadyCutGen = false,
relaxedPcCalculation = relaxedPcCalculation,
prediction = prediction,
historyRamSizeLog2 = historyRamSizeLog2,
injectorStage = injectorStage){
assert(!(prediction == DYNAMIC_TARGET && relaxedBusCmdValid), "IBusSimplePlugin doesn't allow dynamic_target prediction and relaxedBusCmdValid together")
assert(!relaxedBusCmdValid)
var iBus : IBusSimpleBus = null
var decodeExceptionPort : Flow[ExceptionCause] = null
override def setup(pipeline: VexRiscv): Unit = {
super.setup(pipeline)
iBus = master(IBusSimpleBus(false)).setName("iBus")
if(catchAccessFault) {
val exceptionService = pipeline.service(classOf[ExceptionService])
decodeExceptionPort = exceptionService.newExceptionPort(pipeline.decode,1)
@ -110,51 +145,74 @@ class IBusSimplePlugin(interfaceKeepData : Boolean, catchAccessFault : Boolean)
override def build(pipeline: VexRiscv): Unit = {
import pipeline._
import pipeline.config._
iBus = master(IBusSimpleBus(interfaceKeepData)).setName("iBus")
prefetch plug new Area {
val pendingCmd = RegInit(False) clearWhen (iBus.rsp.ready) setWhen (iBus.cmd.fire)
//Emit iBus.cmd request
iBus.cmd.valid := prefetch.arbitration.isValid && !prefetch.arbitration.removeIt && !prefetch.arbitration.isStuckByOthers && !(pendingCmd && !iBus.rsp.ready) //prefetch.arbitration.isValid && !prefetch.arbitration.isStuckByOthers
iBus.cmd.pc := prefetch.output(PC)
prefetch.arbitration.haltItself setWhen (!iBus.cmd.ready || (pendingCmd && !iBus.rsp.ready))
}
pipeline plug new FetchArea(pipeline) {
//Bus rsp buffer
val rspBuffer = if(!interfaceKeepData) new Area{
val valid = RegInit(False) setWhen(iBus.rsp.ready) clearWhen(!fetch.arbitration.isStuck)
val error = Reg(Bool)
val data = Reg(Bits(32 bits))
when(!valid) {
data := iBus.rsp.inst
error := iBus.rsp.error
//Avoid sending to many iBus cmd
val pendingCmd = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0)
val pendingCmdNext = pendingCmd + iBus.cmd.fire.asUInt - iBus.rsp.fire.asUInt
pendingCmd := pendingCmdNext
val cmd = if(relaxedBusCmdValid) new Area {
assert(relaxedPcCalculation, "relaxedBusCmdValid can only be used with relaxedPcCalculation")
def input = fetchPc.output
def output = iBusRsp.input
val fork = StreamForkVex(input, 2, flush)
val busFork = fork(0)
val pipFork = fork(1)
output << pipFork
val okBus = pendingCmd =/= pendingMax
iBus.cmd.valid := busFork.valid && okBus
iBus.cmd.pc := busFork.payload(31 downto 2) @@ "00"
busFork.ready := iBus.cmd.ready && okBus
} else new Area {
def input = fetchPc.output
def output = iBusRsp.input
output << input.continueWhen(iBus.cmd.fire)
iBus.cmd.valid := input.valid && output.ready && pendingCmd =/= pendingMax
iBus.cmd.pc := input.payload(31 downto 2) @@ "00"
}
} else null
//Insert iBus.rsp into INSTRUCTION
fetch.insert(INSTRUCTION) := iBus.rsp.inst
fetch.insert(IBUS_ACCESS_ERROR) := iBus.rsp.error
if(!interfaceKeepData) {
when(rspBuffer.valid) {
fetch.insert(INSTRUCTION) := rspBuffer.data
fetch.insert(IBUS_ACCESS_ERROR) := rspBuffer.error
val rsp = new Area {
import iBusRsp._
//Manage flush for iBus transactions in flight
val discardCounter = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0)
discardCounter := discardCounter - (iBus.rsp.fire && discardCounter =/= 0).asUInt
when(flush) {
discardCounter := (if(relaxedPcCalculation) pendingCmdNext else pendingCmd - iBus.rsp.fire.asUInt)
}
val rspBuffer = StreamFifoLowLatency(IBusSimpleRsp(), cmdToRspStageCount + (if(relaxedBusCmdValid) 1 else 0))
rspBuffer.io.push << iBus.rsp.throwWhen(discardCounter =/= 0).toStream
rspBuffer.io.flush := flush
val fetchRsp = FetchRsp()
fetchRsp.pc := inputPipeline.last.payload
fetchRsp.rsp := rspBuffer.io.pop.payload
fetchRsp.rsp.error.clearWhen(!rspBuffer.io.pop.valid) //Avoid interference with instruction injection from the debug plugin
var issueDetected = False
val join = StreamJoin(Seq(inputPipeline.last, rspBuffer.io.pop), fetchRsp)
inputPipeline.last.ready setWhen(!inputPipeline.last.valid)
output << join.haltWhen(issueDetected)
if(catchAccessFault){
decodeExceptionPort.valid := False
decodeExceptionPort.code := 1
decodeExceptionPort.badAddr := join.pc
when(join.valid && join.rsp.error && !issueDetected){
issueDetected \= True
decodeExceptionPort.valid := iBusRsp.readyForError
}
}
}
}
fetch.insert(IBUS_ACCESS_ERROR) clearWhen(!fetch.arbitration.isValid) //Avoid interference with instruction injection from the debug plugin
if(interfaceKeepData)
fetch.arbitration.haltItself setWhen(fetch.arbitration.isValid && !iBus.rsp.ready)
else
fetch.arbitration.haltItself setWhen(fetch.arbitration.isValid && !iBus.rsp.ready && !rspBuffer.valid)
decode.insert(INSTRUCTION_ANTICIPATED) := Mux(decode.arbitration.isStuck,decode.input(INSTRUCTION),fetch.output(INSTRUCTION))
decode.insert(INSTRUCTION_READY) := True
if(catchAccessFault){
decodeExceptionPort.valid := decode.arbitration.isValid && decode.input(IBUS_ACCESS_ERROR)
decodeExceptionPort.code := 1
decodeExceptionPort.badAddr := decode.input(PC)
}
}
}
}

View file

@ -5,7 +5,12 @@ import spinal.core._
import spinal.lib._
import scala.collection.mutable.ArrayBuffer
case class MemoryTranslatorPort(bus : MemoryTranslatorBus, stage : Stage, args : MemoryTranslatorPortConfig/*, exceptionBus: Flow[ExceptionCause]*/)
object MemoryTranslatorPort{
val PRIORITY_DATA = 1
val PRIORITY_INSTRUCTION = 0
}
case class MemoryTranslatorPort(bus : MemoryTranslatorBus, priority : Int, args : MemoryTranslatorPortConfig/*, exceptionBus: Flow[ExceptionCause]*/)
case class MemoryTranslatorPortConfig(portTlbSize : Int)
@ -16,9 +21,9 @@ class MemoryTranslatorPlugin(tlbSize : Int,
val portsInfo = ArrayBuffer[MemoryTranslatorPort]()
override def newTranslationPort(stage : Stage,args : Any): MemoryTranslatorBus = {
override def newTranslationPort(priority : Int,args : Any): MemoryTranslatorBus = {
// val exceptionBus = pipeline.service(classOf[ExceptionService]).newExceptionPort(stage)
val port = MemoryTranslatorPort(MemoryTranslatorBus(),stage,args.asInstanceOf[MemoryTranslatorPortConfig]/*,exceptionBus*/)
val port = MemoryTranslatorPort(MemoryTranslatorBus(),priority,args.asInstanceOf[MemoryTranslatorPortConfig]/*,exceptionBus*/)
portsInfo += port
port.bus
}
@ -41,7 +46,7 @@ class MemoryTranslatorPlugin(tlbSize : Int,
import Riscv._
//Sorted by priority
val sortedPortsInfo = portsInfo.sortWith((a,b) => indexOf(a.stage) > indexOf(b.stage))
val sortedPortsInfo = portsInfo.sortWith((a,b) => a.priority > b.priority)
case class CacheLine() extends Bundle {
val valid = Bool
@ -94,7 +99,7 @@ class MemoryTranslatorPlugin(tlbSize : Int,
}
sharedMiss.setWhen(sharedIterator >= tlbSize && sharedAccessed === B"00")
when(!port.stage.arbitration.isStuck){
when(port.bus.end){
sharedIterator := 0
sharedMiss.clear()
sharedAccessAsked.clear()
@ -108,13 +113,15 @@ class MemoryTranslatorPlugin(tlbSize : Int,
port.bus.rsp.allowWrite := cacheLine.allowWrite
port.bus.rsp.allowExecute := cacheLine.allowExecute
port.bus.rsp.allowUser := cacheLine.allowUser
port.stage.arbitration.haltItself setWhen (port.bus.cmd.isValid && !cacheHit && !sharedMiss)
port.bus.rsp.hit := cacheHit
// port.stage.arbitration.haltItself setWhen (port.bus.cmd.isValid && !cacheHit && !sharedMiss)
} otherwise {
port.bus.rsp.physicalAddress := port.bus.cmd.virtualAddress
port.bus.rsp.allowRead := True
port.bus.rsp.allowWrite := True
port.bus.rsp.allowExecute := True
port.bus.rsp.allowUser := True
port.bus.rsp.hit := True
}
port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress)
port.bus.rsp.miss := sharedMiss

View file

@ -0,0 +1,198 @@
package vexriscv.plugin
import spinal.core._
import spinal.lib._
object RvcDecompressor{
def main(args: Array[String]): Unit = {
SpinalVerilog(new Component{
out(Delay((apply(Delay(in Bits(16 bits),2))),2))
}.setDefinitionName("Decompressor"))
}
def apply(i : Bits): Bits ={
val ret = Bits(32 bits).assignDontCare()
val rch = B"01" ## i(9 downto 7)
val rcl = B"01" ## i(4 downto 2)
val addi5spnImm = B"00" ## i(10 downto 7) ## i(12 downto 11) ## i(5) ## i(6) ## B"00"
val lwImm = B"00000" ## i(5) ## i(12 downto 10) ## i(6) ## B"00"
def swImm = lwImm
val addImm = B((11 downto 5) -> i(12), (4 downto 0) -> i(6 downto 2))
def lImm = addImm
val jalImm = B((9 downto 0) -> i(12)) ## i(8) ## i(10 downto 9) ## i(6) ## i(7) ## i(2) ## i(11) ## i(5 downto 3) ## B"0"
val luiImm = B((14 downto 0) -> i(12)) ## i(6 downto 2) ## B"0000_0000_0000"
val shiftImm = i(6 downto 2)
val addi16spImm = B((2 downto 0) -> i(12)) ## i(4 downto 3) ## i(5) ## i(2) ## i(6) ## B"0000"
val jImm = B((9 downto 0) -> i(12)) ## i(8) ## i(10 downto 9) ## i(6) ## i(7) ## i(2) ## i(11) ## i(5 downto 3) ## B"0"
val bImm = B((4 downto 0) -> i(12)) ## i(6 downto 5) ## i(2) ## i(11 downto 10) ## i(4 downto 3) ## B"0"
def lwspImm = B"0000" ## i(3 downto 2) ## i(12) ## i(6 downto 4) ## B"00"
def swspImm = B"0000" ## i(8 downto 7) ## i(12 downto 9) ## B"00"
val x0 = B"00000"
val x1 = B"00001"
val x2 = B"00010"
switch(i(1 downto 0) ## i(15 downto 13)){
is(0){ret := addi5spnImm ## B"00010" ## B"000" ## rcl ## B"0010011"} //C.ADDI4SPN -> addi rd0, x2, nzuimm[9:2].
is(2){ret := lwImm ## rch ## B"010" ## rcl ## B"0000011"} //C.LW -> lw rd', offset[6:2](rs1')
is(6){ret := swImm(11 downto 5) ## rcl ## rch ## B"010" ## swImm(4 downto 0) ## B"0100011"} //C.SW -> sw rs2',offset[6:2](rs1')
is(8){ret := addImm ## i(11 downto 7) ## B"000" ## i(11 downto 7) ## B"0010011"} //C.ADDI -> addi rd, rd, nzimm[5:0].
is(9){ret := jalImm(20) ## jalImm(10 downto 1) ## jalImm(11) ## jalImm(19 downto 12) ## x1 ## B"1101111"} //C.JAL -> jalr x1, rs1, 0.
is(10){ret := lImm ## B"00000" ## B"000" ## i(11 downto 7) ## B"0010011"} //C.LI -> addi rd, x0, imm[5:0].
is(11){ //C.ADDI16SP C.LUI ->
val addi16sp = addi16spImm ## i(11 downto 7) ## B"000" ## i(11 downto 7) ## B"0010011"
val lui = luiImm(31 downto 12) ## i(11 downto 7) ## B"0110111"
ret := (i(11 downto 7) === 2) ? addi16sp | lui
}
is(12){
val isImmediate = i(11 downto 10) =/= "11"
val isShift = !i(11)
val func3 = i(11 downto 10).mux(
0 -> B"101",
1 -> B"101",
2 -> B"111",
3 -> i(6 downto 5).mux(
0 -> B"000",
1 -> B"100",
2 -> B"110",
3 -> B"111"
)
)
val msbs = Mux(
sel = i(11 downto 10) === "10",
whenTrue = B((6 downto 0) -> i(12)), //andi
whenFalse = B"0" ## (i(11 downto 10) === B"01" || (i(11 downto 10) === B"11" && i(6 downto 5) === B"00")) ## B"00000"
)
val rs2Shift = (isShift || isImmediate) ? shiftImm | rcl
val opc = (isImmediate ? B"0010011" | B"0110011")
ret := msbs ## rs2Shift ## rch ## func3 ## rch ## opc
}
is(13){ ret := jImm(20) ## jImm(10 downto 1) ## jImm(11) ## jImm(19 downto 12) ## x0 ## B"1101111"}
is(14){ ret := bImm(12) ## bImm(10 downto 5) ## x0 ## rch ## B"000" ## bImm(4 downto 1) ## bImm(11) ## B"1100011" }
is(15){ ret := bImm(12) ## bImm(10 downto 5) ## x0 ## rch ## B"001" ## bImm(4 downto 1) ## bImm(11) ## B"1100011" }
is(16){ ret := B"0000000" ## i(6 downto 2) ## i(11 downto 7) ## B"001" ## i(11 downto 7) ## B"0010011" }
is(18){ ret := lwspImm ## x2 ## B"010" ## i(11 downto 7) ## B"0000011" }
is(20) {
val add = B"000_0000" ## i(6 downto 2) ## (i(12) ? i(11 downto 7) | x0) ## B"000" ## i(11 downto 7) ## B"0110011" //add => add rd, rd, rs2 mv => add rd, x0, rs2
val j = B"0000_0000_0000" ## i(11 downto 7) ## B"000" ## (i(12) ? x1 | x0) ## B"1100111" //jr => jalr x0, rs1, 0. jalr => jalr x1, rs1, 0.
val ebreak = B"000000000001_00000_000_00000_1110011" //EBREAK
val addJ = (i(6 downto 2) === 0) ? j | add
ret := (i(12 downto 2) === B"100_0000_0000") ? ebreak | addJ
}
is(22){ ret := swspImm(11 downto 5) ## i(6 downto 2) ## x2 ## B"010" ## swspImm(4 downto 0) ## B"0100011" }
}
ret
}
}
object StreamForkVex{
def apply[T <: Data](input : Stream[T], portCount: Int, flush : Bool/*, flushDiscardInput : Boolean*/) : Vec[Stream[T]] = {
val outputs = Vec(cloneOf(input), portCount)
val linkEnable = Vec(RegInit(True), portCount)
input.ready := True
for (i <- 0 until portCount) {
when(!outputs(i).ready && linkEnable(i)) {
input.ready := False
}
}
for (i <- 0 until portCount) {
outputs(i).valid := input.valid && linkEnable(i)
outputs(i).payload := input.payload
when(outputs(i).fire) {
linkEnable(i) := False
}
}
when(input.ready || flush) {
linkEnable.foreach(_ := True)
}
outputs
}
}
object StreamVexPimper{
implicit class StreamFlushPimper[T <: Data](pimped : Stream[T]){
def m2sPipeWithFlush(flush : Bool, discardInput : Boolean = true, collapsBubble : Boolean = true): Stream[T] = {
val ret = cloneOf(pimped)
val rValid = RegInit(False)
val rData = Reg(pimped.dataType)
if(!discardInput) rValid.clearWhen(flush)
pimped.ready := (Bool(collapsBubble) && !ret.valid) || ret.ready
when(pimped.ready) {
rValid := pimped.valid
rData := pimped.payload
}
ret.valid := rValid
ret.payload := rData
if(discardInput) rValid.clearWhen(flush)
ret
}
def s2mPipe(flush : Bool): Stream[T] = {
val ret = cloneOf(pimped)
val rValid = RegInit(False)
val rBits = Reg(pimped.dataType)
ret.valid := pimped.valid || rValid
pimped.ready := !rValid
ret.payload := Mux(rValid, rBits, pimped.payload)
when(ret.ready) {
rValid := False
}
when(pimped.ready && (!ret.ready)) {
rValid := pimped.valid
rBits := pimped.payload
}
rValid.clearWhen(flush)
ret
}
}
}
//case class FlowFifoLowLatency[T <: Data](dataType: T, depth: Int) extends Component {
// require(depth >= 1)
// val io = new Bundle {
// val push = slave Flow (dataType)
// val pop = master Stream (dataType)
// val flush = in Bool()
// }
//
//
// val mem = Vec(Reg(dataType), depth)
// val rPtr, wPtr = Counter(depth + 1)
// when(io.push.valid){
// mem(wPtr) := io.push.payload
// wPtr.increment()
// }
//
// when(io.pop.fire){
// rPtr.increment()
// }
// io.pop.valid := rPtr =/= wPtr
//
//
//}

View file

@ -20,134 +20,139 @@ object KeepAttribute{
def apply[T <: Data](that : T) = that.addAttribute(keep).addAttribute(syn_keep_verilog).addAttribute(syn_keep_vhdl)
}
class PcManagerSimplePlugin(resetVector : BigInt,
relaxedPcCalculation : Boolean = false,
keepPcPlus4 : Boolean = true) extends Plugin[VexRiscv] with JumpService{
var externalResetVector : UInt = null
//FetchService interface
case class JumpInfo(interface : Flow[UInt], stage: Stage, priority : Int)
val jumpInfos = ArrayBuffer[JumpInfo]()
override def createJumpInterface(stage: Stage, priority : Int = 0): Flow[UInt] = {
val interface = Flow(UInt(32 bits))
jumpInfos += JumpInfo(interface,stage, priority)
interface
}
var prefetchExceptionPort : Flow[ExceptionCause] = null
override def setup(pipeline: VexRiscv): Unit = {
if(!relaxedPcCalculation) pipeline.unremovableStages += pipeline.prefetch
if(resetVector == null) externalResetVector = in(UInt(32 bits).setName("externalResetVector"))
}
keepPcPlus4 : Boolean = true) extends Plugin[VexRiscv]{
override def build(pipeline: VexRiscv): Unit = {println("PcManagerSimplePlugin is now useless")}
}
override def build(pipeline: VexRiscv): Unit = {
import pipeline.config._
import pipeline._
if(relaxedPcCalculation)
relaxedImpl(pipeline)
else
cycleEffectiveImpl(pipeline)
//Formal verification signals generation
prefetch.insert(FORMAL_PC_NEXT) := prefetch.input(PC) + 4
jumpInfos.foreach(info => {
when(info.interface.valid){
info.stage.output(FORMAL_PC_NEXT) := info.interface.payload
}
})
}
//reduce combinatorial path, and expose the PC to the pipeline as a register
def relaxedImpl(pipeline: VexRiscv): Unit = {
import pipeline.config._
import pipeline._
prefetch plug new Area {
import prefetch._
//Stage always valid
arbitration.isValid := True
//PC calculation without Jump
val pcReg = Reg(UInt(32 bits)) init(if(resetVector != null) resetVector else externalResetVector) addAttribute(Verilator.public)
val pcPlus4 = pcReg + 4
if(keepPcPlus4) KeepAttribute(pcPlus4)
when(arbitration.isFiring){
pcReg := pcPlus4
}
//JumpService hardware implementation
val jump = if(jumpInfos.length != 0) new Area {
val sortedByStage = jumpInfos.sortWith((a, b) => {
(pipeline.indexOf(a.stage) > pipeline.indexOf(b.stage)) ||
(pipeline.indexOf(a.stage) == pipeline.indexOf(b.stage) && a.priority > b.priority)
})
val valids = sortedByStage.map(_.interface.valid)
val pcs = sortedByStage.map(_.interface.payload)
val pcLoad = Flow(UInt(32 bits))
pcLoad.valid := jumpInfos.map(_.interface.valid).orR
pcLoad.payload := MuxOH(OHMasking.first(valids.asBits), pcs)
//application of the selected jump request
when(pcLoad.valid) {
pcReg := pcLoad.payload
}
}
insert(PC_CALC_WITHOUT_JUMP) := pcReg
insert(PC) := pcReg
}
}
//Jump take effect instantly (save one cycle), but expose the PC to the pipeline as a 'long' combinatorial path
def cycleEffectiveImpl(pipeline: VexRiscv): Unit = {
import pipeline.config._
import pipeline.prefetch
prefetch plug new Area {
import prefetch._
//Stage always valid
arbitration.isValid := True
//PC calculation without Jump
val pcReg = Reg(UInt(32 bits)) init(if(resetVector != null) resetVector else externalResetVector) addAttribute(Verilator.public)
val inc = RegInit(False)
val pcBeforeJumps = pcReg + (inc ## B"00").asUInt
insert(PC_CALC_WITHOUT_JUMP) := pcBeforeJumps
val pc = UInt(32 bits)
pc := input(PC_CALC_WITHOUT_JUMP)
val samplePcNext = False
//JumpService hardware implementation
val jump = if(jumpInfos.length != 0) new Area {
val sortedByStage = jumpInfos.sortWith((a, b) => pipeline.indexOf(a.stage) > pipeline.indexOf(b.stage))
val valids = sortedByStage.map(_.interface.valid)
val pcs = sortedByStage.map(_.interface.payload)
val pcLoad = Flow(UInt(32 bits))
pcLoad.valid := jumpInfos.map(_.interface.valid).orR
pcLoad.payload := MuxOH(OHMasking.first(valids.asBits), pcs)
//application of the selected jump request
when(pcLoad.valid) {
inc := False
samplePcNext := True
pc := pcLoad.payload
}
}
when(arbitration.isFiring){
inc := True
samplePcNext := True
}
when(samplePcNext) { pcReg := pc }
insert(PC) := pc
}
}
}
//class PcManagerSimplePlugin(resetVector : BigInt,
// relaxedPcCalculation : Boolean = false,
// keepPcPlus4 : Boolean = true) extends Plugin[VexRiscv] with JumpService{
// //FetchService interface
// case class JumpInfo(interface : Flow[UInt], stage: Stage, priority : Int)
// val jumpInfos = ArrayBuffer[JumpInfo]()
// override def createJumpInterface(stage: Stage, priority : Int = 0): Flow[UInt] = {
// val interface = Flow(UInt(32 bits))
// jumpInfos += JumpInfo(interface,stage, priority)
// interface
// }
// var prefetchExceptionPort : Flow[ExceptionCause] = null
//
// override def setup(pipeline: VexRiscv): Unit = {
// if(!relaxedPcCalculation) pipeline.unremovableStages += pipeline.prefetch
// }
//
//
// override def build(pipeline: VexRiscv): Unit = {
// import pipeline.config._
// import pipeline._
//
// if(relaxedPcCalculation)
// relaxedImpl(pipeline)
// else
// cycleEffectiveImpl(pipeline)
//
// //Formal verification signals generation
// prefetch.insert(FORMAL_PC_NEXT) := prefetch.input(PC) + 4
// jumpInfos.foreach(info => {
// when(info.interface.valid){
// info.stage.output(FORMAL_PC_NEXT) := info.interface.payload
// }
// })
// }
//
// //reduce combinatorial path, and expose the PC to the pipeline as a register
// def relaxedImpl(pipeline: VexRiscv): Unit = {
// import pipeline.config._
// import pipeline._
//
// prefetch plug new Area {
// import prefetch._
// //Stage always valid
// arbitration.isValid := True
//
// //PC calculation without Jump
// val pcReg = Reg(UInt(32 bits)) init(resetVector) addAttribute(Verilator.public)
// val pcPlus4 = pcReg + 4
// if(keepPcPlus4) KeepAttribute(pcPlus4)
// when(arbitration.isFiring){
// pcReg := pcPlus4
// }
//
// //JumpService hardware implementation
// val jump = if(jumpInfos.length != 0) new Area {
// val sortedByStage = jumpInfos.sortWith((a, b) => {
// (pipeline.indexOf(a.stage) > pipeline.indexOf(b.stage)) ||
// (pipeline.indexOf(a.stage) == pipeline.indexOf(b.stage) && a.priority > b.priority)
// })
// val valids = sortedByStage.map(_.interface.valid)
// val pcs = sortedByStage.map(_.interface.payload)
//
// val pcLoad = Flow(UInt(32 bits))
// pcLoad.valid := jumpInfos.map(_.interface.valid).orR
// pcLoad.payload := MuxOH(OHMasking.first(valids.asBits), pcs)
//
// //application of the selected jump request
// when(pcLoad.valid) {
// pcReg := pcLoad.payload
// }
// }
//
// insert(PC_CALC_WITHOUT_JUMP) := pcReg
// insert(PC) := pcReg
// }
// }
//
// //Jump take effect instantly (save one cycle), but expose the PC to the pipeline as a 'long' combinatorial path
// def cycleEffectiveImpl(pipeline: VexRiscv): Unit = {
// import pipeline.config._
// import pipeline.prefetch
//
// prefetch plug new Area {
// import prefetch._
// //Stage always valid
// arbitration.isValid := True
//
// //PC calculation without Jump
// val pcReg = Reg(UInt(32 bits)) init(resetVector) addAttribute(Verilator.public)
// val inc = RegInit(False)
// val pcBeforeJumps = pcReg + (inc ## B"00").asUInt
// insert(PC_CALC_WITHOUT_JUMP) := pcBeforeJumps
// val pc = UInt(32 bits)
// pc := input(PC_CALC_WITHOUT_JUMP)
//
// val samplePcNext = False
//
// //JumpService hardware implementation
// val jump = if(jumpInfos.length != 0) new Area {
// val sortedByStage = jumpInfos.sortWith((a, b) => pipeline.indexOf(a.stage) > pipeline.indexOf(b.stage))
// val valids = sortedByStage.map(_.interface.valid)
// val pcs = sortedByStage.map(_.interface.payload)
//
// val pcLoad = Flow(UInt(32 bits))
// pcLoad.valid := jumpInfos.map(_.interface.valid).orR
// pcLoad.payload := MuxOH(OHMasking.first(valids.asBits), pcs)
//
// //application of the selected jump request
// when(pcLoad.valid) {
// inc := False
// samplePcNext := True
// pc := pcLoad.payload
// }
// }
//
// when(arbitration.isFiring){
// inc := True
// samplePcNext := True
// }
//
// when(samplePcNext) { pcReg := pc }
//
// insert(PC) := pc
// }
// }
//}

View file

@ -11,9 +11,11 @@ trait RegFileReadKind
object ASYNC extends RegFileReadKind
object SYNC extends RegFileReadKind
class RegFilePlugin(regFileReadyKind : RegFileReadKind,zeroBoot : Boolean = false) extends Plugin[VexRiscv]{
class RegFilePlugin(regFileReadyKind : RegFileReadKind,zeroBoot : Boolean = false, writeRfInMemoryStage : Boolean = false) extends Plugin[VexRiscv]{
import Riscv._
assert(!writeRfInMemoryStage)
override def setup(pipeline: VexRiscv): Unit = {
import pipeline.config._
val decoderService = pipeline.service(classOf[DecoderService])
@ -59,7 +61,7 @@ class RegFilePlugin(regFileReadyKind : RegFileReadKind,zeroBoot : Boolean = fals
}
//Write register file
writeBack plug new Area {
(if(writeRfInMemoryStage) memory else writeBack) plug new Area {
import writeBack._
val regFileWrite = global.regFile.writePort.addAttribute(Verilator.public)

View file

@ -10,6 +10,6 @@ class SingleInstructionLimiterPlugin() extends Plugin[VexRiscv] {
import pipeline._
import pipeline.config._
prefetch.arbitration.haltByOther.setWhen(List(fetch,decode,execute,memory,writeBack).map(_.arbitration.isValid).orR)
decode.arbitration.haltByOther.setWhen(List(decode,execute,memory,writeBack).map(_.arbitration.isValid).orR)
}
}

View file

@ -1,6 +1,6 @@
package vexriscv.plugin
import vexriscv.{Riscv, VexRiscv}
import vexriscv.{RVC_GEN, Riscv, VexRiscv}
import spinal.core._
@ -15,7 +15,7 @@ class SrcPlugin(separatedAddSub : Boolean, executeInsertion : Boolean = false) e
val imm = Riscv.IMM(input(INSTRUCTION))
insert(SRC1) := input(SRC1_CTRL).mux(
Src1CtrlEnum.RS -> output(RS1),
Src1CtrlEnum.FOUR -> B(4),
Src1CtrlEnum.PC_INCREMENT -> (if(pipeline(RVC_GEN)) Mux(input(IS_RVC), B(2), B(4)) else B(4)).resized,
Src1CtrlEnum.IMU -> imm.u.resized
)
insert(SRC2) := input(SRC2_CTRL).mux(

View file

@ -5,14 +5,14 @@ import spinal.core._
import spinal.lib._
import scala.collection.mutable.ArrayBuffer
case class StaticMemoryTranslatorPort(bus : MemoryTranslatorBus, stage : Stage)
case class StaticMemoryTranslatorPort(bus : MemoryTranslatorBus, priority : Int)
class StaticMemoryTranslatorPlugin(ioRange : UInt => Bool) extends Plugin[VexRiscv] with MemoryTranslator {
val portsInfo = ArrayBuffer[StaticMemoryTranslatorPort]()
override def newTranslationPort(stage : Stage,args : Any): MemoryTranslatorBus = {
override def newTranslationPort(priority : Int,args : Any): MemoryTranslatorBus = {
// val exceptionBus = pipeline.service(classOf[ExceptionService]).newExceptionPort(stage)
val port = StaticMemoryTranslatorPort(MemoryTranslatorBus(),stage)
val port = StaticMemoryTranslatorPort(MemoryTranslatorBus(),priority)
portsInfo += port
port.bus
}
@ -34,6 +34,7 @@ class StaticMemoryTranslatorPlugin(ioRange : UInt => Bool) extends Plugin[VexRis
port.bus.rsp.allowUser := True
port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress)
port.bus.rsp.miss := False
port.bus.rsp.hit := True
}
}
}

View file

@ -8,12 +8,12 @@ onChipRam 0x0000000000000000 0x0000000000002000 w !xr
Linker script and memory map
LOAD build/src/crt.o
LOAD /opt/riscv/bin/../lib/gcc/riscv64-unknown-elf/7.1.1/rv32i/ilp32/libgcc.a
LOAD /opt/riscv/bin/../lib/gcc/riscv64-unknown-elf/7.2.0/rv32i/ilp32/libgcc.a
START GROUP
LOAD /opt/riscv/bin/../lib/gcc/riscv64-unknown-elf/7.1.1/../../../../riscv64-unknown-elf/lib/rv32i/ilp32/libc.a
LOAD /opt/riscv/bin/../lib/gcc/riscv64-unknown-elf/7.1.1/../../../../riscv64-unknown-elf/lib/rv32i/ilp32/libgloss.a
LOAD /opt/riscv/bin/../lib/gcc/riscv64-unknown-elf/7.2.0/../../../../riscv64-unknown-elf/lib/rv32i/ilp32/libc.a
LOAD /opt/riscv/bin/../lib/gcc/riscv64-unknown-elf/7.2.0/../../../../riscv64-unknown-elf/lib/rv32i/ilp32/libgloss.a
END GROUP
LOAD /opt/riscv/bin/../lib/gcc/riscv64-unknown-elf/7.1.1/rv32i/ilp32/libgcc.a
LOAD /opt/riscv/bin/../lib/gcc/riscv64-unknown-elf/7.2.0/rv32i/ilp32/libgcc.a
0x0000000000000000 . = 0x0
.crt_section 0x0000000000000000 0xd0

2
src/test/cpp/regression/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*.regTraceRef
/freertos.gtkw

View file

@ -0,0 +1,57 @@
Dhrystone Benchmark, Version 2.1 (Language: C)
Program compiled without 'register' attribute
Please give the number of runs through the benchmark:
Execution starts, 200 runs through Dhrystone
Execution ends
Final values of the variables used in the benchmark:
Int_Glob: 5
should be: 5
Bool_Glob: 1
should be: 1
Ch_1_Glob: A
should be: A
Ch_2_Glob: B
should be: B
Arr_1_Glob[8]: 7
should be: 7
Arr_2_Glob[8][7]: 210
should be: Number_Of_Runs + 10
Ptr_Glob->
Ptr_Comp: -2147459900
should be: (implementation-dependent)
Discr: 0
should be: 0
Enum_Comp: 2
should be: 2
Int_Comp: 17
should be: 17
Str_Comp: DHRYSTONE PROGRAM, SOME STRING
should be: DHRYSTONE PROGRAM, SOME STRING
Next_Ptr_Glob->
Ptr_Comp: -2147459900
should be: (implementation-dependent), same as above
Discr: 0
should be: 0
Enum_Comp: 1
should be: 1
Int_Comp: 18
should be: 18
Str_Comp: DHRYSTONE PROGRAM, SOME STRING
should be: DHRYSTONE PROGRAM, SOME STRING
Int_1_Loc: 5
should be: 5
Int_2_Loc: 13
should be: 13
Int_3_Loc: 7
should be: 7
Enum_Loc: 1
should be: 1
Str_1_Loc: DHRYSTONE PROGRAM, 1'ST STRING
should be: DHRYSTONE PROGRAM, 1'ST STRING
Str_2_Loc: DHRYSTONE PROGRAM, 2'ND STRING
should be: DHRYSTONE PROGRAM, 2'ND STRING

View file

@ -0,0 +1,57 @@
Dhrystone Benchmark, Version 2.1 (Language: C)
Program compiled without 'register' attribute
Please give the number of runs through the benchmark:
Execution starts, 200 runs through Dhrystone
Execution ends
Final values of the variables used in the benchmark:
Int_Glob: 5
should be: 5
Bool_Glob: 1
should be: 1
Ch_1_Glob: A
should be: A
Ch_2_Glob: B
should be: B
Arr_1_Glob[8]: 7
should be: 7
Arr_2_Glob[8][7]: 210
should be: Number_Of_Runs + 10
Ptr_Glob->
Ptr_Comp: -2147460916
should be: (implementation-dependent)
Discr: 0
should be: 0
Enum_Comp: 2
should be: 2
Int_Comp: 17
should be: 17
Str_Comp: DHRYSTONE PROGRAM, SOME STRING
should be: DHRYSTONE PROGRAM, SOME STRING
Next_Ptr_Glob->
Ptr_Comp: -2147460916
should be: (implementation-dependent), same as above
Discr: 0
should be: 0
Enum_Comp: 1
should be: 1
Int_Comp: 18
should be: 18
Str_Comp: DHRYSTONE PROGRAM, SOME STRING
should be: DHRYSTONE PROGRAM, SOME STRING
Int_1_Loc: 5
should be: 5
Int_2_Loc: 13
should be: 13
Int_3_Loc: 7
should be: 7
Enum_Loc: 1
should be: 1
Str_1_Loc: DHRYSTONE PROGRAM, 1'ST STRING
should be: DHRYSTONE PROGRAM, 1'ST STRING
Str_2_Loc: DHRYSTONE PROGRAM, 2'ND STRING
should be: DHRYSTONE PROGRAM, 2'ND STRING

View file

@ -0,0 +1,67 @@
[*]
[*] GTKWave Analyzer v3.3.86 (w)1999-2017 BSI
[*] Wed Apr 11 18:53:23 2018
[*]
[dumpfile] "/home/spinalvm/hdl/VexRiscv/src/test/cpp/regression/rv32ui-p-lui.vcd"
[dumpfile_mtime] "Wed Apr 11 18:52:18 2018"
[dumpfile_size] 325049
[savefile] "/home/spinalvm/hdl/VexRiscv/src/test/cpp/regression/icache.gtkw"
[timestart] 1006
[size] 1784 950
[pos] -383 -155
*-5.000000 1046 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
[treeopen] TOP.
[treeopen] TOP.VexRiscv.
[sst_width] 370
[signals_width] 349
[sst_expanded] 1
[sst_vpaned_height] 271
@28
TOP.VexRiscv.decode_arbitration_isValid
TOP.VexRiscv.decode_arbitration_redoIt
TOP.VexRiscv.IBusCachedPlugin_cache.io_cpu_prefetch_haltIt
@22
TOP.VexRiscv.iBus_cmd_payload_address[31:0]
@28
TOP.VexRiscv.iBus_cmd_payload_size[2:0]
TOP.VexRiscv.iBus_cmd_ready
@29
TOP.VexRiscv.iBus_cmd_valid
@22
TOP.VexRiscv.iBus_rsp_payload_data[31:0]
@28
TOP.VexRiscv.iBus_rsp_payload_error
TOP.VexRiscv.iBus_rsp_valid
[color] 2
TOP.VexRiscv.IBusCachedPlugin_cache.io_cpu_prefetch_isValid
[color] 2
TOP.VexRiscv.IBusCachedPlugin_cache.io_cpu_prefetch_haltIt
@22
[color] 2
TOP.VexRiscv.IBusCachedPlugin_cache.io_cpu_prefetch_pc[31:0]
@28
TOP.VexRiscv.IBusCachedPlugin_cache.io_cpu_fetch_isValid
TOP.VexRiscv.IBusCachedPlugin_cache.io_cpu_fetch_isStuck
@22
TOP.VexRiscv.IBusCachedPlugin_cache.io_cpu_fetch_data[31:0]
TOP.VexRiscv.IBusCachedPlugin_cache.io_cpu_fetch_pc[31:0]
@28
[color] 6
TOP.VexRiscv.IBusCachedPlugin_cache.io_cpu_decode_isValid
[color] 6
TOP.VexRiscv.IBusCachedPlugin_cache.io_cpu_decode_cacheMiss
[color] 6
TOP.VexRiscv.IBusCachedPlugin_cache.io_cpu_decode_error
[color] 6
TOP.VexRiscv.IBusCachedPlugin_cache.io_cpu_decode_illegalAccess
[color] 6
TOP.VexRiscv.IBusCachedPlugin_cache.io_cpu_decode_isStuck
[color] 6
TOP.VexRiscv.IBusCachedPlugin_cache.io_cpu_decode_isUser
[color] 6
TOP.VexRiscv.IBusCachedPlugin_cache.io_cpu_decode_mmuMiss
@22
[color] 6
TOP.VexRiscv.IBusCachedPlugin_cache.io_cpu_decode_pc[31:0]
[pattern_trace] 1
[pattern_trace] 0

View file

@ -182,11 +182,13 @@ public:
double cyclesPerSecond = 10e6;
double allowedCycles = 0.0;
uint32_t bootPc = -1;
uint32_t iStall = 1,dStall = 1;
uint32_t iStall = STALL,dStall = STALL;
#ifdef TRACE
VerilatedVcdC* tfp;
#endif
uint32_t seed;
bool withInstructionReadCheck = true;
void setIStall(bool enable) { iStall = enable; }
void setDStall(bool enable) { dStall = enable; }
@ -199,6 +201,8 @@ public:
Workspace(string name){
//seed = VL_RANDOM_I(32)^VL_RANDOM_I(32)^0x1093472;
//srand48(seed);
// setIStall(false);
// setDStall(false);
staticMutex.lock();
@ -241,7 +245,7 @@ public:
virtual void iBusAccess(uint32_t addr, uint32_t *data, bool *error) {
if(addr % 4 != 0) {
cout << "Warning, unaligned IBusAccess : " << addr << endl;
//cout << "Warning, unaligned IBusAccess : " << addr << endl;
// fail();
}
*data = ( (mem[addr + 0] << 0)
@ -386,10 +390,22 @@ public:
#ifdef REF
if(bootPc != -1) top->VexRiscv->core->prefetch_pc = bootPc;
#else
if(bootPc != -1) top->VexRiscv->prefetch_PcManagerSimplePlugin_pcReg = bootPc;
if(bootPc != -1) {
#ifdef IBUS_SIMPLE
top->VexRiscv->IBusSimplePlugin_fetchPc_pcReg = bootPc;
#ifdef COMPRESSED
top->VexRiscv->IBusSimplePlugin_decodePc_pcReg = bootPc;
#endif
#else
top->VexRiscv->IBusCachedPlugin_fetchPc_pcReg = bootPc;
#ifdef COMPRESSED
top->VexRiscv->IBusCachedPlugin_decodePc_pcReg = bootPc;
#endif
#endif
}
#endif
bool failed = false;
try {
// run simulation for 100 clock periods
for (i = 16; i < timeout*2; i+=2) {
@ -431,19 +447,27 @@ public:
if(top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_valid == 1 && top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_address != 0){
regTraces <<
#ifdef TRACE_WITH_TIME
currentTime <<
#endif
" PC " << hex << setw(8) << top->VexRiscv->writeBack_PC << " : reg[" << dec << setw(2) << (uint32_t)top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_address << "] = " << hex << setw(8) << top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_data << endl;
}
if(top->VexRiscv->writeBack_arbitration_isFiring){
if(top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_valid == 1 && top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_address != 0){
regTraces <<
#ifdef TRACE_WITH_TIME
currentTime <<
#endif
" PC " << hex << setw(8) << top->VexRiscv->writeBack_PC << " : reg[" << dec << setw(2) << (uint32_t)top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_address << "] = " << hex << setw(8) << top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_data << endl;
} else {
regTraces <<
#ifdef TRACE_WITH_TIME
currentTime <<
#endif
" PC " << hex << setw(8) << top->VexRiscv->writeBack_PC << endl;
}
}
for(SimElement* simElement : simElements) simElement->preCycle();
dump(i + 1);
#ifndef COMPRESSED
if(withInstructionReadCheck){
if(top->VexRiscv->decode_arbitration_isValid && !top->VexRiscv->decode_arbitration_haltItself && !top->VexRiscv->decode_arbitration_flushAll){
uint32_t expectedData;
@ -452,6 +476,7 @@ public:
assertEq(top->VexRiscv->decode_INSTRUCTION,expectedData);
}
}
#endif
checks();
//top->eval();
@ -477,9 +502,10 @@ public:
staticMutex.unlock();
} catch (const std::exception& e) {
staticMutex.lock();
cout << "FAIL " << name << endl;
cout << "FAIL " << name << endl; //<< " seed : " << seed <<
cycles += instanceCycles;
staticMutex.unlock();
failed = true;
}
@ -489,6 +515,12 @@ public:
#ifdef TRACE
tfp->close();
#endif
#ifdef STOP_ON_ERROR
if(failed){
sleep(1);
exit(-1);
}
#endif
return this;
}
};
@ -498,9 +530,8 @@ public:
#ifdef IBUS_SIMPLE
class IBusSimple : public SimElement{
public:
uint32_t inst_next = VL_RANDOM_I(32);
bool error_next = false;
bool pending = false;
uint32_t pendings[256];
uint32_t rPtr = 0, wPtr = 0;
Workspace *ws;
VVexRiscv* top;
@ -511,26 +542,33 @@ public:
virtual void onReset(){
top->iBus_cmd_ready = 1;
top->iBus_rsp_ready = 1;
top->iBus_rsp_valid = 0;
}
virtual void preCycle(){
if (top->iBus_cmd_valid && top->iBus_cmd_ready && !pending) {
if (top->iBus_cmd_valid && top->iBus_cmd_ready) {
//assertEq(top->iBus_cmd_payload_pc & 3,0);
pending = true;
ws->iBusAccess(top->iBus_cmd_payload_pc,&inst_next,&error_next);
pendings[wPtr] = (top->iBus_cmd_payload_pc);
wPtr = (wPtr + 1) & 0xFF;
//ws->iBusAccess(top->iBus_cmd_payload_pc,&inst_next,&error_next);
}
}
//TODO doesn't catch when instruction removed ?
virtual void postCycle(){
top->iBus_rsp_ready = !pending;
if(pending && (!ws->iStall || VL_RANDOM_I(7) < 100)){
top->iBus_rsp_inst = inst_next;
pending = false;
top->iBus_rsp_ready = 1;
top->iBus_rsp_error = error_next;
top->iBus_rsp_valid = 0;
if(rPtr != wPtr && (!ws->iStall || VL_RANDOM_I(7) < 100)){
uint32_t inst_next;
bool error_next;
ws->iBusAccess(pendings[rPtr], &inst_next,&error_next);
rPtr = (rPtr + 1) & 0xFF;
top->iBus_rsp_payload_inst = inst_next;
top->iBus_rsp_valid = 1;
top->iBus_rsp_payload_error = error_next;
} else {
top->iBus_rsp_payload_inst = VL_RANDOM_I(32);
top->iBus_rsp_payload_error = VL_RANDOM_I(1);
}
if(ws->iStall) top->iBus_cmd_ready = VL_RANDOM_I(7) < 100 && !pending;
if(ws->iStall) top->iBus_cmd_ready = VL_RANDOM_I(7) < 100;
}
};
#endif
@ -1402,17 +1440,19 @@ public:
}
virtual void checks(){
if(top->VexRiscv->writeBack_INSTRUCTION == 0x00000073){
if(top->VexRiscv->writeBack_arbitration_isFiring && top->VexRiscv->writeBack_INSTRUCTION == 0x00000013){
uint32_t instruction;
bool error;
iBusAccess(top->VexRiscv->writeBack_PC, &instruction, &error);
Workspace::iBusAccess(top->VexRiscv->writeBack_PC, &instruction, &error);
//printf("%x => %x\n", top->VexRiscv->writeBack_PC, instruction );
if(instruction == 0x00000073){
uint32_t code = top->VexRiscv->RegFilePlugin_regFile[28];
if((code & 1) == 0){
uint32_t code2 = top->VexRiscv->RegFilePlugin_regFile[3];
if((code & 1) == 0 && (code2 & 1) == 0){
cout << "Wrong error code"<< endl;
fail();
}
if(code == 1){
if(code == 1 || code2 == 1){
pass();
}else{
cout << "Error code " << code/2 << endl;
@ -1425,6 +1465,7 @@ public:
virtual void iBusAccess(uint32_t addr, uint32_t *data, bool *error){
Workspace::iBusAccess(addr,data,error);
if(*data == 0x0ff0000f) *data = 0x00000013;
if(*data == 0x00000073) *data = 0x00000013;
}
};
#endif
@ -1513,9 +1554,10 @@ public:
uint32_t readCmd(uint32_t size, uint32_t address){
accessCmd(false, 2, address, VL_RANDOM_I(32));
if(recv(clientSocket, buffer, 4, 0) != 4){
printf("Should read 4 bytes");
fail();
int error;
if((error = recv(clientSocket, buffer, 4, 0)) != 4){
printf("Should read 4 bytes, had %d", error);
while(1);
}
return *((uint32_t*) buffer);
@ -1558,25 +1600,25 @@ public:
while((readCmd(2,debugAddress) & RISCV_SPINAL_FLAGS_HALT) == 0){usleep(100);}
if((readValue = readCmd(2,debugAddress + 4)) != 0x8000000C){
printf("wrong break PC %x\n",readValue);
printf("wrong breakA PC %x\n",readValue);
clientFail = true; return;
}
writeCmd(2, debugAddress + 4, 0x13 + (1 << 15)); //Read regfile
if((readValue = readCmd(2,debugAddress + 4)) != 10){
printf("wrong break PC %x\n",readValue);
printf("wrong breakB PC %x\n",readValue);
clientFail = true; return;
}
writeCmd(2, debugAddress + 4, 0x13 + (2 << 15)); //Read regfile
if((readValue = readCmd(2,debugAddress + 4)) != 20){
printf("wrong break PC %x\n",readValue);
printf("wrong breakC PC %x\n",readValue);
clientFail = true; return;
}
writeCmd(2, debugAddress + 4, 0x13 + (3 << 15)); //Read regfile
if((readValue = readCmd(2,debugAddress + 4)) != 30){
printf("wrong break PC %x\n",readValue);
printf("wrong breakD PC %x\n",readValue);
clientFail = true; return;
}
@ -1588,7 +1630,7 @@ public:
while((readCmd(2,debugAddress) & RISCV_SPINAL_FLAGS_HALT) == 0){usleep(100);}
if((readValue = readCmd(2,debugAddress + 4)) != 0x80000014){
printf("wrong break PC 2 %x\n",readValue);
printf("wrong breakE PC 3 %x\n",readValue);
clientFail = true; return;
}
@ -1609,7 +1651,7 @@ public:
while((readCmd(2,debugAddress) & RISCV_SPINAL_FLAGS_HALT) == 0){usleep(100);}
if((readValue = readCmd(2,debugAddress + 4)) != 0x80000024){
printf("wrong break PC 2 %x\n",readValue);
printf("wrong breakF PC 3 %x\n",readValue);
clientFail = true; return;
}
@ -1703,10 +1745,12 @@ string riscvTestDiv[] = {
};
string freeRtosTests[] = {
"AltBlock", "AltQTest", "AltPollQ", "blocktim", "countsem", "dead", "EventGroupsDemo", "flop", "integer", "QPeek",
"AltQTest", "AltBlock", "AltPollQ", "blocktim", "countsem", "dead", "EventGroupsDemo", "flop", "integer", "QPeek",
"QueueSet", "recmutex", "semtest", "TaskNotify", "BlockQ", "crhook", "dynamic",
"GenQTest", "PollQ", "QueueOverwrite", "QueueSetPolling", "sp_flop", "test1"
//"flop", "sp_flop" // <- Simple test
//"BlockQ","BlockQ","BlockQ","BlockQ","BlockQ","BlockQ","BlockQ","BlockQ"
// "flop"
// "flop", "sp_flop" // <- Simple test
// "AltBlckQ" ???
};
@ -1761,6 +1805,9 @@ static void multiThreadedExecute(queue<std::function<void()>> &lambdas){
int main(int argc, char **argv, char **env) {
#ifdef SEED
srand48(SEED);
#endif
Verilated::randReset(2);
Verilated::commandArgs(argc, argv);
@ -1798,6 +1845,7 @@ int main(int argc, char **argv, char **env) {
for(const string &name : riscvTestMemory){
redo(REDO,RiscvTest(name).run();)
}
#ifdef MUL
for(const string &name : riscvTestMul){
redo(REDO,RiscvTest(name).run();)
@ -1809,10 +1857,20 @@ int main(int argc, char **argv, char **env) {
}
#endif
#ifdef COMPRESSED
redo(REDO,RiscvTest("rv32uc-p-rvc").bootAt(0x800000FCu)->run());
#endif
#ifdef CSR
uint32_t machineCsrRef[] = {1,11, 2,0x80000003u, 3,0x80000007u, 4,0x8000000bu, 5,6,7,0x80000007u ,
8,6,9,6,10,4,11,4, 12,13,0, 14,2, 15,5,16,17,1 };
redo(REDO,TestX28("machineCsr",machineCsrRef, sizeof(machineCsrRef)/4).noInstructionReadCheck()->run(10e4);)
#ifndef COMPRESSED
uint32_t machineCsrRef[] = {1,11, 2,0x80000003u, 3,0x80000007u, 4,0x8000000bu, 5,6,7,0x80000007u ,
8,6,9,6,10,4,11,4, 12,13,2, 14,2, 15,5,16,17,1 };
redo(REDO,TestX28("machineCsr",machineCsrRef, sizeof(machineCsrRef)/4).noInstructionReadCheck()->run(10e4);)
#else
uint32_t machineCsrRef[] = {1,11, 2,0x80000003u, 3,0x80000007u, 4,0x8000000bu, 5,6,7,0x80000007u ,
8,6,9,6,10,4,11,4, 12,13, 14,2, 15,5,16,17,1 };
redo(REDO,TestX28("machineCsrCompressed",machineCsrRef, sizeof(machineCsrRef)/4).noInstructionReadCheck()->run(10e4);)
#endif
#endif
#ifdef MMU
uint32_t mmuRef[] = {1,2,3, 0x11111111, 0x11111111, 0x11111111, 0x22222222, 0x22222222, 0x22222222, 4, 0x11111111, 0x33333333, 0x33333333, 5,
@ -1842,30 +1900,60 @@ int main(int argc, char **argv, char **env) {
#ifdef DHRYSTONE
Dhrystone("dhrystoneO3_Stall","dhrystoneO3",true,true).run(1.5e6);
#if defined(COMPRESSED)
Dhrystone("dhrystoneO3C_Stall","dhrystoneO3C",true,true).run(1.5e6);
#endif
#if defined(MUL) && defined(DIV)
Dhrystone("dhrystoneO3M_Stall","dhrystoneO3M",true,true).run(1.9e6);
#if defined(COMPRESSED)
Dhrystone("dhrystoneO3MC_Stall","dhrystoneO3MC",true,true).run(1.9e6);
#endif
#endif
Dhrystone("dhrystoneO3","dhrystoneO3",false,false).run(1.9e6);
#if defined(COMPRESSED)
Dhrystone("dhrystoneO3C","dhrystoneO3C",false,false).run(1.9e6);
#endif
#if defined(MUL) && defined(DIV)
Dhrystone("dhrystoneO3M","dhrystoneO3M",false,false).run(1.9e6);
#if defined(COMPRESSED)
Dhrystone("dhrystoneO3MC","dhrystoneO3MC",false,false).run(1.9e6);
#endif
#endif
#endif
#ifdef FREERTOS
#ifdef SEED
srand48(SEED);
#endif
//redo(1,Workspace("freeRTOS_demo").loadHex("../../resources/hex/freeRTOS_demo.hex")->bootAt(0x80000000u)->run(100e6);)
queue<std::function<void()>> tasks;
vector <std::function<void()>> tasks;
for(const string &name : freeRtosTests){
tasks.push([=]() { Workspace(name + "_rv32i_O0").loadHex("../../resources/freertos/" + name + "_rv32i_O0.hex")->bootAt(0x80000000u)->run(4e6*15);});
tasks.push([=]() { Workspace(name + "_rv32i_O3").loadHex("../../resources/freertos/" + name + "_rv32i_O3.hex")->bootAt(0x80000000u)->run(4e6*15);});
#if defined(MUL) && defined(DIV)
tasks.push([=]() { Workspace(name + "_rv32im_O0").loadHex("../../resources/freertos/" + name + "_rv32im_O0.hex")->bootAt(0x80000000u)->run(4e6*15);});
tasks.push([=]() { Workspace(name + "_rv32im_O3").loadHex("../../resources/freertos/" + name + "_rv32im_O3.hex")->bootAt(0x80000000u)->run(4e6*15);});
#endif
/*for(int redo = 0;redo < 4;redo++)*/{
for(const string &name : freeRtosTests){
tasks.push_back([=]() { Workspace(name + "_rv32i_O0").loadHex("../../resources/freertos/" + name + "_rv32i_O0.hex")->bootAt(0x80000000u)->run(4e6*15);});
tasks.push_back([=]() { Workspace(name + "_rv32i_O3").loadHex("../../resources/freertos/" + name + "_rv32i_O3.hex")->bootAt(0x80000000u)->run(4e6*15);});
#ifdef COMPRESSED
tasks.push_back([=]() { Workspace(name + "_rv32ic_O0").loadHex("../../resources/freertos/" + name + "_rv32ic_O0.hex")->bootAt(0x80000000u)->run(4e6*15);});
tasks.push_back([=]() { Workspace(name + "_rv32ic_O3").loadHex("../../resources/freertos/" + name + "_rv32ic_O3.hex")->bootAt(0x80000000u)->run(4e6*15);});
#endif
#if defined(MUL) && defined(DIV)
#ifdef COMPRESSED
tasks.push_back([=]() { Workspace(name + "_rv32imac_O3").loadHex("../../resources/freertos/" + name + "_rv32imac_O3.hex")->bootAt(0x80000000u)->run(4e6*15);});
#else
tasks.push_back([=]() { Workspace(name + "_rv32im_O3").loadHex("../../resources/freertos/" + name + "_rv32im_O3.hex")->bootAt(0x80000000u)->run(4e6*15);});
#endif
#endif
}
}
multiThreadedExecute(tasks);
while(tasks.size() > FREERTOS_COUNT){
tasks.erase(tasks.begin() + (VL_RANDOM_I(32)%tasks.size()));
}
queue <std::function<void()>> tasksSelected(std::deque<std::function<void()>>(tasks.begin(), tasks.end()));
multiThreadedExecute(tasksSelected);
#endif
}

View file

@ -8,7 +8,9 @@ MUL?=yes
DIV?=yes
CSR?=yes
MMU?=yes
SEED?=no
ATOMIC?=no
NO_STALL?=no
DEBUG_PLUGIN?=STD
DEBUG_PLUGIN_EXTERNAL?=no
CUSTOM_SIMD_ADD?=no
@ -21,6 +23,8 @@ TRACE_WITH_TIME=no
REF_TIME=no
THREAD_COUNT?=4
MTIME_INSTR_FACTOR?=no
COMPRESSED?=no
STOP_ON_ERROR?=no
ADDCFLAGS += -CFLAGS -DIBUS_${IBUS}
@ -30,14 +34,34 @@ ADDCFLAGS += -CFLAGS -pthread
ADDCFLAGS += -CFLAGS -DTHREAD_COUNT=${THREAD_COUNT}
ifeq ($(COMPRESSED),yes)
ADDCFLAGS += -CFLAGS -DCOMPRESSED
endif
ifeq ($(DHRYSTONE),yes)
ADDCFLAGS += -CFLAGS -DDHRYSTONE
endif
ifeq ($(STOP_ON_ERROR),yes)
ADDCFLAGS += -CFLAGS -DSTOP_ON_ERROR
endif
ifeq ($(NO_STALL),yes)
ADDCFLAGS += -CFLAGS -DSTALL=0
else
ADDCFLAGS += -CFLAGS -DSTALL=1
endif
ifneq ($(MTIME_INSTR_FACTOR),no)
ADDCFLAGS += -CFLAGS -DMTIME_INSTR_FACTOR=${MTIME_INSTR_FACTOR}
endif
ifneq ($(SEED),no)
ADDCFLAGS += -CFLAGS -DSEED=${SEED}
endif
ifeq ($(TRACE),yes)
VERILATOR_ARGS += --trace
ADDCFLAGS += -CFLAGS -DTRACE
@ -104,6 +128,12 @@ endif
ADDCFLAGS += -CFLAGS -DTRACE_START=${TRACE_START}
ifeq ($(FREERTOS),yes)
ADDCFLAGS += -CFLAGS -DFREERTOS
ADDCFLAGS += -CFLAGS -DFREERTOS_COUNT=99999
else
ifneq ($(FREERTOS),no)
ADDCFLAGS += -CFLAGS -DFREERTOS
ADDCFLAGS += -CFLAGS -DFREERTOS_COUNT=$(FREERTOS)
endif
endif
all: clean run
@ -117,7 +147,7 @@ verilate: ../../../../VexRiscv.v
verilator -cc ../../../../VexRiscv.v -O3 -CFLAGS -std=c++11 -LDFLAGS -pthread ${ADDCFLAGS} --gdbbt ${VERILATOR_ARGS} -Wno-UNOPTFLAT -Wno-WIDTH --x-assign unique --exe main.cpp
compile: verilate
make -j -C obj_dir/ -f VVexRiscv.mk VVexRiscv
make -j${THREAD_COUNT} -C obj_dir/ -f VVexRiscv.mk VVexRiscv
clean:
rm -rf obj_dir

2
src/test/python/gcloud/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
/gcloud.pyc
*.tar.gz

View file

@ -0,0 +1,54 @@
#!/usr/bin/env python
from os import system
from sys import argv
import time
class GCInstance:
def __init__(self, name):
self.instance = name
self.project = "ivory-infusion-209508"
self.zone = "europe-west1-b"
def local(self, cmd):
print(cmd)
system(cmd)
def createCustom(self, cores=1, ram=1024):
self.create("custom-{}-{}".format(cores,ram))
#n1-highcpu-8
def create(self, machine="f1-micro", args = "--preemptible"):
self.delete()
self.local('gcloud beta compute --project=ivory-infusion-209508 instances create {} --zone=europe-west1-b --machine-type={} --subnet=default --network-tier=PREMIUM --no-restart-on-failure --maintenance-policy=TERMINATE {} --service-account=470010940365-compute@developer.gserviceaccount.com --scopes=https://www.googleapis.com/auth/devstorage.read_only,https://www.googleapis.com/auth/logging.write,https://www.googleapis.com/auth/monitoring.write,https://www.googleapis.com/auth/servicecontrol,https://www.googleapis.com/auth/service.management.readonly,https://www.googleapis.com/auth/trace.append --disk=name=miaou,device-name=miaou,mode=rw,boot=yes'.format(self.instance, machine, args))
def stopScript(self, script):
self.local('gcloud compute --project {} instances add-metadata {} --metadata-from-file shutdown-script={} --zone "{}"'.format(self.project, self.instance, script, self.zone))
def start(self):
self.local('gcloud compute --project "{}" instances start --zone "{}" "{}"'.format(self.project, self.zone, self.instance)) # --machine-type=f1-micro
time.sleep(60)
def stopHours(self, hours):
self.remote('sudo shutdown -P +{}'.format(int(hours*60)))
def stop(self):
self.remote('sudo shutdown -P now')
def delete(self):
self.local('gcloud compute --project "{}" instances delete "{}" --zone "{}" --keep-disks all --quiet'.format(self.project, self.instance, self.zone))
def remote(self, cmd):
self.local('gcloud compute --project "{}" ssh --zone "{}" "{}" -- "{}"'.format(self.project, self.zone, self.instance, cmd))
def localToRemote(self, source, target):
self.remote("rm -rf {}".format(target))
self.local('gcloud compute --project "{}" scp --zone "{}" {} {}:{}'.format(self.project, self.zone, source, self.instance, target))
def remoteToLocal(self, source, target):
self.remote("rm -rf {}".format(target))
self.local('gcloud compute --project "{}" scp --zone "{}" {}:{} {}'.format(self.project, self.zone, self.instance, source, target))
#setsid nohup (sbt test;sudo poweroff) &> sbtTest.txt

View file

View file

@ -0,0 +1,10 @@
#!/usr/bin/env python
from gcloud import GCInstance
gci = GCInstance("vexriscv")
gci.create()
gci.start()
gci.remoteToLocal("run.txt","run.txt")
gci.stop()
gci.delete()

View file

@ -0,0 +1,19 @@
#!/usr/bin/env python
from os import system
from sys import argv
from gcloud import GCInstance
gci = GCInstance("vexriscv")
gci.create("n1-highcpu-8")
gci.start()
gci.stopHours(20)
gci.stopScript("src/test/python/gcloud/stopScript.sh")
gci.local("rm -rf archive.tar.gz; git ls-files -z | xargs -0 tar -czf archive.tar.gz")
gci.localToRemote("archive.tar.gz", "")
gci.localToRemote("src/test/python/gcloud/run.sh", "")
gci.remote("rm -rf run.txt; setsid nohup sh run.sh &> run.txt")
#setsid nohup (sbt test;sudo poweroff) &> sbtTest.txt

View file

@ -0,0 +1,18 @@
rm -rf sbtTest.txt
rm -rf VexRiscv
mkdir VexRiscv
tar -xzf archive.tar.gz -C VexRiscv
cd VexRiscv
export VEXRISCV_REGRESSION_CONFIG_COUNT=16
export VEXRISCV_REGRESSION_FREERTOS_COUNT=yes
sbt test
cd ..
#sudo apt-get install mailutils + https://cloud.google.com/compute/docs/tutorials/sending-mail/using-mailgun
echo "Miaou" | mail -s "VexRiscv cloud" charles.papon.90@gmail.com -A run.txt
sleep 15
sudo shutdown -P now

View file

@ -0,0 +1,4 @@
#! /bin/bash
echo "preempted :(" | mail -s "VexRiscv cloud" charles.papon.90@gmail.com -A /home/spinalvm/run.txt
sleep 10

27
src/test/python/gcloud/try.py Executable file
View file

@ -0,0 +1,27 @@
#!/usr/bin/env python
from os import system
from sys import argv
project = "ivory-infusion-209508"
zone = "europe-west1-b"
instance = "miaou"
def local(cmd):
print(cmd)
system(cmd)
def remote(cmd):
cmd = 'gcloud compute --project "{}" ssh --zone "{}" "{}" -- "{}"'.format(project, zone, instance, cmd)
print(cmd)
system(cmd)
def localToRemote(source, target):
remote("rm -rf target")
cmd = 'gcloud compute --project "{}" scp --zone "{}" {} {}:{}'.format(project, zone, source, instance, target)
print(cmd)
system(cmd)
#local("sbt test &")
local("python -c 'from os import system; system(\"(sbt test >> sbtTest.txt) &\")'")
#python -c 'from os import system; system("sbt test")' &

1
src/test/python/tool/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/disasm.s

View file

@ -0,0 +1 @@
.word 0x28488b3

View file

@ -0,0 +1,11 @@
#!/usr/bin/env python3
from os import system
from sys import argv
with open("disasm.s", "w") as f:
instr = int(argv[1], 16)
print(".word 0x%04x" % (instr), file=f)
system("riscv64-unknown-elf-gcc -c disasm.s")
system("riscv64-unknown-elf-objdump -d -M numeric,no-aliases disasm.o")

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,323 @@
build/machineCsr.elf: file format elf32-littleriscv
Disassembly of section .yolo:
80000000 <trap_entry-0x20>:
j _start
80000000: 0900006f j 80000090 <_start>
nop
80000004: 00000013 nop
nop
80000008: 00000013 nop
nop
8000000c: 00000013 nop
nop
80000010: 00000013 nop
nop
80000014: 00000013 nop
nop
80000018: 00000013 nop
nop
8000001c: 00000013 nop
80000020 <trap_entry>:
.global trap_entry
trap_entry:
csrr x28, mcause
80000020: 34202e73 csrr t3,mcause
bnez x28, notICmdAlignementException
80000024: 000e1e63 bnez t3,80000040 <notICmdAlignementException>
li x30, 0xFFFFFFFC
80000028: ffc00f13 li t5,-4
csrr x29, mepc
8000002c: 34102ef3 csrr t4,mepc
and x29,x29,x30
80000030: 01eefeb3 and t4,t4,t5
addi x29, x29, 4
80000034: 004e8e93 addi t4,t4,4
csrw mepc, x29
80000038: 341e9073 csrw mepc,t4
j mepcFixed
8000003c: 01c0006f j 80000058 <mepcFixed>
80000040 <notICmdAlignementException>:
notICmdAlignementException:
li x29, 0x80000000
80000040: 80000eb7 lui t4,0x80000
and x30, x28, x29
80000044: 01de7f33 and t5,t3,t4
bnez x30, mepcFixed
80000048: 000f1863 bnez t5,80000058 <mepcFixed>
csrr x29, mepc
8000004c: 34102ef3 csrr t4,mepc
addi x29, x29, 4
80000050: 004e8e93 addi t4,t4,4 # 80000004 <_etext+0xfffffdf8>
csrw mepc, x29
80000054: 341e9073 csrw mepc,t4
80000058 <mepcFixed>:
mepcFixed:
li x29, 0x80000003u
80000058: 80000eb7 lui t4,0x80000
8000005c: 003e8e93 addi t4,t4,3 # 80000003 <_etext+0xfffffdf7>
bne x29, x28, noSoftwareInterrupt
80000060: 01ce9663 bne t4,t3,8000006c <noSoftwareInterrupt>
li x29, 0x008
80000064: 00800e93 li t4,8
csrc mip, x29
80000068: 344eb073 csrc mip,t4
8000006c <noSoftwareInterrupt>:
noSoftwareInterrupt:
li x29, 0x80000007u
8000006c: 80000eb7 lui t4,0x80000
80000070: 007e8e93 addi t4,t4,7 # 80000007 <_etext+0xfffffdfb>
bne x29, x28, noTimerInterrupt
80000074: 01ce9463 bne t4,t3,8000007c <noTimerInterrupt>
csrw mie, 0
80000078: 30405073 csrwi mie,0
8000007c <noTimerInterrupt>:
noTimerInterrupt:
li x29, 0x8000000bu
8000007c: 80000eb7 lui t4,0x80000
80000080: 00be8e93 addi t4,t4,11 # 8000000b <_etext+0xfffffdff>
bne x29, x28, noExernalInterrupt
80000084: 01ce9463 bne t4,t3,8000008c <noExernalInterrupt>
csrw mie, 0
80000088: 30405073 csrwi mie,0
8000008c <noExernalInterrupt>:
noExernalInterrupt:
mret
8000008c: 30200073 mret
80000090 <_start>:
.text
.globl _start
_start:
li x28, 1
80000090: 00100e13 li t3,1
scall
80000094: 00000073 ecall
li x28, 2
80000098: 00200e13 li t3,2
li t0, 0x008
8000009c: 00800293 li t0,8
csrs mstatus,t0
800000a0: 3002a073 csrs mstatus,t0
li t0, 0x008
800000a4: 00800293 li t0,8
csrw mie,t0
800000a8: 30429073 csrw mie,t0
li t0, 0x008
800000ac: 00800293 li t0,8
csrs mip,t0
800000b0: 3442a073 csrs mip,t0
nop
800000b4: 00000013 nop
nop
800000b8: 00000013 nop
nop
800000bc: 00000013 nop
nop
800000c0: 00000013 nop
nop
800000c4: 00000013 nop
nop
800000c8: 00000013 nop
nop
800000cc: 00000013 nop
nop
800000d0: 00000013 nop
nop
800000d4: 00000013 nop
nop
800000d8: 00000013 nop
nop
800000dc: 00000013 nop
nop
800000e0: 00000013 nop
li x28, 3
800000e4: 00300e13 li t3,3
li t0, 0x080
800000e8: 08000293 li t0,128
csrw mie,t0
800000ec: 30429073 csrw mie,t0
nop
800000f0: 00000013 nop
nop
800000f4: 00000013 nop
nop
800000f8: 00000013 nop
nop
800000fc: 00000013 nop
nop
80000100: 00000013 nop
nop
80000104: 00000013 nop
nop
80000108: 00000013 nop
li x28, 4
8000010c: 00400e13 li t3,4
li t0, 0x800
80000110: 000012b7 lui t0,0x1
80000114: 80028293 addi t0,t0,-2048 # 800 <_stack_size>
csrw mie,t0
80000118: 30429073 csrw mie,t0
nop
8000011c: 00000013 nop
nop
80000120: 00000013 nop
nop
80000124: 00000013 nop
nop
80000128: 00000013 nop
nop
8000012c: 00000013 nop
nop
80000130: 00000013 nop
nop
80000134: 00000013 nop
li x28, 5
80000138: 00500e13 li t3,5
li x3, 0xF00FFF40
8000013c: f01001b7 lui gp,0xf0100
80000140: f4018193 addi gp,gp,-192 # f00fff40 <_etext+0x700ffd34>
lw x4, 0(x3)
80000144: 0001a203 lw tp,0(gp)
lw x5, 4(x3)
80000148: 0041a283 lw t0,4(gp)
addi x4, x4, 1023
8000014c: 3ff20213 addi tp,tp,1023 # 3ff <_stack_size-0x401>
sw x4, 8(x3)
80000150: 0041a423 sw tp,8(gp)
sw x5, 12(x3)
80000154: 0051a623 sw t0,12(gp)
li x28, 6
80000158: 00600e13 li t3,6
li x4, 0x080
8000015c: 08000213 li tp,128
csrw mie,x4
80000160: 30421073 csrw mie,tp
li x28, 7
80000164: 00700e13 li t3,7
wfi
80000168: 10500073 wfi
li x28, 8
8000016c: 00800e13 li t3,8
li x3, 1
80000170: 00100193 li gp,1
sw x4,0(x3)
80000174: 0041a023 sw tp,0(gp)
li x28, 9
80000178: 00900e13 li t3,9
sh x4,0(x3)
8000017c: 00419023 sh tp,0(gp)
li x28, 10
80000180: 00a00e13 li t3,10
lw x4,0(x3)
80000184: 0001a203 lw tp,0(gp)
li x28, 11
80000188: 00b00e13 li t3,11
lh x4,0(x3)
8000018c: 00019203 lh tp,0(gp)
li x28, 12
80000190: 00c00e13 li t3,12
li x28, 13
80000194: 00d00e13 li t3,13
lw x1,0(x0)
80000198: 00002083 lw ra,0(zero) # 0 <_stack_size-0x800>
//unalignedPcA:
//j unalignedPcA+2
//lw x1,0(x0)
li x28, 14
8000019c: 00e00e13 li t3,14
hret
800001a0: 20200073 hret
li x28, 15
800001a4: 00f00e13 li t3,15
li x1, 0xF00FFF60
800001a8: f01000b7 lui ra,0xf0100
800001ac: f6008093 addi ra,ra,-160 # f00fff60 <_etext+0x700ffd54>
lw x2, 0(x1)
800001b0: 0000a103 lw sp,0(ra)
li x28, 16
800001b4: 01000e13 li t3,16
sw x2, 0(x1)
800001b8: 0020a023 sw sp,0(ra)
li x28, 17
800001bc: 01100e13 li t3,17
jr x1
800001c0: 00008067 ret
Disassembly of section .text:
800001c4 <irqCpp>:
}
void irqCpp(int irq){
}
800001c4: 00008067 ret
800001c8 <main>:
}
800001c8: 00000513 li a0,0
800001cc: 00008067 ret
800001d0: 0010 0x10
800001d2: 0000 unimp
800001d4: 0000 unimp
800001d6: 0000 unimp
800001d8: 7a01 lui s4,0xfffe0
800001da: 0052 c.slli zero,0x14
800001dc: 7c01 lui s8,0xfffe0
800001de: 0101 addi sp,sp,0
800001e0: 00020d1b 0x20d1b
800001e4: 0010 0x10
800001e6: 0000 unimp
800001e8: 0018 0x18
800001ea: 0000 unimp
800001ec: ffdc fsw fa5,60(a5)
800001ee: ffff 0xffff
800001f0: 0008 0x8
800001f2: 0000 unimp
800001f4: 0000 unimp
800001f6: 0000 unimp
800001f8: 0010 0x10
800001fa: 0000 unimp
800001fc: 002c addi a1,sp,8
800001fe: 0000 unimp
80000200: ffc4 fsw fs1,60(a5)
80000202: ffff 0xffff
80000204: 0004 0x4
80000206: 0000 unimp
80000208: 0000 unimp
...

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more