mirror of
https://github.com/SpinalHDL/VexRiscv.git
synced 2025-04-24 14:07:54 -04:00
Merge remote-tracking branch 'origin/reworkFetcher'
This commit is contained in:
commit
f8c8643aa5
251 changed files with 226887 additions and 156498 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -45,3 +45,4 @@ obj_dir
|
|||
|
||||
simWorkspace/
|
||||
tmp/
|
||||
/archive.tar.gz
|
||||
|
|
30
.travis.yml
30
.travis.yml
|
@ -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:
|
||||
|
|
83
README.md
83
README.md
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
58
src/main/scala/spinal/lib/misc/HexTools.scala
Normal file
58
src/main/scala/spinal/lib/misc/HexTools.scala
Normal 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)
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ..)
|
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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")
|
||||
)
|
||||
|
|
|
@ -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")
|
||||
)
|
||||
|
|
|
@ -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")
|
||||
)
|
||||
|
|
|
@ -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")
|
||||
)
|
||||
|
|
|
@ -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")
|
||||
)
|
||||
|
|
|
@ -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")
|
||||
)
|
||||
|
|
|
@ -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")
|
||||
)
|
||||
|
|
|
@ -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")
|
||||
)
|
||||
|
|
|
@ -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")
|
||||
)
|
||||
|
|
|
@ -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")
|
||||
)
|
||||
|
|
|
@ -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")
|
||||
)
|
||||
|
|
|
@ -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")
|
||||
)
|
||||
|
|
|
@ -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")
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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/")
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
609
src/main/scala/vexriscv/plugin/Fetcher.scala
Normal file
609
src/main/scala/vexriscv/plugin/Fetcher.scala
Normal 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
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
198
src/main/scala/vexriscv/plugin/Misc.scala
Normal file
198
src/main/scala/vexriscv/plugin/Misc.scala
Normal 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
|
||||
//
|
||||
//
|
||||
//}
|
|
@ -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
|
||||
// }
|
||||
// }
|
||||
//}
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
2
src/test/cpp/regression/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
*.regTraceRef
|
||||
/freertos.gtkw
|
57
src/test/cpp/regression/dhrystoneO3C.logRef
Normal file
57
src/test/cpp/regression/dhrystoneO3C.logRef
Normal 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
|
57
src/test/cpp/regression/dhrystoneO3MC.logRef
Normal file
57
src/test/cpp/regression/dhrystoneO3MC.logRef
Normal 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
|
67
src/test/cpp/regression/icache.gtkw
Normal file
67
src/test/cpp/regression/icache.gtkw
Normal 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
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
2
src/test/python/gcloud/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/gcloud.pyc
|
||||
*.tar.gz
|
54
src/test/python/gcloud/gcloud.py
Normal file
54
src/test/python/gcloud/gcloud.py
Normal 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
|
0
src/test/python/gcloud/makefile
Normal file
0
src/test/python/gcloud/makefile
Normal file
10
src/test/python/gcloud/remotePull.py
Executable file
10
src/test/python/gcloud/remotePull.py
Executable 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()
|
19
src/test/python/gcloud/remoteTest.py
Executable file
19
src/test/python/gcloud/remoteTest.py
Executable 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
|
18
src/test/python/gcloud/run.sh
Normal file
18
src/test/python/gcloud/run.sh
Normal 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
|
||||
|
||||
|
4
src/test/python/gcloud/stopScript.sh
Executable file
4
src/test/python/gcloud/stopScript.sh
Executable 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
27
src/test/python/gcloud/try.py
Executable 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
1
src/test/python/tool/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/disasm.s
|
1
src/test/python/tool/disasm.s
Normal file
1
src/test/python/tool/disasm.s
Normal file
|
@ -0,0 +1 @@
|
|||
.word 0x28488b3
|
11
src/test/python/tool/hexToAsm.py
Executable file
11
src/test/python/tool/hexToAsm.py
Executable 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
3836
src/test/resources/asm/dhrystoneO3C.asm
Normal file
3836
src/test/resources/asm/dhrystoneO3C.asm
Normal file
File diff suppressed because it is too large
Load diff
3554
src/test/resources/asm/dhrystoneO3MC.asm
Normal file
3554
src/test/resources/asm/dhrystoneO3MC.asm
Normal file
File diff suppressed because it is too large
Load diff
323
src/test/resources/asm/machineCsrCompressed.asm
Normal file
323
src/test/resources/asm/machineCsrCompressed.asm
Normal 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
|
||||
...
|
4904
src/test/resources/asm/rv32uc-p-rvc.dump
Normal file
4904
src/test/resources/asm/rv32uc-p-rvc.dump
Normal file
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
1528
src/test/resources/freertos/AltBlckQ_rv32ic_O0.hex
Normal file
1528
src/test/resources/freertos/AltBlckQ_rv32ic_O0.hex
Normal file
File diff suppressed because it is too large
Load diff
1740
src/test/resources/freertos/AltBlckQ_rv32ic_O3.hex
Normal file
1740
src/test/resources/freertos/AltBlckQ_rv32ic_O3.hex
Normal file
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
1616
src/test/resources/freertos/AltBlckQ_rv32imac_O3.hex
Normal file
1616
src/test/resources/freertos/AltBlckQ_rv32imac_O3.hex
Normal file
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
1572
src/test/resources/freertos/AltBlock_rv32ic_O0.hex
Normal file
1572
src/test/resources/freertos/AltBlock_rv32ic_O0.hex
Normal file
File diff suppressed because it is too large
Load diff
1762
src/test/resources/freertos/AltBlock_rv32ic_O3.hex
Normal file
1762
src/test/resources/freertos/AltBlock_rv32ic_O3.hex
Normal file
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
1638
src/test/resources/freertos/AltBlock_rv32imac_O3.hex
Normal file
1638
src/test/resources/freertos/AltBlock_rv32imac_O3.hex
Normal file
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
1499
src/test/resources/freertos/AltPollQ_rv32ic_O0.hex
Normal file
1499
src/test/resources/freertos/AltPollQ_rv32ic_O0.hex
Normal file
File diff suppressed because it is too large
Load diff
1711
src/test/resources/freertos/AltPollQ_rv32ic_O3.hex
Normal file
1711
src/test/resources/freertos/AltPollQ_rv32ic_O3.hex
Normal file
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
1587
src/test/resources/freertos/AltPollQ_rv32imac_O3.hex
Normal file
1587
src/test/resources/freertos/AltPollQ_rv32imac_O3.hex
Normal file
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
1581
src/test/resources/freertos/AltQTest_rv32ic_O0.hex
Normal file
1581
src/test/resources/freertos/AltQTest_rv32ic_O0.hex
Normal file
File diff suppressed because it is too large
Load diff
1784
src/test/resources/freertos/AltQTest_rv32ic_O3.hex
Normal file
1784
src/test/resources/freertos/AltQTest_rv32ic_O3.hex
Normal file
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
Loading…
Add table
Add a link
Reference in a new issue