commit
95237b23ea
128
README.md
128
README.md
|
@ -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/`
|
||||
|
|
16
build.sbt
16
build.sbt
|
@ -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
|
|
@ -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
|
|
@ -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]
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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
|
||||
|
|
|
@ -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; \
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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") {
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue