Merge remote-tracking branch 'origin/master' into dev

This commit is contained in:
Charles Papon 2019-04-29 16:56:04 +02:00
commit 02db756b21
132 changed files with 28372 additions and 1888 deletions

5
.gitignore vendored
View file

@ -1,6 +1,7 @@
*.class
*.log
*.bak
.*.swp
# sbt specific
.cache/
@ -24,6 +25,7 @@ out
bin/
.classpath
.project
.cproject
.settings
.cache-main
@ -39,6 +41,7 @@ obj_dir
*.yaml
*.memTrace
*.regTrace
*.debugTrace
*.tcl
*.o
*.bin
@ -46,4 +49,4 @@ obj_dir
simWorkspace/
tmp/
/archive.tar.gz
*.out32
*.out32

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "src/test/resources/VexRiscvRegressionData"]
path = src/test/resources/VexRiscvRegressionData
url = ../VexRiscvRegressionData.git

View file

@ -1,64 +1,89 @@
language: scala
dist: xenial
notifications:
email:
on_success: never
# See 'project/Version.scala'
scala:
- 2.11.6
- 2.11.12
sbt_args: -no-colors -J-Xss2m
script:
- export VEXRISCV_REGRESSION_CONFIG_COUNT=100
- export VEXRISCV_REGRESSION_FREERTOS_COUNT=no
- sbt -jvm-opts travis/jvmopts.compile compile
- sbt -jvm-opts travis/jvmopts.test test
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- git
- make
- autoconf
- g++
- flex
- bison
jdk:
- oraclejdk8
# - oraclejdk7
# - openjdk7
- openjdk10
env:
- secure: "v7FHP8yK/zixpv1ML05qcRhZfDVDFdTmTPjfMZHL7gmrJveVDgze22x4tY4tB1+JEXhKuVTYvimOrX/Ok+rOOT5gVKLowv4PUQwCR+HgWVIbqjcfZNLsa369v03/p4K/zbjJSiXFahZYOXa0ApED2KWHcVfCrNsPv0UF7YZGiIa1Q/lPBwfmpN1rLih2Mpgn4KVaJky22t7JXJyVrNdGVmIA51slVbyFwFAE8Ww/0tkC+i2PUcWWRMIxtXP4iyq/9Npcq5VdqOatKfWHqAElLfKSPNMYLMlcyxyNpNx4paq8cL6fQxFcBLi9M2msz2i/qpKv30a0tzNo5bQQgucAXOQJB2Buks728upLuqsr+k25hwcqrtjyMOr9UQkt7qXAJH/0kimW7aW1yoMxbm/6mNG98X9D1EzNRewHAKatwJeFy1bw5qIuSQxPBwQMGloManrHOHGotmHKk7Y+dgM/z1UlaAdxSQuKWGXBc8QlQvif8puPYEdJMoInJNRxiWfYu06XnmzTXgMketK7RdULM9DVYzw8hzS2EIWKu8Oa0zn0PTevD2YeJNd4G8mDqO0vz5hloIc7pFsq/exQUB/kFozfCsnvhW8P+MPN0LpuSpptBQTsLWbM5BH0hd46HoWcneDdlMvVrUcgsTPmmSroIkLIEUo+Y2iN5eQHPPp85Cw="
jobs:
include:
- stage: prepare cache-verilator
script:
- cp scripts/regression/verilator.mk $HOME/makefile
- cd $HOME
- make verilator_binary
- &test
stage: Test
name: Dhrystone
script:
- make regression_dhrystone -C scripts/regression
- <<: *test
stage: Test
name: Baremetal
script:
- make regression_random_baremetal -C scripts/regression
- <<: *test
stage: Test
name: Machine OS
script:
- make regression_random_machine_os -C scripts/regression
- <<: *test
stage: Test
name: Machine OS
script:
- make regression_random_machine_os -C scripts/regression
- <<: *test
stage: Test
name: Mixed
script:
- make regression_random -C scripts/regression
- <<: *test
stage: Test
name: Linux
script:
- make regression_random_linux -C scripts/regression
- <<: *test
stage: Test
name: Linux
script:
- make regression_random_linux -C scripts/regression
before_install:
# JDK fix
- cat /etc/hosts # optionally check the content *before*
- sudo hostname "$(hostname | cut -c1-63)"
- sed -e "s/^\\(127\\.0\\.0\\.1.*\\)/\\1 $(hostname | cut -c1-63)/" /etc/hosts | sudo tee /etc/hosts
- cat /etc/hosts # optionally check the content *after*
- cd ..
# Verilator
- sudo apt-get install git make autoconf g++ flex bison -y # First time prerequisites
- git clone http://git.veripool.org/git/verilator # Only first time
- unset VERILATOR_ROOT # For bash
- cd verilator
- git pull # Make sure we're up-to-date
- git checkout verilator_3_916
- autoconf # Create ./configure script
- ./configure
- make -j$(nproc)
- sudo make install
- cd ..
- git clone https://github.com/SpinalHDL/SpinalHDL.git -b dev
- cd VexRiscv
#- curl -T README.md -udolu1990:$BINTRAY_KEY https://api.bintray.com/content/spinalhdl/VexRiscv/test/0.0.4/README.md
#- curl -X POST -udolu1990:$BINTRAY_KEY https://api.bintray.com/content/spinalhdl/VexRiscv/test/0.0.4/publish
#- sbt compile
- export VERILATOR_ROOT=$HOME/verilator
- export PATH=$VERILATOR_ROOT/bin:$PATH
before_cache:
# Tricks to avoid unnecessary cache updates
- find $HOME/.ivy2 -name "ivydata-*.properties" -delete
- find $HOME/.sbt -name "*.lock" -delete
- rm -fv $HOME/.ivy2/.sbt.ivy.lock
- find $HOME/.ivy2/cache -name "ivydata-*.properties" -print -delete
- find $HOME/.sbt -name "*.lock" -print -delete
cache:
directories:
- $HOME/.ivy2/cache
- $HOME/.sbt/boot/
- $HOME/.sbt
- $HOME/verilator

232
README.md
View file

@ -12,6 +12,7 @@
* [By using FreedomStudio](#by-using-freedomstudio)
- [Briey SoC](#briey-soc)
- [Murax SoC](#murax-soc)
- [Running Linux](#running-linux)
- [Build the RISC-V GCC](#build-the-risc-v-gcc)
- [CPU parametrization and instantiation example](#cpu-parametrization-and-instantiation-example)
- [Add a custom instruction to the CPU via the plugin system](#add-a-custom-instruction-to-the-cpu-via-the-plugin-system)
@ -26,22 +27,21 @@
This repository hosts a RISC-V implementation written in SpinalHDL. Here are some specs :
- RV32I[M][C] instruction set
- Pipelined with 5 stages (Fetch, Decode, Execute, Memory, WriteBack)
- RV32I[M][C][A] instruction set (Atomic only inside a single core)
- Pipelined from 2 to 5+ stages ([Fetch*X], Decode, Execute, [Memory], [WriteBack])
- 1.44 DMIPS/Mhz --no-inline when nearly all features are enabled (1.57 DMIPS/Mhz when the divider lookup table is enabled)
- Optimized for FPGA, fully portable
- AXI4 and Avalon ready
- Optimized for FPGA, do not use any vendor specific IP block / primitive
- AXI4, Avalon, wishbone ready
- Optional MUL/DIV extensions
- Optional instruction and data caches
- Optional MMU
- Optional hardware refilled MMU
- Optional debug extension allowing Eclipse debugging via a GDB >> openOCD >> JTAG connection
- Optional interrupts and exception handling with Machine and User modes as defined in the [RISC-V Privileged ISA Specification v1.9](https://riscv.org/specifications/privileged-isa/).
- Optional interrupts and exception handling with Machine, [Supervisor] and [User] modes as defined in the [RISC-V Privileged ISA Specification v1.10](https://riscv.org/specifications/privileged-isa/).
- Two implementations of shift instructions: Single cycle and shiftNumber cycles
- Each stage can have optional bypass or interlock hazard logic
- Zephyr RISC-V port compatible
- Linux compatible
- Zephyr compatible
- [FreeRTOS port](https://github.com/Dolu1990/FreeRTOS-RISCV)
- The data cache supports atomic LR/SC
- Optional RV32 compressed instruction support in the reworkFetch branch for configurations without instruction cache (will be merge in master, WIP)
The hardware description of this CPU is done by using a very software oriented approach
(without any overhead in the generated hardware). Here is a list of software concepts used:
@ -66,48 +66,54 @@ The CPU configurations used below can be found in the `src/scala/vexriscv/demo`
```
VexRiscv smallest (RV32I, 0.52 DMIPS/Mhz, no datapath bypass, no interrupt) ->
Artix 7 -> 346 Mhz 481 LUT 539 FF
Cyclone V -> 201 Mhz 347 ALMs
Cyclone IV -> 190 Mhz 673 LUT 529 FF
iCE40 -> 81 Mhz 1130 LC
Artix 7 -> 366 Mhz 488 LUT 505 FF
Cyclone V -> 181 Mhz 350 ALMs
Cyclone IV -> 177 Mhz 732 LUT 494 FF
iCE40 -> 85 Mhz 1131 LC
VexRiscv smallest (RV32I, 0.52 DMIPS/Mhz, no datapath bypass) ->
Artix 7 -> 340 Mhz 562 LUT 589 FF
Cyclone V -> 202 Mhz 387 ALMs
Cyclone IV -> 180 Mhz 780 LUT 579 FF
iCE40 -> 71 Mhz 1278 LC
Artix 7 -> 317 Mhz 539 LUT 559 FF
Cyclone V -> 191 Mhz 393 ALMs
Cyclone IV -> 171 Mhz 826 LUT 547 FF
iCE40 -> 72 Mhz 1284 LC
VexRiscv small and productive (RV32I, 0.82 DMIPS/Mhz) ->
Artix 7 -> 327 Mhz 698 LUT 558 FF
Cyclone V -> 158 Mhz 524 ALMs
Cyclone IV -> 146 Mhz 1,061 LUT 552 FF
iCE40 -> 55 Mhz 1541 LC
Artix 7 -> 338 Mhz 697 LUT 527 FF
Cyclone V -> 149 Mhz 495 ALMs
Cyclone IV -> 137 Mhz 1,103 LUT 522 FF
iCE40 -> 65 Mhz 1593 LC
VexRiscv small and productive with I$ (RV32I, 0.72 DMIPS/Mhz, 4KB-I$) ->
Artix 7 -> 331 Mhz 727 LUT 600 FF
Cyclone V -> 152 Mhz 536 ALMs
Cyclone IV -> 156 Mhz 1,075 LUT 565 FF
iCE40 -> 54 Mhz 1686 LC
VexRiscv small and productive with I$ (RV32I, 0.70 DMIPS/Mhz, 4KB-I$) ->
Artix 7 -> 314 Mhz 721 LUT 562 FF
Cyclone V -> 152 Mhz 504 ALMs
Cyclone IV -> 142 Mhz 1,146 LUT 528 FF
iCE40 -> 69 Mhz 1661 LC
VexRiscv full no cache (RV32IM, 1.22 DMIPS/Mhz, single cycle barrel shifter, debug module, catch exceptions, static branch) ->
Artix 7 -> 295 Mhz 1399 LUT 971 FF
Cyclone V -> 151 Mhz 922 ALMs
Cyclone IV -> 136 Mhz 1,859 LUT 992 FF
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 -> 325 Mhz 1448 LUT 976 FF
Cyclone V -> 141 Mhz 957 ALMs
Cyclone IV -> 139 Mhz 2,001 LUT 966 FF
VexRiscv full (RV32IM, 1.21 DMIPS/Mhz with cache trashing, 4KB-I$,4KB-D$, single cycle barrel shifter, debug module, catch exceptions, static branch) ->
Artix 7 -> 253 Mhz 1840 LUT 1394 FF
Cyclone V -> 126 Mhz 1,172 ALMs
Cyclone IV -> 117 Mhz 2,548 LUT 1,703 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 -> 241 Mhz 1692 LUT 1202 FF
Cyclone V -> 132 Mhz 1,127 ALMs
Cyclone IV -> 124 Mhz 2,296 LUT 1,115 FF
VexRiscv full max perf -> (RV32IM, 1.44 DMIPS/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 -> 183 Mhz 1813 LUT 1424 FF
Cyclone V -> 93 Mhz 1,253 ALMs
Cyclone IV -> 84 Mhz 2,642 LUT 1,711 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 -> 195 Mhz 1824 LUT 1110 FF
Cyclone V -> 83 Mhz 1,067 ALMs
Cyclone IV -> 78 Mhz 2,335 LUT 1,045 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 -> 218 Mhz 1966 LUT 1551 FF
Cyclone V -> 123 Mhz 1,298 ALMs
Cyclone IV -> 109 Mhz 2,703 LUT 1,498 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 -> 239 Mhz 2483 LUT 2134 FF
Cyclone V -> 130 Mhz 1,636 ALMs
Cyclone IV -> 116 Mhz 3,324 LUT 2,010 FF
VexRiscv full with MMU (RV32IM, 1.26 DMIPS/Mhz with cache trashing, 4KB-I$, 4KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch, MMU) ->
Artix 7 -> 214 Mhz 2070 LUT 1913 FF
Cyclone V -> 108 Mhz 1,430 ALMs
Cyclone IV -> 100 Mhz 2,976 LUT 2,201 FF
```
The following configuration results in 1.44 DMIPS/MHz:
@ -127,7 +133,7 @@ Note that recently, the capability to remove the Fetch/Memory/WriteBack stage wa
On Ubuntu 14 :
```sh
# JAVA JDK 8. Do not try with JDK >= 9
# JAVA JDK 8
sudo add-apt-repository -y ppa:openjdk-r/ppa
sudo apt-get update
sudo apt-get install openjdk-8-jdk -y
@ -177,6 +183,9 @@ NOTES:
do a "sbt clean compile publish-local" in it as described in the dependencies chapter.
## Regression tests
[![Build Status](https://travis-ci.org/SpinalHDL/VexRiscv.svg?branch=master)](https://travis-ci.org/SpinalHDL/VexRiscv)
To run tests (need the verilator simulator), go in the src/test/cpp/regression folder and run :
```sh
@ -223,7 +232,19 @@ continue
## Using Eclipse to run the software and debug it
### By using Zylin plugin
### By using gnu-mcu-eclipse
You can download releases of the IDE here : https://github.com/gnu-mcu-eclipse/org.eclipse.epp.packages/releases
In the IDE, you can import a makefile project by :
- file -> import -> C/C++ -> existing Code as Makefile Project
- Select the folder which contain the makefile, select "Cross GCC" (not "RISC-V Cross GCC")
To create a new debug configuration :
- run -> Debug Configurations -> GDB OpenOCD Debugging double click
- Look at https://drive.google.com/open?id=1c46tyEV0xLwOsk76b0y2qqs8CYy7Zq3f for a configuration example
### By using Zylin plugin (old)
You can use the Eclipse + Zylin embedded CDT plugin to do it (http://opensource.zylin.com/embeddedcdt.html). Tested with Helios Service Release 2 (http://www.Eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/helios/SR2/Eclipse-cpp-helios-SR2-linux-gtk-x86_64.tar.gz) and the corresponding zylin plugin.
To following commands will download Eclipse and install the plugin.
@ -238,13 +259,6 @@ See https://drive.google.com/drive/folders/1NseNHH05B6lmIXqQFVwK8xRjWE4ydeG-?usp
Note that sometime this Eclipse need to be restarted in order to be able to place new breakpoints.
### By using FreedomStudio
You can get FreedomStudio (which is package with Eclipse and some plugins) here: https://www.sifive.com/products/tools/
See https://drive.google.com/drive/folders/1a7FyMOYgFc9UDhfsWUSCjyqDCvOrts2J?usp=sharing to import a makefile project and create a debug configuration.
## Briey SoC
As a demonstrator, a SoC named Briey is implemented in `src/main/scala/vexriscv/demo/Briey.scala`. This SoC is very similar to
the [Pinsec SOC](https://spinalhdl.github.io/SpinalDoc/spinal/lib/pinsec/hardware/):
@ -282,9 +296,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 -> 239 Mhz 3227 LUT 3410 FF
Cyclone V -> 125 Mhz 2,207 ALMs
Cyclone IV -> 112 Mhz 4,594 LUT 3,620
Artix 7 -> 232 Mhz 3042 LUT 3281 FF
Cyclone V -> 138 Mhz 2,179 ALMs
Cyclone IV -> 120 Mhz 4,333 LUT 3,167 FF
```
## Murax SoC
@ -337,18 +351,16 @@ Here are some timing and area measurements of the Murax SoC:
```
Murax interlocked stages (0.45 DMIPS/Mhz, 8 bits GPIO) ->
Artix 7 -> 299 Mhz 984 LUT 1186 FF
Cyclone V -> 175 Mhz 710 ALMs
Cyclone IV -> 137 Mhz 1,436 LUT 1,193 FF
iCE40 -> 48 Mhz 2337 LC (icestorm)
iCE40Ultra -> 20 Mhz 2337 LC (icestorm)
Artix 7 - > 301 Mhz 1032 LUT 1199 FF
Cyclone V -> 183 Mhz 736 ALMs
Cyclone IV -> 148 Mhz 1,481 LUT 1,204 FF
iCE40 -> 69 Mhz 2403 LC (nextpnr)
MuraxFast bypassed stages (0.65 DMIPS/Mhz, 8 bits GPIO) ->
Artix 7 -> 294 Mhz 1128 LUT 1219 FF
Cyclone V -> 165 Mhz 840 ALMs
Cyclone IV -> 141 Mhz 1,680 LUT 1,227 FF
iCE40 -> 48 Mhz 2702 LC (icestorm)
iCE40Ultra -> 22 Mhz 2702 LC (icestorm)
Artix 7 -> 321 Mhz 1198 LUT 1298 FF
Cyclone V -> 165 Mhz 873 ALMs
Cyclone IV -> 145 Mhz 1,691 LUT 1,239 FF
iCE40 -> 61 Mhz 2778 LC (nextpnr)
```
Some scripts to generate the SoC and call the icestorm toolchain can be found here: `scripts/Murax/`
@ -362,6 +374,18 @@ To run it :
sbt "test:runMain vexriscv.MuraxSim"
```
## Running Linux
A default configuration is located in src/main/scala/vexriscv/demo/Linux.scala
This file also contains
- The commands to compile the buildroot image
- How to run the Verilator simulation in interative mode
There is currently no SoC to run it on hardware, it is WIP. But the CPU simulation can already boot linux and run user space application (even python).
Note that VexRiscv can run Linux on both cache full and cache less design.
## Build the RISC-V GCC
A prebuild GCC toolsuite can be found here:
@ -653,18 +677,18 @@ This chapter describes plugins currently implemented.
This plugin implement the CPU frontend (instruction fetch) via a very simple and neutral memory interface going outside the CPU.
| Parameters | type | description |
| ------ | ----------- | ------ |
| catchAccessFault | Boolean | If an the read response specify an read error and this parameter is true, it will generate an CPU exception trap |
| resetVector | BigInt | Address of the program counter after the reset |
| cmdForkOnSecondStage | Boolean | By default jump have an asynchronous immediate effect on the program counter, which allow to reduce the branch penalties by one cycle but could reduce the FMax as it will combinatorialy drive the instruction bus address signal. To avoid this you can set this parameter to true, which will make the jump affecting the programm counter in a sequancial way, which will cut the combinatorial path but add one additional cycle of penalty when a jump occur. |
| cmdForkPersistence | Boolean | If this parameter is false, then request on the iBus can disappear/change before their completion. Which reduce area but isn't safe/supported by many arbitration/slaves. If you set this parameter to true, then the iBus cmd will stay until they are completed.
| compressedGen | Boolean | Enable RVC support |
| busLatencyMin | Int | Specify the minimal latency between the iBus.cmd and iBus.rsp, which will add the corresponding number of stages into the frontend to keep the IPC to 1.|
| injectorStage | Boolean | Add a stage between the frontend and the decode stage of the CPU to improve FMax. (busLatencyMin + injectorStage) should be at least two. |
| prediction | BranchPrediction | Can be set to NONE/STATIC/DYNAMIC/DYNAMIC_TARGET to specify the branch predictor implementation, see bellow for more descriptions |
| historyRamSizeLog2 | Int | Specify the number of entries in the direct mapped prediction cache of DYNAMIC/DYNAMIC_TARGET implementation. 2 pow historyRamSizeLog2 entries |
| ------ | ----------- | ------ |
| catchAccessFault | Boolean | When true, an instruction read response with read error asserted results in a CPU exception trap. |
| resetVector | BigInt | Address of the program counter after the reset. |
| cmdForkOnSecondStage | Boolean | When false, branches immediately update the program counter. This minimizes branch penalties but might reduce FMax because the instruction bus address signal is a combinatorial path. When true, this combinatorial path is removed and the program counter is updated one cycle after a branch is detected. While FMax may improve, an additional branch penalty will be incurred as well. |
| cmdForkPersistence | Boolean | When false, requests on the iBus can disappear/change before they are acknowledged. This reduces area but isn't safe/supported by many arbitration/slaves. When true, once initiated, iBus requests will stay until they are acknowledged. |
| compressedGen | Boolean | Enable RISC-V compressed instruction (RVC) support. |
| busLatencyMin | Int | Specifies the minimal latency between the iBus.cmd and iBus.rsp. A corresponding number of stages are added to the frontend to keep the IPC to 1.|
| injectorStage | Boolean | When true, a stage between the frontend and the decode stage of the CPU is added to improve FMax. (busLatencyMin + injectorStage) should be at least two. |
| prediction | BranchPrediction | Can be set to NONE/STATIC/DYNAMIC/DYNAMIC_TARGET to specify the branch predictor implementation. See below for more details. |
| historyRamSizeLog2 | Int | Specify the number of entries in the direct mapped prediction cache of DYNAMIC/DYNAMIC_TARGET implementation. 2 pow historyRamSizeLog2 entries. |
Here is the SimpleBus interface definition
Here is the SimpleBus interface definition:
```scala
case class IBusSimpleCmd() extends Bundle{
@ -695,9 +719,9 @@ case class IBusSimpleBus(interfaceKeepData : Boolean) extends Bundle with IMaste
Setting cmdForkPersistence and cmdForkOnSecondStage improves iBus cmd timings.
Note that bridges are implemented to convert this interface into AXI4 and Avalon
The iBusSimplePlugin includes bridges to convert from the IBusSimpleBus to AXI4, Avalon, and Wishbone interfaces.
The jump interface implemented by this plugin allow all other plugin to request jumps. The stage argument specify from which stage the jump is asked, which will allow the PcManagerSimplePlugin plugin to manage priorities between jump requests.
This plugin implements a jump interface that allows all other plugins to issue a jump:
```scala
trait JumpService{
@ -705,6 +729,8 @@ trait JumpService{
}
```
The stage argument specifies the stage from which the jump is asked. This allows the PcManagerSimplePlugin plugin to manage priorities between jump requests from
diffent stages.
#### IBusCachedPlugin
@ -712,35 +738,35 @@ Simple and light multi-way instruction cache.
| Parameters | type | description |
| ------ | ----------- | ------ |
| cacheSize | Int | Total storage capacity of the cache |
| bytePerLine | Int | Number of bytes per cache line |
| wayCount | Int | Number of cache ways |
| twoCycleRam | Boolean | Check the tags values in the decode stage instead of the fetch stage to relax timings |
| asyncTagMemory | Boolean | Read the cache tags in a asyncronus manner instead of syncronous one |
| addressWidth | Int | Address width, should be 32 |
| cpuDataWidth | Int | Cpu data width, should be 32 |
| memDataWidth | Int | Memory data width, could potentialy be something else than 32, but only 32 is currently tested |
| catchIllegalAccess | Boolean | Catch when a memory access is done on non valid memory address (MMU) |
| catchAccessFault | Boolean | Catch when the memeory bus is responding with an error |
| catchMemoryTranslationMiss | Boolean | Catch when the MMU miss a TLB |
| resetVector | BigInt | Address of the program counter after the reset |
| relaxedPcCalculation | Boolean | By default jump have an asynchronous immediate effect on the program counter, which allow to reduce the branch penalties by one cycle but could reduce the FMax as it will combinatorialy drive the instruction bus address signal. To avoid this you can set this parameter to true, which will make the jump affecting the programm counter in a sequancial way, which will cut the combinatorial path but add one additional cycle of penalty when a jump occur. |
| compressedGen | Boolean | Enable RVC support |
| prediction | BranchPrediction | Can be set to NONE/STATIC/DYNAMIC/DYNAMIC_TARGET to specify the branch predictor implementation, see bellow for more descriptions |
| resetVector | BigInt | Address of the program counter after the reset. |
| relaxedPcCalculation | Boolean | When false, branches immediately update the program counter. This minimizes branch penalties but might reduce FMax because the instruction bus address signal is a combinatorial path. When true, this combinatorial path is removed and the program counter is updated one cycle after a branch is detected. While FMax may improve, an additional branch penalty will be incurred as well. |
| prediction | BranchPrediction | Can be set to NONE/STATIC/DYNAMIC/DYNAMIC_TARGET to specify the branch predictor implementation. See below for more details. |
| historyRamSizeLog2 | Int | Specify the number of entries in the direct mapped prediction cache of DYNAMIC/DYNAMIC_TARGET implementation. 2 pow historyRamSizeLog2 entries |
| compressedGen | Boolean | Enable RISC-V compressed instruction (RVC) support. |
| config.cacheSize | Int | Total storage capacity of the cache in bytes. |
| config.bytePerLine | Int | Number of bytes per cache line |
| config.wayCount | Int | Number of cache ways |
| config.twoCycleRam | Boolean | Check the tags values in the decode stage instead of the fetch stage to relax timings |
| config.asyncTagMemory | Boolean | Read the cache tags in an asynchronous manner instead of syncronous one |
| config.addressWidth | Int | CPU address width. Should be 32 |
| config.cpuDataWidth | Int | CPU data width. Should be 32 |
| config.memDataWidth | Int | Memory data width. Could potentialy be something else than 32, but only 32 is currently tested |
| config.catchIllegalAccess | Boolean | Catch when a memory access is done on non-valid memory address (MMU) |
| config.catchAccessFault | Boolean | Catch when the memeory bus is responding with an error |
| config.catchMemoryTranslationMiss | Boolean | Catch when the MMU miss a TLB |
Note: If you enable the twoCycleRam option and if wayCount is bigger than one, then the register file plugin should be configured to read the regFile in a asynchronous manner.
Note: If you enable the twoCycleRam option and if wayCount is bigger than one, then the register file plugin should be configured to read the regFile in an asynchronous manner.
#### DecoderSimplePlugin
This plugin provides instruction decoding capabilities to others plugins.
For instance, for a given instruction, the pipeline hazard plugin needs to know if it uses the register file source 1/2 in order stall the pipeline until the hazard is gone.
For instance, for a given instruction, the pipeline hazard plugin needs to know if it uses the register file source 1/2 in order to stall the pipeline until the hazard is gone.
To provide this kind of information, each plugin which implements an instruction documents this kind of information to the DecoderSimplePlugin plugin.
| Parameters | type | description |
| ------ | ----------- | ------ |
| catchIllegalInstruction | Boolean | If set to true, instruction which have no decoding specification will generate a trap exception |
| catchIllegalInstruction | Boolean | When true, instructions that don't match a decoding specification will generate a trap exception |
Here is a usage example :
@ -752,11 +778,11 @@ Here is a usage example :
//Decoding specification when the 'key' pattern is recognized in the instruction
List(
IS_SIMD_ADD -> True,
REGFILE_WRITE_VALID -> True, //Enable the register file write
IS_SIMD_ADD -> True, //Inform the pipeline that the current instruction is a SIMD_ADD instruction
REGFILE_WRITE_VALID -> True, //Notify the hazard management unit that this instruction writes to the register file
BYPASSABLE_EXECUTE_STAGE -> True, //Notify the hazard management unit that the instruction result is already accessible in the EXECUTE stage (Bypass ready)
BYPASSABLE_MEMORY_STAGE -> True, //Same as above but for the memory stage
RS1_USE -> True, //Notify the hazard management unit that this instruction use the RS1 value
RS1_USE -> True, //Notify the hazard management unit that this instruction uses the RS1 value
RS2_USE -> True //Same than above but for RS2.
)
)
@ -853,7 +879,7 @@ The down side is that this predictor has a long combinatorial path coming from t
#### DBusSimplePlugin
This plugin implements the load and store instructions (LB/LH/LW/LBU/LHU/LWU/SB/SH/SW) via a simple and neutral memory bus going out of the CPU.
This plugin implements the load and store instructions (LB/LH/LW/LBU/LHU/LWU/SB/SH/SW) via a simple memory bus going out of the CPU.
| Parameters | type | description |
| ------ | ----------- | ------ |
@ -899,7 +925,7 @@ There is at least one cycle latency between a cmd and the corresponding rsp. The
#### DBusCachedPlugin
Single way cache implementation with a victim buffer. (Documentation is WIP)
Multi way cache implementation with writh-through and allocate on read strategy. (Documentation is WIP)
#### MulPlugin
@ -968,10 +994,10 @@ stage before jumping to mtvec.
Static memory translator plugin which allows one to specify which range of the memory addresses is IO mapped and shouldn't be cached.
#### MemoryTranslatorPlugin
#### MmuPlugin
Simple software refilled MMU implementation. Allows others plugins such as DBusCachedPlugin/IBusCachedPlugin to instanciate memory address translation ports. Each port has a small dedicated
fully associative TLB cache which is refilled from a larger software filled TLB cache via a query which looks up one entry per cycle.
Hardware refilled MMU implementation. Allows others plugins such as DBusCachedPlugin/IBusCachedPlugin to instanciate memory address translation ports. Each port has a small dedicated
fully associative TLB cache which is refilled automaticaly via a dbus access sharing.
#### DebugPlugin

View file

@ -4,19 +4,19 @@ lazy val root = (project in file(".")).
inThisBuild(List(
organization := "com.github.spinalhdl",
scalaVersion := "2.11.12",
version := "1.0.0"
version := "2.0.0"
)),
libraryDependencies ++= Seq(
// "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.2",
// "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.2",
"com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.3",
"com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.3",
"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")
)//.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

View file

@ -2,7 +2,8 @@ This example is for the
[Lattice iCE40HX-8K Breakout Board](http://www.latticesemi.com/Products/DevelopmentBoardsAndKits/iCE40HX8KBreakoutBoard.aspx).
An image of this board is shown below;
![img/iCE40HX8K-breakout-revA.png]
![`iCE40HX8K breakout revA`](img/iCE40HX8K-breakout-revA.png)
This board can be purchased for ~$USD 49 directly from Lattice and is supported
by the IceStorm
@ -20,7 +21,8 @@ mode. This requires removing jumper `J7` and putting the pair of jumpers on
This is shown in **Figure 5** of the
[iCE40HX-8K Breakout Board User Guide](http://www.latticesemi.com/view_document?document_id=50373).
which is also reproduced below;
![img/cram-programming-config.png]
![CRAM Programming Config](img/cram-programming-config.png)
Once your board is ready, you should follow the setup instructions at the
[top level](../../../README.md).

View file

@ -2,7 +2,8 @@ This example is for the
[Lattice iCE40HX-8K Breakout Board](http://www.latticesemi.com/Products/DevelopmentBoardsAndKits/iCE40HX8KBreakoutBoard.aspx).
An image of this board is shown below;
![img/iCE40HX8K-breakout-revA.png]
![`iCE40HX8K breakout revA`](img/iCE40HX8K-breakout-revA.png)
This board can be purchased for ~$USD 49 directly from Lattice and is supported
by the IceStorm
@ -20,7 +21,8 @@ mode. This requires removing jumper `J7` and putting the pair of jumpers on
This is shown in **Figure 5** of the
[iCE40HX-8K Breakout Board User Guide](http://www.latticesemi.com/view_document?document_id=50373).
which is also reproduced below;
![img/cram-programming-config.png]
![CRAM Programming Config](img/cram-programming-config.png)
Once your board is ready, you should follow the setup instructions at the
[top level](../../../README.md).

3
scripts/regression/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
verilator*
verilator
!verilator.mk

View file

@ -0,0 +1,7 @@
.ONESHELL:
include verilator.mk
include regression.mk

View file

@ -0,0 +1,45 @@
.ONESHELL:
regression_random:
cd ../..
export VEXRISCV_REGRESSION_CONFIG_COUNT=4
export VEXRISCV_REGRESSION_FREERTOS_COUNT=1
export VEXRISCV_REGRESSION_ZEPHYR_COUNT=4
export VEXRISCV_REGRESSION_THREAD_COUNT=1
sbt "testOnly vexriscv.TestIndividualFeatures"
regression_random_linux:
cd ../..
export VEXRISCV_REGRESSION_CONFIG_COUNT=3
export VEXRISCV_REGRESSION_CONFIG_LINUX_RATE=1.0
export VEXRISCV_REGRESSION_FREERTOS_COUNT=1
export VEXRISCV_REGRESSION_ZEPHYR_COUNT=2
export VEXRISCV_REGRESSION_THREAD_COUNT=1
sbt "testOnly vexriscv.TestIndividualFeatures"
regression_random_machine_os:
cd ../..
export VEXRISCV_REGRESSION_CONFIG_COUNT=15
export VEXRISCV_REGRESSION_CONFIG_LINUX_RATE=0.0
export VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE=1.0
export VEXRISCV_REGRESSION_FREERTOS_COUNT=1
export VEXRISCV_REGRESSION_ZEPHYR_COUNT=2
export VEXRISCV_REGRESSION_THREAD_COUNT=1
sbt "testOnly vexriscv.TestIndividualFeatures"
regression_random_baremetal:
cd ../..
export VEXRISCV_REGRESSION_CONFIG_COUNT=40
export VEXRISCV_REGRESSION_CONFIG_LINUX_RATE=0.0
export VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE=0.0
export VEXRISCV_REGRESSION_FREERTOS_COUNT=1
export VEXRISCV_REGRESSION_ZEPHYR_COUNT=no
export VEXRISCV_REGRESSION_THREAD_COUNT=1
sbt "testOnly vexriscv.TestIndividualFeatures"
regression_dhrystone:
cd ../..
sbt "testOnly vexriscv.DhrystoneBench"

View file

@ -0,0 +1,20 @@
.ONESHELL:
verilator/configure:
rm -rf verilator*
wget https://www.veripool.org/ftp/verilator-4.012.tgz
tar xvzf verilator*.t*gz
mv verilator-4.012 verilator
verilator/Makefile: verilator/configure
cd verilator
./configure
verilator/bin/verilator_bin: verilator/Makefile
cd verilator
make -j$(shell nproc)
rm -rf src/obj_dbg
rm -rf src/obj_opt
verilator_binary: verilator/bin/verilator_bin

151
src/main/c/common/ram.ld Executable file
View file

@ -0,0 +1,151 @@
OUTPUT_ARCH( "riscv" )
ENTRY( _start )
MEMORY
{
ram : ORIGIN = 0x80000000, LENGTH = 64k
}
SECTIONS
{
__stack_size = DEFINED(__stack_size) ? __stack_size : 2K;
.init :
{
KEEP (*(SORT_NONE(.init)))
}> ram
.text :
{
*(.text.unlikely .text.unlikely.*)
*(.text.startup .text.startup.*)
*(.text .text.*)
*(.gnu.linkonce.t.*)
*(.note.gnu.build-id)
} > ram
.fini :
{
KEEP (*(SORT_NONE(.fini)))
} > ram
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
. = ALIGN(4);
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
} > ram
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
} > ram
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
} > ram
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
} > ram
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
} > ram
.lalign :
{
. = ALIGN(4);
PROVIDE( _data_lma = . );
} > ram
.dalign :
{
. = ALIGN(4);
PROVIDE( _data = . );
} > ram
.data :
{
*(.rdata)
*(.rodata .rodata.*)
*(.gnu.linkonce.r.*)
*(.data .data.*)
*(.gnu.linkonce.d.*)
. = ALIGN(8);
PROVIDE( __global_pointer$ = . + 0x800 );
*(.sdata .sdata.*)
*(.gnu.linkonce.s.*)
. = ALIGN(8);
*(.srodata.cst16)
*(.srodata.cst8)
*(.srodata.cst4)
*(.srodata.cst2)
*(.srodata .srodata.*)
} >ram
. = ALIGN(4);
PROVIDE( _edata = . );
PROVIDE( edata = . );
PROVIDE( _fbss = . );
PROVIDE( __bss_start = . );
.bss :
{
*(.sbss*)
*(.gnu.linkonce.sb.*)
*(.bss .bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
} >ram
. = ALIGN(8);
PROVIDE( _end = . );
PROVIDE( end = . );
.stack :
{
PROVIDE( _heap_end = . );
. = __stack_size;
PROVIDE( _sp = . );
} > ram
}

View file

@ -0,0 +1,16 @@
RISCV_BIN ?= riscv64-unknown-elf-
RISCV_CC=${RISCV_BIN}gcc
RISCV_OBJCOPY=${RISCV_BIN}objcopy
RISCV_OBJDUMP=${RISCV_BIN}objdump
MARCH := rv32i
ifeq ($(MULDIV),yes)
MARCH := $(MARCH)M
endif
ifeq ($(COMPRESSED),yes)
MARCH := $(MARCH)AC
endif
CFLAGS += -march=$(MARCH) -mabi=ilp32 -DUSE_GP
LDFLAGS += -march=$(MARCH) -mabi=ilp32

View file

@ -0,0 +1,74 @@
LDFLAGS += -lc
CFLAGS += -I${STANDALONE}/include
ifeq ($(DEBUG),yes)
CFLAGS += -g3 -Og
endif
ifeq ($(DEBUG),no)
CFLAGS += -O3
endif
LDFLAGS += -nostdlib -lgcc -nostartfiles -ffreestanding -Wl,-Bstatic,-T,$(LDSCRIPT),-Map,$(OBJDIR)/$(PROJ_NAME).map,--print-memory-usage
OBJDIR ?= build
OBJS := $(SRCS)
OBJS := $(OBJS:.c=.o)
OBJS := $(OBJS:.cpp=.o)
OBJS := $(OBJS:.S=.o)
OBJS := $(OBJS:..=miaou)
OBJS := $(addprefix $(OBJDIR)/,$(OBJS))
all: $(OBJDIR)/$(PROJ_NAME).elf $(OBJDIR)/$(PROJ_NAME).hex $(OBJDIR)/$(PROJ_NAME).asm $(OBJDIR)/$(PROJ_NAME).bin
$(OBJDIR)/%.elf: $(OBJS) | $(OBJDIR)
$(RISCV_CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LIBS)
%.hex: %.elf
$(RISCV_OBJCOPY) -O ihex $^ $@
%.bin: %.elf
$(RISCV_OBJCOPY) -O binary $^ $@
%.v: %.elf
$(RISCV_OBJCOPY) -O verilog $^ $@
%.asm: %.elf
$(RISCV_OBJDUMP) -S -d $^ > $@
$(OBJDIR)/%.o: %.c
mkdir -p $(dir $@)
$(RISCV_CC) -c $(CFLAGS) $(INC) -o $@ $^
$(OBJDIR)/%.o: %.cpp
mkdir -p $(dir $@)
$(RISCV_CC) -c $(CFLAGS) $(INC) -o $@ $^
$(OBJDIR)/%.o: %.S
mkdir -p $(dir $@)
$(RISCV_CC) -c $(CFLAGS) -o $@ $^ -D__ASSEMBLY__=1
$(OBJDIR):
mkdir -p $@
clean:
rm -f $(OBJDIR)/$(PROJ_NAME).elf
rm -f $(OBJDIR)/$(PROJ_NAME).hex
rm -f $(OBJDIR)/$(PROJ_NAME).map
rm -f $(OBJDIR)/$(PROJ_NAME).v
rm -f $(OBJDIR)/$(PROJ_NAME).bin
rm -f $(OBJDIR)/$(PROJ_NAME).asm
find $(OBJDIR) -type f -name '*.o' -print0 | xargs -0 -r rm
.SECONDARY: $(OBJS)

6
src/main/c/emulator/.gitignore vendored Normal file
View file

@ -0,0 +1,6 @@
*.map
*.v
*.elf
*.o
*.hex
!*.bin

View file

@ -0,0 +1,620 @@
build/emulator.elf: file format elf32-littleriscv
Disassembly of section .init:
80000000 <_start>:
80000000: 00001117 auipc sp,0x1
80000004: 18810113 addi sp,sp,392 # 80001188 <_sp>
80000008: 00001517 auipc a0,0x1
8000000c: 8dc50513 addi a0,a0,-1828 # 800008e4 <__init_array_end>
80000010: 00001597 auipc a1,0x1
80000014: 8d458593 addi a1,a1,-1836 # 800008e4 <__init_array_end>
80000018: 00001617 auipc a2,0x1
8000001c: 97060613 addi a2,a2,-1680 # 80000988 <__bss_start>
80000020: 00c5fc63 bgeu a1,a2,80000038 <_start+0x38>
80000024: 00052283 lw t0,0(a0)
80000028: 0055a023 sw t0,0(a1)
8000002c: 00450513 addi a0,a0,4
80000030: 00458593 addi a1,a1,4
80000034: fec5e8e3 bltu a1,a2,80000024 <_start+0x24>
80000038: 00001517 auipc a0,0x1
8000003c: 95050513 addi a0,a0,-1712 # 80000988 <__bss_start>
80000040: 00001597 auipc a1,0x1
80000044: 94858593 addi a1,a1,-1720 # 80000988 <__bss_start>
80000048: 00b57863 bgeu a0,a1,80000058 <_start+0x58>
8000004c: 00052023 sw zero,0(a0)
80000050: 00450513 addi a0,a0,4
80000054: feb56ce3 bltu a0,a1,8000004c <_start+0x4c>
80000058: 7e4000ef jal ra,8000083c <__libc_init_array>
8000005c: 178000ef jal ra,800001d4 <init>
80000060: 00000097 auipc ra,0x0
80000064: 01408093 addi ra,ra,20 # 80000074 <done>
80000068: 00000513 li a0,0
8000006c: c30005b7 lui a1,0xc3000
80000070: 30200073 mret
80000074 <done>:
80000074: 0000006f j 80000074 <done>
80000078 <_init>:
80000078: 00008067 ret
8000007c <trapEntry>:
8000007c: 34011173 csrrw sp,mscratch,sp
80000080: 00112223 sw ra,4(sp)
80000084: 00312623 sw gp,12(sp)
80000088: 00412823 sw tp,16(sp)
8000008c: 00512a23 sw t0,20(sp)
80000090: 00612c23 sw t1,24(sp)
80000094: 00712e23 sw t2,28(sp)
80000098: 02812023 sw s0,32(sp)
8000009c: 02912223 sw s1,36(sp)
800000a0: 02a12423 sw a0,40(sp)
800000a4: 02b12623 sw a1,44(sp)
800000a8: 02c12823 sw a2,48(sp)
800000ac: 02d12a23 sw a3,52(sp)
800000b0: 02e12c23 sw a4,56(sp)
800000b4: 02f12e23 sw a5,60(sp)
800000b8: 05012023 sw a6,64(sp)
800000bc: 05112223 sw a7,68(sp)
800000c0: 05212423 sw s2,72(sp)
800000c4: 05312623 sw s3,76(sp)
800000c8: 05412823 sw s4,80(sp)
800000cc: 05512a23 sw s5,84(sp)
800000d0: 05612c23 sw s6,88(sp)
800000d4: 05712e23 sw s7,92(sp)
800000d8: 07812023 sw s8,96(sp)
800000dc: 07912223 sw s9,100(sp)
800000e0: 07a12423 sw s10,104(sp)
800000e4: 07b12623 sw s11,108(sp)
800000e8: 07c12823 sw t3,112(sp)
800000ec: 07d12a23 sw t4,116(sp)
800000f0: 07e12c23 sw t5,120(sp)
800000f4: 07f12e23 sw t6,124(sp)
800000f8: 2c4000ef jal ra,800003bc <trap>
800000fc: 00412083 lw ra,4(sp)
80000100: 00c12183 lw gp,12(sp)
80000104: 01012203 lw tp,16(sp)
80000108: 01412283 lw t0,20(sp)
8000010c: 01812303 lw t1,24(sp)
80000110: 01c12383 lw t2,28(sp)
80000114: 02012403 lw s0,32(sp)
80000118: 02412483 lw s1,36(sp)
8000011c: 02812503 lw a0,40(sp)
80000120: 02c12583 lw a1,44(sp)
80000124: 03012603 lw a2,48(sp)
80000128: 03412683 lw a3,52(sp)
8000012c: 03812703 lw a4,56(sp)
80000130: 03c12783 lw a5,60(sp)
80000134: 04012803 lw a6,64(sp)
80000138: 04412883 lw a7,68(sp)
8000013c: 04812903 lw s2,72(sp)
80000140: 04c12983 lw s3,76(sp)
80000144: 05012a03 lw s4,80(sp)
80000148: 05412a83 lw s5,84(sp)
8000014c: 05812b03 lw s6,88(sp)
80000150: 05c12b83 lw s7,92(sp)
80000154: 06012c03 lw s8,96(sp)
80000158: 06412c83 lw s9,100(sp)
8000015c: 06812d03 lw s10,104(sp)
80000160: 06c12d83 lw s11,108(sp)
80000164: 07012e03 lw t3,112(sp)
80000168: 07412e83 lw t4,116(sp)
8000016c: 07812f03 lw t5,120(sp)
80000170: 07c12f83 lw t6,124(sp)
80000174: 34011173 csrrw sp,mscratch,sp
80000178: 30200073 mret
Disassembly of section .text:
8000017c <putString>:
8000017c: ff010113 addi sp,sp,-16
80000180: 00812423 sw s0,8(sp)
80000184: 00112623 sw ra,12(sp)
80000188: 00050413 mv s0,a0
8000018c: 00054503 lbu a0,0(a0)
80000190: 00050a63 beqz a0,800001a4 <putString+0x28>
80000194: 00140413 addi s0,s0,1
80000198: 668000ef jal ra,80000800 <putC>
8000019c: 00044503 lbu a0,0(s0)
800001a0: fe051ae3 bnez a0,80000194 <putString+0x18>
800001a4: 00c12083 lw ra,12(sp)
800001a8: 00812403 lw s0,8(sp)
800001ac: 01010113 addi sp,sp,16
800001b0: 00008067 ret
800001b4 <setup_pmp>:
800001b4: 01f00793 li a5,31
800001b8: fff00713 li a4,-1
800001bc: 00000297 auipc t0,0x0
800001c0: 01428293 addi t0,t0,20 # 800001d0 <setup_pmp+0x1c>
800001c4: 30529073 csrw mtvec,t0
800001c8: 3b071073 csrw pmpaddr0,a4
800001cc: 3a079073 csrw pmpcfg0,a5
800001d0: 00008067 ret
800001d4 <init>:
800001d4: ff010113 addi sp,sp,-16
800001d8: 00112623 sw ra,12(sp)
800001dc: 00812423 sw s0,8(sp)
800001e0: 01f00793 li a5,31
800001e4: fff00713 li a4,-1
800001e8: 00000297 auipc t0,0x0
800001ec: 01428293 addi t0,t0,20 # 800001fc <init+0x28>
800001f0: 30529073 csrw mtvec,t0
800001f4: 3b071073 csrw pmpaddr0,a4
800001f8: 3a079073 csrw pmpcfg0,a5
800001fc: 80001437 lui s0,0x80001
80000200: 638000ef jal ra,80000838 <halInit>
80000204: 95840413 addi s0,s0,-1704 # 80000958 <_sp+0xfffff7d0>
80000208: 02a00513 li a0,42
8000020c: 00140413 addi s0,s0,1
80000210: 5f0000ef jal ra,80000800 <putC>
80000214: 00044503 lbu a0,0(s0)
80000218: fe051ae3 bnez a0,8000020c <init+0x38>
8000021c: 800007b7 lui a5,0x80000
80000220: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xffffeef4>
80000224: 30579073 csrw mtvec,a5
80000228: 800017b7 lui a5,0x80001
8000022c: 10878793 addi a5,a5,264 # 80001108 <_sp+0xffffff80>
80000230: 34079073 csrw mscratch,a5
80000234: 000017b7 lui a5,0x1
80000238: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80>
8000023c: 30079073 csrw mstatus,a5
80000240: 30405073 csrwi mie,0
80000244: c00007b7 lui a5,0xc0000
80000248: 34179073 csrw mepc,a5
8000024c: 0000b7b7 lui a5,0xb
80000250: 10078793 addi a5,a5,256 # b100 <__stack_size+0xa900>
80000254: 30279073 csrw medeleg,a5
80000258: 22200793 li a5,546
8000025c: 30379073 csrw mideleg,a5
80000260: 14305073 csrwi stval,0
80000264: 80001437 lui s0,0x80001
80000268: 97040413 addi s0,s0,-1680 # 80000970 <_sp+0xfffff7e8>
8000026c: 02a00513 li a0,42
80000270: 00140413 addi s0,s0,1
80000274: 58c000ef jal ra,80000800 <putC>
80000278: 00044503 lbu a0,0(s0)
8000027c: fe051ae3 bnez a0,80000270 <init+0x9c>
80000280: 00c12083 lw ra,12(sp)
80000284: 00812403 lw s0,8(sp)
80000288: 01010113 addi sp,sp,16
8000028c: 00008067 ret
80000290 <readRegister>:
80000290: 800017b7 lui a5,0x80001
80000294: 10878793 addi a5,a5,264 # 80001108 <_sp+0xffffff80>
80000298: 00251513 slli a0,a0,0x2
8000029c: 00f50533 add a0,a0,a5
800002a0: 00052503 lw a0,0(a0)
800002a4: 00008067 ret
800002a8 <writeRegister>:
800002a8: 800017b7 lui a5,0x80001
800002ac: 00251513 slli a0,a0,0x2
800002b0: 10878793 addi a5,a5,264 # 80001108 <_sp+0xffffff80>
800002b4: 00f50533 add a0,a0,a5
800002b8: 00b52023 sw a1,0(a0)
800002bc: 00008067 ret
800002c0 <redirectTrap>:
800002c0: ff010113 addi sp,sp,-16
800002c4: 00112623 sw ra,12(sp)
800002c8: 530000ef jal ra,800007f8 <stopSim>
800002cc: 343027f3 csrr a5,mtval
800002d0: 14379073 csrw stval,a5
800002d4: 341027f3 csrr a5,mepc
800002d8: 14179073 csrw sepc,a5
800002dc: 342027f3 csrr a5,mcause
800002e0: 14279073 csrw scause,a5
800002e4: 105027f3 csrr a5,stvec
800002e8: 34179073 csrw mepc,a5
800002ec: 00c12083 lw ra,12(sp)
800002f0: 01010113 addi sp,sp,16
800002f4: 00008067 ret
800002f8 <emulationTrapToSupervisorTrap>:
800002f8: 800007b7 lui a5,0x80000
800002fc: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xffffeef4>
80000300: 30579073 csrw mtvec,a5
80000304: 343027f3 csrr a5,mtval
80000308: 14379073 csrw stval,a5
8000030c: 342027f3 csrr a5,mcause
80000310: 14279073 csrw scause,a5
80000314: 14151073 csrw sepc,a0
80000318: 105027f3 csrr a5,stvec
8000031c: 34179073 csrw mepc,a5
80000320: 0035d793 srli a5,a1,0x3
80000324: 00459713 slli a4,a1,0x4
80000328: 02077713 andi a4,a4,32
8000032c: 1007f793 andi a5,a5,256
80000330: 00e7e7b3 or a5,a5,a4
80000334: ffffe737 lui a4,0xffffe
80000338: 6dd70713 addi a4,a4,1757 # ffffe6dd <_sp+0x7fffd555>
8000033c: 00e5f5b3 and a1,a1,a4
80000340: 00b7e7b3 or a5,a5,a1
80000344: 000015b7 lui a1,0x1
80000348: 88058593 addi a1,a1,-1920 # 880 <__stack_size+0x80>
8000034c: 00b7e7b3 or a5,a5,a1
80000350: 30079073 csrw mstatus,a5
80000354: 00008067 ret
80000358 <readWord>:
80000358: 00020737 lui a4,0x20
8000035c: 30072073 csrs mstatus,a4
80000360: 00000717 auipc a4,0x0
80000364: 01870713 addi a4,a4,24 # 80000378 <readWord+0x20>
80000368: 30571073 csrw mtvec,a4
8000036c: 00100693 li a3,1
80000370: 00052783 lw a5,0(a0)
80000374: 00000693 li a3,0
80000378: 00020737 lui a4,0x20
8000037c: 30073073 csrc mstatus,a4
80000380: 00068513 mv a0,a3
80000384: 00f5a023 sw a5,0(a1)
80000388: 00008067 ret
8000038c <writeWord>:
8000038c: 00020737 lui a4,0x20
80000390: 30072073 csrs mstatus,a4
80000394: 00000717 auipc a4,0x0
80000398: 01870713 addi a4,a4,24 # 800003ac <writeWord+0x20>
8000039c: 30571073 csrw mtvec,a4
800003a0: 00100793 li a5,1
800003a4: 00b52023 sw a1,0(a0)
800003a8: 00000793 li a5,0
800003ac: 00020737 lui a4,0x20
800003b0: 30073073 csrc mstatus,a4
800003b4: 00078513 mv a0,a5
800003b8: 00008067 ret
800003bc <trap>:
800003bc: fe010113 addi sp,sp,-32
800003c0: 00112e23 sw ra,28(sp)
800003c4: 00812c23 sw s0,24(sp)
800003c8: 00912a23 sw s1,20(sp)
800003cc: 01212823 sw s2,16(sp)
800003d0: 01312623 sw s3,12(sp)
800003d4: 342027f3 csrr a5,mcause
800003d8: 0807cc63 bltz a5,80000470 <trap+0xb4>
800003dc: 00200713 li a4,2
800003e0: 0ce78463 beq a5,a4,800004a8 <trap+0xec>
800003e4: 00900693 li a3,9
800003e8: 04d79463 bne a5,a3,80000430 <trap+0x74>
800003ec: 80001437 lui s0,0x80001
800003f0: 18840413 addi s0,s0,392 # 80001188 <_sp+0x0>
800003f4: fc442783 lw a5,-60(s0)
800003f8: 00100693 li a3,1
800003fc: fa842503 lw a0,-88(s0)
80000400: 2ed78463 beq a5,a3,800006e8 <trap+0x32c>
80000404: 2ee78e63 beq a5,a4,80000700 <trap+0x344>
80000408: 2a078c63 beqz a5,800006c0 <trap+0x304>
8000040c: 01812403 lw s0,24(sp)
80000410: 01c12083 lw ra,28(sp)
80000414: 01412483 lw s1,20(sp)
80000418: 01012903 lw s2,16(sp)
8000041c: 00c12983 lw s3,12(sp)
80000420: 02010113 addi sp,sp,32
80000424: 3d40006f j 800007f8 <stopSim>
80000428: 00777713 andi a4,a4,7
8000042c: 12f70c63 beq a4,a5,80000564 <trap+0x1a8>
80000430: 3c8000ef jal ra,800007f8 <stopSim>
80000434: 343027f3 csrr a5,mtval
80000438: 14379073 csrw stval,a5
8000043c: 341027f3 csrr a5,mepc
80000440: 14179073 csrw sepc,a5
80000444: 342027f3 csrr a5,mcause
80000448: 14279073 csrw scause,a5
8000044c: 105027f3 csrr a5,stvec
80000450: 34179073 csrw mepc,a5
80000454: 01c12083 lw ra,28(sp)
80000458: 01812403 lw s0,24(sp)
8000045c: 01412483 lw s1,20(sp)
80000460: 01012903 lw s2,16(sp)
80000464: 00c12983 lw s3,12(sp)
80000468: 02010113 addi sp,sp,32
8000046c: 00008067 ret
80000470: 0ff7f793 andi a5,a5,255
80000474: 00700713 li a4,7
80000478: fae79ce3 bne a5,a4,80000430 <trap+0x74>
8000047c: 02000793 li a5,32
80000480: 1447a073 csrs sip,a5
80000484: 08000793 li a5,128
80000488: 3047b073 csrc mie,a5
8000048c: 01c12083 lw ra,28(sp)
80000490: 01812403 lw s0,24(sp)
80000494: 01412483 lw s1,20(sp)
80000498: 01012903 lw s2,16(sp)
8000049c: 00c12983 lw s3,12(sp)
800004a0: 02010113 addi sp,sp,32
800004a4: 00008067 ret
800004a8: 341024f3 csrr s1,mepc
800004ac: 300025f3 csrr a1,mstatus
800004b0: 34302473 csrr s0,mtval
800004b4: 02f00613 li a2,47
800004b8: 07f47693 andi a3,s0,127
800004bc: 00c45713 srli a4,s0,0xc
800004c0: f6c684e3 beq a3,a2,80000428 <trap+0x6c>
800004c4: 07300613 li a2,115
800004c8: f6c694e3 bne a3,a2,80000430 <trap+0x74>
800004cc: 00377713 andi a4,a4,3
800004d0: 10f70c63 beq a4,a5,800005e8 <trap+0x22c>
800004d4: 00300793 li a5,3
800004d8: 10f70863 beq a4,a5,800005e8 <trap+0x22c>
800004dc: 00100993 li s3,1
800004e0: 03370463 beq a4,s3,80000508 <trap+0x14c>
800004e4: 314000ef jal ra,800007f8 <stopSim>
800004e8: 343027f3 csrr a5,mtval
800004ec: 14379073 csrw stval,a5
800004f0: 341027f3 csrr a5,mepc
800004f4: 14179073 csrw sepc,a5
800004f8: 342027f3 csrr a5,mcause
800004fc: 14279073 csrw scause,a5
80000500: 105027f3 csrr a5,stvec
80000504: 34179073 csrw mepc,a5
80000508: 00001737 lui a4,0x1
8000050c: 01445793 srli a5,s0,0x14
80000510: c0070693 addi a3,a4,-1024 # c00 <__stack_size+0x400>
80000514: 0ed7e263 bltu a5,a3,800005f8 <trap+0x23c>
80000518: c0270713 addi a4,a4,-1022
8000051c: 0cf77063 bgeu a4,a5,800005dc <trap+0x220>
80000520: fffff737 lui a4,0xfffff
80000524: 38070713 addi a4,a4,896 # fffff380 <_sp+0x7fffe1f8>
80000528: 00e787b3 add a5,a5,a4
8000052c: 00200713 li a4,2
80000530: 0cf76463 bltu a4,a5,800005f8 <trap+0x23c>
80000534: 2e4000ef jal ra,80000818 <rdtimeh>
80000538: 00050913 mv s2,a0
8000053c: 1c099e63 bnez s3,80000718 <trap+0x35c>
80000540: 00545413 srli s0,s0,0x5
80000544: 800017b7 lui a5,0x80001
80000548: 10878793 addi a5,a5,264 # 80001108 <_sp+0xffffff80>
8000054c: 07c47413 andi s0,s0,124
80000550: 00f40433 add s0,s0,a5
80000554: 01242023 sw s2,0(s0)
80000558: 00448493 addi s1,s1,4
8000055c: 34149073 csrw mepc,s1
80000560: ef5ff06f j 80000454 <trap+0x98>
80000564: 00d45713 srli a4,s0,0xd
80000568: 01245793 srli a5,s0,0x12
8000056c: 800016b7 lui a3,0x80001
80000570: 10868693 addi a3,a3,264 # 80001108 <_sp+0xffffff80>
80000574: 07c77713 andi a4,a4,124
80000578: 07c7f793 andi a5,a5,124
8000057c: 00d70733 add a4,a4,a3
80000580: 00d787b3 add a5,a5,a3
80000584: 00072703 lw a4,0(a4)
80000588: 0007a603 lw a2,0(a5)
8000058c: 00020537 lui a0,0x20
80000590: 30052073 csrs mstatus,a0
80000594: 00000517 auipc a0,0x0
80000598: 01850513 addi a0,a0,24 # 800005ac <trap+0x1f0>
8000059c: 30551073 csrw mtvec,a0
800005a0: 00100793 li a5,1
800005a4: 00072803 lw a6,0(a4)
800005a8: 00000793 li a5,0
800005ac: 00020537 lui a0,0x20
800005b0: 30053073 csrc mstatus,a0
800005b4: 18079663 bnez a5,80000740 <trap+0x384>
800005b8: 01b45793 srli a5,s0,0x1b
800005bc: 01c00513 li a0,28
800005c0: e6f568e3 bltu a0,a5,80000430 <trap+0x74>
800005c4: 80001537 lui a0,0x80001
800005c8: 00279793 slli a5,a5,0x2
800005cc: 8e450513 addi a0,a0,-1820 # 800008e4 <_sp+0xfffff75c>
800005d0: 00a787b3 add a5,a5,a0
800005d4: 0007a783 lw a5,0(a5)
800005d8: 00078067 jr a5
800005dc: 234000ef jal ra,80000810 <rdtime>
800005e0: 00050913 mv s2,a0
800005e4: f59ff06f j 8000053c <trap+0x180>
800005e8: 00f45993 srli s3,s0,0xf
800005ec: 01f9f993 andi s3,s3,31
800005f0: 013039b3 snez s3,s3
800005f4: f15ff06f j 80000508 <trap+0x14c>
800005f8: 200000ef jal ra,800007f8 <stopSim>
800005fc: 343027f3 csrr a5,mtval
80000600: 14379073 csrw stval,a5
80000604: 341027f3 csrr a5,mepc
80000608: 14179073 csrw sepc,a5
8000060c: 342027f3 csrr a5,mcause
80000610: 14279073 csrw scause,a5
80000614: 105027f3 csrr a5,stvec
80000618: 34179073 csrw mepc,a5
8000061c: f21ff06f j 8000053c <trap+0x180>
80000620: 01067463 bgeu a2,a6,80000628 <trap+0x26c>
80000624: 00080613 mv a2,a6
80000628: 00020537 lui a0,0x20
8000062c: 30052073 csrs mstatus,a0
80000630: 00000517 auipc a0,0x0
80000634: 01850513 addi a0,a0,24 # 80000648 <trap+0x28c>
80000638: 30551073 csrw mtvec,a0
8000063c: 00100793 li a5,1
80000640: 00c72023 sw a2,0(a4)
80000644: 00000793 li a5,0
80000648: 00020537 lui a0,0x20
8000064c: 30053073 csrc mstatus,a0
80000650: 80000737 lui a4,0x80000
80000654: 07c70713 addi a4,a4,124 # 8000007c <_sp+0xffffeef4>
80000658: 14079463 bnez a5,800007a0 <trap+0x3e4>
8000065c: 00545793 srli a5,s0,0x5
80000660: 07c7f793 andi a5,a5,124
80000664: 00d786b3 add a3,a5,a3
80000668: 0106a023 sw a6,0(a3)
8000066c: 00448493 addi s1,s1,4
80000670: 34149073 csrw mepc,s1
80000674: 30571073 csrw mtvec,a4
80000678: dddff06f j 80000454 <trap+0x98>
8000067c: 01064633 xor a2,a2,a6
80000680: fa9ff06f j 80000628 <trap+0x26c>
80000684: fac872e3 bgeu a6,a2,80000628 <trap+0x26c>
80000688: 00080613 mv a2,a6
8000068c: f9dff06f j 80000628 <trap+0x26c>
80000690: f9065ce3 bge a2,a6,80000628 <trap+0x26c>
80000694: 00080613 mv a2,a6
80000698: f91ff06f j 80000628 <trap+0x26c>
8000069c: f8c856e3 bge a6,a2,80000628 <trap+0x26c>
800006a0: 00080613 mv a2,a6
800006a4: f85ff06f j 80000628 <trap+0x26c>
800006a8: 01067633 and a2,a2,a6
800006ac: f7dff06f j 80000628 <trap+0x26c>
800006b0: 01066633 or a2,a2,a6
800006b4: f75ff06f j 80000628 <trap+0x26c>
800006b8: 01060633 add a2,a2,a6
800006bc: f6dff06f j 80000628 <trap+0x26c>
800006c0: fac42583 lw a1,-84(s0)
800006c4: 15c000ef jal ra,80000820 <setMachineTimerCmp>
800006c8: 08000793 li a5,128
800006cc: 3047a073 csrs mie,a5
800006d0: 02000793 li a5,32
800006d4: 1447b073 csrc sip,a5
800006d8: 341027f3 csrr a5,mepc
800006dc: 00478793 addi a5,a5,4
800006e0: 34179073 csrw mepc,a5
800006e4: d71ff06f j 80000454 <trap+0x98>
800006e8: 0ff57513 andi a0,a0,255
800006ec: 114000ef jal ra,80000800 <putC>
800006f0: 341027f3 csrr a5,mepc
800006f4: 00478793 addi a5,a5,4
800006f8: 34179073 csrw mepc,a5
800006fc: d59ff06f j 80000454 <trap+0x98>
80000700: 108000ef jal ra,80000808 <getC>
80000704: faa42423 sw a0,-88(s0)
80000708: 341027f3 csrr a5,mepc
8000070c: 00478793 addi a5,a5,4
80000710: 34179073 csrw mepc,a5
80000714: d41ff06f j 80000454 <trap+0x98>
80000718: 0e0000ef jal ra,800007f8 <stopSim>
8000071c: 343027f3 csrr a5,mtval
80000720: 14379073 csrw stval,a5
80000724: 341027f3 csrr a5,mepc
80000728: 14179073 csrw sepc,a5
8000072c: 342027f3 csrr a5,mcause
80000730: 14279073 csrw scause,a5
80000734: 105027f3 csrr a5,stvec
80000738: 34179073 csrw mepc,a5
8000073c: e05ff06f j 80000540 <trap+0x184>
80000740: 800007b7 lui a5,0x80000
80000744: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xffffeef4>
80000748: 30579073 csrw mtvec,a5
8000074c: 343027f3 csrr a5,mtval
80000750: 14379073 csrw stval,a5
80000754: 342027f3 csrr a5,mcause
80000758: 14279073 csrw scause,a5
8000075c: 14149073 csrw sepc,s1
80000760: 105027f3 csrr a5,stvec
80000764: 34179073 csrw mepc,a5
80000768: 0035d793 srli a5,a1,0x3
8000076c: 00459713 slli a4,a1,0x4
80000770: 02077713 andi a4,a4,32
80000774: 1007f793 andi a5,a5,256
80000778: 00e7e7b3 or a5,a5,a4
8000077c: ffffe737 lui a4,0xffffe
80000780: 6dd70713 addi a4,a4,1757 # ffffe6dd <_sp+0x7fffd555>
80000784: 00e5f5b3 and a1,a1,a4
80000788: 00001737 lui a4,0x1
8000078c: 00b7e7b3 or a5,a5,a1
80000790: 88070713 addi a4,a4,-1920 # 880 <__stack_size+0x80>
80000794: 00e7e7b3 or a5,a5,a4
80000798: 30079073 csrw mstatus,a5
8000079c: cb9ff06f j 80000454 <trap+0x98>
800007a0: 30571073 csrw mtvec,a4
800007a4: 343027f3 csrr a5,mtval
800007a8: 14379073 csrw stval,a5
800007ac: 342027f3 csrr a5,mcause
800007b0: 14279073 csrw scause,a5
800007b4: 14149073 csrw sepc,s1
800007b8: 105027f3 csrr a5,stvec
800007bc: 34179073 csrw mepc,a5
800007c0: 0035d793 srli a5,a1,0x3
800007c4: 00459713 slli a4,a1,0x4
800007c8: 02077713 andi a4,a4,32
800007cc: 1007f793 andi a5,a5,256
800007d0: 00e7e7b3 or a5,a5,a4
800007d4: ffffe737 lui a4,0xffffe
800007d8: 6dd70713 addi a4,a4,1757 # ffffe6dd <_sp+0x7fffd555>
800007dc: 00e5f5b3 and a1,a1,a4
800007e0: 00b7e5b3 or a1,a5,a1
800007e4: 000017b7 lui a5,0x1
800007e8: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80>
800007ec: 00f5e7b3 or a5,a1,a5
800007f0: 30079073 csrw mstatus,a5
800007f4: c61ff06f j 80000454 <trap+0x98>
800007f8 <stopSim>:
800007f8: fe002e23 sw zero,-4(zero) # fffffffc <_sp+0x7fffee74>
800007fc: 0000006f j 800007fc <stopSim+0x4>
80000800 <putC>:
80000800: fea02c23 sw a0,-8(zero) # fffffff8 <_sp+0x7fffee70>
80000804: 00008067 ret
80000808 <getC>:
80000808: ff802503 lw a0,-8(zero) # fffffff8 <_sp+0x7fffee70>
8000080c: 00008067 ret
80000810 <rdtime>:
80000810: fe002503 lw a0,-32(zero) # ffffffe0 <_sp+0x7fffee58>
80000814: 00008067 ret
80000818 <rdtimeh>:
80000818: fe402503 lw a0,-28(zero) # ffffffe4 <_sp+0x7fffee5c>
8000081c: 00008067 ret
80000820 <setMachineTimerCmp>:
80000820: fec00793 li a5,-20
80000824: fff00713 li a4,-1
80000828: 00e7a023 sw a4,0(a5)
8000082c: fea02423 sw a0,-24(zero) # ffffffe8 <_sp+0x7fffee60>
80000830: 00b7a023 sw a1,0(a5)
80000834: 00008067 ret
80000838 <halInit>:
80000838: 00008067 ret
8000083c <__libc_init_array>:
8000083c: ff010113 addi sp,sp,-16
80000840: 00000797 auipc a5,0x0
80000844: 0a478793 addi a5,a5,164 # 800008e4 <__init_array_end>
80000848: 00812423 sw s0,8(sp)
8000084c: 00000417 auipc s0,0x0
80000850: 09840413 addi s0,s0,152 # 800008e4 <__init_array_end>
80000854: 40f40433 sub s0,s0,a5
80000858: 00912223 sw s1,4(sp)
8000085c: 01212023 sw s2,0(sp)
80000860: 00112623 sw ra,12(sp)
80000864: 40245413 srai s0,s0,0x2
80000868: 00000493 li s1,0
8000086c: 00078913 mv s2,a5
80000870: 04849263 bne s1,s0,800008b4 <__libc_init_array+0x78>
80000874: 805ff0ef jal ra,80000078 <_init>
80000878: 00000797 auipc a5,0x0
8000087c: 06c78793 addi a5,a5,108 # 800008e4 <__init_array_end>
80000880: 00000417 auipc s0,0x0
80000884: 06440413 addi s0,s0,100 # 800008e4 <__init_array_end>
80000888: 40f40433 sub s0,s0,a5
8000088c: 40245413 srai s0,s0,0x2
80000890: 00000493 li s1,0
80000894: 00078913 mv s2,a5
80000898: 02849a63 bne s1,s0,800008cc <__libc_init_array+0x90>
8000089c: 00c12083 lw ra,12(sp)
800008a0: 00812403 lw s0,8(sp)
800008a4: 00412483 lw s1,4(sp)
800008a8: 00012903 lw s2,0(sp)
800008ac: 01010113 addi sp,sp,16
800008b0: 00008067 ret
800008b4: 00249793 slli a5,s1,0x2
800008b8: 00f907b3 add a5,s2,a5
800008bc: 0007a783 lw a5,0(a5)
800008c0: 00148493 addi s1,s1,1
800008c4: 000780e7 jalr a5
800008c8: fa9ff06f j 80000870 <__libc_init_array+0x34>
800008cc: 00249793 slli a5,s1,0x2
800008d0: 00f907b3 add a5,s2,a5
800008d4: 0007a783 lw a5,0(a5)
800008d8: 00148493 addi s1,s1,1
800008dc: 000780e7 jalr a5
800008e0: fb9ff06f j 80000898 <__libc_init_array+0x5c>

Binary file not shown.

View file

@ -0,0 +1,157 @@
:0200000480007A
:100000001711000013018118171500001305C58D85
:10001000971500009385458D171600001306069767
:1000200063FCC5008322050023A05500130545008D
:1000300093854500E3E8C5FE1715000013050595F7
:1000400097150000938585946378B50023200500FB
:1000500013054500E36CB5FEEF00407EEF0080170E
:10006000970000009380400113050000B70500C30E
:10007000730020306F0000006780000073110134AE
:10008000232211002326310023284100232A510076
:10009000232C6100232E7100232081022322910250
:1000A0002324A1022326B1022328C102232AD1023C
:1000B000232CE102232EF102232001052322110526
:1000C000232421052326310523284105232A510510
:1000D000232C6105232E71052320810723229107FC
:1000E0002324A1072326B1072328C107232AD107E8
:1000F000232CE107232EF107EF00402C8320410041
:100100008321C100032201018322410103238101D4
:100110008323C101032401028324410203258102B8
:100120008325C1020326010383264103032781039C
:100130008327C10303280104832841040329810480
:100140008329C104032A0105832A4105032B810564
:10015000832BC105032C0106832C4106032D810648
:10016000832DC106032E0107832E4107032F81072C
:0C017000832FC10773110134730020308D
:10017C00130101FF23248100232611001304050021
:10018C0003450500630A050013041400EF008066A4
:10019C0003450400E31A05FE8320C10003248100FB
:1001AC0013010101678000009307F0011307F0FFB2
:1001BC009702000093824201739052307310073BF8
:1001CC007390073A67800000130101FF232611008A
:1001DC00232481009307F0011307F0FF970200001E
:1001EC0093824201739052307310073B7390073A1D
:1001FC0037140080EF008063130484951305A0026C
:10020C0013041400EF00005F03450400E31A05FE1D
:10021C00B70700809387C70773905730B7170080D4
:10022C009387871073900734B7170000938707885C
:10023C007390073073504030B70700C07390173479
:10024C00B7B70000938707107390273093072022CD
:10025C0073903730735030143714008013040497A4
:10026C001305A00213041400EF00C058034504004A
:10027C00E31A05FE8320C100032481001301010150
:10028C0067800000B717008093878710131525002F
:10029C003305F5000325050067800000B7170080C3
:1002AC0013152500938787103305F5002320B5001F
:1002BC0067800000130101FF23261100EF0000539B
:1002CC00F327303473903714F327103473901714CA
:1002DC00F327203473902714F3275010739017349E
:1002EC008320C1001301010167800000B707008063
:1002FC009387C70773905730F327303473903714B4
:10030C00F32720347390271473101514F32750100F
:10031C007390173493D73500139745001377070262
:10032C0093F70710B3E7E70037E7FFFF1307D76D25
:10033C00B3F5E500B3E7B700B71500009385058862
:10034C00B3E7B700739007306780000037070200EF
:10035C0073200730170700001307870173105730FD
:10036C009306100083270500930600003707020050
:10037C00733007301385060023A0F500678000005A
:10038C003707020073200730170700001307870197
:10039C0073105730930710002320B500930700000B
:1003AC0037070200733007301385070067800000A1
:1003BC00130101FE232E1100232C8100232A91000E
:1003CC002328210123263101F327203463CC07088D
:1003DC00130720006384E70C930690006394D70402
:1003EC003714008013048418832744FC93061000F0
:1003FC00032584FA6384D72E638EE72E638C072A39
:10040C00032481018320C1018324410103290101BB
:10041C008329C100130101026F00403D137777005F
:10042C00630CF712EF00803CF327303473903714D1
:10043C00F327103473901714F32720347390271478
:10044C00F3275010739017348320C10103248101CA
:10045C0083244101032901018329C10013010102F5
:10046C006780000093F7F70F13077000E39CE7FA1F
:10047C009307000273A047149307000873B047302A
:10048C008320C1010324810183244101032901013B
:10049C008329C1001301010267800000F32410348A
:1004AC00F3250030732430341306F0029376F407EE
:1004BC001357C400E384C6F613063007E394C6F65C
:1004CC0013773700630CF710930730006308F710AD
:1004DC009309100063043703EF004031F3273034E5
:1004EC0073903714F327103473901714F3272034B8
:1004FC0073902714F327501073901734371700009C
:10050C0093574401930607C063E2D70E130727C025
:10051C006370F70C37F7FFFF13070738B387E70053
:10052C00130720006364F70CEF00402E130905003D
:10053C00639E091C13545400B717008093878710CF
:10054C001374C4073304F40023202401938444005F
:10055C00739014346FF05FEF1357D400935724014A
:10056C00B7160080938686101377C70793F7C707D3
:10057C003307D700B387D7000327070003A607006C
:10058C00370502007320053017050000130585019F
:10059C0073105530930710000328070093070000D1
:1005AC003705020073300530639607189357B40172
:1005BC001305C001E368F5E6371500809397270013
:1005CC001305458EB387A70083A707006780070034
:1005DC00EF004023130905006FF09FF59359F400C9
:1005EC0093F9F901B33930016FF05FF1EF0000209E
:1005FC00F327303473903714F32710347390171497
:10060C00F327203473902714F3275010739017346A
:10061C006FF01FF263740601130608003705020021
:10062C007320053017050000130585017310553034
:10063C00930710002320C700930700003705020022
:10064C0073300530370700801307C707639407140E
:10065C009357540093F7C707B386D70023A006011E
:10066C009384440073901434731057306FF0DFDDB3
:10067C00334606016FF09FFAE372C8FA13060800BE
:10068C006FF0DFF9E35C06F9130608006FF01FF951
:10069C00E356C8F8130608006FF05FF833760601CE
:1006AC006FF0DFF7336606016FF05FF73306060174
:1006BC006FF0DFF68325C4FAEF00C015930700082E
:1006CC0073A047309307000273B04714F32710341C
:1006DC0093874700739017346FF01FD71375F50F7E
:1006EC00EF004011F32710349387470073901734B1
:1006FC006FF09FD5EF0080102324A4FAF327103459
:10070C0093874700739017346FF01FD4EF00000EDF
:10071C00F327303473903714F32710347390171475
:10072C00F327203473902714F32750107390173449
:10073C006FF05FE0B70700809387C707739057305F
:10074C00F327303473903714F32720347390271425
:10075C0073901414F32750107390173493D73500FB
:10076C00139745001377070293F70710B3E7E700D9
:10077C0037E7FFFF1307D76DB3F5E5003717000018
:10078C00B3E7B70013070788B3E7E70073900730A8
:10079C006FF09FCB73105730F327303473903714AE
:1007AC00F32720347390271473901414F3275010EC
:1007BC007390173493D735001397450013770702BE
:1007CC0093F70710B3E7E70037E7FFFF1307D76D81
:1007DC00B3F5E500B3E5B700B717000093870788BA
:1007EC00B3E7F500739007306FF01FC6232E00FEA1
:1007FC006F000000232CA0FE67800000032580FF03
:10080C0067800000032500FE67800000032540FE82
:10081C00678000009307C0FE1307F0FF23A0E700DA
:10082C002324A0FE23A0B70067800000678000008F
:10083C00130101FF970700009387470A23248100C7
:10084C0017040000130484093304F440232291009C
:10085C00232021012326110013542440930400006B
:10086C001389070063928404EFF05F809707000000
:10087C009387C70617040000130444063304F4409E
:10088C00135424409304000013890700639A8402D4
:10089C008320C1000324810083244100032901002B
:1008AC00130101016780000093972400B307F9003E
:1008BC0083A7070093841400E78007006FF09FFA6A
:1008CC0093972400B307F90083A7070093841400BF
:0808DC00E78007006FF09FFBAD
:1008E400B8060080280600803004008030040080B0
:1008F4007C060080300400803004008030040080D6
:10090400B006008030040080300400803004008091
:10091400A806008030040080300400803004008089
:100924009C06008030040080300400803004008085
:100934009006008030040080300400803004008081
:10094400840600803004008030040080300400807D
:10095400200600802A2A2A20566578526973637615
:100964002042494F53202A2A2A0A00002A2A2A20F0
:1009740053757065727669736F72202A2A2A0A0089
:04098400000000006F
:040000058000000077
:00000001FF

17
src/main/c/emulator/makefile Executable file
View file

@ -0,0 +1,17 @@
PROJ_NAME=emulator
DEBUG=no
MULDIV=no
COMPRESSED=no
STANDALONE = ..
SRCS = $(wildcard src/*.c) \
$(wildcard src/*.cpp) \
$(wildcard src/*.S)
LDSCRIPT = ${STANDALONE}/common/ram.ld
include ${STANDALONE}/common/riscv64-unknown-elf.mk
include ${STANDALONE}/common/standalone.mk

View file

@ -0,0 +1,9 @@
#ifndef CONFIG_H
#define CONFIG_H
//#define QEMU
#define SIM
#define OS_CALL 0xC0000000
#define DTB 0xC3000000
#endif

View file

@ -0,0 +1,148 @@
#include "hal.h"
#include "config.h"
#ifdef SIM
void stopSim(){
*((volatile uint32_t*) 0xFFFFFFFC) = 0;
while(1);
}
void putC(char c){
*((volatile uint32_t*) 0xFFFFFFF8) = c;
}
int32_t getC(){
return *((volatile int32_t*) 0xFFFFFFF8);
}
uint32_t rdtime(){
return *((volatile uint32_t*) 0xFFFFFFE0);
}
uint32_t rdtimeh(){
return *((volatile uint32_t*) 0xFFFFFFE4);
}
void setMachineTimerCmp(uint32_t low, uint32_t high){
volatile uint32_t* base = (volatile uint32_t*) 0xFFFFFFE8;
base[1] = 0xffffffff;
base[0] = low;
base[1] = high;
}
void halInit(){
// putC('*');
// putC('*');
// putC('*');
// while(1){
// int32_t c = getC();
// if(c > 0) putC(c);
// }
}
#endif
#ifdef QEMU
#define VIRT_CLINT 0x2000000
#define SIFIVE_TIMECMP_BASE (VIRT_CLINT + 0x4000)
#define SIFIVE_TIME_BASE (VIRT_CLINT + 0xBFF8)
#define NS16550A_UART0_CTRL_ADDR 0x10000000
#define UART0_CLOCK_FREQ 32000000
#define UART0_BAUD_RATE 115200
enum {
UART_RBR = 0x00, /* Receive Buffer Register */
UART_THR = 0x00, /* Transmit Hold Register */
UART_IER = 0x01, /* Interrupt Enable Register */
UART_DLL = 0x00, /* Divisor LSB (LCR_DLAB) */
UART_DLM = 0x01, /* Divisor MSB (LCR_DLAB) */
UART_FCR = 0x02, /* FIFO Control Register */
UART_LCR = 0x03, /* Line Control Register */
UART_MCR = 0x04, /* Modem Control Register */
UART_LSR = 0x05, /* Line Status Register */
UART_MSR = 0x06, /* Modem Status Register */
UART_SCR = 0x07, /* Scratch Register */
UART_LCR_DLAB = 0x80, /* Divisor Latch Bit */
UART_LCR_8BIT = 0x03, /* 8-bit */
UART_LCR_PODD = 0x08, /* Parity Odd */
UART_LSR_DA = 0x01, /* Data Available */
UART_LSR_OE = 0x02, /* Overrun Error */
UART_LSR_PE = 0x04, /* Parity Error */
UART_LSR_FE = 0x08, /* Framing Error */
UART_LSR_BI = 0x10, /* Break indicator */
UART_LSR_RE = 0x20, /* THR is empty */
UART_LSR_RI = 0x40, /* THR is empty and line is idle */
UART_LSR_EF = 0x80, /* Erroneous data in FIFO */
};
static volatile uint8_t *uart;
static void ns16550a_init()
{
uart = (uint8_t *)(void *)(NS16550A_UART0_CTRL_ADDR);
uint32_t uart_freq = (UART0_CLOCK_FREQ);
uint32_t baud_rate = (UART0_BAUD_RATE);
uint32_t divisor = uart_freq / (16 * baud_rate);
uart[UART_LCR] = UART_LCR_DLAB;
uart[UART_DLL] = divisor & 0xff;
uart[UART_DLM] = (divisor >> 8) & 0xff;
uart[UART_LCR] = UART_LCR_PODD | UART_LCR_8BIT;
}
//static int ns16550a_getchar()
//{
// if (uart[UART_LSR] & UART_LSR_DA) {
// return uart[UART_RBR];
// } else {
// return -1;
// }
//}
//
//static int ns16550a_putchar(int ch)
//{
// while ((uart[UART_LSR] & UART_LSR_RI) == 0);
// return uart[UART_THR] = ch & 0xff;
//}
void stopSim(){
while(1);
}
void putC(char ch){
while ((uart[UART_LSR] & UART_LSR_RI) == 0);
uart[UART_THR] = ch & 0xff;
}
int32_t getC(){
if (uart[UART_LSR] & UART_LSR_DA) {
return uart[UART_RBR];
} else {
return -1;
}
}
uint32_t rdtime(){
return *((volatile uint32_t*) SIFIVE_TIME_BASE);
}
uint32_t rdtimeh(){
return *((volatile uint32_t*) (SIFIVE_TIME_BASE + 4));
}
void setMachineTimerCmp(uint32_t low, uint32_t high){
volatile uint32_t* base = (volatile uint32_t*) SIFIVE_TIMECMP_BASE;
base[1] = 0xffffffff;
base[0] = low;
base[1] = high;
}
void halInit(){
ns16550a_init();
}
#endif

View file

@ -0,0 +1,25 @@
#ifndef HAL_H
#define HAL_H
#include <stdint.h>
#define SBI_SET_TIMER 0
#define SBI_CONSOLE_PUTCHAR 1
#define SBI_CONSOLE_GETCHAR 2
#define SBI_CLEAR_IPI 3
#define SBI_SEND_IPI 4
#define SBI_REMOTE_FENCE_I 5
#define SBI_REMOTE_SFENCE_VMA 6
#define SBI_REMOTE_SFENCE_VMA_ASID 7
#define SBI_SHUTDOWN 8
void halInit();
void stopSim();
void putC(char c);
int32_t getC();
uint32_t rdtime();
uint32_t rdtimeh();
void setMachineTimerCmp(uint32_t low, uint32_t high);
#endif

288
src/main/c/emulator/src/main.c Executable file
View file

@ -0,0 +1,288 @@
#include <stdint.h>
#include "riscv.h"
#include "config.h"
#include "hal.h"
extern const uint32_t _sp;
extern void trapEntry();
extern void emulationTrap();
void putString(char* s){
while(*s){
putC(*s);
s++;
}
}
//Affect mtvec
void setup_pmp(void)
{
// Set up a PMP to permit access to all of memory.
// Ignore the illegal-instruction trap if PMPs aren't supported.
uintptr_t pmpc = PMP_NAPOT | PMP_R | PMP_W | PMP_X;
asm volatile ("la t0, 1f\n\t"
"csrw mtvec, t0\n\t"
"csrw pmpaddr0, %1\n\t"
"csrw pmpcfg0, %0\n\t"
".align 2\n\t"
"1:"
: : "r" (pmpc), "r" (-1UL) : "t0");
}
void init() {
setup_pmp();
halInit();
putString("*** VexRiscv BIOS ***\n");
uint32_t sp = (uint32_t) (&_sp);
csr_write(mtvec, trapEntry);
csr_write(mscratch, sp -32*4);
csr_write(mstatus, 0x0800 | MSTATUS_MPIE);
csr_write(mie, 0);
csr_write(mepc, OS_CALL);
//In future it would probably need to manage missaligned stuff, now it will stop the simulation
csr_write(medeleg, MEDELEG_INSTRUCTION_PAGE_FAULT | MEDELEG_LOAD_PAGE_FAULT | MEDELEG_STORE_PAGE_FAULT | MEDELEG_USER_ENVIRONNEMENT_CALL);
csr_write(mideleg, MIDELEG_SUPERVISOR_TIMER | MIDELEG_SUPERVISOR_EXTERNAL | MIDELEG_SUPERVISOR_SOFTWARE);
csr_write(sbadaddr, 0); //Used to avoid simulation missmatch
putString("*** Supervisor ***\n");
}
int readRegister(uint32_t id){
unsigned int sp = (unsigned int) (&_sp);
return ((int*) sp)[id-32];
}
void writeRegister(uint32_t id, int value){
uint32_t sp = (uint32_t) (&_sp);
((uint32_t*) sp)[id-32] = value;
}
//Currently, this should not happen, unless kernel things are going wrong
void redirectTrap(){
stopSim();
csr_write(sbadaddr, csr_read(mbadaddr));
csr_write(sepc, csr_read(mepc));
csr_write(scause, csr_read(mcause));
csr_write(mepc, csr_read(stvec));
}
void emulationTrapToSupervisorTrap(uint32_t sepc, uint32_t mstatus){
csr_write(mtvec, trapEntry);
csr_write(sbadaddr, csr_read(mbadaddr));
csr_write(scause, csr_read(mcause));
csr_write(sepc, sepc);
csr_write(mepc, csr_read(stvec));
csr_write(mstatus,
(mstatus & ~(MSTATUS_SPP | MSTATUS_MPP | MSTATUS_SIE | MSTATUS_SPIE))
| ((mstatus >> 3) & MSTATUS_SPP)
| (0x0800 | MSTATUS_MPIE)
| ((mstatus & MSTATUS_SIE) << 4)
);
}
#define max(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; })
#define min(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a < _b ? _a : _b; })
//Will modify MTVEC
int32_t readWord(uint32_t address, int32_t *data){
int32_t result, tmp;
int32_t failed;
__asm__ __volatile__ (
" li %[tmp], 0x00020000\n"
" csrs mstatus, %[tmp]\n"
" la %[tmp], 1f\n"
" csrw mtvec, %[tmp]\n"
" li %[failed], 1\n"
" lw %[result], 0(%[address])\n"
" li %[failed], 0\n"
"1:\n"
" li %[tmp], 0x00020000\n"
" csrc mstatus, %[tmp]\n"
: [result]"=&r" (result), [failed]"=&r" (failed), [tmp]"=&r" (tmp)
: [address]"r" (address)
: "memory"
);
*data = result;
return failed;
}
//Will modify MTVEC
int32_t writeWord(uint32_t address, int32_t data){
int32_t result, tmp;
int32_t failed;
__asm__ __volatile__ (
" li %[tmp], 0x00020000\n"
" csrs mstatus, %[tmp]\n"
" la %[tmp], 1f\n"
" csrw mtvec, %[tmp]\n"
" li %[failed], 1\n"
" sw %[data], 0(%[address])\n"
" li %[failed], 0\n"
"1:\n"
" li %[tmp], 0x00020000\n"
" csrc mstatus, %[tmp]\n"
: [failed]"=&r" (failed), [tmp]"=&r" (tmp)
: [address]"r" (address), [data]"r" (data)
: "memory"
);
return failed;
}
void trap(){
int32_t cause = csr_read(mcause);
if(cause < 0){ //interrupt
switch(cause & 0xFF){
case CAUSE_MACHINE_TIMER:{
csr_set(sip, MIP_STIP);
csr_clear(mie, MIE_MTIE);
}break;
default: redirectTrap(); break;
}
} else { //exception
switch(cause){
case CAUSE_ILLEGAL_INSTRUCTION:{
uint32_t mepc = csr_read(mepc);
uint32_t mstatus = csr_read(mstatus);
#ifdef SIM
uint32_t instruction = csr_read(mbadaddr);
#endif
#ifdef QEMU
uint32_t instruction = 0;
uint32_t i;
if (mepc & 2) {
readWord(mepc - 2, &i);
i >>= 16;
if (i & 3 == 3) {
uint32_t u32Buf;
readWord(mepc+2, &u32Buf);
i |= u32Buf << 16;
}
} else {
readWord(mepc, &i);
}
instruction = i;
csr_write(mtvec, trapEntry); //Restore mtvec
#endif
uint32_t opcode = instruction & 0x7F;
uint32_t funct3 = (instruction >> 12) & 0x7;
switch(opcode){
case 0x2F: //Atomic
switch(funct3){
case 0x2:{
uint32_t sel = instruction >> 27;
uint32_t addr = readRegister((instruction >> 15) & 0x1F);
int32_t src = readRegister((instruction >> 20) & 0x1F);
uint32_t rd = (instruction >> 7) & 0x1F;
int32_t readValue;
if(readWord(addr, &readValue)){
emulationTrapToSupervisorTrap(mepc, mstatus);
return;
}
int writeValue;
switch(sel){
case 0x0: writeValue = src + readValue; break;
case 0x1: writeValue = src; break;
//LR SC done in hardware (cheap), and require to keep track of context switches
// case 0x2:{ //LR
// }break;
// case 0x3:{ //SC
// }break;
case 0x4: writeValue = src ^ readValue; break;
case 0xC: writeValue = src & readValue; break;
case 0x8: writeValue = src | readValue; break;
case 0x10: writeValue = min(src, readValue); break;
case 0x14: writeValue = max(src, readValue); break;
case 0x18: writeValue = min((unsigned int)src, (unsigned int)readValue); break;
case 0x1C: writeValue = max((unsigned int)src, (unsigned int)readValue); break;
default: redirectTrap(); return; break;
}
if(writeWord(addr, writeValue)){
emulationTrapToSupervisorTrap(mepc, mstatus);
return;
}
writeRegister(rd, readValue);
csr_write(mepc, mepc + 4);
csr_write(mtvec, trapEntry); //Restore mtvec
}break;
default: redirectTrap(); break;
} break;
case 0x73:{
//CSR
uint32_t input = (instruction & 0x4000) ? ((instruction >> 15) & 0x1F) : readRegister((instruction >> 15) & 0x1F);;
uint32_t clear, set;
uint32_t write;
switch (funct3 & 0x3) {
case 0: redirectTrap(); break;
case 1: clear = ~0; set = input; write = 1; break;
case 2: clear = 0; set = input; write = ((instruction >> 15) & 0x1F) != 0; break;
case 3: clear = input; set = 0; write = ((instruction >> 15) & 0x1F) != 0; break;
}
uint32_t csrAddress = instruction >> 20;
uint32_t old;
switch(csrAddress){
case RDCYCLE :
case RDINSTRET:
case RDTIME : old = rdtime(); break;
case RDCYCLEH :
case RDINSTRETH:
case RDTIMEH : old = rdtimeh(); break;
default: redirectTrap(); break;
}
if(write) {
uint32_t newValue = (old & ~clear) | set;
switch(csrAddress){
default: redirectTrap(); break;
}
}
writeRegister((instruction >> 7) & 0x1F, old);
csr_write(mepc, mepc + 4);
}break;
default: redirectTrap(); break;
}
}break;
case CAUSE_SCALL:{
uint32_t which = readRegister(17);
uint32_t a0 = readRegister(10);
uint32_t a1 = readRegister(11);
uint32_t a2 = readRegister(12);
switch(which){
case SBI_CONSOLE_PUTCHAR:{
putC(a0);
csr_write(mepc, csr_read(mepc) + 4);
}break;
case SBI_CONSOLE_GETCHAR:{
writeRegister(10, getC()); //no char
csr_write(mepc, csr_read(mepc) + 4);
}break;
case SBI_SET_TIMER:{
setMachineTimerCmp(a0, a1);
csr_set(mie, MIE_MTIE);
csr_clear(sip, MIP_STIP);
csr_write(mepc, csr_read(mepc) + 4);
}break;
default: stopSim(); break;
}
}break;
default: redirectTrap(); break;
}
}
}

View file

@ -0,0 +1,133 @@
#ifndef RISCV_H
#define RISCV_H
#define CAUSE_ILLEGAL_INSTRUCTION 2
#define CAUSE_MACHINE_TIMER 7
#define CAUSE_SCALL 9
#define MEDELEG_INSTRUCTION_PAGE_FAULT (1 << 12)
#define MEDELEG_LOAD_PAGE_FAULT (1 << 13)
#define MEDELEG_STORE_PAGE_FAULT (1 << 15)
#define MEDELEG_USER_ENVIRONNEMENT_CALL (1 << 8)
#define MIDELEG_SUPERVISOR_SOFTWARE (1 << 1)
#define MIDELEG_SUPERVISOR_TIMER (1 << 5)
#define MIDELEG_SUPERVISOR_EXTERNAL (1 << 9)
#define MIE_MTIE (1 << 7)
#define MIP_STIP (1 << 5)
#define MSTATUS_UIE 0x00000001
#define MSTATUS_SIE 0x00000002
#define MSTATUS_HIE 0x00000004
#define MSTATUS_MIE 0x00000008
#define MSTATUS_UPIE 0x00000010
#define MSTATUS_SPIE 0x00000020
#define MSTATUS_HPIE 0x00000040
#define MSTATUS_MPIE 0x00000080
#define MSTATUS_SPP 0x00000100
#define MSTATUS_HPP 0x00000600
#define MSTATUS_MPP 0x00001800
#define MSTATUS_FS 0x00006000
#define MSTATUS_XS 0x00018000
#define MSTATUS_MPRV 0x00020000
#define MSTATUS_SUM 0x00040000
#define MSTATUS_MXR 0x00080000
#define MSTATUS_TVM 0x00100000
#define MSTATUS_TW 0x00200000
#define MSTATUS_TSR 0x00400000
#define MSTATUS32_SD 0x80000000
#define MSTATUS_UXL 0x0000000300000000
#define MSTATUS_SXL 0x0000000C00000000
#define MSTATUS64_SD 0x8000000000000000
#define SSTATUS_UIE 0x00000001
#define SSTATUS_SIE 0x00000002
#define SSTATUS_UPIE 0x00000010
#define SSTATUS_SPIE 0x00000020
#define SSTATUS_SPP 0x00000100
#define SSTATUS_FS 0x00006000
#define SSTATUS_XS 0x00018000
#define SSTATUS_SUM 0x00040000
#define SSTATUS_MXR 0x00080000
#define SSTATUS32_SD 0x80000000
#define SSTATUS_UXL 0x0000000300000000
#define SSTATUS64_SD 0x8000000000000000
#define PMP_R 0x01
#define PMP_W 0x02
#define PMP_X 0x04
#define PMP_A 0x18
#define PMP_L 0x80
#define PMP_SHIFT 2
#define PMP_TOR 0x08
#define PMP_NA4 0x10
#define PMP_NAPOT 0x18
#define RDCYCLE 0xC00 //Read-only cycle Cycle counter for RDCYCLE instruction.
#define RDTIME 0xC01 //Read-only time Timer for RDTIME instruction.
#define RDINSTRET 0xC02 //Read-only instret Instructions-retired counter for RDINSTRET instruction.
#define RDCYCLEH 0xC80 //Read-only cycleh Upper 32 bits of cycle, RV32I only.
#define RDTIMEH 0xC81 //Read-only timeh Upper 32 bits of time, RV32I only.
#define RDINSTRETH 0xC82 //Read-only instreth Upper 32 bits of instret, RV32I only.
#define csr_swap(csr, val) \
({ \
unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__ ("csrrw %0, " #csr ", %1" \
: "=r" (__v) : "rK" (__v)); \
__v; \
})
#define csr_read(csr) \
({ \
register unsigned long __v; \
__asm__ __volatile__ ("csrr %0, " #csr \
: "=r" (__v)); \
__v; \
})
#define csr_write(csr, val) \
({ \
unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__ ("csrw " #csr ", %0" \
: : "rK" (__v)); \
})
#define csr_read_set(csr, val) \
({ \
unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__ ("csrrs %0, " #csr ", %1" \
: "=r" (__v) : "rK" (__v)); \
__v; \
})
#define csr_set(csr, val) \
({ \
unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__ ("csrs " #csr ", %0" \
: : "rK" (__v)); \
})
#define csr_read_clear(csr, val) \
({ \
unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__ ("csrrc %0, " #csr ", %1" \
: "=r" (__v) : "rK" (__v)); \
__v; \
})
#define csr_clear(csr, val) \
({ \
unsigned long __v = (unsigned long)(val); \
__asm__ __volatile__ ("csrc " #csr ", %0" \
: : "rK" (__v)); \
})
#endif

51
src/main/c/emulator/src/start.S Executable file
View file

@ -0,0 +1,51 @@
.section .init
.globl _start
.type _start,@function
#include "config.h"
_start:
/*#ifdef USE_GP
.option push
.option norelax
la gp, __global_pointer$
.option pop
#endif*/
la sp, _sp
/* Load data section */
la a0, _data_lma
la a1, _data
la a2, _edata
bgeu a1, a2, 2f
1:
lw t0, (a0)
sw t0, (a1)
addi a0, a0, 4
addi a1, a1, 4
bltu a1, a2, 1b
2:
/* Clear bss section */
la a0, __bss_start
la a1, _end
bgeu a0, a1, 2f
1:
sw zero, (a0)
addi a0, a0, 4
bltu a0, a1, 1b
2:
call __libc_init_array
call init
la ra, done
li a0, 0
li a1, DTB
mret
done:
j done
.globl _init
_init:
ret

View file

@ -0,0 +1,71 @@
.section .init
.globl trapEntry
.type trapEntry,@function
trapEntry:
csrrw sp, mscratch, sp
sw x1, 1*4(sp)
sw x3, 3*4(sp)
sw x4, 4*4(sp)
sw x5, 5*4(sp)
sw x6, 6*4(sp)
sw x7, 7*4(sp)
sw x8, 8*4(sp)
sw x9, 9*4(sp)
sw x10, 10*4(sp)
sw x11, 11*4(sp)
sw x12, 12*4(sp)
sw x13, 13*4(sp)
sw x14, 14*4(sp)
sw x15, 15*4(sp)
sw x16, 16*4(sp)
sw x17, 17*4(sp)
sw x18, 18*4(sp)
sw x19, 19*4(sp)
sw x20, 20*4(sp)
sw x21, 21*4(sp)
sw x22, 22*4(sp)
sw x23, 23*4(sp)
sw x24, 24*4(sp)
sw x25, 25*4(sp)
sw x26, 26*4(sp)
sw x27, 27*4(sp)
sw x28, 28*4(sp)
sw x29, 29*4(sp)
sw x30, 30*4(sp)
sw x31, 31*4(sp)
call trap
lw x1, 1*4(sp)
lw x3, 3*4(sp)
lw x4, 4*4(sp)
lw x5, 5*4(sp)
lw x6, 6*4(sp)
lw x7, 7*4(sp)
lw x8, 8*4(sp)
lw x9, 9*4(sp)
lw x10, 10*4(sp)
lw x11, 11*4(sp)
lw x12, 12*4(sp)
lw x13, 13*4(sp)
lw x14, 14*4(sp)
lw x15, 15*4(sp)
lw x16, 16*4(sp)
lw x17, 17*4(sp)
lw x18, 18*4(sp)
lw x19, 19*4(sp)
lw x20, 20*4(sp)
lw x21, 21*4(sp)
lw x22, 22*4(sp)
lw x23, 23*4(sp)
lw x24, 24*4(sp)
lw x25, 25*4(sp)
lw x26, 26*4(sp)
lw x27, 27*4(sp)
lw x28, 28*4(sp)
lw x29, 29*4(sp)
lw x30, 30*4(sp)
lw x31, 31*4(sp)
csrrw sp, mscratch, sp
mret

View file

@ -0,0 +1,47 @@
#include "riscv.h"
/*
.section .init
.globl readMemory
.type readMemory,@function
readWord:
csrr a4, mepc
li a2, MSTATUS_MPRV
csrs mstatus, a2
li a3, emulationTrap
csrw mepc, a3
lw a0, 0(a0)
li a3, trapEntry
csrw mepc, a3
csrc mstatus, a2
writeWord:
csrr a4, mepc
li a2, MSTATUS_MPRV
csrs mstatus, a2
li a3, emulationTrap
csrw mepc, a3
sw a1, 0(a0)
li a3, trapEntry
csrw mepc, a3
csrc mstatus, a2
*/
//Redirect trap to supervisor
/*
.section .init
.globl emulationTrap
.type emulationTrap,@function
emulationTrap:
li a0, MSTATUS_MPRV
csrc mstatus, a0
la sp, _sp
csrw sepc, a4
csrr a0, mcause
csrw scause, a0
csrr a0, mbadaddr
csrw sbadaddr, a0
call init
mret
*/

View file

@ -43,14 +43,30 @@ object IcestormFlow {
def apply(workspacePath : String,toplevelPath : String,family : String,device : String, pack : String) : Report = {
val projectName = toplevelPath.split("/").last.split("[.]").head
//ifeq ($(NEXTPNR),yes)
//%.json: ${VERILOGS}
// rm -f ${TOPLEVEL}.v*.bin
// cp -f ${ROOT}/hardware/netlist/${TOPLEVEL}.v*.bin . | true
// yosys -p 'synth_ice40 -top $(TOPLEVEL) -json $@' $<
//
//%.asc: $(PIN_DEF) %.json constraint.py
// nextpnr-ice40 --$(DEVICE) --json $(TOPLEVEL).json --pcf $(PIN_DEF) --asc $(TOPLEVEL).asc --pre-pack constraint.py $(NEXTPNR_ARG)
//else
//%.blif: ${VERILOGS}
// rm -f ${TOPLEVEL}.v*.bin
// cp -f ${ROOT}/hardware/netlist/${TOPLEVEL}.v*.bin . | true
// yosys -p 'synth_ice40 -top ${TOPLEVEL} -blif $@' $<
//
//%.asc: $(PIN_DEF) %.blif
// arachne-pnr -d $(subst up,,$(subst hx,,$(subst lp,,$(DEVICE)))) -o $@ -p $^
//endif
val workspacePathFile = new File(workspacePath)
FileUtils.deleteDirectory(workspacePathFile)
workspacePathFile.mkdir()
FileUtils.copyFileToDirectory(new File(toplevelPath), workspacePathFile)
doCmd(List("yosys", "-v3", "-p", s"synth_ice40 -top $projectName -blif ${projectName}.blif", s"$projectName.v" ), workspacePath)
val arachne = doCmd(List("arachne-pnr", "-d", device.replace("hx","").replace("up",""), "--max-passes", "600", "-P", pack, s"$projectName.blif" ,"-o", s"$projectName.asc"), workspacePath)
doCmd(List("yosys", "-v3", "-p", s"synth_ice40 -top $projectName -json ${projectName}.json", s"$projectName.v" ), workspacePath)
val arachne = doCmd(List("nextpnr-ice40", s"--$device", "--json", s"${projectName}.json","--asc", s"$projectName.asc"), workspacePath)
doCmd(List("icepack", s"$projectName.asc", s"$projectName.bin"), workspacePath)
val icetime = doCmd(List("icetime", "-tmd", device, s"${projectName}.asc"), workspacePath)
new Report{
@ -65,7 +81,7 @@ object IcestormFlow {
}
override def getArea() = {
try {
intFind.findFirstIn("LCs[^\\n]*\\/".r.findFirstIn(arachne).get).get.toString() + " LC"
intFind.findFirstIn("ICESTORM_LC\\:[^\\n]*\\/".r.findFirstIn(arachne).get).get.toString() + " LC"
} catch {
case e : Throwable => "error"
}
@ -151,7 +167,7 @@ object IcestormFlow {
// }
SpinalVerilog(StreamFifo(Bits(8 bits), 64))
val report = IcestormFlow(
workspacePath="/home/spinalvm/tmp",
workspacePath="/media/miaou/HD/linux/tmp",
toplevelPath="StreamFifo.v",
family="iCE40",
device="up5k",

View file

@ -7,21 +7,21 @@ import spinal.lib._
import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
trait PipelineConfig[T]
trait PipelineThing[T]
trait Pipeline {
type T <: Pipeline
val plugins = ArrayBuffer[Plugin[T]]()
var stages = ArrayBuffer[Stage]()
var unremovableStages = mutable.Set[Stage]()
val configs = mutable.HashMap[PipelineConfig[_], Any]()
val things = mutable.HashMap[PipelineThing[_], Any]()
// val services = ArrayBuffer[Any]()
def indexOf(stage : Stage) = stages.indexOf(stage)
def service[T](clazz : Class[T]) = {
val filtered = plugins.filter(o => clazz.isAssignableFrom(o.getClass))
assert(filtered.length == 1)
assert(filtered.length == 1, s"??? ${clazz.getName}")
filtered.head.asInstanceOf[T]
}
@ -37,16 +37,23 @@ trait Pipeline {
filtered.head.asInstanceOf[T]
}
def update[T](that : PipelineConfig[T], value : T) : Unit = configs(that) = value
def apply[T](that : PipelineConfig[T]) : T = configs(that).asInstanceOf[T]
def update[T](that : PipelineThing[T], value : T) : Unit = things(that) = value
def apply[T](that : PipelineThing[T]) : T = things(that).asInstanceOf[T]
def build(): Unit ={
plugins.foreach(_.pipeline = this.asInstanceOf[T])
plugins.foreach(_.setup(this.asInstanceOf[T]))
plugins.foreach{ p =>
p.parentScope = Component.current.dslBody //Put the given plugin as a child of the current component
p.reflectNames()
}
//Build plugins
plugins.foreach(_.build(this.asInstanceOf[T]))
//Interconnect stages
class KeyInfo{
var insertStageId = Int.MaxValue
@ -112,7 +119,7 @@ trait Pipeline {
inputDefault := stage.inserts(key)
} else {
val stageBefore = stages(stageIndex - 1)
inputDefault := RegNextWhen(stageBefore.output(key), !stage.arbitration.isStuck).setName(s"${stageBefore.getName()}_to_${stage.getName()}_${key.getName()}")
inputDefault := RegNextWhen(stageBefore.output(key), stage.dontSample.getOrElse(key, Nil).foldLeft(!stage.arbitration.isStuck)(_ && !_)).setName(s"${stageBefore.getName()}_to_${stage.getName()}_${key.getName()}")
}
}
}

View file

@ -62,6 +62,16 @@ object Riscv{
def LR = M"00010--00000-----010-----0101111"
def SC = M"00011------------010-----0101111"
def AMOSWAP = M"00001------------010-----0101111"
def AMOADD = M"00000------------010-----0101111"
def AMOXOR = M"00100------------010-----0101111"
def AMOAND = M"01100------------010-----0101111"
def AMOOR = M"01000------------010-----0101111"
def AMOMIN = M"10000------------010-----0101111"
def AMOMAX = M"10100------------010-----0101111"
def AMOMINU = M"11000------------010-----0101111"
def AMOMAXU = M"11100------------010-----0101111"
def BEQ (rvc : Boolean) = if(rvc) M"-----------------000-----1100011" else M"-----------------000---0-1100011"
def BNE (rvc : Boolean) = if(rvc) M"-----------------001-----1100011" else M"-----------------001---0-1100011"
def BLT (rvc : Boolean) = if(rvc) M"-----------------100-----1100011" else M"-----------------100---0-1100011"
@ -105,6 +115,7 @@ object Riscv{
def FENCE = M"-----------------000-----0001111"
def FENCE_I = M"-----------------001-----0001111"
def SFENCE_VMA = M"0001001----------000000001110011"
object CSR{
def MVENDORID = 0xF11 // MRO Vendor ID.

View file

@ -33,14 +33,21 @@ case class ExceptionCause() extends Bundle{
trait ExceptionService{
def newExceptionPort(stage : Stage, priority : Int = 0) : Flow[ExceptionCause]
def isExceptionPending(stage : Stage) : Bool
}
trait PrivilegeService{
def isUser(stage : Stage) : Bool
def isUser() : Bool
def isSupervisor() : Bool
def isMachine() : Bool
def forceMachine() : Unit
}
case class PrivilegeServiceDefault() extends PrivilegeService{
override def isUser(stage: Stage): Bool = False
override def isUser(): Bool = False
override def isSupervisor(): Bool = False
override def isMachine(): Bool = True
override def forceMachine(): Unit = {}
}
trait InterruptionInhibitor{
@ -51,6 +58,7 @@ trait ExceptionInhibitor{
def inhibateException() : Unit
}
trait RegFileService{
def readStage() : Stage
}
@ -64,19 +72,20 @@ case class MemoryTranslatorCmd() extends Bundle{
case class MemoryTranslatorRsp() extends Bundle{
val physicalAddress = UInt(32 bits)
val isIoAccess = Bool
val allowRead, allowWrite, allowExecute, allowUser = Bool
val miss = Bool
val hit = Bool
val allowRead, allowWrite, allowExecute = Bool
val exception = Bool
val refilling = Bool
}
case class MemoryTranslatorBus() extends Bundle with IMasterSlave{
val cmd = MemoryTranslatorCmd()
val rsp = MemoryTranslatorRsp()
val end = Bool
val busy = Bool
override def asMaster() : Unit = {
out(cmd, end)
in(rsp)
in(rsp, busy)
}
}

View file

@ -4,6 +4,7 @@ import spinal.core._
import spinal.lib._
import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
class Stageable[T <: Data](_dataType : => T) extends HardType[T](_dataType) with Nameable{
@ -49,7 +50,6 @@ class Stage() extends Area{
val haltByOther = False //When settable, stuck the instruction, should only be set by something else than the stucked instruction
val removeIt = False //When settable, unschedule the instruction as if it was never executed (no side effect)
val flushAll = False //When settable, unschedule instructions in the current stage and all prior ones
val redoIt = False //Allow to notify that a given instruction in a pipeline is rescheduled
val isValid = Bool //Inform if a instruction is in the current stage
val isStuck = Bool //Inform if the instruction is stuck (haltItself || haltByOther)
val isStuckByOthers = Bool //Inform if the instruction is stuck by sombody else
@ -68,6 +68,11 @@ class Stage() extends Area{
val inputsDefault = mutable.HashMap[Stageable[Data],Data]()
val outputsDefault = mutable.HashMap[Stageable[Data],Data]()
val dontSample = mutable.HashMap[Stageable[_], ArrayBuffer[Bool]]()
def dontSampleStageable(s : Stageable[_], cond : Bool): Unit ={
dontSample.getOrElseUpdate(s, ArrayBuffer[Bool]()) += cond
}
def inputInit[T <: BaseType](stageable : Stageable[T],initValue : T) =
Component.current.addPrePopTask(() => inputsDefault(stageable.asInstanceOf[Stageable[Data]]).asInstanceOf[T].getDrivingReg.init(initValue))
}

View file

@ -56,7 +56,6 @@ object TestsWorkspace {
memDataWidth = 32,
catchIllegalAccess = true,
catchAccessFault = true,
catchMemoryTranslationMiss = true,
asyncTagMemory = false,
twoCycleRam = false,
twoCycleCache = true
@ -82,8 +81,7 @@ object TestsWorkspace {
catchAccessError = true,
catchIllegal = true,
catchUnaligned = true,
catchMemoryTranslationMiss = true,
atomicEntriesCount = 2
withLrSc = true
),
// memoryTranslatorPortConfig = null
memoryTranslatorPortConfig = MemoryTranslatorPortConfig(

View file

@ -42,6 +42,8 @@ case class VexRiscvConfig(){
object REGFILE_WRITE_VALID extends Stageable(Bool)
object REGFILE_WRITE_DATA extends Stageable(Bits(32 bits))
object MPP extends PipelineThing[UInt]
object DEBUG_BYPASS_CACHE extends PipelineThing[Bool]
object SRC1 extends Stageable(Bits(32 bits))
object SRC2 extends Stageable(Bits(32 bits))
@ -51,6 +53,7 @@ case class VexRiscvConfig(){
object SRC_LESS extends Stageable(Bool)
object SRC_USE_SUB_LESS extends Stageable(Bool)
object SRC_LESS_UNSIGNED extends Stageable(Bool)
object SRC_ADD_ZERO extends Stageable(Bool)
object HAS_SIDE_EFFECT extends Stageable(Bool)
@ -71,7 +74,7 @@ case class VexRiscvConfig(){
}
object Src2CtrlEnum extends SpinalEnum(binarySequential){
val RS, IMI, IMS, PC = newElement()
val RS, IMI, IMS, PC = newElement() //TODO remplacing ZERO could avoid 32 muxes if SRC_ADD can be disabled
}
object SRC1_CTRL extends Stageable(Src1CtrlEnum())
object SRC2_CTRL extends Stageable(Src2CtrlEnum())
@ -79,7 +82,7 @@ case class VexRiscvConfig(){
object RVC_GEN extends PipelineConfig[Boolean]
object RVC_GEN extends PipelineThing[Boolean]
class VexRiscv(val config : VexRiscvConfig) extends Component with Pipeline{
type T = VexRiscv
import config._
@ -96,18 +99,13 @@ class VexRiscv(val config : VexRiscvConfig) extends Component with Pipeline{
plugins ++= config.plugins
//regression usage
decode.input(config.INSTRUCTION).addAttribute(Verilator.public)
decode.input(config.PC).addAttribute(Verilator.public)
decode.arbitration.isValid.addAttribute(Verilator.public)
decode.arbitration.flushAll.addAttribute(Verilator.public)
decode.arbitration.haltItself.addAttribute(Verilator.public)
if(withWriteBackStage) {
writeBack.input(config.INSTRUCTION) keep() addAttribute (Verilator.public)
writeBack.input(config.PC) keep() addAttribute (Verilator.public)
writeBack.arbitration.isValid keep() addAttribute (Verilator.public)
writeBack.arbitration.isFiring keep() addAttribute (Verilator.public)
}
decode.arbitration.removeIt.noBackendCombMerge //Verilator perf
val lastStageInstruction = CombInit(stages.last.input(config.INSTRUCTION)) keep() addAttribute (Verilator.public)
val lastStagePc = CombInit(stages.last.input(config.PC)) keep() addAttribute (Verilator.public)
val lastStageIsValid = CombInit(stages.last.arbitration.isValid) keep() addAttribute (Verilator.public)
val lastStageIsFiring = CombInit(stages.last.arbitration.isFiring) keep() addAttribute (Verilator.public)
//Verilator perf
decode.arbitration.removeIt.noBackendCombMerge
if(withMemoryStage){
memory.arbitration.removeIt.noBackendCombMerge
}

View file

@ -65,7 +65,6 @@ object BrieyConfig{
memDataWidth = 32,
catchIllegalAccess = true,
catchAccessFault = true,
catchMemoryTranslationMiss = true,
asyncTagMemory = false,
twoCycleRam = true,
twoCycleCache = true
@ -89,8 +88,7 @@ object BrieyConfig{
memDataWidth = 32,
catchAccessError = true,
catchIllegal = true,
catchUnaligned = true,
catchMemoryTranslationMiss = true
catchUnaligned = true
),
memoryTranslatorPortConfig = null
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(

View file

@ -23,12 +23,11 @@ object GenFull extends App{
memDataWidth = 32,
catchIllegalAccess = true,
catchAccessFault = true,
catchMemoryTranslationMiss = true,
asyncTagMemory = false,
twoCycleRam = true,
twoCycleCache = true
),
memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
memoryTranslatorPortConfig = MmuPortConfig(
portTlbSize = 4
)
),
@ -42,15 +41,13 @@ object GenFull extends App{
memDataWidth = 32,
catchAccessError = true,
catchIllegal = true,
catchUnaligned = true,
catchMemoryTranslationMiss = true
catchUnaligned = true
),
memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
memoryTranslatorPortConfig = MmuPortConfig(
portTlbSize = 6
)
),
new MemoryTranslatorPlugin(
tlbSize = 32,
new MmuPlugin(
virtualRange = _(31 downto 28) === 0xC,
ioRange = _(31 downto 28) === 0xF
),

View file

@ -27,7 +27,6 @@ object GenFullNoMmu extends App{
memDataWidth = 32,
catchIllegalAccess = true,
catchAccessFault = true,
catchMemoryTranslationMiss = true,
asyncTagMemory = false,
twoCycleRam = true,
twoCycleCache = true
@ -43,8 +42,7 @@ object GenFullNoMmu extends App{
memDataWidth = 32,
catchAccessError = true,
catchIllegal = true,
catchUnaligned = true,
catchMemoryTranslationMiss = true
catchUnaligned = true
)
),
new StaticMemoryTranslatorPlugin(

View file

@ -28,7 +28,6 @@ object GenFullNoMmuMaxPerf extends App{
memDataWidth = 32,
catchIllegalAccess = true,
catchAccessFault = true,
catchMemoryTranslationMiss = false,
asyncTagMemory = false,
twoCycleRam = true,
twoCycleCache = true
@ -44,8 +43,7 @@ object GenFullNoMmuMaxPerf extends App{
memDataWidth = 32,
catchAccessError = true,
catchIllegal = true,
catchUnaligned = true,
catchMemoryTranslationMiss = false
catchUnaligned = true
)
),
new StaticMemoryTranslatorPlugin(

View file

@ -0,0 +1,63 @@
package vexriscv.demo
import vexriscv.plugin._
import vexriscv.ip.{DataCacheConfig, InstructionCacheConfig}
import vexriscv.{plugin, VexRiscv, VexRiscvConfig}
import spinal.core._
/**
* Created by spinalvm on 15.06.17.
*/
object GenFullNoMmuNoCacheSimpleMul extends App{
def cpu() = new VexRiscv(
config = VexRiscvConfig(
plugins = List(
new IBusSimplePlugin(
resetVector = 0x80000000l,
cmdForkOnSecondStage = false,
cmdForkPersistence = false,
prediction = STATIC,
catchAccessFault = false,
compressedGen = false
),
new DBusSimplePlugin(
catchAddressMisaligned = false,
catchAccessFault = false
),
new DecoderSimplePlugin(
catchIllegalInstruction = true
),
new RegFilePlugin(
regFileReadyKind = plugin.SYNC,
zeroBoot = false
),
new IntAluPlugin,
new SrcPlugin(
separatedAddSub = false,
executeInsertion = true
),
new FullBarrelShifterPlugin,
new HazardSimplePlugin(
bypassExecute = true,
bypassMemory = true,
bypassWriteBack = true,
bypassWriteBackBuffer = true,
pessimisticUseSrc = false,
pessimisticWriteRegFile = false,
pessimisticAddressMatch = false
),
new MulSimplePlugin,
new DivPlugin,
new CsrPlugin(CsrPluginConfig.small),
new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
new BranchPlugin(
earlyBranch = false,
catchAddressMisaligned = true
),
new YamlPlugin("cpu0.yaml")
)
)
)
SpinalVerilog(cpu())
}

View file

@ -0,0 +1,61 @@
package vexriscv.demo
import vexriscv.plugin._
import vexriscv.{plugin, VexRiscv, VexRiscvConfig}
import spinal.core._
/**
* Created by spinalvm on 15.06.17.
*/
object GenMicroNoCsr extends App{
def cpu() = new VexRiscv(
config = VexRiscvConfig(
withMemoryStage = false,
withWriteBackStage = false,
plugins = List(
new IBusSimplePlugin(
resetVector = 0x80000000l,
cmdForkOnSecondStage = false,
cmdForkPersistence = false,
prediction = NONE,
catchAccessFault = false,
compressedGen = false
),
new DBusSimplePlugin(
catchAddressMisaligned = false,
catchAccessFault = false,
earlyInjection = false
),
new DecoderSimplePlugin(
catchIllegalInstruction = false
),
new RegFilePlugin(
regFileReadyKind = plugin.SYNC,
zeroBoot = false,
writeRfInMemoryStage = false
),
new IntAluPlugin,
new SrcPlugin(
separatedAddSub = false,
executeInsertion = false
),
new LightShifterPlugin,
new HazardSimplePlugin(
bypassExecute = false,
bypassMemory = false,
bypassWriteBack = false,
bypassWriteBackBuffer = false,
pessimisticUseSrc = false,
pessimisticWriteRegFile = false,
pessimisticAddressMatch = false
),
new BranchPlugin(
earlyBranch = true,
catchAddressMisaligned = false
),
new YamlPlugin("cpu0.yaml")
)
)
)
SpinalConfig(mergeAsyncProcess = false).generateVerilog(cpu())
}

View file

@ -26,7 +26,6 @@ object GenSmallAndProductiveICache extends App{
memDataWidth = 32,
catchIllegalAccess = false,
catchAccessFault = false,
catchMemoryTranslationMiss = false,
asyncTagMemory = false,
twoCycleRam = false,
twoCycleCache = true

View file

@ -0,0 +1,507 @@
/*
* SpinalHDL
* Copyright (c) Dolu, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package vexriscv.demo
import spinal.core._
import spinal.lib.eda.bench.{AlteraStdTargets, Bench, Rtl, XilinxStdTargets}
import spinal.lib.eda.icestorm.IcestormStdTargets
import spinal.lib.master
import vexriscv._
import vexriscv.ip._
import vexriscv.plugin._
/*
prerequired stuff =>
- JAVA JDK >= 8
- SBT
- Verilator
Setup things =>
git clone https://github.com/SpinalHDL/SpinalHDL.git -b dev
git clone https://github.com/SpinalHDL/VexRiscv.git -b linux
cd VexRiscv
Run regressions =>
sbt "runMain vexriscv.demo.LinuxGen -r"
cd src/test/cpp/regression
make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISOR=yes MMU=yes CSR=yes DEBUG_PLUGIN=no COMPRESSED=no MUL=yes DIV=yes LRSC=yes AMO=yes REDO=10 TRACE=no COREMARK=yes LINUX_REGRESSION=yes
Run linux in simulation (Require the machime mode emulator compiled in SIM mode) =>
sbt "runMain vexriscv.demo.LinuxGen"
cd src/test/cpp/regression
export BUILDROOT=/home/miaou/pro/riscv/buildrootSpinal
make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes DEBUG_PLUGIN=no COMPRESSED=no LRSC=yes AMO=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=../../../main/c/emulator/build/emulator.bin VMLINUX=$BUILDROOT/output/images/Image DTB=$BUILDROOT/board/spinal/vexriscv_sim/rv32.dtb RAMDISK=$BUILDROOT/output/images/rootfs.cpio WITH_USER_IO=yes TRACE=no FLOW_INFO=no
Run linux with QEMU (Require the machime mode emulator compiled in QEMU mode)
export BUILDROOT=/home/miaou/pro/riscv/buildrootSpinal
qemu-system-riscv32 -nographic -machine virt -m 1536M -device loader,file=src/main/c/emulator/build/emulator.bin,addr=0x80000000,cpu-num=0 -device loader,file=$BUILDROOT/board/spinal/vexriscv_sim/rv32.dtb,addr=0xC3000000 -device loader,file=$BUILDROOT/output/images/Image,addr=0xC0000000 -device loader,file=$BUILDROOT/output/images/rootfs.cpio,addr=0xc2000000
Buildroot =>
git clone https://github.com/SpinalHDL/buildroot.git -b vexriscv
cd buildroot
make spinal_vexriscv_sim_defconfig
make -j$(nproc)
output/host/bin/riscv32-linux-objcopy -O binary output/images/vmlinux output/images/Image
After changing a kernel config into buildroot =>
cd buildroot
make spinal_vexriscv_sim_defconfig
make linux-dirclean linux-rebuild -j8
output/host/bin/riscv32-linux-objcopy -O binary output/images/vmlinux output/images/Image
Compiling the machine mode emulator (check the config.h file to know the mode) =>
cd src/main/c/emulator
make clean all
Changing the emulator mode =>
Edit the src/main/c/emulator/src/config.h file, and comment/uncomment the SIM/QEMU flags
Other commands (Memo):
decompile file and split it
riscv64-unknown-elf-objdump -S -d vmlinux > vmlinux.asm; split -b 1M vmlinux.asm
Kernel compilation command =>
ARCH=riscv CROSS_COMPILE=riscv32-unknown-linux-gnu- make menuconfig
ARCH=riscv CROSS_COMPILE=riscv32-unknown-linux-gnu- make -j`nproc`; riscv32-unknown-linux-gnu-objcopy -O binary vmlinux vmlinux.bin
Generate a DTB from a DTS =>
dtc -O dtb -o rv32.dtb rv32.dts
https://github.com/riscv/riscv-qemu/wiki#build-and-install
memo :
export DATA=/home/miaou/Downloads/Binaries-master
cd src/test/cpp/regression
rm VexRiscv.v
cp $DATA/VexRiscv.v ../../../..
make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes COMPRESSED=no LRSC=yes AMO=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=$DATA/emulator.bin VMLINUX=$DATA/vmlinux.bin DTB=$DATA/rv32.dtb RAMDISK=$DATA/rootfs.cpio TRACE=no FLOW_INFO=no
make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=no SUPERVISOR=yes CSR=yes COMPRESSED=no MUL=yes DIV=yes LRSC=yes AMO=yes MMU=yes REDO=1 TRACE=no LINUX_REGRESSION=yes
qemu-system-riscv32 -nographic -machine virt -m 1536M -device loader,file=$DATA/emulator.bin,addr=0x80000000,cpu-num=0 -device loader,file=$DATA/rv32.dtb,addr=0xC3000000 -device loader,file=$DATA/vmlinux.bin,addr=0xC0000000 -device loader,file=$DATA/rootfs.cpio,addr=0xc2000000
make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yess SUPERVISOR=yes CSR=yes COMPRESSED=yes MUL=yes DIV=yes LRSC=yes AMO=yes REDO=1 TRACE=no LINUX_REGRESSION=yes
program ../../../main/c/emulator/build/emulator.bin 0x80000000 verify
soc.loadBin(EMULATOR, 0x80000000);
soc.loadBin(VMLINUX, 0xC0000000);
soc.loadBin(DTB, 0xC3000000);
soc.loadBin(RAMDISK, 0xC2000000);
export BUILDROOT=/home/miaou/pro/riscv/buildrootSpinal
make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes COMPRESSED=no LRSC=yes AMO=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes
EMULATOR=../../../main/c/emulator/build/emulator.bin
VMLINUX=/home/miaou/pro/riscv/buildrootSpinal/output/images/Image
DTB=/home/miaou/pro/riscv/buildrootSpinal/board/spinal/vexriscv_sim/rv32.dtb
RAMDISK=/home/miaou/pro/riscv/buildrootSpinal/output/images/rootfs.cpio TRACE=no FLOW_INFO=no
make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes COMPRESSED=no LRSC=yes AMO=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes DEBUG_PLUGIN_EXTERNAL=yes
rm -rf cpio
mkdir cpio
cd cpio
cpio -idv < ../rootfs.cpio
cd ..
make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISOR=yes MMU=yes CSR=yes COMPRESSED=no MUL=yes DIV=yes LRSC=yes AMO=yes REDO=10 TRACE=no COREMARK=yes LINUX_REGRESSION=yes RUN_HEX=~/pro/riscv/zephyr/samples/synchronization/build/zephyr/zephyr.hex
*/
object LinuxGen {
def configFull(litex : Boolean, withMmu : Boolean) = {
val config = VexRiscvConfig(
plugins = List(
//Uncomment the whole IBusSimplePlugin and comment IBusCachedPlugin if you want uncached iBus config
// new IBusSimplePlugin(
// resetVector = 0x80000000l,
// cmdForkOnSecondStage = false,
// cmdForkPersistence = false,
// prediction = DYNAMIC_TARGET,
// historyRamSizeLog2 = 10,
// catchAccessFault = true,
// compressedGen = true,
// busLatencyMin = 1,
// injectorStage = true,
// memoryTranslatorPortConfig = withMmu generate MmuPortConfig(
// portTlbSize = 4
// )
// ),
//Uncomment the whole IBusCachedPlugin and comment IBusSimplePlugin if you want cached iBus config
new IBusCachedPlugin(
resetVector = 0x80000000l,
compressedGen = false,
prediction = STATIC,
injectorStage = false,
config = InstructionCacheConfig(
cacheSize = 4096*1,
bytePerLine = 32,
wayCount = 1,
addressWidth = 32,
cpuDataWidth = 32,
memDataWidth = 32,
catchIllegalAccess = true,
catchAccessFault = true,
asyncTagMemory = false,
twoCycleRam = false,
twoCycleCache = true
// )
),
memoryTranslatorPortConfig = withMmu generate MmuPortConfig(
portTlbSize = 4
)
),
// ).newTightlyCoupledPort(TightlyCoupledPortParameter("iBusTc", a => a(30 downto 28) === 0x0 && a(5))),
// new DBusSimplePlugin(
// catchAddressMisaligned = true,
// catchAccessFault = true,
// earlyInjection = false,
// withLrSc = true,
// memoryTranslatorPortConfig = withMmu generate MmuPortConfig(
// portTlbSize = 4
// )
// ),
new DBusCachedPlugin(
dBusCmdMasterPipe = true,
dBusCmdSlavePipe = true,
dBusRspSlavePipe = true,
config = new DataCacheConfig(
cacheSize = 4096*1,
bytePerLine = 32,
wayCount = 1,
addressWidth = 32,
cpuDataWidth = 32,
memDataWidth = 32,
catchAccessError = true,
catchIllegal = true,
catchUnaligned = true,
withLrSc = true,
withAmo = true
// )
),
memoryTranslatorPortConfig = withMmu generate MmuPortConfig(
portTlbSize = 4
)
),
// new MemoryTranslatorPlugin(
// tlbSize = 32,
// virtualRange = _(31 downto 28) === 0xC,
// ioRange = _(31 downto 28) === 0xF
// ),
new DecoderSimplePlugin(
catchIllegalInstruction = true
),
new RegFilePlugin(
regFileReadyKind = plugin.SYNC,
zeroBoot = true
),
new IntAluPlugin,
new SrcPlugin(
separatedAddSub = false
),
new FullBarrelShifterPlugin(earlyInjection = false),
// new LightShifterPlugin,
new HazardSimplePlugin(
bypassExecute = true,
bypassMemory = true,
bypassWriteBack = true,
bypassWriteBackBuffer = true,
pessimisticUseSrc = false,
pessimisticWriteRegFile = false,
pessimisticAddressMatch = false
),
// new HazardSimplePlugin(false, true, false, true),
// new HazardSimplePlugin(false, false, false, false),
new MulPlugin,
new MulDivIterativePlugin(
genMul = false,
genDiv = true,
mulUnrollFactor = 32,
divUnrollFactor = 1
),
// new DivPlugin,
new CsrPlugin(CsrPluginConfig.linuxMinimal(0x80000020l).copy(ebreakGen = false)),
// new CsrPlugin(//CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = true)/*
// CsrPluginConfig(
// catchIllegalAccess = false,
// mvendorid = null,
// marchid = null,
// mimpid = null,
// mhartid = null,
// misaExtensionsInit = 0,
// misaAccess = CsrAccess.READ_ONLY,
// mtvecAccess = CsrAccess.WRITE_ONLY,
// mtvecInit = 0x80000020l,
// mepcAccess = CsrAccess.READ_WRITE,
// mscratchGen = true,
// mcauseAccess = CsrAccess.READ_ONLY,
// mbadaddrAccess = CsrAccess.READ_ONLY,
// mcycleAccess = CsrAccess.NONE,
// minstretAccess = CsrAccess.NONE,
// ecallGen = true,
// ebreakGen = true,
// wfiGenAsWait = false,
// wfiGenAsNop = true,
// ucycleAccess = CsrAccess.NONE
// )),
// new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
new BranchPlugin(
earlyBranch = false,
catchAddressMisaligned = true,
fenceiGenAsAJump = false
),
new YamlPlugin("cpu0.yaml")
)
)
if(withMmu) config.plugins += new MmuPlugin(
ioRange = (x => if(litex) x(31 downto 28) === 0xB || x(31 downto 28) === 0xE || x(31 downto 28) === 0xF else x(31 downto 28) === 0xF)
) else {
config.plugins += new StaticMemoryTranslatorPlugin(
ioRange = _(31 downto 28) === 0xF
)
}
config
}
def main(args: Array[String]) {
// import spinal.core.sim._
// SimConfig.withConfig(SpinalConfig(mergeAsyncProcess = false, anonymSignalPrefix = "zz_")).allOptimisation.compile(new VexRiscv(configFull)).doSimUntilVoid{ dut =>
// dut.clockDomain.forkStimulus(10)
// dut.clockDomain.forkSimSpeedPrinter(4)
// var iBus : InstructionCacheMemBus = null
//
// dut.plugins.foreach{
// case plugin: IBusCachedPlugin => iBus = plugin.iBus
// case _ =>
// }
// dut.clockDomain.onSamplings{
//// iBus.cmd.ready.randomize()
// iBus.rsp.data #= 0x13
// }
// }
SpinalConfig(mergeAsyncProcess = true, anonymSignalPrefix = "_zz").generateVerilog {
val toplevel = new VexRiscv(configFull(
litex = !args.contains("-r"),
withMmu = true
))
// val toplevel = new VexRiscv(configLight)
// val toplevel = new VexRiscv(configTest)
/*toplevel.rework {
var iBus : AvalonMM = null
for (plugin <- toplevel.config.plugins) plugin match {
case plugin: IBusSimplePlugin => {
plugin.iBus.asDirectionLess() //Unset IO properties of iBus
iBus = master(plugin.iBus.toAvalon())
.setName("iBusAvalon")
.addTag(ClockDomainTag(ClockDomain.current)) //Specify a clock domain to the iBus (used by QSysify)
}
case plugin: IBusCachedPlugin => {
plugin.iBus.asDirectionLess() //Unset IO properties of iBus
iBus = master(plugin.iBus.toAvalon())
.setName("iBusAvalon")
.addTag(ClockDomainTag(ClockDomain.current)) //Specify a clock domain to the iBus (used by QSysify)
}
case plugin: DBusSimplePlugin => {
plugin.dBus.asDirectionLess()
master(plugin.dBus.toAvalon())
.setName("dBusAvalon")
.addTag(ClockDomainTag(ClockDomain.current))
}
case plugin: DBusCachedPlugin => {
plugin.dBus.asDirectionLess()
master(plugin.dBus.toAvalon())
.setName("dBusAvalon")
.addTag(ClockDomainTag(ClockDomain.current))
}
case plugin: DebugPlugin => {
plugin.io.bus.asDirectionLess()
slave(plugin.io.bus.fromAvalon())
.setName("debugBusAvalon")
.addTag(ClockDomainTag(plugin.debugClockDomain))
.parent = null //Avoid the io bundle to be interpreted as a QSys conduit
plugin.io.resetOut
.addTag(ResetEmitterTag(plugin.debugClockDomain))
.parent = null //Avoid the io bundle to be interpreted as a QSys conduit
}
case _ =>
}
for (plugin <- toplevel.config.plugins) plugin match {
case plugin: CsrPlugin => {
plugin.externalInterrupt
.addTag(InterruptReceiverTag(iBus, ClockDomain.current))
plugin.timerInterrupt
.addTag(InterruptReceiverTag(iBus, ClockDomain.current))
}
case _ =>
}
}*/
// toplevel.writeBack.input(config.PC).addAttribute(Verilator.public)
// toplevel.service(classOf[DecoderSimplePlugin]).bench(toplevel)
// toplevel.children.find(_.isInstanceOf[DataCache]).get.asInstanceOf[DataCache].io.cpu.execute.addAttribute(Verilator.public)
// toplevel.rework {
// for (plugin <- toplevel.config.plugins) plugin match {
// case plugin: IBusSimplePlugin => {
// plugin.iBus.setAsDirectionLess().unsetName() //Unset IO properties of iBus
// val iBus = master(IBusSimpleBus()).setName("iBus")
//
// iBus.cmd << plugin.iBus.cmd.halfPipe()
// iBus.rsp.stage >> plugin.iBus.rsp
// }
// case plugin: DBusSimplePlugin => {
// plugin.dBus.setAsDirectionLess().unsetName()
// val dBus = master(DBusSimpleBus()).setName("dBus")
// val pending = RegInit(False) setWhen(plugin.dBus.cmd.fire) clearWhen(plugin.dBus.rsp.ready)
// dBus.cmd << plugin.dBus.cmd.haltWhen(pending).halfPipe()
// plugin.dBus.rsp := RegNext(dBus.rsp)
// plugin.dBus.rsp.ready clearWhen(!pending)
// }
//
// case _ =>
// }
// }
toplevel
}
}
}
object LinuxSyntesisBench extends App{
val withoutMmu = new Rtl {
override def getName(): String = "VexRiscv Without Mmu"
override def getRtlPath(): String = "VexRiscvWithoutMmu.v"
SpinalConfig(inlineRom=true).generateVerilog(new VexRiscv(LinuxGen.configFull(litex = false, withMmu = false)).setDefinitionName(getRtlPath().split("\\.").head))
}
val withMmu = new Rtl {
override def getName(): String = "VexRiscv With Mmu"
override def getRtlPath(): String = "VexRiscvWithMmu.v"
SpinalConfig(inlineRom=true).generateVerilog(new VexRiscv(LinuxGen.configFull(litex = false, withMmu = true)).setDefinitionName(getRtlPath().split("\\.").head))
}
val rtls = List(withoutMmu,withMmu)
// val rtls = List(smallestNoCsr, smallest, smallAndProductive, smallAndProductiveWithICache)
// val rtls = List(smallAndProductive, smallAndProductiveWithICache, fullNoMmuMaxPerf, fullNoMmu, full)
// val rtls = List(fullNoMmu)
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)
Bench(rtls, targets, "/media/miaou/HD/linux/tmp")
}
object LinuxSim extends App{
import spinal.core.sim._
SimConfig.allOptimisation.compile(new VexRiscv(LinuxGen.configFull(litex = false, withMmu = true))).doSim{dut =>
// dut.clockDomain.forkStimulus(10)
// dut.clockDomain.forkSimSpeedPrinter()
// dut.plugins.foreach{
// case p : IBusSimplePlugin => dut.clockDomain.onRisingEdges{
// p.iBus.cmd.ready #= ! p.iBus.cmd.ready.toBoolean
//// p.iBus.rsp.valid.randomize()
//// p.iBus.rsp.inst.randomize()
//// p.iBus.rsp.error.randomize()
// }
// case p : DBusSimplePlugin => dut.clockDomain.onRisingEdges{
// p.dBus.cmd.ready #= ! p.dBus.cmd.ready.toBoolean
//// p.dBus.cmd.ready.randomize()
//// p.dBus.rsp.ready.randomize()
//// p.dBus.rsp.data.randomize()
//// p.dBus.rsp.error.randomize()
// }
// case _ =>
// }
// sleep(10*10000000)
var cycleCounter = 0l
var lastTime = System.nanoTime()
var iBus : IBusSimpleBus = null
var dBus : DBusSimpleBus = null
dut.plugins.foreach{
case p : IBusSimplePlugin =>
iBus = p.iBus
// p.iBus.rsp.valid.randomize()
// p.iBus.rsp.inst.randomize()
// p.iBus.rsp.error.randomize()
case p : DBusSimplePlugin =>
dBus = p.dBus
// p.dBus.cmd.ready.randomize()
// p.dBus.rsp.ready.randomize()
// p.dBus.rsp.data.randomize()
// p.dBus.rsp.error.randomize()
case _ =>
}
dut.clockDomain.resetSim #= false
dut.clockDomain.clockSim #= false
sleep(1)
dut.clockDomain.resetSim #= true
sleep(1)
def f(): Unit ={
cycleCounter += 1
if((cycleCounter & 8191) == 0){
val currentTime = System.nanoTime()
val deltaTime = (currentTime - lastTime)*1e-9
if(deltaTime > 2.0) {
println(f"[Info] Simulation speed : ${cycleCounter / deltaTime * 1e-3}%4.0f kcycles/s")
lastTime = currentTime
cycleCounter = 0
}
}
dut.clockDomain.clockSim #= false
iBus.cmd.ready #= ! iBus.cmd.ready.toBoolean
dBus.cmd.ready #= ! dBus.cmd.ready.toBoolean
delayed(1)(f2)
}
def f2(): Unit ={
dut.clockDomain.clockSim #= true
delayed(1)(f)
}
delayed(1)(f)
sleep(100000000)
}
}

View file

@ -163,3 +163,8 @@ class MuraxApb3Timer extends Component{
interruptCtrl.io.inputs(1) := timerB.io.full
io.interrupt := interruptCtrl.io.pendings.orR
}
object MuraxApb3TimerGen extends App{
SpinalVhdl(new MuraxApb3Timer())
}

View file

@ -101,31 +101,26 @@ object VexRiscvSynthesisBench {
}
val rtls = List(smallestNoCsr, smallest, smallAndProductive, smallAndProductiveWithICache, fullNoMmuNoCache, noCacheNoMmuMaxPerf, fullNoMmuMaxPerf, fullNoMmu, full)
val linuxBalanced = new Rtl {
override def getName(): String = "VexRiscv linux balanced"
override def getRtlPath(): String = "VexRiscvLinuxBalanced.v"
SpinalConfig(inlineRom = true).generateVerilog(wrap(new VexRiscv(LinuxGen.configFull(false, true))).setDefinitionName(getRtlPath().split("\\.").head))
}
val rtls = List(smallestNoCsr, smallest, smallAndProductive, smallAndProductiveWithICache, fullNoMmuNoCache, noCacheNoMmuMaxPerf, fullNoMmuMaxPerf, fullNoMmu, full, linuxBalanced)
// val rtls = List(smallestNoCsr, smallest, smallAndProductive, smallAndProductiveWithICache)
// val rtls = List(smallAndProductive, smallAndProductiveWithICache, fullNoMmuMaxPerf, fullNoMmu, full)
// val rtls = List(fullNoMmu)
// val rtls = List(smallAndProductive)
val targets = XilinxStdTargets(
vivadoArtix7Path = "/eda/Xilinx/Vivado/2017.2/bin"
vivadoArtix7Path = "/media/miaou/HD/linux/Xilinx/Vivado/2018.3/bin"
) ++ AlteraStdTargets(
quartusCycloneIVPath = "/eda/intelFPGA_lite/17.0/quartus/bin",
quartusCycloneVPath = "/eda/intelFPGA_lite/17.0/quartus/bin"
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(
// vivadoArtix7Path = "/eda/Xilinx/Vivado/2017.2/bin"
// )
// val targets = AlteraStdTargets(
// quartusCycloneIVPath = "/eda/intelFPGA_lite/17.0/quartus/bin",
// quartusCycloneVPath = null
// )
// val targets = IcestormStdTargets()
Bench(rtls, targets, "/eda/tmp")
Bench(rtls, targets, "/media/miaou/HD/linux/tmp")
}
}
@ -146,13 +141,13 @@ object BrieySynthesisBench {
val rtls = List(briey)
val targets = XilinxStdTargets(
vivadoArtix7Path = "/eda/Xilinx/Vivado/2017.2/bin"
vivadoArtix7Path = "/media/miaou/HD/linux/Xilinx/Vivado/2018.3/bin"
) ++ AlteraStdTargets(
quartusCycloneIVPath = "/eda/intelFPGA_lite/17.0/quartus/bin/",
quartusCycloneVPath = "/eda/intelFPGA_lite/17.0/quartus/bin/"
quartusCycloneIVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin",
quartusCycloneVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin"
)
Bench(rtls, targets, "/eda/tmp/")
Bench(rtls, targets, "/media/miaou/HD/linux/tmp")
}
}
@ -185,14 +180,13 @@ object MuraxSynthesisBench {
val rtls = List(murax, muraxFast)
val targets = IcestormStdTargets().take(1) ++ XilinxStdTargets(
vivadoArtix7Path = "/eda/Xilinx/Vivado/2017.2/bin"
vivadoArtix7Path = "/media/miaou/HD/linux/Xilinx/Vivado/2018.3/bin"
) ++ AlteraStdTargets(
quartusCycloneIVPath = "/eda/intelFPGA_lite/17.0/quartus/bin/",
quartusCycloneVPath = "/eda/intelFPGA_lite/17.0/quartus/bin/"
quartusCycloneIVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin",
quartusCycloneVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin"
)
Bench(rtls, targets, "/eda/tmp/")
Bench(rtls, targets, "/media/miaou/HD/linux/tmp")
}
}

View file

@ -48,7 +48,6 @@ object VexRiscvAvalonForSim{
memDataWidth = 32,
catchIllegalAccess = true,
catchAccessFault = true,
catchMemoryTranslationMiss = true,
asyncTagMemory = false,
twoCycleRam = true
)
@ -67,8 +66,7 @@ object VexRiscvAvalonForSim{
memDataWidth = 32,
catchAccessError = true,
catchIllegal = true,
catchUnaligned = true,
catchMemoryTranslationMiss = true
catchUnaligned = true
),
memoryTranslatorPortConfig = null
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(

View file

@ -44,7 +44,6 @@ object VexRiscvAvalonWithIntegratedJtag{
memDataWidth = 32,
catchIllegalAccess = true,
catchAccessFault = true,
catchMemoryTranslationMiss = true,
asyncTagMemory = false,
twoCycleRam = true,
twoCycleCache = true
@ -64,8 +63,7 @@ object VexRiscvAvalonWithIntegratedJtag{
memDataWidth = 32,
catchAccessError = true,
catchIllegal = true,
catchUnaligned = true,
catchMemoryTranslationMiss = true
catchUnaligned = true
),
memoryTranslatorPortConfig = null
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(

View file

@ -45,7 +45,6 @@ object VexRiscvAxi4WithIntegratedJtag{
memDataWidth = 32,
catchIllegalAccess = true,
catchAccessFault = true,
catchMemoryTranslationMiss = true,
asyncTagMemory = false,
twoCycleRam = true,
twoCycleCache = true
@ -65,8 +64,7 @@ object VexRiscvAxi4WithIntegratedJtag{
memDataWidth = 32,
catchAccessError = true,
catchIllegal = true,
catchUnaligned = true,
catchMemoryTranslationMiss = true
catchUnaligned = true
),
memoryTranslatorPortConfig = null
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(

View file

@ -44,7 +44,6 @@ object VexRiscvCachedWishboneForSim{
memDataWidth = 32,
catchIllegalAccess = true,
catchAccessFault = true,
catchMemoryTranslationMiss = true,
asyncTagMemory = false,
twoCycleRam = true
)
@ -63,8 +62,7 @@ object VexRiscvCachedWishboneForSim{
memDataWidth = 32,
catchAccessError = true,
catchIllegal = true,
catchUnaligned = true,
catchMemoryTranslationMiss = true
catchUnaligned = true
),
memoryTranslatorPortConfig = null
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(

View file

@ -8,24 +8,26 @@ import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig}
import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig}
import spinal.lib.bus.simple._
case class DataCacheConfig( cacheSize : Int,
bytePerLine : Int,
wayCount : Int,
addressWidth : Int,
cpuDataWidth : Int,
memDataWidth : Int,
catchAccessError : Boolean,
catchIllegal : Boolean,
catchUnaligned : Boolean,
catchMemoryTranslationMiss : Boolean,
clearTagsAfterReset : Boolean = true,
waysHitRetime : Boolean = true,
tagSizeShift : Int = 0, //Used to force infering ram
atomicEntriesCount : Int = 0){
case class DataCacheConfig(cacheSize : Int,
bytePerLine : Int,
wayCount : Int,
addressWidth : Int,
cpuDataWidth : Int,
memDataWidth : Int,
catchAccessError : Boolean,
catchIllegal : Boolean,
catchUnaligned : Boolean,
earlyWaysHits : Boolean = true,
earlyDataMux : Boolean = false,
tagSizeShift : Int = 0, //Used to force infering ram
withLrSc : Boolean = false,
withAmo : Boolean = false){
assert(!(earlyDataMux && !earlyWaysHits))
def burstSize = bytePerLine*8/memDataWidth
val burstLength = bytePerLine/(memDataWidth/8)
def catchSomething = catchUnaligned || catchMemoryTranslationMiss || catchIllegal || catchAccessError
def genAtomic = atomicEntriesCount != 0
def catchSomething = catchUnaligned || catchIllegal || catchAccessError
def getAxi4SharedConfig() = Axi4Config(
addressWidth = addressWidth,
@ -64,121 +66,45 @@ case class DataCacheConfig( cacheSize : Int,
)
}
object Bypasser{
//shot readValid path
def writeFirstMemWrap[T <: Data](readValid : Bool, readLastAddress : UInt, readLastData : T,writeValid : Bool, writeAddress : UInt, writeData : T) : T = {
val writeSample = readValid || (writeValid && writeAddress === readLastAddress)
val writeValidReg = RegNextWhen(writeValid,writeSample)
val writeAddressReg = RegNextWhen(writeAddress,writeSample)
val writeDataReg = RegNextWhen(writeData,writeSample)
(writeValidReg && writeAddressReg === readLastAddress) ? writeDataReg | readLastData
}
//short readValid path
def writeFirstMemWrap(readValid : Bool, readLastAddress : UInt, readLastData : Bits,writeValid : Bool, writeAddress : UInt, writeData : Bits,writeMask : Bits) : Bits = {
val writeHit = writeValid && writeAddress === readLastAddress
val writeSample = readValid || writeHit
val writeValidReg = RegNextWhen(writeValid,writeSample)
val writeAddressReg = RegNextWhen(writeAddress,writeSample)
val writeDataReg = Reg(writeData)
val writeMaskReg = Reg(Bits(widthOf(writeData)/8 bits))
val writeDataRegBytes = writeDataReg.subdivideIn(8 bits)
val writeDataBytes = writeData.subdivideIn(8 bits)
val ret = cloneOf(readLastData)
val retBytes = ret.subdivideIn(8 bits)
val readLastDataBytes = readLastData.subdivideIn(8 bits)
val writeRegHit = writeValidReg && writeAddressReg === readLastAddress
for(b <- writeMask.range){
when(writeHit && writeMask(b)){
writeMaskReg(b) := True
}
when(readValid) {
writeMaskReg(b) := writeMask(b)
}
when(readValid || (writeHit && writeMask(b))){
writeDataRegBytes(b) := writeDataBytes(b)
}
retBytes(b) := (writeRegHit && writeMaskReg(b)) ? writeDataRegBytes(b) | readLastDataBytes(b)
}
ret
}
//Long sample path
// def writeFirstRegWrap[T <: Data](sample : Bool, sampleAddress : UInt,lastAddress : UInt, readData : T, writeValid : Bool, writeAddress : UInt, writeData : T) : (T,T) = {
// val hit = writeValid && (sample ? sampleAddress | lastAddress) === writeAddress
// val bypass = hit ? writeData | readData
// val reg = RegNextWhen(bypass,sample || hit)
// (reg,bypass)
// }
//Short sample path
def writeFirstRegWrap[T <: Data](sample : Bool, sampleAddress : UInt,sampleLastAddress : UInt, sampleData : T, writeValid : Bool, writeAddress : UInt, writeData : T) = {
val bypass = (!sample || (writeValid && sampleAddress === writeAddress)) ? writeData | sampleData
val regEn = sample || (writeValid && sampleLastAddress === writeAddress)
val reg = RegNextWhen(bypass,regEn)
reg
}
def writeFirstRegWrap(sample : Bool, sampleAddress : UInt,sampleLastAddress : UInt, sampleData : Bits, writeValid : Bool, writeAddress : UInt, writeData : Bits,writeMask : Bits) = {
val byteCount = widthOf(writeMask)
val sampleWriteHit = writeValid && sampleAddress === writeAddress
val sampleLastHit = writeValid && sampleLastAddress === writeAddress
val regBytes = Vec(Bits(8 bits),byteCount)
for(b <- writeMask.range){
val bypass = Mux(!sample || (sampleWriteHit && writeMask(b)), writeData(b*8, 8 bits), sampleData(b*8, 8 bits))
val regEn = sample || (sampleLastHit && writeMask(b))
regBytes(b) := RegNextWhen(bypass,regEn)
}
regBytes.asBits
}
}
object DataCacheCpuCmdKind extends SpinalEnum{
val MEMORY,MANAGMENT = newElement()
}
object DataCacheCpuExecute{
implicit def implArgs(that : DataCacheCpuExecute) = that.args
}
case class DataCacheCpuExecute(p : DataCacheConfig) extends Bundle with IMasterSlave{
val isValid = Bool
val isStuck = Bool
val address = UInt(p.addressWidth bit)
// val haltIt = Bool
val args = DataCacheCpuExecuteArgs(p)
override def asMaster(): Unit = {
out(isValid, isStuck, args)
out(isValid, args, address)
// in(haltIt)
}
}
case class DataCacheCpuExecuteArgs(p : DataCacheConfig) extends Bundle{
val kind = DataCacheCpuCmdKind()
val wr = Bool
val address = UInt(p.addressWidth bit)
val data = Bits(p.cpuDataWidth bit)
val size = UInt(2 bits)
val forceUncachedAccess = Bool
val clean, invalidate, way = Bool
val isAtomic = ifGen(p.genAtomic){Bool}
// val all = Bool //Address should be zero when "all" is used
val isLrsc = p.withLrSc generate Bool()
val isAmo = p.withAmo generate Bool()
val amoCtrl = p.withAmo generate new Bundle {
val swap = Bool()
val alu = Bits(3 bits)
}
}
case class DataCacheCpuMemory(p : DataCacheConfig) extends Bundle with IMasterSlave{
val isValid = Bool
val isStuck = Bool
val isRemoved = Bool
val haltIt = Bool
val isWrite = Bool
val address = UInt(p.addressWidth bit)
val mmuBus = MemoryTranslatorBus()
override def asMaster(): Unit = {
out(isValid, isStuck, isRemoved)
in(haltIt)
out(isValid, isStuck, isRemoved, address)
in(isWrite)
slave(mmuBus)
}
}
@ -189,16 +115,18 @@ case class DataCacheCpuWriteBack(p : DataCacheConfig) extends Bundle with IMaste
val isStuck = Bool
val isUser = Bool
val haltIt = Bool
val isWrite = Bool
val data = Bits(p.cpuDataWidth bit)
val mmuMiss, illegalAccess, unalignedAccess , accessError = Bool
val badAddr = UInt(32 bits)
val clearAtomicEntries = ifGen(p.genAtomic) {Bool}
val address = UInt(p.addressWidth bit)
val mmuException, unalignedAccess , accessError = Bool
val clearLrsc = ifGen(p.withLrSc) {Bool}
// val exceptionBus = if(p.catchSomething) Flow(ExceptionCause()) else null
override def asMaster(): Unit = {
out(isValid,isStuck,isUser)
in(haltIt, data, mmuMiss,illegalAccess , unalignedAccess, accessError, badAddr)
outWithNull(clearAtomicEntries)
out(isValid,isStuck,isUser, address)
in(haltIt, data, mmuException, unalignedAccess, accessError, isWrite)
outWithNull(clearLrsc)
}
}
@ -207,10 +135,15 @@ case class DataCacheCpuBus(p : DataCacheConfig) extends Bundle with IMasterSlave
val memory = DataCacheCpuMemory(p)
val writeBack = DataCacheCpuWriteBack(p)
val redo = Bool()
val flush = Event
override def asMaster(): Unit = {
master(execute)
master(memory)
master(writeBack)
master(flush)
in(redo)
}
}
@ -370,8 +303,6 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave
class DataCache(p : DataCacheConfig) extends Component{
import p._
import DataCacheCpuCmdKind._
assert(wayCount == 1)
assert(cpuDataWidth == memDataWidth)
val io = new Bundle{
@ -379,6 +310,7 @@ class DataCache(p : DataCacheConfig) extends Component{
val mem = master(DataCacheMemBus(p))
// val flushDone = out Bool //It pulse at the same time than the manager.request.fire
}
val haltCpu = False
val lineWidth = bytePerLine*8
val lineCount = cacheSize/bytePerLine
@ -397,14 +329,13 @@ class DataCache(p : DataCacheConfig) extends Component{
class LineInfo() extends Bundle{
val used = Bool
val dirty = Bool
val valid, error = Bool()
val address = UInt(tagRange.length bit)
}
val tagsReadCmd = Flow(UInt(log2Up(wayLineCount) bits))
val tagsWriteCmd = Flow(new Bundle{
// val way = UInt(log2Up(wayCount) bits)
val way = Bits(wayCount bits)
val address = UInt(log2Up(wayLineCount) bits)
val data = new LineInfo()
})
@ -413,13 +344,36 @@ class DataCache(p : DataCacheConfig) extends Component{
val dataReadCmd = Flow(UInt(log2Up(wayWordCount) bits))
val dataWriteCmd = Flow(new Bundle{
// val way = UInt(log2Up(wayCount) bits)
val way = Bits(wayCount bits)
val address = UInt(log2Up(wayWordCount) bits)
val data = Bits(wordWidth bits)
val mask = Bits(wordWidth/8 bits)
})
val ways = for(i <- 0 until wayCount) yield new Area{
val tags = Mem(new LineInfo(), wayLineCount)
val data = Mem(Bits(wordWidth bit), wayWordCount)
//Reads
val tagsReadRsp = tags.readSync(tagsReadCmd.payload, tagsReadCmd.valid && !io.cpu.memory.isStuck)
val dataReadRsp = data.readSync(dataReadCmd.payload, dataReadCmd.valid && !io.cpu.memory.isStuck)
//Writes
when(tagsWriteCmd.valid && tagsWriteCmd.way(i)){
tags(tagsWriteCmd.address) := tagsWriteCmd.data
}
when(dataWriteCmd.valid && dataWriteCmd.way(i)){
data.write(
address = dataWriteCmd.address,
data = dataWriteCmd.data,
mask = dataWriteCmd.mask
)
}
}
tagsReadCmd.valid := False
tagsReadCmd.payload.assignDontCare()
dataReadCmd.valid := False
@ -428,376 +382,270 @@ class DataCache(p : DataCacheConfig) extends Component{
tagsWriteCmd.payload.assignDontCare()
dataWriteCmd.valid := False
dataWriteCmd.payload.assignDontCare()
io.mem.cmd.valid := False
io.mem.cmd.payload.assignDontCare()
val way = new Area{
val tags = Mem(new LineInfo(),wayLineCount)
val data = Mem(Bits(wordWidth bit),wayWordCount)
when(tagsWriteCmd.valid){
tags(tagsWriteCmd.address) := tagsWriteCmd.data
}
when(dataWriteCmd.valid){
data.write(
address = dataWriteCmd.address,
data = dataWriteCmd.data,
mask = dataWriteCmd.mask
)
}
val tagReadRspOneAddress = RegNextWhen(tagsReadCmd.payload, tagsReadCmd.valid)
val tagReadRspOne = Bypasser.writeFirstMemWrap(
readValid = tagsReadCmd.valid,
readLastAddress = tagReadRspOneAddress,
readLastData = tags.readSync(tagsReadCmd.payload,enable = tagsReadCmd.valid),
writeValid = tagsWriteCmd.valid,
writeAddress = tagsWriteCmd.address,
writeData = tagsWriteCmd.data
)
val dataReadRspOneKeepAddress = False
val dataReadRspOneAddress = RegNextWhen(dataReadCmd.payload, dataReadCmd.valid && !dataReadRspOneKeepAddress)
val dataReadRspOneWithoutBypass = data.readSync(dataReadCmd.payload,enable = dataReadCmd.valid)
val dataReadRspOne = Bypasser.writeFirstMemWrap(
readValid = dataReadCmd.valid,
readLastAddress = dataReadRspOneAddress,
readLastData = dataReadRspOneWithoutBypass,
writeValid = dataWriteCmd.valid,
writeAddress = dataWriteCmd.address,
writeData = dataWriteCmd.data,
writeMask = dataWriteCmd.mask
)
val tagReadRspTwoEnable = !io.cpu.writeBack.isStuck
val tagReadRspTwoRegIn = (tagsWriteCmd.valid && tagsWriteCmd.address === tagReadRspOneAddress) ? tagsWriteCmd.data | tagReadRspOne
val tagReadRspTwo = RegNextWhen(tagReadRspTwoRegIn ,tagReadRspTwoEnable)
val dataReadRspTwoEnable = !io.cpu.writeBack.isStuck
val dataReadRspTwo = Bypasser.writeFirstRegWrap(
sample = dataReadRspTwoEnable,
sampleAddress = dataReadRspOneAddress,
sampleLastAddress = RegNextWhen(dataReadRspOneAddress, dataReadRspTwoEnable),
sampleData = dataReadRspOne,
writeValid = dataWriteCmd.valid,
writeAddress = dataWriteCmd.address,
writeData = dataWriteCmd.data,
writeMask = dataWriteCmd.mask
)
}
when(io.cpu.execute.isValid && !io.cpu.execute.isStuck){
tagsReadCmd.valid := True
when(io.cpu.execute.isValid && !io.cpu.memory.isStuck){
tagsReadCmd.valid := True
dataReadCmd.valid := True
tagsReadCmd.payload := io.cpu.execute.address(lineRange)
dataReadCmd.valid := True
dataReadCmd.payload := io.cpu.execute.address(lineRange.high downto wordRange.low) //TODO FMAX maybe critical path could be default
dataReadCmd.payload := io.cpu.execute.address(lineRange.high downto wordRange.low)
}
val cpuMemoryStageNeedReadData = Bool()
val victim = new Area{
val requestIn = Stream(cloneable(new Bundle{
// val way = UInt(log2Up(wayCount) bits)
val address = UInt(p.addressWidth bits)
}))
requestIn.valid := False
requestIn.payload.assignDontCare()
val request = requestIn.halfPipe()
request.ready := False
val buffer = Mem(Bits(p.memDataWidth bits),memTransactionPerLine << tagSizeShift) // WARNING << tagSizeShift could resolve cyclone II issue, //.add(new AttributeString("ramstyle","M4K"))
//Send line read commands to fill the buffer
val readLineCmdCounter = Reg(UInt(log2Up(memTransactionPerLine + 1) bits)) init(0)
val dataReadCmdOccure = False
val dataReadRestored = RegInit(False)
when(request.valid){
when(!readLineCmdCounter.msb) {
readLineCmdCounter := readLineCmdCounter + 1
//dataReadCmd := request.address(lineRange.high downto wordRange.low) Done in the manager
dataReadCmdOccure := True
dataReadCmd.valid := True
dataReadCmd.payload := request.address(lineRange) @@ readLineCmdCounter(readLineCmdCounter.high - 1 downto 0)
way.dataReadRspOneKeepAddress := True
} otherwise {
when(!dataReadRestored && cpuMemoryStageNeedReadData) {
dataReadCmd.valid := True
dataReadCmd.payload := way.dataReadRspOneAddress //Restore stage one readed value
}
dataReadRestored := True
}
}
dataReadRestored clearWhen(request.ready)
io.cpu.memory.haltIt := cpuMemoryStageNeedReadData && request.valid && !dataReadRestored
//Fill the buffer with line read responses
val readLineRspCounter = Reg(UInt(log2Up(memTransactionPerLine + 1) bits)) init(0)
when(Delay(dataReadCmdOccure,1, init=False)){
buffer(readLineRspCounter.resized) := way.dataReadRspOneWithoutBypass
readLineRspCounter := readLineRspCounter + 1
}
//Send buffer read commands
val bufferReadCounter = Reg(UInt(log2Up(memTransactionPerLine + 1) bits)) init(0)
val bufferReadStream = Stream(buffer.addressType)
bufferReadStream.valid := readLineRspCounter > bufferReadCounter
bufferReadStream.payload := bufferReadCounter.resized
when(bufferReadStream.fire){
bufferReadCounter := bufferReadCounter + 1
}
val bufferReaded = buffer.streamReadSync(bufferReadStream).stage
bufferReaded.ready := False
//Send memory writes from bufffer read responses
val bufferReadedCounter = Reg(UInt(log2Up(memTransactionPerLine) bits)) init(0)
val memCmdAlreadyUsed = False
when(bufferReaded.valid) {
io.mem.cmd.valid := True
io.mem.cmd.wr := True
io.mem.cmd.address := request.address(tagRange.high downto lineRange.low) @@ U(0,lineRange.low bit)
io.mem.cmd.length := p.burstLength-1
io.mem.cmd.data := bufferReaded.payload
io.mem.cmd.mask := (1<<(wordWidth/8))-1
io.mem.cmd.last := bufferReadedCounter === bufferReadedCounter.maxValue
when(!memCmdAlreadyUsed && io.mem.cmd.ready){
bufferReaded.ready := True
bufferReadedCounter := bufferReadedCounter + 1
when(bufferReadedCounter === bufferReadedCounter.maxValue){
request.ready := True
}
}
}
val counter = Counter(memTransactionPerLine)
when(request.ready){
readLineCmdCounter.msb := False
readLineRspCounter.msb := False
bufferReadCounter.msb := False
def collisionProcess(readAddress : UInt, readMask : Bits): Bits ={
val ret = Bits(wayCount bits)
for(i <- 0 until wayCount){
ret(i) := dataWriteCmd.valid && dataWriteCmd.way(i) && dataWriteCmd.address === readAddress && (readMask & dataWriteCmd.mask) =/= 0
}
ret
}
val stageA = new Area{
val request = RegNextWhen(io.cpu.execute.args, !io.cpu.memory.isStuck)
io.cpu.memory.mmuBus.cmd.isValid := io.cpu.memory.isValid && request.kind === MEMORY //TODO filter request kind
io.cpu.memory.mmuBus.cmd.virtualAddress := request.address
io.cpu.memory.mmuBus.cmd.bypassTranslation := request.way
io.cpu.memory.mmuBus.end := !io.cpu.memory.isStuck || io.cpu.memory.isRemoved
cpuMemoryStageNeedReadData := io.cpu.memory.isValid && request.kind === MEMORY && !request.wr
}
val stageB = new Area {
val request = RegNextWhen(stageA.request, !io.cpu.writeBack.isStuck)
val mmuRsp = RegNextWhen(io.cpu.memory.mmuBus.rsp, !io.cpu.writeBack.isStuck)
val waysHit = if(waysHitRetime)
RegNextWhen(way.tagReadRspTwoRegIn.used && io.cpu.memory.mmuBus.rsp.physicalAddress(tagRange) === way.tagReadRspTwoRegIn.address,!io.cpu.writeBack.isStuck) //Manual retiming
else
way.tagReadRspTwo.used && mmuRsp.physicalAddress(tagRange) === way.tagReadRspTwo.address
//Loader interface
val loaderValid = False
val loaderReady = False
val loadingDone = RegNext(loaderValid && loaderReady) init(False) //one cycle pulse
//delayedXX are used to relax logic timings in flush and evict modes
val delayedIsStuck = RegNext(io.cpu.writeBack.isStuck)
val delayedWaysHitValid = RegNext(waysHit)
val victimNotSent = RegInit(False) clearWhen(victim.requestIn.ready) setWhen(!io.cpu.memory.isStuck)
val loadingNotDone = RegInit(False) clearWhen(loaderReady) setWhen(!io.cpu.memory.isStuck)
val writeMask = request.size.mux (
val stage0 = new Area{
val mask = io.cpu.execute.size.mux (
U(0) -> B"0001",
U(1) -> B"0011",
default -> B"1111"
) |<< mmuRsp.physicalAddress(1 downto 0)
) |<< io.cpu.execute.address(1 downto 0)
val colisions = collisionProcess(io.cpu.execute.address(lineRange.high downto wordRange.low), mask)
}
val stageA = new Area{
def stagePipe[T <: Data](that : T) = RegNextWhen(that, !io.cpu.memory.isStuck)
val request = stagePipe(io.cpu.execute.args)
val mask = stagePipe(stage0.mask)
io.cpu.memory.mmuBus.cmd.isValid := io.cpu.memory.isValid
io.cpu.memory.mmuBus.cmd.virtualAddress := io.cpu.memory.address
io.cpu.memory.mmuBus.cmd.bypassTranslation := False
io.cpu.memory.mmuBus.end := !io.cpu.memory.isStuck || io.cpu.memory.isRemoved
io.cpu.memory.isWrite := request.wr
val wayHits = earlyWaysHits generate ways.map(way => (io.cpu.memory.mmuBus.rsp.physicalAddress(tagRange) === way.tagsReadRsp.address && way.tagsReadRsp.valid))
val dataMux = earlyDataMux generate MuxOH(wayHits, ways.map(_.dataReadRsp))
val colisions = stagePipe(stage0.colisions) | collisionProcess(io.cpu.memory.address(lineRange.high downto wordRange.low), mask) //Assume the writeback stage will never be unstall memory acces while memory stage is stalled
}
val stageB = new Area {
def stagePipe[T <: Data](that : T) = RegNextWhen(that, !io.cpu.writeBack.isStuck)
val request = RegNextWhen(stageA.request, !io.cpu.writeBack.isStuck)
val mmuRspFreeze = False
val mmuRsp = RegNextWhen(io.cpu.memory.mmuBus.rsp, !io.cpu.writeBack.isStuck && !mmuRspFreeze)
val tagsReadRsp = ways.map(w => stagePipe(w.tagsReadRsp))
val dataReadRsp = !earlyDataMux generate ways.map(w => stagePipe(w.dataReadRsp))
val waysHits = if(earlyWaysHits) stagePipe(B(stageA.wayHits)) else B(tagsReadRsp.map(tag => mmuRsp.physicalAddress(tagRange) === tag.address && tag.valid).asBits())
val waysHit = waysHits.orR
val dataMux = if(earlyDataMux) stagePipe(stageA.dataMux) else MuxOH(waysHits, dataReadRsp)
val mask = stagePipe(stageA.mask)
val colisions = stagePipe(stageA.colisions)
//Loader interface
val loaderValid = False
val hadMemRspErrorReg = RegInit(False)
val hadMemRspError = (io.mem.rsp.valid && io.mem.rsp.error) || hadMemRspErrorReg
hadMemRspErrorReg := hadMemRspError && io.cpu.writeBack.haltIt
io.cpu.writeBack.haltIt := io.cpu.writeBack.isValid
io.cpu.writeBack.mmuMiss := False
io.cpu.writeBack.illegalAccess := False
io.cpu.writeBack.unalignedAccess := False
io.cpu.writeBack.accessError := (if(catchAccessError) hadMemRspError && !io.cpu.writeBack.haltIt else False)
io.cpu.writeBack.badAddr := request.address
//Evict the cache after reset logics
val bootEvicts = if(clearTagsAfterReset) new Area {
val flusher = new Area {
val valid = RegInit(True)
mmuRsp.physicalAddress init (0)
when(valid) {
tagsWriteCmd.valid := valid
tagsWriteCmd.address := mmuRsp.physicalAddress(lineRange)
tagsWriteCmd.data.used := False
when(mmuRsp.physicalAddress(lineRange) =/= lineCount - 1) {
tagsWriteCmd.way.setAll()
tagsWriteCmd.data.valid := False
io.cpu.writeBack.haltIt := True
when(mmuRsp.physicalAddress(lineRange) =/= wayLineCount - 1) {
mmuRsp.physicalAddress.getDrivingReg(lineRange) := mmuRsp.physicalAddress(lineRange) + 1
io.cpu.writeBack.haltIt := True
} otherwise {
valid := False
}
}
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){
io.cpu.flush.ready := True
mmuRsp.physicalAddress.getDrivingReg(lineRange) := 0
valid := True
}
}
val atomic = if(genAtomic) new Area{
case class AtomicEntry() extends Bundle{
val valid = Bool()
val size = UInt(2 bits)
val address = UInt(addressWidth bits)
val lrsc = withLrSc generate new Area{
val reserved = RegInit(False)
when(io.cpu.writeBack.isValid && !io.cpu.writeBack.isStuck && !io.cpu.redo && request.isLrsc && !request.wr){
reserved := True
}
when(io.cpu.writeBack.clearLrsc){
reserved := False
}
}
def init: this.type ={
valid init(False)
this
}
}
val entries = Vec(Reg(AtomicEntry()).init, atomicEntriesCount)
val entriesAllocCounter = Counter(atomicEntriesCount)
val entriesHit = entries.map(e => e.valid && e.size === request.size && e.address === request.address).orR
when(io.cpu.writeBack.isValid && request.isAtomic && !request.wr){
entries(entriesAllocCounter).valid := True
entries(entriesAllocCounter).size := request.size
entries(entriesAllocCounter).address := request.address
when(!io.cpu.writeBack.isStuck){
entriesAllocCounter.increment()
}
}
when(io.cpu.writeBack.clearAtomicEntries){
entries.foreach(_.valid := False)
}
val requestDataBypass = CombInit(request.data)
val isAmo = if(withAmo) request.isAmo else False
val amo = withAmo generate new Area{
def rf = request.data
def mem = dataMux
when(request.isAtomic && ! entriesHit){
writeMask := 0
}
} else null
val compare = request.amoCtrl.alu.msb
val unsigned = request.amoCtrl.alu(2 downto 1) === B"11"
val addSub = (rf.asSInt + Mux(compare, ~mem, mem).asSInt + Mux(compare, S(1), S(0))).asBits
val less = Mux(rf.msb === mem.msb, addSub.msb, Mux(unsigned, mem.msb, rf.msb))
val selectRf = request.amoCtrl.swap ? True | (request.amoCtrl.alu.lsb ^ less)
val result = (request.amoCtrl.alu | (request.amoCtrl.swap ## B"00")).mux(
B"000" -> addSub,
B"001" -> (rf ^ mem),
B"010" -> (rf | mem),
B"011" -> (rf & mem),
default -> (selectRf ? rf | mem)
)
val resultRegValid = RegNext(True) clearWhen(!io.cpu.writeBack.isStuck)
val resultReg = RegNext(result)
}
val memCmdSent = RegInit(False) setWhen (io.mem.cmd.ready) clearWhen (!io.cpu.writeBack.isStuck)
io.cpu.redo := False
io.cpu.writeBack.accessError := False
io.cpu.writeBack.mmuException := io.cpu.writeBack.isValid && (if(catchIllegal) mmuRsp.exception || (!mmuRsp.allowWrite && request.wr) || (!mmuRsp.allowRead && (!request.wr || isAmo)) else False)
io.cpu.writeBack.unalignedAccess := io.cpu.writeBack.isValid && (if(catchUnaligned) ((request.size === 2 && mmuRsp.physicalAddress(1 downto 0) =/= 0) || (request.size === 1 && mmuRsp.physicalAddress(0 downto 0) =/= 0)) else False)
io.cpu.writeBack.isWrite := request.wr
io.mem.cmd.valid := False
io.mem.cmd.address.assignDontCare()
io.mem.cmd.length.assignDontCare()
io.mem.cmd.last.assignDontCare()
io.mem.cmd.wr := request.wr
io.mem.cmd.mask := mask
io.mem.cmd.data := requestDataBypass
when(io.cpu.writeBack.isValid) {
if (catchMemoryTranslationMiss) {
io.cpu.writeBack.mmuMiss := mmuRsp.miss
}
switch(request.kind) {
is(MANAGMENT) {
when(delayedIsStuck && !mmuRsp.miss) {
when(delayedWaysHitValid || (request.way && way.tagReadRspTwo.used)) {
io.cpu.writeBack.haltIt.clearWhen(!(victim.requestIn.valid && !victim.requestIn.ready))
victim.requestIn.valid := request.clean && way.tagReadRspTwo.dirty
tagsWriteCmd.valid := victim.requestIn.ready
} otherwise{
io.cpu.writeBack.haltIt := False
}
}
when(mmuRsp.isIoAccess) {
io.cpu.writeBack.haltIt.clearWhen(request.wr ? io.mem.cmd.ready | io.mem.rsp.valid)
victim.requestIn.address := way.tagReadRspTwo.address @@ mmuRsp.physicalAddress(lineRange) @@ U((lineRange.low - 1 downto 0) -> false)
tagsWriteCmd.address := mmuRsp.physicalAddress(lineRange)
tagsWriteCmd.data.used := !request.invalidate
tagsWriteCmd.data.dirty := !request.clean
io.mem.cmd.valid := !memCmdSent
io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto wordRange.low) @@ U(0, wordRange.low bit)
io.mem.cmd.length := 0
io.mem.cmd.last := True
if(withLrSc) when(request.isLrsc && !lrsc.reserved){
io.mem.cmd.valid := False
io.cpu.writeBack.haltIt := False
}
is(MEMORY) {
val illegal = if(catchIllegal) (request.wr && !mmuRsp.allowWrite) || (!request.wr && !mmuRsp.allowRead) || (io.cpu.writeBack.isUser && !mmuRsp.allowUser) else False
val unaligned = if(catchUnaligned) ((request.size === 2 && mmuRsp.physicalAddress(1 downto 0) =/= 0) || (request.size === 1 && mmuRsp.physicalAddress(0 downto 0) =/= 0)) else False
io.cpu.writeBack.illegalAccess := illegal
io.cpu.writeBack.unalignedAccess := unaligned
when((Bool(!catchMemoryTranslationMiss) || !mmuRsp.miss) && !illegal && !unaligned) {
when(request.forceUncachedAccess || mmuRsp.isIoAccess) {
val memCmdSent = RegInit(False)
when(!victim.request.valid) {
//Avoid mixing memory request while victim is pending
io.mem.cmd.wr := request.wr
io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto wordRange.low) @@ U(0, wordRange.low bit)
io.mem.cmd.mask := writeMask
io.mem.cmd.data := request.data
io.mem.cmd.length := 0
io.mem.cmd.last := True
} otherwise {
when(waysHit || request.wr && !isAmo) { //Do not require a cache refill ?
//Data cache update
dataWriteCmd.valid setWhen(request.wr && waysHit)
dataWriteCmd.address := mmuRsp.physicalAddress(lineRange.high downto wordRange.low)
dataWriteCmd.data := requestDataBypass
dataWriteCmd.mask := mask
dataWriteCmd.way := waysHits
when(!memCmdSent) {
io.mem.cmd.valid := True
memCmdSent setWhen (io.mem.cmd.ready)
}
//Write through
io.mem.cmd.valid setWhen(request.wr)
io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto wordRange.low) @@ U(0, wordRange.low bit)
io.mem.cmd.length := 0
io.mem.cmd.last := True
io.cpu.writeBack.haltIt clearWhen(!request.wr || io.mem.cmd.ready)
io.cpu.writeBack.haltIt.clearWhen(memCmdSent && (io.mem.rsp.fire || request.wr)) //Cut mem.cmd.ready path but insert one cycle stall when write
}
memCmdSent clearWhen (!io.cpu.writeBack.isStuck)
} otherwise {
when(waysHit || !loadingNotDone) {
io.cpu.writeBack.haltIt := False
dataWriteCmd.valid := request.wr
dataWriteCmd.address := mmuRsp.physicalAddress(lineRange.high downto wordRange.low)
dataWriteCmd.data := request.data
dataWriteCmd.mask := writeMask
tagsWriteCmd.valid := (!loadingNotDone) || request.wr
tagsWriteCmd.address := mmuRsp.physicalAddress(lineRange)
tagsWriteCmd.data.used := True
tagsWriteCmd.data.dirty := request.wr
tagsWriteCmd.data.address := mmuRsp.physicalAddress(tagRange)
} otherwise {
val victimRequired = way.tagReadRspTwo.used && way.tagReadRspTwo.dirty
loaderValid := loadingNotDone && !(victimNotSent && victim.request.isStall) //Additional condition used to be sure of that all previous victim are written into the RAM
victim.requestIn.valid := victimRequired && victimNotSent
victim.requestIn.address := way.tagReadRspTwo.address @@ mmuRsp.physicalAddress(lineRange) @@ U((lineRange.low - 1 downto 0) -> false)
}
if(withAmo) when(isAmo){
when(!amo.resultRegValid) {
io.mem.cmd.valid := False
dataWriteCmd.valid := False
io.cpu.writeBack.haltIt := True
}
}
//On write to read colisions
when((!request.wr || isAmo) && (colisions & waysHits) =/= 0){
io.cpu.redo := True
if(withAmo) io.mem.cmd.valid := False
}
if(withLrSc) when(request.isLrsc && !lrsc.reserved){
io.mem.cmd.valid := False
dataWriteCmd.valid := False
io.cpu.writeBack.haltIt := False
}
} otherwise { //Do refill
//Emit cmd
io.mem.cmd.valid setWhen(!memCmdSent)
io.mem.cmd.wr := False
io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto lineRange.low) @@ U(0,lineRange.low bit)
io.mem.cmd.length := p.burstLength-1
io.mem.cmd.last := True
loaderValid setWhen(io.mem.cmd.ready)
}
}
}
when(mmuRsp.isIoAccess){
io.cpu.writeBack.data := io.mem.rsp.data
if(catchAccessError) io.cpu.writeBack.accessError := io.mem.rsp.valid && io.mem.rsp.error
} otherwise {
io.cpu.writeBack.data := dataMux
if(catchAccessError) io.cpu.writeBack.accessError := (waysHits & B(tagsReadRsp.map(_.error))) =/= 0
}
//remove side effects on exceptions
when(mmuRsp.refilling || io.cpu.writeBack.accessError || io.cpu.writeBack.mmuException || io.cpu.writeBack.unalignedAccess){
io.mem.cmd.valid := False
tagsWriteCmd.valid := False
dataWriteCmd.valid := False
loaderValid := False
io.cpu.writeBack.haltIt := False
}
io.cpu.redo setWhen(io.cpu.writeBack.isValid && mmuRsp.refilling)
assert(!(io.cpu.writeBack.isValid && !io.cpu.writeBack.haltIt && io.cpu.writeBack.isStuck), "writeBack stuck by another plugin is not allowed")
io.cpu.writeBack.data := (request.forceUncachedAccess || mmuRsp.isIoAccess) ? io.mem.rsp.data | way.dataReadRspTwo //not multi ways
if(genAtomic){
when(request.isAtomic && request.wr){
io.cpu.writeBack.data := (!atomic.entriesHit).asBits.resized
if(withLrSc){
when(request.isLrsc && request.wr){
io.cpu.writeBack.data := (!lrsc.reserved).asBits.resized
}
}
if(withAmo){
when(request.isAmo){
requestDataBypass := amo.resultReg
}
}
}
//The whole life of a loading task, the corresponding manager request is present
val loader = new Area{
val valid = RegNext(stageB.loaderValid) init(False)
val valid = RegInit(False) setWhen(stageB.loaderValid)
val baseAddress = stageB.mmuRsp.physicalAddress
val memCmdSent = RegInit(False)
when(valid && !memCmdSent) {
io.mem.cmd.valid := True
io.mem.cmd.wr := False
io.mem.cmd.address := baseAddress(tagRange.high downto lineRange.low) @@ U(0,lineRange.low bit)
io.mem.cmd.length := p.burstLength-1
io.mem.cmd.last := True
}
when(valid && io.mem.cmd.ready){
memCmdSent := True
}
when(valid && !memCmdSent) {
victim.memCmdAlreadyUsed := True
}
val counter = Counter(memTransactionPerLine)
val waysAllocator = Reg(Bits(wayCount bits)) init(1)
val error = RegInit(False)
when(valid && io.mem.rsp.valid){
dataWriteCmd.valid := True
dataWriteCmd.address := baseAddress(lineRange) @@ counter
dataWriteCmd.data := io.mem.rsp.data
dataWriteCmd.mask := (1<<(wordWidth/8))-1
dataWriteCmd.mask.setAll()
dataWriteCmd.way := waysAllocator
error := error | io.mem.rsp.error
counter.increment()
}
when(counter.willOverflow){
memCmdSent := False
valid := False
stageB.loaderReady := True
//Update tags
tagsWriteCmd.valid := True
tagsWriteCmd.address := baseAddress(lineRange)
tagsWriteCmd.data.valid := True
tagsWriteCmd.data.address := baseAddress(tagRange)
tagsWriteCmd.data.error := error || io.mem.rsp.error
tagsWriteCmd.way := waysAllocator
waysAllocator := (waysAllocator ## waysAllocator.msb).resized
error := False
}
io.cpu.redo setWhen(valid)
stageB.mmuRspFreeze setWhen(stageB.loaderValid || valid)
}
}

View file

@ -17,7 +17,6 @@ case class InstructionCacheConfig( cacheSize : Int,
memDataWidth : Int,
catchIllegalAccess : Boolean,
catchAccessFault : Boolean,
catchMemoryTranslationMiss : Boolean,
asyncTagMemory : Boolean,
twoCycleCache : Boolean = true,
twoCycleRam : Boolean = false,
@ -26,7 +25,7 @@ case class InstructionCacheConfig( cacheSize : Int,
assert(!(twoCycleRam && !twoCycleCache))
def burstSize = bytePerLine*8/memDataWidth
def catchSomething = catchAccessFault || catchMemoryTranslationMiss || catchIllegalAccess
def catchSomething = catchAccessFault || catchIllegalAccess
def getAxi4Config() = Axi4Config(
addressWidth = addressWidth,
@ -86,7 +85,7 @@ trait InstructionCacheCommons{
val pc : UInt
val physicalAddress : UInt
val data : Bits
val cacheMiss, error, mmuMiss, illegalAccess, isUser : Bool
val cacheMiss, error, mmuRefilling, mmuException, isUser : Bool
}
case class InstructionCacheCpuFetch(p : InstructionCacheConfig) extends Bundle with IMasterSlave with InstructionCacheCommons {
@ -99,11 +98,12 @@ case class InstructionCacheCpuFetch(p : InstructionCacheConfig) extends Bundle w
val dataBypass = Bits(p.cpuDataWidth bits)
val mmuBus = MemoryTranslatorBus()
val physicalAddress = UInt(p.addressWidth bits)
val cacheMiss, error, mmuMiss, illegalAccess,isUser = ifGen(!p.twoCycleCache)(Bool)
val cacheMiss, error, mmuRefilling, mmuException, isUser = ifGen(!p.twoCycleCache)(Bool)
val haltIt = Bool
override def asMaster(): Unit = {
out(isValid, isStuck, isRemoved, pc)
inWithNull(error,mmuMiss,illegalAccess,data, cacheMiss,physicalAddress)
inWithNull(error,mmuRefilling,mmuException,data, cacheMiss,physicalAddress, haltIt)
outWithNull(isUser, dataBypass, dataBypassValid)
slaveWithNull(mmuBus)
}
@ -116,12 +116,12 @@ case class InstructionCacheCpuDecode(p : InstructionCacheConfig) extends Bundle
val pc = UInt(p.addressWidth bits)
val physicalAddress = UInt(p.addressWidth bits)
val data = Bits(p.cpuDataWidth bits)
val cacheMiss, error, mmuMiss, illegalAccess, isUser = ifGen(p.twoCycleCache)(Bool)
val cacheMiss, error, mmuRefilling, mmuException, isUser = ifGen(p.twoCycleCache)(Bool)
override def asMaster(): Unit = {
out(isValid, isStuck, pc)
outWithNull(isUser)
inWithNull(error,mmuMiss,illegalAccess,data, cacheMiss, physicalAddress)
inWithNull(error, mmuRefilling, mmuException,data, cacheMiss, physicalAddress)
}
}
@ -250,7 +250,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{
import p._
assert(cpuDataWidth == memDataWidth, "Need testing")
val io = new Bundle{
val flush = slave(InstructionCacheFlushBus())
val flush = in Bool()
val cpu = slave(InstructionCacheCpuBus(p))
val mem = master(InstructionCacheMemBus(p))
}
@ -291,25 +291,23 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{
}
})
io.cpu.prefetch.haltIt := False
io.cpu.fetch.haltIt := io.cpu.fetch.mmuBus.busy
val lineLoader = new Area{
val fire = False
val valid = RegInit(False) clearWhen(fire)
val address = Reg(UInt(addressWidth bits))
val hadError = RegInit(False) clearWhen(fire)
val flushPending = RegInit(True)
when(io.cpu.fill.valid){
valid := True
address := io.cpu.fill.payload
}
io.cpu.prefetch.haltIt setWhen(valid)
io.cpu.prefetch.haltIt := valid || flushPending
val flushCounter = Reg(UInt(log2Up(wayLineCount) + 1 bit)) init(if(preResetFlush) wayLineCount else 0)
val flushCounter = Reg(UInt(log2Up(wayLineCount) + 1 bit))
when(!flushCounter.msb){
io.cpu.prefetch.haltIt := True
flushCounter := flushCounter + 1
@ -317,17 +315,16 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{
when(!RegNext(flushCounter.msb)){
io.cpu.prefetch.haltIt := True
}
val flushFromInterface = RegInit(False)
io.flush.cmd.ready := !(valid || io.cpu.fetch.isValid) //io.cpu.fetch.isValid will avoid bug on first cycle miss
when(io.flush.cmd.valid){
when(io.flush){
io.cpu.prefetch.haltIt := True
when(io.flush.cmd.ready){
flushCounter := 0
flushFromInterface := True
}
flushPending := True
}
io.flush.rsp := flushCounter.msb.rise && flushFromInterface
when(flushPending && !(valid || io.cpu.fetch.isValid) ){
flushCounter := 0
flushPending := False
}
@ -411,8 +408,8 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{
io.cpu.fetch.cacheMiss := !hit.valid
io.cpu.fetch.error := hit.error
io.cpu.fetch.mmuMiss := mmuRsp.miss
io.cpu.fetch.illegalAccess := !mmuRsp.allowExecute || (io.cpu.fetch.isUser && !mmuRsp.allowUser)
io.cpu.fetch.mmuRefilling := mmuRsp.refilling
io.cpu.fetch.mmuException := !mmuRsp.refilling && (mmuRsp.exception || !mmuRsp.allowExecute)
})
}
@ -441,8 +438,8 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{
io.cpu.decode.cacheMiss := !hit.valid
io.cpu.decode.error := hit.error
io.cpu.decode.mmuMiss := mmuRsp.miss
io.cpu.decode.illegalAccess := !mmuRsp.allowExecute || (io.cpu.decode.isUser && !mmuRsp.allowUser)
io.cpu.decode.mmuRefilling := mmuRsp.refilling
io.cpu.decode.mmuException := !mmuRsp.refilling && (mmuRsp.exception || !mmuRsp.allowExecute)
io.cpu.decode.physicalAddress := mmuRsp.physicalAddress
})
}

View file

@ -55,6 +55,7 @@ class BranchPlugin(earlyBranch : Boolean,
fenceiGenAsAJump : Boolean = false,
fenceiGenAsANop : Boolean = false) extends Plugin[VexRiscv] with PredictionInterface{
def catchAddressMisalignedForReal = catchAddressMisaligned && !pipeline(RVC_GEN)
lazy val branchStage = if(earlyBranch) pipeline.execute else pipeline.memory
@ -88,6 +89,8 @@ class BranchPlugin(earlyBranch : Boolean,
import pipeline.config._
import IntAluPlugin._
assert(earlyBranch || withMemoryStage, "earlyBranch must be true when memory stage is disabled!")
val bActions = List[(Stageable[_ <: BaseType],Any)](
SRC1_CTRL -> Src1CtrlEnum.RS,
SRC2_CTRL -> Src2CtrlEnum.RS,
@ -265,7 +268,7 @@ class BranchPlugin(earlyBranch : Boolean,
default{
branch_src1 := input(PC)
branch_src2 := ((input(BRANCH_CTRL) === BranchCtrlEnum.JAL) ? imm.j_sext | imm.b_sext).asUInt
when(input(PREDICTION_HAD_BRANCHED) && ! missAlignedTarget){
when(input(PREDICTION_HAD_BRANCHED)){ //Assume the predictor never predict missaligned stuff, this avoid the need to know if the instruction should branch or not
branch_src2 := (if(pipeline(RVC_GEN)) Mux(input(IS_RVC), B(2), B(4)) else B(4)).asUInt.resized
}
}
@ -375,4 +378,4 @@ class BranchPlugin(earlyBranch : Boolean,
}
}
}
}
}

View file

@ -51,10 +51,11 @@ case class CsrPluginConfig(
ucycleAccess : CsrAccess,
wfiGenAsWait : Boolean,
ecallGen : Boolean,
mtvecModeGen : Boolean = false,
xtvecModeGen : Boolean = false,
noCsrAlu : Boolean = false,
wfiGenAsNop : Boolean = false,
ebreakGen : Boolean = false,
userGen : Boolean = false,
supervisorGen : Boolean = false,
sscratchGen : Boolean = false,
stvecAccess : CsrAccess = CsrAccess.NONE,
@ -70,7 +71,7 @@ case class CsrPluginConfig(
deterministicInteruptionEntry : Boolean = false //Only used for simulatation purposes
){
assert(!ucycleAccess.canWrite)
def privilegeGen = userGen || supervisorGen
def noException = this.copy(ecallGen = false, ebreakGen = false, catchIllegalAccess = false)
}
@ -78,26 +79,104 @@ object CsrPluginConfig{
def all : CsrPluginConfig = all(0x00000020l)
def small : CsrPluginConfig = small(0x00000020l)
def smallest : CsrPluginConfig = smallest(0x00000020l)
def linuxMinimal(mtVecInit : BigInt) = CsrPluginConfig(
catchIllegalAccess = true,
mvendorid = 1,
marchid = 2,
mimpid = 3,
mhartid = 0,
misaExtensionsInit = 0, //TODO
misaAccess = CsrAccess.NONE, //Read required by some regressions
mtvecAccess = CsrAccess.WRITE_ONLY, //Read required by some regressions
mtvecInit = mtVecInit,
mepcAccess = CsrAccess.READ_WRITE,
mscratchGen = true,
mcauseAccess = CsrAccess.READ_ONLY,
mbadaddrAccess = CsrAccess.READ_ONLY,
mcycleAccess = CsrAccess.NONE,
minstretAccess = CsrAccess.NONE,
ucycleAccess = CsrAccess.NONE,
wfiGenAsWait = true,
ecallGen = true,
xtvecModeGen = false,
noCsrAlu = false,
wfiGenAsNop = false,
ebreakGen = true,
userGen = true,
supervisorGen = true,
sscratchGen = true,
stvecAccess = CsrAccess.READ_WRITE,
sepcAccess = CsrAccess.READ_WRITE,
scauseAccess = CsrAccess.READ_WRITE,
sbadaddrAccess = CsrAccess.READ_WRITE,
scycleAccess = CsrAccess.NONE,
sinstretAccess = CsrAccess.NONE,
satpAccess = CsrAccess.NONE, //Implemented into the MMU plugin
medelegAccess = CsrAccess.WRITE_ONLY,
midelegAccess = CsrAccess.WRITE_ONLY,
pipelineCsrRead = false,
deterministicInteruptionEntry = false
)
def linuxFull(mtVecInit : BigInt) = CsrPluginConfig(
catchIllegalAccess = true,
mvendorid = 1,
marchid = 2,
mimpid = 3,
mhartid = 0,
misaExtensionsInit = 0, //TODO
misaAccess = CsrAccess.READ_WRITE,
mtvecAccess = CsrAccess.READ_WRITE,
mtvecInit = mtVecInit,
mepcAccess = CsrAccess.READ_WRITE,
mscratchGen = true,
mcauseAccess = CsrAccess.READ_WRITE,
mbadaddrAccess = CsrAccess.READ_WRITE,
mcycleAccess = CsrAccess.READ_WRITE,
minstretAccess = CsrAccess.READ_WRITE,
ucycleAccess = CsrAccess.READ_ONLY,
wfiGenAsWait = true,
ecallGen = true,
xtvecModeGen = false,
noCsrAlu = false,
wfiGenAsNop = false,
ebreakGen = false,
userGen = true,
supervisorGen = true,
sscratchGen = true,
stvecAccess = CsrAccess.READ_WRITE,
sepcAccess = CsrAccess.READ_WRITE,
scauseAccess = CsrAccess.READ_WRITE,
sbadaddrAccess = CsrAccess.READ_WRITE,
scycleAccess = CsrAccess.READ_WRITE,
sinstretAccess = CsrAccess.READ_WRITE,
satpAccess = CsrAccess.NONE, //Implemented into the MMU plugin
medelegAccess = CsrAccess.READ_WRITE,
midelegAccess = CsrAccess.READ_WRITE,
pipelineCsrRead = false,
deterministicInteruptionEntry = false
)
def all(mtvecInit : BigInt) : CsrPluginConfig = CsrPluginConfig(
catchIllegalAccess = true,
mvendorid = 11,
marchid = 22,
mimpid = 33,
mhartid = 0,
mvendorid = 11,
marchid = 22,
mimpid = 33,
mhartid = 0,
misaExtensionsInit = 66,
misaAccess = CsrAccess.READ_WRITE,
mtvecAccess = CsrAccess.READ_WRITE,
mtvecInit = mtvecInit,
mepcAccess = CsrAccess.READ_WRITE,
mscratchGen = true,
mcauseAccess = CsrAccess.READ_WRITE,
mbadaddrAccess = CsrAccess.READ_WRITE,
mcycleAccess = CsrAccess.READ_WRITE,
minstretAccess = CsrAccess.READ_WRITE,
ecallGen = true,
wfiGenAsWait = true,
ucycleAccess = CsrAccess.READ_ONLY
misaAccess = CsrAccess.READ_WRITE,
mtvecAccess = CsrAccess.READ_WRITE,
mtvecInit = mtvecInit,
mepcAccess = CsrAccess.READ_WRITE,
mscratchGen = true,
mcauseAccess = CsrAccess.READ_WRITE,
mbadaddrAccess = CsrAccess.READ_WRITE,
mcycleAccess = CsrAccess.READ_WRITE,
minstretAccess = CsrAccess.READ_WRITE,
ecallGen = true,
wfiGenAsWait = true,
ucycleAccess = CsrAccess.READ_ONLY
)
def all2(mtvecInit : BigInt) : CsrPluginConfig = CsrPluginConfig(
@ -177,6 +256,7 @@ object CsrPluginConfig{
}
case class CsrWrite(that : Data, bitOffset : Int)
case class CsrRead(that : Data , bitOffset : Int)
case class CsrReadToWriteOverride(that : Data, bitOffset : Int) //Used for special cases, as MIP where there shadow stuff
case class CsrOnWrite(doThat :() => Unit)
case class CsrOnRead(doThat : () => Unit)
case class CsrMapping() extends CsrInterface{
@ -184,6 +264,7 @@ case class CsrMapping() extends CsrInterface{
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))
override def r2w(csrAddress : Int, bitOffset : Int, that : Data): Unit = addMappingAt(csrAddress, CsrReadToWriteOverride(that,bitOffset))
override def onWrite(csrAddress: Int)(body: => Unit): Unit = addMappingAt(csrAddress, CsrOnWrite(() => body))
override def onRead(csrAddress: Int)(body: => Unit): Unit = addMappingAt(csrAddress, CsrOnRead(() => {body}))
}
@ -199,6 +280,8 @@ trait CsrInterface{
w(csrAddress,bitOffset,that)
}
def r2w(csrAddress : Int, bitOffset : Int,that : Data): Unit
def rw(csrAddress : Int, thats : (Int, Data)*) : Unit = for(that <- thats) rw(csrAddress,that._1, that._2)
def w(csrAddress : Int, thats : (Int, Data)*) : Unit = for(that <- thats) w(csrAddress,that._1, that._2)
def r(csrAddress : Int, thats : (Int, Data)*) : Unit = for(that <- thats) r(csrAddress,that._1, that._2)
@ -244,9 +327,13 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
interface
}
var exceptionPendings : Vec[Bool] = null
override def isExceptionPending(stage : Stage): Bool = exceptionPendings(pipeline.stages.indexOf(stage))
var jumpInterface : Flow[UInt] = null
var timerInterrupt, externalInterrupt : Bool = null
var timerInterruptS, externalInterruptS : Bool = null
var timerInterrupt, externalInterrupt, softwareInterrupt : Bool = null
var externalInterruptS : Bool = null
var forceMachineWire : Bool = null
var privilege : UInt = null
var selfException : Flow[ExceptionCause] = null
var contextSwitching : Bool = null
@ -270,23 +357,20 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
val csrMapping = new CsrMapping()
//Interruption and exception data model
case class Delegator(var enable : Bool, privilege : Int)
case class InterruptSpec(var cond : Bool, id : Int, privilege : Int, delegators : List[Delegator])
case class ExceptionSpec(id : Int, delegators : List[Delegator])
var interruptSpecs = ArrayBuffer[InterruptSpec]()
var exceptionSpecs = ArrayBuffer[ExceptionSpec]()
case class InterruptSource(var cond : Bool, id : Int)
case class InterruptPrivilege(privilege : Int){
var privilegeCond : Bool = null
val sources = ArrayBuffer[InterruptSource]()
def addInterrupt(cond : Bool, id : Int, privilege : Int, delegators : List[Delegator]): Unit = {
interruptSpecs += InterruptSpec(cond, id, privilege, delegators)
}
def getInterruptPrivilege(privilege : Int) = customInterrupts.getOrElseUpdate(privilege, InterruptPrivilege(privilege))
var customInterrupts = mutable.LinkedHashMap[Int, InterruptPrivilege]()
def addInterrupt(cond : Bool, id : Int, privilege : Int): Unit = {
getInterruptPrivilege(privilege).sources += InterruptSource(cond, id)
}
def createInterrupt(id : Int, privilege : Int) : Bool = { val ret = Bool(); addInterrupt(ret, id, privilege); ret}
override def r(csrAddress: Int, bitOffset: Int, that: Data): Unit = csrMapping.r(csrAddress, bitOffset, that)
override def w(csrAddress: Int, bitOffset: Int, that: Data): Unit = csrMapping.w(csrAddress, bitOffset, that)
override def r2w(csrAddress: Int, bitOffset: Int, that: Data): Unit = csrMapping.r2w(csrAddress, bitOffset, that)
override def onWrite(csrAddress: Int)(body: => Unit): Unit = csrMapping.onWrite(csrAddress)(body)
override def onRead(csrAddress: Int)(body: => Unit): Unit = csrMapping.onRead(csrAddress)(body)
@ -336,16 +420,18 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
jumpInterface.valid := False
jumpInterface.payload.assignDontCare()
exceptionPendings = Vec(Bool, pipeline.stages.length)
timerInterrupt = in Bool() setName("timerInterrupt")
externalInterrupt = in Bool() setName("externalInterrupt")
softwareInterrupt = in Bool() setName("softwareInterrupt") default(False)
if(supervisorGen){
timerInterruptS = in Bool() setName("timerInterruptS")
// timerInterruptS = in Bool() setName("timerInterruptS")
externalInterruptS = in Bool() setName("externalInterruptS")
}
contextSwitching = Bool().setName("contextSwitching")
privilege = RegInit(U"11").setName("CsrPlugin_privilege")
privilege = UInt(2 bits).setName("CsrPlugin_privilege")
forceMachineWire = False
if(catchIllegalAccess || ecallGen || ebreakGen)
selfException = newExceptionPort(pipeline.execute)
@ -353,16 +439,19 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
allowInterrupts = True
allowException = True
for (privilege <- customInterrupts.values;
source <- privilege.sources){
source.cond = source.cond.pull()
}
for (i <- interruptSpecs) i.cond = i.cond.pull()
pipeline.update(MPP, UInt(2 bits))
}
def inhibateInterrupts() : Unit = allowInterrupts := False
def inhibateException() : Unit = allowException := False
def isUser(stage : Stage) : Bool = privilege === 0
override def isUser() : Bool = privilege === 0
override def isSupervisor(): Bool = privilege === 1
override def isMachine(): Bool = privilege === 3
override def forceMachine(): Unit = forceMachineWire := True
override def build(pipeline: VexRiscv): Unit = {
import pipeline._
@ -382,6 +471,16 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
}
case class Xtvec() extends Bundle {
val mode = Bits(2 bits)
val base = UInt(xlen-2 bits)
}
val privilegeReg = privilegeGen generate RegInit(U"11")
privilege := (if(privilegeGen) privilegeReg else U"11")
when(forceMachineWire) { privilege := 3 }
val machineCsr = pipeline plug new Area{
//Define CSR registers
// Status => MXR, SUM, TVM, TW, TSE ?
@ -390,11 +489,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
val extensions = Reg(Bits(26 bits)) init(misaExtensionsInit) allowUnsetRegToAvoidLatch
}
val mtvec = new Area{
val mode = Reg(Bits(2 bits)).allowUnsetRegToAvoidLatch
val base = Reg(UInt(xlen-2 bits)).allowUnsetRegToAvoidLatch
}
val mtvec = Reg(Xtvec()).allowUnsetRegToAvoidLatch
if(mtvecInit != null) mtvec.mode init(mtvecInit & 0x3)
if(mtvecInit != null) mtvec.base init(mtvecInit / 4)
@ -404,9 +499,9 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
val MPP = RegInit(U"11")
}
val mip = new Area{
val MEIP = RegNext(externalInterrupt) init(False)
val MTIP = RegNext(timerInterrupt) init(False)
val MSIP = RegInit(False)
val MEIP = RegNext(externalInterrupt)
val MTIP = RegNext(timerInterrupt)
val MSIP = RegNext(softwareInterrupt)
}
val mie = new Area{
val MEIE, MTIE, MSIE = RegInit(False)
@ -421,9 +516,13 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
val minstret = Reg(UInt(64 bits)) randBoot()
val medeleg = Reg(Bits(32 bits)) init(0)
val mideleg = Reg(Bits(32 bits)) init(0)
val medeleg = supervisorGen generate new Area {
val IAM, IAF, II, LAM, LAF, SAM, SAF, EU, ES, IPF, LPF, SPF = RegInit(False)
val mapping = mutable.HashMap(0 -> IAM, 1 -> IAF, 2 -> II, 4 -> LAM, 5 -> LAF, 6 -> SAM, 7 -> SAF, 8 -> EU, 9 -> ES, 12 -> IPF, 13 -> LPF, 15 -> SPF)
}
val mideleg = supervisorGen generate new Area {
val ST, SE, SS = RegInit(False)
}
if(mvendorid != null) READ_ONLY(CSR.MVENDORID, U(mvendorid))
if(marchid != null) READ_ONLY(CSR.MARCHID , U(marchid ))
@ -447,12 +546,16 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
minstretAccess(CSR.MINSTRET, minstret(31 downto 0))
minstretAccess(CSR.MINSTRETH, minstret(63 downto 32))
medelegAccess(CSR.MEDELEG, medeleg)
midelegAccess(CSR.MIDELEG, mideleg)
if(supervisorGen) {
for((id, enable) <- medeleg.mapping) medelegAccess(CSR.MEDELEG, id -> enable)
midelegAccess(CSR.MIDELEG, 9 -> mideleg.SE, 5 -> mideleg.ST, 1 -> mideleg.SS)
}
//User CSR
ucycleAccess(CSR.UCYCLE, mcycle(31 downto 0))
ucycleAccess(CSR.UCYCLEH, mcycle(31 downto 0))
ucycleAccess(CSR.UCYCLEH, mcycle(63 downto 32))
pipeline(MPP) := mstatus.MPP
}
val supervisorCsr = ifGen(supervisorGen) {
@ -463,14 +566,16 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
}
val sip = new Area {
val SEIP = RegNext(externalInterruptS) init (False)
val STIP = RegNext(timerInterruptS) init (False)
val SEIP_SOFT = RegInit(False)
val SEIP_INPUT = RegNext(externalInterruptS)
val SEIP_OR = SEIP_SOFT || SEIP_INPUT
val STIP = RegInit(False)
val SSIP = RegInit(False)
}
val sie = new Area {
val SEIE, STIE, SSIE = RegInit(False)
}
val stvec = Reg(UInt(xlen bits)).allowUnsetRegToAvoidLatch
val stvec = Reg(Xtvec()).allowUnsetRegToAvoidLatch
val sscratch = if (sscratchGen) Reg(Bits(xlen bits)) else null
val scause = new Area {
@ -486,15 +591,18 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
}
//Supervisor CSR
WRITE_ONLY(CSR.SSTATUS,8 -> sstatus.SPP, 5 -> sstatus.SPIE, 1 -> sstatus.SIE)
for(offset <- List(0, 0x200)) {
READ_ONLY(CSR.SSTATUS,8 -> sstatus.SPP, 5 -> sstatus.SPIE, 1 -> sstatus.SIE)
for(offset <- List(CSR.MSTATUS, CSR.SSTATUS)) READ_WRITE(offset,8 -> sstatus.SPP, 5 -> sstatus.SPIE, 1 -> sstatus.SIE)
for(offset <- List(CSR.MIP, CSR.SIP)) {
READ_WRITE(offset, 5 -> sip.STIP, 1 -> sip.SSIP)
READ_ONLY(offset, 9 -> sip.SEIP_OR)
WRITE_ONLY(offset, 9 -> sip.SEIP_SOFT)
r2w(offset, 9, sip.SEIP_SOFT)
}
READ_ONLY(CSR.SIP, 9 -> sip.SEIP, 5 -> sip.STIP)
READ_WRITE(CSR.SIP, 1 -> sip.SSIP)
READ_WRITE(CSR.SIE, 9 -> sie.SEIE, 5 -> sie.STIE, 1 -> sie.SSIE)
stvecAccess(CSR.STVEC, stvec)
for(offset <- List(CSR.MIE, CSR.SIE)) READ_WRITE(offset, 9 -> sie.SEIE, 5 -> sie.STIE, 1 -> sie.SSIE)
stvecAccess(CSR.STVEC, 2 -> stvec.base, 0 -> stvec.mode)
sepcAccess(CSR.SEPC, sepc)
if(sscratchGen) READ_WRITE(CSR.SSCRATCH, sscratch)
scauseAccess(CSR.SCAUSE, xlen-1 -> scause.interrupt, 0 -> scause.exceptionCode)
@ -521,58 +629,16 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
if(supervisorGen) {
getInterruptPrivilege(1).privilegeCond = sstatus.SIE && privilege <= "01"
getInterruptPrivilege(1).sources ++= List(
InterruptSource(sip.STIP && sie.STIE, 5),
InterruptSource(sip.SSIP && sie.SSIE, 1),
InterruptSource(sip.SEIP && sie.SEIE, 9)
)
addInterrupt(sip.STIP && sie.STIE, id = 5, privilege = 1, delegators = List(Delegator(mideleg.ST, 3)))
addInterrupt(sip.SSIP && sie.SSIE, id = 1, privilege = 1, delegators = List(Delegator(mideleg.SS, 3)))
addInterrupt(sip.SEIP_OR && sie.SEIE, id = 9, privilege = 1, delegators = List(Delegator(mideleg.SE, 3)))
for((id, enable) <- medeleg.mapping) exceptionSpecs += ExceptionSpec(id, List(Delegator(enable, 3)))
}
getInterruptPrivilege(3).privilegeCond = mstatus.MIE
getInterruptPrivilege(3).sources ++= List(
InterruptSource(mip.MTIP && mie.MTIE, 7),
InterruptSource(mip.MSIP && mie.MSIE, 3),
InterruptSource(mip.MEIP && mie.MEIE, 11)
)
case class DelegatorModel(value : Bits, source : Int, target : Int)
// def solveDelegators(delegators : Seq[DelegatorModel], id : Int, lowerBound : Int): UInt = {
// val filtredDelegators = delegators.filter(_.target >= lowerBound)
// val ret = U(lowerBound, 2 bits)
// for(d <- filtredDelegators){
// when(!d.value(id)){
// ret := d.source
// }
// }
// ret
// }
def solveDelegators(delegators : Seq[DelegatorModel], id : UInt, lowerBound : UInt): UInt = {
if(delegators.isEmpty) return U"11"
val ret = U(delegators.last.target, 2 bits)
for(d <- delegators){
when(!d.value(id) || d.target < lowerBound){
ret := d.source
}
}
ret
// val ret = U"11"
// var continue = True
// for(d <- delegators){
// continue = continue && d.value(id)
// when(continue){
// ret := d.source
// }
// }
// ret.max(lowerBound)
}
val interruptDelegators = ArrayBuffer[DelegatorModel]()
if(midelegAccess.canWrite) interruptDelegators += DelegatorModel(mideleg,3, 1)
val exceptionDelegators = ArrayBuffer[DelegatorModel]()
if(medelegAccess.canWrite) exceptionDelegators += DelegatorModel(medeleg,3, 1)
addInterrupt(mip.MTIP && mie.MTIE, id = 7, privilege = 3, delegators = Nil)
addInterrupt(mip.MSIP && mie.MSIE, id = 3, privilege = 3, delegators = Nil)
addInterrupt(mip.MEIP && mie.MEIE, id = 11, privilege = 3, delegators = Nil)
val mepcCaptureStage = if(exceptionPortsInfos.nonEmpty) lastStage else decode
@ -584,7 +650,27 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
val exceptionValids = Vec(stages.map(s => Bool().setPartialName(s.getName())))
val exceptionValidsRegs = Vec(stages.map(s => Reg(Bool).init(False).setPartialName(s.getName()))).allowUnsetRegToAvoidLatch
val exceptionContext = Reg(ExceptionCause())
val exceptionTargetPrivilege = solveDelegators(exceptionDelegators, exceptionContext.code, privilege)
val exceptionTargetPrivilegeUncapped = U"11"
switch(exceptionContext.code){
for(s <- exceptionSpecs){
is(s.id){
var exceptionPrivilegs = if (supervisorGen) List(1, 3) else List(3)
while(exceptionPrivilegs.length != 1){
val p = exceptionPrivilegs.head
if (exceptionPrivilegs.tail.forall(e => s.delegators.exists(_.privilege == e))) {
val delegUpOn = s.delegators.filter(_.privilege > p).map(_.enable).fold(True)(_ && _)
val delegDownOff = !s.delegators.filter(_.privilege <= p).map(_.enable).orR
when(delegUpOn && delegDownOff) {
exceptionTargetPrivilegeUncapped := p
}
}
exceptionPrivilegs = exceptionPrivilegs.tail
}
}
}
}
val exceptionTargetPrivilege = privilege.max(exceptionTargetPrivilegeUncapped)
val groupedByStage = exceptionPortsInfos.map(_.stage).distinct.map(s => {
val stagePortsInfos = exceptionPortsInfos.filter(_.stage == s).sortWith(_.priority > _.priority)
@ -603,7 +689,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
})
val sortedByStage = groupedByStage.sortWith((a, b) => pipeline.indexOf(a.stage) < pipeline.indexOf(b.stage))
sortedByStage.zipWithIndex.foreach(e => e._1.port.setName(e._1.stage.getName() + "_exception_agregat"))
// sortedByStage.zipWithIndex.foreach(e => e._1.port.setName(e._1.stage.getName() + "_exception_agregat"))
exceptionValids := exceptionValidsRegs
for(portInfo <- sortedByStage; port = portInfo.port ; stage = portInfo.stage; stageId = indexOf(portInfo.stage)) {
when(port.valid) {
@ -624,7 +710,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
else
exceptionValidsRegs(stageId) := False
}
if(stage != stages.last) when(stage.arbitration.isFlushed){
when(stage.arbitration.isFlushed){
exceptionValids(stageId) := False
}
}
@ -632,6 +718,10 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
when(exceptionValidsRegs.orR){
fetcher.haltIt()
}
//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
@ -641,32 +731,27 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
//Process interrupt request, code and privilege
val interrupt = False
val interruptCode = UInt(4 bits).assignDontCare().addTag(Verilator.public)
val interruptDelegatorHit = interruptDelegators.map(d => (d -> False)).toMap
for(model <- customInterrupts.values.toSeq.sortBy(_.privilege)){
when(model.privilegeCond){
when(model.sources.map(_.cond).orR){
interrupt := True
}
for(source <- model.sources){
when(source.cond){
interruptCode := source.id
for(interruptDelegator <- interruptDelegators){
interruptDelegatorHit(interruptDelegator) := (if(interruptDelegator.target < model.privilege){
False
} else {
interruptDelegator.value(source.id)
})
}
var interruptPrivilegs = if (supervisorGen) List(1, 3) else List(3)
val interruptTargetPrivilege = 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")
while(interruptPrivilegs.nonEmpty){
val p = interruptPrivilegs.head
when(privilegeAllowInterrupts(p)){
for(i <- interruptSpecs
if i.privilege <= p //EX : Machine timer interrupt can't go into supervisor mode
if interruptPrivilegs.tail.forall(e => i.delegators.exists(_.privilege == e))){ // EX : Supervisor timer need to have machine mode delegator
val delegUpOn = i.delegators.filter(_.privilege > p).map(_.enable).fold(True)(_ && _)
val delegDownOff = !i.delegators.filter(_.privilege <= p).map(_.enable).orR
when(i.cond && delegUpOn && delegDownOff){
interrupt := True
interruptCode := i.id
interruptTargetPrivilege := p
}
}
}
}
val interruptTargetPrivilege = U(if(interruptDelegators.isEmpty) 3 else interruptDelegators.last.target, 2 bits)
for(interruptDelegator <- interruptDelegators){
when(!interruptDelegatorHit(interruptDelegator)){
interruptTargetPrivilege := interruptDelegator.source
}
interruptPrivilegs = interruptPrivilegs.tail
}
interrupt.clearWhen(!allowInterrupts)
@ -678,8 +763,8 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
//Used to make the pipeline empty softly (for interrupts)
val pipelineLiberator = new Area{
when(interrupt && decode.arbitration.isValid){
decode.arbitration.haltByOther := True
when(interrupt){
decode.arbitration.haltByOther := decode.arbitration.isValid
}
val done = !stagesFromExecute.map(_.arbitration.isValid).orR && fetcher.pcValid(mepcCaptureStage)
@ -704,23 +789,21 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
trapCause := exceptionPortCtrl.exceptionContext.code
}
when(exception || interruptJump){
switch(privilege){
if(supervisorGen) is(1) {
sepc := mepcCaptureStage.input(PC)
}
is(3){
mepc := mepcCaptureStage.input(PC)
}
}
val xtvec = Xtvec().assignDontCare()
switch(targetPrivilege){
if(supervisorGen) is(1) { xtvec := supervisorCsr.stvec }
is(3){ xtvec := machineCsr.mtvec }
}
when(hadException || interruptJump){
fetcher.haltIt() //Avoid having the fetch confused by the incomming privilege switch
jumpInterface.valid := True
jumpInterface.payload := (if(!mtvecModeGen) mtvec.base @@ "00" else (mtvec.mode === 0 || hadException) ? (mtvec.base @@ "00") | ((mtvec.base + trapCause) @@ "00") )
jumpInterface.payload := (if(!xtvecModeGen) xtvec.base @@ "00" else (xtvec.mode === 0 || hadException) ? (xtvec.base @@ "00") | ((xtvec.base + trapCause) @@ "00") )
beforeLastStage.arbitration.flushAll := True
privilege := targetPrivilege
if(privilegeGen) privilegeReg := targetPrivilege
switch(targetPrivilege){
if(supervisorGen) is(1) {
sstatus.SIE := False
@ -728,7 +811,8 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
sstatus.SPP := privilege(0 downto 0)
scause.interrupt := !hadException
scause.exceptionCode := trapCause
if (exceptionPortCtrl != null) {
sepc := mepcCaptureStage.input(PC)
if (exceptionPortCtrl != null) when(hadException){
stval := exceptionPortCtrl.exceptionContext.badAddr
}
}
@ -739,33 +823,37 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
mstatus.MPP := privilege
mcause.interrupt := !hadException
mcause.exceptionCode := trapCause
if(exceptionPortCtrl != null) {
mepc := mepcCaptureStage.input(PC)
if(exceptionPortCtrl != null) when(hadException){
mtval := exceptionPortCtrl.exceptionContext.badAddr
}
}
}
}
lastStage plug new Area{
import lastStage._
//Manage MRET / SRET instructions
when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.XRET) {
jumpInterface.payload := mepc
fetcher.haltIt()
jumpInterface.valid := True
beforeLastStage.arbitration.flushAll := True
switch(input(INSTRUCTION)(29 downto 28)){
is(3){
mstatus.MIE := mstatus.MPIE
mstatus.MPP := U"00"
mstatus.MIE := mstatus.MPIE
mstatus.MPIE := True
privilege := mstatus.MPP
jumpInterface.payload := mepc
if(privilegeGen) privilegeReg := mstatus.MPP
}
if(supervisorGen) is(1){
sstatus.SIE := sstatus.SPIE
sstatus.SPP := U"0"
sstatus.SIE := sstatus.SPIE
sstatus.SPIE := True
privilege := U"0" @@ sstatus.SPP
jumpInterface.payload := sepc
if(privilegeGen) privilegeReg := U"0" @@ sstatus.SPP
}
}
}
@ -790,14 +878,16 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
execute plug new Area{
import execute._
//Manage WFI instructions
val inWfi = False.addTag(Verilator.public)
if(wfiGenAsWait) when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.WFI){
inWfi := True
when(!interrupt){
arbitration.haltItself := True
}
}
}
decode.arbitration.haltByOther setWhen(stagesFromExecute.dropRight(1).map(s => s.arbitration.isValid && s.input(ENV_CTRL) === EnvCtrlEnum.XRET).asBits.orR)
decode.arbitration.haltByOther setWhen(stagesFromExecute.map(s => s.arbitration.isValid && s.input(ENV_CTRL) === EnvCtrlEnum.XRET).asBits.orR)
execute plug new Area {
import execute._
@ -809,7 +899,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
if(selfException != null) {
selfException.valid := False
selfException.code.assignDontCare()
selfException.badAddr.assignDontCare()
selfException.badAddr := input(INSTRUCTION).asUInt
if(catchIllegalAccess) when(illegalAccess || illegalInstruction){
selfException.valid := True
selfException.code := 2
@ -818,8 +908,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
//Manage MRET / SRET instructions
when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.XRET) {
//TODO check MPP value too
when(input(INSTRUCTION)(29 downto 28).asUInt =/= privilege) {
when(input(INSTRUCTION)(29 downto 28).asUInt > privilege) {
illegalInstruction := True
}
}
@ -828,7 +917,11 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
//Manage ECALL instructions
if(ecallGen) when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.ECALL){
selfException.valid := True
selfException.code := 11
switch(privilege) {
is(0) { selfException.code := 8 }
if(supervisorGen) is(1) { selfException.code := 9 }
default { selfException.code := 11 }
}
}
@ -856,9 +949,11 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
// False -> writeSrc,
// True -> Mux(input(INSTRUCTION)(12), ~writeSrc, writeSrc)
// )
val readToWriteData = CombInit(readData)
val writeData = if(noCsrAlu) writeSrc else input(INSTRUCTION)(13).mux(
False -> writeSrc,
True -> Mux(input(INSTRUCTION)(12), readData & ~writeSrc, readData | writeSrc)
True -> Mux(input(INSTRUCTION)(12), readToWriteData & ~writeSrc, readToWriteData | writeSrc)
)
@ -923,6 +1018,17 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
}
}
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 _ =>
}
}
}
}
illegalAccess setWhen(privilege < csrAddress(9 downto 8).asUInt)
illegalAccess clearWhen(!arbitration.isValid || !input(IS_CSR))
})

View file

@ -7,7 +7,7 @@ import spinal.lib._
import spinal.lib.bus.amba4.axi.Axi4
class DAxiCachedPlugin(config : DataCacheConfig, memoryTranslatorPortConfig : Any = null) extends DBusCachedPlugin(config, memoryTranslatorPortConfig){
class DAxiCachedPlugin(config : DataCacheConfig, memoryTranslatorPortConfig : Any = null) extends DBusCachedPlugin(config, memoryTranslatorPortConfig) {
var dAxi : Axi4 = null
override def build(pipeline: VexRiscv): Unit = {
@ -20,18 +20,35 @@ class DAxiCachedPlugin(config : DataCacheConfig, memoryTranslatorPortConfig : An
class DBusCachedPlugin(config : DataCacheConfig,
memoryTranslatorPortConfig : Any = null,
csrInfo : Boolean = false) extends Plugin[VexRiscv]{
dBusCmdMasterPipe : Boolean = false,
dBusCmdSlavePipe : Boolean = false,
dBusRspSlavePipe : Boolean = false,
csrInfo : Boolean = false) extends Plugin[VexRiscv] with DBusAccessService {
import config._
assert(isPow2(cacheSize))
assert(!(memoryTranslatorPortConfig != null && config.cacheSize/config.wayCount > 4096), "When the D$ is used with MMU, each way can't be bigger than a page (4096 bytes)")
var dBus : DataCacheMemBus = null
var mmuBus : MemoryTranslatorBus = null
var exceptionBus : Flow[ExceptionCause] = null
var privilegeService : PrivilegeService = null
var redoBranch : Flow[UInt] = null
@dontName var dBusAccess : DBusAccess = null
override def newDBusAccess(): DBusAccess = {
assert(dBusAccess == null)
dBusAccess = DBusAccess()
dBusAccess
}
object MEMORY_ENABLE extends Stageable(Bool)
object MEMORY_MANAGMENT extends Stageable(Bool)
object MEMORY_WR extends Stageable(Bool)
object MEMORY_ADDRESS_LOW extends Stageable(UInt(2 bits))
object MEMORY_ATOMIC extends Stageable(Bool)
object MEMORY_LRSC extends Stageable(Bool)
object MEMORY_AMO extends Stageable(Bool)
object IS_DBUS_SHARING extends Stageable(Bool())
override def setup(pipeline: VexRiscv): Unit = {
import Riscv._
@ -43,23 +60,22 @@ class DBusCachedPlugin(config : DataCacheConfig,
SRC1_CTRL -> Src1CtrlEnum.RS,
SRC_USE_SUB_LESS -> False,
MEMORY_ENABLE -> True,
RS1_USE -> True
) ++ (if (catchUnaligned) List(IntAluPlugin.ALU_CTRL -> IntAluPlugin.AluCtrlEnum.ADD_SUB) else Nil) //Used for access fault bad address in memory stage
RS1_USE -> True,
IntAluPlugin.ALU_CTRL -> IntAluPlugin.AluCtrlEnum.ADD_SUB
)
val loadActions = stdActions ++ List(
SRC2_CTRL -> Src2CtrlEnum.IMI,
REGFILE_WRITE_VALID -> True,
BYPASSABLE_EXECUTE_STAGE -> False,
BYPASSABLE_MEMORY_STAGE -> False,
MEMORY_WR -> False,
MEMORY_MANAGMENT -> False
MEMORY_WR -> False
) ++ (if(catchSomething) List(HAS_SIDE_EFFECT -> True) else Nil)
val storeActions = stdActions ++ List(
SRC2_CTRL -> Src2CtrlEnum.IMS,
RS2_USE -> True,
MEMORY_WR -> True,
MEMORY_MANAGMENT -> False
MEMORY_WR -> True
)
decoderService.addDefault(MEMORY_ENABLE, False)
@ -68,36 +84,66 @@ class DBusCachedPlugin(config : DataCacheConfig,
List(SB, SH, SW).map(_ -> storeActions)
)
if(genAtomic){
if(withLrSc){
List(LB, LH, LW, LBU, LHU, LWU, SB, SH, SW).foreach(e =>
decoderService.add(e, Seq(MEMORY_ATOMIC -> False))
decoderService.add(e, Seq(MEMORY_LRSC -> False))
)
decoderService.add(
key = LR,
values = loadActions.filter(_._1 != SRC2_CTRL) ++ Seq(
SRC2_CTRL -> Src2CtrlEnum.RS,
MEMORY_ATOMIC -> True
SRC_ADD_ZERO -> True,
MEMORY_LRSC -> True
)
)
decoderService.add(
key = SC,
values = storeActions.filter(_._1 != SRC2_CTRL) ++ Seq(
SRC_ADD_ZERO -> True,
REGFILE_WRITE_VALID -> True,
BYPASSABLE_EXECUTE_STAGE -> False,
BYPASSABLE_MEMORY_STAGE -> False,
MEMORY_ATOMIC -> True
MEMORY_LRSC -> True
)
)
}
if(withAmo){
List(LB, LH, LW, LBU, LHU, LWU, SB, SH, SW).foreach(e =>
decoderService.add(e, Seq(MEMORY_AMO -> False))
)
val amoActions = storeActions.filter(_._1 != SRC2_CTRL) ++ Seq(
SRC_ADD_ZERO -> True,
REGFILE_WRITE_VALID -> True,
BYPASSABLE_EXECUTE_STAGE -> False,
BYPASSABLE_MEMORY_STAGE -> False,
MEMORY_AMO -> True
)
for(i <- List(AMOSWAP, AMOADD, AMOXOR, AMOAND, AMOOR, AMOMIN, AMOMAX, AMOMINU, AMOMAXU)){
decoderService.add(i, amoActions)
}
}
if(withAmo && withLrSc){
for(i <- List(AMOSWAP, AMOADD, AMOXOR, AMOAND, AMOOR, AMOMIN, AMOMAX, AMOMINU, AMOMAXU)){
decoderService.add(i, List(MEMORY_LRSC -> False))
}
for(i <- List(LR, SC)){
decoderService.add(i, List(MEMORY_AMO -> False))
}
}
def MANAGEMENT = M"-------00000-----101-----0001111"
decoderService.add(MANAGEMENT, stdActions ++ List(
SRC2_CTRL -> Src2CtrlEnum.RS,
RS2_USE -> True,
decoderService.addDefault(MEMORY_MANAGMENT, False)
decoderService.add(MANAGEMENT, List(
MEMORY_MANAGMENT -> True
))
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)
if(catchSomething)
exceptionBus = pipeline.service(classOf[ExceptionService]).newExceptionPort(pipeline.writeBack)
@ -105,25 +151,7 @@ class DBusCachedPlugin(config : DataCacheConfig,
if(pipeline.serviceExist(classOf[PrivilegeService]))
privilegeService = pipeline.service(classOf[PrivilegeService])
if(pipeline.serviceExist(classOf[ReportService])){
val report = pipeline.service(classOf[ReportService])
report.add("dBus" -> {
val e = new BusReport()
val c = new CacheReport()
e.kind = "cached"
e.flushInstructions.add(0x13 | (1 << 7)) ////ADDI x1, x0, 0
for(idx <- 0 until cacheSize by bytePerLine){
e.flushInstructions.add(0x7000500F + (1 << 15)) //Clean invalid data cache way x1
e.flushInstructions.add(0x13 + (1 << 7) + (1 << 15) + (bytePerLine << 20)) //ADDI x1, x1, 32
}
e.info = c
c.size = cacheSize
c.bytePerLine = bytePerLine
e
})
}
pipeline.update(DEBUG_BYPASS_CACHE, False)
}
override def build(pipeline: VexRiscv): Unit = {
@ -133,36 +161,57 @@ class DBusCachedPlugin(config : DataCacheConfig,
dBus = master(DataCacheMemBus(this.config)).setName("dBus")
val cache = new DataCache(this.config)
cache.io.mem <> dBus
//Interconnect the plugin dBus with the cache dBus with some optional pipelining
def optionPipe[T](cond : Boolean, on : T)(f : T => T) : T = if(cond) f(on) else on
def cmdBuf = optionPipe(dBusCmdSlavePipe, cache.io.mem.cmd)(_.s2mPipe())
dBus.cmd << optionPipe(dBusCmdMasterPipe, cmdBuf)(_.m2sPipe())
cache.io.mem.rsp << optionPipe(dBusRspSlavePipe,dBus.rsp)(_.m2sPipe())
decode plug new Area {
import decode._
when(mmuBus.busy && arbitration.isValid && input(MEMORY_ENABLE)) {
arbitration.haltItself := True
}
}
execute plug new Area {
import execute._
val size = input(INSTRUCTION)(13 downto 12).asUInt
cache.io.cpu.execute.isValid := arbitration.isValid && input(MEMORY_ENABLE)
cache.io.cpu.execute.isStuck := arbitration.isStuck
cache.io.cpu.execute.address := input(SRC_ADD).asUInt
cache.io.cpu.execute.args.wr := input(MEMORY_WR)
cache.io.cpu.execute.args.address := input(SRC_ADD).asUInt
cache.io.cpu.execute.args.data := size.mux(
U(0) -> input(RS2)( 7 downto 0) ## input(RS2)( 7 downto 0) ## input(RS2)(7 downto 0) ## input(RS2)(7 downto 0),
U(1) -> input(RS2)(15 downto 0) ## input(RS2)(15 downto 0),
default -> input(RS2)(31 downto 0)
)
cache.io.cpu.execute.args.size := size
cache.io.cpu.execute.args.forceUncachedAccess := False
cache.io.cpu.execute.args.kind := input(MEMORY_MANAGMENT) ? DataCacheCpuCmdKind.MANAGMENT | DataCacheCpuCmdKind.MEMORY
cache.io.cpu.execute.args.clean := input(INSTRUCTION)(28)
cache.io.cpu.execute.args.invalidate := input(INSTRUCTION)(29)
cache.io.cpu.execute.args.way := input(INSTRUCTION)(30)
if(genAtomic) {
cache.io.cpu.execute.args.isAtomic := False
when(input(MEMORY_ATOMIC)){
cache.io.cpu.execute.args.isAtomic := True
cache.io.cpu.execute.args.address := input(SRC1).asUInt
cache.io.cpu.flush.valid := arbitration.isValid && input(MEMORY_MANAGMENT)
arbitration.haltItself setWhen(cache.io.cpu.flush.isStall)
if(withLrSc) {
cache.io.cpu.execute.args.isLrsc := False
when(input(MEMORY_LRSC)){
cache.io.cpu.execute.args.isLrsc := True
}
}
insert(MEMORY_ADDRESS_LOW) := cache.io.cpu.execute.args.address(1 downto 0)
if(withAmo){
cache.io.cpu.execute.isAmo := input(MEMORY_AMO)
cache.io.cpu.execute.amoCtrl.alu := input(INSTRUCTION)(31 downto 29)
cache.io.cpu.execute.amoCtrl.swap := input(INSTRUCTION)(27)
}
insert(MEMORY_ADDRESS_LOW) := cache.io.cpu.execute.address(1 downto 0)
when(cache.io.cpu.redo && arbitration.isValid && input(MEMORY_ENABLE)){
arbitration.haltItself := True
}
}
memory plug new Area{
@ -170,33 +219,52 @@ class DBusCachedPlugin(config : DataCacheConfig,
cache.io.cpu.memory.isValid := arbitration.isValid && input(MEMORY_ENABLE)
cache.io.cpu.memory.isStuck := arbitration.isStuck
cache.io.cpu.memory.isRemoved := arbitration.removeIt
arbitration.haltItself setWhen(cache.io.cpu.memory.haltIt)
cache.io.cpu.memory.address := U(input(REGFILE_WRITE_DATA))
cache.io.cpu.memory.mmuBus <> mmuBus
arbitration.haltItself setWhen (mmuBus.cmd.isValid && !mmuBus.rsp.hit && !mmuBus.rsp.miss)
cache.io.cpu.memory.mmuBus.rsp.isIoAccess setWhen(pipeline(DEBUG_BYPASS_CACHE) && !cache.io.cpu.memory.isWrite)
}
writeBack plug new Area{
import writeBack._
cache.io.cpu.writeBack.isValid := arbitration.isValid && input(MEMORY_ENABLE)
cache.io.cpu.writeBack.isStuck := arbitration.isStuck
cache.io.cpu.writeBack.isUser := (if(privilegeService != null) privilegeService.isUser(writeBack) else False)
if(genAtomic) cache.io.cpu.writeBack.clearAtomicEntries := service(classOf[IContextSwitching]).isContextSwitching
cache.io.cpu.writeBack.isUser := (if(privilegeService != null) privilegeService.isUser() else False)
cache.io.cpu.writeBack.address := U(input(REGFILE_WRITE_DATA))
if(withLrSc) cache.io.cpu.writeBack.clearLrsc := service(classOf[IContextSwitching]).isContextSwitching
redoBranch.valid := False
redoBranch.payload := input(PC)
arbitration.flushAll setWhen(redoBranch.valid)
if(catchSomething) {
exceptionBus.valid := cache.io.cpu.writeBack.mmuMiss || cache.io.cpu.writeBack.accessError || cache.io.cpu.writeBack.illegalAccess || cache.io.cpu.writeBack.unalignedAccess
exceptionBus.badAddr := cache.io.cpu.writeBack.badAddr
exceptionBus.valid := False //cache.io.cpu.writeBack.mmuMiss || cache.io.cpu.writeBack.accessError || cache.io.cpu.writeBack.illegalAccess || cache.io.cpu.writeBack.unalignedAccess
exceptionBus.badAddr := U(input(REGFILE_WRITE_DATA))
exceptionBus.code.assignDontCare()
when(cache.io.cpu.writeBack.illegalAccess || cache.io.cpu.writeBack.accessError){
}
when(arbitration.isValid && input(MEMORY_ENABLE)) {
if (catchAccessError) when(cache.io.cpu.writeBack.accessError) {
exceptionBus.valid := True
exceptionBus.code := (input(MEMORY_WR) ? U(7) | U(5)).resized
}
when(cache.io.cpu.writeBack.unalignedAccess){
if (catchUnaligned) when(cache.io.cpu.writeBack.unalignedAccess) {
exceptionBus.valid := True
exceptionBus.code := (input(MEMORY_WR) ? U(6) | U(4)).resized
}
when(cache.io.cpu.writeBack.mmuMiss){
exceptionBus.code := 13
if(catchIllegal) when (cache.io.cpu.writeBack.mmuException) {
exceptionBus.valid := True
exceptionBus.code := (input(MEMORY_WR) ? U(15) | U(13)).resized
}
when(cache.io.cpu.redo) {
redoBranch.valid := True
if(catchSomething) exceptionBus.valid := False
}
}
arbitration.haltItself.setWhen(cache.io.cpu.writeBack.haltIt)
val rspShifted = Bits(32 bits)
@ -218,6 +286,49 @@ class DBusCachedPlugin(config : DataCacheConfig,
}
}
//Share access to the dBus (used by self refilled MMU)
if(dBusAccess != null) pipeline plug new Area{
dBusAccess.cmd.ready := False
val forceDatapath = False
when(dBusAccess.cmd.valid){
decode.arbitration.haltByOther := True
val exceptionService = pipeline.service(classOf[ExceptionService])
when(!stagesFromExecute.map(s => s.arbitration.isValid || exceptionService.isExceptionPending(s)).orR){
when(!cache.io.cpu.redo) {
cache.io.cpu.execute.isValid := True
dBusAccess.cmd.ready := !execute.arbitration.isStuck
}
cache.io.cpu.execute.args.wr := dBusAccess.cmd.write
cache.io.cpu.execute.args.data := dBusAccess.cmd.data
cache.io.cpu.execute.args.size := dBusAccess.cmd.size
if(withLrSc) cache.io.cpu.execute.args.isLrsc := False
if(withAmo) cache.io.cpu.execute.args.isAmo := False
cache.io.cpu.execute.address := dBusAccess.cmd.address //Will only be 12 muxes
forceDatapath := True
}
}
execute.insert(IS_DBUS_SHARING) := dBusAccess.cmd.fire
mmuBus.cmd.bypassTranslation setWhen(memory.input(IS_DBUS_SHARING))
cache.io.cpu.memory.isValid setWhen(memory.input(IS_DBUS_SHARING))
cache.io.cpu.writeBack.isValid setWhen(writeBack.input(IS_DBUS_SHARING))
dBusAccess.rsp.valid := writeBack.input(IS_DBUS_SHARING) && !cache.io.cpu.writeBack.isWrite && (cache.io.cpu.redo || !cache.io.cpu.writeBack.haltIt)
dBusAccess.rsp.data := cache.io.cpu.writeBack.data
dBusAccess.rsp.error := cache.io.cpu.writeBack.unalignedAccess || cache.io.cpu.writeBack.accessError
dBusAccess.rsp.redo := cache.io.cpu.redo
component.addPrePopTask{() =>
when(forceDatapath){
execute.output(REGFILE_WRITE_DATA) := dBusAccess.cmd.address.asBits
}
memory.input(IS_DBUS_SHARING) init(False)
writeBack.input(IS_DBUS_SHARING) init(False)
when(dBusAccess.rsp.valid){
writeBack.input(IS_DBUS_SHARING).getDrivingReg := False
}
}
}
if(csrInfo){
val csr = service(classOf[CsrPlugin])
csr.r(0xCC0, 0 -> U(cacheSize/wayCount), 20 -> U(bytePerLine))

View file

@ -9,6 +9,8 @@ import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig}
import spinal.lib.bus.simple._
import vexriscv.ip.DataCacheMemCmd
import scala.collection.mutable.ArrayBuffer
case class DBusSimpleCmd() extends Bundle{
val wr = Bool
@ -63,6 +65,12 @@ object DBusSimpleBus{
useBTE = true,
useCTI = true
)
def getPipelinedMemoryBusConfig() = PipelinedMemoryBusConfig(
addressWidth = 32,
dataWidth = 32
)
}
case class DBusSimpleBus() extends Bundle with IMasterSlave{
@ -178,7 +186,8 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{
}
def toPipelinedMemoryBus() : PipelinedMemoryBus = {
val bus = PipelinedMemoryBus(32,32)
val pipelinedMemoryBusConfig = DBusSimpleBus.getPipelinedMemoryBusConfig()
val bus = PipelinedMemoryBus(pipelinedMemoryBusConfig)
bus.cmd.valid := cmd.valid
bus.cmd.write := cmd.wr
bus.cmd.address := cmd.address.resized
@ -202,18 +211,34 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false,
catchAccessFault : Boolean = false,
earlyInjection : Boolean = false, /*, idempotentRegions : (UInt) => Bool = (x) => False*/
emitCmdInMemoryStage : Boolean = false,
onlyLoadWords : Boolean = false) extends Plugin[VexRiscv]{
onlyLoadWords : Boolean = false,
withLrSc : Boolean = false,
memoryTranslatorPortConfig : Any = null) extends Plugin[VexRiscv] with DBusAccessService {
var dBus : DBusSimpleBus = null
assert(!(emitCmdInMemoryStage && earlyInjection))
object MEMORY_ENABLE extends Stageable(Bool)
object MEMORY_READ_DATA extends Stageable(Bits(32 bits))
object MEMORY_ADDRESS_LOW extends Stageable(UInt(2 bits))
object ALIGNEMENT_FAULT extends Stageable(Bool)
object MMU_FAULT extends Stageable(Bool)
object MMU_RSP extends Stageable(MemoryTranslatorRsp())
object MEMORY_ATOMIC extends Stageable(Bool)
object ATOMIC_HIT extends Stageable(Bool)
object MEMORY_STORE extends Stageable(Bool)
var memoryExceptionPort : Flow[ExceptionCause] = null
var rspStage : Stage = null
var mmuBus : MemoryTranslatorBus = null
var redoBranch : Flow[UInt] = null
val catchSomething = catchAccessFault || catchAddressMisaligned || memoryTranslatorPortConfig != null
@dontName var dBusAccess : DBusAccess = null
override def newDBusAccess(): DBusAccess = {
assert(dBusAccess == null)
dBusAccess = DBusAccess()
dBusAccess
}
override def setup(pipeline: VexRiscv): Unit = {
import Riscv._
@ -233,12 +258,14 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false,
SRC2_CTRL -> Src2CtrlEnum.IMI,
REGFILE_WRITE_VALID -> True,
BYPASSABLE_EXECUTE_STAGE -> False,
BYPASSABLE_MEMORY_STAGE -> Bool(earlyInjection)
BYPASSABLE_MEMORY_STAGE -> Bool(earlyInjection),
MEMORY_STORE -> False
) ++ (if(catchAccessFault || catchAddressMisaligned) List(HAS_SIDE_EFFECT -> True) else Nil)
val storeActions = stdActions ++ List(
SRC2_CTRL -> Src2CtrlEnum.IMS,
RS2_USE -> True
RS2_USE -> True,
MEMORY_STORE -> True
)
decoderService.addDefault(MEMORY_ENABLE, False)
@ -248,12 +275,42 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false,
)
if(withLrSc){
List(LB, LH, LW, LBU, LHU, LWU, SB, SH, SW).foreach(e =>
decoderService.add(e, Seq(MEMORY_ATOMIC -> False))
)
decoderService.add(
key = LR,
values = loadActions.filter(_._1 != SRC2_CTRL) ++ Seq(
SRC_ADD_ZERO -> True,
MEMORY_ATOMIC -> True
)
)
decoderService.add(
key = SC,
values = storeActions.filter(_._1 != SRC2_CTRL) ++ Seq(
SRC_ADD_ZERO -> True,
REGFILE_WRITE_VALID -> True,
BYPASSABLE_EXECUTE_STAGE -> False,
BYPASSABLE_MEMORY_STAGE -> False,
MEMORY_ATOMIC -> True
)
)
}
decoderService.add(FENCE, Nil)
rspStage = if(stages.last == execute) execute else (if(emitCmdInMemoryStage) writeBack else memory)
if(catchAccessFault || catchAddressMisaligned) {
if(catchSomething) {
val exceptionService = pipeline.service(classOf[ExceptionService])
memoryExceptionPort = exceptionService.newExceptionPort(rspStage)
}
if(memoryTranslatorPortConfig != null) {
mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(MemoryTranslatorPort.PRIORITY_DATA, memoryTranslatorPortConfig)
redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(if(pipeline.memory != null) pipeline.memory else pipeline.execute)
}
}
override def build(pipeline: VexRiscv): Unit = {
@ -263,30 +320,40 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false,
dBus = master(DBusSimpleBus()).setName("dBus")
decode plug new Area {
import decode._
if(mmuBus != null) when(mmuBus.busy && arbitration.isValid && input(MEMORY_ENABLE)) {
arbitration.haltItself := True
}
}
//Emit dBus.cmd request
val cmdSent = if(rspStage == execute) RegInit(False) setWhen(dBus.cmd.fire) clearWhen(!execute.arbitration.isStuck) else False
val cmdStage = if(emitCmdInMemoryStage) memory else execute
cmdStage plug new Area{
import cmdStage._
val privilegeService = pipeline.serviceElse(classOf[PrivilegeService], PrivilegeServiceDefault())
val cmdSent = if(rspStage == execute) RegInit(False) setWhen(dBus.cmd.fire) clearWhen(!execute.arbitration.isStuck) else False
insert(ALIGNEMENT_FAULT) := {
if (catchAddressMisaligned)
(dBus.cmd.size === 2 && dBus.cmd.address(1 downto 0) =/= 0) || (dBus.cmd.size === 1 && dBus.cmd.address(0 downto 0) =/= 0)
else
False
}
if (catchAddressMisaligned)
insert(ALIGNEMENT_FAULT) := (dBus.cmd.size === 2 && dBus.cmd.address(1 downto 0) =/= 0) || (dBus.cmd.size === 1 && dBus.cmd.address(0 downto 0) =/= 0)
else
insert(ALIGNEMENT_FAULT) := False
dBus.cmd.valid := arbitration.isValid && input(MEMORY_ENABLE) && !arbitration.isStuckByOthers && !arbitration.isFlushed && !input(ALIGNEMENT_FAULT) && !cmdSent
dBus.cmd.wr := input(INSTRUCTION)(5)
dBus.cmd.address := input(SRC_ADD).asUInt
val skipCmd = False
skipCmd setWhen(input(ALIGNEMENT_FAULT))
dBus.cmd.valid := arbitration.isValid && input(MEMORY_ENABLE) && !arbitration.isStuckByOthers && !arbitration.isFlushed && !skipCmd && !cmdSent
dBus.cmd.wr := input(MEMORY_STORE)
dBus.cmd.size := input(INSTRUCTION)(13 downto 12).asUInt
dBus.cmd.payload.data := dBus.cmd.size.mux (
U(0) -> input(RS2)(7 downto 0) ## input(RS2)(7 downto 0) ## input(RS2)(7 downto 0) ## input(RS2)(7 downto 0),
U(1) -> input(RS2)(15 downto 0) ## input(RS2)(15 downto 0),
default -> input(RS2)(31 downto 0)
)
when(arbitration.isValid && input(MEMORY_ENABLE) && !dBus.cmd.ready && !input(ALIGNEMENT_FAULT) && !cmdSent){
when(arbitration.isValid && input(MEMORY_ENABLE) && !dBus.cmd.ready && !skipCmd && !cmdSent){
arbitration.haltItself := True
}
@ -298,10 +365,45 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false,
U(1) -> B"0011",
default -> B"1111"
) |<< dBus.cmd.address(1 downto 0)
insert(FORMAL_MEM_ADDR) := dBus.cmd.address & U"xFFFFFFFC"
insert(FORMAL_MEM_WMASK) := (dBus.cmd.valid && dBus.cmd.wr) ? formalMask | B"0000"
insert(FORMAL_MEM_RMASK) := (dBus.cmd.valid && !dBus.cmd.wr) ? formalMask | B"0000"
insert(FORMAL_MEM_WDATA) := dBus.cmd.payload.data
val mmu = (mmuBus != null) generate new Area {
mmuBus.cmd.isValid := arbitration.isValid && input(MEMORY_ENABLE)
mmuBus.cmd.virtualAddress := input(SRC_ADD).asUInt
mmuBus.cmd.bypassTranslation := False
mmuBus.end := !arbitration.isStuck || arbitration.isRemoved
dBus.cmd.address := mmuBus.rsp.physicalAddress
//do not emit memory request if MMU refilling
insert(MMU_FAULT) := input(MMU_RSP).exception || (!input(MMU_RSP).allowWrite && input(MEMORY_STORE)) || (!input(MMU_RSP).allowRead && !input(MEMORY_STORE))
skipCmd.setWhen(input(MMU_FAULT) || input(MMU_RSP).refilling)
insert(MMU_RSP) := mmuBus.rsp
}
val mmuLess = (mmuBus == null) generate new Area{
dBus.cmd.address := input(SRC_ADD).asUInt
}
val atomic = withLrSc generate new Area{
val reserved = RegInit(False)
insert(ATOMIC_HIT) := reserved
when(arbitration.isFiring && input(MEMORY_ENABLE) && input(MEMORY_ATOMIC) && !input(MEMORY_STORE)){
reserved := True
}
when(service(classOf[IContextSwitching]).isContextSwitching){
reserved := False
}
when(input(MEMORY_STORE) && input(MEMORY_ATOMIC) && !input(ATOMIC_HIT)){
skipCmd := True
}
}
}
//Collect dBus.rsp read responses
@ -310,28 +412,44 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false,
insert(MEMORY_READ_DATA) := dBus.rsp.data
arbitration.haltItself setWhen(arbitration.isValid && input(MEMORY_ENABLE) && !input(INSTRUCTION)(5) && !dBus.rsp.ready)
if(catchAccessFault || catchAddressMisaligned){
if(!catchAccessFault){
memoryExceptionPort.code := (input(INSTRUCTION)(5) ? U(6) | U(4)).resized
memoryExceptionPort.valid := input(ALIGNEMENT_FAULT)
} else if(!catchAddressMisaligned){
memoryExceptionPort.valid := dBus.rsp.ready && dBus.rsp.error && !input(INSTRUCTION)(5)
memoryExceptionPort.code := 5
} else {
memoryExceptionPort.valid := dBus.rsp.ready && dBus.rsp.error && !input(INSTRUCTION)(5)
memoryExceptionPort.code := 5
when(input(ALIGNEMENT_FAULT)){
memoryExceptionPort.code := (input(INSTRUCTION)(5) ? U(6) | U(4)).resized
arbitration.haltItself setWhen(arbitration.isValid && input(MEMORY_ENABLE) && !input(MEMORY_STORE) && (!dBus.rsp.ready || (if(rspStage == execute) !cmdSent else False)))
if(catchSomething) {
memoryExceptionPort.valid := False
memoryExceptionPort.code.assignDontCare()
memoryExceptionPort.badAddr := input(REGFILE_WRITE_DATA).asUInt
if(catchAccessFault) when(dBus.rsp.ready && dBus.rsp.error && !input(MEMORY_STORE)) {
memoryExceptionPort.valid := True
memoryExceptionPort.code := 5
}
if(catchAddressMisaligned) when(input(ALIGNEMENT_FAULT)){
memoryExceptionPort.code := (input(MEMORY_STORE) ? U(6) | U(4)).resized
memoryExceptionPort.valid := True
}
if(memoryTranslatorPortConfig != null) {
redoBranch.valid := False
redoBranch.payload := input(PC)
when(input(MMU_RSP).refilling){
redoBranch.valid := True
memoryExceptionPort.valid := False
} elsewhen(input(MMU_FAULT)) {
memoryExceptionPort.valid := True
memoryExceptionPort.code := (input(MEMORY_STORE) ? U(15) | U(13)).resized
}
}
when(!(arbitration.isValid && input(MEMORY_ENABLE) && (if(cmdStage == rspStage) !arbitration.isStuckByOthers else True))){
memoryExceptionPort.valid := False
arbitration.flushAll setWhen(redoBranch.valid)
}
when(!(arbitration.isValid && input(MEMORY_ENABLE) && (Bool(cmdStage != rspStage) || !arbitration.isStuckByOthers))){
if(catchSomething) memoryExceptionPort.valid := False
if(memoryTranslatorPortConfig != null) redoBranch.valid := False
}
memoryExceptionPort.badAddr := input(REGFILE_WRITE_DATA).asUInt //Drived by IntAluPlugin
}
@ -360,13 +478,58 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false,
when(arbitration.isValid && input(MEMORY_ENABLE)) {
output(REGFILE_WRITE_DATA) := (if(!onlyLoadWords) rspFormated else input(MEMORY_READ_DATA))
if(withLrSc){
when(input(MEMORY_ATOMIC) && input(MEMORY_STORE)){
output(REGFILE_WRITE_DATA) := (!input(ATOMIC_HIT)).asBits.resized
}
}
}
if(!earlyInjection && !emitCmdInMemoryStage && config.withWriteBackStage)
assert(!(arbitration.isValid && input(MEMORY_ENABLE) && !input(INSTRUCTION)(5) && arbitration.isStuck),"DBusSimplePlugin doesn't allow writeback stage stall when read happend")
assert(!(arbitration.isValid && input(MEMORY_ENABLE) && !input(MEMORY_STORE) && arbitration.isStuck),"DBusSimplePlugin doesn't allow writeback stage stall when read happend")
//formal
insert(FORMAL_MEM_RDATA) := input(MEMORY_READ_DATA)
}
//Share access to the dBus (used by self refilled MMU)
val dBusSharing = (dBusAccess != null) generate new Area{
val state = Reg(UInt(2 bits)) init(0)
dBusAccess.cmd.ready := False
dBusAccess.rsp.valid := False
dBusAccess.rsp.data := dBus.rsp.data
dBusAccess.rsp.error := dBus.rsp.error
dBusAccess.rsp.redo := False
switch(state){
is(0){
when(dBusAccess.cmd.valid){
decode.arbitration.haltItself := True
when(!stages.dropWhile(_ != execute).map(_.arbitration.isValid).orR){
state := 1
}
}
}
is(1){
decode.arbitration.haltItself := True
dBus.cmd.valid := True
dBus.cmd.address := dBusAccess.cmd.address
dBus.cmd.wr := dBusAccess.cmd.write
dBus.cmd.data := dBusAccess.cmd.data
dBus.cmd.size := dBusAccess.cmd.size
when(dBus.cmd.ready){
state := (dBusAccess.cmd.write ? U(0) | U(2))
dBusAccess.cmd.ready := True
}
}
is(2){
decode.arbitration.haltItself := True
when(dBus.rsp.ready){
dBusAccess.rsp.valid := True
state := 0
}
}
}
}
}
}

View file

@ -141,8 +141,8 @@ class DebugPlugin(val debugClockDomain : ClockDomain, hardwareBreakpointCount :
val haltIt = RegInit(False)
val stepIt = RegInit(False)
val isPipActive = RegNext(stages.map(_.arbitration.isValid).orR)
val isPipBusy = isPipActive || RegNext(isPipActive)
val isPipBusy = RegNext(stages.map(_.arbitration.isValid).orR || iBusFetcher.incoming())
val godmode = RegInit(False) setWhen(haltIt && !isPipBusy)
val haltedByBreak = RegInit(False)
val hardwareBreakpoints = Vec(Reg(new Bundle{
@ -176,6 +176,7 @@ class DebugPlugin(val debugClockDomain : ClockDomain, hardwareBreakpointCount :
resetIt setWhen (io.bus.cmd.data(16)) clearWhen (io.bus.cmd.data(24))
haltIt setWhen (io.bus.cmd.data(17)) clearWhen (io.bus.cmd.data(25))
haltedByBreak clearWhen (io.bus.cmd.data(25))
godmode clearWhen(io.bus.cmd.data(25))
}
}
is(0x1) {
@ -219,10 +220,6 @@ class DebugPlugin(val debugClockDomain : ClockDomain, hardwareBreakpointCount :
}
}
when(stepIt && Cat(pipeline.stages.map(_.arbitration.redoIt)).asBits.orR) {
haltIt := False
}
//Avoid having two C instruction executed in a single step
if(pipeline(RVC_GEN)){
val cleanStep = RegNext(stepIt && decode.arbitration.isFiring) init(False)
@ -236,10 +233,17 @@ class DebugPlugin(val debugClockDomain : ClockDomain, hardwareBreakpointCount :
service(classOf[InterruptionInhibitor]).inhibateInterrupts()
}
}
if(serviceExist(classOf[ExceptionInhibitor])) {
when(haltIt) {
service(classOf[ExceptionInhibitor]).inhibateException()
when(godmode) {
pipeline.plugins.foreach{
case p : ExceptionInhibitor => p.inhibateException()
case _ =>
}
pipeline.plugins.foreach{
case p : PrivilegeService => p.forceMachine()
case _ =>
}
if(pipeline.things.contains(DEBUG_BYPASS_CACHE)) pipeline(DEBUG_BYPASS_CACHE) := True
}
}}
}

View file

@ -66,8 +66,8 @@ class DecoderSimplePlugin(catchIllegalInstruction : Boolean = false, forceLegalI
}
}
val defaults = mutable.HashMap[Stageable[_ <: BaseType], BaseType]()
val encodings = mutable.HashMap[MaskedLiteral,ArrayBuffer[(Stageable[_ <: BaseType], BaseType)]]()
val defaults = mutable.LinkedHashMap[Stageable[_ <: BaseType], BaseType]()
val encodings = mutable.LinkedHashMap[MaskedLiteral,ArrayBuffer[(Stageable[_ <: BaseType], BaseType)]]()
var decodeExceptionPort : Flow[ExceptionCause] = null
@ -105,7 +105,7 @@ class DecoderSimplePlugin(catchIllegalInstruction : Boolean = false, forceLegalI
} else {
var offset = 0
var defaultValue, defaultCare = BigInt(0)
val offsetOf = mutable.HashMap[Stageable[_ <: BaseType], Int]()
val offsetOf = mutable.LinkedHashMap[Stageable[_ <: BaseType], Int]()
//Build defaults value and field offset map
stageables.foreach(e => {
@ -160,7 +160,7 @@ class DecoderSimplePlugin(catchIllegalInstruction : Boolean = false, forceLegalI
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.code := 2
decodeExceptionPort.badAddr.assignDontCare()
decodeExceptionPort.badAddr := input(INSTRUCTION).asUInt
}
}
@ -191,8 +191,8 @@ object DecodingBench extends App{
object Symplify{
val cache = mutable.HashMap[Bits,mutable.HashMap[Masked,Bool]]()
def getCache(addr : Bits) = cache.getOrElseUpdate(addr,mutable.HashMap[Masked,Bool]())
val cache = mutable.LinkedHashMap[Bits,mutable.LinkedHashMap[Masked,Bool]]()
def getCache(addr : Bits) = cache.getOrElseUpdate(addr,mutable.LinkedHashMap[Masked,Bool]())
//Generate terms logic for the given input
def logicOf(input : Bits,terms : Seq[Masked]) = terms.map(t => getCache(input).getOrElseUpdate(t,t === input)).asBits.orR

View file

@ -20,7 +20,8 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
val injectorReadyCutGen : Boolean,
val prediction : BranchPrediction,
val historyRamSizeLog2 : Int,
val injectorStage : Boolean) extends Plugin[VexRiscv] with JumpService with IBusFetcher{
val injectorStage : Boolean,
val relaxPredictorAddress : Boolean) extends Plugin[VexRiscv] with JumpService with IBusFetcher{
var prefetchExceptionPort : Flow[ExceptionCause] = null
var decodePrediction : DecodePredictionBus = null
var fetchPrediction : FetchPredictionBus = null
@ -284,7 +285,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
bufferData := input.rsp.inst(31 downto 16)
}
bufferValid.clearWhen(flush)
iBusRsp.readyForError.clearWhen(bufferValid && isRvc)
iBusRsp.readyForError.clearWhen(bufferValid && isRvc) //Can't emit error, as there is a earlier instruction pending
incomingInstruction setWhen(bufferValid && bufferData(1 downto 0) =/= 3)
})
@ -293,19 +294,21 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
val injector = new Area {
val inputBeforeStage = condApply(if (decodePcGen) decompressor.output else iBusRsp.output, injectorReadyCutGen)(_.s2mPipe(flush))
if (injectorReadyCutGen) {
iBusRsp.readyForError.clearWhen(inputBeforeStage.valid)
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(flush, collapsBubble = false)
decode.insert(INSTRUCTION_ANTICIPATED) := Mux(decode.arbitration.isStuck, decode.input(INSTRUCTION), inputBeforeStage.rsp.inst)
iBusRsp.readyForError.clearWhen(decodeInput.valid)
iBusRsp.readyForError.clearWhen(decodeInput.valid) //Can't emit error when there is a instruction pending in the injector stage buffer
incomingInstruction setWhen (decodeInput.valid)
decodeInput
} else {
inputBeforeStage
})
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] = {
stucks.scanLeft(input)((i, stuck) => {
@ -488,8 +491,17 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
decodePrediction.cmd.hadBranch := decode.input(BRANCH_CTRL) === BranchCtrlEnum.JAL || (decode.input(BRANCH_CTRL) === BranchCtrlEnum.B && conditionalBranchPrediction)
val noPredictionOnMissaligned = (!pipeline(RVC_GEN)) generate new Area{
val missaligned = decode.input(BRANCH_CTRL).mux(
BranchCtrlEnum.JAL -> imm.j_sext(1),
default -> imm.b_sext(1)
)
decodePrediction.cmd.hadBranch clearWhen(missaligned)
}
predictionJumpInterface.valid := decodePrediction.cmd.hadBranch && decode.arbitration.isFiring //TODO OH Doublon de priorité
predictionJumpInterface.payload := decode.input(PC) + ((decode.input(BRANCH_CTRL) === BranchCtrlEnum.JAL) ? imm.j_sext | imm.b_sext).asUInt
if(relaxPredictorAddress) KeepAttribute(predictionJumpInterface.payload)
// when(predictionJumpInterface.payload((if(pipeline(RVC_GEN)) 0 else 1) downto 0) =/= 0){
// decodePrediction.cmd.hadBranch := False
@ -605,5 +617,10 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
})
}
}
def stageXToIBusRsp[T <: Data](stage : Any, input : T): (T) ={
iBusRsp.stages.dropWhile(_ != stage).tail.foldLeft(input)((data,stage) => RegNextWhen(data, stage.output.ready))
}
}
}

View file

@ -21,6 +21,8 @@ class HaltOnExceptionPlugin() extends Plugin[VexRiscv] with ExceptionService {
exceptionPortsInfos += ExceptionPortInfo(interface,stage,priority)
interface
}
override def isExceptionPending(stage : Stage): Bool = False
override def build(pipeline: VexRiscv): Unit = {
import pipeline._

View file

@ -34,7 +34,8 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
config : InstructionCacheConfig,
memoryTranslatorPortConfig : Any = null,
injectorStage : Boolean = false,
withoutInjectorStage : Boolean = false) extends IBusFetcherImpl(
withoutInjectorStage : Boolean = false,
relaxPredictorAddress : Boolean = true) extends IBusFetcherImpl(
resetVector = resetVector,
keepPcPlus4 = keepPcPlus4,
decodePcGen = compressedGen,
@ -44,9 +45,14 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
injectorReadyCutGen = false,
prediction = prediction,
historyRamSizeLog2 = historyRamSizeLog2,
injectorStage = (!config.twoCycleCache && !withoutInjectorStage) || injectorStage){
injectorStage = (!config.twoCycleCache && !withoutInjectorStage) || injectorStage,
relaxPredictorAddress = relaxPredictorAddress){
import config._
assert(isPow2(cacheSize))
assert(!(memoryTranslatorPortConfig != null && config.cacheSize/config.wayCount > 4096), "When the I$ is used with MMU, each way can't be bigger than a page (4096 bytes)")
assert(!(withoutInjectorStage && injectorStage))
var iBus : InstructionCacheMemBus = null
@ -74,11 +80,9 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
super.setup(pipeline)
def MANAGEMENT = M"-----------------100-----0001111"
val decoderService = pipeline.service(classOf[DecoderService])
decoderService.addDefault(FLUSH_ALL, False)
decoderService.add(MANAGEMENT, List(
decoderService.add(FENCE_I, List(
FLUSH_ALL -> True
))
@ -101,7 +105,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
val e = new BusReport()
val c = new CacheReport()
e.kind = "cached"
e.flushInstructions.add(0x400F) //invalid instruction cache
e.flushInstructions.add(0x100F) //FENCE.I
e.flushInstructions.add(0x13)
e.flushInstructions.add(0x13)
e.flushInstructions.add(0x13)
@ -163,8 +167,11 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
cache.io.cpu.fetch.isStuck := !stages(1).input.ready
cache.io.cpu.fetch.pc := stages(1).input.payload
stages(1).halt setWhen(cache.io.cpu.fetch.haltIt)
if (!twoCycleCache) {
cache.io.cpu.fetch.isUser := privilegeService.isUser(decode)
cache.io.cpu.fetch.isUser := privilegeService.isUser()
}
}
@ -173,7 +180,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
cache.io.cpu.decode.isValid := stages(2).input.valid && !tightlyCoupledHit
cache.io.cpu.decode.isStuck := !stages(2).input.ready
cache.io.cpu.decode.pc := stages(2).input.payload
cache.io.cpu.decode.isUser := privilegeService.isUser(decode)
cache.io.cpu.decode.isUser := privilegeService.isUser()
if ((!twoCycleRam || wayCount == 1) && !compressedGen && !injectorStage) {
decode.insert(INSTRUCTION_ANTICIPATED) := Mux(decode.arbitration.isStuck, decode.input(INSTRUCTION), cache.io.cpu.fetch.data)
@ -186,34 +193,51 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
val cacheRsp = if (twoCycleCache) cache.io.cpu.decode else cache.io.cpu.fetch
val cacheRspArbitration = stages(if (twoCycleCache) 2 else 1)
var issueDetected = False
val redoFetch = False //RegNext(False) init(False)
when(cacheRsp.isValid && cacheRsp.cacheMiss && !issueDetected) {
issueDetected \= True
redoFetch := iBusRsp.readyForError
}
val redoFetch = False
//Refill / redo
assert(decodePcGen == compressedGen)
cache.io.cpu.fill.valid := redoFetch
cache.io.cpu.fill.valid := redoFetch && !cacheRsp.mmuRefilling
cache.io.cpu.fill.payload := cacheRsp.physicalAddress
redoBranch.valid := redoFetch
redoBranch.payload := (if (decodePcGen) decode.input(PC) else cacheRsp.pc)
if (catchSomething) {
val accessFault = if (catchAccessFault) cacheRsp.error else False
val mmuMiss = if (catchMemoryTranslationMiss) cacheRsp.mmuMiss else False
val illegalAccess = if (catchIllegalAccess) cacheRsp.illegalAccess else False
decodeExceptionPort.valid := False
decodeExceptionPort.code := mmuMiss ? U(14) | 1
decodeExceptionPort.badAddr := cacheRsp.pc
when(cacheRsp.isValid && (accessFault || mmuMiss || illegalAccess) && !issueDetected) {
issueDetected \= True
decodeExceptionPort.valid := iBusRsp.readyForError
}
decodeExceptionPort.code.assignDontCare()
decodeExceptionPort.badAddr := cacheRsp.pc(31 downto 2) @@ "00"
}
when(cacheRsp.isValid && cacheRsp.mmuRefilling && !issueDetected) {
issueDetected \= True
redoFetch := True
}
if(catchIllegalAccess) when(cacheRsp.isValid && cacheRsp.mmuException && !issueDetected) {
issueDetected \= True
decodeExceptionPort.valid := iBusRsp.readyForError
decodeExceptionPort.code := 12
}
when(cacheRsp.isValid && cacheRsp.cacheMiss && !issueDetected) {
issueDetected \= True
cache.io.cpu.fill.valid := True
redoFetch := True
}
if(catchAccessFault) when(cacheRsp.isValid && cacheRsp.error && !issueDetected) {
issueDetected \= True
decodeExceptionPort.valid := iBusRsp.readyForError
decodeExceptionPort.code := 1
}
redoFetch clearWhen(!iBusRsp.readyForError)
cache.io.cpu.fill.valid clearWhen(!iBusRsp.readyForError)
if (catchSomething) decodeExceptionPort.valid clearWhen(fetcherHalt)
redoBranch.valid := redoFetch
redoBranch.payload := (if (decodePcGen) decode.input(PC) else cacheRsp.pc)
cacheRspArbitration.halt setWhen (issueDetected || iBusRspOutputHalt)
iBusRsp.output.valid := cacheRspArbitration.output.valid
cacheRspArbitration.output.ready := iBusRsp.output.ready
@ -223,31 +247,19 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
if (mmuBus != null) {
cache.io.cpu.fetch.mmuBus <> mmuBus
(if (twoCycleCache) stages(1).halt else rsp.iBusRspOutputHalt) setWhen (mmuBus.cmd.isValid && !mmuBus.rsp.hit && !mmuBus.rsp.miss)
} else {
cache.io.cpu.fetch.mmuBus.rsp.physicalAddress := cache.io.cpu.fetch.mmuBus.cmd.virtualAddress
cache.io.cpu.fetch.mmuBus.rsp.allowExecute := True
cache.io.cpu.fetch.mmuBus.rsp.allowRead := True
cache.io.cpu.fetch.mmuBus.rsp.allowWrite := True
cache.io.cpu.fetch.mmuBus.rsp.allowUser := True
cache.io.cpu.fetch.mmuBus.rsp.isIoAccess := False
cache.io.cpu.fetch.mmuBus.rsp.miss := False
cache.io.cpu.fetch.mmuBus.rsp.hit := False
cache.io.cpu.fetch.mmuBus.rsp.exception := False
cache.io.cpu.fetch.mmuBus.rsp.refilling := False
cache.io.cpu.fetch.mmuBus.busy := False
}
val flushStage = if(memory != null) memory else execute
flushStage plug new Area {
import flushStage._
cache.io.flush.cmd.valid := False
when(arbitration.isValid && input(FLUSH_ALL)) {
cache.io.flush.cmd.valid := True
when(!cache.io.flush.cmd.ready) {
arbitration.haltItself := True
}
}
}
val flushStage = decode
cache.io.flush := flushStage.arbitration.isValid && flushStage.input(FLUSH_ALL)
}
}
}

View file

@ -7,6 +7,7 @@ import spinal.lib.bus.amba4.axi._
import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig}
import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig}
import spinal.lib.bus.simple._
import vexriscv.Riscv.{FENCE, FENCE_I}
case class IBusSimpleCmd() extends Bundle{
@ -59,6 +60,11 @@ object IBusSimpleBus{
useBTE = true,
useCTI = true
)
def getPipelinedMemoryBusConfig() = PipelinedMemoryBusConfig(
addressWidth = 32,
dataWidth = 32
)
}
@ -136,7 +142,8 @@ case class IBusSimpleBus(interfaceKeepData : Boolean = false) extends Bundle wit
}
def toPipelinedMemoryBus(): PipelinedMemoryBus = {
val bus = PipelinedMemoryBus(32,32)
val pipelinedMemoryBusConfig = IBusSimpleBus.getPipelinedMemoryBusConfig()
val bus = PipelinedMemoryBus(pipelinedMemoryBusConfig)
bus.cmd.arbitrationFrom(cmd)
bus.cmd.address := cmd.pc.resized
bus.cmd.write := False
@ -166,7 +173,9 @@ class IBusSimplePlugin(resetVector : BigInt,
pendingMax : Int = 7,
injectorStage : Boolean = true,
rspHoldValue : Boolean = false,
singleInstructionPipeline : Boolean = false
singleInstructionPipeline : Boolean = false,
memoryTranslatorPortConfig : Any = null,
relaxPredictorAddress : Boolean = true
) extends IBusFetcherImpl(
resetVector = resetVector,
keepPcPlus4 = keepPcPlus4,
@ -177,19 +186,31 @@ class IBusSimplePlugin(resetVector : BigInt,
injectorReadyCutGen = false,
prediction = prediction,
historyRamSizeLog2 = historyRamSizeLog2,
injectorStage = injectorStage){
injectorStage = injectorStage,
relaxPredictorAddress = relaxPredictorAddress){
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)
override def setup(pipeline: VexRiscv): Unit = {
super.setup(pipeline)
iBus = master(IBusSimpleBus(false)).setName("iBus")
if(catchAccessFault) {
val exceptionService = pipeline.service(classOf[ExceptionService])
decodeExceptionPort = exceptionService.newExceptionPort(pipeline.decode,1)
val decoderService = pipeline.service(classOf[DecoderService])
decoderService.add(FENCE_I, Nil)
if(catchSomething) {
decodeExceptionPort = pipeline.service(classOf[ExceptionService]).newExceptionPort(pipeline.decode,1)
}
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
}
}
@ -199,16 +220,20 @@ class IBusSimplePlugin(resetVector : BigInt,
pipeline plug new FetchArea(pipeline) {
var cmd = Stream(IBusSimpleCmd())
iBus.cmd << (if(cmdForkPersistence && !cmdForkOnSecondStage) cmd.s2mPipe() else cmd)
val cmdWithS2mPipe = cmdForkPersistence && (!cmdForkOnSecondStage || mmuBus != null)
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 cmdFork = if(!cmdForkPersistence || !cmdForkOnSecondStage) new Area {
val secondStagePersistence = cmdForkPersistence && cmdForkOnSecondStage && !cmdWithS2mPipe
def cmdForkStage = if(!secondStagePersistence) iBusRsp.stages(if(cmdForkOnSecondStage) 1 else 0) else iBusRsp.stages(1)
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 = iBusRsp.stages(if(cmdForkOnSecondStage) 1 else 0)
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
@ -217,16 +242,40 @@ class IBusSimplePlugin(resetVector : BigInt,
}else {
cmd.valid := stage.input.valid && stage.output.ready && pendingCmd =/= pendingMax
}
cmd.pc := stage.input.payload(31 downto 2) @@ "00"
} else new Area{
//This implementation keep the cmd on the bus until it's executed, even if the pipeline is flushed
def stage = iBusRsp.stages(1)
def stage = cmdForkStage
val pendingFull = pendingCmd === pendingMax
val cmdKeep = RegInit(False) setWhen(cmd.valid) 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
cmd.pc := stage.input.payload(31 downto 2) @@ "00"
}
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 || flush
cmd.pc := mmuBus.rsp.physicalAddress(31 downto 2) @@ "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
}
val joinCtx = stageXToIBusRsp(cmdForkStage, mmuBus.rsp)
}
val mmuLess = (mmuBus == null) generate new Area{
cmd.pc := cmdForkStage.input.payload(31 downto 2) @@ "00"
}
val rspJoin = new Area {
@ -235,7 +284,7 @@ class IBusSimplePlugin(resetVector : BigInt,
val discardCounter = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0)
discardCounter := discardCounter - (iBus.rsp.fire && discardCounter =/= 0).asUInt
when(flush) {
if(cmdForkOnSecondStage && cmdForkPersistence)
if(secondStagePersistence)
discardCounter := pendingCmd + cmd.valid.asUInt - iBus.rsp.fire.asUInt
else
discardCounter := (if(cmdForkOnSecondStage) pendingCmdNext else pendingCmd - iBus.rsp.fire.asUInt)
@ -261,24 +310,41 @@ class IBusSimplePlugin(resetVector : BigInt,
fetchRsp.rsp.error.clearWhen(!rspBufferOutput.valid) //Avoid interference with instruction injection from the debug plugin
var issueDetected = False
val join = Stream(FetchRsp())
val exceptionDetected = False
val redoRequired = False
join.valid := stages.last.output.valid && rspBufferOutput.valid
join.payload := fetchRsp
stages.last.output.ready := stages.last.output.valid ? join.fire | join.ready
rspBufferOutput.ready := join.fire
output << join.haltWhen(issueDetected)
output << join.haltWhen(exceptionDetected || redoRequired)
if(catchAccessFault){
decodeExceptionPort.valid := False
decodeExceptionPort.code := 1
decodeExceptionPort.badAddr := join.pc
when(join.valid && join.rsp.error && !issueDetected){
issueDetected \= True
decodeExceptionPort.valid := iBusRsp.readyForError
if(memoryTranslatorPortConfig != null){
redoRequired setWhen( stages.last.input.valid && mmu.joinCtx.refilling)
redoBranch.valid := redoRequired && iBusRsp.readyForError
redoBranch.payload := decode.input(PC)
decode.arbitration.flushAll setWhen(redoBranch.valid)
}
if(catchSomething){
decodeExceptionPort.code.assignDontCare()
decodeExceptionPort.badAddr := join.pc(31 downto 2) @@ "00"
if(catchAccessFault) when(join.valid && join.rsp.error){
decodeExceptionPort.code := 1
exceptionDetected := True
}
if(memoryTranslatorPortConfig != null) {
val privilegeService = pipeline.serviceElse(classOf[PrivilegeService], PrivilegeServiceDefault())
when(stages.last.input.valid && !mmu.joinCtx.refilling && (mmu.joinCtx.exception || !mmu.joinCtx.allowExecute)){
decodeExceptionPort.code := 12
exceptionDetected := True
}
}
decodeExceptionPort.valid := exceptionDetected && iBusRsp.readyForError && !fetcherHalt
}
}
}
}
}
}

View file

@ -4,7 +4,7 @@ import vexriscv._
import spinal.core._
object IntAluPlugin{
object AluBitwiseCtrlEnum extends SpinalEnum(binarySequential){
val XOR, OR, AND, SRC1 = newElement()
val XOR, OR, AND = newElement()
}
object AluCtrlEnum extends SpinalEnum(binarySequential){
val ADD_SUB, SLT_SLTU, BITWISE = newElement()
@ -70,7 +70,7 @@ class IntAluPlugin extends Plugin[VexRiscv]{
))
decoderService.add(List(
LUI -> (otherAction ++ List(ALU_CTRL -> AluCtrlEnum.BITWISE, ALU_BITWISE_CTRL -> AluBitwiseCtrlEnum.SRC1, SRC1_CTRL -> Src1CtrlEnum.IMU)),
LUI -> (otherAction ++ List(ALU_CTRL -> AluCtrlEnum.ADD_SUB, SRC1_CTRL -> Src1CtrlEnum.IMU, SRC_USE_SUB_LESS -> False, SRC_ADD_ZERO -> True)),
AUIPC -> (otherAction ++ List(ALU_CTRL -> AluCtrlEnum.ADD_SUB, SRC_USE_SUB_LESS -> False, SRC1_CTRL -> Src1CtrlEnum.IMU, SRC2_CTRL -> Src2CtrlEnum.PC))
))
}
@ -86,8 +86,7 @@ class IntAluPlugin extends Plugin[VexRiscv]{
val bitwise = input(ALU_BITWISE_CTRL).mux(
AluBitwiseCtrlEnum.AND -> (input(SRC1) & input(SRC2)),
AluBitwiseCtrlEnum.OR -> (input(SRC1) | input(SRC2)),
AluBitwiseCtrlEnum.XOR -> (input(SRC1) ^ input(SRC2)),
AluBitwiseCtrlEnum.SRC1 -> input(SRC1)
AluBitwiseCtrlEnum.XOR -> (input(SRC1) ^ input(SRC2))
)
// mux results

View file

@ -112,19 +112,20 @@ class MemoryTranslatorPlugin(tlbSize : Int,
port.bus.rsp.allowRead := cacheLine.allowRead
port.bus.rsp.allowWrite := cacheLine.allowWrite
port.bus.rsp.allowExecute := cacheLine.allowExecute
port.bus.rsp.allowUser := cacheLine.allowUser
port.bus.rsp.hit := cacheHit
???
// port.bus.rsp.hit := cacheHit
// port.stage.arbitration.haltItself setWhen (port.bus.cmd.isValid && !cacheHit && !sharedMiss)
} otherwise {
port.bus.rsp.physicalAddress := port.bus.cmd.virtualAddress
port.bus.rsp.allowRead := True
port.bus.rsp.allowWrite := True
port.bus.rsp.allowExecute := True
port.bus.rsp.allowUser := True
port.bus.rsp.hit := True
???
// port.bus.rsp.hit := True
}
port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress)
port.bus.rsp.miss := sharedMiss
???
// port.bus.rsp.miss := sharedMiss
}
}

View file

@ -0,0 +1,261 @@
package vexriscv.plugin
import vexriscv.{VexRiscv, _}
import spinal.core._
import spinal.lib._
import scala.collection.mutable.ArrayBuffer
trait DBusAccessService{
def newDBusAccess() : DBusAccess
}
case class DBusAccessCmd() extends Bundle {
val address = UInt(32 bits)
val size = UInt(2 bits)
val write = Bool
val data = Bits(32 bits)
val writeMask = Bits(4 bits)
}
case class DBusAccessRsp() extends Bundle {
val data = Bits(32 bits)
val error = Bool()
val redo = Bool()
}
case class DBusAccess() extends Bundle {
val cmd = Stream(DBusAccessCmd())
val rsp = Flow(DBusAccessRsp())
}
object MmuPort{
val PRIORITY_DATA = 1
val PRIORITY_INSTRUCTION = 0
}
case class MmuPort(bus : MemoryTranslatorBus, priority : Int, args : MmuPortConfig, id : Int/*, exceptionBus: Flow[ExceptionCause]*/)
case class MmuPortConfig(portTlbSize : Int)
class MmuPlugin(ioRange : UInt => Bool,
virtualRange : UInt => Bool = address => True,
// allowUserIo : Boolean = false,
enableMmuInMachineMode : Boolean = false) extends Plugin[VexRiscv] with MemoryTranslator {
var dBusAccess : DBusAccess = null
val portsInfo = ArrayBuffer[MmuPort]()
override def newTranslationPort(priority : Int,args : Any): MemoryTranslatorBus = {
val port = MmuPort(MemoryTranslatorBus(),priority,args.asInstanceOf[MmuPortConfig], portsInfo.length)
portsInfo += port
port.bus
}
object IS_SFENCE_VMA extends Stageable(Bool)
override def setup(pipeline: VexRiscv): Unit = {
import Riscv._
import pipeline.config._
val decoderService = pipeline.service(classOf[DecoderService])
decoderService.addDefault(IS_SFENCE_VMA, False)
decoderService.add(SFENCE_VMA, List(IS_SFENCE_VMA -> True))
dBusAccess = pipeline.service(classOf[DBusAccessService]).newDBusAccess()
}
override def build(pipeline: VexRiscv): Unit = {
import pipeline._
import pipeline.config._
import Riscv._
val csrService = pipeline.service(classOf[CsrInterface])
//Sorted by priority
val sortedPortsInfo = portsInfo.sortWith((a,b) => a.priority > b.priority)
case class CacheLine() extends Bundle {
val valid, exception, superPage = Bool
val virtualAddress = Vec(UInt(10 bits), UInt(10 bits))
val physicalAddress = Vec(UInt(10 bits), UInt(10 bits))
val allowRead, allowWrite, allowExecute, allowUser = Bool
def init = {
valid init (False)
this
}
}
val csr = pipeline plug new Area{
val status = new Area{
val sum, mxr, mprv = RegInit(False)
}
val satp = new Area {
val mode = RegInit(False)
val ppn = Reg(UInt(20 bits))
}
for(offset <- List(CSR.MSTATUS, CSR.SSTATUS)) csrService.rw(offset, 19 -> status.mxr, 18 -> status.sum, 17 -> status.mprv)
csrService.rw(CSR.SATP, 31 -> satp.mode, 0 -> satp.ppn)
}
val core = pipeline plug new Area {
val ports = for (port <- sortedPortsInfo) yield new Area {
val handle = port
val id = port.id
val cache = Vec(Reg(CacheLine()) init, port.args.portTlbSize)
val cacheHits = cache.map(line => line.valid && line.virtualAddress(1) === port.bus.cmd.virtualAddress(31 downto 22) && (line.superPage || line.virtualAddress(0) === port.bus.cmd.virtualAddress(21 downto 12)))
val cacheHit = cacheHits.asBits.orR
val cacheLine = MuxOH(cacheHits, cache)
val privilegeService = pipeline.serviceElse(classOf[PrivilegeService], PrivilegeServiceDefault())
val entryToReplace = Counter(port.args.portTlbSize)
val requireMmuLockup = virtualRange(port.bus.cmd.virtualAddress) && !port.bus.cmd.bypassTranslation && csr.satp.mode
if(!enableMmuInMachineMode) {
requireMmuLockup clearWhen(!csr.status.mprv && privilegeService.isMachine())
when(privilegeService.isMachine()) {
if (port.priority == MmuPort.PRIORITY_DATA) {
requireMmuLockup clearWhen (!csr.status.mprv || pipeline(MPP) === 3)
} else {
requireMmuLockup := False
}
}
}
when(requireMmuLockup) {
port.bus.rsp.physicalAddress := cacheLine.physicalAddress(1) @@ (cacheLine.superPage ? port.bus.cmd.virtualAddress(21 downto 12) | cacheLine.physicalAddress(0)) @@ port.bus.cmd.virtualAddress(11 downto 0)
port.bus.rsp.allowRead := cacheLine.allowRead || csr.status.mxr && cacheLine.allowExecute
port.bus.rsp.allowWrite := cacheLine.allowWrite
port.bus.rsp.allowExecute := cacheLine.allowExecute
port.bus.rsp.exception := cacheHit && (cacheLine.exception || cacheLine.allowUser && privilegeService.isSupervisor() && !csr.status.sum || !cacheLine.allowUser && privilegeService.isUser())
port.bus.rsp.refilling := !cacheHit
} otherwise {
port.bus.rsp.physicalAddress := port.bus.cmd.virtualAddress
port.bus.rsp.allowRead := True
port.bus.rsp.allowWrite := True
port.bus.rsp.allowExecute := True
port.bus.rsp.exception := False
port.bus.rsp.refilling := False
}
port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress)
// Avoid keeping any invalid line in the cache after an exception.
// https://github.com/riscv/riscv-linux/blob/8fe28cb58bcb235034b64cbbb7550a8a43fd88be/arch/riscv/include/asm/pgtable.h#L276
when(service(classOf[IContextSwitching]).isContextSwitching) {
for (line <- cache) {
when(line.exception) {
line.valid := False
}
}
}
}
val shared = new Area {
val State = new SpinalEnum{
val IDLE, L1_CMD, L1_RSP, L0_CMD, L0_RSP = newElement()
}
val state = RegInit(State.IDLE)
val vpn = Reg(Vec(UInt(10 bits), UInt(10 bits)))
val portId = Reg(UInt(log2Up(portsInfo.length) bits))
case class PTE() extends Bundle {
val V, R, W ,X, U, G, A, D = Bool()
val RSW = Bits(2 bits)
val PPN0 = UInt(10 bits)
val PPN1 = UInt(12 bits)
}
val dBusRsp = new Area{
val pte = PTE()
pte.assignFromBits(dBusAccess.rsp.data)
val exception = !pte.V || (!pte.R && pte.W) || dBusAccess.rsp.error
val leaf = pte.R || pte.X
}
val pteBuffer = RegNextWhen(dBusRsp.pte, dBusAccess.rsp.valid && !dBusAccess.rsp.redo)
dBusAccess.cmd.valid := False
dBusAccess.cmd.write := False
dBusAccess.cmd.size := 2
dBusAccess.cmd.address.assignDontCare()
dBusAccess.cmd.data.assignDontCare()
dBusAccess.cmd.writeMask.assignDontCare()
switch(state){
is(State.IDLE){
for(port <- portsInfo.sortBy(_.priority)){
when(port.bus.cmd.isValid && port.bus.rsp.refilling){
vpn(1) := port.bus.cmd.virtualAddress(31 downto 22)
vpn(0) := port.bus.cmd.virtualAddress(21 downto 12)
portId := port.id
state := State.L1_CMD
}
}
}
is(State.L1_CMD){
dBusAccess.cmd.valid := True
dBusAccess.cmd.address := csr.satp.ppn @@ vpn(1) @@ U"00"
when(dBusAccess.cmd.ready){
state := State.L1_RSP
}
}
is(State.L1_RSP){
when(dBusAccess.rsp.valid){
state := State.L0_CMD
when(dBusRsp.leaf || dBusRsp.exception){
state := State.IDLE
}
when(dBusAccess.rsp.redo){
state := State.L1_CMD
}
}
}
is(State.L0_CMD){
dBusAccess.cmd.valid := True
dBusAccess.cmd.address := pteBuffer.PPN1(9 downto 0) @@ pteBuffer.PPN0 @@ vpn(0) @@ U"00"
when(dBusAccess.cmd.ready){
state := State.L0_RSP
}
}
is(State.L0_RSP){
when(dBusAccess.rsp.valid) {
state := State.IDLE
when(dBusAccess.rsp.redo){
state := State.L0_CMD
}
}
}
}
for(port <- ports) {
port.handle.bus.busy := state =/= State.IDLE && portId === port.id
}
when(dBusAccess.rsp.valid && !dBusAccess.rsp.redo && (dBusRsp.leaf || dBusRsp.exception)){
for(port <- ports){
when(portId === port.id) {
port.entryToReplace.increment()
for ((line, lineId) <- port.cache.zipWithIndex) {
when(port.entryToReplace === lineId){
val superPage = state === State.L1_RSP
line.valid := True
line.exception := dBusRsp.exception || (superPage && dBusRsp.pte.PPN0 =/= 0)
line.virtualAddress := vpn
line.physicalAddress := Vec(dBusRsp.pte.PPN0, dBusRsp.pte.PPN1(9 downto 0))
line.allowRead := dBusRsp.pte.R
line.allowWrite := dBusRsp.pte.W
line.allowExecute := dBusRsp.pte.X
line.allowUser := dBusRsp.pte.U
line.superPage := state === State.L1_RSP
}
}
}
}
}
}
}
val fenceStage = stages.last
fenceStage plug new Area{
import fenceStage._
when(arbitration.isValid && input(IS_SFENCE_VMA)){ // || csrService.isWriting(CSR.SATP)
for(port <- core.ports; line <- port.cache) line.valid := False //Assume that the instruction already fetched into the pipeline are ok
}
}
}
}

View file

@ -0,0 +1,90 @@
package vexriscv.plugin
import vexriscv._
import vexriscv.VexRiscv
import spinal.core._
class MulSimplePlugin extends Plugin[VexRiscv]{
object MUL_OPA extends Stageable(SInt(33 bits))
object MUL_OPB extends Stageable(SInt(33 bits))
object MUL extends Stageable(Bits(64 bits))
object IS_MUL extends Stageable(Bool)
override def setup(pipeline: VexRiscv): Unit = {
import Riscv._
import pipeline.config._
val actions = List[(Stageable[_ <: BaseType],Any)](
SRC1_CTRL -> Src1CtrlEnum.RS,
SRC2_CTRL -> Src2CtrlEnum.RS,
REGFILE_WRITE_VALID -> True,
BYPASSABLE_EXECUTE_STAGE -> False,
BYPASSABLE_MEMORY_STAGE -> False,
RS1_USE -> True,
RS2_USE -> True,
IS_MUL -> True
)
val decoderService = pipeline.service(classOf[DecoderService])
decoderService.addDefault(IS_MUL, False)
decoderService.add(List(
MULX -> actions
))
}
override def build(pipeline: VexRiscv): Unit = {
import pipeline._
import pipeline.config._
// Prepare signed inputs for the multiplier in the next stage.
// This will map them best to an FPGA DSP.
execute plug new Area {
import execute._
val aSigned,bSigned = Bool
val a,b = Bits(32 bit)
a := input(SRC1)
b := input(SRC2)
switch(input(INSTRUCTION)(13 downto 12)) {
is(B"01") {
aSigned := True
bSigned := True
}
is(B"10") {
aSigned := True
bSigned := False
}
default {
aSigned := False
bSigned := False
}
}
insert(MUL_OPA) := ((aSigned ? a.msb | False) ## a).asSInt
insert(MUL_OPB) := ((bSigned ? b.msb | False) ## b).asSInt
}
memory plug new Area {
import memory._
insert(MUL) := (input(MUL_OPA) * input(MUL_OPB))(63 downto 0).asBits
}
writeBack plug new Area {
import writeBack._
when(arbitration.isValid && input(IS_MUL)){
switch(input(INSTRUCTION)(13 downto 12)){
is(B"00"){
output(REGFILE_WRITE_DATA) := input(MUL)(31 downto 0)
}
is(B"01",B"10",B"11"){
output(REGFILE_WRITE_DATA) := input(MUL)(63 downto 32)
}
}
}
}
}
}

View file

@ -1,14 +1,14 @@
package vexriscv.plugin
import vexriscv.{Pipeline, Stage}
import spinal.core.Area
import spinal.core.{Area, Nameable}
/**
* Created by PIC32F_USER on 03/03/2017.
*/
trait Plugin[T <: Pipeline] {
trait Plugin[T <: Pipeline] extends Nameable{
var pipeline : T = null.asInstanceOf[T]
def getName() = this.getClass.getSimpleName.replace("$","")
setName(this.getClass.getSimpleName.replace("$",""))
def setup(pipeline: T) : Unit = {}
def build(pipeline: T) : Unit

View file

@ -91,7 +91,7 @@ class RegFilePlugin(regFileReadyKind : RegFileReadKind,
import writeStage._
def shadowPrefix(that : Bits) = if(withShadow) global.shadow.write ## that else that
val regFileWrite = global.regFile.writePort.addAttribute(Verilator.public)
val regFileWrite = global.regFile.writePort.addAttribute(Verilator.public).setName("lastStageRegFileWrite")
regFileWrite.valid := output(REGFILE_WRITE_VALID) && arbitration.isFiring
regFileWrite.address := U(shadowPrefix(output(INSTRUCTION)(rdRange)))
regFileWrite.data := output(REGFILE_WRITE_DATA)

View file

@ -69,12 +69,14 @@ class FullBarrelShifterPlugin(earlyInjection : Boolean = false) extends Plugin[V
val injectionStage = if(earlyInjection) execute else memory
injectionStage plug new Area{
import injectionStage._
switch(input(SHIFT_CTRL)){
is(ShiftCtrlEnum.SLL){
output(REGFILE_WRITE_DATA) := Reverse(input(SHIFT_RIGHT))
}
is(ShiftCtrlEnum.SRL,ShiftCtrlEnum.SRA){
output(REGFILE_WRITE_DATA) := input(SHIFT_RIGHT)
when(arbitration.isValid){
switch(input(SHIFT_CTRL)) {
is(ShiftCtrlEnum.SLL) {
output(REGFILE_WRITE_DATA) := Reverse(input(SHIFT_RIGHT))
}
is(ShiftCtrlEnum.SRL, ShiftCtrlEnum.SRA) {
output(REGFILE_WRITE_DATA) := input(SHIFT_RIGHT)
}
}
}
}
@ -105,24 +107,30 @@ class LightShifterPlugin extends Plugin[VexRiscv]{
val immediateActions = List[(Stageable[_ <: BaseType],Any)](
SRC1_CTRL -> Src1CtrlEnum.RS,
SRC2_CTRL -> Src2CtrlEnum.IMI,
ALU_CTRL -> AluCtrlEnum.BITWISE,
ALU_BITWISE_CTRL -> AluBitwiseCtrlEnum.SRC1,
REGFILE_WRITE_VALID -> True,
BYPASSABLE_EXECUTE_STAGE -> True,
BYPASSABLE_MEMORY_STAGE -> True,
RS1_USE -> True
RS1_USE -> True,
//Get SRC1 through the MMU to the RF write path
ALU_CTRL -> AluCtrlEnum.ADD_SUB,
SRC_USE_SUB_LESS -> False,
SRC_ADD_ZERO -> True
)
val nonImmediateActions = List[(Stageable[_ <: BaseType],Any)](
SRC1_CTRL -> Src1CtrlEnum.RS,
SRC2_CTRL -> Src2CtrlEnum.RS,
ALU_CTRL -> AluCtrlEnum.BITWISE,
ALU_BITWISE_CTRL -> AluBitwiseCtrlEnum.SRC1,
REGFILE_WRITE_VALID -> True,
BYPASSABLE_EXECUTE_STAGE -> True,
BYPASSABLE_MEMORY_STAGE -> True,
RS1_USE -> True,
RS2_USE -> True
RS2_USE -> True,
//Get SRC1 through the MMU to the RF write path
ALU_CTRL -> AluCtrlEnum.ADD_SUB,
SRC_USE_SUB_LESS -> False,
SRC_ADD_ZERO -> True
)
val decoderService = pipeline.service(classOf[DecoderService])
@ -156,6 +164,7 @@ class LightShifterPlugin extends Plugin[VexRiscv]{
val shiftInput = isActive ? (if(withMemoryStage) memory.input(REGFILE_WRITE_DATA) else shiftReg) | input(SRC1)
val done = amplitude(4 downto 1) === 0
if(withMemoryStage) memory.dontSampleStageable(REGFILE_WRITE_DATA, arbitration.isStuckByOthers)
when(arbitration.isValid && isShift && input(SRC2)(4 downto 0) =/= 0){
output(REGFILE_WRITE_DATA) := input(SHIFT_CTRL).mux(

View file

@ -1,13 +1,26 @@
package vexriscv.plugin
import vexriscv.{RVC_GEN, Riscv, VexRiscv}
import vexriscv._
import spinal.core._
class SrcPlugin(separatedAddSub : Boolean = false, executeInsertion : Boolean = false, decodeAddSub : Boolean = false) extends Plugin[VexRiscv]{
object SRC2_FORCE_ZERO extends Stageable(Bool)
override def setup(pipeline: VexRiscv): Unit = {
import pipeline.config._
val decoderService = pipeline.service(classOf[DecoderService])
decoderService.addDefault(SRC_ADD_ZERO, False) //TODO avoid this default to simplify decoding ?
}
override def build(pipeline: VexRiscv): Unit = {
import pipeline._
import pipeline.config._
decode.insert(SRC2_FORCE_ZERO) := decode.input(SRC_ADD_ZERO) && !decode.input(SRC_USE_SUB_LESS)
val insertionStage = if(executeInsertion) execute else decode
insertionStage plug new Area{
import insertionStage._
@ -33,8 +46,9 @@ class SrcPlugin(separatedAddSub : Boolean = false, executeInsertion : Boolean =
import addSubStage._
// ADD, SUB
val add = (input(SRC1).asUInt + input(SRC2).asUInt).asBits.addAttribute("keep")
val sub = (input(SRC1).asUInt - input(SRC2).asUInt).asBits.addAttribute("keep")
val add = (U(input(SRC1)) + U(input(SRC2))).asBits.addAttribute("keep")
val sub = (U(input(SRC1)) - U(input(SRC2))).asBits.addAttribute("keep")
when(input(SRC_ADD_ZERO)){ add := input(SRC1) }
// SLT, SLTU
val less = Mux(input(SRC1).msb === input(SRC2).msb, sub.msb,
@ -50,7 +64,9 @@ class SrcPlugin(separatedAddSub : Boolean = false, executeInsertion : Boolean =
import addSubStage._
// ADD, SUB
val addSub = (input(SRC1).asSInt + Mux(input(SRC_USE_SUB_LESS), ~input(SRC2), input(SRC2)).asSInt + Mux(input(SRC_USE_SUB_LESS), S(1), S(0))).asBits
val addSub = (input(SRC1).asSInt + Mux(input(SRC_USE_SUB_LESS), ~input(SRC2), input(SRC2)).asSInt + Mux(input(SRC_USE_SUB_LESS), S(1, 32 bits), S(0, 32 bits))).asBits
when(input(SRC2_FORCE_ZERO)){ addSub := input(SRC1) }
// SLT, SLTU
val less = Mux(input(SRC1).msb === input(SRC2).msb, addSub.msb,

View file

@ -31,10 +31,10 @@ class StaticMemoryTranslatorPlugin(ioRange : UInt => Bool) extends Plugin[VexRis
port.bus.rsp.allowRead := True
port.bus.rsp.allowWrite := True
port.bus.rsp.allowExecute := True
port.bus.rsp.allowUser := True
port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress)
port.bus.rsp.miss := False
port.bus.rsp.hit := True
port.bus.rsp.exception := False
port.bus.rsp.refilling := False
port.bus.busy := False
}
}
}

4
src/test/cpp/raw/amo/.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
*.map
*.v
*.elf
*.o

View file

@ -0,0 +1,247 @@
build/amo.elf: file format elf32-littleriscv
Disassembly of section .crt_section:
80000000 <_start>:
80000000: 00100e13 li t3,1
80000004: 00000097 auipc ra,0x0
80000008: 27408093 addi ra,ra,628 # 80000278 <test1_data>
8000000c: 02d00113 li sp,45
80000010: 0820a1af amoswap.w gp,sp,(ra)
80000014: 0000a203 lw tp,0(ra)
80000018: 02d00a13 li s4,45
8000001c: 224a1663 bne s4,tp,80000248 <fail>
80000020: 00b00a13 li s4,11
80000024: 223a1263 bne s4,gp,80000248 <fail>
80000028 <test2>:
80000028: 00200e13 li t3,2
8000002c: 00000097 auipc ra,0x0
80000030: 25008093 addi ra,ra,592 # 8000027c <test2_data>
80000034: 03700113 li sp,55
80000038: 0820a1af amoswap.w gp,sp,(ra)
8000003c: 0000a203 lw tp,0(ra)
80000040: 03700a13 li s4,55
80000044: 204a1263 bne s4,tp,80000248 <fail>
80000048: 01600a13 li s4,22
8000004c: 1e3a1e63 bne s4,gp,80000248 <fail>
80000050 <test3>:
80000050: 00300e13 li t3,3
80000054: 00000097 auipc ra,0x0
80000058: 22c08093 addi ra,ra,556 # 80000280 <test3_data>
8000005c: 04200113 li sp,66
80000060: 0020a1af amoadd.w gp,sp,(ra)
80000064: 0000a203 lw tp,0(ra)
80000068: 08b00a13 li s4,139
8000006c: 1c4a1e63 bne s4,tp,80000248 <fail>
80000070: 04900a13 li s4,73
80000074: 1c3a1a63 bne s4,gp,80000248 <fail>
80000078 <test4>:
80000078: 00400e13 li t3,4
8000007c: 00000097 auipc ra,0x0
80000080: 20808093 addi ra,ra,520 # 80000284 <test4_data>
80000084: 05700113 li sp,87
80000088: 2020a1af amoxor.w gp,sp,(ra)
8000008c: 0000a203 lw tp,0(ra)
80000090: 06d00a13 li s4,109
80000094: 1a4a1a63 bne s4,tp,80000248 <fail>
80000098: 03a00a13 li s4,58
8000009c: 1a3a1663 bne s4,gp,80000248 <fail>
800000a0 <test5>:
800000a0: 00500e13 li t3,5
800000a4: 00000097 auipc ra,0x0
800000a8: 1e408093 addi ra,ra,484 # 80000288 <test5_data>
800000ac: 02c00113 li sp,44
800000b0: 6020a1af amoand.w gp,sp,(ra)
800000b4: 0000a203 lw tp,0(ra)
800000b8: 02800a13 li s4,40
800000bc: 184a1663 bne s4,tp,80000248 <fail>
800000c0: 03800a13 li s4,56
800000c4: 183a1263 bne s4,gp,80000248 <fail>
800000c8 <test6>:
800000c8: 00600e13 li t3,6
800000cc: 00000097 auipc ra,0x0
800000d0: 1c008093 addi ra,ra,448 # 8000028c <test6_data>
800000d4: 01800113 li sp,24
800000d8: 4020a1af amoor.w gp,sp,(ra)
800000dc: 0000a203 lw tp,0(ra)
800000e0: 05b00a13 li s4,91
800000e4: 164a1263 bne s4,tp,80000248 <fail>
800000e8: 04b00a13 li s4,75
800000ec: 143a1e63 bne s4,gp,80000248 <fail>
800000f0 <test7>:
800000f0: 00700e13 li t3,7
800000f4: 00000097 auipc ra,0x0
800000f8: 19c08093 addi ra,ra,412 # 80000290 <test7_data>
800000fc: 01800113 li sp,24
80000100: 8020a1af amomin.w gp,sp,(ra)
80000104: 0000a203 lw tp,0(ra)
80000108: 01800a13 li s4,24
8000010c: 124a1e63 bne s4,tp,80000248 <fail>
80000110: 03800a13 li s4,56
80000114: 123a1a63 bne s4,gp,80000248 <fail>
80000118 <test8>:
80000118: 00800e13 li t3,8
8000011c: 00000097 auipc ra,0x0
80000120: 17808093 addi ra,ra,376 # 80000294 <test8_data>
80000124: 05800113 li sp,88
80000128: 8020a1af amomin.w gp,sp,(ra)
8000012c: 0000a203 lw tp,0(ra)
80000130: 05300a13 li s4,83
80000134: 104a1a63 bne s4,tp,80000248 <fail>
80000138: 05300a13 li s4,83
8000013c: 103a1663 bne s4,gp,80000248 <fail>
80000140 <test9>:
80000140: 00900e13 li t3,9
80000144: 00000097 auipc ra,0x0
80000148: 15408093 addi ra,ra,340 # 80000298 <test9_data>
8000014c: fca00113 li sp,-54
80000150: 8020a1af amomin.w gp,sp,(ra)
80000154: 0000a203 lw tp,0(ra)
80000158: fca00a13 li s4,-54
8000015c: 0e4a1663 bne s4,tp,80000248 <fail>
80000160: 02100a13 li s4,33
80000164: 0e3a1263 bne s4,gp,80000248 <fail>
80000168 <test10>:
80000168: 00a00e13 li t3,10
8000016c: 00000097 auipc ra,0x0
80000170: 13008093 addi ra,ra,304 # 8000029c <test10_data>
80000174: 03400113 li sp,52
80000178: 8020a1af amomin.w gp,sp,(ra)
8000017c: 0000a203 lw tp,0(ra)
80000180: fbf00a13 li s4,-65
80000184: 0c4a1263 bne s4,tp,80000248 <fail>
80000188: fbf00a13 li s4,-65
8000018c: 0a3a1e63 bne s4,gp,80000248 <fail>
80000190 <test11>:
80000190: 00b00e13 li t3,11
80000194: 00000097 auipc ra,0x0
80000198: 10c08093 addi ra,ra,268 # 800002a0 <test11_data>
8000019c: fcc00113 li sp,-52
800001a0: a020a1af amomax.w gp,sp,(ra)
800001a4: 0000a203 lw tp,0(ra)
800001a8: fcc00a13 li s4,-52
800001ac: 084a1e63 bne s4,tp,80000248 <fail>
800001b0: fa900a13 li s4,-87
800001b4: 083a1a63 bne s4,gp,80000248 <fail>
800001b8 <test12>:
800001b8: 00c00e13 li t3,12
800001bc: 00000097 auipc ra,0x0
800001c0: 0e808093 addi ra,ra,232 # 800002a4 <test12_data>
800001c4: 03400113 li sp,52
800001c8: a020a1af amomax.w gp,sp,(ra)
800001cc: 0000a203 lw tp,0(ra)
800001d0: 03400a13 li s4,52
800001d4: 064a1a63 bne s4,tp,80000248 <fail>
800001d8: fc900a13 li s4,-55
800001dc: 063a1663 bne s4,gp,80000248 <fail>
800001e0 <test13>:
800001e0: 00d00e13 li t3,13
800001e4: 00000097 auipc ra,0x0
800001e8: 0c408093 addi ra,ra,196 # 800002a8 <test13_data>
800001ec: ffff0137 lui sp,0xffff0
800001f0: c020a1af amominu.w gp,sp,(ra)
800001f4: 0000a203 lw tp,0(ra)
800001f8: ffff0a37 lui s4,0xffff0
800001fc: 044a1663 bne s4,tp,80000248 <fail>
80000200: ffff0a37 lui s4,0xffff0
80000204: 004a0a13 addi s4,s4,4 # ffff0004 <test14_data+0x7ffefd58>
80000208: 043a1063 bne s4,gp,80000248 <fail>
8000020c: 0480006f j 80000254 <pass>
80000210 <test14>:
80000210: 00e00e13 li t3,14
80000214: 00000097 auipc ra,0x0
80000218: 09808093 addi ra,ra,152 # 800002ac <test14_data>
8000021c: ffff0137 lui sp,0xffff0
80000220: 00c10113 addi sp,sp,12 # ffff000c <test14_data+0x7ffefd60>
80000224: e020a1af amomaxu.w gp,sp,(ra)
80000228: 0000a203 lw tp,0(ra)
8000022c: ffff0a37 lui s4,0xffff0
80000230: 00ca0a13 addi s4,s4,12 # ffff000c <test14_data+0x7ffefd60>
80000234: 004a1a63 bne s4,tp,80000248 <fail>
80000238: ffff0a37 lui s4,0xffff0
8000023c: 005a0a13 addi s4,s4,5 # ffff0005 <test14_data+0x7ffefd59>
80000240: 003a1463 bne s4,gp,80000248 <fail>
80000244: 0100006f j 80000254 <pass>
80000248 <fail>:
80000248: f0100137 lui sp,0xf0100
8000024c: f2410113 addi sp,sp,-220 # f00fff24 <test14_data+0x700ffc78>
80000250: 01c12023 sw t3,0(sp)
80000254 <pass>:
80000254: f0100137 lui sp,0xf0100
80000258: f2010113 addi sp,sp,-224 # f00fff20 <test14_data+0x700ffc74>
8000025c: 00012023 sw zero,0(sp)
80000260: 00000013 nop
80000264: 00000013 nop
80000268: 00000013 nop
8000026c: 00000013 nop
80000270: 00000013 nop
80000274: 00000013 nop
80000278 <test1_data>:
80000278: 0000000b 0xb
8000027c <test2_data>:
8000027c: 0016 c.slli zero,0x5
...
80000280 <test3_data>:
80000280: 0049 c.nop 18
...
80000284 <test4_data>:
80000284: 003a c.slli zero,0xe
...
80000288 <test5_data>:
80000288: 0038 addi a4,sp,8
...
8000028c <test6_data>:
8000028c: 0000004b fnmsub.s ft0,ft0,ft0,ft0,rne
80000290 <test7_data>:
80000290: 0038 addi a4,sp,8
...
80000294 <test8_data>:
80000294: 00000053 fadd.s ft0,ft0,ft0,rne
80000298 <test9_data>:
80000298: 0021 c.nop 8
...
8000029c <test10_data>:
8000029c: ffffffbf 0xffffffbf
800002a0 <test11_data>:
800002a0: ffa9 bnez a5,800001fa <test13+0x1a>
800002a2: ffff 0xffff
800002a4 <test12_data>:
800002a4: ffc9 bnez a5,8000023e <test14+0x2e>
800002a6: ffff 0xffff
800002a8 <test13_data>:
800002a8: 0004 0x4
800002aa: ffff 0xffff
800002ac <test14_data>:
800002ac: 0005 c.nop 1
800002ae: ffff 0xffff

View file

@ -0,0 +1,45 @@
:0200000480007A
:10000000130E100097000000938040271301D002C8
:10001000AFA1200803A20000130AD00263164A22EF
:10002000130AB00063123A22130E2000970000005A
:100030009380002513017003AFA1200803A20000E4
:10004000130A700363124A20130A6001631E3A1EEA
:10005000130E3000970000009380C022130120048B
:10006000AFA1200003A20000130AB008631E4A1CBF
:10007000130A9004631A3A1C130E40009700000004
:100080009380802013017005AFA1202003A20000FF
:10009000130AD006631A4A1A130AA00363163A1AFF
:1000A000130E5000970000009380401E1301C00201
:1000B000AFA1206003A20000130A800263164A1851
:1000C000130A800363123A18130E600097000000B1
:1000D0009380001C13018001AFA1204003A2000007
:1000E000130AB00563124A16130AB004631E3A14C9
:1000F000130E7000970000009380C0191301800157
:10010000AFA1208003A20000130A8001631E4A12DF
:10011000130A8003631A3A12130E8000970000003E
:100120009380801713018005AFA1208003A20000F7
:10013000130A3005631A4A10130A300563163A1081
:10014000130E900097000000938040151301A0FC4F
:10015000AFA1208003A20000130AA0FC63164A0E80
:10016000130A100263123A0E130EA000970000004B
:100170009380001313014003AFA1208003A200006D
:10018000130AF0FB63124A0C130AF0FB631E3A0ACF
:10019000130EB000970000009380C0101301C0FC44
:1001A000AFA120A003A20000130AC0FC631E4A08EE
:1001B000130A90FA631A3A08130EC0009700000061
:1001C0009380800E13014003AFA120A003A2000082
:1001D000130A4003631A4A06130A90FC63163A0690
:1001E000130ED000970000009380400C3701FFFFF2
:1001F000AFA120C003A20000370AFFFF63164A0424
:10020000370AFFFF130A4A0063103A046F008004A4
:10021000130EE00097000000938080093701FFFF74
:100220001301C100AFA120E003A20000370AFFFFC5
:10023000130ACA00631A4A00370AFFFF130A5A005A
:1002400063143A006F000001370110F0130141F20E
:100250002320C101370110F0130101F22320010016
:100260001300000013000000130000001300000042
:1002700013000000130000000B0000001600000037
:10028000490000003A000000380000004B00000068
:10029000380000005300000021000000BFFFFFFFF6
:1002A000A9FFFFFFC9FFFFFF0400FFFF0500FFFFDD
:00000001FF

View file

@ -0,0 +1,5 @@
PROJ_NAME=amo
ATOMIC=yes
include ../common/asm.mk

View file

@ -0,0 +1,174 @@
.globl _star
#define TEST_ID x28
_start:
#define assert(reg, value) \
li x20, value; \
bne x20, reg, fail;
test1:
li TEST_ID, 1
la x1, test1_data
li x2, 45
amoswap.w x3,x2,(x1)
lw x4, 0(x1)
assert(x4, 45)
assert(x3, 11)
test2:
li TEST_ID, 2
la x1, test2_data
li x2, 55
amoswap.w x3,x2,(x1)
lw x4, 0(x1)
assert(x4, 55)
assert(x3, 22)
test3:
li TEST_ID,3
la x1, test3_data
li x2, 66
amoadd.w x3,x2,(x1)
lw x4, 0(x1)
assert(x4, 66+73)
assert(x3, 73)
test4:
li TEST_ID,4
la x1, test4_data
li x2, 87
amoxor.w x3,x2,(x1)
lw x4, 0(x1)
assert(x4, 87^58)
assert(x3, 58)
test5:
li TEST_ID,5
la x1, test5_data
li x2, 44
amoand.w x3,x2,(x1)
lw x4, 0(x1)
assert(x4, 44 & 56)
assert(x3, 56)
test6:
li TEST_ID,6
la x1, test6_data
li x2, 24
amoor.w x3,x2,(x1)
lw x4, 0(x1)
assert(x4, 24 | 75)
assert(x3, 75)
test7:
li TEST_ID,7
la x1, test7_data
li x2, 24
amomin.w x3,x2,(x1)
lw x4, 0(x1)
assert(x4, 24)
assert(x3, 56)
test8:
li TEST_ID,8
la x1, test8_data
li x2, 88
amomin.w x3,x2,(x1)
lw x4, 0(x1)
assert(x4, 83)
assert(x3, 83)
test9:
li TEST_ID,9
la x1, test9_data
li x2, -54
amomin.w x3,x2,(x1)
lw x4, 0(x1)
assert(x4, -54)
assert(x3, 33)
test10:
li TEST_ID,10
la x1, test10_data
li x2, 52
amomin.w x3,x2,(x1)
lw x4, 0(x1)
assert(x4, -65)
assert(x3, -65)
test11:
li TEST_ID,11
la x1, test11_data
li x2, -52
amomax.w x3,x2,(x1)
lw x4, 0(x1)
assert(x4, -52)
assert(x3, -87)
test12:
li TEST_ID,12
la x1, test12_data
li x2, 52
amomax.w x3,x2,(x1)
lw x4, 0(x1)
assert(x4, 52)
assert(x3, -55)
test13:
li TEST_ID,13
la x1, test13_data
li x2, 0xFFFF0000
amominu.w x3,x2,(x1)
lw x4, 0(x1)
assert(x4, 0xFFFF0000)
assert(x3, 0xFFFF0004)
j pass
test14:
li TEST_ID,14
la x1, test14_data
li x2, 0xFFFF000C
amomaxu.w x3,x2,(x1)
lw x4, 0(x1)
assert(x4, 0xFFFF000C)
assert(x3, 0xFFFF0005)
j pass
fail:
li x2, 0xF00FFF24
sw TEST_ID, 0(x2)
pass:
li x2, 0xF00FFF20
sw x0, 0(x2)
nop
nop
nop
nop
nop
nop
test1_data: .word 11
test2_data: .word 22
test3_data: .word 73
test4_data: .word 58
test5_data: .word 56
test6_data: .word 75
test7_data: .word 56
test8_data: .word 83
test9_data: .word 33
test10_data: .word -65
test11_data: .word -87
test12_data: .word -55
test13_data: .word 0xFFFF0004
test14_data: .word 0xFFFF0005

View file

@ -0,0 +1,16 @@
OUTPUT_ARCH( "riscv" )
MEMORY {
onChipRam (W!RX)/*(RX)*/ : ORIGIN = 0x80000000, LENGTH = 128K
}
SECTIONS
{
.crt_section :
{
. = ALIGN(4);
*crt.o(.text)
} > onChipRam
}

View file

@ -0,0 +1,86 @@
RISCV_PATH?=/opt/riscv/
RISCV_NAME = riscv64-unknown-elf
RISCV_OBJCOPY = $(RISCV_PATH)/bin/$(RISCV_NAME)-objcopy
RISCV_OBJDUMP = $(RISCV_PATH)/bin/$(RISCV_NAME)-objdump
RISCV_CLIB=$(RISCV_PATH)$(RISCV_NAME)/lib/
RISCV_CC=$(RISCV_PATH)/bin/$(RISCV_NAME)-gcc
LDSCRIPT=src/ld
MABI=ilp32
MARCH := rv32i
ifeq ($(MULDIV),yes)
MARCH := $(MARCH)m
endif
ifeq ($(ATOMIC),yes)
MARCH := $(MARCH)a
endif
ifeq ($(COMPRESSED),yes)
MARCH := $(MARCH)c
endif
CFLAGS += -march=$(MARCH) -mabi=$(MABI)
LDFLAGS += -march=$(MARCH) -mabi=$(MABI)
SRCS = $(wildcard src/*.c) \
$(wildcard src/*.cpp) \
$(wildcard src/*.S)
CFLAGS += -static
LDFLAGS += -e_start -T $(LDSCRIPT) -nostartfiles -Wl,-Map,$(OBJDIR)/$(PROJ_NAME).map -Wl,--print-memory-usage
OBJDIR = build
OBJS := $(SRCS)
OBJS := $(OBJS:.c=.o)
OBJS := $(OBJS:.cpp=.o)
OBJS := $(OBJS:.S=.o)
OBJS := $(addprefix $(OBJDIR)/,$(OBJS))
all: $(OBJDIR)/$(PROJ_NAME).elf $(OBJDIR)/$(PROJ_NAME).hex $(OBJDIR)/$(PROJ_NAME).asm
@echo "done"
$(OBJDIR)/%.elf: $(OBJS) | $(OBJDIR)
$(RISCV_CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LIBS)
%.hex: %.elf
$(RISCV_OBJCOPY) -O ihex $^ $@
%.bin: %.elf
$(RISCV_OBJCOPY) -O binary $^ $@
%.v: %.elf
$(RISCV_OBJCOPY) -O verilog $^ $@
%.asm: %.elf
$(RISCV_OBJDUMP) -S -d $^ > $@
$(OBJDIR)/%.o: %.c
mkdir -p $(dir $@)
$(RISCV_CC) -c $(CFLAGS) $(INC) -o $@ $^
$(OBJDIR)/%.o: %.cpp
mkdir -p $(dir $@)
$(RISCV_CC) -c $(CFLAGS) $(INC) -o $@ $^
$(OBJDIR)/%.o: %.S
mkdir -p $(dir $@)
$(RISCV_CC) -c $(CFLAGS) -o $@ $^ -D__ASSEMBLY__=1
$(OBJDIR):
mkdir -p $@
clean:
rm -f $(OBJDIR)/$(PROJ_NAME).elf
rm -f $(OBJDIR)/$(PROJ_NAME).hex
rm -f $(OBJDIR)/$(PROJ_NAME).map
rm -f $(OBJDIR)/$(PROJ_NAME).v
rm -f $(OBJDIR)/$(PROJ_NAME).asm
find $(OBJDIR) -type f -name '*.o' -print0 | xargs -0 -r rm
.SECONDARY: $(OBJS)

4
src/test/cpp/raw/dcache/.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
*.map
*.v
*.elf
*.o

View file

@ -0,0 +1,78 @@
build/dcache.elf: file format elf32-littleriscv
Disassembly of section .crt_section:
80000000 <_start>:
80000000: 00000097 auipc ra,0x0
80000004: 0b408093 addi ra,ra,180 # 800000b4 <fail>
80000008 <test1>:
80000008: 00100e13 li t3,1
8000000c: 00100093 li ra,1
80000010: 00300113 li sp,3
80000014: 00208093 addi ra,ra,2
80000018: 08209e63 bne ra,sp,800000b4 <fail>
8000001c <test2>:
8000001c: 00200e13 li t3,2
80000020: f56700b7 lui ra,0xf5670
80000024: 900ff137 lui sp,0x900ff
80000028: 40000313 li t1,1024
8000002c <test2_repeat>:
8000002c: 00100193 li gp,1
80000030: 00200293 li t0,2
80000034: 006303b3 add t2,t1,t1
80000038: 007181b3 add gp,gp,t2
8000003c: 007282b3 add t0,t0,t2
80000040: 00312023 sw gp,0(sp) # 900ff000 <pass+0x100fef40>
80000044: 0000a023 sw zero,0(ra) # f5670000 <pass+0x7566ff40>
80000048: 00012203 lw tp,0(sp)
8000004c: 06429463 bne t0,tp,800000b4 <fail>
80000050: ffc30313 addi t1,t1,-4
80000054: 01008093 addi ra,ra,16
80000058: 01010113 addi sp,sp,16
8000005c: 0000500f 0x500f
80000060: fc0316e3 bnez t1,8000002c <test2_repeat>
80000064 <test3>:
80000064: 00300e13 li t3,3
80000068: f56700b7 lui ra,0xf5670
8000006c: 900ff137 lui sp,0x900ff
80000070: 40000313 li t1,1024
80000074 <test3_repeat>:
80000074: 00200193 li gp,2
80000078: 00300293 li t0,3
8000007c: 006303b3 add t2,t1,t1
80000080: 007181b3 add gp,gp,t2
80000084: 007282b3 add t0,t0,t2
80000088: 00012203 lw tp,0(sp) # 900ff000 <pass+0x100fef40>
8000008c: 00312023 sw gp,0(sp)
80000090: 0000a023 sw zero,0(ra) # f5670000 <pass+0x7566ff40>
80000094: 0000500f 0x500f
80000098: 00012203 lw tp,0(sp)
8000009c: 00429c63 bne t0,tp,800000b4 <fail>
800000a0: ffc30313 addi t1,t1,-4
800000a4: 01008093 addi ra,ra,16
800000a8: 01010113 addi sp,sp,16
800000ac: fc0314e3 bnez t1,80000074 <test3_repeat>
800000b0: 0100006f j 800000c0 <pass>
800000b4 <fail>:
800000b4: f0100137 lui sp,0xf0100
800000b8: f2410113 addi sp,sp,-220 # f00fff24 <pass+0x700ffe64>
800000bc: 01c12023 sw t3,0(sp)
800000c0 <pass>:
800000c0: f0100137 lui sp,0xf0100
800000c4: f2010113 addi sp,sp,-224 # f00fff20 <pass+0x700ffe60>
800000c8: 00012023 sw zero,0(sp)
800000cc: 00000013 nop
800000d0: 00000013 nop
800000d4: 00000013 nop
800000d8: 00000013 nop
800000dc: 00000013 nop
800000e0: 00000013 nop

View file

@ -0,0 +1,17 @@
:0200000480007A
:10000000970000009380400B130E10009300100027
:100010001301300093802000639E2008130E2000FF
:10002000B70067F537F10F901303004093011000FC
:1000300093022000B3036300B3817100B3827200A6
:100040002320310023A00000032201006394420614
:100050001303C3FF93800001130101010F5000003F
:10006000E31603FC130E3000B70067F537F10F906D
:10007000130300409301200093023000B303630098
:10008000B3817100B382720003220100232031008A
:1000900023A000000F50000003220100639C4200D7
:1000A0001303C3FF9380000113010101E31403FC58
:1000B0006F000001370110F0130141F22320C1014C
:1000C000370110F0130101F223200100130000009A
:1000D00013000000130000001300000013000000D4
:0400E0001300000009
:00000001FF

View file

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

View file

@ -0,0 +1,75 @@
.globl _star
#define TEST_ID x28
_start:
la x1, fail
//csrw mtvec, x1
test1: //Dummy test
li TEST_ID, 1
li x1, 1
li x2, 3
addi x1, x1, 2
bne x1, x2, fail
test2: //No invalidate, without load => new one
li TEST_ID, 2
li x1, 0xF5670000
li x2, 0x900FF000
li x6, 4096/4
test2_repeat:
la x3, 1
la x5, 2
add x7, x6, x6
add x3, x3, x7
add x5, x5, x7
sw x3, 0(x2)
sw x0, 0(x1)
lw x4, 0(x2)
bne x5,x4, fail
addi x6, x6, -4
addi x1, x1, 16
addi x2, x2, 16
.word 0x000500F // dcache flush
bnez x6, test2_repeat
test3: //with invalidate, with preload
li TEST_ID, 3
li x1, 0xF5670000
li x2, 0x900FF000
li x6, 4096/4
test3_repeat:
la x3, 2
la x5, 3
add x7, x6, x6
add x3, x3, x7
add x5, x5, x7
lw x4, 0(x2)
sw x3, 0(x2)
sw x0, 0(x1)
.word 0x000500F // dcache flush
lw x4, 0(x2)
bne x5,x4, fail
addi x6, x6, -4
addi x1, x1, 16
addi x2, x2, 16
bnez x6, test3_repeat
j pass
fail:
li x2, 0xF00FFF24
sw TEST_ID, 0(x2)
pass:
li x2, 0xF00FFF20
sw x0, 0(x2)
nop
nop
nop
nop
nop
nop

View file

@ -0,0 +1,16 @@
OUTPUT_ARCH( "riscv" )
MEMORY {
onChipRam (W!RX)/*(RX)*/ : ORIGIN = 0x80000000, LENGTH = 128K
}
SECTIONS
{
.crt_section :
{
. = ALIGN(4);
*crt.o(.text)
} > onChipRam
}

4
src/test/cpp/raw/deleg/.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
*.map
*.v
*.elf
*.o

View file

@ -0,0 +1,541 @@
build/deleg.elf: file format elf32-littleriscv
Disassembly of section .crt_section:
80000000 <_start>:
80000000: 00100e93 li t4,1
80000004: 00000097 auipc ra,0x0
80000008: 6fc08093 addi ra,ra,1788 # 80000700 <mtrap>
8000000c: 30509073 csrw mtvec,ra
80000010: 00000097 auipc ra,0x0
80000014: 72808093 addi ra,ra,1832 # 80000738 <strap>
80000018: 10509073 csrw stvec,ra
8000001c: f00110b7 lui ra,0xf0011
80000020: 00000113 li sp,0
80000024: 0020a023 sw sp,0(ra) # f0011000 <strap+0x700108c8>
80000028 <test1>:
80000028: 00100e13 li t3,1
8000002c: 00000f17 auipc t5,0x0
80000030: 00cf0f13 addi t5,t5,12 # 80000038 <test2>
80000034: 00000073 ecall
80000038 <test2>:
80000038: 00200e13 li t3,2
8000003c: 000020b7 lui ra,0x2
80000040: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800>
80000044: 00000113 li sp,0
80000048: 3000b073 csrc mstatus,ra
8000004c: 30012073 csrs mstatus,sp
80000050: 00000097 auipc ra,0x0
80000054: 01408093 addi ra,ra,20 # 80000064 <test2+0x2c>
80000058: 34109073 csrw mepc,ra
8000005c: 30200073 mret
80000060: 6880006f j 800006e8 <fail>
80000064: 00000f17 auipc t5,0x0
80000068: 024f0f13 addi t5,t5,36 # 80000088 <test4>
8000006c: 00000073 ecall
80000070: 6780006f j 800006e8 <fail>
80000074 <test3>:
80000074: 00300e13 li t3,3
80000078: 00000f17 auipc t5,0x0
8000007c: 010f0f13 addi t5,t5,16 # 80000088 <test4>
80000080: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff>
80000084: 6640006f j 800006e8 <fail>
80000088 <test4>:
80000088: 00400e13 li t3,4
8000008c: 000020b7 lui ra,0x2
80000090: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800>
80000094: 00001137 lui sp,0x1
80000098: 80010113 addi sp,sp,-2048 # 800 <_start-0x7ffff800>
8000009c: 3000b073 csrc mstatus,ra
800000a0: 30012073 csrs mstatus,sp
800000a4: 00000097 auipc ra,0x0
800000a8: 01408093 addi ra,ra,20 # 800000b8 <test4+0x30>
800000ac: 34109073 csrw mepc,ra
800000b0: 30200073 mret
800000b4: 6340006f j 800006e8 <fail>
800000b8: 00000f17 auipc t5,0x0
800000bc: 010f0f13 addi t5,t5,16 # 800000c8 <test5>
800000c0: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff>
800000c4: 6240006f j 800006e8 <fail>
800000c8 <test5>:
800000c8: 00500e13 li t3,5
800000cc: 000020b7 lui ra,0x2
800000d0: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800>
800000d4: 00000113 li sp,0
800000d8: 3000b073 csrc mstatus,ra
800000dc: 30012073 csrs mstatus,sp
800000e0: 00000097 auipc ra,0x0
800000e4: 01408093 addi ra,ra,20 # 800000f4 <test5+0x2c>
800000e8: 34109073 csrw mepc,ra
800000ec: 30200073 mret
800000f0: 5f80006f j 800006e8 <fail>
800000f4: 00000f17 auipc t5,0x0
800000f8: 010f0f13 addi t5,t5,16 # 80000104 <test6>
800000fc: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff>
80000100: 5e80006f j 800006e8 <fail>
80000104 <test6>:
80000104: 00600e13 li t3,6
80000108: 01000093 li ra,16
8000010c: 30209073 csrw medeleg,ra
80000110 <test7>:
80000110: 00700e13 li t3,7
80000114: 00000f17 auipc t5,0x0
80000118: 010f0f13 addi t5,t5,16 # 80000124 <test8>
8000011c: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff>
80000120: 5c80006f j 800006e8 <fail>
80000124 <test8>:
80000124: 00800e13 li t3,8
80000128: 00000f17 auipc t5,0x0
8000012c: 03cf0f13 addi t5,t5,60 # 80000164 <test9>
80000130: 000020b7 lui ra,0x2
80000134: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800>
80000138: 00001137 lui sp,0x1
8000013c: 80010113 addi sp,sp,-2048 # 800 <_start-0x7ffff800>
80000140: 3000b073 csrc mstatus,ra
80000144: 30012073 csrs mstatus,sp
80000148: 00000097 auipc ra,0x0
8000014c: 01408093 addi ra,ra,20 # 8000015c <test8+0x38>
80000150: 34109073 csrw mepc,ra
80000154: 30200073 mret
80000158: 5900006f j 800006e8 <fail>
8000015c: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff>
80000160: 5880006f j 800006e8 <fail>
80000164 <test9>:
80000164: 00900e13 li t3,9
80000168: 00000f17 auipc t5,0x0
8000016c: 038f0f13 addi t5,t5,56 # 800001a0 <test10>
80000170: 000020b7 lui ra,0x2
80000174: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800>
80000178: 00000113 li sp,0
8000017c: 3000b073 csrc mstatus,ra
80000180: 30012073 csrs mstatus,sp
80000184: 00000097 auipc ra,0x0
80000188: 01408093 addi ra,ra,20 # 80000198 <test9+0x34>
8000018c: 34109073 csrw mepc,ra
80000190: 30200073 mret
80000194: 5540006f j 800006e8 <fail>
80000198: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff>
8000019c: 54c0006f j 800006e8 <fail>
800001a0 <test10>:
800001a0: 00a00e13 li t3,10
800001a4: 00000f17 auipc t5,0x0
800001a8: 03cf0f13 addi t5,t5,60 # 800001e0 <test11>
800001ac: f00110b7 lui ra,0xf0011
800001b0: 00000113 li sp,0
800001b4: 0020a023 sw sp,0(ra) # f0011000 <strap+0x700108c8>
800001b8: 00800093 li ra,8
800001bc: 30009073 csrw mstatus,ra
800001c0: 000010b7 lui ra,0x1
800001c4: 80008093 addi ra,ra,-2048 # 800 <_start-0x7ffff800>
800001c8: 30409073 csrw mie,ra
800001cc: f00110b7 lui ra,0xf0011
800001d0: 00100113 li sp,1
800001d4: 0020a023 sw sp,0(ra) # f0011000 <strap+0x700108c8>
800001d8: 10500073 wfi
800001dc: 50c0006f j 800006e8 <fail>
800001e0 <test11>:
800001e0: 00b00e13 li t3,11
800001e4: 00000f17 auipc t5,0x0
800001e8: 068f0f13 addi t5,t5,104 # 8000024c <test12>
800001ec: f00110b7 lui ra,0xf0011
800001f0: 00000113 li sp,0
800001f4: 0020a023 sw sp,0(ra) # f0011000 <strap+0x700108c8>
800001f8: 00800093 li ra,8
800001fc: 30009073 csrw mstatus,ra
80000200: 000010b7 lui ra,0x1
80000204: 80008093 addi ra,ra,-2048 # 800 <_start-0x7ffff800>
80000208: 30409073 csrw mie,ra
8000020c: 000020b7 lui ra,0x2
80000210: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800>
80000214: 00001137 lui sp,0x1
80000218: 80010113 addi sp,sp,-2048 # 800 <_start-0x7ffff800>
8000021c: 3000b073 csrc mstatus,ra
80000220: 30012073 csrs mstatus,sp
80000224: 00000097 auipc ra,0x0
80000228: 01408093 addi ra,ra,20 # 80000238 <test11+0x58>
8000022c: 34109073 csrw mepc,ra
80000230: 30200073 mret
80000234: 4b40006f j 800006e8 <fail>
80000238: f00110b7 lui ra,0xf0011
8000023c: 00100113 li sp,1
80000240: 0020a023 sw sp,0(ra) # f0011000 <strap+0x700108c8>
80000244: 10500073 wfi
80000248: 4a00006f j 800006e8 <fail>
8000024c <test12>:
8000024c: 00c00e13 li t3,12
80000250: 00000f17 auipc t5,0x0
80000254: 064f0f13 addi t5,t5,100 # 800002b4 <test14>
80000258: f00110b7 lui ra,0xf0011
8000025c: 00000113 li sp,0
80000260: 0020a023 sw sp,0(ra) # f0011000 <strap+0x700108c8>
80000264: 00800093 li ra,8
80000268: 30009073 csrw mstatus,ra
8000026c: 000010b7 lui ra,0x1
80000270: 80008093 addi ra,ra,-2048 # 800 <_start-0x7ffff800>
80000274: 30409073 csrw mie,ra
80000278: 000020b7 lui ra,0x2
8000027c: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800>
80000280: 00000113 li sp,0
80000284: 3000b073 csrc mstatus,ra
80000288: 30012073 csrs mstatus,sp
8000028c: 00000097 auipc ra,0x0
80000290: 01408093 addi ra,ra,20 # 800002a0 <test12+0x54>
80000294: 34109073 csrw mepc,ra
80000298: 30200073 mret
8000029c: 44c0006f j 800006e8 <fail>
800002a0: f00110b7 lui ra,0xf0011
800002a4: 00100113 li sp,1
800002a8: 0020a023 sw sp,0(ra) # f0011000 <strap+0x700108c8>
800002ac: 10500073 wfi
800002b0: 4380006f j 800006e8 <fail>
800002b4 <test14>:
800002b4: 00200093 li ra,2
800002b8: 10009073 csrw sstatus,ra
800002bc: 00e00e13 li t3,14
800002c0: 00000f17 auipc t5,0x0
800002c4: 040f0f13 addi t5,t5,64 # 80000300 <test15>
800002c8: f00120b7 lui ra,0xf0012
800002cc: 00000113 li sp,0
800002d0: 0020a023 sw sp,0(ra) # f0012000 <strap+0x700118c8>
800002d4: 00200093 li ra,2
800002d8: 30009073 csrw mstatus,ra
800002dc: 20000093 li ra,512
800002e0: 30409073 csrw mie,ra
800002e4: 00000e93 li t4,0
800002e8: f00120b7 lui ra,0xf0012
800002ec: 00100113 li sp,1
800002f0: 0020a023 sw sp,0(ra) # f0012000 <strap+0x700118c8>
800002f4: 06400093 li ra,100
800002f8: fff08093 addi ra,ra,-1
800002fc: fe104ee3 bgtz ra,800002f8 <test14+0x44>
80000300 <test15>:
80000300: 00f00e13 li t3,15
80000304: 00000f17 auipc t5,0x0
80000308: 068f0f13 addi t5,t5,104 # 8000036c <test16>
8000030c: f00120b7 lui ra,0xf0012
80000310: 00000113 li sp,0
80000314: 0020a023 sw sp,0(ra) # f0012000 <strap+0x700118c8>
80000318: 00200093 li ra,2
8000031c: 30009073 csrw mstatus,ra
80000320: 20000093 li ra,512
80000324: 30409073 csrw mie,ra
80000328: 000020b7 lui ra,0x2
8000032c: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800>
80000330: 00001137 lui sp,0x1
80000334: 80010113 addi sp,sp,-2048 # 800 <_start-0x7ffff800>
80000338: 3000b073 csrc mstatus,ra
8000033c: 30012073 csrs mstatus,sp
80000340: 00000097 auipc ra,0x0
80000344: 01408093 addi ra,ra,20 # 80000354 <test15+0x54>
80000348: 34109073 csrw mepc,ra
8000034c: 30200073 mret
80000350: 3980006f j 800006e8 <fail>
80000354: 00100e93 li t4,1
80000358: f00120b7 lui ra,0xf0012
8000035c: 00100113 li sp,1
80000360: 0020a023 sw sp,0(ra) # f0012000 <strap+0x700118c8>
80000364: 10500073 wfi
80000368: 3800006f j 800006e8 <fail>
8000036c <test16>:
8000036c: 01000e13 li t3,16
80000370: 00000f17 auipc t5,0x0
80000374: 060f0f13 addi t5,t5,96 # 800003d0 <test17>
80000378: f00120b7 lui ra,0xf0012
8000037c: 00000113 li sp,0
80000380: 0020a023 sw sp,0(ra) # f0012000 <strap+0x700118c8>
80000384: 00200093 li ra,2
80000388: 30009073 csrw mstatus,ra
8000038c: 20000093 li ra,512
80000390: 30409073 csrw mie,ra
80000394: 000020b7 lui ra,0x2
80000398: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800>
8000039c: 00000113 li sp,0
800003a0: 3000b073 csrc mstatus,ra
800003a4: 30012073 csrs mstatus,sp
800003a8: 00000097 auipc ra,0x0
800003ac: 01408093 addi ra,ra,20 # 800003bc <test16+0x50>
800003b0: 34109073 csrw mepc,ra
800003b4: 30200073 mret
800003b8: 3300006f j 800006e8 <fail>
800003bc: f00120b7 lui ra,0xf0012
800003c0: 00100113 li sp,1
800003c4: 0020a023 sw sp,0(ra) # f0012000 <strap+0x700118c8>
800003c8: 10500073 wfi
800003cc: 31c0006f j 800006e8 <fail>
800003d0 <test17>:
800003d0: 01100e13 li t3,17
800003d4: 20000093 li ra,512
800003d8: 30309073 csrw mideleg,ra
800003dc: 00000f17 auipc t5,0x0
800003e0: 040f0f13 addi t5,t5,64 # 8000041c <test18>
800003e4: f00120b7 lui ra,0xf0012
800003e8: 00000113 li sp,0
800003ec: 0020a023 sw sp,0(ra) # f0012000 <strap+0x700118c8>
800003f0: 00200093 li ra,2
800003f4: 30009073 csrw mstatus,ra
800003f8: 20000093 li ra,512
800003fc: 30409073 csrw mie,ra
80000400: 00000e93 li t4,0
80000404: f00120b7 lui ra,0xf0012
80000408: 00100113 li sp,1
8000040c: 0020a023 sw sp,0(ra) # f0012000 <strap+0x700118c8>
80000410: 06400093 li ra,100
80000414: fff08093 addi ra,ra,-1
80000418: fe104ee3 bgtz ra,80000414 <test17+0x44>
8000041c <test18>:
8000041c: 01200e13 li t3,18
80000420: 00000f17 auipc t5,0x0
80000424: 068f0f13 addi t5,t5,104 # 80000488 <test19>
80000428: f00120b7 lui ra,0xf0012
8000042c: 00000113 li sp,0
80000430: 0020a023 sw sp,0(ra) # f0012000 <strap+0x700118c8>
80000434: 00200093 li ra,2
80000438: 30009073 csrw mstatus,ra
8000043c: 20000093 li ra,512
80000440: 30409073 csrw mie,ra
80000444: 000020b7 lui ra,0x2
80000448: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800>
8000044c: 00001137 lui sp,0x1
80000450: 80010113 addi sp,sp,-2048 # 800 <_start-0x7ffff800>
80000454: 3000b073 csrc mstatus,ra
80000458: 30012073 csrs mstatus,sp
8000045c: 00000097 auipc ra,0x0
80000460: 01408093 addi ra,ra,20 # 80000470 <test18+0x54>
80000464: 34109073 csrw mepc,ra
80000468: 30200073 mret
8000046c: 27c0006f j 800006e8 <fail>
80000470: 00100e93 li t4,1
80000474: f00120b7 lui ra,0xf0012
80000478: 00100113 li sp,1
8000047c: 0020a023 sw sp,0(ra) # f0012000 <strap+0x700118c8>
80000480: 10500073 wfi
80000484: 2640006f j 800006e8 <fail>
80000488 <test19>:
80000488: 01300e13 li t3,19
8000048c: 00000f17 auipc t5,0x0
80000490: 060f0f13 addi t5,t5,96 # 800004ec <test20>
80000494: f00120b7 lui ra,0xf0012
80000498: 00000113 li sp,0
8000049c: 0020a023 sw sp,0(ra) # f0012000 <strap+0x700118c8>
800004a0: 00200093 li ra,2
800004a4: 30009073 csrw mstatus,ra
800004a8: 20000093 li ra,512
800004ac: 30409073 csrw mie,ra
800004b0: 000020b7 lui ra,0x2
800004b4: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800>
800004b8: 00000113 li sp,0
800004bc: 3000b073 csrc mstatus,ra
800004c0: 30012073 csrs mstatus,sp
800004c4: 00000097 auipc ra,0x0
800004c8: 01408093 addi ra,ra,20 # 800004d8 <test19+0x50>
800004cc: 34109073 csrw mepc,ra
800004d0: 30200073 mret
800004d4: 2140006f j 800006e8 <fail>
800004d8: f00120b7 lui ra,0xf0012
800004dc: 00100113 li sp,1
800004e0: 0020a023 sw sp,0(ra) # f0012000 <strap+0x700118c8>
800004e4: 10500073 wfi
800004e8: 2000006f j 800006e8 <fail>
800004ec <test20>:
800004ec: f00120b7 lui ra,0xf0012
800004f0: 00000113 li sp,0
800004f4: 0020a023 sw sp,0(ra) # f0012000 <strap+0x700118c8>
800004f8: 01400e13 li t3,20
800004fc: 00000f17 auipc t5,0x0
80000500: 030f0f13 addi t5,t5,48 # 8000052c <test21>
80000504: 00200093 li ra,2
80000508: 30009073 csrw mstatus,ra
8000050c: 20000093 li ra,512
80000510: 30409073 csrw mie,ra
80000514: 00000e93 li t4,0
80000518: 20000093 li ra,512
8000051c: 1440a073 csrs sip,ra
80000520: 06400093 li ra,100
80000524: fff08093 addi ra,ra,-1
80000528: fe104ee3 bgtz ra,80000524 <test20+0x38>
8000052c <test21>:
8000052c: 01500e13 li t3,21
80000530: 00000f17 auipc t5,0x0
80000534: 060f0f13 addi t5,t5,96 # 80000590 <test22>
80000538: 20000093 li ra,512
8000053c: 1440b073 csrc sip,ra
80000540: 00200093 li ra,2
80000544: 30009073 csrw mstatus,ra
80000548: 20000093 li ra,512
8000054c: 30409073 csrw mie,ra
80000550: 000020b7 lui ra,0x2
80000554: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800>
80000558: 00001137 lui sp,0x1
8000055c: 80010113 addi sp,sp,-2048 # 800 <_start-0x7ffff800>
80000560: 3000b073 csrc mstatus,ra
80000564: 30012073 csrs mstatus,sp
80000568: 00000097 auipc ra,0x0
8000056c: 01408093 addi ra,ra,20 # 8000057c <test21+0x50>
80000570: 34109073 csrw mepc,ra
80000574: 30200073 mret
80000578: 1700006f j 800006e8 <fail>
8000057c: 00100e93 li t4,1
80000580: 20000093 li ra,512
80000584: 1440a073 csrs sip,ra
80000588: 10500073 wfi
8000058c: 15c0006f j 800006e8 <fail>
80000590 <test22>:
80000590: 01600e13 li t3,22
80000594: 00000f17 auipc t5,0x0
80000598: 058f0f13 addi t5,t5,88 # 800005ec <test23>
8000059c: 20000093 li ra,512
800005a0: 1440b073 csrc sip,ra
800005a4: 00200093 li ra,2
800005a8: 30009073 csrw mstatus,ra
800005ac: 20000093 li ra,512
800005b0: 30409073 csrw mie,ra
800005b4: 20000093 li ra,512
800005b8: 1440a073 csrs sip,ra
800005bc: 000020b7 lui ra,0x2
800005c0: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800>
800005c4: 00000113 li sp,0
800005c8: 3000b073 csrc mstatus,ra
800005cc: 30012073 csrs mstatus,sp
800005d0: 00000097 auipc ra,0x0
800005d4: 01408093 addi ra,ra,20 # 800005e4 <test22+0x54>
800005d8: 34109073 csrw mepc,ra
800005dc: 30200073 mret
800005e0: 1080006f j 800006e8 <fail>
800005e4: 10500073 wfi
800005e8: 1000006f j 800006e8 <fail>
800005ec <test23>:
800005ec: 01700e13 li t3,23
800005f0: 00000e93 li t4,0
800005f4: f00120b7 lui ra,0xf0012
800005f8: 00000113 li sp,0
800005fc: 0020a023 sw sp,0(ra) # f0012000 <strap+0x700118c8>
80000600: 20000093 li ra,512
80000604: 1440b073 csrc sip,ra
80000608: 344021f3 csrr gp,mip
8000060c: f00120b7 lui ra,0xf0012
80000610: 00100113 li sp,1
80000614: 0020a023 sw sp,0(ra) # f0012000 <strap+0x700118c8>
80000618: 20000093 li ra,512
8000061c: 1440b073 csrc sip,ra
80000620: 344021f3 csrr gp,mip
80000624: f00120b7 lui ra,0xf0012
80000628: 00000113 li sp,0
8000062c: 0020a023 sw sp,0(ra) # f0012000 <strap+0x700118c8>
80000630: 20000093 li ra,512
80000634: 1440b073 csrc sip,ra
80000638: 344021f3 csrr gp,mip
8000063c: f00120b7 lui ra,0xf0012
80000640: 00000113 li sp,0
80000644: 0020a023 sw sp,0(ra) # f0012000 <strap+0x700118c8>
80000648: 20000093 li ra,512
8000064c: 1440a073 csrs sip,ra
80000650: 344021f3 csrr gp,mip
80000654: f00120b7 lui ra,0xf0012
80000658: 00100113 li sp,1
8000065c: 0020a023 sw sp,0(ra) # f0012000 <strap+0x700118c8>
80000660: 20000093 li ra,512
80000664: 1440a073 csrs sip,ra
80000668: 344021f3 csrr gp,mip
8000066c: f00120b7 lui ra,0xf0012
80000670: 00000113 li sp,0
80000674: 0020a023 sw sp,0(ra) # f0012000 <strap+0x700118c8>
80000678 <test24>:
80000678: 01800e13 li t3,24
8000067c: 00200093 li ra,2
80000680: 3040a073 csrs mie,ra
80000684: 3440a073 csrs mip,ra
80000688: 3000a073 csrs mstatus,ra
8000068c: 00100e93 li t4,1
80000690: 00000f17 auipc t5,0x0
80000694: 03cf0f13 addi t5,t5,60 # 800006cc <test25>
80000698: 000020b7 lui ra,0x2
8000069c: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800>
800006a0: 00001137 lui sp,0x1
800006a4: 80010113 addi sp,sp,-2048 # 800 <_start-0x7ffff800>
800006a8: 3000b073 csrc mstatus,ra
800006ac: 30012073 csrs mstatus,sp
800006b0: 00000097 auipc ra,0x0
800006b4: 01408093 addi ra,ra,20 # 800006c4 <test24_s>
800006b8: 34109073 csrw mepc,ra
800006bc: 30200073 mret
800006c0: 0280006f j 800006e8 <fail>
800006c4 <test24_s>:
800006c4: 10500073 wfi
800006c8: 0200006f j 800006e8 <fail>
800006cc <test25>:
800006cc: 01900e13 li t3,25
800006d0: 00000f17 auipc t5,0x0
800006d4: 014f0f13 addi t5,t5,20 # 800006e4 <test26>
800006d8: 30046073 csrsi mstatus,8
800006dc: 10500073 wfi
800006e0: 0080006f j 800006e8 <fail>
800006e4 <test26>:
800006e4: 0100006f j 800006f4 <pass>
800006e8 <fail>:
800006e8: f0100137 lui sp,0xf0100
800006ec: f2410113 addi sp,sp,-220 # f00fff24 <strap+0x700ff7ec>
800006f0: 01c12023 sw t3,0(sp)
800006f4 <pass>:
800006f4: f0100137 lui sp,0xf0100
800006f8: f2010113 addi sp,sp,-224 # f00fff20 <strap+0x700ff7e8>
800006fc: 00012023 sw zero,0(sp)
80000700 <mtrap>:
80000700: fe0e84e3 beqz t4,800006e8 <fail>
80000704: 342020f3 csrr ra,mcause
80000708: 341020f3 csrr ra,mepc
8000070c: 300020f3 csrr ra,mstatus
80000710: 343020f3 csrr ra,mtval
80000714: 08000093 li ra,128
80000718: 3000b073 csrc mstatus,ra
8000071c: 00200093 li ra,2
80000720: fc1e8ae3 beq t4,ra,800006f4 <pass>
80000724: 000020b7 lui ra,0x2
80000728: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800>
8000072c: 3000a073 csrs mstatus,ra
80000730: 341f1073 csrw mepc,t5
80000734: 30200073 mret
80000738 <strap>:
80000738: fa0e88e3 beqz t4,800006e8 <fail>
8000073c: 142020f3 csrr ra,scause
80000740: 141020f3 csrr ra,sepc
80000744: 100020f3 csrr ra,sstatus
80000748: 143020f3 csrr ra,stval
8000074c: 00000073 ecall
80000750: 00000013 nop
80000754: 00000013 nop
80000758: 00000013 nop
8000075c: 00000013 nop
80000760: 00000013 nop
80000764: 00000013 nop

View file

@ -0,0 +1,122 @@
: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
:040000058000000077
:00000001FF

View file

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

View file

@ -0,0 +1,382 @@
.globl _start
#define TEST_ID x28
#define TRAP_OK x29
#define TRAP_RET x30
#include "encoding.h"
#define externalInterrupt(value) \
li x1, 0xF0011000; \
li x2, value; \
sw x2, 0(x1); \
#define externalInterruptS(value) \
li x1, 0xF0012000; \
li x2, value; \
sw x2, 0(x1); \
#define delay() \
li x1, 100; \
1: \
addi x1, x1, -1; \
bgt x1, x0, 1b; \
#define setPriv(value) \
li x1, 3 << 11; \
li x2, value << 11; \
csrc mstatus, x1; \
csrs mstatus, x2; \
auipc x1, 0; \
addi x1, x1, 20; \
csrw mepc, x1; \
mret; \
j fail; \
ROM_SUPER_0:
_start:
li TRAP_OK, 1
la x1, mtrap
csrw mtvec, x1
la x1, strap
csrw stvec, x1
externalInterrupt(0);
test1:
li TEST_ID, 1
la TRAP_RET, test2
ecall
test2: //simple ecall from user to machine
li TEST_ID, 2
setPriv(0)
la TRAP_RET, test4
ecall
j fail
test3: //M mialigned load exception without deleg
li TEST_ID, 3
la TRAP_RET, test4
lw x1, 1(x0)
j fail
test4: //S mialigned load exception without deleg
li TEST_ID, 4
setPriv(1)
la TRAP_RET, test5
lw x1, 1(x0)
j fail
test5: //U mialigned load exception without deleg
li TEST_ID, 5
setPriv(0)
la TRAP_RET, test6
lw x1, 1(x0)
j fail
test6: // set medeleg
li TEST_ID, 6
li x1, 1 << CAUSE_MISALIGNED_LOAD
csrw medeleg, x1
test7: //machine mode exception
li TEST_ID, 7
la TRAP_RET, test8
lw x1, 1(x0)
j fail
test8: //supervisor mode exception
li TEST_ID, 8
la TRAP_RET, test9
setPriv(1)
lw x1, 1(x0)
j fail
test9: //user mode exception
li TEST_ID, 9
la TRAP_RET, test10
setPriv(0)
lw x1, 1(x0)
j fail
test10: //M external interrupt
li TEST_ID, 10
la TRAP_RET, test11
externalInterrupt(0)
li x1, MSTATUS_MIE
csrw mstatus, x1
li x1, 1 << 11
csrw mie, x1
externalInterrupt(1)
wfi
j fail
test11: //S external interrupt
li TEST_ID, 11
la TRAP_RET, test12
externalInterrupt(0)
li x1, MSTATUS_MIE
csrw mstatus, x1
li x1, 1 << 11
csrw mie, x1
setPriv(1)
externalInterrupt(1)
wfi
j fail
test12: //U external interrupt
li TEST_ID, 12
la TRAP_RET, test14
externalInterrupt(0)
li x1, MSTATUS_MIE
csrw mstatus, x1
li x1, 1 << 11
csrw mie, x1
setPriv(0)
externalInterrupt(1)
wfi
j fail
test14: //M external interrupt S
li x1, MSTATUS_SIE
csrw sstatus, x1
li TEST_ID, 14
la TRAP_RET, test15
externalInterruptS(0)
li x1, MSTATUS_SIE
csrw mstatus, x1
li x1, 1 << 9
csrw mie, x1
li TRAP_OK, 0
externalInterruptS(1)
delay()
test15: //S external interrupt S
li TEST_ID, 15
la TRAP_RET, test16
externalInterruptS(0)
li x1, SSTATUS_SIE
csrw mstatus, x1
li x1, 1 << 9
csrw mie, x1
setPriv(1)
li TRAP_OK, 1
externalInterruptS(1)
wfi
j fail
test16: //U external interrupt S
li TEST_ID, 16
la TRAP_RET, test17
externalInterruptS(0)
li x1, SSTATUS_SIE
csrw mstatus, x1
li x1, 1 << 9
csrw mie, x1
setPriv(0)
externalInterruptS(1)
wfi
j fail
test17:// set mideleg
li TEST_ID, 17
li x1, 1 << 9
csrw mideleg, x1
la TRAP_RET, test18
externalInterruptS(0)
li x1, MSTATUS_SIE
csrw mstatus, x1
li x1, 1 << 9
csrw mie, x1
li TRAP_OK, 0
externalInterruptS(1)
delay()
test18: //S external interrupt S with deleg
li TEST_ID, 18
la TRAP_RET, test19
externalInterruptS(0)
li x1, SSTATUS_SIE
csrw mstatus, x1
li x1, 1 << 9
csrw mie, x1
setPriv(1)
li TRAP_OK, 1
externalInterruptS(1)
wfi
j fail
test19: //U external interrupt S with deleg
li TEST_ID, 19
la TRAP_RET, test20
externalInterruptS(0)
li x1, SSTATUS_SIE
csrw mstatus, x1
li x1, 1 << 9
csrw mie, x1
setPriv(0)
externalInterruptS(1)
wfi
j fail
test20:// M external interrupt S by software with deleg
externalInterruptS(0)
li TEST_ID, 20
la TRAP_RET, test21
li x1, MSTATUS_SIE
csrw mstatus, x1
li x1, 1 << 9
csrw mie, x1
li TRAP_OK, 0
li x1, 1 << 9
csrs sip, x1
delay()
test21: //S external interrupt S by software with deleg
li TEST_ID, 21
la TRAP_RET, test22
li x1, 1 << 9
csrc sip, x1
li x1, SSTATUS_SIE
csrw mstatus, x1
li x1, 1 << 9
csrw mie, x1
setPriv(1)
li TRAP_OK, 1
li x1, 1 << 9
csrs sip, x1
wfi
j fail
test22: //U external interrupt S by software with deleg
li TEST_ID, 22
la TRAP_RET, test23
li x1, 1 << 9
csrc sip, x1
li x1, SSTATUS_SIE
csrw mstatus, x1
li x1, 1 << 9
csrw mie, x1
li x1, 1 << 9
csrs sip, x1
setPriv(0)
wfi
j fail
test23: //Test software and hardware setting inettrupt
li TEST_ID, 23
li TRAP_OK, 0
externalInterruptS(0)
li x1, 1 << 9
csrc sip, x1
csrr x3, mip
externalInterruptS(1)
li x1, 1 << 9
csrc sip, x1
csrr x3, mip
externalInterruptS(0)
li x1, 1 << 9
csrc sip, x1
csrr x3, mip
externalInterruptS(0)
li x1, 1 << 9
csrs sip, x1
csrr x3, mip
externalInterruptS(1)
li x1, 1 << 9
csrs sip, x1
csrr x3, mip
externalInterruptS(0)
test24: //test supervisor software interrupt
li TEST_ID, 24
li x1, 2
csrs mie, x1
csrs mip, x1
csrs mstatus, x1
li TRAP_OK, 1
la TRAP_RET, test25
setPriv(1)
test24_s:
wfi
j fail
test25: //test undelegated supervisor interrupt in machine mode (continue test24)
li TEST_ID, 25
la TRAP_RET, test26
csrsi mstatus, 1 << 3 //mie
wfi
j fail
test26:
j pass
fail:
li x2, 0xF00FFF24
sw TEST_ID, 0(x2)
pass:
li x2, 0xF00FFF20
sw x0, 0(x2)
mtrap:
beq TRAP_OK, x0, fail
csrr x1, mcause
csrr x1, mepc
csrr x1, mstatus
csrr x1, mbadaddr
li x1, MSTATUS_MPIE
csrc mstatus, x1
li x1, 2
beq TRAP_OK, x1, pass
li x1, 3 << 11
csrs mstatus, x1
csrw mepc, TRAP_RET
mret
strap:
beq TRAP_OK, x0, fail
csrr x1, scause
csrr x1, sepc
csrr x1, sstatus
csrr x1, sbadaddr
ecall
nop
nop
nop
nop
nop
nop

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,16 @@
OUTPUT_ARCH( "riscv" )
MEMORY {
onChipRam (W!RX)/*(RX)*/ : ORIGIN = 0x80000000, LENGTH = 128K
}
SECTIONS
{
.crt_section :
{
. = ALIGN(4);
*crt.o(.text)
} > onChipRam
}

4
src/test/cpp/raw/icache/.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
*.map
*.v
*.elf
*.o

View file

@ -0,0 +1,51 @@
build/icache.elf: file format elf32-littleriscv
Disassembly of section .crt_section:
80000000 <_start>:
80000000: 00000097 auipc ra,0x0
80000004: 04c08093 addi ra,ra,76 # 8000004c <fail>
80000008 <test1>:
80000008: 00100e13 li t3,1
8000000c: 00100093 li ra,1
80000010: 00300113 li sp,3
80000014: 00208093 addi ra,ra,2
80000018: 02209a63 bne ra,sp,8000004c <fail>
8000001c <test2>:
8000001c: 00200e13 li t3,2
80000020: 01300093 li ra,19
80000024: 00000117 auipc sp,0x0
80000028: 02010113 addi sp,sp,32 # 80000044 <test2_trigger>
8000002c: 0040006f j 80000030 <test2_aligned>
80000030 <test2_aligned>:
80000030: 00112023 sw ra,0(sp)
80000034: 0000100f fence.i
80000038: 00800a13 li s4,8
8000003c: fffa0a13 addi s4,s4,-1
80000040: fe0a1ee3 bnez s4,8000003c <test2_aligned+0xc>
80000044 <test2_trigger>:
80000044: 0080006f j 8000004c <fail>
80000048: 0100006f j 80000058 <pass>
8000004c <fail>:
8000004c: f0100137 lui sp,0xf0100
80000050: f2410113 addi sp,sp,-220 # f00fff24 <pass+0x700ffecc>
80000054: 01c12023 sw t3,0(sp)
80000058 <pass>:
80000058: f0100137 lui sp,0xf0100
8000005c: f2010113 addi sp,sp,-224 # f00fff20 <pass+0x700ffec8>
80000060: 00012023 sw zero,0(sp)
80000064: 00000013 nop
80000068: 00000013 nop
8000006c: 00000013 nop
80000070: 00000013 nop
80000074: 00000013 nop
80000078: 00000013 nop
...

View file

@ -0,0 +1,11 @@
:0200000480007A
:10000000970000009380C004130E100093001000AE
:100010001301300093802000639A2002130E200009
:100020009300300117010000130101026F0040002E
:10003000232011000F100000130A8000130AFAFF9A
:10004000E31E0AFE6F0080006F000001370110F010
:10005000130141F22320C101370110F0130101F215
:100060002320010013000000130000001300000013
:100070001300000013000000130000000000000047
:04008000000000007C
:00000001FF

View file

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

View file

@ -0,0 +1,49 @@
.globl _star
#define TEST_ID x28
#define delay \
li x20, 8; \
1: addi x20, x20, -1; \
bne x20, x0, 1b;
_start:
la x1, fail
// csrw mtvec, x1
test1: //Dummy test
li TEST_ID, 1
li x1, 1
li x2, 3
addi x1, x1, 2
bne x1, x2, fail
test2:
li TEST_ID, 2
li x1, 0x13 //nop
la x2, test2_trigger
j test2_aligned
.align(4)
test2_aligned:
sw x1, 0(x2)
fence.i
delay
test2_trigger:
j fail
j pass
fail:
li x2, 0xF00FFF24
sw TEST_ID, 0(x2)
pass:
li x2, 0xF00FFF20
sw x0, 0(x2)
nop
nop
nop
nop
nop
nop

View file

@ -0,0 +1,16 @@
OUTPUT_ARCH( "riscv" )
MEMORY {
onChipRam (W!RX)/*(RX)*/ : ORIGIN = 0x80000000, LENGTH = 128K
}
SECTIONS
{
.crt_section :
{
. = ALIGN(4);
*crt.o(.text)
} > onChipRam
}

4
src/test/cpp/raw/lrsc/.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
*.map
*.v
*.elf
*.o

View file

@ -0,0 +1,217 @@
build/lrsc.elf: file format elf32-littleriscv
Disassembly of section .crt_section:
80000000 <trap_entry-0x20>:
80000000: 04c0006f j 8000004c <_start>
80000004: 00000013 nop
80000008: 00000013 nop
8000000c: 00000013 nop
80000010: 00000013 nop
80000014: 00000013 nop
80000018: 00000013 nop
8000001c: 00000013 nop
80000020 <trap_entry>:
80000020: 30002ef3 csrr t4,mstatus
80000024: 080efe93 andi t4,t4,128
80000028: 000e8a63 beqz t4,8000003c <notExternalInterrupt>
8000002c: 00002eb7 lui t4,0x2
80000030: 800e8e93 addi t4,t4,-2048 # 1800 <trap_entry-0x7fffe820>
80000034: 300e9073 csrw mstatus,t4
80000038: 30200073 mret
8000003c <notExternalInterrupt>:
8000003c: 34102ef3 csrr t4,mepc
80000040: 004e8e93 addi t4,t4,4
80000044: 341e9073 csrw mepc,t4
80000048: 30200073 mret
8000004c <_start>:
8000004c: 00100e13 li t3,1
80000050: 10000537 lui a0,0x10000
80000054: 06400593 li a1,100
80000058: 06500613 li a2,101
8000005c: 06600693 li a3,102
80000060: 00d52023 sw a3,0(a0) # 10000000 <trap_entry-0x70000020>
80000064: 18b5262f sc.w a2,a1,(a0)
80000068: 00100713 li a4,1
8000006c: 26e61e63 bne a2,a4,800002e8 <fail>
80000070: 00052703 lw a4,0(a0)
80000074: 26e69a63 bne a3,a4,800002e8 <fail>
80000078: 00200e13 li t3,2
8000007c: 10000537 lui a0,0x10000
80000080: 00450513 addi a0,a0,4 # 10000004 <trap_entry-0x7000001c>
80000084: 06700593 li a1,103
80000088: 06800613 li a2,104
8000008c: 06900693 li a3,105
80000090: 00d52023 sw a3,0(a0)
80000094: 18b5262f sc.w a2,a1,(a0)
80000098: 00100713 li a4,1
8000009c: 24e61663 bne a2,a4,800002e8 <fail>
800000a0: 00052703 lw a4,0(a0)
800000a4: 24e69263 bne a3,a4,800002e8 <fail>
800000a8: 00300e13 li t3,3
800000ac: 10000537 lui a0,0x10000
800000b0: 00450513 addi a0,a0,4 # 10000004 <trap_entry-0x7000001c>
800000b4: 06700593 li a1,103
800000b8: 06800613 li a2,104
800000bc: 06900693 li a3,105
800000c0: 18b5262f sc.w a2,a1,(a0)
800000c4: 00100713 li a4,1
800000c8: 22e61063 bne a2,a4,800002e8 <fail>
800000cc: 00052703 lw a4,0(a0)
800000d0: 20e69c63 bne a3,a4,800002e8 <fail>
800000d4: 00400e13 li t3,4
800000d8: 10000537 lui a0,0x10000
800000dc: 00850513 addi a0,a0,8 # 10000008 <trap_entry-0x70000018>
800000e0: 06a00593 li a1,106
800000e4: 06b00613 li a2,107
800000e8: 06c00693 li a3,108
800000ec: 00d52023 sw a3,0(a0)
800000f0: 100527af lr.w a5,(a0)
800000f4: 18b5262f sc.w a2,a1,(a0)
800000f8: 1ed79863 bne a5,a3,800002e8 <fail>
800000fc: 1e061663 bnez a2,800002e8 <fail>
80000100: 00052703 lw a4,0(a0)
80000104: 1ee59263 bne a1,a4,800002e8 <fail>
80000108: 00500e13 li t3,5
8000010c: 10000537 lui a0,0x10000
80000110: 00850513 addi a0,a0,8 # 10000008 <trap_entry-0x70000018>
80000114: 06d00593 li a1,109
80000118: 06e00613 li a2,110
8000011c: 06f00693 li a3,111
80000120: 00d52023 sw a3,0(a0)
80000124: 18b5262f sc.w a2,a1,(a0)
80000128: 1c061063 bnez a2,800002e8 <fail>
8000012c: 00052703 lw a4,0(a0)
80000130: 1ae59c63 bne a1,a4,800002e8 <fail>
80000134: 00600e13 li t3,6
80000138: 10000537 lui a0,0x10000
8000013c: 00c50513 addi a0,a0,12 # 1000000c <trap_entry-0x70000014>
80000140: 07000593 li a1,112
80000144: 07100613 li a2,113
80000148: 07200693 li a3,114
8000014c: 10000437 lui s0,0x10000
80000150: 01040413 addi s0,s0,16 # 10000010 <trap_entry-0x70000010>
80000154: 07300493 li s1,115
80000158: 07400913 li s2,116
8000015c: 07500993 li s3,117
80000160: 00d52023 sw a3,0(a0)
80000164: 01342023 sw s3,0(s0)
80000168: 100527af lr.w a5,(a0)
8000016c: 10042aaf lr.w s5,(s0)
80000170: 18b5262f sc.w a2,a1,(a0)
80000174: 1894292f sc.w s2,s1,(s0)
80000178: 16d79863 bne a5,a3,800002e8 <fail>
8000017c: 16061663 bnez a2,800002e8 <fail>
80000180: 00052703 lw a4,0(a0)
80000184: 16e59263 bne a1,a4,800002e8 <fail>
80000188: 173a9063 bne s5,s3,800002e8 <fail>
8000018c: 14091e63 bnez s2,800002e8 <fail>
80000190: 00042a03 lw s4,0(s0)
80000194: 15449a63 bne s1,s4,800002e8 <fail>
80000198: 00700e13 li t3,7
8000019c: 10000537 lui a0,0x10000
800001a0: 01450513 addi a0,a0,20 # 10000014 <trap_entry-0x7000000c>
800001a4: 07800593 li a1,120
800001a8: 07900613 li a2,121
800001ac: 07a00693 li a3,122
800001b0: 01000e93 li t4,16
800001b4 <test7>:
800001b4: 00d52023 sw a3,0(a0)
800001b8: 100527af lr.w a5,(a0)
800001bc: 18b5262f sc.w a2,a1,(a0)
800001c0: 12d79463 bne a5,a3,800002e8 <fail>
800001c4: 12061263 bnez a2,800002e8 <fail>
800001c8: 00052703 lw a4,0(a0)
800001cc: 10e59e63 bne a1,a4,800002e8 <fail>
800001d0: fffe8e93 addi t4,t4,-1
800001d4: 00450513 addi a0,a0,4
800001d8: 00358593 addi a1,a1,3
800001dc: 00360613 addi a2,a2,3
800001e0: 00368693 addi a3,a3,3
800001e4: fc0e98e3 bnez t4,800001b4 <test7>
800001e8: 00900e13 li t3,9
800001ec: 10000537 lui a0,0x10000
800001f0: 10050513 addi a0,a0,256 # 10000100 <trap_entry-0x6fffff20>
800001f4: 07b00593 li a1,123
800001f8: 07c00613 li a2,124
800001fc: 07d00693 li a3,125
80000200: 00d52023 sw a3,0(a0)
80000204: 100527af lr.w a5,(a0)
80000208: 00000073 ecall
8000020c: 18b5262f sc.w a2,a1,(a0)
80000210: 00100713 li a4,1
80000214: 0ce61a63 bne a2,a4,800002e8 <fail>
80000218: 00052703 lw a4,0(a0)
8000021c: 0ce69663 bne a3,a4,800002e8 <fail>
80000220: 00b00e13 li t3,11
80000224: 10000537 lui a0,0x10000
80000228: 30050513 addi a0,a0,768 # 10000300 <trap_entry-0x6ffffd20>
8000022c: 08200593 li a1,130
80000230: 08300613 li a2,131
80000234: 08400693 li a3,132
80000238: 00d52023 sw a3,0(a0)
8000023c: 00001eb7 lui t4,0x1
80000240: 800e8e93 addi t4,t4,-2048 # 800 <trap_entry-0x7ffff820>
80000244: 304e9073 csrw mie,t4
80000248: 00800e93 li t4,8
8000024c: 100527af lr.w a5,(a0)
80000250: 300e9073 csrw mstatus,t4
80000254: 00000013 nop
80000258: 00000013 nop
8000025c: 00000013 nop
80000260: 00000013 nop
80000264: 00000013 nop
80000268: 00000013 nop
8000026c: 18b5262f sc.w a2,a1,(a0)
80000270: 00100713 li a4,1
80000274: 06e61a63 bne a2,a4,800002e8 <fail>
80000278: 00052703 lw a4,0(a0)
8000027c: 06e69663 bne a3,a4,800002e8 <fail>
80000280: 00c00e13 li t3,12
80000284: 10000537 lui a0,0x10000
80000288: 40050513 addi a0,a0,1024 # 10000400 <trap_entry-0x6ffffc20>
8000028c: 08c00593 li a1,140
80000290: 08d00613 li a2,141
80000294: 08e00693 li a3,142
80000298: 00d52023 sw a3,0(a0)
8000029c: 00001eb7 lui t4,0x1
800002a0: 800e8e93 addi t4,t4,-2048 # 800 <trap_entry-0x7ffff820>
800002a4: 304e9073 csrw mie,t4
800002a8: 00002eb7 lui t4,0x2
800002ac: 808e8e93 addi t4,t4,-2040 # 1808 <trap_entry-0x7fffe818>
800002b0: 100527af lr.w a5,(a0)
800002b4: 300e9073 csrw mstatus,t4
800002b8: 00000013 nop
800002bc: 00000013 nop
800002c0: 00000013 nop
800002c4: 00000013 nop
800002c8: 00000013 nop
800002cc: 00000013 nop
800002d0: 18b5262f sc.w a2,a1,(a0)
800002d4: 00100713 li a4,1
800002d8: 00e61863 bne a2,a4,800002e8 <fail>
800002dc: 00052703 lw a4,0(a0)
800002e0: 00e69463 bne a3,a4,800002e8 <fail>
800002e4: 0100006f j 800002f4 <pass>
800002e8 <fail>:
800002e8: f0100137 lui sp,0xf0100
800002ec: f2410113 addi sp,sp,-220 # f00fff24 <pass+0x700ffc30>
800002f0: 01c12023 sw t3,0(sp)
800002f4 <pass>:
800002f4: f0100137 lui sp,0xf0100
800002f8: f2010113 addi sp,sp,-224 # f00fff20 <pass+0x700ffc2c>
800002fc: 00012023 sw zero,0(sp)
80000300: 00000013 nop
80000304: 00000013 nop
80000308: 00000013 nop
8000030c: 00000013 nop
80000310: 00000013 nop
80000314: 00000013 nop

View file

@ -0,0 +1,53 @@
:0200000480007A
:100000006F00C00413000000130000001300000084
:100010001300000013000000130000001300000094
:10002000F32E003093FE0E08638A0E00B72E0000F8
:10003000938E0E8073900E3073002030F32E1034A8
:10004000938E4E0073901E3473002030130E1000F8
:100050003705001093054006130650069306600608
:100060002320D5002F26B51813071000631EE6269F
:1000700003270500639AE626130E200037050010BB
:100080001305450093057006130680069306900637
:100090002320D5002F26B518130710006316E62479
:1000A000032705006392E624130E30003705001085
:1000B0001305450093057006130680069306900607
:1000C0002F26B518130710006310E622032705003A
:1000D000639CE620130E40003705001013058500D1
:1000E0009305A0061306B0069306C0062320D5008C
:1000F000AF2705102F26B5186398D71E6316061E66
:10010000032705006392E51E130E5000370500100B
:10011000130585009305D0061306E0069306F00646
:100120002320D5002F26B5186310061C03270500D1
:10013000639CE51A130E6000370500101305C50017
:1001400093050007130610079306200737040010D5
:10015000130404019304300713094007930950075F
:100160002320D50023203401AF270510AF2A041027
:100170002F26B5182F2994186398D71663160616DC
:10018000032705006392E51663903A17631E09146E
:10019000032A0400639A4415130E700037050010FB
:1001A0001305450193058007130690079306A007E2
:1001B000930E00012320D500AF2705102F26B51878
:1001C0006394D7126312061203270500639EE5109D
:1001D000938EFEFF13054500938535001306360008
:1001E00093863600E3980EFC130E9000370500103E
:1001F000130505109305B0071306C0079306D00733
:100200002320D500AF270510730000002F26B51856
:1002100013071000631AE60C032705006396E60C2B
:10022000130EB000370500101305053093052008A4
:1002300013063008930640082320D500B71E00009F
:10024000938E0E8073904E30930E8000AF27051072
:1002500073900E3013000000130000001300000024
:100260001300000013000000130000002F26B51833
:1002700013071000631AE606032705006396E606D7
:10028000130EC00037050010130505409305C00884
:100290001306D0089306E0082320D500B71E0000FF
:1002A000938E0E8073904E30B72E0000938E8E800A
:1002B000AF27051073900E301300000013000000EC
:1002C00013000000130000001300000013000000E2
:1002D0002F26B518130710006318E6000327050042
:1002E0006394E6006F000001370110F0130141F242
:1002F0002320C101370110F0130101F22320010076
:1003000013000000130000001300000013000000A1
:080310001300000013000000BF
:040000058000004C2B
:00000001FF

View file

@ -0,0 +1,5 @@
PROJ_NAME=lrsc
ATOMIC=yes
include ../common/asm.mk

View file

@ -0,0 +1,265 @@
.globl _start
j _start
nop
nop
nop
nop
nop
nop
nop
.global trap_entry
trap_entry:
csrr x29, mstatus
and x29, x29, 0x080
beqz x29, notExternalInterrupt
li x29, 0x1800 //000 disable interrupts
csrw mstatus,x29
mret
notExternalInterrupt:
csrr x29, mepc
addi x29, x29, 4
csrw mepc, x29
mret
_start:
//Test 1 SC on unreserved area should fail and not write memory
li x28, 1
li a0, 0x10000000
li a1, 100
li a2, 101
li a3, 102
sw a3, 0(a0)
sc.w a2, a1, (a0)
li a4, 1
bne a2, a4, fail
lw a4, 0(a0)
bne a3, a4, fail
//Test 2 SC on another unreserved area should fail and not write memory
li x28, 2
li a0, 0x10000004
li a1, 103
li a2, 104
li a3, 105
sw a3, 0(a0)
sc.w a2, a1, (a0)
li a4, 1
bne a2, a4, fail
lw a4, 0(a0)
bne a3, a4, fail
//Test 3 retrying SC on unreserved area should fail and not write memory
li x28, 3
li a0, 0x10000004
li a1, 103
li a2, 104
li a3, 105
sc.w a2, a1, (a0)
li a4, 1
bne a2, a4, fail
lw a4, 0(a0)
bne a3, a4, fail
//Test 4 SC on reserved area should pass and should be written write memory
li x28, 4
li a0, 0x10000008
li a1, 106
li a2, 107
li a3, 108
sw a3, 0(a0)
lr.w a5, (a0)
sc.w a2, a1, (a0)
bne a5, a3, fail
bne a2, x0, fail
lw a4, 0(a0)
bne a1, a4, fail
//Test 5 redo SC on reserved area should pass and should be written write memory
li x28, 5
li a0, 0x10000008
li a1, 109
li a2, 110
li a3, 111
sw a3, 0(a0)
sc.w a2, a1, (a0)
bne a2, x0, fail
lw a4, 0(a0)
bne a1, a4, fail
//Test 6 Allow two entries at the same time
li x28, 6
li a0, 0x1000000C
li a1, 112
li a2, 113
li a3, 114
li s0, 0x10000010
li s1, 115
li s2, 116
li s3, 117
sw a3, 0(a0)
sw s3, 0(s0)
lr.w a5, (a0)
lr.w s5, (s0)
sc.w a2, a1, (a0)
sc.w s2, s1, (s0)
bne a5, a3, fail
bne a2, x0, fail
lw a4, 0(a0)
bne a1, a4, fail
bne s5, s3, fail
bne s2, x0, fail
lw s4, 0(s0)
bne s1, s4, fail
//Test 7 do a lot of allocation to clear the entries
li x28, 7
li a0, 0x10000014
li a1, 120
li a2, 121
li a3, 122
li x29, 16
test7:
sw a3, 0(a0)
lr.w a5, (a0)
sc.w a2, a1, (a0)
bne a5, a3, fail
bne a2, x0, fail
lw a4, 0(a0)
bne a1, a4, fail
add x29, x29, -1
add a0, a0, 4
add a1, a1, 3
add a2, a2, 3
add a3, a3, 3
bnez x29, test7
//Test 8 SC on discarded entries should fail
/* li x28, 8
li a0, 0x10000018
li a1, 120
li a2, 121
li a3, 122
lw a5, 0(a0)
sc.w a2, a1, (a0)
li a4, 1
bne a2, a4, fail
lw a4, 0(a0)
bne a5, a4, fail*/
//Test 9 SC should fail after a context switching
li x28, 9
li a0, 0x10000100
li a1, 123
li a2, 124
li a3, 125
sw a3, 0(a0)
lr.w a5, (a0)
scall
sc.w a2, a1, (a0)
li a4, 1
bne a2, a4, fail
lw a4, 0(a0)
bne a3, a4, fail
//Test 10 SC should fail if the address doesn't match
/* li x28, 10
li a0, 0x10000200
li a6, 0x10000204
li a1, 126
li a2, 127
li a3, 128
li a7, 129
sw a3, 0(a0)
sw a7, 0(a6)
lr.w a5, (a6)
sc.w a2, a1, (a0)
li a4, 1
bne a2, a4, fail
lw a4, 0(a6)
bne a7, a4, fail*/
//Test 11 SC should fail after a external interrupt context switching
li x28, 11
li a0, 0x10000300
li a1, 130
li a2, 131
li a3, 132
sw a3, 0(a0)
li x29, 0x800 //800 external interrupts
csrw mie,x29
li x29, 0x008 //008 enable interrupts
lr.w a5, (a0)
csrw mstatus,x29 //Enable external interrupt (will jump instantly due to testbench setup)
nop
nop
nop
nop
nop
nop
sc.w a2, a1, (a0)
li a4, 1
bne a2, a4, fail
lw a4, 0(a0)
bne a3, a4, fail
//Test 12 SC should fail after a external interrupt context switching (callback on lr)
li x28, 12
li a0, 0x10000400
li a1, 140
li a2, 141
li a3, 142
sw a3, 0(a0)
li x29, 0x800 //800 external interrupts
csrw mie,x29
li x29, 0x1808 //008 enable interrupts
lr.w a5, (a0)
csrw mstatus,x29 //Enable external interrupt (will jump instantly due to testbench setup)
nop
nop
nop
nop
nop
nop
sc.w a2, a1, (a0)
li a4, 1
bne a2, a4, fail
lw a4, 0(a0)
bne a3, a4, fail
j pass
fail: //x28 => error code
li x2, 0xF00FFF24
sw x28, 0(x2)
pass:
li x2, 0xF00FFF20
sw x0, 0(x2)
nop
nop
nop
nop
nop
nop

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