SpinalHDL 1.4.0

Merge branch 'dev'
This commit is contained in:
Dolu1990 2020-03-09 13:49:06 +01:00
commit 95237b23ea
29 changed files with 1752 additions and 1122 deletions

128
README.md
View File

@ -65,55 +65,54 @@ dhrystone binaries which fit inside a 4KB I$ and 4KB D$ (I already had this case
The CPU configurations used below can be found in the `src/scala/vexriscv/demo` directory.
```
VexRiscv smallest (RV32I, 0.52 DMIPS/Mhz, no datapath bypass, no interrupt) ->
Artix 7 -> 233 Mhz 494 LUT 505 FF
Cyclone V -> 193 Mhz 347 ALMs
Cyclone IV -> 179 Mhz 730 LUT 494 FF
VexRiscv small (RV32I, 0.52 DMIPS/Mhz, no datapath bypass, no interrupt) ->
Artix 7 -> 243 Mhz 504 LUT 505 FF
Cyclone V -> 174 Mhz 352 ALMs
Cyclone IV -> 179 Mhz 731 LUT 494 FF
iCE40 -> 92 Mhz 1130 LC
VexRiscv smallest (RV32I, 0.52 DMIPS/Mhz, no datapath bypass) ->
Artix 7 -> 232 Mhz 538 LUT 562 FF
Cyclone V -> 189 Mhz 387 ALMs
Cyclone IV -> 175 Mhz 829 LUT 550 FF
VexRiscv small (RV32I, 0.52 DMIPS/Mhz, no datapath bypass) ->
Artix 7 -> 240 Mhz 556 LUT 566 FF
Cyclone V -> 194 Mhz 394 ALMs
Cyclone IV -> 174 Mhz 831 LUT 555 FF
iCE40 -> 85 Mhz 1292 LC
VexRiscv small and productive (RV32I, 0.82 DMIPS/Mhz) ->
Artix 7 -> 226 Mhz 689 LUT 531 FF
Cyclone V -> 145 Mhz 499 ALMs
Cyclone IV -> 150 Mhz 1,111 LUT 525 FF
Artix 7 -> 232 Mhz 816 LUT 534 FF
Cyclone V -> 155 Mhz 492 ALMs
Cyclone IV -> 155 Mhz 1,111 LUT 530 FF
iCE40 -> 63 Mhz 1596 LC
VexRiscv small and productive with I$ (RV32I, 0.70 DMIPS/Mhz, 4KB-I$) ->
Artix 7 -> 230 Mhz 734 LUT 564 FF
Cyclone V -> 145 Mhz 511 ALMs
Cyclone IV -> 144 Mhz 1,145 LUT 531 FF
Artix 7 -> 220 Mhz 730 LUT 570 FF
Cyclone V -> 142 Mhz 501 ALMs
Cyclone IV -> 150 Mhz 1,139 LUT 536 FF
iCE40 -> 66 Mhz 1680 LC
VexRiscv full no cache (RV32IM, 1.21 DMIPS/Mhz 2.30 Coremark/Mhz, single cycle barrel shifter, debug module, catch exceptions, static branch) ->
Artix 7 -> 219 Mhz 1537 LUT 977 FF
Cyclone V -> 139 Mhz 958 ALMs
Cyclone IV -> 135 Mhz 2,011 LUT 968 FF
Artix 7 -> 216 Mhz 1418 LUT 949 FF
Cyclone V -> 133 Mhz 933 ALMs
Cyclone IV -> 143 Mhz 2,076 LUT 972 FF
VexRiscv full (RV32IM, 1.21 DMIPS/Mhz 2.30 Coremark/Mhz with cache trashing, 4KB-I$,4KB-D$, single cycle barrel shifter, debug module, catch exceptions, static branch) ->
Artix 7 -> 193 Mhz 1706 LUT 1172 FF
Cyclone V -> 144 Mhz 1,128 ALMs
Cyclone IV -> 133 Mhz 2,298 LUT 1,096 FF
Artix 7 -> 199 Mhz 1840 LUT 1158 FF
Cyclone V -> 141 Mhz 1,166 ALMs
Cyclone IV -> 131 Mhz 2,407 LUT 1,067 FF
VexRiscv full max dmips/mhz -> (RV32IM, 1.44 DMIPS/Mhz 2.70 Coremark/Mhz,, 16KB-I$,16KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch prediction in the fetch stage, branch and shift operations done in the Execute stage) ->
Artix 7 -> 140 Mhz 1767 LUT 1128 FF
Cyclone V -> 90 Mhz 1,089 ALMs
Cyclone IV -> 79 Mhz 2,336 LUT 1,048 FF
VexRiscv full max perf (HZ*IPC) -> (RV32IM, 1.38 DMIPS/Mhz 2.57 Coremark/Mhz, 8KB-I$,8KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch prediction in the fetch stage, branch and shift operations done in the Execute stage) ->
Artix 7 -> 200 Mhz 1935 LUT 1216 FF
Cyclone V -> 130 Mhz 1,166 ALMs
Cyclone IV -> 126 Mhz 2,484 LUT 1,120 FF
VexRiscv full with MMU (RV32IM, 1.24 DMIPS/Mhz 2.35 Coremark/Mhz, with cache trashing, 4KB-I$, 4KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch, MMU) ->
Artix 7 -> 161 Mhz 1985 LUT 1585 FF
Cyclone V -> 124 Mhz 1,319 ALMs
Cyclone IV -> 122 Mhz 2,710 LUT 1,501 FF
Artix 7 -> 151 Mhz 2021 LUT 1541 FF
Cyclone V -> 124 Mhz 1,368 ALMs
Cyclone IV -> 128 Mhz 2,826 LUT 1,474 FF
VexRiscv linux balanced (RV32IMA, 1.21 DMIPS/Mhz 2.27 Coremark/Mhz, with cache trashing, 4KB-I$, 4KB-D$, single cycle barrel shifter, catch exceptions, static branch, MMU, Supervisor, Compatible with mainstream linux) ->
Artix 7 -> 170 Mhz 2530 LUT 2013 FF
Cyclone V -> 125 Mhz 1,618 ALMs
Cyclone IV -> 116 Mhz 3,314 LUT 2,016 FF
Artix 7 -> 180 Mhz 2883 LUT 2130 FF
Cyclone V -> 131 Mhz 1,764 ALMs
Cyclone IV -> 121 Mhz 3,608 LUT 2,082 FF
```
The following configuration results in 1.44 DMIPS/MHz:
@ -186,24 +185,47 @@ NOTES:
[![Build Status](https://travis-ci.org/SpinalHDL/VexRiscv.svg?branch=master)](https://travis-ci.org/SpinalHDL/VexRiscv)
To run tests (Verilator simulator is required), go in the `src/test/cpp/regression` folder and run:
To run tests (need java, scala, verilator), just do :
```sh
# To test the GenFull CPU
# (Don't worry about the CSR test not passing, basically the GenFull isn't the truly full version of the CPU, some CSR features are disabled in it)
make clean run
# To test the GenSmallest CPU
make clean run IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no
export VEXRISCV_REGRESSION_SEED=42
export VEXRISCV_REGRESSION_TEST_ID=
sbt "testOnly vexriscv.TestIndividualFeatures"
```
The self-test includes:
- ISA tests from https://github.com/riscv/riscv-tests/tree/master/isa
This will generate random VexRiscv configuration and test them with:
- ISA tests from https://github.com/riscv/riscv-tests/tree/master/isa and https://github.com/riscv/riscv-compliance
- Dhrystone benchmark
- 24 FreeRTOS tests
- Coremark benchmark
- Zephyr os
- Buildroot/Linux os
- Some handwritten tests to check the CSR, debug module and MMU plugins
You can enable FreeRTOS tests by adding `FREERTOS=yes` to the command line, but it will take time to run. Also, it uses `THREAD_COUNT` host CPU threads to run multiple regression tests in parallel.
You can rerun some specific test by setting VEXRISCV_REGRESSION_TEST_ID by their id. For instance, if you want to rerun :
- test_id_5_test_IBus_CachedS1024W1BPL32Relaxvexriscv.plugin.DYNAMIC_DBus_CachedS8192W2BPL16_MulDiv_MulDivFpga_Shift_FullLate_Branch_Late_Hazard_BypassAll_RegFile_SyncDR_Src__Csr_AllNoException_Decoder__Debug_None_DBus_NoMmu
- test_id_9_test_IBus_Simple1S2InjStagevexriscv.plugin.STATIC_DBus_SimpleLate_MulDiv_MulDivFpgaSimple_Shift_FullEarly_Branch_Late_Hazard_Interlock_RegFile_AsyncER_Src_AddSubExecute_Csr_None_Decoder__Debug_None_DBus_NoMmu
then :
```
export VEXRISCV_REGRESSION_TEST_ID=5,9
```
Also there is a few environnement variable that you can use to modulate the random generation :
| Parameters | range | description |
| ------------------------------------------- | ------------------ | ----------- |
| VEXRISCV_REGRESSION_SEED | Int | Seed used to generate the random configurations |
| VEXRISCV_REGRESSION_TEST_ID | \[Int\[,\Int\]\*\] | Random configuration that should be keeped and tested |
| VEXRISCV_REGRESSION_CONFIG_COUNT | Int | Number of random configurations |
| VEXRISCV_REGRESSION_CONFIG_RVC_RATE | 0.0-1.0 | Chance to generate a RVC config |
| VEXRISCV_REGRESSION_CONFIG_LINUX_RATE | 0.0-1.0 | Chance to generate a linux ready config |
| VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE | 0.0-1.0 | Chance to generate a machine mode OS ready config |
| VEXRISCV_REGRESSION_LINUX_REGRESSION | yes/no | Enable the linux test |
| VEXRISCV_REGRESSION_COREMARK | yes/no | Enable the Coremark test |
| VEXRISCV_REGRESSION_ZEPHYR_COUNT | Int | Number of zephyr tests to run on capable configs |
| VEXRISCV_REGRESSION_CONFIG_DEMW_RATE | 0.0-1.0 | Chance to generate a config with writeback stage |
| VEXRISCV_REGRESSION_CONFIG_DEM_RATE | 0.0-1.0 | Chance to generate a config with memory stage |
## Interactive debug of the simulated CPU via GDB OpenOCD and Verilator
To use this, you just need to use the same command as with running tests, but adding `DEBUG_PLUGIN_EXTERNAL=yes` in the make arguments.
@ -296,9 +318,9 @@ You can find some FPGA projects which instantiate the Briey SoC here (DE1-SoC, D
Here are some measurements of Briey SoC timings and area:
```
Artix 7 -> 186 Mhz 3138 LUT 3328 FF
Cyclone V -> 139 Mhz 2,175 ALMs
Cyclone IV -> 129 Mhz 4,337 LUT 3,170 FF
Artix 7 -> 181 Mhz 3220 LUT 3181 FF
Cyclone V -> 142 Mhz 2,222 ALMs
Cyclone IV -> 130 Mhz 4,538 LUT 3,211 FF
```
## Murax SoC
@ -351,16 +373,16 @@ Here are some timing and area measurements of the Murax SoC:
```
Murax interlocked stages (0.45 DMIPS/Mhz, 8 bits GPIO) ->
Artix 7 -> 215 Mhz 1044 LUT 1202 FF
Cyclone V -> 173 Mhz 737 ALMs
Cyclone IV -> 144 Mhz 1,484 LUT 1,206 FF
iCE40 -> 64 Mhz 2422 LC (nextpnr)
Artix 7 -> 216 Mhz 1109 LUT 1201 FF
Cyclone V -> 182 Mhz 725 ALMs
Cyclone IV -> 147 Mhz 1,551 LUT 1,223 FF
iCE40 -> 64 Mhz 2422 LC (nextpnr)
MuraxFast bypassed stages (0.65 DMIPS/Mhz, 8 bits GPIO) ->
Artix 7 -> 229 Mhz 1269 LUT 1302 FF
Cyclone V -> 159 Mhz 864 ALMs
Cyclone IV -> 137 Mhz 1,688 LUT 1,241 FF
iCE40 -> 66 Mhz 2799 LC (nextpnr)
Artix 7 -> 224 Mhz 1278 LUT 1300 FF
Cyclone V -> 173 Mhz 867 ALMs
Cyclone IV -> 143 Mhz 1,755 LUT 1,258 FF
iCE40 -> 66 Mhz 2799 LC (nextpnr)
```
Some scripts to generate the SoC and call the icestorm toolchain can be found here: `scripts/Murax/`

View File

@ -1,3 +1,4 @@
val spinalVersion = "1.4.0"
lazy val root = (project in file(".")).
settings(
@ -7,16 +8,13 @@ lazy val root = (project in file(".")).
version := "2.0.0"
)),
libraryDependencies ++= Seq(
"com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.8",
"com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.8",
"org.scalatest" % "scalatest_2.11" % "2.2.1",
"org.yaml" % "snakeyaml" % "1.8"
"com.github.spinalhdl" % "spinalhdl-core_2.11" % spinalVersion,
"com.github.spinalhdl" % "spinalhdl-lib_2.11" % spinalVersion,
compilerPlugin("com.github.spinalhdl" % "spinalhdl-idsl-plugin_2.11" % spinalVersion),
"org.scalatest" % "scalatest_2.11" % "2.2.1",
"org.yaml" % "snakeyaml" % "1.8"
),
name := "VexRiscv"
)//.dependsOn(spinalHdlSim,spinalHdlCore,spinalHdlLib)
//lazy val spinalHdlSim = ProjectRef(file("../SpinalHDL"), "sim")
//lazy val spinalHdlCore = ProjectRef(file("../SpinalHDL"), "core")
//lazy val spinalHdlLib = ProjectRef(file("../SpinalHDL"), "lib")
)
fork := true

194
doc/smp/smp.md Normal file
View File

@ -0,0 +1,194 @@
# Coherent interface specification
Features :
- 3 interface (write, read, probe) composed of 7 streams
- Two data paths (read + write), but allow dirty/clean sharing by reusing the write data path
- Allow multi level coherent interconnect
- No ordering, but provide barrier
- Allow cache-full and cache-less agents
## A few hint to help reading the spec
In order to make the spec more readable, there is some definitions :
### Stream
A stream is a primitive interface which carry transactions using a valid/ready handshake.
### Memory copy
To talk in a non abstract way, in a system with multiple caches, a given memory address can potentialy be loaded in multiple caches at the same time. So let's define that :
- The DDR memory is named `main memory`
- Each cache line can be loaded with a part of the main memory, let's name that a `memory copy`
### Master / Interconnect / Slave
A master could be for instance a CPU cache, the side of the interconnect toward the main memory or toward a more general interconnect.
A slave could be main memory, the side of the interconnect toward a CPU cache or toward a less general interconnect.
The spec will try to stay abstract and define the coherent interface as something which can be used between two agents (cpu, interconnect, main memory)
## Memory copy status
Memory copy, in other words, cache line, have more states than non coherent systems :
| Name | Description |
|---------------|-------------|
| Valid/Invalid | Line loaded or not |
| Shared/Unique | shared => multiple copy of the cache line in different caches, unique => no other caches has a copy of the line |
| Owner/Lodger | lodger => copy of the line, but no other responsibility, owner => the given cache is responsible to write back dirty data and answer probes with the data |
| Clean/Dirty | clean => match main memory, dirty => main memory need updates |
All combination of those cache flag are valid. But if a cache line is invalid, the other status have no meaning.
Later in the spec, memory copy state can be described for example as :
- VSOC for (Valid, Shared, Owner, Clean)
- V-OC for (Valid, Shared or Unique, Owner, Clean)
- !V-OC for NOT (Valid, Shared or Unique, Owner, Clean)
- ...
## Coherent interface
One full coherent interface is composed of 3 inner interfaces, them-self composed of 7 stream described bellow as `interfaceName (Side -> StreamName -> Side -> StreamName -> ...)`
- write (M -> writeCmd -> S -> writeRsp -> M)
- read (M -> readCmd- > S -> readRsp -> M -> readAck -> S)
- probe (S -> probeCmd -> M -> probeRsp -> S)
### Read interface
Used by masters to obtain new memory copies and make copies unique (used to write them).
Composed of 3 stream :
| Name | Direction | Description |
|---------|-----------|----------|
| readCmd | M -> S | Emit memory read and cache management commands |
| readRsp | M <- S | Return some data and/or a status from readCmd |
| readAck | M -> S | Return ACK from readRsp to syncronize the interconnect status |
### Write interface
Used by masters to write data back to the memory and notify the interconnect of memory copies eviction (used to keep potential directories updated).
Composed of 2 stream :
| Name | Direction | Description |
|---------|-----------|----------|
| writeCmd | M -> S | Emit memory writes and cache management commands |
| writeRsp | M <- S | Return a status from writeCmd |
### Probe interface
Used by the interconnect to order master to change their memory copies status and get memory copies owners data.
Composed of 2 stream :
| Name | Direction | Description |
|----------|-----------|----------|
| probeCmd | M <- S | Used for cache management |
| probeRsp | M -> S | Acknowledgment |
## Transactions
This chapter define transactions moving over the 3 previously defined interface (read/write/probe).
### Read commands
Emitted on the readCmd channel (master -> slave)
| Command | Initial state | Description | Usage example |
|-------------|---------------|----------|------|
| readShared | I--- | Get a memory copy as V--- | Want to read a uncached address |
| readUnique | I--- | Get a memory copy as VUO- | Want to write a uncached address |
| readOnce | I--- | Get a memory copy without coherency tracking | Instruction cache read |
| makeUnique | VS-- | Make other memory copy as I--- and make yourself VUO- | Want to write into a shared line |
| readBarrier | N/A | Ensure that the visibility of the memory operations of this channel do not cross the barrier | ISA fence |
makeUnique should be designed with care. There is a few corner cases :
- While a master has a inflight makeUnique, a probe can change its state, in such case, the makeUnique become weak and invalidation is canceled. This is usefull for multi level coherent interconnects.
- Multi level coherent interconnect should be careful to properly move the ownership and not lose dirty data
I'm not sure yet if we should add some barrier transactions to enforce
### Read responses
Emitted on the readRsp channel (master <- slave)
readSuccess, readError, data shared/unique clean/dirty owner/notOwner
| Responses | From command | Description |
|-------------|---------------|----------|
| readSuccess | makeUnique, readBarrier | - |
| readError | readShared, readUnique, readOnce | Bad address |
| readData | readShared, readUnique, readOnce | Data + coherency status (V---) |
### Read ack
Emitted on the readAck channel (master -> slave), it carry no information, just a notification that the master received the read response
| Name | From command | Description |
|--------------|---------------|----------|
| readSuccess | * | - |
### Write commands
Write commands can be emitted on the writeCmd channel (master -> slave)
| Name | Initial state | Description | Usage example |
|--------------|---------------|----------|----------|
| writeInvalid | V-O- | Write the memory copy and update it status to I--- | Need to free the dirty cache line |
| writeShare | V-O- | Write the memory copy but keep it as VSO- | A probe makeShared asked it |
| writeUnique | VUO- | Write the memory copy but keep it as VUO- | A probe probeOnce need to read the data |
| evict | V---, !V-OD | Notify the interconnect that the cache line is now I--- | Need to free a clean cache line |
| writeBarrier | N/A | Ensure that the visibility of the memory operations of this channel do not cross the barrier | ISA fence |
### Write responses
Emitted on the writeRsp channel (master <- slave), it carry no information, just a notification that the corresponding command is done.
| Name | From command | Description |
|--------------|---------------|----------|
| writeSuccess | * | - |
### Probe commands
Probe commands can be emitted on the probeCmd channel (slave -> master)
| Name | Description | Usage example |
|-------------|-------------|---------------|
| makeInvalid | Make the memory copy I--- | Another cache want to make his shared copy unique to write it |
| makeShared | Make the memory copy VS-- | Another cache want to read a memory block, so unique copy need to be shared |
| probeOnce | Read the V-O- memory copy | A non coherent agent did a readOnce |
makeInvalid and makeShared could result into one of the following probeSuccess, writeInvalid, writeShare
probeOnce can result into one of the following probeSuccess, writeShare, writeUnique
To help the slave matching the writeInvalid and writeShare generated from a probe, those request are tagged with a matching ID.
### Probe responses
Emitted on the probeRsp channel (master -> slave), it carry no information, just a notification that the corresponding command is done.
| Name | From command | Description |
|--------------|---------------|----------|
| probeSuccess | * | - |
## Channel interlocking
This is a delicate subject as if everything was permited, it would be easy to end up with deadlocks.
There is the streams priority (top => high priority, bottom => low priority) A lower priority stream should not block a higher priority stream in order to avoid deadlocks.
- writeCmd, writeRsp, readRsp, readAck, probeRsp. Nothing should realy block them excepted bandwidth
- probeCmd. Can be blocked by inflight/generated writes
- readCmd. Can be blocked by inflight/generated probes
In other words :
Masters can emit writeCmd and wait their writeRsp completion before answering probes commands.
Slaves can emit probeCmd and wait their proveRsp completion before answering reads.
Slaves can emit readRsp and wait on their readAck completion before doing anything else

View File

@ -13,7 +13,6 @@ trait JumpService{
trait IBusFetcher{
def haltIt() : Unit
def flushIt() : Unit
def incoming() : Bool
def pcValid(stage : Stage) : Bool
def getInjectionPort() : Stream[Bits]

View File

@ -36,7 +36,6 @@ case class VexRiscvConfig(){
object PC extends Stageable(UInt(32 bits))
object PC_CALC_WITHOUT_JUMP extends Stageable(UInt(32 bits))
object INSTRUCTION extends Stageable(Bits(32 bits))
object INSTRUCTION_READY extends Stageable(Bool)
object INSTRUCTION_ANTICIPATED extends Stageable(Bits(32 bits))
object LEGAL_INSTRUCTION extends Stageable(Bool)
object REGFILE_WRITE_VALID extends Stageable(Bool)

View File

@ -20,7 +20,7 @@ object GenFullNoMmuMaxPerf extends App{
prediction = DYNAMIC_TARGET,
historyRamSizeLog2 = 8,
config = InstructionCacheConfig(
cacheSize = 4096*4,
cacheSize = 4096*2,
bytePerLine =32,
wayCount = 1,
addressWidth = 32,
@ -29,13 +29,13 @@ object GenFullNoMmuMaxPerf extends App{
catchIllegalAccess = true,
catchAccessFault = true,
asyncTagMemory = false,
twoCycleRam = true,
twoCycleRam = false,
twoCycleCache = true
)
),
new DBusCachedPlugin(
config = new DataCacheConfig(
cacheSize = 4096*4,
cacheSize = 4096*2,
bytePerLine = 32,
wayCount = 1,
addressWidth = 32,
@ -76,7 +76,7 @@ object GenFullNoMmuMaxPerf extends App{
new CsrPlugin(CsrPluginConfig.small),
new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
new BranchPlugin(
earlyBranch = true,
earlyBranch = false,
catchAddressMisaligned = true
),
new YamlPlugin("cpu0.yaml")

View File

@ -56,7 +56,7 @@ object GenNoCacheNoMmuMaxPerf extends App{
new CsrPlugin(CsrPluginConfig.small),
new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
new BranchPlugin(
earlyBranch = true,
earlyBranch = false,
catchAddressMisaligned = true
),
new YamlPlugin("cpu0.yaml")

View File

@ -272,7 +272,7 @@ object LinuxGen {
// wfiGenAsNop = true,
// ucycleAccess = CsrAccess.NONE
// )),
// new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
new BranchPlugin(
earlyBranch = false,
catchAddressMisaligned = true,
@ -310,7 +310,7 @@ object LinuxGen {
// }
// }
SpinalConfig(mergeAsyncProcess = true, anonymSignalPrefix = "_zz").generateVerilog {
SpinalConfig(mergeAsyncProcess = false, anonymSignalPrefix = "_zz").generateVerilog {
val toplevel = new VexRiscv(configFull(

View File

@ -4,8 +4,9 @@ import spinal.core._
import spinal.lib._
import spinal.lib.eda.bench._
import spinal.lib.eda.icestorm.IcestormStdTargets
import spinal.lib.io.InOutWrapper
import vexriscv.VexRiscv
import vexriscv.plugin.{DecoderSimplePlugin}
import vexriscv.plugin.DecoderSimplePlugin
import scala.collection.mutable.ArrayBuffer
import scala.util.Random
@ -96,7 +97,7 @@ object VexRiscvSynthesisBench {
}
val full = new Rtl {
override def getName(): String = "VexRiscv full"
override def getName(): String = "VexRiscv full with MMU"
override def getRtlPath(): String = "VexRiscvFull.v"
SpinalVerilog(wrap(GenFull.cpu()).setDefinitionName(getRtlPath().split("\\.").head))
}
@ -113,15 +114,10 @@ object VexRiscvSynthesisBench {
// val rtls = List(smallAndProductive, smallAndProductiveWithICache, fullNoMmuMaxPerf, fullNoMmu, full)
// val rtls = List(smallAndProductive)
val targets = XilinxStdTargets(
vivadoArtix7Path = "/media/miaou/HD/linux/Xilinx/Vivado/2018.3/bin"
) ++ AlteraStdTargets(
quartusCycloneIVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin",
quartusCycloneVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin"
) ++ IcestormStdTargets().take(1)
val targets = XilinxStdTargets() ++ AlteraStdTargets() ++ IcestormStdTargets().take(1)
// val targets = IcestormStdTargets()
Bench(rtls, targets, "/media/miaou/HD/linux/tmp")
Bench(rtls, targets)
}
}
@ -132,7 +128,7 @@ object BrieySynthesisBench {
override def getName(): String = "Briey"
override def getRtlPath(): String = "Briey.v"
SpinalVerilog({
val briey = new Briey(BrieyConfig.default).setDefinitionName(getRtlPath().split("\\.").head)
val briey = InOutWrapper(new Briey(BrieyConfig.default).setDefinitionName(getRtlPath().split("\\.").head))
briey.io.axiClk.setName("clk")
briey
})
@ -141,14 +137,9 @@ object BrieySynthesisBench {
val rtls = List(briey)
val targets = XilinxStdTargets(
vivadoArtix7Path = "/media/miaou/HD/linux/Xilinx/Vivado/2018.3/bin"
) ++ AlteraStdTargets(
quartusCycloneIVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin",
quartusCycloneVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin"
)
val targets = XilinxStdTargets() ++ AlteraStdTargets() ++ IcestormStdTargets().take(1)
Bench(rtls, targets, "/media/miaou/HD/linux/tmp")
Bench(rtls, targets)
}
}
@ -161,7 +152,7 @@ object MuraxSynthesisBench {
override def getName(): String = "Murax"
override def getRtlPath(): String = "Murax.v"
SpinalVerilog({
val murax = new Murax(MuraxConfig.default.copy(gpioWidth = 8)).setDefinitionName(getRtlPath().split("\\.").head)
val murax = InOutWrapper(new Murax(MuraxConfig.default.copy(gpioWidth = 8)).setDefinitionName(getRtlPath().split("\\.").head))
murax.io.mainClk.setName("clk")
murax
})
@ -172,7 +163,7 @@ object MuraxSynthesisBench {
override def getName(): String = "MuraxFast"
override def getRtlPath(): String = "MuraxFast.v"
SpinalVerilog({
val murax = new Murax(MuraxConfig.fast.copy(gpioWidth = 8)).setDefinitionName(getRtlPath().split("\\.").head)
val murax = InOutWrapper(new Murax(MuraxConfig.fast.copy(gpioWidth = 8)).setDefinitionName(getRtlPath().split("\\.").head))
murax.io.mainClk.setName("clk")
murax
})
@ -180,14 +171,9 @@ object MuraxSynthesisBench {
val rtls = List(murax, muraxFast)
val targets = IcestormStdTargets().take(1) ++ XilinxStdTargets(
vivadoArtix7Path = "/media/miaou/HD/linux/Xilinx/Vivado/2018.3/bin"
) ++ AlteraStdTargets(
quartusCycloneIVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin",
quartusCycloneVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin"
)
val targets = XilinxStdTargets() ++ AlteraStdTargets() ++ IcestormStdTargets().take(1)
Bench(rtls, targets, "/media/miaou/HD/linux/tmp")
Bench(rtls, targets)
}
}

View File

@ -259,7 +259,7 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave
val cmdBridge = Stream (DataCacheMemCmd(p))
val isBurst = cmdBridge.length =/= 0
cmdBridge.valid := cmd.valid
cmdBridge.address := (isBurst ? (cmd.address(31 downto widthOf(counter) + 2) @@ counter @@ "00") | (cmd.address(31 downto 2) @@ "00"))
cmdBridge.address := (isBurst ? (cmd.address(31 downto widthOf(counter) + 2) @@ counter @@ U"00") | (cmd.address(31 downto 2) @@ U"00"))
cmdBridge.wr := cmd.wr
cmdBridge.mask := cmd.mask
cmdBridge.data := cmd.data
@ -278,8 +278,8 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave
bus.ADR := cmdBridge.address >> 2
bus.CTI := Mux(isBurst, cmdBridge.last ? B"111" | B"010", B"000")
bus.BTE := "00"
bus.SEL := cmdBridge.wr ? cmdBridge.mask | "1111"
bus.BTE := B"00"
bus.SEL := cmdBridge.wr ? cmdBridge.mask | B"1111"
bus.WE := cmdBridge.wr
bus.DAT_MOSI := cmdBridge.data
@ -402,7 +402,7 @@ class DataCache(p : DataCacheConfig) extends Component{
//Writes
when(tagsWriteCmd.valid && tagsWriteCmd.way(i)){
tags(tagsWriteCmd.address) := tagsWriteCmd.data
tags.write(tagsWriteCmd.address, tagsWriteCmd.data)
}
when(dataWriteCmd.valid && dataWriteCmd.way(i)){
data.write(
@ -490,8 +490,7 @@ class DataCache(p : DataCacheConfig) extends Component{
//Evict the cache after reset logics
val flusher = new Area {
val valid = RegInit(True)
mmuRsp.physicalAddress init (0)
val valid = RegInit(False)
when(valid) {
tagsWriteCmd.valid := valid
tagsWriteCmd.address := mmuRsp.physicalAddress(lineRange)
@ -506,7 +505,10 @@ class DataCache(p : DataCacheConfig) extends Component{
}
io.cpu.flush.ready := False
when(io.cpu.flush.valid && !io.cpu.execute.isValid && !io.cpu.memory.isValid && !io.cpu.writeBack.isValid && !io.cpu.redo){
val start = RegInit(True) //Used to relax timings
start := !start && io.cpu.flush.valid && !io.cpu.execute.isValid && !io.cpu.memory.isValid && !io.cpu.writeBack.isValid && !io.cpu.redo
when(start){
io.cpu.flush.ready := True
mmuRsp.physicalAddress.getDrivingReg(lineRange) := 0
valid := True

View File

@ -114,7 +114,7 @@ case class InstructionCacheCpuFetch(p : InstructionCacheConfig) extends Bundle w
val mmuBus = MemoryTranslatorBus()
val physicalAddress = UInt(p.addressWidth bits)
val cacheMiss, error, mmuRefilling, mmuException, isUser = ifGen(!p.twoCycleCache)(Bool)
val haltIt = Bool
val haltIt = Bool() //Used to wait on the MMU rsp busy
override def asMaster(): Unit = {
out(isValid, isStuck, isRemoved, pc)

View File

@ -197,7 +197,7 @@ class BranchPlugin(earlyBranch : Boolean,
).asUInt
val branchAdder = branch_src1 + branch_src2
insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ "0"
insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ U"0"
}
//Apply branchs (JAL,JALR, Bxx)
@ -274,7 +274,7 @@ class BranchPlugin(earlyBranch : Boolean,
}
}
val branchAdder = branch_src1 + branch_src2
insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ "0"
insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ U"0"
}
@ -341,7 +341,7 @@ class BranchPlugin(earlyBranch : Boolean,
).asUInt
val branchAdder = branch_src1 + input(BRANCH_SRC2)
insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ "0"
insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ U"0"
insert(NEXT_PC) := input(PC) + (if(pipeline(RVC_GEN)) ((input(IS_RVC)) ? U(2) | U(4)) else 4)
insert(TARGET_MISSMATCH) := decode.input(PC) =/= input(BRANCH_CALC)
}

View File

@ -69,6 +69,7 @@ case class CsrPluginConfig(
midelegAccess : CsrAccess = CsrAccess.NONE,
pipelineCsrRead : Boolean = false,
pipelinedInterrupt : Boolean = true,
csrOhDecoder : Boolean = true,
deterministicInteruptionEntry : Boolean = false, //Only used for simulatation purposes
wfiOutput : Boolean = false
){
@ -263,7 +264,7 @@ case class CsrReadToWriteOverride(that : Data, bitOffset : Int) //Used for speci
case class CsrOnWrite(doThat :() => Unit)
case class CsrOnRead(doThat : () => Unit)
case class CsrMapping() extends CsrInterface{
val mapping = mutable.HashMap[Int,ArrayBuffer[Any]]()
val mapping = mutable.LinkedHashMap[Int,ArrayBuffer[Any]]()
def addMappingAt(address : Int,that : Any) = mapping.getOrElseUpdate(address,new ArrayBuffer[Any]) += that
override def r(csrAddress : Int, bitOffset : Int, that : Data): Unit = addMappingAt(csrAddress, CsrRead(that,bitOffset))
override def w(csrAddress : Int, bitOffset : Int, that : Data): Unit = addMappingAt(csrAddress, CsrWrite(that,bitOffset))
@ -447,9 +448,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
if(supervisorGen) {
redoInterface = pcManagerService.createJumpInterface(pipeline.execute)
redoInterface.valid := False
redoInterface.payload.assignDontCare()
redoInterface = pcManagerService.createJumpInterface(pipeline.execute, -1)
}
exceptionPendings = Vec(Bool, pipeline.stages.length)
@ -643,10 +642,13 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
satpAccess(CSR.SATP, 31 -> satp.MODE, 22 -> satp.ASID, 0 -> satp.PPN)
if(supervisorGen) onWrite(CSR.SATP){
execute.arbitration.flushNext := True
redoInterface.valid := True
redoInterface.payload := execute.input(PC) + 4
if(supervisorGen) {
redoInterface.valid := False
redoInterface.payload := decode.input(PC)
onWrite(CSR.SATP){
execute.arbitration.flushNext := True
redoInterface.valid := True
}
}
}
}
@ -685,7 +687,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
//Aggregate all exception port and remove required instructions
val exceptionPortCtrl = if(exceptionPortsInfos.nonEmpty) new Area{
val exceptionPortCtrl = exceptionPortsInfos.nonEmpty generate new Area{
val firstStageIndexWithExceptionPort = exceptionPortsInfos.map(i => indexOf(i.stage)).min
val exceptionValids = Vec(stages.map(s => Bool().setPartialName(s.getName())))
val exceptionValidsRegs = Vec(stages.map(s => Reg(Bool).init(False).setPartialName(s.getName()))).allowUnsetRegToAvoidLatch
@ -762,7 +764,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
//Avoid the PC register of the last stage to change durring an exception handleing (Used to fill Xepc)
stages.last.dontSample.getOrElseUpdate(PC, ArrayBuffer[Bool]()) += exceptionValids.last
exceptionPendings := exceptionValidsRegs
} else null
}
@ -775,8 +777,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
var privilegs = if (supervisorGen) List(1, 3) else List(3)
val targetPrivilege = if(pipelinedInterrupt) Reg(UInt(2 bits)) else UInt(2 bits).assignDontCare()
val privilegeAllowInterrupts = mutable.HashMap[Int, Bool]()
if (supervisorGen) privilegeAllowInterrupts += 1 -> ((sstatus.SIE && privilege === "01") || privilege < "01")
privilegeAllowInterrupts += 3 -> (mstatus.MIE || privilege < "11")
if (supervisorGen) privilegeAllowInterrupts += 1 -> ((sstatus.SIE && privilege === U"01") || privilege < U"01")
privilegeAllowInterrupts += 3 -> (mstatus.MIE || privilege < U"11")
while (privilegs.nonEmpty) {
val p = privilegs.head
when(privilegeAllowInterrupts(p)) {
@ -808,17 +810,29 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
//Used to make the pipeline empty softly (for interrupts)
val pipelineLiberator = new Area{
when(interrupt.valid && allowInterrupts){
decode.arbitration.haltByOther := decode.arbitration.isValid
val pcValids = Vec(RegInit(False), stagesFromExecute.length)
val active = interrupt.valid && allowInterrupts && decode.arbitration.isValid
when(active){
decode.arbitration.haltByOther := True
for((stage, reg, previous) <- (stagesFromExecute, pcValids, True :: pcValids.toList).zipped){
when(!stage.arbitration.isStuck){
reg := previous
}
}
}
when(!active || decode.arbitration.isRemoved) {
pcValids.foreach(_ := False)
}
val done = !stagesFromExecute.map(_.arbitration.isValid).orR && fetcher.pcValid(mepcCaptureStage)
// val pcValids = for(stage <- stagesFromExecute) yield RegInit(False) clearWhen(!started) setWhen(!stage.arbitration.isValid)
val done = CombInit(pcValids.last)
if(exceptionPortCtrl != null) done.clearWhen(exceptionPortCtrl.exceptionValidsRegs.tail.orR)
}
//Interrupt/Exception entry logic
val interruptJump = Bool.addTag(Verilator.public)
interruptJump := interrupt.valid && pipelineLiberator.done && allowInterrupts
if(pipelinedInterrupt) interrupt.valid clearWhen(interruptJump) //avoid double fireing
val hadException = RegNext(exception) init(False)
pipelineLiberator.done.clearWhen(hadException)
@ -844,7 +858,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
fetcher.haltIt() //Avoid having the fetch confused by the incomming privilege switch
jumpInterface.valid := True
jumpInterface.payload := (if(!xtvecModeGen) xtvec.base @@ "00" else (xtvec.mode === 0 || hadException) ? (xtvec.base @@ "00") | ((xtvec.base + trapCause) @@ "00") )
jumpInterface.payload := (if(!xtvecModeGen) xtvec.base @@ U"00" else (xtvec.mode === 0 || hadException) ? (xtvec.base @@ U"00") | ((xtvec.base + trapCause) @@ U"00") )
lastStage.arbitration.flushNext := True
if(privilegeGen) privilegeReg := targetPrivilege
@ -917,8 +931,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
val imm = IMM(input(INSTRUCTION))
insert(CSR_WRITE_OPCODE) := ! (
(input(INSTRUCTION)(14 downto 13) === "01" && input(INSTRUCTION)(rs1Range) === 0)
|| (input(INSTRUCTION)(14 downto 13) === "11" && imm.z === 0)
(input(INSTRUCTION)(14 downto 13) === B"01" && input(INSTRUCTION)(rs1Range) === 0)
|| (input(INSTRUCTION)(14 downto 13) === B"11" && imm.z === 0)
)
insert(CSR_READ_OPCODE) := input(INSTRUCTION)(13 downto 7) =/= B"0100000"
}
@ -984,7 +998,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
val imm = IMM(input(INSTRUCTION))
def writeSrc = input(SRC1)
// val readDataValid = True
val readData = B(0, 32 bits)
val readData = Bits(32 bits)
val writeInstruction = arbitration.isValid && input(IS_CSR) && input(CSR_WRITE_OPCODE)
val readInstruction = arbitration.isValid && input(IS_CSR) && input(CSR_READ_OPCODE)
val writeEnable = writeInstruction && ! blockedBySideEffects && !arbitration.isStuckByOthers// && readDataRegValid
@ -1030,50 +1044,84 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
//Translation of the csrMapping into real logic
val csrAddress = input(INSTRUCTION)(csrRange)
Component.current.addPrePopTask(() => {
switch(csrAddress) {
for ((address, jobs) <- csrMapping.mapping) {
is(address) {
val withWrite = jobs.exists(j => j.isInstanceOf[CsrWrite] || j.isInstanceOf[CsrOnWrite])
val withRead = jobs.exists(j => j.isInstanceOf[CsrRead] || j.isInstanceOf[CsrOnRead])
if(withRead && withWrite) {
illegalAccess := False
} else {
if (withWrite) illegalAccess.clearWhen(input(CSR_WRITE_OPCODE))
if (withRead) illegalAccess.clearWhen(input(CSR_READ_OPCODE))
}
Component.current.afterElaboration{
def doJobs(jobs : ArrayBuffer[Any]): Unit ={
val withWrite = jobs.exists(j => j.isInstanceOf[CsrWrite] || j.isInstanceOf[CsrOnWrite])
val withRead = jobs.exists(j => j.isInstanceOf[CsrRead] || j.isInstanceOf[CsrOnRead])
if(withRead && withWrite) {
illegalAccess := False
} else {
if (withWrite) illegalAccess.clearWhen(input(CSR_WRITE_OPCODE))
if (withRead) illegalAccess.clearWhen(input(CSR_READ_OPCODE))
}
when(writeEnable) {
for (element <- jobs) element match {
case element: CsrWrite => element.that.assignFromBits(writeData(element.bitOffset, element.that.getBitsWidth bits))
case element: CsrOnWrite =>
element.doThat()
case _ =>
}
}
when(writeEnable) {
for (element <- jobs) element match {
case element: CsrWrite => element.that.assignFromBits(writeData(element.bitOffset, element.that.getBitsWidth bits))
case element: CsrOnWrite =>
element.doThat()
case _ =>
}
}
for (element <- jobs) element match {
case element: CsrRead if element.that.getBitsWidth != 0 => readData(element.bitOffset, element.that.getBitsWidth bits) := element.that.asBits
case _ =>
}
when(readEnable) {
for (element <- jobs) element match {
case element: CsrOnRead =>
element.doThat()
case _ =>
}
}
when(readEnable) {
for (element <- jobs) element match {
case element: CsrOnRead =>
element.doThat()
case _ =>
}
}
}
switch(csrAddress) {
for ((address, jobs) <- csrMapping.mapping if jobs.exists(_.isInstanceOf[CsrReadToWriteOverride])) {
is(address) {
for (element <- jobs) element match {
case element: CsrReadToWriteOverride if element.that.getBitsWidth != 0 => readToWriteData(element.bitOffset, element.that.getBitsWidth bits) := element.that.asBits
case _ =>
def doJobsOverride(jobs : ArrayBuffer[Any]): Unit ={
for (element <- jobs) element match {
case element: CsrReadToWriteOverride if element.that.getBitsWidth != 0 => readToWriteData(element.bitOffset, element.that.getBitsWidth bits) := element.that.asBits
case _ =>
}
}
csrOhDecoder match {
case false => {
readData := 0
switch(csrAddress) {
for ((address, jobs) <- csrMapping.mapping) {
is(address) {
doJobs(jobs)
for (element <- jobs) element match {
case element: CsrRead if element.that.getBitsWidth != 0 => readData(element.bitOffset, element.that.getBitsWidth bits) := element.that.asBits
case _ =>
}
}
}
}
switch(csrAddress) {
for ((address, jobs) <- csrMapping.mapping if jobs.exists(_.isInstanceOf[CsrReadToWriteOverride])) {
is(address) {
doJobsOverride(jobs)
}
}
}
}
case true => {
val oh = csrMapping.mapping.keys.toList.distinct.map(address => address -> RegNextWhen(decode.input(INSTRUCTION)(csrRange) === address, !execute.arbitration.isStuck).setCompositeName(this, "csr_" + address)).toMap
val readDatas = ArrayBuffer[Bits]()
for ((address, jobs) <- csrMapping.mapping) {
when(oh(address)){
doJobs(jobs)
}
if(jobs.exists(_.isInstanceOf[CsrRead])) {
val masked = B(0, 32 bits)
when(oh(address)) (for (element <- jobs) element match {
case element: CsrRead if element.that.getBitsWidth != 0 => masked(element.bitOffset, element.that.getBitsWidth bits) := element.that.asBits
case _ =>
})
readDatas += masked
}
}
readData := readDatas.reduceBalancedTree(_ | _)
for ((address, jobs) <- csrMapping.mapping) {
when(oh(address)){
doJobsOverride(jobs)
}
}
}
@ -1081,7 +1129,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
illegalAccess setWhen(privilege < csrAddress(9 downto 8).asUInt)
illegalAccess clearWhen(!arbitration.isValid || !input(IS_CSR))
})
}
}
}
}

View File

@ -145,7 +145,7 @@ class DBusCachedPlugin(val config : DataCacheConfig,
decoderService.add(FENCE, Nil)
mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(MemoryTranslatorPort.PRIORITY_DATA ,memoryTranslatorPortConfig)
redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(if(pipeline.writeBack != null) pipeline.writeBack else pipeline.execute)
redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(if(pipeline.writeBack != null) pipeline.writeBack else pipeline.memory)
if(catchSomething)
exceptionBus = pipeline.service(classOf[ExceptionService]).newExceptionPort(if(pipeline.writeBack == null) pipeline.memory else pipeline.writeBack)

View File

@ -201,7 +201,6 @@ class DebugPlugin(val debugClockDomain : ClockDomain, hardwareBreakpointCount :
execute.arbitration.haltByOther := True
busReadDataReg := execute.input(PC).asBits
when(stagesFromExecute.tail.map(_.arbitration.isValid).orR === False){
iBusFetcher.flushIt()
iBusFetcher.haltIt()
execute.arbitration.flushIt := True
execute.arbitration.flushNext := True
@ -214,10 +213,11 @@ class DebugPlugin(val debugClockDomain : ClockDomain, hardwareBreakpointCount :
iBusFetcher.haltIt()
}
when(stepIt && iBusFetcher.incoming()) {
iBusFetcher.haltIt()
when(stepIt) {
//Assume nothing will stop the CPU in the decode stage
when(decode.arbitration.isValid) {
haltIt := True
decode.arbitration.flushNext := True
}
}

View File

@ -172,7 +172,7 @@ class DecoderSimplePlugin(catchIllegalInstruction : Boolean = false,
}
if(catchIllegalInstruction){
decodeExceptionPort.valid := arbitration.isValid && input(INSTRUCTION_READY) && !input(LEGAL_INSTRUCTION) // ?? HalitIt to alow decoder stage to wait valid data from 2 stages cache cache ??
decodeExceptionPort.valid := arbitration.isValid && !input(LEGAL_INSTRUCTION) // ?? HalitIt to alow decoder stage to wait valid data from 2 stages cache cache ??
decodeExceptionPort.code := 2
decodeExceptionPort.badAddr := input(INSTRUCTION).asUInt
}

View File

@ -16,12 +16,14 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
val decodePcGen : Boolean,
val compressedGen : Boolean,
val cmdToRspStageCount : Int,
val pcRegReusedForSecondStage : Boolean,
val allowPcRegReusedForSecondStage : Boolean,
val injectorReadyCutGen : Boolean,
val prediction : BranchPrediction,
val historyRamSizeLog2 : Int,
val injectorStage : Boolean,
val relaxPredictorAddress : Boolean) extends Plugin[VexRiscv] with JumpService with IBusFetcher{
val relaxPredictorAddress : Boolean,
val fetchRedoGen : Boolean,
val predictionBuffer : Boolean = true) extends Plugin[VexRiscv] with JumpService with IBusFetcher{
var prefetchExceptionPort : Flow[ExceptionCause] = null
var decodePrediction : DecodePredictionBus = null
var fetchPrediction : FetchPredictionBus = null
@ -31,7 +33,6 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
// assert(!(cmdToRspStageCount == 1 && !injectorStage))
assert(!(compressedGen && !decodePcGen))
var fetcherHalt : Bool = null
var fetcherflushIt : Bool = null
var pcValids : Vec[Bool] = null
def pcValid(stage : Stage) = pcValids(pipeline.indexOf(stage))
var incomingInstruction : Bool = null
@ -42,12 +43,10 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
injectionPort = Stream(Bits(32 bits))
injectionPort
}
def pcRegReusedForSecondStage = allowPcRegReusedForSecondStage && prediction != DYNAMIC_TARGET //TODO might not be required for DYNAMIC_TARGET
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] = {
@ -61,7 +60,6 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
// var decodeExceptionPort : Flow[ExceptionCause] = null
override def setup(pipeline: VexRiscv): Unit = {
fetcherHalt = False
fetcherflushIt = False
incomingInstruction = False
if(resetVector == null) externalResetVector = in(UInt(32 bits).setName("externalResetVector"))
@ -75,21 +73,33 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
}
case DYNAMIC_TARGET => {
fetchPrediction = pipeline.service(classOf[PredictionInterface]).askFetchPrediction()
if(compressedGen && cmdToRspStageCount > 1){
dynamicTargetFailureCorrection = createJumpInterface(pipeline.decode)
}
}
}
pcValids = Vec(Bool, pipeline.stages.size)
}
object IBUS_RSP
object DECOMPRESSOR
object INJECTOR_M2S
def isDrivingDecode(s : Any): Boolean = {
if(injectorStage) return s == INJECTOR_M2S
s == IBUS_RSP || s == DECOMPRESSOR
}
class FetchArea(pipeline : VexRiscv) extends Area {
import pipeline._
import pipeline.config._
val externalFlush = stages.map(_.arbitration.flushNext).orR
//JumpService hardware implementation
def getFlushAt(s : Any, lastCond : Boolean = true): Bool = {
if(isDrivingDecode(s) && lastCond) pipeline.decode.arbitration.isRemoved else externalFlush
}
//Arbitrate jump requests into pcLoad
val jump = new Area {
val sortedByStage = jumpInfos.sortWith((a, b) => {
(pipeline.indexOf(a.stage) > pipeline.indexOf(b.stage)) ||
@ -103,7 +113,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
pcLoad.payload := MuxOH(OHMasking.first(valids.asBits), pcs)
}
fetcherflushIt setWhen(stages.map(_.arbitration.flushNext).orR)
//The fetchPC pcReg can also be use for the second stage of the fetch
//When the fetcherHalt is set and the pipeline isn't stalled,, the pc is propagated to to the pcReg, which allow
@ -112,12 +122,16 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
//PC calculation without Jump
val output = Stream(UInt(32 bits))
val pcReg = Reg(UInt(32 bits)) init(if(resetVector != null) resetVector else externalResetVector) addAttribute(Verilator.public)
val corrected = False
val correction = False
val correctionReg = RegInit(False) setWhen(correction) clearWhen(output.fire)
val corrected = correction || correctionReg
val pcRegPropagate = False
val booted = RegNext(True) init (False)
val inc = RegInit(False) clearWhen(corrected || pcRegPropagate) setWhen(output.fire) clearWhen(!output.valid && output.ready)
val inc = RegInit(False) clearWhen(correction || pcRegPropagate) setWhen(output.fire) clearWhen(!output.valid && output.ready)
val pc = pcReg + (inc ## B"00").asUInt
val predictionPcLoad = ifGen(prediction == DYNAMIC_TARGET) (Flow(UInt(32 bits)))
val redo = (fetchRedoGen || prediction == DYNAMIC_TARGET) generate Flow(UInt(32 bits))
val flushed = False
if(compressedGen) when(inc) {
pc(1) := False
@ -125,22 +139,27 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
if(predictionPcLoad != null) {
when(predictionPcLoad.valid) {
corrected := True
correction := True
pc := predictionPcLoad.payload
}
}
if(redo != null) when(redo.valid){
correction := True
pc := redo.payload
flushed := True
}
when(jump.pcLoad.valid) {
corrected := True
correction := True
pc := jump.pcLoad.payload
flushed := True
}
when(booted && (output.ready || fetcherflushIt || pcRegPropagate)){
when(booted && (output.ready || correction || pcRegPropagate)){
pcReg := pc
}
pc(0) := False
if(!pipeline(RVC_GEN)) pc(1) := False
if(!compressedGen) pc(1) := False
output.valid := !fetcherHalt && booted
output.payload := pc
@ -148,6 +167,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
val decodePc = ifGen(decodePcGen)(new Area {
//PC calculation without Jump
val flushed = False
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))
@ -170,6 +190,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
//application of the selected jump request
when(jump.pcLoad.valid && (!decode.arbitration.isStuck || decode.arbitration.isRemoved)) {
pcReg := jump.pcLoad.payload
flushed := True
}
})
@ -177,116 +198,109 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
case class FetchRsp() extends Bundle {
val pc = UInt(32 bits)
val rsp = IBusSimpleRsp()
val isRvc = Bool
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) {
// inputPipeline(i) << {i match {
// case 0 => input.m2sPipeWithFlush(flush, false, collapsBubble = false)
// case _ => inputPipeline(i-1).haltWhen(inputPipelineHalt(i-1)).m2sPipeWithFlush(flush,collapsBubble = false)
// }}
// }
// val stages = Array.fill(cmdToRspStageCount)(Stream(UInt(32 bits)))
val redoFetch = False
val stages = Array.fill(cmdToRspStageCount + 1)(new Bundle {
val input = Stream(UInt(32 bits))
val output = Stream(UInt(32 bits))
val halt = Bool
val inputSample = Bool
val halt = Bool()
})
stages(0).input << fetchPc.output
stages(0).inputSample := True
for(s <- stages) {
s.halt := False
s.output << s.input.haltWhen(s.halt)
}
if(fetchPc.redo != null) {
fetchPc.redo.valid := redoFetch
fetchPc.redo.payload := stages.last.input.payload
}
val flush = (if(isDrivingDecode(IBUS_RSP)) pipeline.decode.arbitration.isRemoved || decode.arbitration.flushNext && !decode.arbitration.isStuck else externalFlush) || redoFetch
for((s,sNext) <- (stages, stages.tail).zipped) {
val sFlushed = if(s != stages.head) flush else False
val sNextFlushed = flush
if(s == stages.head && pcRegReusedForSecondStage) {
sNext.input.arbitrationFrom(s.output.toEvent().m2sPipeWithFlush(fetcherflushIt, s != stages.head, collapsBubble = false))
sNext.input.arbitrationFrom(s.output.toEvent().m2sPipeWithFlush(sNextFlushed, false, collapsBubble = false, flushInput = sFlushed))
sNext.input.payload := fetchPc.pcReg
fetchPc.pcRegPropagate setWhen(sNext.input.ready)
} else {
sNext.input << s.output.m2sPipeWithFlush(fetcherflushIt, s != stages.head, collapsBubble = false)
sNext.input << s.output.m2sPipeWithFlush(sNextFlushed, false, collapsBubble = false, flushInput = sFlushed)
}
}
//
// val pipeline = Vec(Stream(UInt(32 bits)), cmdToRspStageCount + 1)
// val halts = Vec(False, cmdToRspStageCount)
// for(i <- 0 until cmdToRspStageCount + 1) {
// pipeline(i) << {i match {
// case 0 => pipeline(0) << fetchPc.output.haltWhen(halts(i))
// case 1 => pipeline(1).m2sPipeWithFlush(flush, false, collapsBubble = false)
// case _ => inputPipeline(i-1).haltWhen(inputPipelineHalt(i-1)).m2sPipeWithFlush(flush,collapsBubble = false)
// }}
// }
// ...
val readyForError = True
val output = Stream(FetchRsp())
incomingInstruction setWhen(stages.tail.map(_.input.valid).reduce(_ || _))
}
val decompressor = ifGen(decodePcGen)(new Area{
def input = iBusRsp.output
val input = iBusRsp.output.clearValidWhen(iBusRsp.redoFetch)
val output = Stream(FetchRsp())
val flush = getFlushAt(DECOMPRESSOR)
val flushNext = if(isDrivingDecode(DECOMPRESSOR)) decode.arbitration.flushNext else False
val consumeCurrent = if(isDrivingDecode(DECOMPRESSOR)) flushNext && output.ready else False
val bufferValid = RegInit(False)
val bufferData = Reg(Bits(16 bits))
val isInputLowRvc = input.rsp.inst(1 downto 0) =/= 3
val isInputHighRvc = input.rsp.inst(17 downto 16) =/= 3
val throw2BytesReg = RegInit(False)
val throw2Bytes = throw2BytesReg || input.pc(1)
val unaligned = throw2Bytes || bufferValid
def aligned = !unaligned
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))
whenFalse = input.rsp.inst(31 downto 16) ## (throw2Bytes ? 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.valid := input.valid && !(throw2Bytes && !bufferValid && !isInputHighRvc)
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 && !fetcherflushIt /* && ((isRvc && !bufferValid && !input.pc(1)) || (!isRvc && bufferValid && input.rsp.inst(16, 2 bits) =/= 3))*/) {
input.pc.getDrivingReg(1) := True
}
})
input.ready := output.ready && (!iBusRsp.stages.last.input.valid || flushNext || (!(bufferValid && isInputHighRvc) && !(aligned && isInputLowRvc && isInputHighRvc)))
bufferValid clearWhen(output.fire)
val bufferFill = False
when(input.fire){
when(!(!isRvc && !input.pc(1) && !bufferValid) && !(isRvc && input.pc(1) && output.ready)) {
bufferValid := True
bufferFill := True
} otherwise {
bufferValid := False
}
bufferData := input.rsp.inst(31 downto 16)
when(output.fire){
throw2BytesReg := (aligned && isInputLowRvc && isInputHighRvc) || (bufferValid && isInputHighRvc)
}
val bufferFill = (aligned && isInputLowRvc && !isInputHighRvc) || (bufferValid && !isInputHighRvc) || (throw2Bytes && !isRvc && !isInputHighRvc)
when(output.ready && input.valid){
bufferValid := False
}
when(output.ready && input.valid){
bufferData := input.rsp.inst(31 downto 16)
bufferValid setWhen(bufferFill)
}
when(flush || consumeCurrent){
throw2BytesReg := False
bufferValid := False
}
if(fetchPc.redo != null) {
fetchPc.redo.payload(1) setWhen(throw2BytesReg)
}
bufferValid.clearWhen(fetcherflushIt)
iBusRsp.readyForError.clearWhen(bufferValid && isRvc) //Can't emit error, as there is a earlier instruction pending
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(fetcherflushIt))
val inputBeforeStage = condApply(if (decodePcGen) decompressor.output else iBusRsp.output, injectorReadyCutGen)(_.s2mPipe(externalFlush))
if (injectorReadyCutGen) {
iBusRsp.readyForError.clearWhen(inputBeforeStage.valid) //Can't emit error if there is a instruction pending in the s2mPipe
incomingInstruction setWhen (inputBeforeStage.valid)
}
val decodeInput = (if (injectorStage) {
val decodeInput = inputBeforeStage.m2sPipeWithFlush(fetcherflushIt, collapsBubble = false)
val flushStage = getFlushAt(INJECTOR_M2S)
val decodeInput = inputBeforeStage.m2sPipeWithFlush(flushStage, false, collapsBubble = false, flushInput = externalFlush)
decode.insert(INSTRUCTION_ANTICIPATED) := Mux(decode.arbitration.isStuck, decode.input(INSTRUCTION), inputBeforeStage.rsp.inst)
iBusRsp.readyForError.clearWhen(decodeInput.valid) //Can't emit error when there is a instruction pending in the injector stage buffer
incomingInstruction setWhen (decodeInput.valid)
@ -298,16 +312,16 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
if(!decodePcGen) iBusRsp.readyForError.clearWhen(!pcValid(decode)) //Need to wait a valid PC on the decode stage, as it is use to fill CSR xEPC
def pcUpdatedGen(input : Bool, stucks : Seq[Bool], relaxedInput : Boolean) : Seq[Bool] = {
def pcUpdatedGen(input : Bool, stucks : Seq[Bool], relaxedInput : Boolean, flush : Bool) : Seq[Bool] = {
stucks.scanLeft(input)((i, stuck) => {
val reg = RegInit(False)
if(!relaxedInput) when(fetcherflushIt) {
if(!relaxedInput) when(flush) {
reg := False
}
when(!stuck) {
reg := i
}
if(relaxedInput || i != input) when(fetcherflushIt) {
if(relaxedInput || i != input) when(flush) {
reg := False
}
reg
@ -316,20 +330,17 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
val stagesFromExecute = stages.dropWhile(_ != execute).toList
val nextPcCalc = if (decodePcGen) new Area{
val valids = pcUpdatedGen(True, False :: stagesFromExecute.map(_.arbitration.isStuck), true)
val valids = pcUpdatedGen(True, False :: stagesFromExecute.map(_.arbitration.isStuck), true, decodePc.flushed)
pcValids := Vec(valids.takeRight(stages.size))
} else new Area{
val valids = pcUpdatedGen(True, iBusRsp.stages.tail.map(!_.input.ready) ++ (if (injectorStage) List(!decodeInput.ready) else Nil) ++ stagesFromExecute.map(_.arbitration.isStuck), false)
val valids = pcUpdatedGen(True, iBusRsp.stages.tail.map(!_.input.ready) ++ (if (injectorStage) List(!decodeInput.ready) else Nil) ++ stagesFromExecute.map(_.arbitration.isStuck), false, fetchPc.flushed)
pcValids := Vec(valids.takeRight(stages.size))
}
val decodeRemoved = RegInit(False) setWhen(decode.arbitration.isRemoved) clearWhen(fetcherflushIt) //!decode.arbitration.isStuck || decode.arbitration.isFlushed
decodeInput.ready := !decode.arbitration.isStuck
decode.arbitration.isValid := decodeInput.valid && !decodeRemoved
decode.arbitration.isValid := decodeInput.valid
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) {
@ -415,18 +426,15 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
}
}
def stage1ToInjectorPipe[T <: Data](input : T): (T,T) ={
def stage1ToInjectorPipe[T <: Data](input : T): (T, T, T) ={
val iBusRspContext = iBusRsp.stages.drop(1).dropRight(1).foldLeft(input)((data,stage) => RegNextWhen(data, stage.output.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 iBusRspContextOutput = cloneOf(input)
iBusRspContextOutput := iBusRspContext
val injectorContext = Delay(iBusRspContextOutput, cycleCount=if(injectorStage) 1 else 0, when=injector.decodeInput.ready)
val injectorContextWire = cloneOf(input) //Allow combinatorial override
injectorContextWire := injectorContext
(ifGen(compressedGen)(decompressorContext), injectorContextWire)
(iBusRspContext, iBusRspContextOutput, injectorContextWire)
}
val predictor = prediction match {
@ -449,10 +457,10 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
}
val fetchContext = DynamicContext()
fetchContext.hazard := hazard
fetchContext.line := historyCache.readSync((fetchPc.output.payload >> 2).resized, iBusRsp.stages(0).output.ready || fetcherflushIt)
fetchContext.line := historyCache.readSync((fetchPc.output.payload >> 2).resized, iBusRsp.stages(0).output.ready || externalFlush)
object PREDICTION_CONTEXT extends Stageable(DynamicContext())
decode.insert(PREDICTION_CONTEXT) := stage1ToInjectorPipe(fetchContext)._2
decode.insert(PREDICTION_CONTEXT) := stage1ToInjectorPipe(fetchContext)._3
val decodeContextPrediction = decode.input(PREDICTION_CONTEXT).line.history.msb
val branchStage = decodePrediction.stage
@ -488,13 +496,11 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
}
//TODO no more fireing depedancies
predictionJumpInterface.valid := decode.arbitration.isValid && decodePrediction.cmd.hadBranch //TODO OH Doublon de priorité
predictionJumpInterface.valid := decode.arbitration.isValid && decodePrediction.cmd.hadBranch
predictionJumpInterface.payload := decode.input(PC) + ((decode.input(BRANCH_CTRL) === BranchCtrlEnum.JAL) ? imm.j_sext | imm.b_sext).asUInt
if(relaxPredictorAddress) KeepAttribute(predictionJumpInterface.payload)
decode.arbitration.flushNext setWhen(predictionJumpInterface.valid)
when(predictionJumpInterface.valid && decode.arbitration.isFiring){
flushIt()
}
if(relaxPredictorAddress) KeepAttribute(predictionJumpInterface.payload)
}
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")
@ -502,26 +508,40 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
case class BranchPredictorLine() extends Bundle{
val source = Bits(30 - historyRamSizeLog2 bits)
val branchWish = UInt(2 bits)
val last2Bytes = ifGen(compressedGen)(Bool)
val target = UInt(32 bits)
val unaligned = ifGen(compressedGen)(Bool)
}
val history = Mem(BranchPredictorLine(), 1 << historyRamSizeLog2)
val historyWrite = history.writePort
val historyWriteDelayPatched = history.writePort
val historyWrite = cloneOf(historyWriteDelayPatched)
historyWriteDelayPatched.valid := historyWrite.valid
historyWriteDelayPatched.address := (if(predictionBuffer) historyWrite.address - 1 else historyWrite.address)
historyWriteDelayPatched.data := historyWrite.data
val line = history.readSync((iBusRsp.stages(0).input.payload >> 2).resized, iBusRsp.stages(0).output.ready || fetcherflushIt)
val hit = line.source === (iBusRsp.stages(1).input.payload.asBits >> 2 + historyRamSizeLog2) && (if(compressedGen)(!(!line.unaligned && iBusRsp.stages(1).input.payload(1))) else True)
//Avoid stoping instruction fetch in the middle patch
if(compressedGen && cmdToRspStageCount == 1){
hit clearWhen(!decompressor.output.valid)
}
val writeLast = RegNextWhen(historyWriteDelayPatched, iBusRsp.stages(0).output.ready)
//Avoid write to read hazard
val historyWriteLast = RegNextWhen(historyWrite, iBusRsp.stages(0).output.ready)
val hazard = historyWriteLast.valid && historyWriteLast.address === (iBusRsp.stages(1).input.payload >> 2).resized
//TODO improve predictionPcLoad way of doing things
fetchPc.predictionPcLoad.valid := line.branchWish.msb && hit && !hazard && iBusRsp.stages(1).output.valid //XXX && !(!line.unaligned && iBusRsp.inputPipeline(0).payload(1))
val buffer = predictionBuffer generate new Area{
val line = history.readSync((iBusRsp.stages(0).input.payload >> 2).resized, iBusRsp.stages(0).output.ready)
val pcCorrected = RegNextWhen(fetchPc.corrected, iBusRsp.stages(0).input.ready)
val hazard = (writeLast.valid && writeLast.address === (iBusRsp.stages(1).input.payload >> 2).resized)
}
val (line, hazard) = predictionBuffer match {
case true =>
(RegNextWhen(buffer.line, iBusRsp.stages(0).output.ready),
RegNextWhen(buffer.hazard, iBusRsp.stages(0).output.ready) || buffer.pcCorrected)
case false =>
(history.readSync((iBusRsp.stages(0).input.payload >> 2).resized,
iBusRsp.stages(0).output.ready), writeLast.valid && writeLast.address === (iBusRsp.stages(1).input.payload >> 2).resized)
}
val hit = line.source === (iBusRsp.stages(1).input.payload.asBits >> 2 + historyRamSizeLog2)
if(compressedGen) hit clearWhen(!line.last2Bytes && iBusRsp.stages(1).input.payload(1))
fetchPc.predictionPcLoad.valid := line.branchWish.msb && hit && !hazard && iBusRsp.stages(1).input.valid
fetchPc.predictionPcLoad.payload := line.target
case class PredictionResult() extends Bundle{
@ -535,22 +555,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
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
}
}
val (iBusRspContext, iBusRspContextOutput, injectorContext) = stage1ToInjectorPipe(fetchContext)
object PREDICTION_CONTEXT extends Stageable(PredictionResult())
pipeline.decode.insert(PREDICTION_CONTEXT) := injectorContext
@ -565,7 +570,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
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)
if(compressedGen) historyWrite.data.last2Bytes := fetchPrediction.stage.input(PC)(1) && fetchPrediction.stage.input(IS_RVC)
when(fetchPrediction.rsp.wasRight) {
historyWrite.valid := branchContext.hit
@ -582,27 +587,31 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
historyWrite.valid clearWhen(branchContext.hazard || !branchStage.arbitration.isFiring)
val compressor = compressedGen generate new Area{
val predictionBranch = iBusRspContext.hit && !iBusRspContext.hazard && iBusRspContext.line.branchWish(1)
val unalignedWordIssue = iBusRsp.output.valid && predictionBranch && iBusRspContext.line.last2Bytes && Mux(decompressor.unaligned, !decompressor.isInputHighRvc, decompressor.isInputLowRvc && !decompressor.isInputHighRvc)
val predictionFailure = ifGen(compressedGen && cmdToRspStageCount > 1)(new Area{
val predictionBranch = decompressorContext.hit && !decompressorContext.hazard && decompressorContext.line.branchWish(1)
val unalignedWordIssue = decompressor.bufferFill && decompressor.input.rsp.inst(17 downto 16) === 3 && predictionBranch
val decompressorFailure = RegInit(False) setWhen(unalignedWordIssue) clearWhen(fetcherflushIt)
val injectorFailure = Delay(decompressorFailure, cycleCount=if(injectorStage) 1 else 0, when=injector.decodeInput.ready)
val bypassFailure = if(!injectorStage) False else decompressorFailure && !injector.decodeInput.valid
dynamicTargetFailureCorrection.valid := False
dynamicTargetFailureCorrection.payload := decode.input(PC)
when(injectorFailure || bypassFailure){
when(unalignedWordIssue){
historyWrite.valid := True
historyWrite.address := (decode.input(PC) >> 2).resized
historyWrite.address := (iBusRsp.stages(1).input.payload >> 2).resized
historyWrite.data.branchWish := 0
decode.arbitration.isValid := False
decode.arbitration.flushNext := True
dynamicTargetFailureCorrection.valid := True
iBusRsp.redoFetch := True
}
})
//Do not trigger prediction hit when it is one for the upper RVC word and we aren't there yet
iBusRspContextOutput.hit clearWhen(iBusRspContext.line.last2Bytes && (decompressor.bufferValid || (!decompressor.throw2Bytes && decompressor.isInputLowRvc)))
decodePc.predictionPcLoad.valid := injectorContext.line.branchWish.msb && injectorContext.hit && !injectorContext.hazard && injector.decodeInput.fire
decodePc.predictionPcLoad.payload := injectorContext.line.target
//Clean the RVC buffer when a prediction was made
when(iBusRspContext.line.branchWish.msb && iBusRspContextOutput.hit && !iBusRspContext.hazard && decompressor.output.fire){
decompressor.bufferValid := False
decompressor.throw2BytesReg := False
decompressor.input.ready := True //Drop the remaining byte if any
}
}
}
}

View File

@ -35,18 +35,21 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
memoryTranslatorPortConfig : Any = null,
injectorStage : Boolean = false,
withoutInjectorStage : Boolean = false,
relaxPredictorAddress : Boolean = true) extends IBusFetcherImpl(
relaxPredictorAddress : Boolean = true,
predictionBuffer : Boolean = true) extends IBusFetcherImpl(
resetVector = resetVector,
keepPcPlus4 = keepPcPlus4,
decodePcGen = compressedGen,
compressedGen = compressedGen,
cmdToRspStageCount = (if(config.twoCycleCache) 2 else 1) + (if(relaxedPcCalculation) 1 else 0),
pcRegReusedForSecondStage = true,
allowPcRegReusedForSecondStage = true,
injectorReadyCutGen = false,
prediction = prediction,
historyRamSizeLog2 = historyRamSizeLog2,
injectorStage = (!config.twoCycleCache && !withoutInjectorStage) || injectorStage,
relaxPredictorAddress = relaxPredictorAddress){
relaxPredictorAddress = relaxPredictorAddress,
fetchRedoGen = true,
predictionBuffer = predictionBuffer){
import config._
assert(isPow2(cacheSize))
@ -58,7 +61,6 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
var iBus : InstructionCacheMemBus = null
var mmuBus : MemoryTranslatorBus = null
var privilegeService : PrivilegeService = null
var redoBranch : Flow[UInt] = null
var decodeExceptionPort : Flow[ExceptionCause] = null
val tightlyCoupledPorts = ArrayBuffer[TightlyCoupledPort]()
def tightlyGen = tightlyCoupledPorts.nonEmpty
@ -86,9 +88,6 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
FLUSH_ALL -> True
))
redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(pipeline.decode, priority = 1) //Priority 1 will win against branch predictor
if(catchSomething) {
val exceptionService = pipeline.service(classOf[ExceptionService])
decodeExceptionPort = exceptionService.newExceptionPort(pipeline.decode,1)
@ -157,7 +156,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
stages(0).halt setWhen (cache.io.cpu.prefetch.haltIt)
cache.io.cpu.fetch.isRemoved := fetcherflushIt
cache.io.cpu.fetch.isRemoved := externalFlush
}
@ -211,7 +210,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
if (catchSomething) {
decodeExceptionPort.valid := False
decodeExceptionPort.code.assignDontCare()
decodeExceptionPort.badAddr := cacheRsp.pc(31 downto 2) @@ "00"
decodeExceptionPort.badAddr := cacheRsp.pc(31 downto 2) @@ U"00"
}
when(cacheRsp.isValid && cacheRsp.mmuRefilling && !issueDetected) {
@ -237,19 +236,9 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
decodeExceptionPort.code := 1
}
when(!iBusRsp.readyForError){
redoFetch := False
cache.io.cpu.fill.valid := False
when(redoFetch) {
iBusRsp.redoFetch := True
}
// when(pipeline.stages.map(_.arbitration.flushIt).orR){
// cache.io.cpu.fill.valid := False
// }
redoBranch.valid := redoFetch
redoBranch.payload := (if (decodePcGen) decode.input(PC) else cacheRsp.pc)
decode.arbitration.flushNext setWhen(redoBranch.valid)
cacheRspArbitration.halt setWhen (issueDetected || iBusRspOutputHalt)

View File

@ -233,27 +233,31 @@ class IBusSimplePlugin( resetVector : BigInt,
val rspHoldValue : Boolean = false,
val singleInstructionPipeline : Boolean = false,
val memoryTranslatorPortConfig : Any = null,
relaxPredictorAddress : Boolean = true
relaxPredictorAddress : Boolean = true,
predictionBuffer : Boolean = true
) extends IBusFetcherImpl(
resetVector = resetVector,
keepPcPlus4 = keepPcPlus4,
decodePcGen = compressedGen,
compressedGen = compressedGen,
cmdToRspStageCount = busLatencyMin + (if(cmdForkOnSecondStage) 1 else 0),
pcRegReusedForSecondStage = !(cmdForkOnSecondStage && cmdForkPersistence),
allowPcRegReusedForSecondStage = !(cmdForkOnSecondStage && cmdForkPersistence),
injectorReadyCutGen = false,
prediction = prediction,
historyRamSizeLog2 = historyRamSizeLog2,
injectorStage = injectorStage,
relaxPredictorAddress = relaxPredictorAddress){
relaxPredictorAddress = relaxPredictorAddress,
fetchRedoGen = memoryTranslatorPortConfig != null,
predictionBuffer = predictionBuffer){
var iBus : IBusSimpleBus = null
var decodeExceptionPort : Flow[ExceptionCause] = null
val catchSomething = memoryTranslatorPortConfig != null || catchAccessFault
var mmuBus : MemoryTranslatorBus = null
var redoBranch : Flow[UInt] = null
if(rspHoldValue) assert(busLatencyMin <= 1)
// if(rspHoldValue) assert(busLatencyMin <= 1)
assert(!rspHoldValue, "rspHoldValue not supported yet")
assert(!singleInstructionPipeline)
override def setup(pipeline: VexRiscv): Unit = {
super.setup(pipeline)
@ -268,7 +272,6 @@ class IBusSimplePlugin( resetVector : BigInt,
if(memoryTranslatorPortConfig != null) {
mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(MemoryTranslatorPort.PRIORITY_INSTRUCTION, memoryTranslatorPortConfig)
redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(pipeline.decode, priority = 1) //Priority 1 will win against branch predictor
}
}
@ -282,9 +285,12 @@ class IBusSimplePlugin( resetVector : BigInt,
iBus.cmd << (if(cmdWithS2mPipe) cmd.s2mPipe() else cmd)
//Avoid sending to many iBus cmd
val pendingCmd = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0)
val pendingCmdNext = pendingCmd + cmd.fire.asUInt - iBus.rsp.fire.asUInt
pendingCmd := pendingCmdNext
val pending = new Area{
val inc, dec = Bool()
val value = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0)
val next = value + U(inc) - U(dec)
value := next
}
val secondStagePersistence = cmdForkPersistence && cmdForkOnSecondStage && !cmdWithS2mPipe
def cmdForkStage = if(!secondStagePersistence) iBusRsp.stages(if(cmdForkOnSecondStage) 1 else 0) else iBusRsp.stages(1)
@ -292,104 +298,98 @@ class IBusSimplePlugin( resetVector : BigInt,
val cmdFork = if(!secondStagePersistence) new Area {
//This implementation keep the cmd on the bus until it's executed or the the pipeline is flushed
def stage = cmdForkStage
stage.halt setWhen(stage.input.valid && (!cmd.valid || !cmd.ready))
if(singleInstructionPipeline) {
cmd.valid := stage.input.valid && pendingCmd =/= pendingMax && !stages.map(_.arbitration.isValid).orR
assert(injectorStage == false)
assert(iBusRsp.stages.dropWhile(_ != stage).length <= 2)
}else {
cmd.valid := stage.input.valid && stage.output.ready && pendingCmd =/= pendingMax
}
val canEmit = stage.output.ready && pending.value =/= pendingMax
stage.halt setWhen(stage.input.valid && (!canEmit || !cmd.ready))
cmd.valid := stage.input.valid && canEmit
pending.inc := cmd.fire
} else new Area{
//This implementation keep the cmd on the bus until it's executed, even if the pipeline is flushed
def stage = cmdForkStage
val pendingFull = pendingCmd === pendingMax
val cmdKeep = RegInit(False) setWhen(cmd.valid) clearWhen(cmd.ready)
val pendingFull = pending.value === pendingMax
val enterTheMarket = Bool()
val cmdKeep = RegInit(False) setWhen(enterTheMarket) clearWhen(cmd.ready)
val cmdFired = RegInit(False) setWhen(cmd.fire) clearWhen(stage.input.ready)
stage.halt setWhen(cmd.isStall || (pendingFull && !cmdFired))
cmd.valid := (stage.input.valid || cmdKeep) && !pendingFull && !cmdFired
enterTheMarket := stage.input.valid && !pendingFull && !cmdFired && !cmdKeep
// stage.halt setWhen(cmd.isStall || (pendingFull && !cmdFired)) //(cmd.isStall)
stage.halt setWhen(pendingFull && !cmdFired && !cmdKeep)
stage.halt setWhen(!cmd.ready && !cmdFired)
cmd.valid := enterTheMarket || cmdKeep
pending.inc := enterTheMarket
}
val mmu = (mmuBus != null) generate new Area {
mmuBus.cmd.isValid := cmdForkStage.input.valid
mmuBus.cmd.virtualAddress := cmdForkStage.input.payload
mmuBus.cmd.bypassTranslation := False
mmuBus.end := cmdForkStage.output.fire || fetcherflushIt
mmuBus.end := cmdForkStage.output.fire || externalFlush
cmd.pc := mmuBus.rsp.physicalAddress(31 downto 2) @@ "00"
cmd.pc := mmuBus.rsp.physicalAddress(31 downto 2) @@ U"00"
//do not emit memory request if MMU miss
when(mmuBus.rsp.exception || mmuBus.rsp.refilling){
cmdForkStage.halt := False
cmd.valid := False
}
when(mmuBus.busy){
cmdForkStage.input.valid := False
cmdForkStage.input.ready := False
//do not emit memory request if MMU had issues
when(cmdForkStage.input.valid) {
when(mmuBus.rsp.refilling) {
cmdForkStage.halt := True
cmd.valid := False
}
when(mmuBus.rsp.exception) {
cmdForkStage.halt := False
cmd.valid := False
}
}
val joinCtx = stageXToIBusRsp(cmdForkStage, mmuBus.rsp)
}
val mmuLess = (mmuBus == null) generate new Area{
cmd.pc := cmdForkStage.input.payload(31 downto 2) @@ "00"
cmd.pc := cmdForkStage.input.payload(31 downto 2) @@ U"00"
}
val rspJoin = 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(fetcherflushIt) {
if(secondStagePersistence)
discardCounter := pendingCmd + cmd.valid.asUInt - iBus.rsp.fire.asUInt
else
discardCounter := (if(cmdForkOnSecondStage) pendingCmdNext else pendingCmd - iBus.rsp.fire.asUInt)
}
val rspBufferOutput = Stream(IBusSimpleRsp())
val rspBuffer = if(!rspHoldValue) new Area{
val rspBuffer = new Area {
val output = Stream(IBusSimpleRsp())
val c = StreamFifoLowLatency(IBusSimpleRsp(), busLatencyMin + (if(cmdForkOnSecondStage && cmdForkPersistence) 1 else 0))
c.io.push << iBus.rsp.throwWhen(discardCounter =/= 0).toStream
c.io.flush := fetcherflushIt
rspBufferOutput << c.io.pop
} else new Area{
val rspStream = iBus.rsp.throwWhen(discardCounter =/= 0).toStream
val validReg = RegInit(False) setWhen(rspStream.valid) clearWhen(rspBufferOutput.ready)
rspBufferOutput << rspStream
rspBufferOutput.valid setWhen(validReg)
val discardCounter = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0)
discardCounter := discardCounter - (c.io.pop.valid && discardCounter =/= 0).asUInt
when(iBusRsp.flush) {
discardCounter := (if(cmdForkOnSecondStage) pending.next else pending.value - U(pending.dec))
}
c.io.push << iBus.rsp.toStream
// if(compressedGen) c.io.flush setWhen(decompressor.consumeCurrent)
// if(!compressedGen && isDrivingDecode(IBUS_RSP)) c.io.flush setWhen(decode.arbitration.flushNext && iBusRsp.output.ready)
val flush = discardCounter =/= 0 || iBusRsp.flush
output.valid := c.io.pop.valid && discardCounter === 0
output.payload := c.io.pop.payload
c.io.pop.ready := output.ready || flush
pending.dec := c.io.pop.fire // iBus.rsp.valid && flush || c.io.pop.valid && output.ready instead to avoid unecessary dependancies ?
}
val fetchRsp = FetchRsp()
fetchRsp.pc := stages.last.output.payload
fetchRsp.rsp := rspBufferOutput.payload
fetchRsp.rsp.error.clearWhen(!rspBufferOutput.valid) //Avoid interference with instruction injection from the debug plugin
fetchRsp.rsp := rspBuffer.output.payload
fetchRsp.rsp.error.clearWhen(!rspBuffer.output.valid) //Avoid interference with instruction injection from the debug plugin
val join = Stream(FetchRsp())
val exceptionDetected = False
val redoRequired = False
join.valid := stages.last.output.valid && rspBufferOutput.valid
join.valid := stages.last.output.valid && rspBuffer.output.valid
join.payload := fetchRsp
stages.last.output.ready := stages.last.output.valid ? join.fire | join.ready
rspBufferOutput.ready := join.fire
output << join.haltWhen(exceptionDetected || redoRequired)
rspBuffer.output.ready := join.fire
output << join.haltWhen(exceptionDetected)
if(memoryTranslatorPortConfig != null){
redoRequired setWhen( stages.last.input.valid && mmu.joinCtx.refilling)
redoBranch.valid := redoRequired && iBusRsp.readyForError
redoBranch.payload := decode.input(PC)
decode.arbitration.flushIt setWhen(redoBranch.valid)
decode.arbitration.flushNext setWhen(redoBranch.valid)
when(stages.last.input.valid && mmu.joinCtx.refilling) {
iBusRsp.redoFetch := True
}
}
if(catchSomething){
decodeExceptionPort.code.assignDontCare()
decodeExceptionPort.badAddr := join.pc(31 downto 2) @@ "00"
decodeExceptionPort.badAddr := join.pc(31 downto 2) @@ U"00"
if(catchAccessFault) when(join.valid && join.rsp.error){
decodeExceptionPort.code := 1

View File

@ -50,7 +50,7 @@ object RvcDecompressor{
ret := (i(11 downto 7) === 2) ? addi16sp | lui
}
is(12){
val isImmediate = i(11 downto 10) =/= "11"
val isImmediate = i(11 downto 10) =/= B"11"
val isShift = !i(11)
val func3 = i(11 downto 10).mux(
0 -> B"101",
@ -64,7 +64,7 @@ object RvcDecompressor{
)
)
val msbs = Mux(
sel = i(11 downto 10) === "10",
sel = i(11 downto 10) === B"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"
)
@ -122,7 +122,7 @@ object StreamForkVex{
object StreamVexPimper{
implicit class StreamFlushPimper[T <: Data](pimped : Stream[T]){
def m2sPipeWithFlush(flush : Bool, discardInput : Boolean = true, collapsBubble : Boolean = true): Stream[T] = {
def m2sPipeWithFlush(flush : Bool, discardInput : Boolean = true, collapsBubble : Boolean = true, flushInput : Bool = null): Stream[T] = {
val ret = cloneOf(pimped)
val rValid = RegInit(False)
@ -132,7 +132,10 @@ object StreamVexPimper{
pimped.ready := (Bool(collapsBubble) && !ret.valid) || ret.ready
when(pimped.ready) {
rValid := pimped.valid
if(flushInput == null)
rValid := pimped.valid
else
rValid := pimped.valid && !flushInput
rData := pimped.payload
}

View File

@ -108,7 +108,7 @@ class MulDivIterativePlugin(genMul : Boolean = true,
val div = ifGen(genDiv) (new Area{
assert(isPow2(divUnrollFactor))
def area = this
//register allocation
def numerator = rs1(31 downto 0)
def denominator = rs2
@ -130,13 +130,13 @@ class MulDivIterativePlugin(genMul : Boolean = true,
numerator := inNumerator
remainder := inRemainder
}
case _ => {
case _ => new Area {
val remainderShifted = (inRemainder ## inNumerator.msb).asUInt
val remainderMinusDenominator = remainderShifted - denominator
val outRemainder = !remainderMinusDenominator.msb ? remainderMinusDenominator.resize(32 bits) | remainderShifted.resize(32 bits)
val outNumerator = (inNumerator ## !remainderMinusDenominator.msb).asUInt.resize(32 bits)
stages(outNumerator, outRemainder, stage - 1)
}
}.setCompositeName(area, "stage_" + (divUnrollFactor-stage))
}
stages(numerator, remainder, divUnrollFactor)
@ -167,7 +167,7 @@ class MulDivIterativePlugin(genMul : Boolean = true,
}
if(dhrystoneOpt) {
execute.insert(FAST_DIV_VALID) := execute.input(IS_DIV) && execute.input(INSTRUCTION)(13 downto 12) === "00" && !execute.input(RS1).msb && !execute.input(RS2).msb && execute.input(RS1).asUInt < 16 && execute.input(RS2).asUInt < 16 && execute.input(RS2) =/= 0
execute.insert(FAST_DIV_VALID) := execute.input(IS_DIV) && execute.input(INSTRUCTION)(13 downto 12) === B"00" && !execute.input(RS1).msb && !execute.input(RS2).msb && execute.input(RS1).asUInt < 16 && execute.input(RS2).asUInt < 16 && execute.input(RS2) =/= 0
execute.insert(FAST_DIV_VALUE) := (0 to 15).flatMap(n => (0 to 15).map(d => U(if (d == 0) 0 else n / d, 4 bits))).read(U(execute.input(RS1)(3 downto 0)) @@ U(execute.input(RS2)(3 downto 0))) //(U(execute.input(RS1)(3 downto 0)) / U(execute.input(RS2)(3 downto 0))
when(execute.input(FAST_DIV_VALID)) {
execute.output(IS_DIV) := False

View File

@ -2,6 +2,7 @@ package vexriscv.plugin
import vexriscv._
import vexriscv.VexRiscv
import spinal.core._
import spinal.lib.KeepAttribute
//Input buffer generaly avoid the FPGA synthesis to duplicate reg inside the DSP cell, which could stress timings quite much.
class MulPlugin(inputBuffer : Boolean = false) extends Plugin[VexRiscv]{
@ -94,6 +95,12 @@ class MulPlugin(inputBuffer : Boolean = false) extends Plugin[VexRiscv]{
insert(MUL_LH) := aSLow * bHigh
insert(MUL_HL) := aHigh * bSLow
insert(MUL_HH) := aHigh * bHigh
Component.current.afterElaboration{
//Avoid synthesis tools to retime RS1 RS2 from execute stage to decode stage leading to bad timings (ex : Vivado, even if retiming is disabled)
KeepAttribute(input(RS1))
KeepAttribute(input(RS2))
}
}
//First aggregation of partial multiplication

File diff suppressed because it is too large Load Diff

View File

@ -1,122 +1,174 @@
:0200000480007A
:10000000930E1000970000009380C06F73905030E3
:10001000970000009380807273905010B71001F029
:100020001301000023A02000130E1000170F000082
:10003000130FCF0073000000130E2000B720000044
:10004000938000801301000073B0003073200130F2
:1000500097000000938040017390103473002030AB
:100060006F008068170F0000130F4F02730000002D
:100070006F008067130E3000170F0000130F0F0181
:10008000832010006F004066130E4000B720000070
:1000900093800080371100001301018073B000309D
:1000A000732001309700000093804001739010345A
:1000B000730020306F004063170F0000130F0F0113
:1000C000832010006F004062130E5000B720000024
:1000D000938000801301000073B000307320013062
:1000E000970000009380400173901034730020301B
:1000F0006F00805F170F0000130F0F0183201000A7
:100100006F00805E130E600093000001739020303A
:10011000130E7000170F0000130F0F018320100043
:100120006F00805C130E8000170F0000130FCF03C9
:10013000B720000093800080371100001301018078
:1001400073B00030732001309700000093804001AD
:1001500073901034730020306F000059832010001A
:100160006F008058130E9000170F0000130F8F03BD
:10017000B7200000938000801301000073B00030AE
:100180007320013097000000938040017390103479
:10019000730020306F004055832010006F00C05462
:1001A000130EA000170F0000130FCF03B71001F0BC
:1001B0001301000023A02000930080007390003002
:1001C000B71000009380008073904030B71001F0AA
:1001D0001301100023A02000730050106F00C050C6
:1001E000130EB000170F0000130F8F06B71001F0A9
:1001F0001301000023A020009300800073900030C2
:10020000B71000009380008073904030B72000004A
:1002100093800080371100001301018073B000301B
:1002200073200130970000009380400173901034D8
:10023000730020306F00404BB71001F01301100025
:1002400023A02000730050106F00004A130EC0005E
:10025000170F0000130F4F06B71001F01301000035
:1002600023A020009300800073900030B71000009E
:100270009380008073904030B7200000938000800E
:100280001301000073B000307320013097000000AC
:100290009380400173901034730020306F00C0448D
:1002A000B71001F01301100023A0200073005010BC
:1002B0006F0080439300200073900010130EE00045
:1002C000170F0000130F0F04B72001F013010000F7
:1002D00023A02000930020007390003093000020A2
:1002E00073904030930E0000B72001F0130110000E
:1002F00023A02000930040069380F0FFE34E10FE01
:10030000130EF000170F0000130F8F06B72001F037
:100310001301000023A02000930020007390003000
:100320009300002073904030B7200000938000803D
:10033000371100001301018073B0003073200130C9
:1003400097000000938040017390103473002030B8
:100350006F008039930E1000B72001F013011000D8
:1003600023A02000730050106F000038130E00010E
:10037000170F0000130F0F06B72001F01301000044
:1003800023A02000930020007390003093000020F1
:1003900073904030B720000093800080130100006C
:1003A00073B000307320013097000000938040014B
:1003B00073901034730020306F000033B72001F0C9
:1003C0001301100023A02000730050106F00C031F3
:1003D000130E10019300002073903030170F0000AF
:1003E000130F0F04B72001F01301000023A0200019
:1003F00093002000739000309300002073904030F1
:10040000930E0000B72001F01301100023A020007C
:10041000930040069380F0FFE34E10FE130E200180
:10042000170F0000130F8F06B72001F01301000013
:1004300023A0200093002000739000309300002040
:1004400073904030B7200000938000803711000087
:100450001301018073B00030732001309700000059
:100460009380400173901034730020306F00C027D8
:10047000930E1000B72001F01301100023A02000FC
:10048000730050106F004026130E3001170F00004C
:10049000130F0F06B72001F01301000023A0200066
:1004A0009300200073900030930000207390403040
:1004B000B7200000938000801301000073B000306B
:1004C0007320013097000000938040017390103436
:1004D000730020306F004021B72001F0130110009D
:1004E00023A02000730050106F000020B72001F0FF
:1004F0001301000023A02000130E4001170F00007D
:10050000130F0F039300200073900030930000201E
:1005100073904030930E00009300002073A04014AD
:10052000930040069380F0FFE34E10FE130E50013F
:10053000170F0000130F0F069300002073B0401434
:10054000930020007390003093000020739040309F
:10055000B720000093800080371100001301018054
:1005600073B0003073200130970000009380400189
:1005700073901034730020306F000017930E10003A
:100580009300002073A04014730050106F00C0153A
:10059000130E6001170F0000130F8F05930000204A
:1005A00073B040149300200073900030930000203B
:1005B000739040309300002073A04014B7200000D7
:1005C000938000801301000073B00030732001306D
:1005D0009700000093804001739010347300203026
:1005E0006F008010730050106F000010130E700128
:1005F000930E0000B72001F01301000023A020009B
:100600009300002073B04014F3214034B72001F070
:100610001301100023A020009300002073B04014A9
:10062000F3214034B72001F01301000023A0200083
:100630009300002073B04014F3214034B72001F040
:100640001301000023A020009300002073A0401499
:10065000F3214034B72001F01301100023A0200043
:100660009300002073A04014F3214034B72001F020
:100670001301000023A02000130E8001930020002E
:1006800073A0403073A0403473A00030930E10006C
:10069000170F0000130FCF03B720000093800080D6
:1006A000371100001301018073B000307320013056
:1006B0009700000093804001739010347300203045
:1006C0006F008002730050106F000002130E900143
:1006D000170F0000130F4F017360043073005010A8
:1006E0006F0080006F000001370110F0130141F22C
:1006F0002320C101370110F0130101F22320010072
:10070000E3840EFEF3202034F3201034F320003075
:10071000F32030349300000873B0003093002000C1
:10072000E38A1EFCB72000009380008073A0003095
:1007300073101F3473002030E3880EFAF320201466
:10074000F3201014F3200010F32030147300000085
:10075000130000001300000013000000130000004D
:0807600013000000130000006B
:10000000930E1000971000009380C0A3739050309F
:1000100097100000938080A673905010B71001F0E5
:100020001301000023A020001300000013000000B3
:100030001300000013000000130000001300000074
:100040001300000013000000130E1000170F000033
:10005000130FCF0073000000130E2000B720000024
:10006000938000801301000073B0003073200130D2
:10007000970000009380400173901034730020308B
:100080006F00901A170F0000130F4F02730000004B
:100090006F009019130E3000170F0000130F0F019F
:1000A000832010006F005018130E4000B72000008E
:1000B00093800080371100001301018073B000307D
:1000C000732001309700000093804001739010343A
:1000D000730020306F005015170F0000130F0F0131
:1000E000832010006F005014130E5000B720000042
:1000F000938000801301000073B000307320013042
:1001000097000000938040017390103473002030FA
:100110006F009011170F0000130F0F0183201000C4
:100120006F009010130E6000930000017390203058
:10013000130E7000170F0000130F0F018320100023
:100140006F00900E130E8000170F0000130FCF03E7
:10015000B720000093800080371100001301018058
:1001600073B000307320013097000000938040018D
:1001700073901034730020306F00100B8320100038
:100180006F00900A130E9000170F0000130F8F03DB
:10019000B7200000938000801301000073B000308E
:1001A0007320013097000000938040017390103459
:1001B000730020306F005007832010006F00D006BE
:1001C000130EA000170F0000130FCF07B71001F098
:1001D0001301000023A02000130000001300000002
:1001E00013000000130000001300000013000000C3
:1001F0001300000013000000930080007390003093
:10020000B71000009380008073904030B71001F069
:100210001301100023A020001300000013000000B1
:100220001300000013000000130000001300000082
:100230001300000013000000730050106F00C07E18
:10024000130EB000170F0000130F8F0AB71001F044
:100250001301000023A02000130000001300000081
:100260001300000013000000130000001300000042
:100270001300000013000000930080007390003012
:10028000B71000009380008073904030B7200000CA
:1002900093800080371100001301018073B000309B
:1002A0007320013097000000938040017390103458
:1002B000730020306F004077B71001F01301100079
:1002C00023A0200013000000130000001300000012
:1002D00013000000130000001300000013000000D2
:1002E00013000000730050106F000074130EC00064
:1002F000170F0000130F4F0AB71001F01301000091
:1003000023A02000130000001300000013000000D1
:100310001300000013000000130000001300000091
:10032000130000009300800073900030B7100000AD
:100330009380008073904030B7200000938000804D
:100340001301000073B000307320013097000000EB
:100350009380400173901034730020306F00C06CA4
:10036000B71001F01301100023A0200013000000BB
:100370001300000013000000130000001300000031
:100380001300000013000000130000007300501061
:100390006F0080699300200073900010130EE0003E
:1003A000170F0000130F0F08B72001F01301000012
:1003B00023A0200013000000130000001300000021
:1003C00013000000130000001300000013000000E1
:1003D0001300000093002000739000309300002071
:1003E00073904030930E0000B72001F0130110000D
:1003F00023A02000130000001300000013000000E1
:1004000013000000130000001300000013000000A0
:1004100013000000930040069380F0FFE34E10FEAF
:10042000130EF000170F0000130F8F0AB72001F012
:100430001301000023A0200013000000130000009F
:100440001300000013000000130000001300000060
:100450001300000013000000930020007390003090
:100460009300002073904030B720000093800080FC
:10047000371100001301018073B000307320013088
:100480009700000093804001739010347300203077
:100490006F008059930E1000B72001F01301100077
:1004A00023A0200013000000130000001300000030
:1004B00013000000130000001300000013000000F0
:1004C00013000000730050106F000056130E00015F
:1004D000170F0000130F0F0AB72001F013010000DF
:1004E00023A02000130000001300000013000000F0
:1004F00013000000130000001300000013000000B0
:10050000130000009300200073900030930000203F
:1005100073904030B72000009380008013010000EA
:1005200073B00030732001309700000093804001C9
:1005300073901034730020306F00004FB72001F02B
:100540001301100023A0200013000000130000007E
:10055000130000001300000013000000130000004F
:100560001300000013000000730050106F00C04B18
:10057000130E10019300002073903030170F00000D
:10058000130F0F08B72001F01301000023A0200073
:10059000130000001300000013000000130000000F
:1005A00013000000130000001300000013000000FF
:1005B000930020007390003093000020739040302F
:1005C000930E0000B72001F01301100023A02000BB
:1005D00013000000130000001300000013000000CF
:1005E00013000000130000001300000013000000BF
:1005F000930040069380F0FFE34E10FE130E20019F
:10060000170F0000130F8F0AB72001F0130100002D
:1006100023A02000130000001300000013000000BE
:10062000130000001300000013000000130000007E
:10063000130000009300200073900030930000200E
:1006400073904030B7200000938000803711000085
:100650001301018073B00030732001309700000057
:100660009380400173901034730020306F00C03BC2
:10067000930E1000B72001F01301100023A02000FA
:10068000130000001300000013000000130000001E
:10069000130000001300000013000000130000000E
:1006A000730050106F004038130E3001170F000018
:1006B000130F0F0AB72001F01301000023A0200040
:1006C00013000000130000001300000013000000DE
:1006D00013000000130000001300000013000000CE
:1006E00093002000739000309300002073904030FE
:1006F000B7200000938000801301000073B0003029
:1007000073200130970000009380400173901034F3
:10071000730020306F004031B72001F0130110004A
:1007200023A02000130000001300000013000000AD
:10073000130000001300000013000000130000006D
:1007400013000000730050106F00002EB72001F05E
:100750001301000023A0200013000000130000007C
:10076000130000001300000013000000130000003D
:100770001300000013000000130E4001170F0000CB
:10078000130F0F039300200073900030930000209C
:1007900073904030930E00009300002073A040142B
:1007A000930040069380F0FFE34E10FE130E5001BD
:1007B000170F0000130F0F069300002073B04014B2
:1007C000930020007390003093000020739040301D
:1007D000B7200000938000803711000013010180D2
:1007E00073B0003073200130970000009380400107
:1007F00073901034730020306F000023930E1000AC
:100800009300002073A04014730050106F00C021AB
:10081000130E6001170F0000130F8F0593000020C7
:1008200073B04014930020007390003093000020B8
:10083000739040309300002073A04014B720000054
:10084000938000801301000073B0003073200130EA
:1008500097000000938040017390103473002030A3
:100860006F00801C730050106F00001C130E70018D
:10087000930E0000B72001F01301000023A0200018
:10088000130000001300000013000000130000001C
:10089000130000001300000013000000130000000C
:1008A0009300002073B04014F3214034B72001F0CE
:1008B0001301100023A0200013000000130000000B
:1008C00013000000130000001300000013000000DC
:1008D00013000000130000009300002073B04014C8
:1008E000F3214034B72001F01301000023A02000C1
:1008F00013000000130000001300000013000000AC
:10090000130000001300000013000000130000009B
:100910009300002073B04014F3214034B72001F05D
:100920001301000023A020001300000013000000AA
:10093000130000001300000013000000130000006B
:1009400013000000130000009300002073A0401467
:10095000F3214034B72001F01301100023A0200040
:10096000130000001300000013000000130000003B
:10097000130000001300000013000000130000002B
:100980009300002073A04014F3214034B72001F0FD
:100990001301000023A0200013000000130000003A
:1009A00013000000130000001300000013000000FB
:1009B0001300000013000000130E800193002000BC
:1009C00073A0403073A0403473A00030930E100029
:1009D000170F0000130FCF03B72000009380008093
:1009E000371100001301018073B000307320013013
:1009F0009700000093804001739010347300203002
:100A00006F008002730050106F000002130E9001FF
:100A1000170F0000130F4F01736004307300501064
:100A20006F0080006F000001370110F0130141F2E8
:100A30002320C101370110F0130101F2232001002E
:100A4000E3840EFEF3202034F3201034F320003032
:100A5000F32030349300000873B00030930020007E
:100A6000E38A1EFCB72000009380008073A0003052
:100A700073101F3473002030E3880EFAF320201423
:100A8000F3201014F3200010F32030147300000042
:100A9000130000001300000013000000130000000A
:080AA000130000001300000028
:040000058000000077
:00000001FF

View File

@ -10,11 +10,28 @@
li x1, 0xF0011000; \
li x2, value; \
sw x2, 0(x1); \
nop; \
nop; \
nop; \
nop; \
nop; \
nop; \
nop; \
nop; \
#define externalInterruptS(value) \
li x1, 0xF0012000; \
li x2, value; \
sw x2, 0(x1); \
nop; \
nop; \
nop; \
nop; \
nop; \
nop; \
nop; \
nop; \

View File

@ -2805,7 +2805,7 @@ public:
uint32_t regFileWriteRefIndex = 0;
TestA() : WorkspaceRegression("testA") {
loadHex("../../resources/hex/testA.hex");
loadHex(string(REGRESSION_PATH) + "../../resources/hex/testA.hex");
}
virtual void checks(){
@ -2831,7 +2831,7 @@ public:
TestX28(string name, uint32_t *ref, uint32_t refSize) : WorkspaceRegression(name) {
this->ref = ref;
this->refSize = refSize;
loadHex("../../resources/hex/" + name + ".hex");
loadHex(string(REGRESSION_PATH) + "../../resources/hex/" + name + ".hex");
}
virtual void checks(){
@ -2851,7 +2851,7 @@ public:
class RiscvTest : public WorkspaceRegression{
public:
RiscvTest(string name) : WorkspaceRegression(name) {
loadHex("../../resources/hex/" + name + ".hex");
loadHex(string(REGRESSION_PATH) + "../../resources/hex/" + name + ".hex");
bootAt(0x800000bcu);
}
@ -2899,7 +2899,7 @@ public:
setIStall(iStall);
setDStall(dStall);
withRiscvRef();
loadHex("../../resources/hex/" + hexName + ".hex");
loadHex(string(REGRESSION_PATH) + "../../resources/hex/" + hexName + ".hex");
this->hexName = hexName;
}
@ -2942,7 +2942,7 @@ public:
int out32Counter = 0;
Compliance(string name) : WorkspaceRegression(name) {
withRiscvRef();
loadHex("../../resources/hex/" + name + ".elf.hex");
loadHex(string(REGRESSION_PATH) + "../../resources/hex/" + name + ".elf.hex");
out32.open (name + ".out32");
this->name = name;
}
@ -2963,7 +2963,7 @@ public:
virtual void pass(){
FILE *refFile = fopen((string("../../resources/ref/") + name + ".reference_output").c_str(), "r");
FILE *refFile = fopen((string(REGRESSION_PATH) + string("../../resources/ref/") + name + ".reference_output").c_str(), "r");
fseek(refFile, 0, SEEK_END);
uint32_t refSize = ftell(refFile);
fseek(refFile, 0, SEEK_SET);
@ -3152,7 +3152,7 @@ public:
DebugPluginTest() : WorkspaceRegression("DebugPluginTest") {
loadHex("../../resources/hex/debugPlugin.hex");
loadHex(string(REGRESSION_PATH) + "../../resources/hex/debugPlugin.hex");
pthread_create(&clientThreadId, NULL, &clientThreadWrapper, this);
}
@ -3837,17 +3837,17 @@ int main(int argc, char **argv, char **env) {
// #endif
#ifdef IBUS_CACHED
redo(REDO,WorkspaceRegression("icache").withRiscvRef()->loadHex("../raw/icache/build/icache.hex")->bootAt(0x80000000u)->run(50e3););
redo(REDO,WorkspaceRegression("icache").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../raw/icache/build/icache.hex")->bootAt(0x80000000u)->run(50e3););
#endif
#ifdef DBUS_CACHED
redo(REDO,WorkspaceRegression("dcache").loadHex("../raw/dcache/build/dcache.hex")->bootAt(0x80000000u)->run(2500e3););
redo(REDO,WorkspaceRegression("dcache").loadHex(string(REGRESSION_PATH) + "../raw/dcache/build/dcache.hex")->bootAt(0x80000000u)->run(2500e3););
#endif
#ifdef MMU
redo(REDO,WorkspaceRegression("mmu").withRiscvRef()->loadHex("../raw/mmu/build/mmu.hex")->bootAt(0x80000000u)->run(50e3););
redo(REDO,WorkspaceRegression("mmu").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../raw/mmu/build/mmu.hex")->bootAt(0x80000000u)->run(50e3););
#endif
#ifdef SUPERVISOR
redo(REDO,WorkspaceRegression("deleg").withRiscvRef()->loadHex("../raw/deleg/build/deleg.hex")->bootAt(0x80000000u)->run(50e3););
redo(REDO,WorkspaceRegression("deleg").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../raw/deleg/build/deleg.hex")->bootAt(0x80000000u)->run(50e3););
#endif
#ifdef DEBUG_PLUGIN
@ -3858,20 +3858,20 @@ int main(int argc, char **argv, char **env) {
#endif
#ifdef CUSTOM_SIMD_ADD
redo(REDO,WorkspaceRegression("custom_simd_add").loadHex("../custom/simd_add/build/custom_simd_add.hex")->bootAt(0x00000000u)->run(50e3););
redo(REDO,WorkspaceRegression("custom_simd_add").loadHex(string(REGRESSION_PATH) + "../custom/simd_add/build/custom_simd_add.hex")->bootAt(0x00000000u)->run(50e3););
#endif
#ifdef CUSTOM_CSR
redo(REDO,WorkspaceRegression("custom_csr").loadHex("../custom/custom_csr/build/custom_csr.hex")->bootAt(0x00000000u)->run(50e3););
redo(REDO,WorkspaceRegression("custom_csr").loadHex(string(REGRESSION_PATH) + "../custom/custom_csr/build/custom_csr.hex")->bootAt(0x00000000u)->run(50e3););
#endif
#ifdef LRSC
redo(REDO,WorkspaceRegression("lrsc").withRiscvRef()->loadHex("../raw/lrsc/build/lrsc.hex")->bootAt(0x00000000u)->run(10e3););
redo(REDO,WorkspaceRegression("lrsc").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../raw/lrsc/build/lrsc.hex")->bootAt(0x00000000u)->run(10e3););
#endif
#ifdef AMO
redo(REDO,WorkspaceRegression("amo").withRiscvRef()->loadHex("../raw/amo/build/amo.hex")->bootAt(0x00000000u)->run(10e3););
redo(REDO,WorkspaceRegression("amo").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../raw/amo/build/amo.hex")->bootAt(0x00000000u)->run(10e3););
#endif
#ifdef DHRYSTONE
@ -3910,7 +3910,7 @@ int main(int argc, char **argv, char **env) {
if(withStall == -1) break;
#endif
WorkspaceRegression("coremark_" + rv + (withStall > 0 ? "_stall" : "_nostall")).withRiscvRef()
->loadBin("../../resources/bin/coremark_" + rv + ".bin", 0x80000000)
->loadBin(string(REGRESSION_PATH) + "../../resources/bin/coremark_" + rv + ".bin", 0x80000000)
->bootAt(0x80000000)
->setIStall(withStall > 0)
->setDStall(withStall > 0)
@ -3930,17 +3930,17 @@ int main(int argc, char **argv, char **env) {
/*for(int redo = 0;redo < 4;redo++)*/{
for(const string &name : freeRtosTests){
tasks.push_back([=]() { WorkspaceRegression(name + "_rv32i_O0").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32i_O0.hex")->bootAt(0x80000000u)->run(4e6*15);});
tasks.push_back([=]() { WorkspaceRegression(name + "_rv32i_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32i_O3.hex")->bootAt(0x80000000u)->run(4e6*15);});
tasks.push_back([=]() { WorkspaceRegression(name + "_rv32i_O0").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../../resources/freertos/" + name + "_rv32i_O0.hex")->bootAt(0x80000000u)->run(4e6*15);});
tasks.push_back([=]() { WorkspaceRegression(name + "_rv32i_O3").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../../resources/freertos/" + name + "_rv32i_O3.hex")->bootAt(0x80000000u)->run(4e6*15);});
#ifdef COMPRESSED
// tasks.push_back([=]() { WorkspaceRegression(name + "_rv32ic_O0").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32ic_O0.hex")->bootAt(0x80000000u)->run(5e6*15);});
tasks.push_back([=]() { WorkspaceRegression(name + "_rv32ic_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32ic_O3.hex")->bootAt(0x80000000u)->run(4e6*15);});
// tasks.push_back([=]() { WorkspaceRegression(name + "_rv32ic_O0").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../../resources/freertos/" + name + "_rv32ic_O0.hex")->bootAt(0x80000000u)->run(5e6*15);});
tasks.push_back([=]() { WorkspaceRegression(name + "_rv32ic_O3").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../../resources/freertos/" + name + "_rv32ic_O3.hex")->bootAt(0x80000000u)->run(4e6*15);});
#endif
#if defined(MUL) && defined(DIV)
// #ifdef COMPRESSED
// tasks.push_back([=]() { WorkspaceRegression(name + "_rv32imac_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32imac_O3.hex")->bootAt(0x80000000u)->run(4e6*15);});
// tasks.push_back([=]() { WorkspaceRegression(name + "_rv32imac_O3").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../../resources/freertos/" + name + "_rv32imac_O3.hex")->bootAt(0x80000000u)->run(4e6*15);});
// #else
tasks.push_back([=]() { WorkspaceRegression(name + "_rv32im_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32im_O3.hex")->bootAt(0x80000000u)->run(4e6*15);});
tasks.push_back([=]() { WorkspaceRegression(name + "_rv32im_O3").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../../resources/freertos/" + name + "_rv32im_O3.hex")->bootAt(0x80000000u)->run(4e6*15);});
// #endif
#endif
}
@ -3967,12 +3967,12 @@ int main(int argc, char **argv, char **env) {
/*for(int redo = 0;redo < 4;redo++)*/{
for(const string &name : zephyrTests){
#ifdef COMPRESSED
tasks.push_back([=]() { ZephyrRegression(name + "_rv32ic").withRiscvRef()->loadHex("../../resources/VexRiscvRegressionData/sim/zephyr/" + name + "_rv32ic.hex")->bootAt(0x80000000u)->run(180e6);});
tasks.push_back([=]() { ZephyrRegression(name + "_rv32ic").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../../resources/VexRiscvRegressionData/sim/zephyr/" + name + "_rv32ic.hex")->bootAt(0x80000000u)->run(180e6);});
#else
tasks.push_back([=]() { ZephyrRegression(name + "_rv32i").withRiscvRef()->loadHex("../../resources/VexRiscvRegressionData/sim/zephyr/" + name + "_rv32i.hex")->bootAt(0x80000000u)->run(180e6);});
tasks.push_back([=]() { ZephyrRegression(name + "_rv32i").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../../resources/VexRiscvRegressionData/sim/zephyr/" + name + "_rv32i.hex")->bootAt(0x80000000u)->run(180e6);});
#endif
#if defined(MUL) && defined(DIV)
tasks.push_back([=]() { ZephyrRegression(name + "_rv32im").withRiscvRef()->loadHex("../../resources/VexRiscvRegressionData/sim/zephyr/" + name + "_rv32im.hex")->bootAt(0x80000000u)->run(180e6);});
tasks.push_back([=]() { ZephyrRegression(name + "_rv32im").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../../resources/VexRiscvRegressionData/sim/zephyr/" + name + "_rv32im.hex")->bootAt(0x80000000u)->run(180e6);});
#endif
}
}
@ -3993,10 +3993,10 @@ int main(int argc, char **argv, char **env) {
LinuxRegression soc("linux");
#ifndef DEBUG_PLUGIN_EXTERNAL
soc.withRiscvRef();
soc.loadBin(EMULATOR, 0x80000000);
soc.loadBin(VMLINUX, 0xC0000000);
soc.loadBin(DTB, 0xC3000000);
soc.loadBin(RAMDISK, 0xC2000000);
soc.loadBin(string(REGRESSION_PATH) + EMULATOR, 0x80000000);
soc.loadBin(string(REGRESSION_PATH) + VMLINUX, 0xC0000000);
soc.loadBin(string(REGRESSION_PATH) + DTB, 0xC3000000);
soc.loadBin(string(REGRESSION_PATH) + RAMDISK, 0xC2000000);
#endif
//soc.setIStall(true);
//soc.setDStall(true);

View File

@ -1,5 +1,6 @@
DEBUG?=no
REGRESSION_PATH?=./
VEXRISCV_FILE?=../../../../VexRiscv.v
IBUS?=CACHED
IBUS_TC?=no
DBUS?=CACHED
@ -38,6 +39,7 @@ STOP_ON_ERROR?=no
COREMARK=no
WITH_USER_IO?=no
ADDCFLAGS += -CFLAGS -DREGRESSION_PATH='\"$(REGRESSION_PATH)/\"'
ADDCFLAGS += -CFLAGS -DIBUS_${IBUS}
ADDCFLAGS += -CFLAGS -DDBUS_${DBUS}
ADDCFLAGS += -CFLAGS -DREDO=${REDO}
@ -107,11 +109,11 @@ endif
ifneq ($(shell grep timerInterrupt ../../../../VexRiscv.v -w),)
ifneq ($(shell grep timerInterrupt ${VEXRISCV_FILE} -w),)
ADDCFLAGS += -CFLAGS -DTIMER_INTERRUPT
endif
ifneq ($(shell grep externalInterrupt ../../../../VexRiscv.v -w),)
ifneq ($(shell grep externalInterrupt ${VEXRISCV_FILE} -w),)
ifneq ($(EXTERNAL_INTERRUPT),no)
ADDCFLAGS += -CFLAGS -DEXTERNAL_INTERRUPT
endif
@ -267,10 +269,9 @@ all: clean run
run: compile
./obj_dir/VVexRiscv
verilate: ../../../../VexRiscv.v
rm -f VexRiscv.v*.bin
cp ../../../../VexRiscv.v*.bin . | true
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
verilate: ${VEXRISCV_FILE}
cp ${VEXRISCV_FILE}*.bin . | true
verilator -cc ${VEXRISCV_FILE} -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${THREAD_COUNT} -C obj_dir/ -f VVexRiscv.mk VVexRiscv

View File

@ -102,9 +102,9 @@ class DhrystoneBench extends FunSuite{
getDmips(
name = "GenLinuxBalenced",
gen = LinuxGen.main(Array.fill[String](0)("")),
testCmd = "make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISOR=yes MMU=no CSR=yes CSR_SKIP_TEST=yes DEBUG_PLUGIN=no COMPRESSED=no MUL=yes DIV=yes LRSC=yes AMO=yes REDO=10 TRACE=no COREMARK=yes LINUX_REGRESSION=no"
testCmd = "make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISOR=yes MMU=no CSR=yes CSR_SKIP_TEST=yes COMPRESSED=no MUL=yes DIV=yes LRSC=yes AMO=yes REDO=10 TRACE=no COREMARK=yes LINUX_REGRESSION=no"
)
//make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yess SUPERVISOR=yes CSR=yes COMPRESSED=no MUL=yes DIV=yes LRSC=yes AMO=yes REDO=1 TRACE=no LINUX_REGRESSION=yes SEED=42
test("final_report") {

View File

@ -1,9 +1,10 @@
package vexriscv
import java.io.File
import java.io.{File, OutputStream}
import java.util.concurrent.TimeUnit
import org.apache.commons.io.FileUtils
import org.scalatest.FunSuite
import org.scalatest.{BeforeAndAfterAll, FunSuite, ParallelTestExecution, Tag, Transformer}
import spinal.core._
import vexriscv.demo._
import vexriscv.ip.{DataCacheConfig, InstructionCacheConfig}
@ -11,6 +12,8 @@ import vexriscv.plugin._
import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
import scala.concurrent.duration.Duration
import scala.concurrent.{Await, ExecutionContext, Future}
import scala.sys.process._
import scala.util.Random
@ -313,7 +316,7 @@ class SrcDimension extends VexRiscvDimension("Src") {
}
class IBusDimension extends VexRiscvDimension("IBus") {
class IBusDimension(rvcRate : Double) extends VexRiscvDimension("IBus") {
override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = {
@ -322,7 +325,7 @@ class IBusDimension extends VexRiscvDimension("IBus") {
if(r.nextDouble() < 0.5){
val latency = r.nextInt(5) + 1
val compressed = r.nextBoolean()
val compressed = r.nextDouble() < rvcRate
val injectorStage = r.nextBoolean() || latency == 1
val prediction = random(r, List(NONE, STATIC, DYNAMIC, DYNAMIC_TARGET))
val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL)
@ -345,7 +348,7 @@ class IBusDimension extends VexRiscvDimension("IBus") {
}
} else {
val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL)
val compressed = r.nextBoolean()
val compressed = r.nextDouble() < rvcRate
val tighlyCoupled = r.nextBoolean() && !catchAll
// val tighlyCoupled = false
val prediction = random(r, List(NONE, STATIC, DYNAMIC, DYNAMIC_TARGET))
@ -497,14 +500,14 @@ class MmuDimension extends VexRiscvDimension("DBus") {
trait CatchAllPosition
class CsrDimension(freertos : String, zephyr : String) extends VexRiscvDimension("Csr") {
class CsrDimension(freertos : String, zephyr : String, linux : String) extends VexRiscvDimension("Csr") {
override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = {
val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL)
val supervisor = universes.contains(VexRiscvUniverse.SUPERVISOR)
if(supervisor){
new VexRiscvPosition("Supervisor") with CatchAllPosition{
override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.linuxFull(0x80000020l))
override def testParam = s"FREERTOS=$freertos ZEPHYR=$zephyr LINUX_REGRESSION=${sys.env.getOrElse("VEXRISCV_REGRESSION_LINUX_REGRESSION", "yes")} SUPERVISOR=yes"
override def testParam = s"FREERTOS=$freertos ZEPHYR=$zephyr LINUX_REGRESSION=$linux SUPERVISOR=yes"
}
} else if(catchAll){
new VexRiscvPosition("MachineOs") with CatchAllPosition{
@ -534,6 +537,7 @@ class DebugDimension extends VexRiscvDimension("Debug") {
},
new VexRiscvPosition("Enable") {
override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset")))
override def testParam = "CONCURRENT_OS_EXECUTIONS=yes"
}
))
}
@ -553,32 +557,100 @@ class DecoderDimension extends VexRiscvDimension("Decoder") {
}
}
class TestIndividualFeatures extends FunSuite {
def doCmd(cmd: String): String = {
val stdOut = new StringBuilder()
class Logger extends ProcessLogger {
override def err(s: => String): Unit = {
if (!s.startsWith("ar: creating ")) println(s)
}
override def out(s: => String): Unit = {
println(s)
stdOut ++= s
}
override def buffer[T](f: => T) = f
}
Process(cmd, new File("src/test/cpp/regression")).!(new Logger)
stdOut.toString()
object PlayFuture extends App{
implicit val ec = ExecutionContext.global
val x = for(i <- 0 until 160) yield Future {
print(s"$i ")
Thread.sleep(1000)
}
Thread.sleep(8000)
}
class MultithreadedFunSuite extends FunSuite {
implicit val ec = ExecutionContext.global
class Job(body : => Unit){
val originalOutput = Console.out
val buffer = mutable.Queue[Char]()
var bufferEnabled = true
def redirector() = new OutputStream{
override def write(i: Int): Unit = synchronized {
if(bufferEnabled) buffer += i.toChar
else originalOutput.print(i.toChar)
}
}
val future = Future{
Console.withOut(redirector()){
Console.withErr(redirector())(body)
}
}
def join(): Unit = {
Thread.sleep(50)
synchronized{
bufferEnabled = false
buffer.foreach(originalOutput.print)
}
Await.result(future, Duration.Inf)
}
}
override protected def test(testName: String, testTags: Tag*)(testFun: => Unit) {
val job = new Job(testFun)
super.test(testName, testTags :_*)(job.join())
}
protected def testSingleThread(testName: String, testTags: Tag*)(testFun: => Unit) {
super.test(testName, testTags :_*)(testFun)
}
}
class FunTestPara extends MultithreadedFunSuite{
def createTest(name : String): Unit ={
test(name){
for(i <- 0 to 4) {
println(s"$name $i")
Thread.sleep(500)
}
}
}
(0 to 80).map(_.toString).foreach(createTest)
}
class FunTestPlay extends FunSuite {
def createTest(name : String): Unit ={
test(name){
Thread.sleep(500)
for(i <- 0 to 4) {
println(s"$name $i")
Thread.sleep(500)
}
}
}
(0 to 80).map(_.toString).foreach(createTest)
}
class TestIndividualFeatures extends MultithreadedFunSuite {
val testCount = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_COUNT", "100").toInt
val seed = sys.env.getOrElse("VEXRISCV_REGRESSION_SEED", Random.nextLong().toString).toLong
val testId : Set[Int] = sys.env.get("VEXRISCV_REGRESSION_TEST_ID") match {
case Some(x) if x != "" => x.split(',').map(_.toInt).toSet
case _ => (0 until testCount).toSet
}
val rvcRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_RVC_RATE", "0.5").toDouble
val linuxRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_LINUX_RATE", "0.3").toDouble
val machineOsRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE", "0.5").toDouble
val linuxRegression = sys.env.getOrElse("VEXRISCV_REGRESSION_LINUX_REGRESSION", "yes")
val coremarkRegression = sys.env.getOrElse("VEXRISCV_REGRESSION_COREMARK", "yes")
val zephyrCount = sys.env.getOrElse("VEXRISCV_REGRESSION_ZEPHYR_COUNT", "4")
val demwRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEMW_RATE", "0.6").toDouble
val demRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEM_RATE", "0.5").toDouble
val lock = new{}
val dimensions = List(
new IBusDimension,
new IBusDimension(rvcRate),
new DBusDimension,
new MulDivDimension,
new ShiftDimension,
@ -586,18 +658,46 @@ class TestIndividualFeatures extends FunSuite {
new HazardDimension,
new RegFileDimension,
new SrcDimension,
new CsrDimension(/*sys.env.getOrElse("VEXRISCV_REGRESSION_FREERTOS_COUNT", "1")*/ "0", sys.env.getOrElse("VEXRISCV_REGRESSION_ZEPHYR_COUNT", "4")), //Freertos old port software is broken
new CsrDimension(/*sys.env.getOrElse("VEXRISCV_REGRESSION_FREERTOS_COUNT", "1")*/ "0", zephyrCount, linuxRegression), //Freertos old port software is broken
new DecoderDimension,
new DebugDimension,
new MmuDimension
)
var clockCounter = 0l
var startAt = System.currentTimeMillis()
def doTest(positionsToApply : List[VexRiscvPosition], prefix : String = "", testSeed : Int, universes : mutable.HashSet[VexRiscvUniverse]): Unit ={
val noMemory = universes.contains(VexRiscvUniverse.NO_MEMORY)
val noWriteback = universes.contains(VexRiscvUniverse.NO_WRITEBACK)
def gen = {
val name = (if(noMemory) "noMemoryStage_" else "") + (if(noWriteback) "noWritebackStage_" else "") + positionsToApply.map(d => d.dimension.name + "_" + d.name).mkString("_")
val workspace = "simWorkspace"
val project = s"$workspace/$prefix"
def doCmd(cmd: String): String = {
val stdOut = new StringBuilder()
class Logger extends ProcessLogger {
override def err(s: => String): Unit = {
if (!s.startsWith("ar: creating ")) println(s)
}
override def out(s: => String): Unit = {
println(s)
stdOut ++= s
}
override def buffer[T](f: => T) = f
}
Process(cmd, new File(project)).!(new Logger)
stdOut.toString()
}
test(prefix + name) {
println("START TEST " + prefix + name)
//Cleanup
FileUtils.deleteDirectory(new File(project))
FileUtils.forceMkdir(new File(project))
//Generate RTL
FileUtils.deleteQuietly(new File("VexRiscv.v"))
SpinalVerilog{
SpinalConfig(targetDirectory = project).generateVerilog{
val config = VexRiscvConfig(
withMemoryStage = !noMemory,
withWriteBackStage = !noWriteback,
@ -609,61 +709,52 @@ class TestIndividualFeatures extends FunSuite {
for (positionToApply <- positionsToApply) positionToApply.applyOn(config)
new VexRiscv(config)
}
}
val name = (if(noMemory) "noMemoryStage_" else "") + (if(noWriteback) "noWritebackStage_" else "") + positionsToApply.map(d => d.dimension.name + "_" + d.name).mkString("_")
test(prefix + name + "_gen") {
gen
}
//Setup test
val files = List("main.cpp", "encoding.h" ,"makefile", "dhrystoneO3.logRef", "dhrystoneO3C.logRef","dhrystoneO3MC.logRef","dhrystoneO3M.logRef")
files.foreach(f => FileUtils.copyFileToDirectory(new File(s"src/test/cpp/regression/$f"), new File(project)))
test(prefix + name + "_test") {
println("START TEST " + prefix + name)
//Test RTL
val debug = true
val stdCmd = (s"make clean run WITH_USER_IO=no REDO=10 TRACE=${if(debug) "yes" else "no"} TRACE_START=9999924910246l STOP_ON_ERROR=no FLOW_INFO=no STOP_ON_ERROR=no DHRYSTONE=yes COREMARK=${sys.env.getOrElse("VEXRISCV_REGRESSION_COREMARK", "yes")} THREAD_COUNT=${sys.env.getOrElse("VEXRISCV_REGRESSION_THREAD_COUNT", 1)} ") + s" SEED=${testSeed} "
val stdCmd = (s"make run REGRESSION_PATH=../../src/test/cpp/regression VEXRISCV_FILE=VexRiscv.v WITH_USER_IO=no REDO=10 TRACE=${if(debug) "yes" else "no"} TRACE_START=1000000000000l STOP_ON_ERROR=no FLOW_INFO=no STOP_ON_ERROR=no DHRYSTONE=yes COREMARK=${coremarkRegression} THREAD_COUNT=1 ") + s" SEED=${testSeed} "
val testCmd = stdCmd + (positionsToApply).map(_.testParam).mkString(" ")
println(testCmd)
val str = doCmd(testCmd)
assert(str.contains("REGRESSION SUCCESS") && !str.contains("Broken pipe"))
val pattern = "Had simulate ([0-9]+)".r
val hit = pattern.findFirstMatchIn(str)
lock.synchronized(clockCounter += hit.get.group(1).toLong)
}
}
val testId : Option[mutable.HashSet[Int]] = None
val seed = sys.env.getOrElse("VEXRISCV_REGRESSION_SEED", Random.nextLong().toString).toLong
//
// val testId = Some(mutable.HashSet(3,4,9,11,13,16,18,19,20,21))
// val testId = Some(mutable.HashSet(11))
// val testId = Some(mutable.HashSet(4, 11))
// val seed = 6592877339343561798l
val rand = new Random(seed)
test("Info"){
println(s"MAIN_SEED=$seed")
}
println(s"Seed=$seed")
for(i <- 0 until sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_COUNT", "100").toInt){
for(i <- 0 until testCount){
var positions : List[VexRiscvPosition] = null
var universe = mutable.HashSet[VexRiscvUniverse]()
if(rand.nextDouble() < 0.5) universe += VexRiscvUniverse.EXECUTE_RF
if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_LINUX_RATE", "0.3").toDouble > rand.nextDouble()) {
if(linuxRate > rand.nextDouble()) {
universe += VexRiscvUniverse.CATCH_ALL
universe += VexRiscvUniverse.MMU
universe += VexRiscvUniverse.FORCE_MULDIV
universe += VexRiscvUniverse.SUPERVISOR
if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEMW_RATE", "0.6").toDouble < rand.nextDouble()){
if(demwRate < rand.nextDouble()){
universe += VexRiscvUniverse.NO_WRITEBACK
}
} else {
if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE", "0.5").toDouble > rand.nextDouble()) {
if(machineOsRate > rand.nextDouble()) {
universe += VexRiscvUniverse.CATCH_ALL
if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEMW_RATE", "0.6").toDouble < rand.nextDouble()){
if(demwRate < rand.nextDouble()){
universe += VexRiscvUniverse.NO_WRITEBACK
}
}
if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEMW_RATE", "0.6").toDouble > rand.nextDouble()){
}else if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEM_RATE", "0.5").toDouble > rand.nextDouble()){
if(demwRate > rand.nextDouble()){
}else if(demRate > rand.nextDouble()){
universe += VexRiscvUniverse.NO_WRITEBACK
} else {
universe += VexRiscvUniverse.NO_WRITEBACK
@ -676,8 +767,13 @@ class TestIndividualFeatures extends FunSuite {
}while(!positions.forall(_.isCompatibleWith(positions)))
val testSeed = rand.nextInt()
if(testId.isEmpty || testId.get.contains(i))
doTest(positions," random_" + i + "_", testSeed, universe)
if(testId.contains(i))
doTest(positions,"test_id_" + i + "_", testSeed, universe)
Hack.dCounter += 1
}
testSingleThread("report"){
val time = (System.currentTimeMillis() - startAt)*1e-3
val clockPerSecond = (clockCounter/time*1e-3).toLong
println(s"Duration=${(time/60).toInt}mn clocks=${(clockCounter*1e-6).toLong}M clockPerSecond=${clockPerSecond}K")
}
}