mirror of
https://github.com/SpinalHDL/VexRiscv.git
synced 2025-04-23 21:47:06 -04:00
Merge remote-tracking branch 'origin/dev' into dev-asid
This commit is contained in:
commit
72f85ef6c0
119 changed files with 9980 additions and 2685 deletions
328
README.md
328
README.md
|
@ -7,9 +7,9 @@
|
|||
- [CPU generation](#cpu-generation)
|
||||
- [Regression tests](#regression-tests)
|
||||
- [Interactive debug of the simulated CPU via GDB OpenOCD and Verilator](#interactive-debug-of-the-simulated-cpu-via-gdb-openocd-and-verilator)
|
||||
- [Using Eclipse to run the software and debug it](#using-Eclipse-to-run-the-software-and-debug-it)
|
||||
* [By using Zylin plugin](#by-using-zylin-plugin)
|
||||
* [By using FreedomStudio](#by-using-freedomstudio)
|
||||
- [Using Eclipse to run and debug the software](#using-Eclipse-to-run-and-debug-the-software)
|
||||
* [By using gnu-mcu-eclipse](#by-using-gnu-mcu-eclipse)
|
||||
* [By using Zylin plugin (old)](#by-using-zylin-plugin-old)
|
||||
- [Briey SoC](#briey-soc)
|
||||
- [Murax SoC](#murax-soc)
|
||||
- [Running Linux](#running-linux)
|
||||
|
@ -30,14 +30,14 @@ This repository hosts a RISC-V implementation written in SpinalHDL. Here are som
|
|||
- 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, do not use any vendor specific IP block / primitive
|
||||
- Optimized for FPGA, does not use any vendor specific IP block / primitive
|
||||
- AXI4, Avalon, wishbone ready
|
||||
- Optional MUL/DIV extensions
|
||||
- Optional instruction and data caches
|
||||
- Optional hardware refilled MMU
|
||||
- Optional debug extension allowing Eclipse debugging via a GDB >> openOCD >> JTAG connection
|
||||
- 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
|
||||
- Two implementations of shift instructions: single cycle (full barrel shifter) and shiftNumber cycles
|
||||
- Each stage can have optional bypass or interlock hazard logic
|
||||
- Linux compatible (SoC : https://github.com/enjoy-digital/linux-on-litex-vexriscv)
|
||||
- Zephyr compatible
|
||||
|
@ -57,68 +57,67 @@ For commercial support, please contact spinalhdl@gmail.com.
|
|||
|
||||
## Area usage and maximal frequency
|
||||
|
||||
The following numbers were obtained by synthesizing the CPU as toplevel without any specific synthesis options to save area or to get better maximal frequency (neutral).<br>
|
||||
The following numbers were obtained by synthesizing the CPU as toplevel on the fastest speed grade without any specific synthesis options to save area or to get better maximal frequency (neutral).<br>
|
||||
The clock constraint is set to an unattainable value, which tends to increase the design area.<br>
|
||||
The dhrystone benchmark was compiled with the `-O3 -fno-inline` option.<br>
|
||||
All the cached configurations have some cache trashing during the dhrystone benchmark except the `VexRiscv full max perf` one. This of course reduces the performance. It is possible to produce
|
||||
All the cached configurations have some cache trashing during the dhrystone benchmark except the `VexRiscv full max perf` one. This, of course, reduces the performance. It is possible to produce
|
||||
dhrystone binaries which fit inside a 4KB I$ and 4KB D$ (I already had this case once) but currently it isn't the case.<br>
|
||||
The CPU configurations used below can be found in the `src/scala/vexriscv/demo` directory.
|
||||
|
||||
```
|
||||
VexRiscv smallest (RV32I, 0.52 DMIPS/Mhz, no datapath bypass, no interrupt) ->
|
||||
Artix 7 -> 324 Mhz 496 LUT 505 FF
|
||||
Cyclone V -> 193 Mhz 347 ALMs
|
||||
Cyclone IV -> 179 Mhz 730 LUT 494 FF
|
||||
VexRiscv small (RV32I, 0.52 DMIPS/Mhz, no datapath bypass, no interrupt) ->
|
||||
Artix 7 -> 243 Mhz 504 LUT 505 FF
|
||||
Cyclone V -> 174 Mhz 352 ALMs
|
||||
Cyclone IV -> 179 Mhz 731 LUT 494 FF
|
||||
iCE40 -> 92 Mhz 1130 LC
|
||||
|
||||
VexRiscv smallest (RV32I, 0.52 DMIPS/Mhz, no datapath bypass) ->
|
||||
Artix 7 -> 328 Mhz 539 LUT 562 FF
|
||||
Cyclone V -> 189 Mhz 387 ALMs
|
||||
Cyclone IV -> 175 Mhz 829 LUT 550 FF
|
||||
VexRiscv small (RV32I, 0.52 DMIPS/Mhz, no datapath bypass) ->
|
||||
Artix 7 -> 240 Mhz 556 LUT 566 FF
|
||||
Cyclone V -> 194 Mhz 394 ALMs
|
||||
Cyclone IV -> 174 Mhz 831 LUT 555 FF
|
||||
iCE40 -> 85 Mhz 1292 LC
|
||||
|
||||
VexRiscv small and productive (RV32I, 0.82 DMIPS/Mhz) ->
|
||||
Artix 7 -> 324 Mhz 701 LUT 531 FF
|
||||
Cyclone V -> 145 Mhz 499 ALMs
|
||||
Cyclone IV -> 150 Mhz 1,111 LUT 525 FF
|
||||
Artix 7 -> 232 Mhz 816 LUT 534 FF
|
||||
Cyclone V -> 155 Mhz 492 ALMs
|
||||
Cyclone IV -> 155 Mhz 1,111 LUT 530 FF
|
||||
iCE40 -> 63 Mhz 1596 LC
|
||||
|
||||
VexRiscv small and productive with I$ (RV32I, 0.70 DMIPS/Mhz, 4KB-I$) ->
|
||||
Artix 7 -> 336 Mhz 764 LUT 562 FF
|
||||
Cyclone V -> 145 Mhz 511 ALMs
|
||||
Cyclone IV -> 144 Mhz 1,145 LUT 531 FF
|
||||
Artix 7 -> 220 Mhz 730 LUT 570 FF
|
||||
Cyclone V -> 142 Mhz 501 ALMs
|
||||
Cyclone IV -> 150 Mhz 1,139 LUT 536 FF
|
||||
iCE40 -> 66 Mhz 1680 LC
|
||||
|
||||
VexRiscv full no cache (RV32IM, 1.21 DMIPS/Mhz 2.30 Coremark/Mhz, single cycle barrel shifter, debug module, catch exceptions, static branch) ->
|
||||
Artix 7 -> 326 Mhz 1544 LUT 977 FF
|
||||
Cyclone V -> 139 Mhz 958 ALMs
|
||||
Cyclone IV -> 135 Mhz 2,011 LUT 968 FF
|
||||
Artix 7 -> 216 Mhz 1418 LUT 949 FF
|
||||
Cyclone V -> 133 Mhz 933 ALMs
|
||||
Cyclone IV -> 143 Mhz 2,076 LUT 972 FF
|
||||
|
||||
VexRiscv full (RV32IM, 1.21 DMIPS/Mhz 2.30 Coremark/Mhz with cache trashing, 4KB-I$,4KB-D$, single cycle barrel shifter, debug module, catch exceptions, static branch) ->
|
||||
Artix 7 -> 279 Mhz 1686 LUT 1172 FF
|
||||
Cyclone V -> 144 Mhz 1,128 ALMs
|
||||
Cyclone IV -> 133 Mhz 2,298 LUT 1,096 FF
|
||||
Artix 7 -> 199 Mhz 1840 LUT 1158 FF
|
||||
Cyclone V -> 141 Mhz 1,166 ALMs
|
||||
Cyclone IV -> 131 Mhz 2,407 LUT 1,067 FF
|
||||
|
||||
VexRiscv full max dmips/mhz -> (RV32IM, 1.44 DMIPS/Mhz 2.70 Coremark/Mhz,, 16KB-I$,16KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch prediction in the fetch stage, branch and shift operations done in the Execute stage) ->
|
||||
Artix 7 -> 193 Mhz 1758 LUT 1094 FF
|
||||
Cyclone V -> 90 Mhz 1,089 ALMs
|
||||
Cyclone IV -> 79 Mhz 2,336 LUT 1,048 FF
|
||||
VexRiscv full max perf (HZ*IPC) -> (RV32IM, 1.38 DMIPS/Mhz 2.57 Coremark/Mhz, 8KB-I$,8KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch prediction in the fetch stage, branch and shift operations done in the Execute stage) ->
|
||||
Artix 7 -> 200 Mhz 1935 LUT 1216 FF
|
||||
Cyclone V -> 130 Mhz 1,166 ALMs
|
||||
Cyclone IV -> 126 Mhz 2,484 LUT 1,120 FF
|
||||
|
||||
VexRiscv full with MMU (RV32IM, 1.24 DMIPS/Mhz 2.35 Coremark/Mhz, with cache trashing, 4KB-I$, 4KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch, MMU) ->
|
||||
Artix 7 -> 239 Mhz 2029 LUT 1585 FF
|
||||
Cyclone V -> 124 Mhz 1,319 ALMs
|
||||
Cyclone IV -> 122 Mhz 2,710 LUT 1,501 FF
|
||||
Artix 7 -> 151 Mhz 2021 LUT 1541 FF
|
||||
Cyclone V -> 124 Mhz 1,368 ALMs
|
||||
Cyclone IV -> 128 Mhz 2,826 LUT 1,474 FF
|
||||
|
||||
VexRiscv linux balanced (RV32IMA, 1.21 DMIPS/Mhz 2.27 Coremark/Mhz, with cache trashing, 4KB-I$, 4KB-D$, single cycle barrel shifter, catch exceptions, static branch, MMU, Supervisor, Compatible with mainstream linux) ->
|
||||
Artix 7 -> 249 Mhz 2549 LUT 2014 FF
|
||||
Cyclone V -> 125 Mhz 1,618 ALMs
|
||||
Cyclone IV -> 116 Mhz 3,314 LUT 2,016 FF
|
||||
|
||||
Artix 7 -> 180 Mhz 2883 LUT 2130 FF
|
||||
Cyclone V -> 131 Mhz 1,764 ALMs
|
||||
Cyclone IV -> 121 Mhz 3,608 LUT 2,082 FF
|
||||
```
|
||||
|
||||
The following configuration results in 1.44 DMIPS/MHz:
|
||||
|
||||
- 5 stage : F -> D -> E -> M -> WB
|
||||
- 5 stage: F -> D -> E -> M -> WB
|
||||
- single cycle ADD/SUB/Bitwise/Shift ALU
|
||||
- branch/jump done in the E stage
|
||||
- memory load values are bypassed in the WB stage (late result)
|
||||
|
@ -126,11 +125,11 @@ The following configuration results in 1.44 DMIPS/MHz:
|
|||
- single cycle multiplication with bypassing in the WB stage (late result)
|
||||
- dynamic branch prediction done in the F stage with a direct mapped target buffer cache (no penalties on correct predictions)
|
||||
|
||||
Note that recently, the capability to remove the Fetch/Memory/WriteBack stage was added to reduce the area of the CPU, which end up with a smaller CPU and a better DMIPS/Mhz for the small configurations.
|
||||
Note that, recently, the capability to remove the Fetch/Memory/WriteBack stage was added to reduce the area of the CPU, which ends up with a smaller CPU and a better DMIPS/Mhz for the small configurations.
|
||||
|
||||
## Dependencies
|
||||
|
||||
On Ubuntu 14 :
|
||||
On Ubuntu 14:
|
||||
|
||||
```sh
|
||||
# JAVA JDK 8
|
||||
|
@ -146,14 +145,14 @@ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 2EE0EA64E40A89
|
|||
sudo apt-get update
|
||||
sudo apt-get install sbt
|
||||
|
||||
# Verilator (for sim only, realy need 3.9+, in general apt-get will give you 3.8)
|
||||
# Verilator (for sim only, really needs 3.9+, in general apt-get will give you 3.8)
|
||||
sudo apt-get install git make autoconf g++ flex bison
|
||||
git clone http://git.veripool.org/git/verilator # Only first time
|
||||
unsetenv VERILATOR_ROOT # For csh; ignore error if on bash
|
||||
unset VERILATOR_ROOT # For bash
|
||||
cd verilator
|
||||
git pull # Make sure we're up-to-date
|
||||
git checkout verilator_3_918
|
||||
git checkout v3.916
|
||||
autoconf # Create ./configure script
|
||||
./configure
|
||||
make
|
||||
|
@ -162,10 +161,10 @@ sudo make install
|
|||
|
||||
## CPU generation
|
||||
You can find two example CPU instances in:
|
||||
- src/main/scala/vexriscv/demo/GenFull.scala
|
||||
- src/main/scala/vexriscv/demo/GenSmallest.scala
|
||||
- `src/main/scala/vexriscv/demo/GenFull.scala`
|
||||
- `src/main/scala/vexriscv/demo/GenSmallest.scala`
|
||||
|
||||
To generate the corresponding RTL as a VexRiscv.v file, run the following commands in the root directory of this repository:
|
||||
To generate the corresponding RTL as a `VexRiscv.v` file, run the following commands in the root directory of this repository:
|
||||
|
||||
```sh
|
||||
sbt "runMain vexriscv.demo.GenFull"
|
||||
|
@ -186,33 +185,56 @@ NOTES:
|
|||
|
||||
[](https://travis-ci.org/SpinalHDL/VexRiscv)
|
||||
|
||||
To run tests (need the verilator simulator), go in the src/test/cpp/regression folder and run :
|
||||
To run tests (need java, scala, verilator), just do :
|
||||
|
||||
```sh
|
||||
# To test the GenFull CPU
|
||||
# (Don't worry about the CSR test not passing, basicaly the GenFull isn't the truly full version of the CPU, some CSR features are disable in it)
|
||||
make clean run
|
||||
|
||||
# To test the GenSmallest CPU
|
||||
make clean run IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no
|
||||
export VEXRISCV_REGRESSION_SEED=42
|
||||
export VEXRISCV_REGRESSION_TEST_ID=
|
||||
sbt "testOnly vexriscv.TestIndividualFeatures"
|
||||
```
|
||||
|
||||
The self-test includes:
|
||||
- ISA tests from https://github.com/riscv/riscv-tests/tree/master/isa
|
||||
This will generate random VexRiscv configuration and test them with:
|
||||
- ISA tests from https://github.com/riscv/riscv-tests/tree/master/isa and https://github.com/riscv/riscv-compliance
|
||||
- Dhrystone benchmark
|
||||
- 24 FreeRTOS tests
|
||||
- Coremark benchmark
|
||||
- Zephyr os
|
||||
- Buildroot/Linux os
|
||||
- Some handwritten tests to check the CSR, debug module and MMU plugins
|
||||
|
||||
You can enable FreeRTOS tests by adding `FREERTOS=yes` to the command line, but it will take time to run. Also, it uses THREAD_COUNT host CPU threads to run multiple regression in parallel.
|
||||
You can rerun some specific test by setting VEXRISCV_REGRESSION_TEST_ID by their id. For instance, if you want to rerun :
|
||||
- test_id_5_test_IBus_CachedS1024W1BPL32Relaxvexriscv.plugin.DYNAMIC_DBus_CachedS8192W2BPL16_MulDiv_MulDivFpga_Shift_FullLate_Branch_Late_Hazard_BypassAll_RegFile_SyncDR_Src__Csr_AllNoException_Decoder__Debug_None_DBus_NoMmu
|
||||
- test_id_9_test_IBus_Simple1S2InjStagevexriscv.plugin.STATIC_DBus_SimpleLate_MulDiv_MulDivFpgaSimple_Shift_FullEarly_Branch_Late_Hazard_Interlock_RegFile_AsyncER_Src_AddSubExecute_Csr_None_Decoder__Debug_None_DBus_NoMmu
|
||||
|
||||
then :
|
||||
|
||||
```
|
||||
export VEXRISCV_REGRESSION_TEST_ID=5,9
|
||||
```
|
||||
|
||||
Also there is a few environnement variable that you can use to modulate the random generation :
|
||||
|
||||
| Parameters | range | description |
|
||||
| ------------------------------------------- | ------------------ | ----------- |
|
||||
| VEXRISCV_REGRESSION_SEED | Int | Seed used to generate the random configurations |
|
||||
| VEXRISCV_REGRESSION_TEST_ID | \[Int\[,\Int\]\*\] | Random configuration that should be keeped and tested |
|
||||
| VEXRISCV_REGRESSION_CONFIG_COUNT | Int | Number of random configurations |
|
||||
| VEXRISCV_REGRESSION_CONFIG_RVC_RATE | 0.0-1.0 | Chance to generate a RVC config |
|
||||
| VEXRISCV_REGRESSION_CONFIG_LINUX_RATE | 0.0-1.0 | Chance to generate a linux ready config |
|
||||
| VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE | 0.0-1.0 | Chance to generate a machine mode OS ready config |
|
||||
| VEXRISCV_REGRESSION_LINUX_REGRESSION | yes/no | Enable the linux test |
|
||||
| VEXRISCV_REGRESSION_COREMARK | yes/no | Enable the Coremark test |
|
||||
| VEXRISCV_REGRESSION_ZEPHYR_COUNT | Int | Number of zephyr tests to run on capable configs |
|
||||
| VEXRISCV_REGRESSION_CONFIG_DEMW_RATE | 0.0-1.0 | Chance to generate a config with writeback stage |
|
||||
| VEXRISCV_REGRESSION_CONFIG_DEM_RATE | 0.0-1.0 | Chance to generate a config with memory stage |
|
||||
|
||||
## Interactive debug of the simulated CPU via GDB OpenOCD and Verilator
|
||||
It's as described to run tests, but you just have to add `DEBUG_PLUGIN_EXTERNAL=yes` in the make arguments.
|
||||
Work for the GenFull, but not for the GenSmallest as this configuration has no debug module.
|
||||
To use this, you just need to use the same command as with running tests, but adding `DEBUG_PLUGIN_EXTERNAL=yes` in the make arguments.
|
||||
This works for the `GenFull` configuration, but not for `GenSmallest`, as this configuration has no debug module.
|
||||
|
||||
Then you can use the https://github.com/SpinalHDL/openocd_riscv tool to create a GDB server connected to the target (the simulated CPU)
|
||||
Then, you can use the [OpenOCD RISC-V](https://github.com/SpinalHDL/openocd_riscv) tool to create a GDB server connected to the target (the simulated CPU), as follows:
|
||||
|
||||
```sh
|
||||
#in the VexRiscv repository, to run the simulation on which one OpenOCD can connect itself =>
|
||||
#In the VexRiscv repository, to run the simulation on which one OpenOCD can connect itself =>
|
||||
sbt "runMain vexriscv.demo.GenFull"
|
||||
cd src/test/cpp/regression
|
||||
make run DEBUG_PLUGIN_EXTERNAL=yes
|
||||
|
@ -230,17 +252,17 @@ continue
|
|||
# Now it should print messages in the Verilator simulation of the CPU
|
||||
```
|
||||
|
||||
## Using Eclipse to run the software and debug it
|
||||
## Using Eclipse to run and debug the software
|
||||
|
||||
### By using gnu-mcu-eclipse
|
||||
|
||||
You can download releases of the IDE here : https://github.com/gnu-mcu-eclipse/org.eclipse.epp.packages/releases
|
||||
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 :
|
||||
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")
|
||||
- Select the folder which contains the makefile, then select "Cross GCC" (not "RISC-V Cross GCC")
|
||||
|
||||
To create a new debug configuration :
|
||||
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
|
||||
|
||||
|
@ -257,13 +279,13 @@ cd eclipse
|
|||
|
||||
See https://drive.google.com/drive/folders/1NseNHH05B6lmIXqQFVwK8xRjWE4ydeG-?usp=sharing to import a makefile project and create a debug configuration.
|
||||
|
||||
Note that sometime this Eclipse need to be restarted in order to be able to place new breakpoints.
|
||||
Note that sometimes Eclipse needs to be restarted in order to be able to place new breakpoints.
|
||||
|
||||
## 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/):
|
||||
As a demonstration, 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/):
|
||||
|
||||

|
||||

|
||||
|
||||
To generate the Briey SoC Hardware:
|
||||
|
||||
|
@ -271,7 +293,7 @@ To generate the Briey SoC Hardware:
|
|||
sbt "runMain vexriscv.demo.Briey"
|
||||
```
|
||||
|
||||
To run the verilator simulation of the Briey SoC which can then be connected to OpenOCD/GDB, first get those dependencies:
|
||||
To run the verilator simulation of the Briey SoC, which can then be connected to OpenOCD/GDB, first get these dependencies:
|
||||
|
||||
```sh
|
||||
sudo apt-get install build-essential xorg-dev libudev-dev libts-dev libgl1-mesa-dev libglu1-mesa-dev libasound2-dev libpulse-dev libopenal-dev libogg-dev libvorbis-dev libaudiofile-dev libpng12-dev libfreetype6-dev libusb-dev libdbus-1-dev zlib1g-dev libdirectfb-dev libsdl2-dev
|
||||
|
@ -289,16 +311,16 @@ To connect OpenOCD (https://github.com/SpinalHDL/openocd_riscv) to the simulatio
|
|||
src/openocd -f tcl/interface/jtag_tcp.cfg -c "set BRIEY_CPU0_YAML /home/spinalvm/Spinal/VexRiscv/cpu0.yaml" -f tcl/target/briey.cfg
|
||||
```
|
||||
|
||||
You can find multiple software examples and demos here: https://github.com/SpinalHDL/VexRiscvSocSoftware/tree/master/projects/briey
|
||||
You can find multiple software examples and demos here: <https://github.com/SpinalHDL/VexRiscvSocSoftware/tree/master/projects/briey>
|
||||
|
||||
You can find some FPGA projects which instantiate the Briey SoC here (DE1-SoC, DE0-Nano): https://drive.google.com/drive/folders/0B-CqLXDTaMbKZGdJZlZ5THAxRTQ?usp=sharing
|
||||
|
||||
Here are some measurements of Briey SoC timings and area :
|
||||
Here are some measurements of Briey SoC timings and area:
|
||||
|
||||
```
|
||||
Artix 7 -> 275 Mhz 3072 LUT 3291 FF
|
||||
Cyclone V -> 139 Mhz 2,175 ALMs
|
||||
Cyclone IV -> 129 Mhz 4,337 LUT 3,170 FF
|
||||
Artix 7 -> 181 Mhz 3220 LUT 3181 FF
|
||||
Cyclone V -> 142 Mhz 2,222 ALMs
|
||||
Cyclone IV -> 130 Mhz 4,538 LUT 3,211 FF
|
||||
```
|
||||
|
||||
## Murax SoC
|
||||
|
@ -313,13 +335,13 @@ Murax is a very light SoC (it fits in an ICE40 FPGA) which can work without any
|
|||
- one 16 bits prescaler, two 16 bits timers
|
||||
- one UART with tx/rx fifo
|
||||
|
||||
Depending the CPU configuration, on the ICE40-hx8k FPGA with icestorm for synthesis, the full SoC has the following area/performance :
|
||||
Depending on the CPU configuration, on the ICE40-hx8k FPGA with icestorm for synthesis, the full SoC has the following area/performance:
|
||||
- RV32I interlocked stages => 51 Mhz, 2387 LC 0.45 DMIPS/Mhz
|
||||
- RV32I bypassed stages => 45 Mhz, 2718 LC 0.65 DMIPS/Mhz
|
||||
|
||||
Its implementation can be found here: `src/main/scala/vexriscv/demo/Murax.scala`.
|
||||
|
||||
To generate the Murax SoC Hardware :
|
||||
To generate the Murax SoC Hardware:
|
||||
|
||||
```sh
|
||||
# To generate the SoC without any content in the ram
|
||||
|
@ -333,13 +355,13 @@ The demo program included by default with `MuraxWithRamInit` will blink the
|
|||
LEDs and echo characters received on the UART back to the user. To see this
|
||||
when running the Verilator sim, type some text and press enter.
|
||||
|
||||
Then go in src/test/cpp/murax and run the simulation with :
|
||||
Then go in `src/test/cpp/murax` and run the simulation with:
|
||||
|
||||
```sh
|
||||
make clean run
|
||||
```
|
||||
|
||||
To connect OpenOCD (https://github.com/SpinalHDL/openocd_riscv) to the simulation :
|
||||
To connect OpenOCD (https://github.com/SpinalHDL/openocd_riscv) to the simulation:
|
||||
|
||||
```sh
|
||||
src/openocd -f tcl/interface/jtag_tcp.cfg -c "set MURAX_CPU0_YAML /home/spinalvm/Spinal/VexRiscv/cpu0.yaml" -f tcl/target/murax.cfg
|
||||
|
@ -351,21 +373,21 @@ Here are some timing and area measurements of the Murax SoC:
|
|||
|
||||
```
|
||||
Murax interlocked stages (0.45 DMIPS/Mhz, 8 bits GPIO) ->
|
||||
Artix 7 -> 313 Mhz 1039 LUT 1200 FF
|
||||
Cyclone V -> 173 Mhz 737 ALMs
|
||||
Cyclone IV -> 144 Mhz 1,484 LUT 1,206 FF
|
||||
iCE40 -> 64 Mhz 2422 LC (nextpnr)
|
||||
Artix 7 -> 216 Mhz 1109 LUT 1201 FF
|
||||
Cyclone V -> 182 Mhz 725 ALMs
|
||||
Cyclone IV -> 147 Mhz 1,551 LUT 1,223 FF
|
||||
iCE40 -> 64 Mhz 2422 LC (nextpnr)
|
||||
|
||||
MuraxFast bypassed stages (0.65 DMIPS/Mhz, 8 bits GPIO) ->
|
||||
Artix 7 -> 323 Mhz 1241 LUT 1301 FF
|
||||
Cyclone V -> 159 Mhz 864 ALMs
|
||||
Cyclone IV -> 137 Mhz 1,688 LUT 1,241 FF
|
||||
iCE40 -> 66 Mhz 2799 LC (nextpnr)
|
||||
Artix 7 -> 224 Mhz 1278 LUT 1300 FF
|
||||
Cyclone V -> 173 Mhz 867 ALMs
|
||||
Cyclone IV -> 143 Mhz 1,755 LUT 1,258 FF
|
||||
iCE40 -> 66 Mhz 2799 LC (nextpnr)
|
||||
```
|
||||
|
||||
Some scripts to generate the SoC and call the icestorm toolchain can be found here: `scripts/Murax/`
|
||||
|
||||
A toplevel simulation testbench with the same features + a GUI are implemented with SpinalSim. You can find it in `src/test/scala/vexriscv/MuraxSim.scala`.
|
||||
A top level simulation testbench with the same features + a GUI are implemented with SpinalSim. You can find it in `src/test/scala/vexriscv/MuraxSim.scala`.
|
||||
|
||||
To run it :
|
||||
|
||||
|
@ -376,13 +398,13 @@ sbt "test:runMain vexriscv.MuraxSim"
|
|||
|
||||
## Running Linux
|
||||
|
||||
A default configuration is located in src/main/scala/vexriscv/demo/Linux.scala
|
||||
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).
|
||||
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 applications (even python).
|
||||
|
||||
Note that VexRiscv can run Linux on both cache full and cache less design.
|
||||
|
||||
|
@ -395,10 +417,10 @@ A prebuild GCC toolsuite can be found here:
|
|||
The VexRiscvSocSoftware makefiles are expecting to find this prebuild version in /opt/riscv/__contentOfThisPreBuild__
|
||||
|
||||
```sh
|
||||
wget https://static.dev.sifive.com/dev-tools/riscv64-unknown-elf-gcc-20171231-x86_64-linux-centos6.tar.gz
|
||||
tar -xzvf riscv64-unknown-elf-gcc-20171231-x86_64-linux-centos6.tar.gz
|
||||
sudo mv riscv64-unknown-elf-gcc-20171231-x86_64-linux-centos6 /opt/riscv64-unknown-elf-gcc-20171231-x86_64-linux-centos6
|
||||
sudo mv /opt/riscv64-unknown-elf-gcc-20171231-x86_64-linux-centos6 /opt/riscv
|
||||
version=riscv64-unknown-elf-gcc-8.3.0-2019.08.0-x86_64-linux-ubuntu14
|
||||
wget -O riscv64-unknown-elf-gcc.tar.gz riscv https://static.dev.sifive.com/dev-tools/$version.tar.gz
|
||||
tar -xzvf riscv64-unknown-elf-gcc.tar.gz
|
||||
sudo mv $version /opt/riscv
|
||||
echo 'export PATH=/opt/riscv/bin:$PATH' >> ~/.bashrc
|
||||
```
|
||||
|
||||
|
@ -494,7 +516,7 @@ import spinal.core._
|
|||
import vexriscv.plugin.Plugin
|
||||
import vexriscv.{Stageable, DecoderService, VexRiscv}
|
||||
|
||||
//This plugin example will add a new instruction named SIMD_ADD which do the following :
|
||||
//This plugin example will add a new instruction named SIMD_ADD which does the following:
|
||||
//
|
||||
//RD : Regfile Destination, RS : Regfile Source
|
||||
//RD( 7 downto 0) = RS1( 7 downto 0) + RS2( 7 downto 0)
|
||||
|
@ -509,7 +531,7 @@ import vexriscv.{Stageable, DecoderService, VexRiscv}
|
|||
//Note : RS1, RS2, RD positions follow the RISC-V spec and are common for all instruction of the ISA
|
||||
|
||||
class SimdAddPlugin extends Plugin[VexRiscv]{
|
||||
//Define the concept of IS_SIMD_ADD signals, which specify if the current instruction is destined for ths plugin
|
||||
//Define the concept of IS_SIMD_ADD signals, which specify if the current instruction is destined for this plugin
|
||||
object IS_SIMD_ADD extends Stageable(Bool)
|
||||
|
||||
//Callback to setup the plugin and ask for different services
|
||||
|
@ -519,10 +541,10 @@ class SimdAddPlugin extends Plugin[VexRiscv]{
|
|||
//Retrieve the DecoderService instance
|
||||
val decoderService = pipeline.service(classOf[DecoderService])
|
||||
|
||||
//Specify the IS_SIMD_ADD default value when instruction are decoded
|
||||
//Specify the IS_SIMD_ADD default value when instructions are decoded
|
||||
decoderService.addDefault(IS_SIMD_ADD, False)
|
||||
|
||||
//Specify the instruction decoding which should be applied when the instruction match the 'key' parttern
|
||||
//Specify the instruction decoding which should be applied when the instruction matches the 'key' parttern
|
||||
decoderService.add(
|
||||
//Bit pattern of the new SIMD_ADD instruction
|
||||
key = M"0000011----------000-----0110011",
|
||||
|
@ -533,8 +555,8 @@ class SimdAddPlugin extends Plugin[VexRiscv]{
|
|||
REGFILE_WRITE_VALID -> True, //Enable the register file write
|
||||
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
|
||||
RS2_USE -> True //Same than above but for RS2.
|
||||
RS1_USE -> True, //Notify the hazard management unit that this instruction uses the RS1 value
|
||||
RS2_USE -> True //Same as above but for RS2.
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -545,19 +567,19 @@ class SimdAddPlugin extends Plugin[VexRiscv]{
|
|||
|
||||
//Add a new scope on the execute stage (used to give a name to signals)
|
||||
execute plug new Area {
|
||||
//Define some signals used internally to the plugin
|
||||
//Define some signals used internally by the plugin
|
||||
val rs1 = execute.input(RS1).asUInt
|
||||
//32 bits UInt value of the regfile[RS1]
|
||||
val rs2 = execute.input(RS2).asUInt
|
||||
val rd = UInt(32 bits)
|
||||
|
||||
//Do some computation
|
||||
//Do some computations
|
||||
rd(7 downto 0) := rs1(7 downto 0) + rs2(7 downto 0)
|
||||
rd(16 downto 8) := rs1(16 downto 8) + rs2(16 downto 8)
|
||||
rd(23 downto 16) := rs1(23 downto 16) + rs2(23 downto 16)
|
||||
rd(31 downto 24) := rs1(31 downto 24) + rs2(31 downto 24)
|
||||
|
||||
//When the instruction is a SIMD_ADD one, then write the result into the register file data path.
|
||||
//When the instruction is a SIMD_ADD, write the result into the register file data path.
|
||||
when(execute.input(IS_SIMD_ADD)) {
|
||||
execute.output(REGFILE_WRITE_DATA) := rd.asBits
|
||||
}
|
||||
|
@ -572,15 +594,15 @@ This example is a very simple one, but each plugin can really have access to the
|
|||
- Halt a given stage of the CPU
|
||||
- Unschedule instructions
|
||||
- Emit an exception
|
||||
- Introduce new instruction decoding specification
|
||||
- Introduce a new instruction decoding specification
|
||||
- Ask to jump the PC somewhere
|
||||
- Read signals published by other plugins
|
||||
- override published signals values
|
||||
- Override published signals values
|
||||
- Provide an alternative implementation
|
||||
- ...
|
||||
|
||||
As a demonstrator, this SimdAddPlugin was integrated in the `src/main/scala/vexriscv/demo/GenCustomSimdAdd.scala` CPU configuration
|
||||
and is self-tested by the `src/test/cpp/custom/simd_add` application by running the following commands :
|
||||
As a demonstration, this SimdAddPlugin was integrated in the `src/main/scala/vexriscv/demo/GenCustomSimdAdd.scala` CPU configuration
|
||||
and is self-tested by the `src/test/cpp/custom/simd_add` application by running the following commands:
|
||||
|
||||
```sh
|
||||
# Generate the CPU
|
||||
|
@ -589,7 +611,7 @@ sbt "runMain vexriscv.demo.GenCustomSimdAdd"
|
|||
cd src/test/cpp/regression/
|
||||
|
||||
# Optionally add TRACE=yes if you want to get the VCD waveform from the simulation.
|
||||
# Also you have to know that by default, the testbench introduce instruction/data bus stall.
|
||||
# Also you have to know that, by default, the testbench introduce instruction/data bus stall.
|
||||
# Note the CUSTOM_SIMD_ADD flag is set to yes.
|
||||
make clean run IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no DHRYSTONE=no REDO=2 CUSTOM_SIMD_ADD=yes
|
||||
```
|
||||
|
@ -607,14 +629,14 @@ The second one (`CustomCsrDemoGpioPlugin`) creates a GPIO peripheral directly ma
|
|||
|
||||
## CPU clock and resets
|
||||
|
||||
Without the debug plugin, the CPU will have a standard `clk` input and a `reset` input. But with the debug plugin the situation is the following :
|
||||
Without the debug plugin, the CPU will have a standard `clk` input and a `reset` input. But with the debug plugin the situation is the following:
|
||||
|
||||
- clk : As before, the clock which drive the whole CPU design, including the debug logic
|
||||
- reset : Reset all the CPU states excepted the debug logics
|
||||
- debugReset : Reset the debug logic of the CPU
|
||||
- debug_resetOut : a CPU output signal which allows the JTAG to reset the CPU + the memory interconnect + the peripherals
|
||||
- `clk`: as before, the clock which drives the whole CPU design, including the debug logic
|
||||
- `reset`: reset all the CPU states except the debug logic
|
||||
- `debugReset`: reset the debug logic of the CPU
|
||||
- `debug_resetOut`: a CPU output signal which allows the JTAG to reset the CPU + the memory interconnect + the peripherals
|
||||
|
||||
So here is the reset interconnect in case you use the debug plugin :
|
||||
So here is the reset interconnect, in case you use the debug plugin:
|
||||
|
||||
```
|
||||
VexRiscv
|
||||
|
@ -635,20 +657,20 @@ toplevelReset >----+--------> debugReset |
|
|||
## VexRiscv Architecture
|
||||
|
||||
VexRiscv is implemented via a 5 stage in-order pipeline on which many optional and complementary plugins add functionalities to provide a functional RISC-V CPU.
|
||||
This approach is completely unconventional and only possible through meta hardware description languages (SpinalHDL in the current case) but has proven its advantages
|
||||
This approach is completely unconventional and only possible through meta hardware description languages (SpinalHDL, in the current case) but has proven its advantages
|
||||
via the VexRiscv implementation:
|
||||
|
||||
- You can swap/turn on/turn off parts of the CPU directly via the plugin system
|
||||
- You can add new functionalities/instruction without having to modify any sources code of the CPU
|
||||
- It allows the CPU configuration to cover a very large spectrum of implementation without cooking spaghetti code
|
||||
- It allows your code base to truly produce a parametrized CPU design
|
||||
- You can add new functionalities/instructions without having to modify any of the sources of the CPU
|
||||
- It allows the CPU configuration to cover a very large spectrum of implementations without cooking spaghetti code
|
||||
- It allows your codebase to truly produce a parametrized CPU design
|
||||
|
||||
If you generate the CPU without any plugin, it will only contain the definition of the 5 pipeline stages and their basic arbitration, but nothing else,
|
||||
as everything else, including the program counter is added into the CPU via plugins.
|
||||
and everything else, including the program counter is added into the CPU via plugins.
|
||||
|
||||
### Plugins
|
||||
|
||||
This chapter describes plugins currently implemented.
|
||||
This chapter describes the currently implemented plugins.
|
||||
|
||||
- [IBusSimplePlugin](#ibussimpleplugin)
|
||||
- [IBusCachedPlugin](#ibuscachedplugin)
|
||||
|
@ -674,7 +696,7 @@ This chapter describes plugins currently implemented.
|
|||
|
||||
#### IBusSimplePlugin
|
||||
|
||||
This plugin implement the CPU frontend (instruction fetch) via a very simple and neutral memory interface going outside the CPU.
|
||||
This plugin implements the CPU frontend (instruction fetch) via a very simple and neutral memory interface going outside the CPU.
|
||||
|
||||
| Parameters | type | description |
|
||||
| ------ | ----------- | ------ |
|
||||
|
@ -715,7 +737,7 @@ case class IBusSimpleBus(interfaceKeepData : Boolean) extends Bundle with IMaste
|
|||
}
|
||||
```
|
||||
|
||||
**Important** : Checkout the cmdForkPersistence parameter, because if it's not set, it can break the iBus compatibility with your memory system (unless you externaly add some buffers)
|
||||
**Important** : check out the cmdForkPersistence parameter, because if it is not set, it can break the iBus compatibility with your memory system (unless you externaly add some buffers).
|
||||
|
||||
Setting cmdForkPersistence and cmdForkOnSecondStage improves iBus cmd timings.
|
||||
|
||||
|
@ -759,19 +781,19 @@ Note: If you enable the twoCycleRam option and if wayCount is bigger than one, t
|
|||
|
||||
#### DecoderSimplePlugin
|
||||
|
||||
This plugin provides instruction decoding capabilities to others plugins.
|
||||
This plugin provides instruction decoding capabilities to other 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 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.
|
||||
Each plugin that implements an instruction provides this kind of information to the DecoderSimplePlugin plugin.
|
||||
|
||||
| Parameters | type | description |
|
||||
| ------ | ----------- | ------ |
|
||||
| catchIllegalInstruction | Boolean | When true, instructions that don't match a decoding specification will generate a trap exception |
|
||||
|
||||
Here is a usage example :
|
||||
Here is a usage example:
|
||||
|
||||
```scala
|
||||
//Specify the instruction decoding which should be applied when the instruction match the 'key' pattern
|
||||
//Specify the instruction decoding which should be applied when the instruction matches the 'key' pattern
|
||||
decoderService.add(
|
||||
//Bit pattern of the new instruction
|
||||
key = M"0000011----------000-----0110011",
|
||||
|
@ -797,15 +819,21 @@ This plugin implements the register file.
|
|||
|
||||
| Parameters | type | description |
|
||||
| ------ | ----------- | ------ |
|
||||
| regFileReadyKind | RegFileReadKind | Can bet set to ASYNC or SYNC. Specifies the kind of memory read used to implement the register file. ASYNC means zero cycle latency memory read, while SYNC means one cycle latency memory read which can be mapped into standard FPGA memory blocks |
|
||||
| zeroBoot | Boolean | Load all registers with zeroes at the beginning of simulations to keep everything deterministic in logs/traces|
|
||||
| regFileReadyKind | RegFileReadKind | Can be set to ASYNC or SYNC. Specifies the kind of memory read used to implement the register file. ASYNC means zero cycle latency memory read, while SYNC means one cycle latency memory read which can be mapped into standard FPGA memory blocks |
|
||||
| zeroBoot | Boolean | Load all registers with zeroes at the beginning of the simulation to keep everything deterministic in logs/traces|
|
||||
|
||||
This register file use a `don't care` read-during-write policy, so the bypassing/hazard plugin should take care of this.
|
||||
|
||||
If you get a `Missing inserts : INSTRUCTION_ANTICIPATE` error, that's because the RegFilePlugin is configured to use SYNC memory read ports to access the register file, but the IBus plugin configuration can't provide the instruction's register file read address one cycle before the decode stage. To workaround that you can :
|
||||
|
||||
- Configure the RegFilePlugin to implement the register file read in a asyncronus manner (ASYNC), if your target device support such things
|
||||
- If you use the IBusSimplePlugin, you need to enable the injectorStage configuration
|
||||
- If you use the IBusCachedPlugin, you can either enable the injectorStage, or set twoCycleCache + twoCycleRam to false.
|
||||
|
||||
#### HazardSimplePlugin
|
||||
|
||||
This plugin checks the pipeline instruction dependencies and, if necessary or possible, will stop the instruction in the decoding stage or bypass the instruction results
|
||||
from the later stages to the decode stage.
|
||||
from the later stages of the decode stage.
|
||||
|
||||
Since the register file is implemented with a `don't care` read-during-write policy, this plugin also manages these kind of hazards.
|
||||
|
||||
|
@ -829,7 +857,7 @@ Except for SRC1/SRC2, this plugin does everything at the begining of Execute sta
|
|||
|
||||
#### IntAluPlugin
|
||||
|
||||
This plugin implements all ADD/SUB/SLT/SLTU/XOR/OR/AND/LUI/AUIPC instructions in the execute stage by using the SrcPlugin outputs. It is a realy simple plugin.
|
||||
This plugin implements all ADD/SUB/SLT/SLTU/XOR/OR/AND/LUI/AUIPC instructions in the execute stage by using the SrcPlugin outputs. It is a really simple plugin.
|
||||
|
||||
The result is injected into the pipeline directly at the end of the execute stage.
|
||||
|
||||
|
@ -841,7 +869,7 @@ The result is injected into the pipeline directly at the end of the execute stag
|
|||
|
||||
#### FullBarrelShifterPlugin
|
||||
|
||||
Implements SLL/SRL/SRA instructions by using a full barrel shifter, so it execute all shifts in a single cycle.
|
||||
Implements SLL/SRL/SRA instructions by using a full barrel shifter, so it executes all shifts in a single cycle.
|
||||
|
||||
| Parameters | type | description |
|
||||
| ------ | ----------- | ------ |
|
||||
|
@ -849,7 +877,7 @@ Implements SLL/SRL/SRA instructions by using a full barrel shifter, so it execut
|
|||
|
||||
#### BranchPlugin
|
||||
|
||||
This plugin implement all branch/jump instructions (JAL/JALR/BEQ/BNE/BLT/BGE/BLTU/BGEU) with primitives used by the cpu frontend plugins to implement branch prediction. The prediction implementation is set in the frontend plugins (IBusX)
|
||||
This plugin implements all branch/jump instructions (JAL/JALR/BEQ/BNE/BLT/BGE/BLTU/BGEU) with primitives used by the cpu frontend plugins to implement branch prediction. The prediction implementation is set in the frontend plugins (IBusX).
|
||||
|
||||
| Parameters | type | description |
|
||||
| ------ | ----------- | ------ |
|
||||
|
@ -869,13 +897,13 @@ otherwise the standard penalty is applied.
|
|||
|
||||
##### Prediction DYNAMIC
|
||||
|
||||
Same as the STATIC prediction, except that to do the prediction, it use a direct mapped 2 bit history cache (BHT) which remembers if the branch is more likely to be taken or not.
|
||||
Same as the STATIC prediction, except that to do the prediction, it uses a direct mapped 2 bit history cache (BHT) which remembers if the branch is more likely to be taken or not.
|
||||
|
||||
##### Prediction DYNAMIC_TARGET
|
||||
|
||||
This predictor uses a direct mapped branch target buffer (BTB) in the Fetch stage which store the PC of the instruction, the target PC of the instruction and a 2 bit history to remember
|
||||
if the branch is more likely to be taken or not. This is the most efficient branch predictor actualy implemented on VexRiscv as when the branch prediction is right, it produce no branch penalty.
|
||||
The down side is that this predictor has a long combinatorial path coming from the prediction cache read port to the programm counter by passing through the jump interface.
|
||||
This predictor uses a direct mapped branch target buffer (BTB) in the Fetch stage which stores the PC of the instruction, the target PC of the instruction and a 2 bit history to remember
|
||||
if the branch is more likely to be taken or not. This is actually the most efficient branch predictor implemented on VexRiscv, because when the branch prediction is right, it produces no branch penalty.
|
||||
The downside is that this predictor has a long combinatorial path coming from the prediction cache read port to the programm counter, passing through the jump interface.
|
||||
|
||||
#### DBusSimplePlugin
|
||||
|
||||
|
@ -919,7 +947,7 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{
|
|||
}
|
||||
```
|
||||
|
||||
Note that bridges are available to convert this interface into AXI4 and Avalon
|
||||
Note that there are bridges available that can convert this interface into AXI4 and Avalon.
|
||||
|
||||
There is at least one cycle latency between a cmd and the corresponding rsp. The rsp.ready flag should be false after a read cmd until the rsp is present.
|
||||
|
||||
|
@ -937,7 +965,7 @@ The processing is fully pipelined between the Execute/Memory/Writeback stage. Th
|
|||
Implements the division/modulo instruction from the RISC-V M extension. It is done in a simple iterative way which always takes 34 cycles. The result is inserted into the
|
||||
Memory stage.
|
||||
|
||||
This plugin is now based on the MulDivIterativePlugin one.
|
||||
This plugin is now based on MulDivIterativePlugin.
|
||||
|
||||
#### MulDivIterativePlugin
|
||||
|
||||
|
@ -955,14 +983,14 @@ This plugin is able to unroll the iterative calculation process to reduce the nu
|
|||
The number of cycles used to execute a multiplication is '32/mulUnrollFactor'
|
||||
The number of cycles used to execute a division is '32/divUnrollFactor + 1'
|
||||
|
||||
Both mul/div are processed into the memory stage (late result).
|
||||
Both mul/div are processed in the memory stage (late result).
|
||||
|
||||
#### CsrPlugin
|
||||
|
||||
Implements most of the Machine mode and a few of the User mode registers as specified in the RISC-V priviledged spec.
|
||||
The access mode of most of the CSR is parameterizable (NONE/READ_ONLY/WRITE_ONLY/READ_WRITE) to reduce the area usage of unneeded features.
|
||||
Implements most of the Machine mode and a few of the User mode registers, as specified in the RISC-V priviledged spec.
|
||||
The access mode of most of the CSR is parameterizable to reduce the area usage of unneeded features.
|
||||
|
||||
(CsrAccess can be NONE/READ_ONLY/WRITE_ONLY/READ_WRITE)
|
||||
(CsrAccess can be `NONE/READ_ONLY/WRITE_ONLY/READ_WRITE`)
|
||||
|
||||
| Parameters | type | description |
|
||||
| ------ | ----------- | ------ |
|
||||
|
@ -992,11 +1020,11 @@ stage before jumping to mtvec.
|
|||
|
||||
#### StaticMemoryTranslatorPlugin
|
||||
|
||||
Static memory translator plugin which allows one to specify which range of the memory addresses is IO mapped and shouldn't be cached.
|
||||
Static memory translator plugin which allows to specify which range of the memory addresses is I/O mapped and shouldn't be cached.
|
||||
|
||||
#### MmuPlugin
|
||||
|
||||
Hardware refilled MMU implementation. Allows others plugins such as DBusCachedPlugin/IBusCachedPlugin to instanciate memory address translation ports. Each port has a small dedicated
|
||||
Hardware refilled MMU implementation. Allows other 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
|
||||
|
@ -1010,7 +1038,7 @@ The JTAG interface is provided by another bridge, which makes it possible to eff
|
|||
|
||||
The internals of the debug plugin are done in a manner which reduces the area usage and the FMax impact of this plugin.
|
||||
|
||||
Here is the simple bus to access it, the rsp come one cycle after the request :
|
||||
Here is the simple bus to access it, the rsp comes one cycle after the request:
|
||||
|
||||
```scala
|
||||
case class DebugExtensionCmd() extends Bundle{
|
||||
|
@ -1034,7 +1062,7 @@ case class DebugExtensionBus() extends Bundle with IMasterSlave{
|
|||
```
|
||||
|
||||
|
||||
Here is the register mapping :
|
||||
Here is the register mapping:
|
||||
|
||||
```
|
||||
Read address 0x00 ->
|
||||
|
@ -1056,12 +1084,10 @@ Write Address 0x04 ->
|
|||
bits (31 downto 0) : Instruction that should be pushed into the CPU pipeline for debug purposes
|
||||
```
|
||||
|
||||
The OpenOCD port is there :
|
||||
https://github.com/SpinalHDL/openocd_riscv
|
||||
The OpenOCD port is here: <https://github.com/SpinalHDL/openocd_riscv>
|
||||
|
||||
#### YamlPlugin
|
||||
|
||||
This plugin offers a service to others plugins to generate a usefull Yaml file about the CPU configuration. It contains, for instance, the sequence of instruction required
|
||||
This plugin offers a service to other plugins to generate a useful Yaml file describing the CPU configuration. It contains, for instance, the sequence of instructions required
|
||||
to flush the data cache (information used by openocd).
|
||||
|
||||
|
||||
|
|
19
build.sbt
19
build.sbt
|
@ -1,4 +1,3 @@
|
|||
|
||||
lazy val root = (project in file(".")).
|
||||
settings(
|
||||
inThisBuild(List(
|
||||
|
@ -6,17 +5,19 @@ lazy val root = (project in file(".")).
|
|||
scalaVersion := "2.11.12",
|
||||
version := "2.0.0"
|
||||
)),
|
||||
scalacOptions += s"-Xplugin:${new File(baseDirectory.value + "/../SpinalHDL/idslplugin/target/scala-2.11/spinalhdl-idsl-plugin_2.11-1.4.2.jar")}",
|
||||
scalacOptions += s"-Xplugin-require:idsl-plugin",
|
||||
libraryDependencies ++= Seq(
|
||||
"com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.6",
|
||||
"com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.6",
|
||||
// "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.6",
|
||||
// "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.6",
|
||||
"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(spinalHdlIdslPlugin, spinalHdlSim,spinalHdlCore,spinalHdlLib)
|
||||
lazy val spinalHdlIdslPlugin = ProjectRef(file("../SpinalHDL"), "idslplugin")
|
||||
lazy val spinalHdlSim = ProjectRef(file("../SpinalHDL"), "sim")
|
||||
lazy val spinalHdlCore = ProjectRef(file("../SpinalHDL"), "core")
|
||||
lazy val spinalHdlLib = ProjectRef(file("../SpinalHDL"), "lib")
|
||||
|
||||
|
||||
fork := true
|
||||
fork := true
|
||||
|
|
216
doc/smp/smp.md
Normal file
216
doc/smp/smp.md
Normal file
|
@ -0,0 +1,216 @@
|
|||
# Coherent interface specification
|
||||
|
||||
Features :
|
||||
- 3 interface (write, read, probe) composed of 7 streams
|
||||
- Two data paths (read + write), but allow dirty/clean sharing by reusing the write data path
|
||||
- Allow multi level coherent interconnect
|
||||
- No ordering, but provide barrier
|
||||
- Allow cache-full and cache-less agents
|
||||
|
||||
## A few hint to help reading the spec
|
||||
|
||||
In order to make the spec more readable, there is some definitions :
|
||||
|
||||
### Stream
|
||||
|
||||
A stream is a primitive interface which carry transactions using a valid/ready handshake.
|
||||
|
||||
### Memory copy
|
||||
|
||||
To talk in a non abstract way, in a system with multiple caches, a given memory address can potentialy be loaded in multiple caches at the same time. So let's define that :
|
||||
|
||||
- The DDR memory is named `main memory`
|
||||
- Each cache line can be loaded with a part of the main memory, let's name that a `memory copy`
|
||||
|
||||
### Master / Interconnect / Slave
|
||||
|
||||
A master could be for instance a CPU cache, the side of the interconnect toward the main memory or toward a more general interconnect.
|
||||
|
||||
A slave could be main memory, the side of the interconnect toward a CPU cache or toward a less general interconnect.
|
||||
|
||||
The spec will try to stay abstract and define the coherent interface as something which can be used between two agents (cpu, interconnect, main memory)
|
||||
|
||||
## Memory copy status
|
||||
|
||||
Memory copy, in other words, cache line, have more states than non coherent systems :
|
||||
|
||||
| Name | Description |
|
||||
|---------------|-------------|
|
||||
| Valid/Invalid | Line loaded or not |
|
||||
| Shared/Unique | shared => multiple copy of the cache line in different caches, unique => no other caches has a copy of the line |
|
||||
| Owner/Lodger | lodger => copy of the line, but no other responsibility, owner => the given cache is responsible to write back dirty data and answer probes with the data |
|
||||
| Clean/Dirty | clean => match main memory, dirty => main memory need updates |
|
||||
|
||||
All combination of those cache flag are valid. But if a cache line is invalid, the other status have no meaning.
|
||||
|
||||
Later in the spec, memory copy state can be described for example as :
|
||||
|
||||
- VSOC for (Valid, Shared, Owner, Clean)
|
||||
- V-OC for (Valid, Shared or Unique, Owner, Clean)
|
||||
- !V-OC for NOT (Valid, Shared or Unique, Owner, Clean)
|
||||
- ...
|
||||
|
||||
## Coherent interface
|
||||
|
||||
One full coherent interface is composed of 3 inner interfaces, them-self composed of 7 stream described bellow as `interfaceName (Side -> StreamName -> Side -> StreamName -> ...)`
|
||||
- write (M -> writeCmd -> S -> writeRsp -> M)
|
||||
- read (M -> readCmd- > S -> readRsp -> M -> readAck -> S)
|
||||
- probe (S -> probeCmd -> M -> probeRsp -> S)
|
||||
|
||||
The following streams could physically be merges in order to reduce the number of arbitration :
|
||||
|
||||
- writeCmd, probeRsp, readAck
|
||||
- writeRsp, readRsp
|
||||
|
||||
### Read interface
|
||||
|
||||
Used by masters to obtain new memory copies and make copies unique (used to write them).
|
||||
|
||||
Composed of 3 stream :
|
||||
|
||||
| Name | Direction | Description |
|
||||
|---------|-----------|----------|
|
||||
| readCmd | M -> S | Emit memory read and cache management commands |
|
||||
| readRsp | M <- S | Return some data and/or a status from readCmd |
|
||||
| readAck | M -> S | Return ACK from readRsp to synchronize the interconnect status |
|
||||
|
||||
### Write interface
|
||||
|
||||
Used by masters to write data back to the memory and notify the interconnect of memory copies eviction (used to keep potential directories updated).
|
||||
|
||||
Composed of 2 stream :
|
||||
|
||||
| Name | Direction | Description |
|
||||
|---------|-----------|----------|
|
||||
| writeCmd | M -> S | Emit memory writes and cache management commands |
|
||||
| writeRsp | M <- S | Return a status from writeCmd |
|
||||
|
||||
### Probe interface
|
||||
|
||||
Used by the interconnect to order master to change their memory copies status and get memory copies owners data.
|
||||
|
||||
Composed of 2 stream :
|
||||
|
||||
| Name | Direction | Description |
|
||||
|----------|-----------|----------|
|
||||
| probeCmd | M <- S | Used for cache management |
|
||||
| probeRsp | M -> S | Acknowledgment |
|
||||
|
||||
## Transactions
|
||||
|
||||
This chapter define transactions moving over the 3 previously defined interface (read/write/probe).
|
||||
|
||||
### Read commands
|
||||
|
||||
Emitted on the readCmd channel (master -> slave)
|
||||
|
||||
| Command | Initial state | Description | Usage example |
|
||||
|-------------|---------------|----------|------|
|
||||
| readShared | I--- | Get a memory copy as V--- | Want to read a uncached address |
|
||||
| readUnique | I--- | Get a memory copy as VUO- | Want to write a uncached address |
|
||||
| readOnce | I--- | Get a memory copy without coherency tracking | Instruction cache read |
|
||||
| makeUnique | VS-- | Make other memory copy as I--- and make yourself VUO- | Want to write into a shared line |
|
||||
| readBarrier | N/A | Ensure that the visibility of the memory operations of this channel do not cross the barrier | ISA fence |
|
||||
|
||||
makeUnique should be designed with care. There is a few corner cases :
|
||||
- While a master has a inflight makeUnique, a probe can change its state, in such case, the makeUnique become weak and invalidation is canceled. This is usefull for multi level coherent interconnects.
|
||||
- Multi level coherent interconnect should be careful to properly move the ownership and not lose dirty data
|
||||
|
||||
I'm not sure yet if we should add some barrier transactions to enforce
|
||||
|
||||
### Read responses
|
||||
|
||||
Emitted on the readRsp channel (master <- slave)
|
||||
|
||||
readSuccess, readError, data shared/unique clean/dirty owner/notOwner
|
||||
|
||||
| Responses | From command | Description |
|
||||
|-------------|---------------|----------|
|
||||
| readSuccess | makeUnique, readBarrier | - |
|
||||
| readError | readShared, readUnique, readOnce | Bad address |
|
||||
| readData | readShared, readUnique, readOnce | Data + coherency status (V---) |
|
||||
|
||||
### Read ack
|
||||
|
||||
Emitted on the readAck channel (master -> slave), it carry no information, just a notification that the master received the read response
|
||||
|
||||
| Name | From command | Description |
|
||||
|--------------|---------------|----------|
|
||||
| readSuccess | * | - |
|
||||
|
||||
### Write commands
|
||||
|
||||
Write commands can be emitted on the writeCmd channel (master -> slave)
|
||||
|
||||
| Name | Initial state | Description | Usage example |
|
||||
|--------------|---------------|----------|----------|
|
||||
| writeInvalid | V-O- | Write the memory copy and update it status to I--- | Need to free the dirty cache line |
|
||||
| writeShare | V-O- | Write the memory copy but keep it as VSO- | A probe makeShared asked it |
|
||||
| writeUnique | VUO- | Write the memory copy but keep it as VUO- | A probe probeOnce need to read the data |
|
||||
| evict | V---, !V-OD | Notify the interconnect that the cache line is now I--- | Need to free a clean cache line |
|
||||
| writeBarrier | N/A | Ensure that the visibility of the memory operations of this channel do not cross the barrier | ISA fence |
|
||||
|
||||
### Write responses
|
||||
|
||||
Emitted on the writeRsp channel (master <- slave), it carry no information, just a notification that the corresponding command is done.
|
||||
|
||||
| Name | From command | Description |
|
||||
|--------------|---------------|----------|
|
||||
| writeSuccess | * | - |
|
||||
|
||||
### Probe commands
|
||||
|
||||
Probe commands can be emitted on the probeCmd channel (slave -> master)
|
||||
|
||||
| Name | Description | Usage example |
|
||||
|-------------|-------------|---------------|
|
||||
| makeInvalid | Make the memory copy I--- | Another cache want to make his shared copy unique to write it |
|
||||
| makeShared | Make the memory copy VS-- | Another cache want to read a memory block, so unique copy need to be shared |
|
||||
| probeOnce | Read the V-O- memory copy | A non coherent agent did a readOnce |
|
||||
|
||||
makeInvalid and makeShared could result into one of the following probeSuccess, writeInvalid, writeShare
|
||||
|
||||
probeOnce can result into one of the following probeSuccess, writeShare, writeUnique
|
||||
|
||||
To help the slave matching the writeInvalid and writeShare generated from a probe, those request are tagged with a matching ID.
|
||||
|
||||
### Probe responses
|
||||
|
||||
Emitted on the probeRsp channel (master -> slave), it carry no information, just a notification that the corresponding command is done.
|
||||
|
||||
| Name | From command | Description |
|
||||
|--------------|---------------|----------|
|
||||
| probeSuccess | * | - |
|
||||
|
||||
|
||||
## Channel interlocking
|
||||
|
||||
This is a delicate subject as if everything was permited, it would be easy to end up with deadlocks.
|
||||
|
||||
There is the streams priority (top => high priority, bottom => low priority) A lower priority stream should not block a higher priority stream in order to avoid deadlocks.
|
||||
- writeCmd, writeRsp, readRsp, readAck, probeRsp. Nothing should realy block them excepted bandwidth
|
||||
- probeCmd. Can be blocked by inflight/generated writes
|
||||
- readCmd. Can be blocked by inflight/generated probes
|
||||
|
||||
In other words :
|
||||
|
||||
Masters can emit writeCmd and wait their writeRsp completion before answering probes commands.
|
||||
Slaves can emit probeCmd and wait their proveRsp completion before answering reads.
|
||||
Slaves can emit readRsp and wait on their readAck completion before doing anything else
|
||||
|
||||
## Interface subsets
|
||||
|
||||
There is a few cases where you could need a specific subset of the coherent interface :
|
||||
- Instruction caches do not necessarily need to maintain the coherency with the memory system.
|
||||
- DMA need to read and write the memory system, but are cache-less (no probe)
|
||||
|
||||
### ReadOnly interface without maintained coherency
|
||||
|
||||
Such interface is only composed of the read bus on which the readCmd stream can only use readOnce requests
|
||||
|
||||
|
||||
### WriteOnly interface
|
||||
|
||||
In such interface, there is no read/probe buses, but only a writeCmd and a writeRsp stream. The writeCmd will invalidate other memory copies, then write into the memory while the writeRsp will return a writeSuccess/writeError status.
|
||||
|
||||
|
|
@ -1,2 +1,3 @@
|
|||
addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "5.2.4")
|
||||
|
||||
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.10")
|
||||
|
|
129
scripts/Murax/arty_a7/README.md
Normal file
129
scripts/Murax/arty_a7/README.md
Normal file
|
@ -0,0 +1,129 @@
|
|||
This example is for the Digilent ARTY A7 35T board.
|
||||
|
||||
# Using the example
|
||||
|
||||
## Before Starting
|
||||
|
||||
You should make sure you have the following tools installed:
|
||||
* vivado 2018.1 or later
|
||||
* riscv toolchain (riscv64-unknown-elf)
|
||||
* sbt
|
||||
|
||||
## Board setup
|
||||
Make sure you have a rev E board. If you have a later version check that the
|
||||
flash part is S25FL128SAGMF100.
|
||||
|
||||
Jumper settings for board rev E:
|
||||
* Disconnect anything from the connectors (Pmod, Arduino)
|
||||
* Jumpers: JP1 and JP2 on, others off.
|
||||
|
||||
## Building
|
||||
|
||||
You should be able to just type `make` and get output similar to this;
|
||||
```
|
||||
...
|
||||
Memory region Used Size Region Size %age Used
|
||||
RAM: 896 B 2 KB 43.75%
|
||||
...
|
||||
---------------------------------------------------------------------------------
|
||||
Finished RTL Elaboration : Time (s): cpu = 00:00:08 ; elapsed = 00:00:09 . Memory (MB): peak = 1457.785 ; gain = 243.430 ; free physical = 17940 ; free virtual = 57159
|
||||
---------------------------------------------------------------------------------
|
||||
...
|
||||
---------------------------------------------------------------------------------
|
||||
Finished Technology Mapping : Time (s): cpu = 00:02:42 ; elapsed = 00:02:58 . Memory (MB): peak = 1986.879 ; gain = 772.523 ; free physical = 17454 ; free virtual = 56670
|
||||
---------------------------------------------------------------------------------
|
||||
...
|
||||
---------------------------------------------------------------------------------
|
||||
Finished Writing Synthesis Report : Time (s): cpu = 00:02:45 ; elapsed = 00:03:01 . Memory (MB): peak = 1986.879 ; gain = 772.523 ; free physical = 17457 ; free virtual = 56673
|
||||
---------------------------------------------------------------------------------
|
||||
...
|
||||
Writing bitstream ./toplevel.bit...
|
||||
...
|
||||
mmi files generated
|
||||
...
|
||||
********************************************
|
||||
./soc_latest_sw.bit correctly generated
|
||||
********************************************
|
||||
...
|
||||
********************************************
|
||||
./soc_latest_sw.mcs correctly generated
|
||||
********************************************
|
||||
|
||||
INFO: [Common 17-206] Exiting Vivado at Thu Nov 28 04:00:50 2019...
|
||||
```
|
||||
|
||||
The process should take around 8 minutes on a reasonably fast computer.
|
||||
|
||||
## Programming
|
||||
|
||||
### Direct FPGA RAM programming
|
||||
|
||||
Run `make prog` to program the bit file directly to FPGA RAM.
|
||||
|
||||
You should get output like the following;
|
||||
```
|
||||
...
|
||||
****** Xilinx hw_server v2018.1
|
||||
**** Build date : Apr 4 2018-18:56:09
|
||||
** Copyright 1986-2018 Xilinx, Inc. All Rights Reserved.
|
||||
|
||||
INFO: [Labtoolstcl 44-466] Opening hw_target localhost:3121/xilinx_tcf/Digilent/210319AB569AA
|
||||
INFO: [Labtools 27-1434] Device xc7a35t (JTAG device index = 0) is programmed with a design that has no supported debug core(s) in it.
|
||||
WARNING: [Labtools 27-3361] The debug hub core was not detected.
|
||||
Resolution:
|
||||
1. Make sure the clock connected to the debug hub (dbg_hub) core is a free running clock and is active.
|
||||
2. Make sure the BSCAN_SWITCH_USER_MASK device property in Vivado Hardware Manager reflects the user scan chain setting in the design and refresh the device. To determine the user scan chain setting in the design, open the implemented design and use 'get_property C_USER_SCAN_CHAIN [get_debug_cores dbg_hub]'.
|
||||
For more details on setting the scan chain property, consult the Vivado Debug and Programming User Guide (UG908).
|
||||
INFO: [Labtools 27-3164] End of startup status: HIGH
|
||||
INFO: [Common 17-206] Exiting Vivado at Thu Nov 28 04:01:36 2019...
|
||||
```
|
||||
|
||||
After programming the LED4~LED7 shall show some activity.
|
||||
|
||||
### QSPI flash programming
|
||||
|
||||
Run `make flash` to program the bit file to the QSPI flash.
|
||||
|
||||
You should get output like the following;
|
||||
```
|
||||
...
|
||||
****** Xilinx hw_server v2018.1
|
||||
**** Build date : Apr 4 2018-18:56:09
|
||||
** Copyright 1986-2018 Xilinx, Inc. All Rights Reserved.
|
||||
|
||||
|
||||
INFO: [Labtoolstcl 44-466] Opening hw_target localhost:3121/xilinx_tcf/Digilent/210319AB569AA
|
||||
INFO: [Labtools 27-1434] Device xc7a35t (JTAG device index = 0) is programmed with a design that has no supported debug core(s) in it.
|
||||
...
|
||||
INFO: [Labtools 27-3164] End of startup status: HIGH
|
||||
Mfg ID : 1 Memory Type : 20 Memory Capacity : 18 Device ID 1 : 0 Device ID 2 : 0
|
||||
Performing Erase Operation...
|
||||
Erase Operation successful.
|
||||
Performing Program and Verify Operations...
|
||||
Program/Verify Operation successful.
|
||||
INFO: [Labtoolstcl 44-377] Flash programming completed successfully
|
||||
program_hw_cfgmem: Time (s): cpu = 00:00:00.11 ; elapsed = 00:00:52 . Memory (MB): peak = 1792.711 ; gain = 8.000 ; free physical = 17712 ; free virtual = 56943
|
||||
INFO: [Labtoolstcl 44-464] Closing hw_target localhost:3121/xilinx_tcf/Digilent/210319AB569AA
|
||||
...
|
||||
INFO: [Common 17-206] Exiting Vivado at Thu Nov 28 04:06:28 2019...
|
||||
```
|
||||
|
||||
After programming the flash you need to press the "PROG" button on the board. Then after a second or so the "DONE" LED shall be ON and LED4~LED7 shall show some activity.
|
||||
|
||||
|
||||
## Connect
|
||||
|
||||
After programming you should be able to connect to the serial port and have some output.
|
||||
|
||||
On Linux you can do this using a command like `screen /dev/ttyUSB1`. Other good alternatives:
|
||||
|
||||
* moserial (GUI)
|
||||
* picocom (can be launched via the file "picocom_arty")
|
||||
|
||||
Parameters:
|
||||
* port is : /dev/ttyUSB1
|
||||
* flowcontrol : none
|
||||
* baudrate is : 115200
|
||||
* parity is : none
|
||||
* databits are : 8
|
||||
* stopbits are : 1
|
366
scripts/Murax/arty_a7/arty_a7.xdc
Normal file
366
scripts/Murax/arty_a7/arty_a7.xdc
Normal file
|
@ -0,0 +1,366 @@
|
|||
set_property PACKAGE_PIN F4 [get_ports tck]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports tck]
|
||||
|
||||
set_property PACKAGE_PIN D2 [get_ports tms]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports tms]
|
||||
|
||||
set_property PACKAGE_PIN D4 [get_ports tdo]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports tdo]
|
||||
set_property PULLUP true [get_ports tdo]
|
||||
|
||||
set_property PACKAGE_PIN E2 [get_ports tdi]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports tdi]
|
||||
|
||||
set_property PACKAGE_PIN D3 [get_ports trst]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports trst]
|
||||
set_property PULLUP true [get_ports trst]
|
||||
|
||||
|
||||
## serial:0.tx
|
||||
set_property PACKAGE_PIN D10 [get_ports serial_tx]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports serial_tx]
|
||||
## serial:0.rx
|
||||
set_property PACKAGE_PIN A9 [get_ports serial_rx]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports serial_rx]
|
||||
## clk100:0
|
||||
set_property PACKAGE_PIN E3 [get_ports clk100]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports clk100]
|
||||
## cpu_reset:0
|
||||
set_property PACKAGE_PIN C2 [get_ports cpu_reset]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports cpu_reset]
|
||||
## eth_ref_clk:0
|
||||
#set_property LOC G18 [get_ports eth_ref_clk]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_ref_clk]
|
||||
## user_led:0
|
||||
set_property PACKAGE_PIN H5 [get_ports user_led0]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports user_led0]
|
||||
## user_led:1
|
||||
set_property PACKAGE_PIN J5 [get_ports user_led1]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports user_led1]
|
||||
## user_led:2
|
||||
set_property PACKAGE_PIN T9 [get_ports user_led2]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports user_led2]
|
||||
## user_led:3
|
||||
set_property PACKAGE_PIN T10 [get_ports user_led3]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports user_led3]
|
||||
## user_sw:0
|
||||
set_property PACKAGE_PIN A8 [get_ports user_sw0]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports user_sw0]
|
||||
## user_sw:1
|
||||
set_property PACKAGE_PIN C11 [get_ports user_sw1]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports user_sw1]
|
||||
## user_sw:2
|
||||
set_property PACKAGE_PIN C10 [get_ports user_sw2]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports user_sw2]
|
||||
## user_sw:3
|
||||
set_property PACKAGE_PIN A10 [get_ports user_sw3]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports user_sw3]
|
||||
## user_btn:0
|
||||
set_property PACKAGE_PIN D9 [get_ports user_btn0]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports user_btn0]
|
||||
## user_btn:1
|
||||
set_property PACKAGE_PIN C9 [get_ports user_btn1]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports user_btn1]
|
||||
## user_btn:2
|
||||
set_property PACKAGE_PIN B9 [get_ports user_btn2]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports user_btn2]
|
||||
## user_btn:3
|
||||
set_property PACKAGE_PIN B8 [get_ports user_btn3]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports user_btn3]
|
||||
## spiflash_1x:0.cs_n
|
||||
#set_property LOC L13 [get_ports spiflash_1x_cs_n]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_cs_n]
|
||||
# ## spiflash_1x:0.mosi
|
||||
#set_property LOC K17 [get_ports spiflash_1x_mosi]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_mosi]
|
||||
# ## spiflash_1x:0.miso
|
||||
#set_property LOC K18 [get_ports spiflash_1x_miso]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_miso]
|
||||
# ## spiflash_1x:0.wp
|
||||
#set_property LOC L14 [get_ports spiflash_1x_wp]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_wp]
|
||||
# ## spiflash_1x:0.hold
|
||||
#set_property LOC M14 [get_ports spiflash_1x_hold]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_hold]
|
||||
# ## ddram:0.a
|
||||
#set_property LOC R2 [get_ports ddram_a[0]]
|
||||
#set_property SLEW FAST [get_ports ddram_a[0]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_a[0]]
|
||||
# ## ddram:0.a
|
||||
#set_property LOC M6 [get_ports ddram_a[1]]
|
||||
#set_property SLEW FAST [get_ports ddram_a[1]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_a[1]]
|
||||
# ## ddram:0.a
|
||||
#set_property LOC N4 [get_ports ddram_a[2]]
|
||||
#set_property SLEW FAST [get_ports ddram_a[2]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_a[2]]
|
||||
# ## ddram:0.a
|
||||
#set_property LOC T1 [get_ports ddram_a[3]]
|
||||
#set_property SLEW FAST [get_ports ddram_a[3]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_a[3]]
|
||||
# ## ddram:0.a
|
||||
#set_property LOC N6 [get_ports ddram_a[4]]
|
||||
#set_property SLEW FAST [get_ports ddram_a[4]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_a[4]]
|
||||
# ## ddram:0.a
|
||||
#set_property LOC R7 [get_ports ddram_a[5]]
|
||||
#set_property SLEW FAST [get_ports ddram_a[5]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_a[5]]
|
||||
# ## ddram:0.a
|
||||
#set_property LOC V6 [get_ports ddram_a[6]]
|
||||
#set_property SLEW FAST [get_ports ddram_a[6]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_a[6]]
|
||||
# ## ddram:0.a
|
||||
#set_property LOC U7 [get_ports ddram_a[7]]
|
||||
#set_property SLEW FAST [get_ports ddram_a[7]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_a[7]]
|
||||
# ## ddram:0.a
|
||||
#set_property LOC R8 [get_ports ddram_a[8]]
|
||||
#set_property SLEW FAST [get_ports ddram_a[8]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_a[8]]
|
||||
# ## ddram:0.a
|
||||
#set_property LOC V7 [get_ports ddram_a[9]]
|
||||
#set_property SLEW FAST [get_ports ddram_a[9]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_a[9]]
|
||||
# ## ddram:0.a
|
||||
#set_property LOC R6 [get_ports ddram_a[10]]
|
||||
#set_property SLEW FAST [get_ports ddram_a[10]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_a[10]]
|
||||
# ## ddram:0.a
|
||||
#set_property LOC U6 [get_ports ddram_a[11]]
|
||||
#set_property SLEW FAST [get_ports ddram_a[11]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_a[11]]
|
||||
# ## ddram:0.a
|
||||
#set_property LOC T6 [get_ports ddram_a[12]]
|
||||
#set_property SLEW FAST [get_ports ddram_a[12]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_a[12]]
|
||||
# ## ddram:0.a
|
||||
#set_property LOC T8 [get_ports ddram_a[13]]
|
||||
#set_property SLEW FAST [get_ports ddram_a[13]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_a[13]]
|
||||
# ## ddram:0.ba
|
||||
#set_property LOC R1 [get_ports ddram_ba[0]]
|
||||
#set_property SLEW FAST [get_ports ddram_ba[0]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_ba[0]]
|
||||
# ## ddram:0.ba
|
||||
#set_property LOC P4 [get_ports ddram_ba[1]]
|
||||
#set_property SLEW FAST [get_ports ddram_ba[1]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_ba[1]]
|
||||
# ## ddram:0.ba
|
||||
#set_property LOC P2 [get_ports ddram_ba[2]]
|
||||
#set_property SLEW FAST [get_ports ddram_ba[2]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_ba[2]]
|
||||
# ## ddram:0.ras_n
|
||||
#set_property LOC P3 [get_ports ddram_ras_n]
|
||||
#set_property SLEW FAST [get_ports ddram_ras_n]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_ras_n]
|
||||
# ## ddram:0.cas_n
|
||||
#set_property LOC M4 [get_ports ddram_cas_n]
|
||||
#set_property SLEW FAST [get_ports ddram_cas_n]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_cas_n]
|
||||
# ## ddram:0.we_n
|
||||
#set_property LOC P5 [get_ports ddram_we_n]
|
||||
#set_property SLEW FAST [get_ports ddram_we_n]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_we_n]
|
||||
# ## ddram:0.cs_n
|
||||
#set_property LOC U8 [get_ports ddram_cs_n]
|
||||
#set_property SLEW FAST [get_ports ddram_cs_n]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_cs_n]
|
||||
# ## ddram:0.dm
|
||||
#set_property LOC L1 [get_ports ddram_dm[0]]
|
||||
#set_property SLEW FAST [get_ports ddram_dm[0]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dm[0]]
|
||||
# ## ddram:0.dm
|
||||
#set_property LOC U1 [get_ports ddram_dm[1]]
|
||||
#set_property SLEW FAST [get_ports ddram_dm[1]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dm[1]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC K5 [get_ports ddram_dq[0]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[0]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[0]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[0]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC L3 [get_ports ddram_dq[1]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[1]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[1]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[1]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC K3 [get_ports ddram_dq[2]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[2]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[2]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[2]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC L6 [get_ports ddram_dq[3]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[3]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[3]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[3]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC M3 [get_ports ddram_dq[4]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[4]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[4]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[4]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC M1 [get_ports ddram_dq[5]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[5]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[5]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[5]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC L4 [get_ports ddram_dq[6]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[6]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[6]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[6]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC M2 [get_ports ddram_dq[7]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[7]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[7]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[7]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC V4 [get_ports ddram_dq[8]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[8]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[8]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[8]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC T5 [get_ports ddram_dq[9]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[9]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[9]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[9]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC U4 [get_ports ddram_dq[10]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[10]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[10]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[10]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC V5 [get_ports ddram_dq[11]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[11]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[11]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[11]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC V1 [get_ports ddram_dq[12]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[12]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[12]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[12]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC T3 [get_ports ddram_dq[13]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[13]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[13]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[13]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC U3 [get_ports ddram_dq[14]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[14]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[14]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[14]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC R3 [get_ports ddram_dq[15]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[15]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[15]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[15]]
|
||||
# ## ddram:0.dqs_p
|
||||
#set_property LOC N2 [get_ports ddram_dqs_p[0]]
|
||||
#set_property SLEW FAST [get_ports ddram_dqs_p[0]]
|
||||
#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_p[0]]
|
||||
# ## ddram:0.dqs_p
|
||||
#set_property LOC U2 [get_ports ddram_dqs_p[1]]
|
||||
#set_property SLEW FAST [get_ports ddram_dqs_p[1]]
|
||||
#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_p[1]]
|
||||
# ## ddram:0.dqs_n
|
||||
#set_property LOC N1 [get_ports ddram_dqs_n[0]]
|
||||
#set_property SLEW FAST [get_ports ddram_dqs_n[0]]
|
||||
#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_n[0]]
|
||||
# ## ddram:0.dqs_n
|
||||
#set_property LOC V2 [get_ports ddram_dqs_n[1]]
|
||||
#set_property SLEW FAST [get_ports ddram_dqs_n[1]]
|
||||
#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_n[1]]
|
||||
# ## ddram:0.clk_p
|
||||
#set_property LOC U9 [get_ports ddram_clk_p]
|
||||
#set_property SLEW FAST [get_ports ddram_clk_p]
|
||||
#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_clk_p]
|
||||
# ## ddram:0.clk_n
|
||||
#set_property LOC V9 [get_ports ddram_clk_n]
|
||||
#set_property SLEW FAST [get_ports ddram_clk_n]
|
||||
#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_clk_n]
|
||||
# ## ddram:0.cke
|
||||
#set_property LOC N5 [get_ports ddram_cke]
|
||||
#set_property SLEW FAST [get_ports ddram_cke]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_cke]
|
||||
# ## ddram:0.odt
|
||||
#set_property LOC R5 [get_ports ddram_odt]
|
||||
#set_property SLEW FAST [get_ports ddram_odt]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_odt]
|
||||
# ## ddram:0.reset_n
|
||||
#set_property LOC K6 [get_ports ddram_reset_n]
|
||||
#set_property SLEW FAST [get_ports ddram_reset_n]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_reset_n]
|
||||
# ## eth_clocks:0.tx
|
||||
#set_property LOC H16 [get_ports eth_clocks_tx]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_clocks_tx]
|
||||
# ## eth_clocks:0.rx
|
||||
#set_property LOC F15 [get_ports eth_clocks_rx]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_clocks_rx]
|
||||
# ## eth:0.rst_n
|
||||
#set_property LOC C16 [get_ports eth_rst_n]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_rst_n]
|
||||
# ## eth:0.mdio
|
||||
#set_property LOC K13 [get_ports eth_mdio]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_mdio]
|
||||
# ## eth:0.mdc
|
||||
#set_property LOC F16 [get_ports eth_mdc]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_mdc]
|
||||
# ## eth:0.rx_dv
|
||||
#set_property LOC G16 [get_ports eth_rx_dv]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_dv]
|
||||
# ## eth:0.rx_er
|
||||
#set_property LOC C17 [get_ports eth_rx_er]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_er]
|
||||
# ## eth:0.rx_data
|
||||
#set_property LOC D18 [get_ports eth_rx_data[0]]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[0]]
|
||||
# ## eth:0.rx_data
|
||||
#set_property LOC E17 [get_ports eth_rx_data[1]]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[1]]
|
||||
# ## eth:0.rx_data
|
||||
#set_property LOC E18 [get_ports eth_rx_data[2]]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[2]]
|
||||
# ## eth:0.rx_data
|
||||
#set_property LOC G17 [get_ports eth_rx_data[3]]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[3]]
|
||||
# ## eth:0.tx_en
|
||||
#set_property LOC H15 [get_ports eth_tx_en]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_en]
|
||||
# ## eth:0.tx_data
|
||||
#set_property LOC H14 [get_ports eth_tx_data[0]]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[0]]
|
||||
# ## eth:0.tx_data
|
||||
#set_property LOC J14 [get_ports eth_tx_data[1]]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[1]]
|
||||
# ## eth:0.tx_data
|
||||
#set_property LOC J13 [get_ports eth_tx_data[2]]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[2]]
|
||||
# ## eth:0.tx_data
|
||||
#set_property LOC H17 [get_ports eth_tx_data[3]]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[3]]
|
||||
# ## eth:0.col
|
||||
#set_property LOC D17 [get_ports eth_col]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_col]
|
||||
# ## eth:0.crs
|
||||
#set_property LOC G14 [get_ports eth_crs]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_crs]
|
||||
|
||||
set_property INTERNAL_VREF 0.75 [get_iobanks 34]
|
||||
|
||||
|
||||
create_clock -period 10.000 -name clk100 [get_nets clk100]
|
||||
|
||||
#create_clock -name eth_rx_clk -period 40.0 [get_nets eth_rx_clk]
|
||||
|
||||
#create_clock -name eth_tx_clk -period 40.0 [get_nets eth_tx_clk]
|
||||
|
||||
#set_clock_groups -group [get_clocks -include_generated_clocks -of [get_nets sys_clk]] -group [get_clocks -include_generated_clocks -of [get_nets eth_rx_clk]] -asynchronous
|
||||
|
||||
#set_clock_groups -group [get_clocks -include_generated_clocks -of [get_nets sys_clk]] -group [get_clocks -include_generated_clocks -of [get_nets eth_tx_clk]] -asynchronous
|
||||
|
||||
#set_clock_groups -group [get_clocks -include_generated_clocks -of [get_nets eth_rx_clk]] -group [get_clocks -include_generated_clocks -of [get_nets eth_tx_clk]] -asynchronous
|
||||
|
||||
|
||||
|
||||
|
||||
set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]
|
350
scripts/Murax/arty_a7/arty_a7_org.xdc
Normal file
350
scripts/Murax/arty_a7/arty_a7_org.xdc
Normal file
|
@ -0,0 +1,350 @@
|
|||
## serial:0.tx
|
||||
set_property LOC D10 [get_ports serial_tx]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports serial_tx]
|
||||
## serial:0.rx
|
||||
set_property LOC A9 [get_ports serial_rx]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports serial_rx]
|
||||
## clk100:0
|
||||
set_property LOC E3 [get_ports clk100]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports clk100]
|
||||
## cpu_reset:0
|
||||
set_property LOC C2 [get_ports cpu_reset]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports cpu_reset]
|
||||
## eth_ref_clk:0
|
||||
#set_property LOC G18 [get_ports eth_ref_clk]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_ref_clk]
|
||||
## user_led:0
|
||||
set_property LOC H5 [get_ports user_led0]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports user_led0]
|
||||
## user_led:1
|
||||
set_property LOC J5 [get_ports user_led1]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports user_led1]
|
||||
## user_led:2
|
||||
set_property LOC T9 [get_ports user_led2]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports user_led2]
|
||||
## user_led:3
|
||||
set_property LOC T10 [get_ports user_led3]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports user_led3]
|
||||
## user_sw:0
|
||||
set_property LOC A8 [get_ports user_sw0]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports user_sw0]
|
||||
## user_sw:1
|
||||
set_property LOC C11 [get_ports user_sw1]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports user_sw1]
|
||||
## user_sw:2
|
||||
set_property LOC C10 [get_ports user_sw2]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports user_sw2]
|
||||
## user_sw:3
|
||||
set_property LOC A10 [get_ports user_sw3]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports user_sw3]
|
||||
## user_btn:0
|
||||
set_property LOC D9 [get_ports user_btn0]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports user_btn0]
|
||||
## user_btn:1
|
||||
set_property LOC C9 [get_ports user_btn1]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports user_btn1]
|
||||
## user_btn:2
|
||||
set_property LOC B9 [get_ports user_btn2]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports user_btn2]
|
||||
## user_btn:3
|
||||
set_property LOC B8 [get_ports user_btn3]
|
||||
set_property IOSTANDARD LVCMOS33 [get_ports user_btn3]
|
||||
## spiflash_1x:0.cs_n
|
||||
#set_property LOC L13 [get_ports spiflash_1x_cs_n]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_cs_n]
|
||||
# ## spiflash_1x:0.mosi
|
||||
#set_property LOC K17 [get_ports spiflash_1x_mosi]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_mosi]
|
||||
# ## spiflash_1x:0.miso
|
||||
#set_property LOC K18 [get_ports spiflash_1x_miso]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_miso]
|
||||
# ## spiflash_1x:0.wp
|
||||
#set_property LOC L14 [get_ports spiflash_1x_wp]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_wp]
|
||||
# ## spiflash_1x:0.hold
|
||||
#set_property LOC M14 [get_ports spiflash_1x_hold]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_hold]
|
||||
# ## ddram:0.a
|
||||
#set_property LOC R2 [get_ports ddram_a[0]]
|
||||
#set_property SLEW FAST [get_ports ddram_a[0]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_a[0]]
|
||||
# ## ddram:0.a
|
||||
#set_property LOC M6 [get_ports ddram_a[1]]
|
||||
#set_property SLEW FAST [get_ports ddram_a[1]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_a[1]]
|
||||
# ## ddram:0.a
|
||||
#set_property LOC N4 [get_ports ddram_a[2]]
|
||||
#set_property SLEW FAST [get_ports ddram_a[2]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_a[2]]
|
||||
# ## ddram:0.a
|
||||
#set_property LOC T1 [get_ports ddram_a[3]]
|
||||
#set_property SLEW FAST [get_ports ddram_a[3]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_a[3]]
|
||||
# ## ddram:0.a
|
||||
#set_property LOC N6 [get_ports ddram_a[4]]
|
||||
#set_property SLEW FAST [get_ports ddram_a[4]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_a[4]]
|
||||
# ## ddram:0.a
|
||||
#set_property LOC R7 [get_ports ddram_a[5]]
|
||||
#set_property SLEW FAST [get_ports ddram_a[5]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_a[5]]
|
||||
# ## ddram:0.a
|
||||
#set_property LOC V6 [get_ports ddram_a[6]]
|
||||
#set_property SLEW FAST [get_ports ddram_a[6]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_a[6]]
|
||||
# ## ddram:0.a
|
||||
#set_property LOC U7 [get_ports ddram_a[7]]
|
||||
#set_property SLEW FAST [get_ports ddram_a[7]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_a[7]]
|
||||
# ## ddram:0.a
|
||||
#set_property LOC R8 [get_ports ddram_a[8]]
|
||||
#set_property SLEW FAST [get_ports ddram_a[8]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_a[8]]
|
||||
# ## ddram:0.a
|
||||
#set_property LOC V7 [get_ports ddram_a[9]]
|
||||
#set_property SLEW FAST [get_ports ddram_a[9]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_a[9]]
|
||||
# ## ddram:0.a
|
||||
#set_property LOC R6 [get_ports ddram_a[10]]
|
||||
#set_property SLEW FAST [get_ports ddram_a[10]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_a[10]]
|
||||
# ## ddram:0.a
|
||||
#set_property LOC U6 [get_ports ddram_a[11]]
|
||||
#set_property SLEW FAST [get_ports ddram_a[11]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_a[11]]
|
||||
# ## ddram:0.a
|
||||
#set_property LOC T6 [get_ports ddram_a[12]]
|
||||
#set_property SLEW FAST [get_ports ddram_a[12]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_a[12]]
|
||||
# ## ddram:0.a
|
||||
#set_property LOC T8 [get_ports ddram_a[13]]
|
||||
#set_property SLEW FAST [get_ports ddram_a[13]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_a[13]]
|
||||
# ## ddram:0.ba
|
||||
#set_property LOC R1 [get_ports ddram_ba[0]]
|
||||
#set_property SLEW FAST [get_ports ddram_ba[0]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_ba[0]]
|
||||
# ## ddram:0.ba
|
||||
#set_property LOC P4 [get_ports ddram_ba[1]]
|
||||
#set_property SLEW FAST [get_ports ddram_ba[1]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_ba[1]]
|
||||
# ## ddram:0.ba
|
||||
#set_property LOC P2 [get_ports ddram_ba[2]]
|
||||
#set_property SLEW FAST [get_ports ddram_ba[2]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_ba[2]]
|
||||
# ## ddram:0.ras_n
|
||||
#set_property LOC P3 [get_ports ddram_ras_n]
|
||||
#set_property SLEW FAST [get_ports ddram_ras_n]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_ras_n]
|
||||
# ## ddram:0.cas_n
|
||||
#set_property LOC M4 [get_ports ddram_cas_n]
|
||||
#set_property SLEW FAST [get_ports ddram_cas_n]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_cas_n]
|
||||
# ## ddram:0.we_n
|
||||
#set_property LOC P5 [get_ports ddram_we_n]
|
||||
#set_property SLEW FAST [get_ports ddram_we_n]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_we_n]
|
||||
# ## ddram:0.cs_n
|
||||
#set_property LOC U8 [get_ports ddram_cs_n]
|
||||
#set_property SLEW FAST [get_ports ddram_cs_n]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_cs_n]
|
||||
# ## ddram:0.dm
|
||||
#set_property LOC L1 [get_ports ddram_dm[0]]
|
||||
#set_property SLEW FAST [get_ports ddram_dm[0]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dm[0]]
|
||||
# ## ddram:0.dm
|
||||
#set_property LOC U1 [get_ports ddram_dm[1]]
|
||||
#set_property SLEW FAST [get_ports ddram_dm[1]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dm[1]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC K5 [get_ports ddram_dq[0]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[0]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[0]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[0]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC L3 [get_ports ddram_dq[1]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[1]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[1]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[1]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC K3 [get_ports ddram_dq[2]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[2]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[2]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[2]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC L6 [get_ports ddram_dq[3]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[3]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[3]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[3]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC M3 [get_ports ddram_dq[4]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[4]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[4]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[4]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC M1 [get_ports ddram_dq[5]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[5]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[5]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[5]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC L4 [get_ports ddram_dq[6]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[6]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[6]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[6]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC M2 [get_ports ddram_dq[7]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[7]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[7]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[7]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC V4 [get_ports ddram_dq[8]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[8]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[8]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[8]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC T5 [get_ports ddram_dq[9]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[9]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[9]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[9]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC U4 [get_ports ddram_dq[10]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[10]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[10]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[10]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC V5 [get_ports ddram_dq[11]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[11]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[11]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[11]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC V1 [get_ports ddram_dq[12]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[12]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[12]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[12]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC T3 [get_ports ddram_dq[13]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[13]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[13]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[13]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC U3 [get_ports ddram_dq[14]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[14]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[14]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[14]]
|
||||
# ## ddram:0.dq
|
||||
#set_property LOC R3 [get_ports ddram_dq[15]]
|
||||
#set_property SLEW FAST [get_ports ddram_dq[15]]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[15]]
|
||||
#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[15]]
|
||||
# ## ddram:0.dqs_p
|
||||
#set_property LOC N2 [get_ports ddram_dqs_p[0]]
|
||||
#set_property SLEW FAST [get_ports ddram_dqs_p[0]]
|
||||
#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_p[0]]
|
||||
# ## ddram:0.dqs_p
|
||||
#set_property LOC U2 [get_ports ddram_dqs_p[1]]
|
||||
#set_property SLEW FAST [get_ports ddram_dqs_p[1]]
|
||||
#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_p[1]]
|
||||
# ## ddram:0.dqs_n
|
||||
#set_property LOC N1 [get_ports ddram_dqs_n[0]]
|
||||
#set_property SLEW FAST [get_ports ddram_dqs_n[0]]
|
||||
#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_n[0]]
|
||||
# ## ddram:0.dqs_n
|
||||
#set_property LOC V2 [get_ports ddram_dqs_n[1]]
|
||||
#set_property SLEW FAST [get_ports ddram_dqs_n[1]]
|
||||
#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_n[1]]
|
||||
# ## ddram:0.clk_p
|
||||
#set_property LOC U9 [get_ports ddram_clk_p]
|
||||
#set_property SLEW FAST [get_ports ddram_clk_p]
|
||||
#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_clk_p]
|
||||
# ## ddram:0.clk_n
|
||||
#set_property LOC V9 [get_ports ddram_clk_n]
|
||||
#set_property SLEW FAST [get_ports ddram_clk_n]
|
||||
#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_clk_n]
|
||||
# ## ddram:0.cke
|
||||
#set_property LOC N5 [get_ports ddram_cke]
|
||||
#set_property SLEW FAST [get_ports ddram_cke]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_cke]
|
||||
# ## ddram:0.odt
|
||||
#set_property LOC R5 [get_ports ddram_odt]
|
||||
#set_property SLEW FAST [get_ports ddram_odt]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_odt]
|
||||
# ## ddram:0.reset_n
|
||||
#set_property LOC K6 [get_ports ddram_reset_n]
|
||||
#set_property SLEW FAST [get_ports ddram_reset_n]
|
||||
#set_property IOSTANDARD SSTL15 [get_ports ddram_reset_n]
|
||||
# ## eth_clocks:0.tx
|
||||
#set_property LOC H16 [get_ports eth_clocks_tx]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_clocks_tx]
|
||||
# ## eth_clocks:0.rx
|
||||
#set_property LOC F15 [get_ports eth_clocks_rx]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_clocks_rx]
|
||||
# ## eth:0.rst_n
|
||||
#set_property LOC C16 [get_ports eth_rst_n]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_rst_n]
|
||||
# ## eth:0.mdio
|
||||
#set_property LOC K13 [get_ports eth_mdio]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_mdio]
|
||||
# ## eth:0.mdc
|
||||
#set_property LOC F16 [get_ports eth_mdc]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_mdc]
|
||||
# ## eth:0.rx_dv
|
||||
#set_property LOC G16 [get_ports eth_rx_dv]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_dv]
|
||||
# ## eth:0.rx_er
|
||||
#set_property LOC C17 [get_ports eth_rx_er]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_er]
|
||||
# ## eth:0.rx_data
|
||||
#set_property LOC D18 [get_ports eth_rx_data[0]]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[0]]
|
||||
# ## eth:0.rx_data
|
||||
#set_property LOC E17 [get_ports eth_rx_data[1]]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[1]]
|
||||
# ## eth:0.rx_data
|
||||
#set_property LOC E18 [get_ports eth_rx_data[2]]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[2]]
|
||||
# ## eth:0.rx_data
|
||||
#set_property LOC G17 [get_ports eth_rx_data[3]]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[3]]
|
||||
# ## eth:0.tx_en
|
||||
#set_property LOC H15 [get_ports eth_tx_en]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_en]
|
||||
# ## eth:0.tx_data
|
||||
#set_property LOC H14 [get_ports eth_tx_data[0]]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[0]]
|
||||
# ## eth:0.tx_data
|
||||
#set_property LOC J14 [get_ports eth_tx_data[1]]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[1]]
|
||||
# ## eth:0.tx_data
|
||||
#set_property LOC J13 [get_ports eth_tx_data[2]]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[2]]
|
||||
# ## eth:0.tx_data
|
||||
#set_property LOC H17 [get_ports eth_tx_data[3]]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[3]]
|
||||
# ## eth:0.col
|
||||
#set_property LOC D17 [get_ports eth_col]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_col]
|
||||
# ## eth:0.crs
|
||||
#set_property LOC G14 [get_ports eth_crs]
|
||||
#set_property IOSTANDARD LVCMOS33 [get_ports eth_crs]
|
||||
|
||||
set_property INTERNAL_VREF 0.750 [get_iobanks 34]
|
||||
|
||||
create_clock -name sys_clk -period 10.0 [get_nets sys_clk]
|
||||
|
||||
create_clock -name clk100 -period 10.0 [get_nets clk100]
|
||||
|
||||
#create_clock -name eth_rx_clk -period 40.0 [get_nets eth_rx_clk]
|
||||
|
||||
#create_clock -name eth_tx_clk -period 40.0 [get_nets eth_tx_clk]
|
||||
|
||||
#set_clock_groups -group [get_clocks -include_generated_clocks -of [get_nets sys_clk]] -group [get_clocks -include_generated_clocks -of [get_nets eth_rx_clk]] -asynchronous
|
||||
|
||||
#set_clock_groups -group [get_clocks -include_generated_clocks -of [get_nets sys_clk]] -group [get_clocks -include_generated_clocks -of [get_nets eth_tx_clk]] -asynchronous
|
||||
|
||||
#set_clock_groups -group [get_clocks -include_generated_clocks -of [get_nets eth_rx_clk]] -group [get_clocks -include_generated_clocks -of [get_nets eth_tx_clk]] -asynchronous
|
||||
|
||||
set_false_path -quiet -to [get_nets -quiet -filter {mr_ff == TRUE}]
|
||||
|
||||
set_false_path -quiet -to [get_pins -quiet -filter {REF_PIN_NAME == PRE} -of [get_cells -quiet -filter {ars_ff1 == TRUE || ars_ff2 == TRUE}]]
|
||||
|
||||
set_max_delay 2 -quiet -from [get_pins -quiet -filter {REF_PIN_NAME == Q} -of [get_cells -quiet -filter {ars_ff1 == TRUE}]] -to [get_pins -quiet -filter {REF_PIN_NAME == D} -of [get_cells -quiet -filter {ars_ff2 == TRUE}]]
|
50
scripts/Murax/arty_a7/make_bit_file.tcl
Normal file
50
scripts/Murax/arty_a7/make_bit_file.tcl
Normal file
|
@ -0,0 +1,50 @@
|
|||
|
||||
# Input files
|
||||
set mmi_file "./soc.mmi"
|
||||
set elf_file "./soc.elf"
|
||||
set source_bit_file "./soc.bit"
|
||||
|
||||
# Output files
|
||||
set output_bit_file "./soc_latest_sw.bit"
|
||||
|
||||
# Enable to turn on debug
|
||||
set updatemem_debug 0
|
||||
|
||||
# Assemble bit file that can be downloaded to device directly
|
||||
# Combine the original bit file, mmi file, and software elf to create the full bitstream
|
||||
|
||||
# Delete target file
|
||||
file delete -force $output_bit_file
|
||||
|
||||
# Determine if the user has built the project and has the target source file
|
||||
# If not, then use the reference bit file shipped with the project
|
||||
if { ![file exists $source_bit_file] } {
|
||||
puts "\n********************************************"
|
||||
puts "INFO - File $source_bit_file doesn't exist as project has not been built"
|
||||
puts " Using $reference_bit_file instead\n"
|
||||
puts "********************************************/n"
|
||||
set source_bit_file $reference_bit_file
|
||||
}
|
||||
|
||||
# Banner message to console as there is no output for a few seconds
|
||||
puts " Running updatemem ..."
|
||||
|
||||
if { $updatemem_debug } {
|
||||
set error [catch {exec updatemem --debug --force --meminfo $mmi_file --data $elf_file --bit $source_bit_file --proc dummy --out $output_bit_file} result]
|
||||
} else {
|
||||
set error [catch {exec updatemem --force --meminfo $mmi_file --data $elf_file --bit $source_bit_file --proc dummy --out $output_bit_file} result]
|
||||
}
|
||||
|
||||
# Print the stdout from updatemem
|
||||
puts $result
|
||||
|
||||
# Updatemem returns 0 even when there is an error, so cannot trap on error. Having deleted output file to start, then
|
||||
# detect if it now exists, else exit.
|
||||
if { ![file exists $output_bit_file] } {
|
||||
puts "ERROR - $output_bit_file not made"
|
||||
return -1
|
||||
} else {
|
||||
puts "\n********************************************"
|
||||
puts " $output_bit_file correctly generated"
|
||||
puts "********************************************\n"
|
||||
}
|
6
scripts/Murax/arty_a7/make_mcs_file
Executable file
6
scripts/Murax/arty_a7/make_mcs_file
Executable file
|
@ -0,0 +1,6 @@
|
|||
#!/bin/sh
|
||||
#Create mcs file for QSPI flash
|
||||
|
||||
cd ./build
|
||||
|
||||
vivado -mode batch -source ../make_mcs_file.tcl -notrace
|
31
scripts/Murax/arty_a7/make_mcs_file.tcl
Normal file
31
scripts/Murax/arty_a7/make_mcs_file.tcl
Normal file
|
@ -0,0 +1,31 @@
|
|||
|
||||
# Input file
|
||||
set source_bit_file "./latest.bit"
|
||||
|
||||
# Output file
|
||||
set output_mcs_file "./latest.mcs"
|
||||
|
||||
# Delete target file
|
||||
file delete -force $output_mcs_file
|
||||
|
||||
# Determine if the user has built the project and has the target source file
|
||||
# If not, then use the reference bit file shipped with the project
|
||||
if { ![file exists $source_bit_file] } {
|
||||
puts "\n********************************************"
|
||||
puts "INFO - File $source_bit_file doesn't exist as project has not been built\n"
|
||||
puts "********************************************/n"
|
||||
error
|
||||
}
|
||||
|
||||
# Create MCS file for base board QSPI flash memory
|
||||
write_cfgmem -force -format MCS -size 16 -interface SPIx4 -loadbit " up 0 $source_bit_file" $output_mcs_file
|
||||
|
||||
# Check MCS was correctly made
|
||||
if { ![file exists $output_mcs_file] } {
|
||||
puts "ERROR - $output_bit_file not made"
|
||||
return -1
|
||||
} else {
|
||||
puts "\n********************************************"
|
||||
puts " $output_mcs_file correctly generated"
|
||||
puts "********************************************\n"
|
||||
}
|
4
scripts/Murax/arty_a7/make_mmi_files
Executable file
4
scripts/Murax/arty_a7/make_mmi_files
Executable file
|
@ -0,0 +1,4 @@
|
|||
#!/bin/sh
|
||||
|
||||
cd ./build
|
||||
vivado -mode batch -source ../make_mmi_files.tcl -notrace
|
6
scripts/Murax/arty_a7/make_mmi_files.tcl
Normal file
6
scripts/Murax/arty_a7/make_mmi_files.tcl
Normal file
|
@ -0,0 +1,6 @@
|
|||
source [file join [file dirname [file normalize [info script]]] vivado_params.tcl]
|
||||
|
||||
open_project -read_only $outputdir/$projectName
|
||||
open_run impl_1
|
||||
source $base/soc_mmi.tcl
|
||||
puts "mmi files generated"
|
9
scripts/Murax/arty_a7/make_vivado_project
Executable file
9
scripts/Murax/arty_a7/make_vivado_project
Executable file
|
@ -0,0 +1,9 @@
|
|||
#!/bin/sh
|
||||
|
||||
#cannot rm build because it erase software images that the make file copy there
|
||||
#rm -rf ./build
|
||||
|
||||
mkdir -p ./build
|
||||
|
||||
cd ./build
|
||||
vivado -mode batch -source ../make_vivado_project.tcl -notrace
|
46
scripts/Murax/arty_a7/make_vivado_project.tcl
Normal file
46
scripts/Murax/arty_a7/make_vivado_project.tcl
Normal file
|
@ -0,0 +1,46 @@
|
|||
#Create output directory and clear contents
|
||||
source [file join [file dirname [file normalize [info script]]] vivado_params.tcl]
|
||||
|
||||
file mkdir $outputdir
|
||||
set files [glob -nocomplain "$outputdir/*"]
|
||||
if {[llength $files] != 0} {
|
||||
puts "deleting contents of $outputdir"
|
||||
file delete -force {*}[glob -directory $outputdir *]; # clear folder contents
|
||||
} else {
|
||||
puts "$outputdir is empty"
|
||||
}
|
||||
|
||||
#Create project
|
||||
create_project -part $part $projectName $outputdir
|
||||
|
||||
#add source files to Vivado project
|
||||
#add_files -fileset sim_1 ./path/to/testbench.vhd
|
||||
#add_files [glob ./path/to/sources/*.vhd]
|
||||
#add_files -fileset constrs_1 ./path/to/constraint/constraint.xdc
|
||||
#add_files [glob ./path/to/library/sources/*.vhd]
|
||||
#set_property -library userDefined [glob ./path/to/library/sources/*.vhd]
|
||||
add_files [glob $base/*.v]
|
||||
add_files [glob $topv]
|
||||
add_files -fileset constrs_1 $base/arty_a7.xdc
|
||||
|
||||
#set top level module and update compile order
|
||||
set_property top toplevel [current_fileset]
|
||||
update_compile_order -fileset sources_1
|
||||
#update_compile_order -fileset sim_1
|
||||
|
||||
#launch synthesis
|
||||
launch_runs synth_1
|
||||
wait_on_run synth_1
|
||||
|
||||
#Run implementation and generate bitstream
|
||||
set_property STEPS.PHYS_OPT_DESIGN.IS_ENABLED true [get_runs impl_1]
|
||||
launch_runs impl_1 -to_step write_bitstream
|
||||
wait_on_run impl_1
|
||||
puts "Implementation done!"
|
||||
|
||||
#reports generated by default
|
||||
#open_run impl_1
|
||||
#report_timing_summary -check_timing_verbose -report_unconstrained -file report_timing_summary.rpt
|
||||
#report_utilization -hierarchical -file report_utilization.rpt
|
||||
|
||||
#TODO: add checks about timing, DRC, CDC such that the script give clear indication if design is OK or not
|
62
scripts/Murax/arty_a7/makefile
Normal file
62
scripts/Murax/arty_a7/makefile
Normal file
|
@ -0,0 +1,62 @@
|
|||
ROOT=../../..
|
||||
SWBASE=$(ROOT)/src/main/c/murax
|
||||
SOCSW=hello_world
|
||||
SOCMEMSRC=$(SWBASE)/$(SOCSW)/build/$(SOCSW).v
|
||||
SOCMEM=build/soc.mem
|
||||
|
||||
TOP=Murax
|
||||
|
||||
all : build/latest.bit
|
||||
|
||||
../../../$(TOP).v : toplevel.v
|
||||
(cd ../../..; sbt "runMain vexriscv.demo.Murax_arty")
|
||||
|
||||
.PHONY: $(SOCMEMSRC)
|
||||
$(SOCMEMSRC):
|
||||
mkdir -p build
|
||||
make -C $(SWBASE)/$(SOCSW)
|
||||
|
||||
$(SOCMEM) : $(SOCMEMSRC)
|
||||
cp -u $(SOCMEMSRC) $(SOCMEM)
|
||||
|
||||
build/vivado_project/fpga.runs/impl_1/toplevel.bit : toplevel.v arty_a7.xdc ../../../$(TOP).v
|
||||
mkdir -p build
|
||||
./make_vivado_project
|
||||
cp build/vivado_project/fpga.runs/impl_1/toplevel.bit build/latest.bit
|
||||
|
||||
build/soc.mmi: build/vivado_project/fpga.runs/impl_1/toplevel.bit
|
||||
./make_mmi_files
|
||||
|
||||
build/latest_soc_sw.bit : $(SOCMEM) build/soc.mmi
|
||||
rm -f updatemem.jou updatemem.log
|
||||
updatemem -force --meminfo build/soc.mmi --data $(SOCMEM) --bit build/latest.bit --proc dummy --out build/latest_soc_sw.bit
|
||||
cp build/latest_soc_sw.bit build/latest.bit
|
||||
|
||||
build/latest.bit : build/latest_soc_sw.bit
|
||||
|
||||
build/latest.mcs : build/latest.bit
|
||||
./make_mcs_file
|
||||
|
||||
prog : build/latest.bit
|
||||
./write_fpga
|
||||
|
||||
flash : build/latest.mcs
|
||||
./write_flash
|
||||
|
||||
clean-soc-sw:
|
||||
make -C $(SWBASE)/$(SOCSW) clean-all
|
||||
|
||||
soc-sw: clean-soc-sw $(SOCMEM)
|
||||
|
||||
.PHONY: clean
|
||||
clean :
|
||||
rm -rf build
|
||||
mkdir build
|
||||
rm -f updatemem.jou
|
||||
rm -f updatemem.log
|
||||
|
||||
clean-sw: clean-soc-sw
|
||||
|
||||
clean-all : clean clean-sw
|
||||
rm -f ../../../$(TOP).v
|
||||
rm -f ../../../$(TOP).v_*
|
4
scripts/Murax/arty_a7/open_vivado_project
Executable file
4
scripts/Murax/arty_a7/open_vivado_project
Executable file
|
@ -0,0 +1,4 @@
|
|||
#!/bin/sh
|
||||
|
||||
cd ./build
|
||||
vivado -mode batch -source ../open_vivado_project.tcl -notrace
|
4
scripts/Murax/arty_a7/open_vivado_project.tcl
Normal file
4
scripts/Murax/arty_a7/open_vivado_project.tcl
Normal file
|
@ -0,0 +1,4 @@
|
|||
source [file join [file dirname [file normalize [info script]]] vivado_params.tcl]
|
||||
|
||||
open_project -read_only $outputdir/$projectName
|
||||
start_gui
|
1
scripts/Murax/arty_a7/picocom_arty
Normal file
1
scripts/Murax/arty_a7/picocom_arty
Normal file
|
@ -0,0 +1 @@
|
|||
picocom --baud 115200 --imap lfcrlf /dev/ttyUSB1
|
151
scripts/Murax/arty_a7/soc_mmi.tcl
Normal file
151
scripts/Murax/arty_a7/soc_mmi.tcl
Normal file
|
@ -0,0 +1,151 @@
|
|||
#script to update the init values of RAM without re-synthesis
|
||||
|
||||
if {![info exists mmi_file]} {
|
||||
# Set MMI output file name
|
||||
set mmi_file "soc.mmi"
|
||||
}
|
||||
if {![info exists part]} {
|
||||
set part "xc7a35ticsg324-1L"
|
||||
}
|
||||
|
||||
# Function to swap bits
|
||||
proc swap_bits { bit } {
|
||||
|
||||
if { $bit > 23 } {return [expr {24 + (31 - $bit)}]}
|
||||
if { $bit > 15 } {return [expr {16 + (23 - $bit)}]}
|
||||
if { $bit > 7 } {return [expr {8 + (15 - $bit)}]}
|
||||
return [expr {7 - $bit}]
|
||||
}
|
||||
|
||||
# If run from batch file, will need to open project, then open the run
|
||||
# open_run impl_1
|
||||
|
||||
# Find all the RAMs, place in a list
|
||||
set rams [get_cells -hier -regexp {.*core/system_ram/.*} -filter {REF_NAME == RAMB36E1 || REF_NAME == RAMB18E1}]
|
||||
|
||||
puts "[llength $rams] RAMs in total"
|
||||
foreach m $rams {puts $m}
|
||||
|
||||
set mems [dict create]
|
||||
foreach m $rams {
|
||||
set numbers [regexp -all -inline -- {[0-9]+} $m]
|
||||
dict set mems $numbers $m
|
||||
}
|
||||
set keys [dict keys $mems]
|
||||
#set keys [lsort -integer $keys]
|
||||
set rams []
|
||||
foreach key $keys {
|
||||
set m [dict get $mems $key]
|
||||
puts "$key -> $m"
|
||||
lappend rams $m
|
||||
}
|
||||
|
||||
puts "after sort:"
|
||||
foreach m $rams {puts $m}
|
||||
puts $rams
|
||||
|
||||
if { [llength $rams] == 0 } {
|
||||
puts "Error - no memories found"
|
||||
return -1
|
||||
}
|
||||
|
||||
if { [expr {[llength $rams] % 4}] != 0 } {
|
||||
puts "Error - Number of memories not divisible by 4"
|
||||
return -1
|
||||
}
|
||||
|
||||
set size_bytes [expr {4096*[llength $rams]}]
|
||||
puts "Instruction memory size $size_bytes"
|
||||
|
||||
# Currently only support memory sizes between 16kB, (one byte per mem), and 128kB, (one bit per mem)
|
||||
if { ($size_bytes < (4*4096)) || ($size_bytes > (32*4096)) } {
|
||||
puts "Error - Memory size of $size_bytes out of range"
|
||||
puts " Script only supports memory sizes between 16kB and 128kB"
|
||||
return -1
|
||||
}
|
||||
|
||||
# Create and open target mmi file
|
||||
set fp [open $mmi_file {WRONLY CREAT TRUNC}]
|
||||
if { $fp == 0 } {
|
||||
puts "Error - Unable to open $mmi_file for writing"
|
||||
return -1
|
||||
}
|
||||
|
||||
# Write the file header
|
||||
puts $fp "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
|
||||
puts $fp "<MemInfo Version=\"1\" Minor=\"15\">"
|
||||
puts $fp " <Processor Endianness=\"ignored\" InstPath=\"dummy\">"
|
||||
puts $fp " <AddressSpace Name=\"soc_side\" Begin=\"[expr {0x80000000}]\" End=\"[expr {0x80000000 + $size_bytes-1}]\">"
|
||||
puts $fp " <BusBlock>"
|
||||
|
||||
# Calculate the expected number of bits per memory
|
||||
set mem_bits [expr {32/[llength $rams]}]
|
||||
|
||||
puts "mem_bits = $mem_bits"
|
||||
|
||||
set mem_info [dict create]
|
||||
|
||||
set i 0
|
||||
foreach ram $rams {
|
||||
# Get the RAM location
|
||||
set loc_val [get_property LOC [get_cells $ram]]
|
||||
regexp {(RAMB.+_)([0-9XY]+)} $loc_val full ram_name loc_xy
|
||||
|
||||
set memi [dict create ram $ram loc $loc_xy]
|
||||
|
||||
set numbers [regexp -all -inline -- {[0-9]+} $ram]
|
||||
if { [llength $numbers] == 2 } {
|
||||
dict lappend mem_info [lindex $numbers 0] $memi
|
||||
} else {
|
||||
dict lappend mem_info [expr $i/4] $memi
|
||||
}
|
||||
incr i
|
||||
}
|
||||
|
||||
set sorted_mem_info [dict create]
|
||||
foreach {idx mems} $mem_info {
|
||||
foreach mem [lreverse $mems] {
|
||||
dict lappend sorted_mem_info $idx $mem
|
||||
}
|
||||
}
|
||||
foreach mems $sorted_mem_info {
|
||||
foreach mem $mems {
|
||||
puts $mem
|
||||
}
|
||||
}
|
||||
|
||||
set lsb 0
|
||||
set memlen [ expr 4096*8 / $mem_bits ]
|
||||
foreach {idx mems} $sorted_mem_info {
|
||||
puts "idx=$idx"
|
||||
foreach mem $mems {
|
||||
puts "mem=$mem"
|
||||
set ram [dict get $mem ram]
|
||||
set loc [dict get $mem loc]
|
||||
set msb [expr $lsb+$mem_bits-1]
|
||||
set addr_start 0
|
||||
set addr_end [expr $memlen-1]
|
||||
puts "ram=$ram loc=$loc lsb=$lsb msb=$msb addr_start=$addr_start addr_end=$addr_end"
|
||||
puts $fp " <!-- $ram -->"
|
||||
puts $fp " <BitLane MemType=\"RAMB36\" Placement=\"$loc\">"
|
||||
puts $fp " <DataWidth MSB=\"$msb\" LSB=\"$lsb\"/>"
|
||||
puts $fp " <!--not used!--><AddressRange Begin=\"$addr_start\" End=\"$addr_end\"/>"
|
||||
puts $fp " <Parity ON=\"false\" NumBits=\"0\"/>"
|
||||
puts $fp " </BitLane>"
|
||||
|
||||
set lsb [expr ($msb+1)%32]
|
||||
}
|
||||
}
|
||||
|
||||
puts $fp " </BusBlock>"
|
||||
puts $fp " </AddressSpace>"
|
||||
puts $fp " </Processor>"
|
||||
puts $fp " <Config>"
|
||||
puts $fp " <Option Name=\"Part\" Val=\"$part\"/>"
|
||||
puts $fp " </Config>"
|
||||
puts $fp " <DRC>"
|
||||
puts $fp " <Rule Name=\"RDADDRCHANGE\" Val=\"false\"/>"
|
||||
puts $fp " </DRC>"
|
||||
puts $fp "</MemInfo>"
|
||||
|
||||
close $fp
|
66
scripts/Murax/arty_a7/toplevel.v
Normal file
66
scripts/Murax/arty_a7/toplevel.v
Normal file
|
@ -0,0 +1,66 @@
|
|||
`timescale 1ns / 1ps
|
||||
|
||||
module toplevel(
|
||||
input wire clk100,
|
||||
input wire cpu_reset,//active low
|
||||
|
||||
input wire tck,
|
||||
input wire tms,
|
||||
input wire tdi,
|
||||
input wire trst,//ignored
|
||||
output reg tdo,
|
||||
|
||||
input wire serial_rx,
|
||||
output wire serial_tx,
|
||||
|
||||
input wire user_sw0,
|
||||
input wire user_sw1,
|
||||
input wire user_sw2,
|
||||
input wire user_sw3,
|
||||
|
||||
input wire user_btn0,
|
||||
input wire user_btn1,
|
||||
input wire user_btn2,
|
||||
input wire user_btn3,
|
||||
|
||||
output wire user_led0,
|
||||
output wire user_led1,
|
||||
output wire user_led2,
|
||||
output wire user_led3
|
||||
);
|
||||
|
||||
wire [31:0] io_gpioA_read;
|
||||
wire [31:0] io_gpioA_write;
|
||||
wire [31:0] io_gpioA_writeEnable;
|
||||
|
||||
wire io_asyncReset = ~cpu_reset;
|
||||
|
||||
assign {user_led3,user_led2,user_led1,user_led0} = io_gpioA_write[3 : 0];
|
||||
assign io_gpioA_read[3:0] = {user_sw3,user_sw2,user_sw1,user_sw0};
|
||||
assign io_gpioA_read[7:4] = {user_btn3,user_btn2,user_btn1,user_btn0};
|
||||
assign io_gpioA_read[11:8] = {tck,tms,tdi,trst};
|
||||
|
||||
reg tesic_tck,tesic_tms,tesic_tdi;
|
||||
wire tesic_tdo;
|
||||
reg soc_tck,soc_tms,soc_tdi;
|
||||
wire soc_tdo;
|
||||
|
||||
always @(*) begin
|
||||
{soc_tck, soc_tms, soc_tdi } = {tck,tms,tdi};
|
||||
tdo = soc_tdo;
|
||||
end
|
||||
|
||||
Murax core (
|
||||
.io_asyncReset(io_asyncReset),
|
||||
.io_mainClk (clk100 ),
|
||||
.io_jtag_tck(soc_tck),
|
||||
.io_jtag_tdi(soc_tdi),
|
||||
.io_jtag_tdo(soc_tdo),
|
||||
.io_jtag_tms(soc_tms),
|
||||
.io_gpioA_read (io_gpioA_read),
|
||||
.io_gpioA_write (io_gpioA_write),
|
||||
.io_gpioA_writeEnable(io_gpioA_writeEnable),
|
||||
.io_uart_txd(serial_tx),
|
||||
.io_uart_rxd(serial_rx)
|
||||
);
|
||||
endmodule
|
5
scripts/Murax/arty_a7/vivado_params.tcl
Normal file
5
scripts/Murax/arty_a7/vivado_params.tcl
Normal file
|
@ -0,0 +1,5 @@
|
|||
set outputdir ./vivado_project
|
||||
set part "xc7a35ticsg324-1L"
|
||||
set base ".."
|
||||
set projectName "fpga"
|
||||
set topv "$base/../../../Murax.v"
|
3
scripts/Murax/arty_a7/write_flash
Executable file
3
scripts/Murax/arty_a7/write_flash
Executable file
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
cd ./build
|
||||
vivado -mode batch -source ../write_flash.tcl -notrace
|
26
scripts/Murax/arty_a7/write_flash.tcl
Normal file
26
scripts/Murax/arty_a7/write_flash.tcl
Normal file
|
@ -0,0 +1,26 @@
|
|||
|
||||
open_hw
|
||||
connect_hw_server
|
||||
open_hw_target
|
||||
current_hw_device [get_hw_devices xc7a35t_0]
|
||||
refresh_hw_device -update_hw_probes false [lindex [get_hw_devices xc7a35t_0] 0]
|
||||
|
||||
create_hw_cfgmem -hw_device [lindex [get_hw_devices] 0] -mem_dev [lindex [get_cfgmem_parts {s25fl128sxxxxxx0-spi-x1_x2_x4}] 0]
|
||||
set_property PROBES.FILE {} [get_hw_devices xc7a35t_0]
|
||||
set_property FULL_PROBES.FILE {} [get_hw_devices xc7a35t_0]
|
||||
refresh_hw_device [lindex [get_hw_devices xc7a35t_0] 0]
|
||||
set_property PROGRAM.ADDRESS_RANGE {use_file} [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]]
|
||||
set_property PROGRAM.FILES [list "latest.mcs" ] [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]]
|
||||
set_property PROGRAM.PRM_FILE {} [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]]
|
||||
set_property PROGRAM.UNUSED_PIN_TERMINATION {pull-none} [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]]
|
||||
set_property PROGRAM.BLANK_CHECK 0 [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]]
|
||||
set_property PROGRAM.ERASE 1 [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]]
|
||||
set_property PROGRAM.CFG_PROGRAM 1 [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]]
|
||||
set_property PROGRAM.VERIFY 1 [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]]
|
||||
set_property PROGRAM.CHECKSUM 0 [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]]
|
||||
|
||||
if {![string equal [get_property PROGRAM.HW_CFGMEM_TYPE [lindex [get_hw_devices xc7a35t_0] 0]] [get_property MEM_TYPE [get_property CFGMEM_PART [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]]]]] } { create_hw_bitstream -hw_device [lindex [get_hw_devices xc7a35t_0] 0] [get_property PROGRAM.HW_CFGMEM_BITFILE [ lindex [get_hw_devices xc7a35t_0] 0]]; program_hw_devices [lindex [get_hw_devices xc7a35t_0] 0]; };
|
||||
program_hw_cfgmem -hw_cfgmem [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]]
|
||||
|
||||
close_hw_target
|
||||
close_hw
|
3
scripts/Murax/arty_a7/write_fpga
Executable file
3
scripts/Murax/arty_a7/write_fpga
Executable file
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
cd ./build
|
||||
vivado -mode batch -source ../write_fpga.tcl -notrace
|
10
scripts/Murax/arty_a7/write_fpga.tcl
Normal file
10
scripts/Murax/arty_a7/write_fpga.tcl
Normal file
|
@ -0,0 +1,10 @@
|
|||
open_hw
|
||||
connect_hw_server
|
||||
open_hw_target
|
||||
current_hw_device [get_hw_devices xc7a35t_0]
|
||||
refresh_hw_device -update_hw_probes false [lindex [get_hw_devices xc7a35t_0] 0]
|
||||
set_property PROBES.FILE {} [get_hw_devices xc7a35t_0]
|
||||
set_property FULL_PROBES.FILE {} [get_hw_devices xc7a35t_0]
|
||||
set_property PROGRAM.FILE {latest.bit} [get_hw_devices xc7a35t_0]
|
||||
program_hw_devices [get_hw_devices xc7a35t_0]
|
||||
disconnect_hw_server
|
|
@ -1,19 +1,21 @@
|
|||
|
||||
VBASE = ../../..
|
||||
VNAME = Murax_iCE40_hx8k_breakout_board_xip
|
||||
VERILOG = ${VBASE}/${VNAME}.v
|
||||
|
||||
VERILOG = ../../../Murax_iCE40_hx8k_breakout_board_xip.v
|
||||
all: prog
|
||||
|
||||
generate :
|
||||
#(cd ../../..; sbt "runMain vexriscv.demo.Murax_iCE40_hx8k_breakout_board_xip")
|
||||
${VERILOG} :
|
||||
(cd ${VBASE}; sbt "runMain vexriscv.demo.${VNAME}")
|
||||
|
||||
../../../Murax_iCE40_hx8k_breakout_board_xip.v :
|
||||
#(cd ../../..; sbt "runMain vexriscv.demo.Murax_iCE40_hx8k_breakout_board_xip")
|
||||
generate : ${VERILOG}
|
||||
|
||||
../../../Murax_iCE40_hx8k_breakout_board_xip.v*.bin:
|
||||
${VERILOG}*.bin:
|
||||
|
||||
bin/Murax_iCE40_hx8k_breakout_board_xip.blif : ${VERILOG} ../../../Murax_iCE40_hx8k_breakout_board_xip.v*.bin
|
||||
bin/Murax_iCE40_hx8k_breakout_board_xip.blif : ${VERILOG} ${VERILOG}*.bin
|
||||
mkdir -p bin
|
||||
rm -f Murax_iCE40_hx8k_breakout_board_xip.v*.bin
|
||||
cp ../../../Murax_iCE40_hx8k_breakout_board_xip.v*.bin . | true
|
||||
cp ${VERILOG}*.bin . | true
|
||||
yosys -v3 -p "synth_ice40 -top Murax_iCE40_hx8k_breakout_board_xip -blif bin/Murax_iCE40_hx8k_breakout_board_xip.blif" ${VERILOG}
|
||||
|
||||
bin/Murax_iCE40_hx8k_breakout_board_xip.asc : Murax_iCE40_hx8k_breakout_board_xip.pcf bin/Murax_iCE40_hx8k_breakout_board_xip.blif
|
||||
|
@ -28,11 +30,15 @@ time: bin/Murax_iCE40_hx8k_breakout_board_xip.bin
|
|||
icetime -tmd hx8k bin/Murax_iCE40_hx8k_breakout_board_xip.asc
|
||||
|
||||
prog : bin/Murax_iCE40_hx8k_breakout_board_xip.bin
|
||||
lsusb -d 0403:6010
|
||||
iceprog -S bin/Murax_iCE40_hx8k_breakout_board_xip.bin
|
||||
|
||||
sudo-prog : bin/Murax_iCE40_hx8k_breakout_board_xip.bin
|
||||
sudo lsusb -d 0403:6010
|
||||
sudo iceprog -S bin/Murax_iCE40_hx8k_breakout_board_xip.bin
|
||||
|
||||
clean :
|
||||
rm -rf bin
|
||||
rm -f Murax_iCE40_hx8k_breakout_board_xip.v*.bin
|
||||
rm -f ${VERILOG}*.bin
|
||||
rm -f ${VERILOG}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
## iCE40-hx8k breakout board
|
||||
|
||||
set_io io_J3 J3
|
||||
set_io io_H16 H16
|
||||
set_io io_G15 G15
|
||||
set_io io_G16 G16
|
||||
set_io io_F15 F15
|
||||
set_io io_B12 B12
|
||||
set_io io_B10 B10
|
||||
set_io io_mainClk J3
|
||||
set_io io_jtag_tck H16
|
||||
set_io io_jtag_tdi G15
|
||||
set_io io_jtag_tdo G16
|
||||
set_io io_jtag_tms F15
|
||||
set_io io_uart_txd B12
|
||||
set_io io_uart_rxd B10
|
||||
set_io io_led[0] B5
|
||||
set_io io_led[1] B4
|
||||
set_io io_led[2] A2
|
||||
|
@ -17,7 +17,7 @@ set_io io_led[6] B3
|
|||
set_io io_led[7] C3
|
||||
|
||||
#XIP
|
||||
set_io io_P12 P12
|
||||
set_io io_P11 P11
|
||||
set_io io_R11 R11
|
||||
set_io io_R12 R12
|
||||
set_io io_miso P12
|
||||
set_io io_mosi P11
|
||||
set_io io_sclk R11
|
||||
set_io io_spis R12
|
||||
|
|
|
@ -9,6 +9,10 @@ This board can be purchased for ~$USD 49 directly from Lattice and is supported
|
|||
by the IceStorm
|
||||
[`iceprog`](https://github.com/cliffordwolf/icestorm/tree/master/iceprog) tool.
|
||||
|
||||
# Bootloader operations
|
||||
|
||||
A bootloader is implemented in a ROM within the FPGA bitfile. It configure the SPI and attempt to read the first word in 'XIP' area of the flash (0xE0040000 in CPU address space, 0x40000 in flash). If this first word is not 0xFFFFFFFF and the same value is read 3 times,
|
||||
then the bootloader jump at 0xE0040000.
|
||||
|
||||
# Using the example
|
||||
|
||||
|
@ -59,12 +63,29 @@ The process should take around 30 seconds on a reasonable fast computer.
|
|||
|
||||
## Programming
|
||||
|
||||
Make sure the FPGA board is the only USB peripheral with ID 0403:6010
|
||||
|
||||
For example, this is bad:
|
||||
```
|
||||
user@lafite:~$ lsusb -d 0403:6010
|
||||
Bus 001 Device 088: ID 0403:6010 Future Technology Devices International, Ltd FT2232C Dual USB-UART/FIFO IC
|
||||
Bus 001 Device 090: ID 0403:6010 Future Technology Devices International, Ltd FT2232C Dual USB-UART/FIFO IC
|
||||
```
|
||||
This is good:
|
||||
```
|
||||
user@lafite:~$ lsusb -d 0403:6010
|
||||
Bus 001 Device 088: ID 0403:6010 Future Technology Devices International, Ltd FT2232C Dual USB-UART/FIFO IC
|
||||
```
|
||||
|
||||
|
||||
After building you should be able to run `make prog`. You may need to run `make
|
||||
sudo-prog` if root is needed to access your USB devices.
|
||||
|
||||
You should get output like the following;
|
||||
```
|
||||
iceprog -S bin/toplevel.bin
|
||||
lsusb -d 0403:6010
|
||||
Bus 001 Device 088: ID 0403:6010 Future Technology Devices International, Ltd FT2232C Dual USB-UART/FIFO IC
|
||||
iceprog -S bin/Murax_iCE40_hx8k_breakout_board_xip.bin
|
||||
init..
|
||||
cdone: high
|
||||
reset..
|
||||
|
@ -74,13 +95,113 @@ cdone: high
|
|||
Bye.
|
||||
```
|
||||
|
||||
After programming the LEDs at the top of the board should start flashing in an
|
||||
interesting pattern.
|
||||
WARNING: having this output does NOT guarantee you actually programmed anything in the FPGA!
|
||||
|
||||
## Connect
|
||||
After programming nothing visual will happen, except the LEDs being off.
|
||||
The bootloader is waiting for a valid content in the flash (see Bootloader operations).
|
||||
|
||||
After programming you should be able to connect to the serial port and have the
|
||||
output echoed back to you.
|
||||
## Programming flash image
|
||||
|
||||
On Linux you can do this using a command like `screen /dev/ttyUSB1`. Then as
|
||||
you type you should get back the same characters.
|
||||
### Connect JTAG
|
||||
|
||||
We will use vexrisc JTAG to program the flash, so you need openocd and a
|
||||
suitable JTAG dongle.
|
||||
|
||||
Pin-out:
|
||||
```
|
||||
TCK: H16 aka J2.25
|
||||
TDO: G16 aka J2.26
|
||||
TDI: G15 aka J2.27
|
||||
TMS: F15 aka J2.28
|
||||
```
|
||||
In addition you need to connect the ground and VTarget aka VIO: J2.2 on the
|
||||
board.
|
||||
|
||||
### Start GDB server / OpenOCD
|
||||
Make sure to use https://github.com/SpinalHDL/openocd_riscv
|
||||
Make sure to select the configuration file which match your JTAG dongle.
|
||||
|
||||
An example with the dongle "ft2232h_breakout":
|
||||
```
|
||||
src/openocd -f tcl/interface/ftdi/ft2232h_breakout.cfg -c "set MURAX_CPU0_YAML ../VexRiscv/cpu0.yaml" -f tcl/target/murax_xip.cfg
|
||||
```
|
||||
|
||||
You should get an output like below:
|
||||
```
|
||||
Open On-Chip Debugger 0.10.0+dev-01214-g0ace94f (2019-10-02-18:23)
|
||||
Licensed under GNU GPL v2
|
||||
For bug reports, read
|
||||
http://openocd.org/doc/doxygen/bugs.html
|
||||
../VexRiscv/cpu0.yaml
|
||||
adapter speed: 100 kHz
|
||||
adapter_nsrst_delay: 260
|
||||
Info : auto-selecting first available session transport "jtag". To override use 'transport select <transport>'.
|
||||
jtag_ntrst_delay: 250
|
||||
Info : set servers polling period to 50ms
|
||||
Error: libusb_get_string_descriptor_ascii() failed with LIBUSB_ERROR_INVALID_PARAM
|
||||
Info : clock speed 100 kHz
|
||||
Info : JTAG tap: fpga_spinal.bridge tap/device found: 0x10001fff (mfg: 0x7ff (<invalid>), part: 0x0001, ver: 0x1)
|
||||
Info : Listening on port 3333 for gdb connections
|
||||
requesting target halt and executing a soft reset
|
||||
Info : Listening on port 6666 for tcl connections
|
||||
Info : Listening on port 4444 for telnet connections
|
||||
```
|
||||
|
||||
### Loading the flash with telnet
|
||||
|
||||
First we connect and stop execution on the device:
|
||||
```
|
||||
user@lafite:~/Downloads/vexrisc_full/VexRiscv/src/main/c/murax/xipBootloader$ telnet 127.0.0.1 4444
|
||||
Trying 127.0.0.1...
|
||||
Connected to 127.0.0.1.
|
||||
Escape character is '^]'.
|
||||
Open On-Chip Debugger
|
||||
> reset
|
||||
JTAG tap: fpga_spinal.bridge tap/device found: 0x10001fff (mfg: 0x7ff (<invalid>), part: 0x0001, ver: 0x1)
|
||||
>
|
||||
```
|
||||
|
||||
Now we can safely connect the J7 jumper on the board to be able to access the flash.
|
||||
After that, we can load the program in flash:
|
||||
```
|
||||
> flash erase_sector 0 4 4
|
||||
erased sectors 4 through 4 on flash bank 0 in 0.872235s
|
||||
> flash write_bank 0 /home/user/dev/vexrisc_fork/VexRiscv/src/main/c/murax/xipBootloader/demo_xip.bin 0x40000
|
||||
wrote 48 bytes from file /home/user/dev/vexrisc_fork/VexRiscv/src/main/c/murax/xipBootloader/demo_xip.bin to flash bank 0 at offset 0x00040000 in 0.285539s (0.164 KiB/s)
|
||||
> flash verify_bank 0 /home/user/dev/vexrisc_fork/VexRiscv/src/main/c/murax/xipBootloader/demo_xip.bin 0x40000
|
||||
read 48 bytes from file /home/user/dev/vexrisc_fork/VexRiscv/src/main/c/murax/xipBootloader/demo_xip.bin and flash bank 0 at offset 0x00040000 in 0.192036s (0.244 KiB/s)
|
||||
contents match
|
||||
> reset
|
||||
JTAG tap: fpga_spinal.bridge tap/device found: 0x10001fff (mfg: 0x7ff (<invalid>), part: 0x0001, ver: 0x1)
|
||||
> resume
|
||||
> exit
|
||||
Connection closed by foreign host.
|
||||
```
|
||||
|
||||
From now the device runs the code from flash, LEDs shall display a dot moving from D9 to D2.
|
||||
|
||||
### Loading flash using GDB / eclipse
|
||||
```
|
||||
src/openocd -f tcl/interface/ftdi/ft2232h_breakout.cfg -c "set MURAX_CPU0_YAML ../VexRiscv/cpu0.yaml" -f tcl/target/murax_xip.cfg
|
||||
```
|
||||
- Make sure J7 is connected.
|
||||
- Connect to GDB / eclipse as usual.
|
||||
|
||||
From there code loading, step, break points works as usual (including software break points in flash).
|
||||
|
||||
## Update hardware/bootloader
|
||||
|
||||
- Stop any OpenOCD connection
|
||||
- Remove J7, then:
|
||||
```
|
||||
make clean prog
|
||||
```
|
||||
- Remember to check a single FTDI device is listed in the output. If not:
|
||||
- Disconnect the other devices
|
||||
```
|
||||
make prog
|
||||
```
|
||||
- Connect J7, flash software shall start executing.
|
||||
|
||||
## Flash software
|
||||
Refer to "Loading the flash with telnet" or "Loading flash using GDB / eclipse".
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
|
||||
verilator/configure:
|
||||
rm -rf verilator*
|
||||
wget https://www.veripool.org/ftp/verilator-4.012.tgz
|
||||
wget https://www.veripool.org/ftp/verilator-4.034.tgz
|
||||
tar xvzf verilator*.t*gz
|
||||
mv verilator-4.012 verilator
|
||||
mv verilator-4.034 verilator
|
||||
|
||||
verilator/Makefile: verilator/configure
|
||||
cd verilator
|
||||
|
|
|
@ -18,10 +18,11 @@ sim: all
|
|||
qemu: CFLAGS += -DQEMU
|
||||
qemu: all
|
||||
|
||||
litex: CFLAGS += -DLITEX -I${LITEX_BASE}/software/include
|
||||
litex: | check_litex_base all
|
||||
check_litex_base:
|
||||
litex: CFLAGS += -DLITEX -I${LITEX_GENERATED} -I${LITEX_BASE}/litex/soc/software/include
|
||||
litex: | check_litex all
|
||||
check_litex:
|
||||
@[ "${LITEX_BASE}" ] || ( echo ">> LITEX_BASE is not set"; exit 1 )
|
||||
@[ "${LITEX_GENERATED}" ] || ( echo ">> LITEX_GENERATED is not set"; exit 1 )
|
||||
|
||||
include ${STANDALONE}/common/riscv64-unknown-elf.mk
|
||||
include ${STANDALONE}/common/standalone.mk
|
||||
|
|
|
@ -146,38 +146,6 @@ void halInit(){
|
|||
|
||||
#ifdef LITEX
|
||||
|
||||
// this is copied from LiteX <hw/common.h>
|
||||
#define CSR_ACCESSORS_DEFINED
|
||||
static inline void csr_writeb(uint8_t value, unsigned long addr)
|
||||
{
|
||||
*((volatile uint8_t *)addr) = value;
|
||||
}
|
||||
|
||||
static inline uint8_t csr_readb(unsigned long addr)
|
||||
{
|
||||
return *(volatile uint8_t *)addr;
|
||||
}
|
||||
|
||||
static inline void csr_writew(uint16_t value, unsigned long addr)
|
||||
{
|
||||
*((volatile uint16_t *)addr) = value;
|
||||
}
|
||||
|
||||
static inline uint16_t csr_readw(unsigned long addr)
|
||||
{
|
||||
return *(volatile uint16_t *)addr;
|
||||
}
|
||||
|
||||
static inline void csr_writel(uint32_t value, unsigned long addr)
|
||||
{
|
||||
*((volatile uint32_t *)addr) = value;
|
||||
}
|
||||
|
||||
static inline uint32_t csr_readl(unsigned long addr)
|
||||
{
|
||||
return *(volatile uint32_t *)addr;
|
||||
}
|
||||
|
||||
// this is a file generated by LiteX
|
||||
#include <generated/csr.h>
|
||||
|
||||
|
|
134
src/main/c/murax/hello_world/makefile
Normal file
134
src/main/c/murax/hello_world/makefile
Normal file
|
@ -0,0 +1,134 @@
|
|||
PROJ_NAME=hello_world
|
||||
DEBUG=no
|
||||
BENCH=no
|
||||
MULDIV=no
|
||||
|
||||
SRCS = $(wildcard src/*.c) \
|
||||
$(wildcard src/*.cpp) \
|
||||
$(wildcard src/*.S)
|
||||
|
||||
OBJDIR = build
|
||||
|
||||
INC =
|
||||
LIBS =
|
||||
LIBSINC = -L$(OBJDIR)
|
||||
LDSCRIPT = ./src/linker.ld
|
||||
|
||||
#include ../../../resources/gcc.mk
|
||||
# Set it to yes if you are using the sifive precompiled GCC pack
|
||||
SIFIVE_GCC_PACK ?= yes
|
||||
|
||||
ifeq ($(SIFIVE_GCC_PACK),yes)
|
||||
RISCV_NAME ?= riscv64-unknown-elf
|
||||
RISCV_PATH ?= /opt/riscv/
|
||||
else
|
||||
RISCV_NAME ?= riscv32-unknown-elf
|
||||
ifeq ($(MULDIV),yes)
|
||||
RISCV_PATH ?= /opt/riscv32im/
|
||||
else
|
||||
RISCV_PATH ?= /opt/riscv32i/
|
||||
endif
|
||||
endif
|
||||
|
||||
MABI=ilp32
|
||||
MARCH := rv32i
|
||||
ifeq ($(MULDIV),yes)
|
||||
MARCH := $(MARCH)m
|
||||
endif
|
||||
ifeq ($(COMPRESSED),yes)
|
||||
MARCH := $(MARCH)ac
|
||||
endif
|
||||
|
||||
CFLAGS += -march=$(MARCH) -mabi=$(MABI) -DNDEBUG
|
||||
LDFLAGS += -march=$(MARCH) -mabi=$(MABI)
|
||||
|
||||
|
||||
|
||||
#include ../../../resources/subproject.mk
|
||||
|
||||
|
||||
ifeq ($(DEBUG),yes)
|
||||
CFLAGS += -g3 -O0
|
||||
endif
|
||||
|
||||
ifeq ($(DEBUG),no)
|
||||
CFLAGS += -g -Os
|
||||
endif
|
||||
|
||||
ifeq ($(BENCH),yes)
|
||||
CFLAGS += -fno-inline
|
||||
endif
|
||||
|
||||
ifeq ($(SIFIVE_GCC_PACK),yes)
|
||||
RISCV_CLIB=$(RISCV_PATH)/$(RISCV_NAME)/lib/$(MARCH)/$(MABI)/
|
||||
else
|
||||
RISCV_CLIB=$(RISCV_PATH)/$(RISCV_NAME)/lib/
|
||||
endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
RISCV_OBJCOPY = $(RISCV_PATH)/bin/$(RISCV_NAME)-objcopy
|
||||
RISCV_OBJDUMP = $(RISCV_PATH)/bin/$(RISCV_NAME)-objdump
|
||||
RISCV_CC=$(RISCV_PATH)/bin/$(RISCV_NAME)-gcc
|
||||
|
||||
CFLAGS += -MD -fstrict-volatile-bitfields -fno-strict-aliasing
|
||||
LDFLAGS += -nostdlib -lgcc -mcmodel=medany -nostartfiles -ffreestanding -Wl,-Bstatic,-T,$(LDSCRIPT),-Map,$(OBJDIR)/$(PROJ_NAME).map,--print-memory-usage
|
||||
#LDFLAGS += -lgcc -lc -lg -nostdlib -lgcc -msave-restore --strip-debug,
|
||||
|
||||
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).v
|
||||
|
||||
$(OBJDIR)/%.elf: $(OBJS) | $(OBJDIR)
|
||||
$(RISCV_CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LIBSINC) $(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 $@ $^
|
||||
$(RISCV_CC) -S $(CFLAGS) $(INC) -o $@.disasm $^
|
||||
|
||||
$(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 $@
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf $(OBJDIR)/src
|
||||
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
|
||||
find $(OBJDIR) -type f -name '*.d' -print0 | xargs -0 -r rm
|
||||
|
||||
clean-all : clean
|
||||
|
||||
.SECONDARY: $(OBJS)
|
98
src/main/c/murax/hello_world/src/crt.S
Normal file
98
src/main/c/murax/hello_world/src/crt.S
Normal file
|
@ -0,0 +1,98 @@
|
|||
.global crtStart
|
||||
.global main
|
||||
.global irqCallback
|
||||
|
||||
.section .start_jump,"ax",@progbits
|
||||
crtStart:
|
||||
//long jump to allow crtInit to be anywhere
|
||||
//do it always in 12 bytes
|
||||
lui x2, %hi(crtInit)
|
||||
addi x2, x2, %lo(crtInit)
|
||||
jalr x1,x2
|
||||
nop
|
||||
|
||||
.section .text
|
||||
|
||||
.global trap_entry
|
||||
.align 5
|
||||
trap_entry:
|
||||
sw x1, - 1*4(sp)
|
||||
sw x5, - 2*4(sp)
|
||||
sw x6, - 3*4(sp)
|
||||
sw x7, - 4*4(sp)
|
||||
sw x10, - 5*4(sp)
|
||||
sw x11, - 6*4(sp)
|
||||
sw x12, - 7*4(sp)
|
||||
sw x13, - 8*4(sp)
|
||||
sw x14, - 9*4(sp)
|
||||
sw x15, -10*4(sp)
|
||||
sw x16, -11*4(sp)
|
||||
sw x17, -12*4(sp)
|
||||
sw x28, -13*4(sp)
|
||||
sw x29, -14*4(sp)
|
||||
sw x30, -15*4(sp)
|
||||
sw x31, -16*4(sp)
|
||||
addi sp,sp,-16*4
|
||||
call irqCallback
|
||||
lw x1 , 15*4(sp)
|
||||
lw x5, 14*4(sp)
|
||||
lw x6, 13*4(sp)
|
||||
lw x7, 12*4(sp)
|
||||
lw x10, 11*4(sp)
|
||||
lw x11, 10*4(sp)
|
||||
lw x12, 9*4(sp)
|
||||
lw x13, 8*4(sp)
|
||||
lw x14, 7*4(sp)
|
||||
lw x15, 6*4(sp)
|
||||
lw x16, 5*4(sp)
|
||||
lw x17, 4*4(sp)
|
||||
lw x28, 3*4(sp)
|
||||
lw x29, 2*4(sp)
|
||||
lw x30, 1*4(sp)
|
||||
lw x31, 0*4(sp)
|
||||
addi sp,sp,16*4
|
||||
mret
|
||||
.text
|
||||
|
||||
|
||||
crtInit:
|
||||
.option push
|
||||
.option norelax
|
||||
la gp, __global_pointer$
|
||||
.option pop
|
||||
la sp, _stack_start
|
||||
|
||||
bss_init:
|
||||
la a0, _bss_start
|
||||
la a1, _bss_end
|
||||
bss_loop:
|
||||
beq a0,a1,bss_done
|
||||
sw zero,0(a0)
|
||||
add a0,a0,4
|
||||
j bss_loop
|
||||
bss_done:
|
||||
|
||||
ctors_init:
|
||||
la a0, _ctors_start
|
||||
addi sp,sp,-4
|
||||
ctors_loop:
|
||||
la a1, _ctors_end
|
||||
beq a0,a1,ctors_done
|
||||
lw a3,0(a0)
|
||||
add a0,a0,4
|
||||
sw a0,0(sp)
|
||||
jalr a3
|
||||
lw a0,0(sp)
|
||||
j ctors_loop
|
||||
ctors_done:
|
||||
addi sp,sp,4
|
||||
|
||||
|
||||
li a0, 0x880 //880 enable timer + external interrupts
|
||||
csrw mie,a0
|
||||
li a0, 0x1808 //1808 enable interrupts
|
||||
csrw mstatus,a0
|
||||
|
||||
call main
|
||||
infinitLoop:
|
||||
j infinitLoop
|
15
src/main/c/murax/hello_world/src/gpio.h
Normal file
15
src/main/c/murax/hello_world/src/gpio.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#ifndef GPIO_H_
|
||||
#define GPIO_H_
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
volatile uint32_t INPUT;
|
||||
volatile uint32_t OUTPUT;
|
||||
volatile uint32_t OUTPUT_ENABLE;
|
||||
} Gpio_Reg;
|
||||
|
||||
|
||||
#endif /* GPIO_H_ */
|
||||
|
||||
|
17
src/main/c/murax/hello_world/src/interrupt.h
Normal file
17
src/main/c/murax/hello_world/src/interrupt.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#ifndef INTERRUPTCTRL_H_
|
||||
#define INTERRUPTCTRL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
volatile uint32_t PENDINGS;
|
||||
volatile uint32_t MASKS;
|
||||
} InterruptCtrl_Reg;
|
||||
|
||||
static void interruptCtrl_init(InterruptCtrl_Reg* reg){
|
||||
reg->MASKS = 0;
|
||||
reg->PENDINGS = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
#endif /* INTERRUPTCTRL_H_ */
|
110
src/main/c/murax/hello_world/src/linker.ld
Normal file
110
src/main/c/murax/hello_world/src/linker.ld
Normal file
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
*/
|
||||
OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv", "elf32-littleriscv")
|
||||
OUTPUT_ARCH(riscv)
|
||||
ENTRY(crtStart)
|
||||
|
||||
MEMORY {
|
||||
RAM (rwx): ORIGIN = 0x80000000, LENGTH = 2k
|
||||
}
|
||||
|
||||
_stack_size = DEFINED(_stack_size) ? _stack_size : 256;
|
||||
_heap_size = DEFINED(_heap_size) ? _heap_size : 0;
|
||||
|
||||
SECTIONS {
|
||||
|
||||
._vector ORIGIN(RAM): {
|
||||
*crt.o(.start_jump);
|
||||
*crt.o(.text);
|
||||
} > RAM
|
||||
|
||||
._user_heap (NOLOAD):
|
||||
{
|
||||
. = ALIGN(8);
|
||||
PROVIDE ( end = . );
|
||||
PROVIDE ( _end = . );
|
||||
PROVIDE ( _heap_start = .);
|
||||
. = . + _heap_size;
|
||||
. = ALIGN(8);
|
||||
PROVIDE ( _heap_end = .);
|
||||
} > RAM
|
||||
|
||||
._stack (NOLOAD):
|
||||
{
|
||||
. = ALIGN(16);
|
||||
PROVIDE (_stack_end = .);
|
||||
. = . + _stack_size;
|
||||
. = ALIGN(16);
|
||||
PROVIDE (_stack_start = .);
|
||||
} > 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
|
||||
|
||||
.bss (NOLOAD) : {
|
||||
. = ALIGN(4);
|
||||
/* This is used by the startup in order to initialize the .bss secion */
|
||||
_bss_start = .;
|
||||
*(.sbss*)
|
||||
*(.gnu.linkonce.sb.*)
|
||||
*(.bss .bss.*)
|
||||
*(.gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
_bss_end = .;
|
||||
} > RAM
|
||||
|
||||
|
||||
.rodata :
|
||||
{
|
||||
*(.rdata)
|
||||
*(.rodata .rodata.*)
|
||||
*(.gnu.linkonce.r.*)
|
||||
} > RAM
|
||||
|
||||
.noinit (NOLOAD) : {
|
||||
. = ALIGN(4);
|
||||
*(.noinit .noinit.*)
|
||||
. = ALIGN(4);
|
||||
} > RAM
|
||||
|
||||
.memory : {
|
||||
*(.text);
|
||||
end = .;
|
||||
} > RAM
|
||||
|
||||
.ctors :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_ctors_start = .;
|
||||
KEEP(*(.init_array*))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*(.ctors))
|
||||
. = ALIGN(4);
|
||||
_ctors_end = .;
|
||||
PROVIDE ( END_OF_SW_IMAGE = . );
|
||||
} > RAM
|
||||
|
||||
}
|
42
src/main/c/murax/hello_world/src/main.c
Normal file
42
src/main/c/murax/hello_world/src/main.c
Normal file
|
@ -0,0 +1,42 @@
|
|||
//#include "stddefs.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#include "murax.h"
|
||||
|
||||
void print(const char*str){
|
||||
while(*str){
|
||||
uart_write(UART,*str);
|
||||
str++;
|
||||
}
|
||||
}
|
||||
void println(const char*str){
|
||||
print(str);
|
||||
uart_write(UART,'\n');
|
||||
}
|
||||
|
||||
void delay(uint32_t loops){
|
||||
for(int i=0;i<loops;i++){
|
||||
int tmp = GPIO_A->OUTPUT;
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
GPIO_A->OUTPUT_ENABLE = 0x0000000F;
|
||||
GPIO_A->OUTPUT = 0x00000001;
|
||||
println("hello world arty a7 v1");
|
||||
const int nleds = 4;
|
||||
const int nloops = 2000000;
|
||||
while(1){
|
||||
for(unsigned int i=0;i<nleds-1;i++){
|
||||
GPIO_A->OUTPUT = 1<<i;
|
||||
delay(nloops);
|
||||
}
|
||||
for(unsigned int i=0;i<nleds-1;i++){
|
||||
GPIO_A->OUTPUT = (1<<(nleds-1))>>i;
|
||||
delay(nloops);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void irqCallback(){
|
||||
}
|
17
src/main/c/murax/hello_world/src/murax.h
Normal file
17
src/main/c/murax/hello_world/src/murax.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#ifndef __MURAX_H__
|
||||
#define __MURAX_H__
|
||||
|
||||
#include "timer.h"
|
||||
#include "prescaler.h"
|
||||
#include "interrupt.h"
|
||||
#include "gpio.h"
|
||||
#include "uart.h"
|
||||
|
||||
#define GPIO_A ((Gpio_Reg*)(0xF0000000))
|
||||
#define TIMER_PRESCALER ((Prescaler_Reg*)0xF0020000)
|
||||
#define TIMER_INTERRUPT ((InterruptCtrl_Reg*)0xF0020010)
|
||||
#define TIMER_A ((Timer_Reg*)0xF0020040)
|
||||
#define TIMER_B ((Timer_Reg*)0xF0020050)
|
||||
#define UART ((Uart_Reg*)(0xF0010000))
|
||||
|
||||
#endif /* __MURAX_H__ */
|
16
src/main/c/murax/hello_world/src/prescaler.h
Normal file
16
src/main/c/murax/hello_world/src/prescaler.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#ifndef PRESCALERCTRL_H_
|
||||
#define PRESCALERCTRL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
volatile uint32_t LIMIT;
|
||||
} Prescaler_Reg;
|
||||
|
||||
static void prescaler_init(Prescaler_Reg* reg){
|
||||
|
||||
}
|
||||
|
||||
#endif /* PRESCALERCTRL_H_ */
|
20
src/main/c/murax/hello_world/src/timer.h
Normal file
20
src/main/c/murax/hello_world/src/timer.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#ifndef TIMERCTRL_H_
|
||||
#define TIMERCTRL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
volatile uint32_t CLEARS_TICKS;
|
||||
volatile uint32_t LIMIT;
|
||||
volatile uint32_t VALUE;
|
||||
} Timer_Reg;
|
||||
|
||||
static void timer_init(Timer_Reg *reg){
|
||||
reg->CLEARS_TICKS = 0;
|
||||
reg->VALUE = 0;
|
||||
}
|
||||
|
||||
|
||||
#endif /* TIMERCTRL_H_ */
|
42
src/main/c/murax/hello_world/src/uart.h
Normal file
42
src/main/c/murax/hello_world/src/uart.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
#ifndef UART_H_
|
||||
#define UART_H_
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
volatile uint32_t DATA;
|
||||
volatile uint32_t STATUS;
|
||||
volatile uint32_t CLOCK_DIVIDER;
|
||||
volatile uint32_t FRAME_CONFIG;
|
||||
} Uart_Reg;
|
||||
|
||||
enum UartParity {NONE = 0,EVEN = 1,ODD = 2};
|
||||
enum UartStop {ONE = 0,TWO = 1};
|
||||
|
||||
typedef struct {
|
||||
uint32_t dataLength;
|
||||
enum UartParity parity;
|
||||
enum UartStop stop;
|
||||
uint32_t clockDivider;
|
||||
} Uart_Config;
|
||||
|
||||
static uint32_t uart_writeAvailability(Uart_Reg *reg){
|
||||
return (reg->STATUS >> 16) & 0xFF;
|
||||
}
|
||||
static uint32_t uart_readOccupancy(Uart_Reg *reg){
|
||||
return reg->STATUS >> 24;
|
||||
}
|
||||
|
||||
static void uart_write(Uart_Reg *reg, uint32_t data){
|
||||
while(uart_writeAvailability(reg) == 0);
|
||||
reg->DATA = data;
|
||||
}
|
||||
|
||||
static void uart_applyConfig(Uart_Reg *reg, Uart_Config *config){
|
||||
reg->CLOCK_DIVIDER = config->clockDivider;
|
||||
reg->FRAME_CONFIG = ((config->dataLength-1) << 0) | (config->parity << 8) | (config->stop << 16);
|
||||
}
|
||||
|
||||
#endif /* UART_H_ */
|
||||
|
||||
|
|
@ -42,13 +42,33 @@ crtStart:
|
|||
li t0, 0x1
|
||||
sw t0, CTRL_XIP_CONFIG(CTRL)
|
||||
li t0, XIP_BASE
|
||||
lw t1, (t0)
|
||||
li t2, 0xFFFFFFFF
|
||||
xor t3,t1,t2
|
||||
beqz t3,retry
|
||||
//if we are here we have read a value from flash which is not all ones
|
||||
lw t2, (t0)
|
||||
xor t3,t1,t2
|
||||
bnez t3,retry
|
||||
lw t2, (t0)
|
||||
xor t3,t1,t2
|
||||
bnez t3,retry
|
||||
//if we are here we have read the same value 3 times, so flash seems good, lets's jump
|
||||
jr t0
|
||||
|
||||
retry:
|
||||
li a0, 0x800
|
||||
call spiWrite
|
||||
li t1,100000
|
||||
loop:
|
||||
addi t1,t1,-1
|
||||
bnez t1, loop
|
||||
j crtStart
|
||||
|
||||
spiWrite:
|
||||
sw a0,CTRL_DATA(CTRL)
|
||||
spiWrite_wait:
|
||||
lw t0,CTRL_STATUS(CTRL)
|
||||
srli t0,t0,0x10
|
||||
slli t0,t0,0x10
|
||||
beqz t0,spiWrite_wait
|
||||
ret
|
||||
|
|
Binary file not shown.
|
@ -7,18 +7,21 @@
|
|||
|
||||
crtStart:
|
||||
|
||||
|
||||
li x31, 0x12340000 // magic word expected by bootloader
|
||||
|
||||
li x31, GPIO_BASE
|
||||
li t0, 0x000000FF
|
||||
sw t0, GPIO_OUTPUT_ENABLE(x31)
|
||||
|
||||
li t0,0
|
||||
li t0,1
|
||||
redo:
|
||||
sw t0, GPIO_OUTPUT(x31)
|
||||
li t1,10000
|
||||
addi t0,t0,1
|
||||
slli t0,t0,1
|
||||
andi t0,t0,0xFF
|
||||
bnez t0, loop
|
||||
li t0,1
|
||||
loop:
|
||||
addi t1,t1,-1
|
||||
bnez t1, loop
|
||||
j redo
|
||||
|
||||
|
|
Binary file not shown.
|
@ -4,20 +4,34 @@ LFLAGS= -nostdlib -mcmodel=medany -nostartfiles -ffreestanding -fPIC -fPIE
|
|||
|
||||
all: crt.S demo.S
|
||||
riscv64-unknown-elf-gcc -c $(CFLAGS) -o crt.o crt.S
|
||||
riscv64-unknown-elf-gcc $(CFLAGS) -o crt.elf crt.o $(LFLAGS) -Wl,-Bstatic,-T,mapping.ld,-Map,crt.map,--print-memory-usage
|
||||
riscv64-unknown-elf-gcc $(CFLAGS) -o crt.elf crt.o $(LFLAGS) -Wl,-Bstatic,-T,mapping_rom.ld,-Map,crt.map,--print-memory-usage
|
||||
riscv64-unknown-elf-objdump -S -d crt.elf > crt.asm
|
||||
riscv64-unknown-elf-objcopy -O binary crt.elf crt.bin
|
||||
|
||||
riscv64-unknown-elf-gcc $(CFLAGS) -o crt_ram.elf crt.o $(LFLAGS) -Wl,-Bstatic,-T,mapping.ld,-Map,crt_ram.map,--print-memory-usage
|
||||
riscv64-unknown-elf-objdump -S -d crt_ram.elf > crt_ram.asm
|
||||
riscv64-unknown-elf-objcopy -O binary crt_ram.elf crt_ram.bin
|
||||
|
||||
riscv64-unknown-elf-gcc -c $(CFLAGS) -o demo.o demo.S
|
||||
riscv64-unknown-elf-gcc $(CFLAGS) -o demo.elf demo.o $(LFLAGS) -Wl,-Bstatic,-T,mapping.ld,-Map,demo.map,--print-memory-usage
|
||||
riscv64-unknown-elf-objdump -S -d demo.elf > demo.asm
|
||||
riscv64-unknown-elf-objcopy -O binary demo.elf demo.bin
|
||||
|
||||
riscv64-unknown-elf-gcc $(CFLAGS) -o demo_rom.elf demo.o $(LFLAGS) -Wl,-Bstatic,-T,mapping_rom.ld,-Map,demo_rom.map,--print-memory-usage
|
||||
riscv64-unknown-elf-objdump -S -d demo_rom.elf > demo_rom.asm
|
||||
riscv64-unknown-elf-objcopy -O binary demo_rom.elf demo_rom.bin
|
||||
|
||||
riscv64-unknown-elf-gcc $(CFLAGS) -o demo_xip.elf demo.o $(LFLAGS) -Wl,-Bstatic,-T,mapping_xip.ld,-Map,demo_xip.map,--print-memory-usage
|
||||
riscv64-unknown-elf-objdump -S -d demo_xip.elf > demo_xip.asm
|
||||
riscv64-unknown-elf-objcopy -O binary demo_xip.elf demo_xip.bin
|
||||
|
||||
clean:
|
||||
clean-for-commit:
|
||||
rm -f *.o
|
||||
rm -f *.bin
|
||||
rm -f *.elf
|
||||
rm -f *.asm
|
||||
rm -f *.map
|
||||
rm -f *.map
|
||||
rm -f *.d
|
||||
rm demo_rom.bin demo.bin crt_ram.bin
|
||||
|
||||
clean: clean-for-commit
|
||||
rm -f *.bin
|
||||
|
|
96
src/main/c/murax/xipBootloader/mapping_rom.ld
Normal file
96
src/main/c/murax/xipBootloader/mapping_rom.ld
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
*/
|
||||
OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv", "elf32-littleriscv")
|
||||
OUTPUT_ARCH(riscv)
|
||||
ENTRY(crtStart)
|
||||
|
||||
MEMORY {
|
||||
mem : ORIGIN = 0x80000000, LENGTH = 0x00000400
|
||||
rom : ORIGIN = 0xF001E000, LENGTH = 0x00000400
|
||||
}
|
||||
|
||||
_stack_size = DEFINED(_stack_size) ? _stack_size : 0;
|
||||
|
||||
SECTIONS {
|
||||
|
||||
.vector : {
|
||||
*crt.o(.text);
|
||||
} > rom
|
||||
|
||||
.memory : {
|
||||
*(.text);
|
||||
end = .;
|
||||
} > rom
|
||||
|
||||
.rodata :
|
||||
{
|
||||
*(.rdata)
|
||||
*(.rodata .rodata.*)
|
||||
*(.gnu.linkonce.r.*)
|
||||
} > rom
|
||||
|
||||
.ctors :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_ctors_start = .;
|
||||
KEEP(*(.init_array*))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*(.ctors))
|
||||
. = ALIGN(4);
|
||||
_ctors_end = .;
|
||||
} > rom
|
||||
|
||||
.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.*)
|
||||
} > rom
|
||||
|
||||
.bss (NOLOAD) : {
|
||||
. = ALIGN(4);
|
||||
/* This is used by the startup in order to initialize the .bss secion */
|
||||
_bss_start = .;
|
||||
*(.sbss*)
|
||||
*(.gnu.linkonce.sb.*)
|
||||
*(.bss .bss.*)
|
||||
*(.gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
_bss_end = .;
|
||||
} > mem
|
||||
|
||||
.noinit (NOLOAD) : {
|
||||
. = ALIGN(4);
|
||||
*(.noinit .noinit.*)
|
||||
. = ALIGN(4);
|
||||
} > mem
|
||||
|
||||
._stack (NOLOAD):
|
||||
{
|
||||
. = ALIGN(16);
|
||||
PROVIDE (_stack_end = .);
|
||||
. = . + _stack_size;
|
||||
. = ALIGN(16);
|
||||
PROVIDE (_stack_start = .);
|
||||
} > mem
|
||||
|
||||
}
|
96
src/main/c/murax/xipBootloader/mapping_xip.ld
Normal file
96
src/main/c/murax/xipBootloader/mapping_xip.ld
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
*/
|
||||
OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv", "elf32-littleriscv")
|
||||
OUTPUT_ARCH(riscv)
|
||||
ENTRY(crtStart)
|
||||
|
||||
MEMORY {
|
||||
mem : ORIGIN = 0x80000000, LENGTH = 0x00000400
|
||||
xip : ORIGIN = 0xE0040000, LENGTH = 0x00000400
|
||||
}
|
||||
|
||||
_stack_size = DEFINED(_stack_size) ? _stack_size : 0;
|
||||
|
||||
SECTIONS {
|
||||
|
||||
.vector : {
|
||||
*crt.o(.text);
|
||||
} > xip
|
||||
|
||||
.memory : {
|
||||
*(.text);
|
||||
end = .;
|
||||
} > xip
|
||||
|
||||
.rodata :
|
||||
{
|
||||
*(.rdata)
|
||||
*(.rodata .rodata.*)
|
||||
*(.gnu.linkonce.r.*)
|
||||
} > xip
|
||||
|
||||
.ctors :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_ctors_start = .;
|
||||
KEEP(*(.init_array*))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*(.ctors))
|
||||
. = ALIGN(4);
|
||||
_ctors_end = .;
|
||||
} > xip
|
||||
|
||||
.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.*)
|
||||
} > xip
|
||||
|
||||
.bss (NOLOAD) : {
|
||||
. = ALIGN(4);
|
||||
/* This is used by the startup in order to initialize the .bss secion */
|
||||
_bss_start = .;
|
||||
*(.sbss*)
|
||||
*(.gnu.linkonce.sb.*)
|
||||
*(.bss .bss.*)
|
||||
*(.gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
_bss_end = .;
|
||||
} > mem
|
||||
|
||||
.noinit (NOLOAD) : {
|
||||
. = ALIGN(4);
|
||||
*(.noinit .noinit.*)
|
||||
. = ALIGN(4);
|
||||
} > mem
|
||||
|
||||
._stack (NOLOAD):
|
||||
{
|
||||
. = ALIGN(16);
|
||||
PROVIDE (_stack_end = .);
|
||||
. = . + _stack_size;
|
||||
. = ALIGN(16);
|
||||
PROVIDE (_stack_start = .);
|
||||
} > mem
|
||||
|
||||
}
|
|
@ -1,241 +0,0 @@
|
|||
package spinal.lib.bus.wishbone
|
||||
|
||||
import spinal.core._
|
||||
import spinal.lib._
|
||||
|
||||
/** This class is used for configuring the Wishbone class
|
||||
* @param addressWidth size in bits of the address line
|
||||
* @param dataWidth size in bits of the data line
|
||||
* @param selWidth size in bits of the selection line, deafult to 0 (disabled)
|
||||
* @param useSTALL activate the stall line, default to false (disabled)
|
||||
* @param useLOCK activate the lock line, default to false (disabled)
|
||||
* @param useERR activate the error line, default to false (disabled)
|
||||
* @param useRTY activate the retry line, default to false (disabled)
|
||||
* @param tgaWidth size in bits of the tag address linie, deafult to 0 (disabled)
|
||||
* @param tgcWidth size in bits of the tag cycle line, deafult to 0 (disabled)
|
||||
* @param tgdWidth size in bits of the tag data line, deafult to 0 (disabled)
|
||||
* @param useBTE activate the BTE line, deafult to 0 (disabled)
|
||||
* @param useCTI activate the CTI line, deafult to 0 (disabled)
|
||||
* @example {{{
|
||||
* val wishboneBusConf = new WishboneConfig(32,8).withCycleTag(8).withDataTag(8)
|
||||
* val wishboneBus = new Wishbone(wishboneBusConf)
|
||||
* }}}
|
||||
* @todo test example
|
||||
*/
|
||||
case class WishboneConfig(
|
||||
val addressWidth : Int,
|
||||
val dataWidth : Int,
|
||||
val selWidth : Int = 0,
|
||||
val useSTALL : Boolean = false,
|
||||
val useLOCK : Boolean = false,
|
||||
val useERR : Boolean = false,
|
||||
val useRTY : Boolean = false,
|
||||
val tgaWidth : Int = 0,
|
||||
val tgcWidth : Int = 0,
|
||||
val tgdWidth : Int = 0,
|
||||
val useBTE : Boolean = false,
|
||||
val useCTI : Boolean = false
|
||||
){
|
||||
def useTGA = tgaWidth > 0
|
||||
def useTGC = tgcWidth > 0
|
||||
def useTGD = tgdWidth > 0
|
||||
def useSEL = selWidth > 0
|
||||
def isPipelined = useSTALL
|
||||
def pipelined : WishboneConfig = this.copy(useSTALL = true)
|
||||
def withDataTag(size : Int) : WishboneConfig = this.copy(tgdWidth = size)
|
||||
def withAddressTag(size : Int) : WishboneConfig = this.copy(tgaWidth = size)
|
||||
def withCycleTag(size : Int) : WishboneConfig = this.copy(tgdWidth = size)
|
||||
}
|
||||
|
||||
/** This class rappresent a Wishbone bus
|
||||
* @param config an istance of WishboneConfig, it will be used to configurate the Wishbone Bus
|
||||
*/
|
||||
case class Wishbone(config: WishboneConfig) extends Bundle with IMasterSlave {
|
||||
/////////////////////
|
||||
// MINIMAL SIGNALS //
|
||||
/////////////////////
|
||||
val CYC = Bool
|
||||
val STB = Bool
|
||||
val ACK = Bool
|
||||
val WE = Bool
|
||||
val ADR = UInt(config.addressWidth bits)
|
||||
val DAT_MISO = Bits(config.dataWidth bits)
|
||||
val DAT_MOSI = Bits(config.dataWidth bits)
|
||||
|
||||
///////////////////////////
|
||||
// OPTIONAL FLOW CONTROS //
|
||||
///////////////////////////
|
||||
val SEL = if(config.useSEL) Bits(config.selWidth bits) else null
|
||||
val STALL = if(config.useSTALL) Bool else null
|
||||
val LOCK = if(config.useLOCK) Bool else null
|
||||
val ERR = if(config.useERR) Bool else null
|
||||
val RTY = if(config.useRTY) Bool else null
|
||||
|
||||
//////////
|
||||
// TAGS //
|
||||
//////////
|
||||
val TGD_MISO = if(config.useTGD) Bits(config.tgdWidth bits) else null
|
||||
val TGD_MOSI = if(config.useTGD) Bits(config.tgdWidth bits) else null
|
||||
val TGA = if(config.useTGA) Bits(config.tgaWidth bits) else null
|
||||
val TGC = if(config.useTGC) Bits(config.tgcWidth bits) else null
|
||||
val BTE = if(config.useBTE) Bits(2 bits) else null
|
||||
val CTI = if(config.useCTI) Bits(3 bits) else null
|
||||
|
||||
override def asMaster(): Unit = {
|
||||
outWithNull(DAT_MOSI, TGD_MOSI, ADR, CYC, LOCK, SEL, STB, TGA, TGC, WE, CTI, BTE)
|
||||
inWithNull(DAT_MISO, TGD_MISO, ACK, STALL, ERR, RTY)
|
||||
}
|
||||
|
||||
// def isCycle : Bool = if(config.useERR) !ERR && CYC else CYC
|
||||
// def isWrite : Bool = isCycle && WE
|
||||
// def isRead : Bool = isCycle && !WE
|
||||
// def isReadCycle : Bool = isRead && STB
|
||||
// def isWriteCycle : Bool = isWrite && STB
|
||||
// def isStalled : Bool = if(config.isPipelined) isCycle && STALL else False
|
||||
// def isAcknoledge : Bool = isCycle && ACK
|
||||
// def isStrobe : Bool = isCycle && STB
|
||||
|
||||
// def doSlaveWrite : Bool = this.CYC && this.STB && this.WE
|
||||
// def doSlaveRead : Bool = this.CYC && this.STB && !this.WE
|
||||
// def doSlavePipelinedWrite : Bool = this.CYC && this.WE
|
||||
// def doSlavePipelinedRead : Bool = this.CYC && !this.WE
|
||||
|
||||
/** Connect the istance of this bus with another, allowing for resize of data
|
||||
* @param that the wishbone instance that will be connected and resized
|
||||
* @param allowDataResize allow to resize "that" data lines, default to false (disable)
|
||||
* @param allowAddressResize allow to resize "that" address lines, default to false (disable)
|
||||
* @param allowTagResize allow to resize "that" tag lines, default to false (disable)
|
||||
*/
|
||||
def connectTo(that : Wishbone, allowDataResize : Boolean = false, allowAddressResize : Boolean = false, allowTagResize : Boolean = false) : Unit = {
|
||||
this.CYC <> that.CYC
|
||||
this.STB <> that.STB
|
||||
this.WE <> that.WE
|
||||
this.ACK <> that.ACK
|
||||
|
||||
if(allowDataResize){
|
||||
this.DAT_MISO.resized <> that.DAT_MISO
|
||||
this.DAT_MOSI <> that.DAT_MOSI.resized
|
||||
} else {
|
||||
this.DAT_MOSI <> that.DAT_MOSI
|
||||
this.DAT_MISO <> that.DAT_MISO
|
||||
}
|
||||
|
||||
if(allowAddressResize){
|
||||
this.ADR <> that.ADR.resized
|
||||
} else {
|
||||
this.ADR <> that.ADR
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
// OPTIONAL FLOW CONTROS //
|
||||
///////////////////////////
|
||||
if(this.config.useSTALL && that.config.useSTALL) this.STALL <> that.STALL
|
||||
if(this.config.useERR && that.config.useERR) this.ERR <> that.ERR
|
||||
if(this.config.useRTY && that.config.useRTY) this.RTY <> that.RTY
|
||||
if(this.config.useSEL && that.config.useSEL) this.SEL <> that.SEL
|
||||
if(this.config.useCTI && that.config.useCTI) this.CTI <> that.CTI
|
||||
|
||||
//////////
|
||||
// TAGS //
|
||||
//////////
|
||||
if(this.config.useTGA && that.config.useTGA)
|
||||
if(allowTagResize) this.TGA <> that.TGA.resized else this.TGA <> that.TGA
|
||||
|
||||
if(this.config.useTGC && that.config.useTGC)
|
||||
if(allowTagResize) this.TGC <> that.TGC.resized else this.TGC <> that.TGC
|
||||
|
||||
if(this.config.useBTE && that.config.useBTE)
|
||||
if(allowTagResize) this.BTE <> that.BTE.resized else this.BTE <> that.BTE
|
||||
|
||||
if(this.config.useTGD && that.config.useTGD){
|
||||
if(allowTagResize){
|
||||
this.TGD_MISO <> that.TGD_MISO.resized
|
||||
this.TGD_MOSI <> that.TGD_MOSI.resized
|
||||
} else {
|
||||
this.TGD_MISO <> that.TGD_MISO
|
||||
this.TGD_MOSI <> that.TGD_MOSI
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Connect common Wishbone signals
|
||||
* @example{{{wishbone1 <-> wishbone2}}}
|
||||
*/
|
||||
def <-> (sink : Wishbone) : Unit = {
|
||||
/////////////////////
|
||||
// MINIMAL SIGNALS //
|
||||
/////////////////////
|
||||
sink.CYC <> this.CYC
|
||||
sink.ADR <> this.ADR
|
||||
sink.DAT_MOSI <> this.DAT_MOSI
|
||||
sink.DAT_MISO <> this.DAT_MISO
|
||||
sink.STB <> this.STB
|
||||
sink.WE <> this.WE
|
||||
sink.ACK <> this.ACK
|
||||
|
||||
///////////////////////////
|
||||
// OPTIONAL FLOW CONTROS //
|
||||
///////////////////////////
|
||||
if(this.config.useSTALL && sink.config.useSTALL) sink.STALL <> this.STALL
|
||||
if(this.config.useERR && sink.config.useERR) sink.ERR <> this.ERR
|
||||
if(this.config.useRTY && sink.config.useRTY) sink.RTY <> this.RTY
|
||||
if(this.config.useSEL && sink.config.useSEL) sink.SEL <> this.SEL
|
||||
|
||||
//////////
|
||||
// TAGS //
|
||||
//////////
|
||||
if(this.config.useTGA && sink.config.useTGA) sink.TGA <> this.TGA
|
||||
if(this.config.useTGC && sink.config.useTGC) sink.TGC <> this.TGC
|
||||
if(this.config.useCTI && sink.config.useCTI) sink.CTI <> this.CTI
|
||||
if(this.config.useBTE && sink.config.useBTE) sink.BTE <> this.BTE
|
||||
if(this.config.useTGD && sink.config.useTGD){
|
||||
sink.TGD_MISO <> this.TGD_MISO
|
||||
sink.TGD_MOSI <> this.TGD_MOSI
|
||||
}
|
||||
}
|
||||
|
||||
/** Clear all the relevant signals in the wishbone bus
|
||||
* @example{{{
|
||||
* val wishbone1 = master(Wishbone(WishboneConfig(8,8)))
|
||||
* val wishbone2 = slave(Wishbone(WishboneConfig(8,8)))
|
||||
* val wishbone2 = slave(Wishbone(WishboneConfig(8,8).withDataTag(8)))
|
||||
*
|
||||
* // this will clear only the following signals: CYC,ADR,DAT_MOSI,STB,WE
|
||||
* wishbone1.clearAll()
|
||||
* // this will clear only the following signals: DAT_MISO,ACK
|
||||
* wishbone2.clearAll()
|
||||
* // this will clear only the following signals: DAT_MISO,ACK,TGD_MISO
|
||||
* wishbone3.clearAll()
|
||||
* }}}
|
||||
*/
|
||||
def clearAll() : Unit = {
|
||||
/////////////////////
|
||||
// MINIMAl SIGLALS //
|
||||
/////////////////////
|
||||
if( isMasterInterface) this.CYC.clear()
|
||||
if( isMasterInterface) this.ADR.clearAll()
|
||||
if( isMasterInterface) this.DAT_MOSI.clearAll()
|
||||
if(!isMasterInterface) this.DAT_MISO.clearAll()
|
||||
if( isMasterInterface) this.STB.clear()
|
||||
if( isMasterInterface) this.WE.clear()
|
||||
if(!isMasterInterface) this.ACK.clear()
|
||||
|
||||
///////////////////////////
|
||||
// OPTIONAL FLOW CONTROS //
|
||||
///////////////////////////
|
||||
if(this.config.useSTALL && !isMasterInterface) this.STALL.clear()
|
||||
if(this.config.useERR && !isMasterInterface) this.ERR.clear()
|
||||
if(this.config.useRTY && !isMasterInterface) this.RTY.clear()
|
||||
if(this.config.useSEL && isMasterInterface) this.SEL.clearAll()
|
||||
|
||||
//////////
|
||||
// TAGS //
|
||||
//////////
|
||||
if(this.config.useTGA && isMasterInterface) this.TGA.clearAll()
|
||||
if(this.config.useTGC && isMasterInterface) this.TGC.clearAll()
|
||||
if(this.config.useCTI && isMasterInterface) this.CTI.clearAll()
|
||||
if(this.config.useBTE && isMasterInterface) this.BTE.clearAll()
|
||||
if(this.config.useTGD && !isMasterInterface) this.TGD_MISO.clearAll()
|
||||
if(this.config.useTGD && isMasterInterface) this.TGD_MOSI.clearAll()
|
||||
}
|
||||
}
|
|
@ -14,7 +14,7 @@ trait Pipeline {
|
|||
val plugins = ArrayBuffer[Plugin[T]]()
|
||||
var stages = ArrayBuffer[Stage]()
|
||||
var unremovableStages = mutable.Set[Stage]()
|
||||
val things = mutable.HashMap[PipelineThing[_], Any]()
|
||||
val things = mutable.LinkedHashMap[PipelineThing[_], Any]()
|
||||
// val services = ArrayBuffer[Any]()
|
||||
|
||||
def stageBefore(stage : Stage) = stages(indexOf(stage)-1)
|
||||
|
@ -78,7 +78,7 @@ trait Pipeline {
|
|||
def setInsertStageId(stageId : Int) = insertStageId = stageId
|
||||
}
|
||||
|
||||
val inputOutputKeys = mutable.HashMap[Stageable[Data],KeyInfo]()
|
||||
val inputOutputKeys = mutable.LinkedHashMap[Stageable[Data],KeyInfo]()
|
||||
val insertedStageable = mutable.Set[Stageable[Data]]()
|
||||
for(stageIndex <- 0 until stages.length; stage = stages(stageIndex)){
|
||||
stage.inserts.keysIterator.foreach(signal => inputOutputKeys.getOrElseUpdate(signal,new KeyInfo).setInsertStageId(stageIndex))
|
||||
|
|
|
@ -4,6 +4,8 @@ import spinal.core._
|
|||
|
||||
|
||||
object Riscv{
|
||||
def misaToInt(values : String) = values.toLowerCase.map(e => 1 << (e-'a')).reduce(_ | _)
|
||||
|
||||
def funct7Range = 31 downto 25
|
||||
def rdRange = 11 downto 7
|
||||
def funct3Range = 14 downto 12
|
||||
|
@ -157,7 +159,10 @@ object Riscv{
|
|||
|
||||
|
||||
|
||||
def UCYCLE = 0xC00 // UR Machine ucycle counter.
|
||||
def UCYCLEH = 0xC80
|
||||
def UCYCLE = 0xC00 // UR Machine ucycle counter.
|
||||
def UCYCLEH = 0xC80
|
||||
def UTIME = 0xC01 // rdtime
|
||||
def UTIMEH = 0xC81
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ trait JumpService{
|
|||
|
||||
trait IBusFetcher{
|
||||
def haltIt() : Unit
|
||||
def flushIt() : Unit
|
||||
def incoming() : Bool
|
||||
def pcValid(stage : Stage) : Bool
|
||||
def getInjectionPort() : Stream[Bits]
|
||||
|
@ -66,20 +65,28 @@ trait RegFileService{
|
|||
|
||||
case class MemoryTranslatorCmd() extends Bundle{
|
||||
val isValid = Bool
|
||||
val isStuck = Bool
|
||||
val virtualAddress = UInt(32 bits)
|
||||
val bypassTranslation = Bool
|
||||
}
|
||||
case class MemoryTranslatorRsp() extends Bundle{
|
||||
case class MemoryTranslatorRsp(p : MemoryTranslatorBusParameter) extends Bundle{
|
||||
val physicalAddress = UInt(32 bits)
|
||||
val isIoAccess = Bool
|
||||
val allowRead, allowWrite, allowExecute = Bool
|
||||
val exception = Bool
|
||||
val refilling = Bool
|
||||
val bypassTranslation = Bool
|
||||
val ways = Vec(MemoryTranslatorRspWay(), p.wayCount)
|
||||
}
|
||||
case class MemoryTranslatorRspWay() extends Bundle{
|
||||
val sel = Bool()
|
||||
val physical = UInt(32 bits)
|
||||
}
|
||||
|
||||
case class MemoryTranslatorBus() extends Bundle with IMasterSlave{
|
||||
val cmd = MemoryTranslatorCmd()
|
||||
val rsp = MemoryTranslatorRsp()
|
||||
case class MemoryTranslatorBusParameter(wayCount : Int = 0, latency : Int = 0)
|
||||
case class MemoryTranslatorBus(p : MemoryTranslatorBusParameter) extends Bundle with IMasterSlave{
|
||||
val cmd = Vec(MemoryTranslatorCmd(), p.latency + 1)
|
||||
val rsp = MemoryTranslatorRsp(p)
|
||||
val end = Bool
|
||||
val busy = Bool
|
||||
|
||||
|
|
|
@ -61,15 +61,15 @@ class Stage() extends Area{
|
|||
}
|
||||
|
||||
|
||||
val inputs = mutable.HashMap[Stageable[Data],Data]()
|
||||
val outputs = mutable.HashMap[Stageable[Data],Data]()
|
||||
val signals = mutable.HashMap[Stageable[Data],Data]()
|
||||
val inserts = mutable.HashMap[Stageable[Data],Data]()
|
||||
val inputs = mutable.LinkedHashMap[Stageable[Data],Data]()
|
||||
val outputs = mutable.LinkedHashMap[Stageable[Data],Data]()
|
||||
val signals = mutable.LinkedHashMap[Stageable[Data],Data]()
|
||||
val inserts = mutable.LinkedHashMap[Stageable[Data],Data]()
|
||||
|
||||
val inputsDefault = mutable.HashMap[Stageable[Data],Data]()
|
||||
val outputsDefault = mutable.HashMap[Stageable[Data],Data]()
|
||||
val inputsDefault = mutable.LinkedHashMap[Stageable[Data],Data]()
|
||||
val outputsDefault = mutable.LinkedHashMap[Stageable[Data],Data]()
|
||||
|
||||
val dontSample = mutable.HashMap[Stageable[_], ArrayBuffer[Bool]]()
|
||||
val dontSample = mutable.LinkedHashMap[Stageable[_], ArrayBuffer[Bool]]()
|
||||
|
||||
def dontSampleStageable(s : Stageable[_], cond : Bool): Unit ={
|
||||
dontSample.getOrElseUpdate(s, ArrayBuffer[Bool]()) += cond
|
||||
|
|
|
@ -26,76 +26,106 @@ import vexriscv.ip._
|
|||
import spinal.lib.bus.avalon.AvalonMM
|
||||
import spinal.lib.eda.altera.{InterruptReceiverTag, ResetEmitterTag}
|
||||
|
||||
|
||||
// make clean all SEED=42 MMU=no STOP_ON_ERROR=yes DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes SUPERVISOR=yes REDO=1 DHRYSTONE=yes LRSC=yes AMO=yes LINUX_REGRESSION=yes TRACE=yes TRACE_START=1000000000 FLOW_INFO=ye IBUS_DATA_WIDTH=128 DBUS_DATA_WIDTH=128
|
||||
//make clean all SEED=42 MMU=no STOP_ON_ERROR=yes DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes SUPERVISOR=yes REDO=1 DHRYSTONE=yes LRSC=yes AMO=yes TRACE=yes TRACE_START=1000000000 FLOW_INFO=ye IBUS_DATA_WIDTH=128 DBUS_DATA_WIDTH=128 LINUX_SOC_SMP=yes VMLINUX=../../../../../buildroot/output/images/Image RAMDISK=../../../../../buildroot/output/images/rootfs.cpio DTB=../../../../../buildroot/output/images/dtb EMULATOR=../../../../../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin
|
||||
object TestsWorkspace {
|
||||
def main(args: Array[String]) {
|
||||
def configFull = {
|
||||
val config = VexRiscvConfig(
|
||||
plugins = List(
|
||||
// new IBusSimplePlugin(
|
||||
// resetVector = 0x80000000l,
|
||||
// cmdForkOnSecondStage = false,
|
||||
// cmdForkPersistence = false,
|
||||
// prediction = NONE,
|
||||
// historyRamSizeLog2 = 10,
|
||||
// catchAccessFault = false,
|
||||
// compressedGen = false,
|
||||
// busLatencyMin = 1,
|
||||
// injectorStage = true
|
||||
// ),
|
||||
new MmuPlugin(
|
||||
ioRange = x => x(31 downto 28) === 0xF
|
||||
),
|
||||
//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 = NONE,
|
||||
injectorStage = true,
|
||||
prediction = STATIC,
|
||||
injectorStage = false,
|
||||
config = InstructionCacheConfig(
|
||||
cacheSize = 4096,
|
||||
bytePerLine = 32,
|
||||
wayCount = 1,
|
||||
cacheSize = 4096*2,
|
||||
bytePerLine = 64,
|
||||
wayCount = 2,
|
||||
addressWidth = 32,
|
||||
cpuDataWidth = 32,
|
||||
memDataWidth = 32,
|
||||
memDataWidth = 128,
|
||||
catchIllegalAccess = true,
|
||||
catchAccessFault = true,
|
||||
asyncTagMemory = false,
|
||||
twoCycleRam = false,
|
||||
twoCycleCache = true
|
||||
twoCycleRam = true,
|
||||
twoCycleCache = true,
|
||||
reducedBankWidth = true
|
||||
// )
|
||||
),
|
||||
memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
||||
portTlbSize = 4
|
||||
memoryTranslatorPortConfig = MmuPortConfig(
|
||||
portTlbSize = 4,
|
||||
latency = 1,
|
||||
earlyRequireMmuLockup = true,
|
||||
earlyCacheHits = true
|
||||
)
|
||||
),
|
||||
// ).newTightlyCoupledPort(TightlyCoupledPortParameter("iBusTc", a => a(30 downto 28) === 0x0 && a(5))),
|
||||
// new DBusSimplePlugin(
|
||||
// catchAddressMisaligned = true,
|
||||
// catchAccessFault = false,
|
||||
// earlyInjection = false
|
||||
// ),
|
||||
// ).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,
|
||||
bytePerLine = 32,
|
||||
cacheSize = 4096*1,
|
||||
bytePerLine = 64,
|
||||
wayCount = 1,
|
||||
addressWidth = 32,
|
||||
cpuDataWidth = 32,
|
||||
memDataWidth = 32,
|
||||
memDataWidth = 128,
|
||||
catchAccessError = true,
|
||||
catchIllegal = true,
|
||||
catchUnaligned = true,
|
||||
withLrSc = true
|
||||
withLrSc = true,
|
||||
withAmo = true,
|
||||
withExclusive = true,
|
||||
withInvalidate = true,
|
||||
pendingMax = 32
|
||||
// )
|
||||
),
|
||||
// memoryTranslatorPortConfig = null
|
||||
memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
||||
portTlbSize = 6
|
||||
memoryTranslatorPortConfig = MmuPortConfig(
|
||||
portTlbSize = 4,
|
||||
latency = 1,
|
||||
earlyRequireMmuLockup = true,
|
||||
earlyCacheHits = true
|
||||
)
|
||||
),
|
||||
// new StaticMemoryTranslatorPlugin(
|
||||
|
||||
// new MemoryTranslatorPlugin(
|
||||
// tlbSize = 32,
|
||||
// virtualRange = _(31 downto 28) === 0xC,
|
||||
// ioRange = _(31 downto 28) === 0xF
|
||||
// ),
|
||||
new MemoryTranslatorPlugin(
|
||||
tlbSize = 32,
|
||||
virtualRange = _(31 downto 28) === 0xC,
|
||||
ioRange = _(31 downto 28) === 0xF
|
||||
),
|
||||
|
||||
new DecoderSimplePlugin(
|
||||
catchIllegalInstruction = true
|
||||
),
|
||||
|
@ -107,7 +137,7 @@ object TestsWorkspace {
|
|||
new SrcPlugin(
|
||||
separatedAddSub = false
|
||||
),
|
||||
new FullBarrelShifterPlugin(earlyInjection = true),
|
||||
new FullBarrelShifterPlugin(earlyInjection = false),
|
||||
// new LightShifterPlugin,
|
||||
new HazardSimplePlugin(
|
||||
bypassExecute = true,
|
||||
|
@ -128,7 +158,7 @@ object TestsWorkspace {
|
|||
divUnrollFactor = 1
|
||||
),
|
||||
// new DivPlugin,
|
||||
new CsrPlugin(CsrPluginConfig.all(0x80000020l)),
|
||||
new CsrPlugin(CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = false, misaExtensionsInit = Riscv.misaToInt("imas"))),
|
||||
// new CsrPlugin(//CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = true)/*
|
||||
// CsrPluginConfig(
|
||||
// catchIllegalAccess = false,
|
||||
|
@ -154,9 +184,9 @@ object TestsWorkspace {
|
|||
// )),
|
||||
new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
|
||||
new BranchPlugin(
|
||||
earlyBranch = true,
|
||||
earlyBranch = false,
|
||||
catchAddressMisaligned = true,
|
||||
fenceiGenAsAJump = true
|
||||
fenceiGenAsAJump = false
|
||||
),
|
||||
new YamlPlugin("cpu0.yaml")
|
||||
)
|
||||
|
@ -244,10 +274,3 @@ object TestsWorkspace {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO DivPlugin should not used MixedDivider (double twoComplement)
|
||||
//TODO DivPlugin should register the twoComplement output before pipeline insertion
|
||||
//TODO MulPlugin doesn't fit well on Artix (FMAX)
|
||||
//TODO PcReg design is unoptimized by Artix synthesis
|
||||
//TODO FMAX SRC mux + bipass mux prioriti
|
||||
//TODO FMAX, isFiring is to pesimisstinc in some cases(include removeIt flushed ..)
|
|
@ -23,6 +23,12 @@ case class VexRiscvConfig(){
|
|||
val plugins = ArrayBuffer[Plugin[VexRiscv]]()
|
||||
|
||||
def add(that : Plugin[VexRiscv]) : this.type = {plugins += that;this}
|
||||
def find[T](clazz: Class[T]): Option[T] = {
|
||||
plugins.find(_.getClass == clazz) match {
|
||||
case Some(x) => Some(x.asInstanceOf[T])
|
||||
case None => None
|
||||
}
|
||||
}
|
||||
|
||||
//Default Stageables
|
||||
object IS_RVC extends Stageable(Bool)
|
||||
|
@ -36,7 +42,6 @@ case class VexRiscvConfig(){
|
|||
object PC extends Stageable(UInt(32 bits))
|
||||
object PC_CALC_WITHOUT_JUMP extends Stageable(UInt(32 bits))
|
||||
object INSTRUCTION extends Stageable(Bits(32 bits))
|
||||
object INSTRUCTION_READY extends Stageable(Bool)
|
||||
object INSTRUCTION_ANTICIPATED extends Stageable(Bits(32 bits))
|
||||
object LEGAL_INSTRUCTION extends Stageable(Bool)
|
||||
object REGFILE_WRITE_VALID extends Stageable(Bool)
|
||||
|
|
164
src/main/scala/vexriscv/VexRiscvBmbGenerator.scala
Normal file
164
src/main/scala/vexriscv/VexRiscvBmbGenerator.scala
Normal file
|
@ -0,0 +1,164 @@
|
|||
package vexriscv
|
||||
|
||||
import spinal.core._
|
||||
import spinal.lib.bus.bmb.{Bmb, BmbAccessCapabilities, BmbAccessParameter, BmbImplicitDebugDecoder, BmbInvalidationParameter, BmbParameter, BmbInterconnectGenerator}
|
||||
import spinal.lib.bus.misc.AddressMapping
|
||||
import spinal.lib.com.jtag.{Jtag, JtagTapInstructionCtrl}
|
||||
import spinal.lib.generator._
|
||||
import spinal.lib.slave
|
||||
import vexriscv.plugin._
|
||||
|
||||
|
||||
object VexRiscvBmbGenerator{
|
||||
val DEBUG_NONE = 0
|
||||
val DEBUG_JTAG = 1
|
||||
val DEBUG_JTAG_CTRL = 2
|
||||
val DEBUG_BUS = 3
|
||||
val DEBUG_BMB = 4
|
||||
}
|
||||
|
||||
case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGenerator = null) extends Generator {
|
||||
import VexRiscvBmbGenerator._
|
||||
|
||||
val config = Handle[VexRiscvConfig]
|
||||
val withDebug = Handle[Int]
|
||||
val debugClockDomain = Handle[ClockDomain]
|
||||
val debugReset = Handle[Bool]
|
||||
val debugAskReset = Handle[() => Unit]
|
||||
val hardwareBreakpointCount = Handle(0)
|
||||
|
||||
val iBus, dBus = product[Bmb]
|
||||
|
||||
val externalInterrupt = product[Bool]
|
||||
val externalSupervisorInterrupt = product[Bool]
|
||||
val timerInterrupt = product[Bool]
|
||||
val softwareInterrupt = product[Bool]
|
||||
|
||||
def setTimerInterrupt(that: Handle[Bool]) = Dependable(that, timerInterrupt){timerInterrupt := that}
|
||||
def setSoftwareInterrupt(that: Handle[Bool]) = Dependable(that, softwareInterrupt){softwareInterrupt := that}
|
||||
|
||||
|
||||
def disableDebug() = {
|
||||
withDebug.load(DEBUG_NONE)
|
||||
}
|
||||
|
||||
def enableJtag(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator) : Unit = debugCd{
|
||||
this.debugClockDomain.merge(debugCd.outputClockDomain)
|
||||
val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH)
|
||||
debugAskReset.load(null)
|
||||
withDebug.load(DEBUG_JTAG)
|
||||
}
|
||||
|
||||
def enableJtagInstructionCtrl(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator) : Unit = debugCd{
|
||||
this.debugClockDomain.merge(debugCd.outputClockDomain)
|
||||
val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH)
|
||||
debugAskReset.load(null)
|
||||
withDebug.load(DEBUG_JTAG_CTRL)
|
||||
dependencies += jtagClockDomain
|
||||
}
|
||||
|
||||
def enableDebugBus(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator) : Unit = debugCd{
|
||||
this.debugClockDomain.merge(debugCd.outputClockDomain)
|
||||
val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH)
|
||||
debugAskReset.load(null)
|
||||
withDebug.load(DEBUG_BUS)
|
||||
}
|
||||
|
||||
val debugBmbAccessSource = Handle[BmbAccessCapabilities]
|
||||
val debugBmbAccessRequirements = Handle[BmbAccessParameter]
|
||||
def enableDebugBmb(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator, mapping : AddressMapping)(implicit debugMaster : BmbImplicitDebugDecoder = null) : Unit = debugCd{
|
||||
this.debugClockDomain.merge(debugCd.outputClockDomain)
|
||||
val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH)
|
||||
debugAskReset.load(null)
|
||||
withDebug.load(DEBUG_BMB)
|
||||
val slaveModel = interconnectSmp.addSlave(
|
||||
accessSource = debugBmbAccessSource,
|
||||
accessCapabilities = debugBmbAccessSource.derivate(DebugExtensionBus.getBmbAccessParameter(_)),
|
||||
accessRequirements = debugBmbAccessRequirements,
|
||||
bus = debugBmb,
|
||||
mapping = mapping
|
||||
)
|
||||
slaveModel.onClockDomain(debugCd.outputClockDomain)
|
||||
debugBmb.derivatedFrom(debugBmbAccessRequirements)(Bmb(_))
|
||||
if(debugMaster != null) interconnectSmp.addConnection(debugMaster.bus, debugBmb)
|
||||
dependencies += debugBmb
|
||||
}
|
||||
|
||||
|
||||
dependencies ++= List(config)
|
||||
dependencies += Dependable(withDebug) {
|
||||
if (withDebug.get != DEBUG_NONE) {
|
||||
dependencies ++= List(debugClockDomain, debugAskReset)
|
||||
}
|
||||
}
|
||||
|
||||
val jtag = add task (withDebug.get == DEBUG_JTAG generate slave(Jtag()))
|
||||
val jtagInstructionCtrl = withDebug.produce(withDebug.get == DEBUG_JTAG_CTRL generate JtagTapInstructionCtrl())
|
||||
val debugBus = withDebug.produce(withDebug.get == DEBUG_BUS generate DebugExtensionBus())
|
||||
val debugBmb = Handle[Bmb]
|
||||
val jtagClockDomain = Handle[ClockDomain]
|
||||
|
||||
val logic = add task new Area {
|
||||
withDebug.get != DEBUG_NONE generate new Area {
|
||||
config.add(new DebugPlugin(debugClockDomain, hardwareBreakpointCount))
|
||||
}
|
||||
|
||||
val cpu = new VexRiscv(config)
|
||||
for (plugin <- cpu.plugins) plugin match {
|
||||
case plugin: IBusSimplePlugin => iBus.load(plugin.iBus.toBmb())
|
||||
case plugin: DBusSimplePlugin => dBus.load(plugin.dBus.toBmb())
|
||||
case plugin: IBusCachedPlugin => iBus.load(plugin.iBus.toBmb())
|
||||
case plugin: DBusCachedPlugin => dBus.load(plugin.dBus.toBmb())
|
||||
case plugin: CsrPlugin => {
|
||||
externalInterrupt load plugin.externalInterrupt
|
||||
timerInterrupt load plugin.timerInterrupt
|
||||
softwareInterrupt load plugin.softwareInterrupt
|
||||
if (plugin.config.supervisorGen) externalSupervisorInterrupt load plugin.externalInterruptS
|
||||
}
|
||||
case plugin: DebugPlugin => plugin.debugClockDomain {
|
||||
if(debugAskReset.get != null) when(RegNext(plugin.io.resetOut)) {
|
||||
debugAskReset.get()
|
||||
} else {
|
||||
debugReset.load(RegNext(plugin.io.resetOut))
|
||||
}
|
||||
|
||||
withDebug.get match {
|
||||
case DEBUG_JTAG => jtag <> plugin.io.bus.fromJtag()
|
||||
case DEBUG_JTAG_CTRL => jtagInstructionCtrl <> plugin.io.bus.fromJtagInstructionCtrl(jtagClockDomain)
|
||||
case DEBUG_BUS => debugBus <> plugin.io.bus
|
||||
case DEBUG_BMB => debugBmb >> plugin.io.bus.fromBmb()
|
||||
}
|
||||
}
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
|
||||
val parameterGenerator = new Generator {
|
||||
val iBusParameter, dBusParameter = product[BmbParameter]
|
||||
dependencies += config
|
||||
|
||||
add task {
|
||||
for (plugin <- config.plugins) plugin match {
|
||||
case plugin: IBusSimplePlugin => iBusParameter.load(IBusSimpleBus.getBmbParameter())
|
||||
case plugin: DBusSimplePlugin => dBusParameter.load(DBusSimpleBus.getBmbParameter())
|
||||
case plugin: IBusCachedPlugin => iBusParameter.load(plugin.config.getBmbParameter())
|
||||
case plugin: DBusCachedPlugin => dBusParameter.load(plugin.config.getBmbParameter())
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val invalidationSource = Handle[BmbInvalidationParameter]
|
||||
val invalidationRequirements = Handle[BmbInvalidationParameter]
|
||||
if(interconnectSmp != null){
|
||||
interconnectSmp.addMaster(accessRequirements = parameterGenerator.iBusParameter.derivate(_.access), bus = iBus)
|
||||
interconnectSmp.addMaster(
|
||||
accessRequirements = parameterGenerator.dBusParameter.derivate(_.access),
|
||||
invalidationSource = invalidationSource,
|
||||
invalidationCapabilities = invalidationSource,
|
||||
invalidationRequirements = invalidationRequirements,
|
||||
bus = dBus
|
||||
)
|
||||
}
|
||||
|
||||
}
|
|
@ -13,7 +13,9 @@ import spinal.lib.com.uart.{Apb3UartCtrl, Uart, UartCtrlGenerics, UartCtrlMemory
|
|||
import spinal.lib.graphic.RgbConfig
|
||||
import spinal.lib.graphic.vga.{Axi4VgaCtrl, Axi4VgaCtrlGenerics, Vga}
|
||||
import spinal.lib.io.TriStateArray
|
||||
import spinal.lib.memory.sdram.SdramGeneration.SDR
|
||||
import spinal.lib.memory.sdram._
|
||||
import spinal.lib.memory.sdram.sdr.{Axi4SharedSdramCtrl, IS42x320D, SdramInterface, SdramTimings}
|
||||
import spinal.lib.misc.HexTools
|
||||
import spinal.lib.soc.pinsec.{PinsecTimerCtrl, PinsecTimerCtrlExternal}
|
||||
import spinal.lib.system.debugger.{JtagAxi4SharedDebugger, JtagBridge, SystemDebugger, SystemDebuggerConfig}
|
||||
|
@ -412,6 +414,7 @@ object BrieyDe0Nano{
|
|||
def main(args: Array[String]) {
|
||||
object IS42x160G {
|
||||
def layout = SdramLayout(
|
||||
generation = SDR,
|
||||
bankWidth = 2,
|
||||
columnWidth = 9,
|
||||
rowWidth = 13,
|
||||
|
|
72
src/main/scala/vexriscv/demo/GenCustomInterrupt.scala
Normal file
72
src/main/scala/vexriscv/demo/GenCustomInterrupt.scala
Normal file
|
@ -0,0 +1,72 @@
|
|||
package vexriscv.demo
|
||||
|
||||
import spinal.core._
|
||||
import vexriscv.plugin._
|
||||
import vexriscv.{VexRiscv, VexRiscvConfig, plugin}
|
||||
|
||||
/**
|
||||
* Created by spinalvm on 15.06.17.
|
||||
*/
|
||||
object GenCustomInterrupt extends App{
|
||||
def cpu() = new VexRiscv(
|
||||
config = VexRiscvConfig(
|
||||
plugins = List(
|
||||
new UserInterruptPlugin(
|
||||
interruptName = "miaou",
|
||||
code = 20
|
||||
),
|
||||
new UserInterruptPlugin(
|
||||
interruptName = "rawrrr",
|
||||
code = 24
|
||||
),
|
||||
new CsrPlugin(
|
||||
CsrPluginConfig.smallest.copy(
|
||||
xtvecModeGen = true,
|
||||
mtvecAccess = CsrAccess.WRITE_ONLY
|
||||
)
|
||||
),
|
||||
new IBusSimplePlugin(
|
||||
resetVector = 0x80000000l,
|
||||
cmdForkOnSecondStage = false,
|
||||
cmdForkPersistence = false,
|
||||
prediction = NONE,
|
||||
catchAccessFault = false,
|
||||
compressedGen = false
|
||||
),
|
||||
new DBusSimplePlugin(
|
||||
catchAddressMisaligned = false,
|
||||
catchAccessFault = false
|
||||
),
|
||||
new DecoderSimplePlugin(
|
||||
catchIllegalInstruction = false
|
||||
),
|
||||
new RegFilePlugin(
|
||||
regFileReadyKind = plugin.SYNC,
|
||||
zeroBoot = false
|
||||
),
|
||||
new IntAluPlugin,
|
||||
new SrcPlugin(
|
||||
separatedAddSub = false,
|
||||
executeInsertion = true
|
||||
),
|
||||
new LightShifterPlugin,
|
||||
new HazardSimplePlugin(
|
||||
bypassExecute = true,
|
||||
bypassMemory = true,
|
||||
bypassWriteBack = true,
|
||||
bypassWriteBackBuffer = true,
|
||||
pessimisticUseSrc = false,
|
||||
pessimisticWriteRegFile = false,
|
||||
pessimisticAddressMatch = false
|
||||
),
|
||||
new BranchPlugin(
|
||||
earlyBranch = false,
|
||||
catchAddressMisaligned = false
|
||||
),
|
||||
new YamlPlugin("cpu0.yaml")
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
SpinalVerilog(cpu())
|
||||
}
|
|
@ -20,7 +20,7 @@ object GenFullNoMmuMaxPerf extends App{
|
|||
prediction = DYNAMIC_TARGET,
|
||||
historyRamSizeLog2 = 8,
|
||||
config = InstructionCacheConfig(
|
||||
cacheSize = 4096*4,
|
||||
cacheSize = 4096*2,
|
||||
bytePerLine =32,
|
||||
wayCount = 1,
|
||||
addressWidth = 32,
|
||||
|
@ -29,13 +29,13 @@ object GenFullNoMmuMaxPerf extends App{
|
|||
catchIllegalAccess = true,
|
||||
catchAccessFault = true,
|
||||
asyncTagMemory = false,
|
||||
twoCycleRam = true,
|
||||
twoCycleRam = false,
|
||||
twoCycleCache = true
|
||||
)
|
||||
),
|
||||
new DBusCachedPlugin(
|
||||
config = new DataCacheConfig(
|
||||
cacheSize = 4096*4,
|
||||
cacheSize = 4096*2,
|
||||
bytePerLine = 32,
|
||||
wayCount = 1,
|
||||
addressWidth = 32,
|
||||
|
@ -76,7 +76,7 @@ object GenFullNoMmuMaxPerf extends App{
|
|||
new CsrPlugin(CsrPluginConfig.small),
|
||||
new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
|
||||
new BranchPlugin(
|
||||
earlyBranch = true,
|
||||
earlyBranch = false,
|
||||
catchAddressMisaligned = true
|
||||
),
|
||||
new YamlPlugin("cpu0.yaml")
|
||||
|
|
|
@ -56,7 +56,7 @@ object GenNoCacheNoMmuMaxPerf extends App{
|
|||
new CsrPlugin(CsrPluginConfig.small),
|
||||
new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
|
||||
new BranchPlugin(
|
||||
earlyBranch = true,
|
||||
earlyBranch = false,
|
||||
catchAddressMisaligned = true
|
||||
),
|
||||
new YamlPlugin("cpu0.yaml")
|
||||
|
|
83
src/main/scala/vexriscv/demo/GenSmallAndProductiveCfu.scala
Normal file
83
src/main/scala/vexriscv/demo/GenSmallAndProductiveCfu.scala
Normal file
|
@ -0,0 +1,83 @@
|
|||
package vexriscv.demo
|
||||
|
||||
import spinal.core._
|
||||
import vexriscv.plugin._
|
||||
import vexriscv.{VexRiscv, VexRiscvConfig, plugin}
|
||||
|
||||
/**
|
||||
* Created by spinalvm on 15.06.17.
|
||||
*/
|
||||
object GenSmallAndProductiveCfu extends App{
|
||||
def cpu() = new VexRiscv(
|
||||
config = VexRiscvConfig(
|
||||
plugins = List(
|
||||
new IBusSimplePlugin(
|
||||
resetVector = 0x80000000l,
|
||||
cmdForkOnSecondStage = false,
|
||||
cmdForkPersistence = false,
|
||||
prediction = NONE,
|
||||
catchAccessFault = false,
|
||||
compressedGen = false
|
||||
),
|
||||
new DBusSimplePlugin(
|
||||
catchAddressMisaligned = false,
|
||||
catchAccessFault = false
|
||||
),
|
||||
new CsrPlugin(CsrPluginConfig.smallest),
|
||||
new DecoderSimplePlugin(
|
||||
catchIllegalInstruction = false
|
||||
),
|
||||
new RegFilePlugin(
|
||||
regFileReadyKind = plugin.SYNC,
|
||||
zeroBoot = false
|
||||
),
|
||||
new IntAluPlugin,
|
||||
new SrcPlugin(
|
||||
separatedAddSub = false,
|
||||
executeInsertion = true
|
||||
),
|
||||
new LightShifterPlugin,
|
||||
new HazardSimplePlugin(
|
||||
bypassExecute = true,
|
||||
bypassMemory = true,
|
||||
bypassWriteBack = true,
|
||||
bypassWriteBackBuffer = true,
|
||||
pessimisticUseSrc = false,
|
||||
pessimisticWriteRegFile = false,
|
||||
pessimisticAddressMatch = false
|
||||
),
|
||||
new BranchPlugin(
|
||||
earlyBranch = false,
|
||||
catchAddressMisaligned = false
|
||||
),
|
||||
new CfuPlugin(
|
||||
stageCount = 1,
|
||||
allowZeroLatency = true,
|
||||
encodings = List(
|
||||
CfuPluginEncoding (
|
||||
instruction = M"-------------------------0001011",
|
||||
functionId = List(14 downto 12),
|
||||
input2Kind = CfuPlugin.Input2Kind.RS
|
||||
)
|
||||
),
|
||||
busParameter = CfuBusParameter(
|
||||
CFU_VERSION = 0,
|
||||
CFU_INTERFACE_ID_W = 0,
|
||||
CFU_FUNCTION_ID_W = 2,
|
||||
CFU_REORDER_ID_W = 0,
|
||||
CFU_REQ_RESP_ID_W = 0,
|
||||
CFU_INPUTS = 2,
|
||||
CFU_INPUT_DATA_W = 32,
|
||||
CFU_OUTPUTS = 1,
|
||||
CFU_OUTPUT_DATA_W = 32,
|
||||
CFU_FLOW_REQ_READY_ALWAYS = false,
|
||||
CFU_FLOW_RESP_READY_ALWAYS = false
|
||||
)
|
||||
),
|
||||
new YamlPlugin("cpu0.yaml")
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
SpinalVerilog(cpu())
|
||||
}
|
72
src/main/scala/vexriscv/demo/GenTwoThreeStage.scala
Normal file
72
src/main/scala/vexriscv/demo/GenTwoThreeStage.scala
Normal file
|
@ -0,0 +1,72 @@
|
|||
package vexriscv.demo
|
||||
|
||||
import spinal.core.SpinalVerilog
|
||||
import vexriscv.{VexRiscv, VexRiscvConfig, plugin}
|
||||
import vexriscv.plugin.{BranchPlugin, CsrPlugin, CsrPluginConfig, DBusSimplePlugin, DecoderSimplePlugin, DivPlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusSimplePlugin, IntAluPlugin, LightShifterPlugin, MulPlugin, MulSimplePlugin, NONE, RegFilePlugin, SrcPlugin, YamlPlugin}
|
||||
|
||||
object GenTwoThreeStage extends App{
|
||||
def cpu(withMulDiv : Boolean,
|
||||
bypass : Boolean,
|
||||
barrielShifter : Boolean,
|
||||
withMemoryStage : Boolean) = new VexRiscv(
|
||||
config = VexRiscvConfig(
|
||||
withMemoryStage = withMemoryStage,
|
||||
withWriteBackStage = false,
|
||||
plugins = List(
|
||||
new IBusSimplePlugin(
|
||||
resetVector = 0x80000000l,
|
||||
cmdForkOnSecondStage = false,
|
||||
cmdForkPersistence = false,
|
||||
prediction = NONE,
|
||||
catchAccessFault = false,
|
||||
compressedGen = false,
|
||||
injectorStage = false
|
||||
),
|
||||
new DBusSimplePlugin(
|
||||
catchAddressMisaligned = false,
|
||||
catchAccessFault = false
|
||||
),
|
||||
new CsrPlugin(CsrPluginConfig.smallest),
|
||||
new DecoderSimplePlugin(
|
||||
catchIllegalInstruction = false
|
||||
),
|
||||
new RegFilePlugin(
|
||||
regFileReadyKind = plugin.SYNC,
|
||||
readInExecute = true,
|
||||
zeroBoot = true,
|
||||
x0Init = false
|
||||
),
|
||||
new IntAluPlugin,
|
||||
new SrcPlugin(
|
||||
separatedAddSub = false,
|
||||
executeInsertion = true
|
||||
),
|
||||
new HazardSimplePlugin(
|
||||
bypassExecute = bypass,
|
||||
bypassMemory = bypass,
|
||||
bypassWriteBack = bypass,
|
||||
bypassWriteBackBuffer = bypass,
|
||||
pessimisticUseSrc = false,
|
||||
pessimisticWriteRegFile = false,
|
||||
pessimisticAddressMatch = false
|
||||
),
|
||||
new BranchPlugin(
|
||||
earlyBranch = true,
|
||||
catchAddressMisaligned = false
|
||||
),
|
||||
new YamlPlugin("cpu0.yaml")
|
||||
) ++ (if(!withMulDiv) Nil else List(
|
||||
new MulSimplePlugin,
|
||||
new DivPlugin
|
||||
)) ++ List(if(!barrielShifter)
|
||||
new LightShifterPlugin
|
||||
else
|
||||
new FullBarrelShifterPlugin(
|
||||
earlyInjection = true
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
SpinalVerilog(cpu(true,true,true,true))
|
||||
}
|
|
@ -119,7 +119,12 @@ make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes COMPRE
|
|||
rm -rf cpio
|
||||
mkdir cpio
|
||||
cd cpio
|
||||
cpio -idv < ../rootfs.cpio
|
||||
sudo cpio -i < ../rootfs.cpio
|
||||
cd ..
|
||||
|
||||
rm rootfs.cpio
|
||||
cd cpio
|
||||
sudo find | sudo cpio -H newc -o > ../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
|
||||
|
@ -129,7 +134,7 @@ make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISO
|
|||
|
||||
|
||||
object LinuxGen {
|
||||
def configFull(litex : Boolean, withMmu : Boolean) = {
|
||||
def configFull(litex : Boolean, withMmu : Boolean, withSmp : Boolean = false) = {
|
||||
val config = VexRiscvConfig(
|
||||
plugins = List(
|
||||
//Uncomment the whole IBusSimplePlugin and comment IBusCachedPlugin if you want uncached iBus config
|
||||
|
@ -196,6 +201,8 @@ object LinuxGen {
|
|||
catchAccessError = true,
|
||||
catchIllegal = true,
|
||||
catchUnaligned = true,
|
||||
withExclusive = withSmp,
|
||||
withInvalidate = withSmp,
|
||||
withLrSc = true,
|
||||
withAmo = true
|
||||
// )
|
||||
|
@ -267,7 +274,7 @@ object LinuxGen {
|
|||
// wfiGenAsNop = true,
|
||||
// ucycleAccess = CsrAccess.NONE
|
||||
// )),
|
||||
// new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
|
||||
new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
|
||||
new BranchPlugin(
|
||||
earlyBranch = false,
|
||||
catchAddressMisaligned = true,
|
||||
|
@ -305,7 +312,7 @@ object LinuxGen {
|
|||
// }
|
||||
// }
|
||||
|
||||
SpinalConfig(mergeAsyncProcess = true, anonymSignalPrefix = "_zz").generateVerilog {
|
||||
SpinalConfig(mergeAsyncProcess = false, anonymSignalPrefix = "_zz").generateVerilog {
|
||||
|
||||
|
||||
val toplevel = new VexRiscv(configFull(
|
||||
|
|
|
@ -65,7 +65,7 @@ object MuraxConfig{
|
|||
SpiXdrMasterCtrl.Parameters(8, 12, SpiXdrParameter(2, 2, 1)).addFullDuplex(0,1,false),
|
||||
cmdFifoDepth = 32,
|
||||
rspFifoDepth = 32,
|
||||
xip = SpiXdrMasterCtrl.XipBusParameters(addressWidth = 24, dataWidth = 32)
|
||||
xip = SpiXdrMasterCtrl.XipBusParameters(addressWidth = 24, lengthWidth = 2)
|
||||
)),
|
||||
hardwareBreakpointCount = if(withXip) 3 else 0,
|
||||
cpuPlugins = ArrayBuffer( //DebugPlugin added by the toplevel
|
||||
|
@ -298,13 +298,7 @@ case class Murax(config : MuraxConfig) extends Component{
|
|||
val accessBus = new PipelinedMemoryBus(PipelinedMemoryBusConfig(24,32))
|
||||
mainBusMapping += accessBus -> (0xE0000000l, 16 MB)
|
||||
|
||||
ctrl.io.xip.cmd.valid <> (accessBus.cmd.valid && !accessBus.cmd.write)
|
||||
ctrl.io.xip.cmd.ready <> accessBus.cmd.ready
|
||||
ctrl.io.xip.cmd.payload <> accessBus.cmd.address
|
||||
|
||||
ctrl.io.xip.rsp.valid <> accessBus.rsp.valid
|
||||
ctrl.io.xip.rsp.payload <> accessBus.rsp.data
|
||||
|
||||
ctrl.io.xip.fromPipelinedMemoryBus() << accessBus
|
||||
val bootloader = Apb3Rom("src/main/c/murax/xipBootloader/crt.bin")
|
||||
apbMapping += bootloader.io.apb -> (0x1E000, 4 kB)
|
||||
})
|
||||
|
@ -368,57 +362,55 @@ object Murax_iCE40_hx8k_breakout_board_xip{
|
|||
|
||||
case class Murax_iCE40_hx8k_breakout_board_xip() extends Component{
|
||||
val io = new Bundle {
|
||||
val J3 = in Bool()
|
||||
val H16 = in Bool()
|
||||
val G15 = in Bool()
|
||||
val G16 = out Bool()
|
||||
val F15 = in Bool()
|
||||
val B12 = out Bool()
|
||||
val B10 = in Bool()
|
||||
val mainClk = in Bool()
|
||||
val jtag_tck = in Bool()
|
||||
val jtag_tdi = in Bool()
|
||||
val jtag_tdo = out Bool()
|
||||
val jtag_tms = in Bool()
|
||||
val uart_txd = out Bool()
|
||||
val uart_rxd = in Bool()
|
||||
|
||||
|
||||
//p12 as mosi mean flash config
|
||||
val P12 = inout(Analog(Bool))
|
||||
val P11 = inout(Analog(Bool))
|
||||
val R11 = out Bool()
|
||||
val R12 = out Bool()
|
||||
val mosi = inout(Analog(Bool))
|
||||
val miso = inout(Analog(Bool))
|
||||
val sclk = out Bool()
|
||||
val spis = out Bool()
|
||||
|
||||
val led = out Bits(8 bits)
|
||||
}
|
||||
val murax = Murax(MuraxConfig.default(withXip = true))
|
||||
val murax = Murax(MuraxConfig.default(withXip = true).copy(onChipRamSize = 8 kB))
|
||||
murax.io.asyncReset := False
|
||||
|
||||
val mainClkBuffer = SB_GB()
|
||||
mainClkBuffer.USER_SIGNAL_TO_GLOBAL_BUFFER <> io.J3
|
||||
mainClkBuffer.USER_SIGNAL_TO_GLOBAL_BUFFER <> io.mainClk
|
||||
mainClkBuffer.GLOBAL_BUFFER_OUTPUT <> murax.io.mainClk
|
||||
|
||||
val jtagClkBuffer = SB_GB()
|
||||
jtagClkBuffer.USER_SIGNAL_TO_GLOBAL_BUFFER <> io.H16
|
||||
jtagClkBuffer.USER_SIGNAL_TO_GLOBAL_BUFFER <> io.jtag_tck
|
||||
jtagClkBuffer.GLOBAL_BUFFER_OUTPUT <> murax.io.jtag.tck
|
||||
|
||||
io.led <> murax.io.gpioA.write(7 downto 0)
|
||||
|
||||
murax.io.jtag.tdi <> io.G15
|
||||
murax.io.jtag.tdo <> io.G16
|
||||
murax.io.jtag.tms <> io.F15
|
||||
murax.io.jtag.tdi <> io.jtag_tdi
|
||||
murax.io.jtag.tdo <> io.jtag_tdo
|
||||
murax.io.jtag.tms <> io.jtag_tms
|
||||
murax.io.gpioA.read <> 0
|
||||
murax.io.uart.txd <> io.B12
|
||||
murax.io.uart.rxd <> io.B10
|
||||
murax.io.uart.txd <> io.uart_txd
|
||||
murax.io.uart.rxd <> io.uart_rxd
|
||||
|
||||
|
||||
|
||||
val xip = new ClockingArea(murax.systemClockDomain) {
|
||||
RegNext(murax.io.xip.ss.asBool) <> io.R12
|
||||
RegNext(murax.io.xip.ss.asBool) <> io.spis
|
||||
|
||||
val sclkIo = SB_IO_SCLK()
|
||||
sclkIo.PACKAGE_PIN <> io.R11
|
||||
sclkIo.PACKAGE_PIN <> io.sclk
|
||||
sclkIo.CLOCK_ENABLE := True
|
||||
|
||||
sclkIo.OUTPUT_CLK := ClockDomain.current.readClockWire
|
||||
sclkIo.D_OUT_0 <> murax.io.xip.sclk.write(0)
|
||||
sclkIo.D_OUT_1 <> RegNext(murax.io.xip.sclk.write(1))
|
||||
|
||||
val datas = for ((data, pin) <- (murax.io.xip.data, List(io.P12, io.P11).reverse).zipped) yield new Area {
|
||||
val datas = for ((data, pin) <- (murax.io.xip.data, List(io.mosi, io.miso)).zipped) yield new Area {
|
||||
val dataIo = SB_IO_DATA()
|
||||
dataIo.PACKAGE_PIN := pin
|
||||
dataIo.CLOCK_ENABLE := True
|
||||
|
@ -438,45 +430,6 @@ object Murax_iCE40_hx8k_breakout_board_xip{
|
|||
|
||||
def main(args: Array[String]) {
|
||||
SpinalVerilog(Murax_iCE40_hx8k_breakout_board_xip())
|
||||
/*SpinalVerilog{
|
||||
val c = Murax(MuraxConfig.default(withXip = true))
|
||||
|
||||
|
||||
|
||||
|
||||
c.rework {
|
||||
c.resetCtrlClockDomain {
|
||||
c.io.xip.setAsDirectionLess.allowDirectionLessIo.flattenForeach(_.unsetName())
|
||||
|
||||
out(RegNext(c.io.xip.ss)).setName("io_xip_ss")
|
||||
|
||||
val sclk = SB_IO_SCLK()
|
||||
sclk.PACKAGE_PIN := inout(Analog(Bool)).setName("io_xip_sclk")
|
||||
sclk.CLOCK_ENABLE := True
|
||||
|
||||
sclk.OUTPUT_CLK := ClockDomain.current.readClockWire
|
||||
sclk.D_OUT_0 <> c.io.xip.sclk.write(0)
|
||||
sclk.D_OUT_1 <> RegNext(c.io.xip.sclk.write(1))
|
||||
|
||||
for (i <- 0 until c.io.xip.p.dataWidth) {
|
||||
val data = c.io.xip.data(i)
|
||||
val bb = SB_IO_DATA()
|
||||
bb.PACKAGE_PIN := inout(Analog(Bool)).setName(s"io_xip_data_$i" )
|
||||
bb.CLOCK_ENABLE := True
|
||||
|
||||
bb.OUTPUT_CLK := ClockDomain.current.readClockWire
|
||||
bb.OUTPUT_ENABLE <> data.writeEnable
|
||||
bb.D_OUT_0 <> data.write(0)
|
||||
bb.D_OUT_1 <> RegNext(data.write(1))
|
||||
|
||||
bb.INPUT_CLK := ClockDomain.current.readClockWire
|
||||
data.read(0) := bb.D_IN_0
|
||||
data.read(1) := RegNext(bb.D_IN_1)
|
||||
}
|
||||
}
|
||||
}
|
||||
c
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -518,3 +471,10 @@ object MuraxWithRamInit{
|
|||
SpinalVerilog(Murax(MuraxConfig.default.copy(onChipRamSize = 4 kB, onChipRamHexFile = "src/main/ressource/hex/muraxDemo.hex")))
|
||||
}
|
||||
}
|
||||
|
||||
object Murax_arty{
|
||||
def main(args: Array[String]) {
|
||||
val hex = "src/main/c/murax/hello_world/build/hello_world.hex"
|
||||
SpinalVerilog(Murax(MuraxConfig.default(false).copy(coreFrequency = 100 MHz,onChipRamSize = 32 kB, onChipRamHexFile = hex)))
|
||||
}
|
||||
}
|
||||
|
|
103
src/main/scala/vexriscv/demo/OpenRoad.scala
Normal file
103
src/main/scala/vexriscv/demo/OpenRoad.scala
Normal file
|
@ -0,0 +1,103 @@
|
|||
package vexriscv.demo
|
||||
|
||||
import spinal.core._
|
||||
import vexriscv.ip.{DataCacheConfig, InstructionCacheConfig}
|
||||
import vexriscv.{Riscv, VexRiscv, VexRiscvConfig, plugin}
|
||||
import vexriscv.plugin.{BranchPlugin, CsrAccess, CsrPlugin, CsrPluginConfig, DBusCachedPlugin, DecoderSimplePlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusCachedPlugin, IntAluPlugin, MmuPlugin, MmuPortConfig, MulDivIterativePlugin, MulPlugin, RegFilePlugin, STATIC, SrcPlugin, YamlPlugin}
|
||||
|
||||
object OpenRoad extends App{
|
||||
|
||||
def linuxConfig = VexRiscvConfig(
|
||||
withMemoryStage = true,
|
||||
withWriteBackStage = true,
|
||||
List(
|
||||
// new SingleInstructionLimiterPlugin(),
|
||||
new IBusCachedPlugin(
|
||||
resetVector = 0,
|
||||
compressedGen = false,
|
||||
prediction = vexriscv.plugin.NONE,
|
||||
injectorStage = false,
|
||||
config = InstructionCacheConfig(
|
||||
cacheSize = 4096,
|
||||
bytePerLine = 64,
|
||||
wayCount = 1,
|
||||
addressWidth = 32,
|
||||
cpuDataWidth = 32,
|
||||
memDataWidth = 32,
|
||||
catchIllegalAccess = true,
|
||||
catchAccessFault = true,
|
||||
asyncTagMemory = true,
|
||||
twoCycleRam = false,
|
||||
twoCycleCache = true
|
||||
),
|
||||
memoryTranslatorPortConfig = MmuPortConfig(
|
||||
portTlbSize = 4
|
||||
)
|
||||
),
|
||||
new DBusCachedPlugin(
|
||||
dBusCmdMasterPipe = true,
|
||||
dBusCmdSlavePipe = true,
|
||||
dBusRspSlavePipe = true,
|
||||
config = new DataCacheConfig(
|
||||
cacheSize = 4096,
|
||||
bytePerLine = 64,
|
||||
wayCount = 1,
|
||||
addressWidth = 32,
|
||||
cpuDataWidth = 32,
|
||||
memDataWidth = 32,
|
||||
catchAccessError = true,
|
||||
catchIllegal = true,
|
||||
catchUnaligned = true,
|
||||
asyncTagMemory = true,
|
||||
withLrSc = true,
|
||||
withAmo = true
|
||||
// )
|
||||
),
|
||||
memoryTranslatorPortConfig = MmuPortConfig(
|
||||
portTlbSize = 4
|
||||
)
|
||||
),
|
||||
new DecoderSimplePlugin(
|
||||
catchIllegalInstruction = true
|
||||
),
|
||||
new RegFilePlugin(
|
||||
regFileReadyKind = plugin.SYNC,
|
||||
zeroBoot = false,
|
||||
x0Init = true
|
||||
),
|
||||
new IntAluPlugin,
|
||||
new SrcPlugin(
|
||||
separatedAddSub = false
|
||||
),
|
||||
new FullBarrelShifterPlugin(earlyInjection = true),
|
||||
new HazardSimplePlugin(
|
||||
bypassExecute = true,
|
||||
bypassMemory = true,
|
||||
bypassWriteBack = true,
|
||||
bypassWriteBackBuffer = true,
|
||||
pessimisticUseSrc = false,
|
||||
pessimisticWriteRegFile = false,
|
||||
pessimisticAddressMatch = false
|
||||
),
|
||||
new MulDivIterativePlugin(
|
||||
genMul = true,
|
||||
genDiv = true,
|
||||
mulUnrollFactor = 32,
|
||||
divUnrollFactor = 8
|
||||
),
|
||||
new CsrPlugin(CsrPluginConfig.openSbi(0,Riscv.misaToInt("imas")).copy(ebreakGen = false, mtvecAccess = CsrAccess.READ_WRITE)), //mtvecAccess read required by freertos
|
||||
|
||||
new BranchPlugin(
|
||||
earlyBranch = true,
|
||||
catchAddressMisaligned = true,
|
||||
fenceiGenAsAJump = false
|
||||
),
|
||||
new MmuPlugin(
|
||||
ioRange = (x => x(31))
|
||||
),
|
||||
new YamlPlugin("cpu0.yaml")
|
||||
)
|
||||
)
|
||||
|
||||
SpinalConfig().addStandardMemBlackboxing(blackboxAllWhatsYouCan).generateVerilog(new VexRiscv(linuxConfig).setDefinitionName("VexRiscvMsuI4D4"))
|
||||
}
|
|
@ -1,10 +1,14 @@
|
|||
package vexriscv.demo
|
||||
|
||||
import spinal.core._
|
||||
import spinal.lib._
|
||||
import spinal.lib.eda.bench._
|
||||
import spinal.lib.eda.icestorm.IcestormStdTargets
|
||||
import vexriscv.VexRiscv
|
||||
import vexriscv.plugin.{DecoderSimplePlugin, KeepAttribute}
|
||||
import spinal.lib.eda.xilinx.VivadoFlow
|
||||
import spinal.lib.io.InOutWrapper
|
||||
import vexriscv.plugin.CsrAccess.{READ_ONLY, READ_WRITE, WRITE_ONLY}
|
||||
import vexriscv.{VexRiscv, VexRiscvConfig, plugin}
|
||||
import vexriscv.plugin.{BranchPlugin, CsrPlugin, CsrPluginConfig, DBusSimplePlugin, DecoderSimplePlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusSimplePlugin, IntAluPlugin, LightShifterPlugin, NONE, RegFilePlugin, SrcPlugin, YamlPlugin}
|
||||
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
import scala.util.Random
|
||||
|
@ -47,6 +51,89 @@ object VexRiscvSynthesisBench {
|
|||
// top
|
||||
// }
|
||||
|
||||
val twoStage = new Rtl {
|
||||
override def getName(): String = "VexRiscv two stages"
|
||||
override def getRtlPath(): String = "VexRiscvTwoStages.v"
|
||||
SpinalVerilog(wrap(GenTwoThreeStage.cpu(
|
||||
withMulDiv = false,
|
||||
bypass = false,
|
||||
barrielShifter = false,
|
||||
withMemoryStage = false
|
||||
)).setDefinitionName(getRtlPath().split("\\.").head))
|
||||
}
|
||||
val twoStageBarell = new Rtl {
|
||||
override def getName(): String = "VexRiscv two stages with barriel"
|
||||
override def getRtlPath(): String = "VexRiscvTwoStagesBar.v"
|
||||
SpinalVerilog(wrap(GenTwoThreeStage.cpu(
|
||||
withMulDiv = false,
|
||||
bypass = true,
|
||||
barrielShifter = true,
|
||||
withMemoryStage = false
|
||||
)).setDefinitionName(getRtlPath().split("\\.").head))
|
||||
}
|
||||
val twoStageMulDiv = new Rtl {
|
||||
override def getName(): String = "VexRiscv two stages with Mul Div"
|
||||
override def getRtlPath(): String = "VexRiscvTwoStagesMD.v"
|
||||
SpinalVerilog(wrap(GenTwoThreeStage.cpu(
|
||||
withMulDiv = true,
|
||||
bypass = false,
|
||||
barrielShifter = false,
|
||||
withMemoryStage = false
|
||||
)).setDefinitionName(getRtlPath().split("\\.").head))
|
||||
}
|
||||
val twoStageAll = new Rtl {
|
||||
override def getName(): String = "VexRiscv two stages with Mul Div fast"
|
||||
override def getRtlPath(): String = "VexRiscvTwoStagesMDfast.v"
|
||||
SpinalVerilog(wrap(GenTwoThreeStage.cpu(
|
||||
withMulDiv = true,
|
||||
bypass = true,
|
||||
barrielShifter = true,
|
||||
withMemoryStage = false
|
||||
)).setDefinitionName(getRtlPath().split("\\.").head))
|
||||
}
|
||||
|
||||
|
||||
val threeStage = new Rtl {
|
||||
override def getName(): String = "VexRiscv three stages"
|
||||
override def getRtlPath(): String = "VexRiscvThreeStages.v"
|
||||
SpinalVerilog(wrap(GenTwoThreeStage.cpu(
|
||||
withMulDiv = false,
|
||||
bypass = false,
|
||||
barrielShifter = false,
|
||||
withMemoryStage = true
|
||||
)).setDefinitionName(getRtlPath().split("\\.").head))
|
||||
}
|
||||
val threeStageBarell = new Rtl {
|
||||
override def getName(): String = "VexRiscv three stages with barriel"
|
||||
override def getRtlPath(): String = "VexRiscvThreeStagesBar.v"
|
||||
SpinalVerilog(wrap(GenTwoThreeStage.cpu(
|
||||
withMulDiv = false,
|
||||
bypass = true,
|
||||
barrielShifter = true,
|
||||
withMemoryStage = true
|
||||
)).setDefinitionName(getRtlPath().split("\\.").head))
|
||||
}
|
||||
val threeStageMulDiv = new Rtl {
|
||||
override def getName(): String = "VexRiscv three stages with Mul Div"
|
||||
override def getRtlPath(): String = "VexRiscvThreeStagesMD.v"
|
||||
SpinalVerilog(wrap(GenTwoThreeStage.cpu(
|
||||
withMulDiv = true,
|
||||
bypass = false,
|
||||
barrielShifter = false,
|
||||
withMemoryStage = true
|
||||
)).setDefinitionName(getRtlPath().split("\\.").head))
|
||||
}
|
||||
val threeStageAll = new Rtl {
|
||||
override def getName(): String = "VexRiscv three stages with Mul Div fast"
|
||||
override def getRtlPath(): String = "VexRiscvThreeStagesMDfast.v"
|
||||
SpinalVerilog(wrap(GenTwoThreeStage.cpu(
|
||||
withMulDiv = true,
|
||||
bypass = true,
|
||||
barrielShifter = true,
|
||||
withMemoryStage = true
|
||||
)).setDefinitionName(getRtlPath().split("\\.").head))
|
||||
}
|
||||
|
||||
val smallestNoCsr = new Rtl {
|
||||
override def getName(): String = "VexRiscv smallest no CSR"
|
||||
override def getRtlPath(): String = "VexRiscvSmallestNoCsr.v"
|
||||
|
@ -95,7 +182,7 @@ object VexRiscvSynthesisBench {
|
|||
}
|
||||
|
||||
val full = new Rtl {
|
||||
override def getName(): String = "VexRiscv full"
|
||||
override def getName(): String = "VexRiscv full with MMU"
|
||||
override def getRtlPath(): String = "VexRiscvFull.v"
|
||||
SpinalVerilog(wrap(GenFull.cpu()).setDefinitionName(getRtlPath().split("\\.").head))
|
||||
}
|
||||
|
@ -107,20 +194,77 @@ object VexRiscvSynthesisBench {
|
|||
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(smallAndProductive)
|
||||
val linuxBalancedSmp = new Rtl {
|
||||
override def getName(): String = "VexRiscv linux balanced SMP"
|
||||
override def getRtlPath(): String = "VexRiscvLinuxBalancedSmp.v"
|
||||
SpinalConfig(inlineRom = true).generateVerilog(wrap(new VexRiscv(LinuxGen.configFull(false, true, withSmp = true))).setDefinitionName(getRtlPath().split("\\.").head))
|
||||
}
|
||||
|
||||
val targets = XilinxStdTargets(
|
||||
vivadoArtix7Path = "/media/miaou/HD/linux/Xilinx/Vivado/2018.3/bin"
|
||||
) ++ AlteraStdTargets(
|
||||
quartusCycloneIVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin",
|
||||
quartusCycloneVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin"
|
||||
) ++ IcestormStdTargets().take(1)
|
||||
|
||||
|
||||
val rtls = List(
|
||||
twoStage, twoStageBarell, twoStageMulDiv, twoStageAll,
|
||||
threeStage, threeStageBarell, threeStageMulDiv, threeStageAll,
|
||||
smallestNoCsr, smallest, smallAndProductive, smallAndProductiveWithICache, fullNoMmuNoCache, noCacheNoMmuMaxPerf, fullNoMmuMaxPerf, fullNoMmu, full, linuxBalanced, linuxBalancedSmp
|
||||
)
|
||||
// val rtls = List(linuxBalanced, linuxBalancedSmp)
|
||||
// val rtls = List(smallest)
|
||||
val targets = XilinxStdTargets() ++ AlteraStdTargets() ++ IcestormStdTargets().take(1) ++ List(
|
||||
new Target {
|
||||
override def getFamilyName(): String = "Kintex UltraScale"
|
||||
override def synthesise(rtl: Rtl, workspace: String): Report = {
|
||||
VivadoFlow(
|
||||
frequencyTarget = 50 MHz,
|
||||
vivadoPath=sys.env.getOrElse("VIVADO_ARTIX_7_BIN", null),
|
||||
workspacePath=workspace + "_area",
|
||||
toplevelPath=rtl.getRtlPath(),
|
||||
family=getFamilyName(),
|
||||
device="xcku035-fbva900-3-e"
|
||||
)
|
||||
}
|
||||
},
|
||||
new Target {
|
||||
override def getFamilyName(): String = "Kintex UltraScale"
|
||||
override def synthesise(rtl: Rtl, workspace: String): Report = {
|
||||
VivadoFlow(
|
||||
frequencyTarget = 800 MHz,
|
||||
vivadoPath=sys.env.getOrElse("VIVADO_ARTIX_7_BIN", null),
|
||||
workspacePath=workspace + "_fmax",
|
||||
toplevelPath=rtl.getRtlPath(),
|
||||
family=getFamilyName(),
|
||||
device="xcku035-fbva900-3-e"
|
||||
)
|
||||
}
|
||||
},
|
||||
new Target {
|
||||
override def getFamilyName(): String = "Kintex UltraScale+"
|
||||
override def synthesise(rtl: Rtl, workspace: String): Report = {
|
||||
VivadoFlow(
|
||||
frequencyTarget = 50 MHz,
|
||||
vivadoPath=sys.env.getOrElse("VIVADO_ARTIX_7_BIN", null),
|
||||
workspacePath=workspace + "_area",
|
||||
toplevelPath=rtl.getRtlPath(),
|
||||
family=getFamilyName(),
|
||||
device="xcku3p-ffvd900-3-e"
|
||||
)
|
||||
}
|
||||
},
|
||||
new Target {
|
||||
override def getFamilyName(): String = "Kintex UltraScale+"
|
||||
override def synthesise(rtl: Rtl, workspace: String): Report = {
|
||||
VivadoFlow(
|
||||
frequencyTarget = 800 MHz,
|
||||
vivadoPath=sys.env.getOrElse("VIVADO_ARTIX_7_BIN", null),
|
||||
workspacePath=workspace + "_fmax",
|
||||
toplevelPath=rtl.getRtlPath(),
|
||||
family=getFamilyName(),
|
||||
device="xcku3p-ffvd900-3-e"
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
// val targets = IcestormStdTargets()
|
||||
Bench(rtls, targets, "/media/miaou/HD/linux/tmp")
|
||||
Bench(rtls, targets)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,7 +275,7 @@ object BrieySynthesisBench {
|
|||
override def getName(): String = "Briey"
|
||||
override def getRtlPath(): String = "Briey.v"
|
||||
SpinalVerilog({
|
||||
val briey = new Briey(BrieyConfig.default).setDefinitionName(getRtlPath().split("\\.").head)
|
||||
val briey = InOutWrapper(new Briey(BrieyConfig.default).setDefinitionName(getRtlPath().split("\\.").head))
|
||||
briey.io.axiClk.setName("clk")
|
||||
briey
|
||||
})
|
||||
|
@ -140,14 +284,9 @@ object BrieySynthesisBench {
|
|||
|
||||
val rtls = List(briey)
|
||||
|
||||
val targets = XilinxStdTargets(
|
||||
vivadoArtix7Path = "/media/miaou/HD/linux/Xilinx/Vivado/2018.3/bin"
|
||||
) ++ AlteraStdTargets(
|
||||
quartusCycloneIVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin",
|
||||
quartusCycloneVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin"
|
||||
)
|
||||
val targets = XilinxStdTargets() ++ AlteraStdTargets() ++ IcestormStdTargets().take(1)
|
||||
|
||||
Bench(rtls, targets, "/media/miaou/HD/linux/tmp")
|
||||
Bench(rtls, targets)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,7 +299,7 @@ object MuraxSynthesisBench {
|
|||
override def getName(): String = "Murax"
|
||||
override def getRtlPath(): String = "Murax.v"
|
||||
SpinalVerilog({
|
||||
val murax = new Murax(MuraxConfig.default.copy(gpioWidth = 8)).setDefinitionName(getRtlPath().split("\\.").head)
|
||||
val murax = InOutWrapper(new Murax(MuraxConfig.default.copy(gpioWidth = 8)).setDefinitionName(getRtlPath().split("\\.").head))
|
||||
murax.io.mainClk.setName("clk")
|
||||
murax
|
||||
})
|
||||
|
@ -171,7 +310,7 @@ object MuraxSynthesisBench {
|
|||
override def getName(): String = "MuraxFast"
|
||||
override def getRtlPath(): String = "MuraxFast.v"
|
||||
SpinalVerilog({
|
||||
val murax = new Murax(MuraxConfig.fast.copy(gpioWidth = 8)).setDefinitionName(getRtlPath().split("\\.").head)
|
||||
val murax = InOutWrapper(new Murax(MuraxConfig.fast.copy(gpioWidth = 8)).setDefinitionName(getRtlPath().split("\\.").head))
|
||||
murax.io.mainClk.setName("clk")
|
||||
murax
|
||||
})
|
||||
|
@ -179,14 +318,9 @@ object MuraxSynthesisBench {
|
|||
|
||||
val rtls = List(murax, muraxFast)
|
||||
|
||||
val targets = IcestormStdTargets().take(1) ++ XilinxStdTargets(
|
||||
vivadoArtix7Path = "/media/miaou/HD/linux/Xilinx/Vivado/2018.3/bin"
|
||||
) ++ AlteraStdTargets(
|
||||
quartusCycloneIVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin",
|
||||
quartusCycloneVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin"
|
||||
)
|
||||
val targets = XilinxStdTargets() ++ AlteraStdTargets() ++ IcestormStdTargets().take(1)
|
||||
|
||||
Bench(rtls, targets, "/media/miaou/HD/linux/tmp")
|
||||
Bench(rtls, targets)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -197,4 +331,100 @@ object AllSynthesisBench {
|
|||
MuraxSynthesisBench.main(args)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
object VexRiscvCustomSynthesisBench {
|
||||
def main(args: Array[String]) {
|
||||
|
||||
|
||||
def gen(csr : CsrPlugin) = new VexRiscv(
|
||||
config = VexRiscvConfig(
|
||||
plugins = List(
|
||||
new IBusSimplePlugin(
|
||||
resetVector = 0x80000000l,
|
||||
cmdForkOnSecondStage = false,
|
||||
cmdForkPersistence = false,
|
||||
prediction = NONE,
|
||||
catchAccessFault = false,
|
||||
compressedGen = false
|
||||
),
|
||||
new DBusSimplePlugin(
|
||||
catchAddressMisaligned = false,
|
||||
catchAccessFault = false
|
||||
),
|
||||
new DecoderSimplePlugin(
|
||||
catchIllegalInstruction = false
|
||||
),
|
||||
new RegFilePlugin(
|
||||
regFileReadyKind = plugin.SYNC,
|
||||
zeroBoot = false
|
||||
),
|
||||
new IntAluPlugin,
|
||||
new SrcPlugin(
|
||||
separatedAddSub = false,
|
||||
executeInsertion = true
|
||||
),
|
||||
csr,
|
||||
new FullBarrelShifterPlugin(),
|
||||
new HazardSimplePlugin(
|
||||
bypassExecute = true,
|
||||
bypassMemory = true,
|
||||
bypassWriteBack = true,
|
||||
bypassWriteBackBuffer = true,
|
||||
pessimisticUseSrc = false,
|
||||
pessimisticWriteRegFile = false,
|
||||
pessimisticAddressMatch = false
|
||||
),
|
||||
new BranchPlugin(
|
||||
earlyBranch = false,
|
||||
catchAddressMisaligned = false
|
||||
),
|
||||
new YamlPlugin("cpu0.yaml")
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
val fixedMtvec = new Rtl {
|
||||
override def getName(): String = "Fixed MTVEC"
|
||||
override def getRtlPath(): String = "fixedMtvec.v"
|
||||
SpinalVerilog(gen(new CsrPlugin(CsrPluginConfig.smallest(0x80000000l))).setDefinitionName(getRtlPath().split("\\.").head))
|
||||
}
|
||||
|
||||
val writeOnlyMtvec = new Rtl {
|
||||
override def getName(): String = "write only MTVEC"
|
||||
override def getRtlPath(): String = "woMtvec.v"
|
||||
SpinalVerilog(gen(new CsrPlugin(CsrPluginConfig.smallest(null).copy(mtvecAccess = WRITE_ONLY))).setDefinitionName(getRtlPath().split("\\.").head))
|
||||
}
|
||||
|
||||
val readWriteMtvec = new Rtl {
|
||||
override def getName(): String = "read write MTVEC"
|
||||
override def getRtlPath(): String = "wrMtvec.v"
|
||||
SpinalVerilog(gen(new CsrPlugin(CsrPluginConfig.smallest(null).copy(mtvecAccess = READ_WRITE))).setDefinitionName(getRtlPath().split("\\.").head))
|
||||
}
|
||||
|
||||
val fixedMtvecRoCounter = new Rtl {
|
||||
override def getName(): String = "Fixed MTVEC, read only mcycle/minstret"
|
||||
override def getRtlPath(): String = "fixedMtvecRoCounter.v"
|
||||
SpinalVerilog(gen(new CsrPlugin(CsrPluginConfig.smallest(0x80000000l).copy(mcycleAccess = READ_ONLY, minstretAccess = READ_ONLY))).setDefinitionName(getRtlPath().split("\\.").head))
|
||||
}
|
||||
|
||||
|
||||
val rwMtvecRoCounter = new Rtl {
|
||||
override def getName(): String = "read write MTVEC, read only mcycle/minstret"
|
||||
override def getRtlPath(): String = "readWriteMtvecRoCounter.v"
|
||||
SpinalVerilog(gen(new CsrPlugin(CsrPluginConfig.smallest(null).copy(mtvecAccess = READ_WRITE, mcycleAccess = READ_ONLY, minstretAccess = READ_ONLY))).setDefinitionName(getRtlPath().split("\\.").head))
|
||||
}
|
||||
|
||||
|
||||
// val rtls = List(twoStage, twoStageBarell, twoStageMulDiv, twoStageAll, smallestNoCsr, smallest, smallAndProductive, smallAndProductiveWithICache, fullNoMmuNoCache, noCacheNoMmuMaxPerf, fullNoMmuMaxPerf, fullNoMmu, full, linuxBalanced, linuxBalancedSmp)
|
||||
val rtls = List(fixedMtvec, writeOnlyMtvec, readWriteMtvec,fixedMtvecRoCounter, rwMtvecRoCounter)
|
||||
// val rtls = List(smallest)
|
||||
val targets = XilinxStdTargets() ++ AlteraStdTargets() ++ IcestormStdTargets().take(1)
|
||||
|
||||
// val targets = IcestormStdTargets()
|
||||
Bench(rtls, targets)
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ package vexriscv.demo
|
|||
import spinal.core._
|
||||
import spinal.lib._
|
||||
import spinal.lib.bus.avalon.AvalonMM
|
||||
import spinal.lib.com.jtag.Jtag
|
||||
import spinal.lib.com.jtag.{Jtag, JtagTapInstructionCtrl}
|
||||
import spinal.lib.eda.altera.{InterruptReceiverTag, QSysify, ResetEmitterTag}
|
||||
import vexriscv.ip.{DataCacheConfig, InstructionCacheConfig}
|
||||
import vexriscv.plugin._
|
||||
|
@ -163,6 +163,11 @@ object VexRiscvAhbLite3{
|
|||
plugin.io.bus.setAsDirectionLess()
|
||||
val jtag = slave(new Jtag()).setName("jtag")
|
||||
jtag <> plugin.io.bus.fromJtag()
|
||||
|
||||
// // On Artix FPGA jtag :
|
||||
// val jtagCtrl = JtagTapInstructionCtrl()
|
||||
// val tap = jtagCtrl.fromXilinxBscane2(userId = 1)
|
||||
// jtagCtrl <> plugin.io.bus.fromJtagInstructionCtrl(ClockDomain(tap.TCK))
|
||||
}
|
||||
case _ =>
|
||||
}
|
||||
|
|
288
src/main/scala/vexriscv/demo/smp/Misc.scala
Normal file
288
src/main/scala/vexriscv/demo/smp/Misc.scala
Normal file
|
@ -0,0 +1,288 @@
|
|||
package vexriscv.demo.smp
|
||||
|
||||
|
||||
import spinal.core._
|
||||
import spinal.lib.bus.bmb._
|
||||
import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig, WishboneSlaveFactory}
|
||||
import spinal.lib.com.jtag.Jtag
|
||||
import spinal.lib._
|
||||
import spinal.lib.bus.bmb.sim.{BmbMemoryMultiPort, BmbMemoryTester}
|
||||
import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping}
|
||||
import spinal.lib.eda.bench.Bench
|
||||
import spinal.lib.generator.{Generator, Handle}
|
||||
import spinal.lib.misc.Clint
|
||||
import spinal.lib.sim.{SimData, SparseMemory, StreamDriver, StreamMonitor, StreamReadyRandomizer}
|
||||
import vexriscv.{VexRiscv, VexRiscvConfig}
|
||||
import vexriscv.plugin.{CsrPlugin, DBusCachedPlugin, DebugPlugin, IBusCachedPlugin}
|
||||
|
||||
import scala.collection.mutable
|
||||
import scala.util.Random
|
||||
|
||||
case class LiteDramNativeParameter(addressWidth : Int, dataWidth : Int)
|
||||
|
||||
case class LiteDramNativeCmd(p : LiteDramNativeParameter) extends Bundle{
|
||||
val we = Bool()
|
||||
val addr = UInt(p.addressWidth bits)
|
||||
}
|
||||
|
||||
case class LiteDramNativeWData(p : LiteDramNativeParameter) extends Bundle{
|
||||
val data = Bits(p.dataWidth bits)
|
||||
val we = Bits(p.dataWidth/8 bits)
|
||||
}
|
||||
|
||||
case class LiteDramNativeRData(p : LiteDramNativeParameter) extends Bundle{
|
||||
val data = Bits(p.dataWidth bits)
|
||||
}
|
||||
|
||||
|
||||
case class LiteDramNative(p : LiteDramNativeParameter) extends Bundle with IMasterSlave {
|
||||
val cmd = Stream(LiteDramNativeCmd(p))
|
||||
val wdata = Stream(LiteDramNativeWData(p))
|
||||
val rdata = Stream(LiteDramNativeRData(p))
|
||||
override def asMaster(): Unit = {
|
||||
master(cmd, wdata)
|
||||
slave(rdata)
|
||||
}
|
||||
|
||||
def fromBmb(bmb : Bmb, wdataFifoSize : Int, rdataFifoSize : Int) = {
|
||||
val bridge = BmbToLiteDram(
|
||||
bmbParameter = bmb.p,
|
||||
liteDramParameter = this.p,
|
||||
wdataFifoSize = wdataFifoSize,
|
||||
rdataFifoSize = rdataFifoSize
|
||||
)
|
||||
bridge.io.input << bmb
|
||||
bridge.io.output <> this
|
||||
bridge
|
||||
}
|
||||
|
||||
def simSlave(ram : SparseMemory,cd : ClockDomain, bmb : Bmb = null): Unit ={
|
||||
import spinal.core.sim._
|
||||
def bus = this
|
||||
case class Cmd(address : Long, we : Boolean)
|
||||
case class WData(data : BigInt, we : Long)
|
||||
val cmdQueue = mutable.Queue[Cmd]()
|
||||
val wdataQueue = mutable.Queue[WData]()
|
||||
val rdataQueue = mutable.Queue[BigInt]()
|
||||
|
||||
|
||||
case class Ref(address : Long, data : BigInt, we : Long, time : Long)
|
||||
val ref = mutable.Queue[Ref]()
|
||||
if(bmb != null) StreamMonitor(bmb.cmd, cd){p =>
|
||||
if(bmb.cmd.opcode.toInt == 1) ref.enqueue(Ref(p.fragment.address.toLong, p.fragment.data.toBigInt, p.fragment.mask.toLong, simTime()))
|
||||
}
|
||||
|
||||
var writeCmdCounter, writeDataCounter = 0
|
||||
StreamReadyRandomizer(bus.cmd, cd).factor = 0.5f
|
||||
StreamMonitor(bus.cmd, cd) { t =>
|
||||
cmdQueue.enqueue(Cmd(t.addr.toLong * (p.dataWidth/8) , t.we.toBoolean))
|
||||
if(t.we.toBoolean) writeCmdCounter += 1
|
||||
}
|
||||
|
||||
StreamReadyRandomizer(bus.wdata, cd).factor = 0.5f
|
||||
StreamMonitor(bus.wdata, cd) { p =>
|
||||
writeDataCounter += 1
|
||||
// if(p.data.toBigInt == BigInt("00000002000000020000000200000002",16)){
|
||||
// println("ASD")
|
||||
// }
|
||||
wdataQueue.enqueue(WData(p.data.toBigInt, p.we.toLong))
|
||||
}
|
||||
|
||||
// new SimStreamAssert(cmd,cd)
|
||||
// new SimStreamAssert(wdata,cd)
|
||||
// new SimStreamAssert(rdata,cd)
|
||||
|
||||
cd.onSamplings{
|
||||
if(writeDataCounter-writeCmdCounter > 2){
|
||||
println("miaou")
|
||||
}
|
||||
if(cmdQueue.nonEmpty && Random.nextFloat() < 0.5){
|
||||
val cmd = cmdQueue.head
|
||||
if(cmd.we){
|
||||
if(wdataQueue.nonEmpty){
|
||||
// if(cmd.address == 0xc02ae850l) {
|
||||
// println(s"! $writeCmdCounter $writeDataCounter")
|
||||
// }
|
||||
cmdQueue.dequeue()
|
||||
val wdata = wdataQueue.dequeue()
|
||||
val raw = wdata.data.toByteArray
|
||||
val left = wdata.data.toByteArray.size-1
|
||||
if(bmb != null){
|
||||
assert(ref.nonEmpty)
|
||||
assert((ref.head.address & 0xFFFFFFF0l) == cmd.address)
|
||||
assert(ref.head.data == wdata.data)
|
||||
assert(ref.head.we == wdata.we)
|
||||
ref.dequeue()
|
||||
}
|
||||
// if(cmd.address == 0xc02ae850l) {
|
||||
// println(s"$cmd $wdata ${simTime()}")
|
||||
// }
|
||||
for(i <- 0 until p.dataWidth/8){
|
||||
|
||||
|
||||
if(((wdata.we >> i) & 1) != 0) {
|
||||
// if(cmd.address == 0xc02ae850l) {
|
||||
// println(s"W $i ${ if (left - i >= 0) raw(left - i) else 0}")
|
||||
// }
|
||||
ram.write(cmd.address + i, if (left - i >= 0) raw(left - i) else 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cmdQueue.dequeue()
|
||||
val value = new Array[Byte](p.dataWidth/8+1)
|
||||
val left = value.size-1
|
||||
for(i <- 0 until p.dataWidth/8) {
|
||||
value(left-i) = ram.read(cmd.address+i)
|
||||
}
|
||||
rdataQueue.enqueue(BigInt(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StreamDriver(bus.rdata, cd){ p =>
|
||||
if(rdataQueue.isEmpty){
|
||||
false
|
||||
} else {
|
||||
p.data #= rdataQueue.dequeue()
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
case class BmbToLiteDram(bmbParameter : BmbParameter,
|
||||
liteDramParameter : LiteDramNativeParameter,
|
||||
wdataFifoSize : Int,
|
||||
rdataFifoSize : Int) extends Component{
|
||||
val io = new Bundle {
|
||||
val input = slave(Bmb(bmbParameter))
|
||||
val output = master(LiteDramNative(liteDramParameter))
|
||||
}
|
||||
|
||||
val resized = io.input.resize(liteDramParameter.dataWidth)
|
||||
val unburstified = resized.unburstify()
|
||||
case class Context() extends Bundle {
|
||||
val context = Bits(unburstified.p.access.contextWidth bits)
|
||||
val source = UInt(unburstified.p.access.sourceWidth bits)
|
||||
val isWrite = Bool()
|
||||
}
|
||||
|
||||
assert(isPow2(rdataFifoSize))
|
||||
val pendingRead = Reg(UInt(log2Up(rdataFifoSize) + 1 bits)) init(0)
|
||||
|
||||
val halt = Bool()
|
||||
val (cmdFork, dataFork) = StreamFork2(unburstified.cmd.haltWhen(halt))
|
||||
val outputCmd = Stream(LiteDramNativeCmd(liteDramParameter))
|
||||
outputCmd.arbitrationFrom(cmdFork.haltWhen(pendingRead.msb))
|
||||
outputCmd.addr := (cmdFork.address >> log2Up(liteDramParameter.dataWidth/8)).resized
|
||||
outputCmd.we := cmdFork.isWrite
|
||||
|
||||
io.output.cmd <-< outputCmd
|
||||
|
||||
if(bmbParameter.access.canWrite) {
|
||||
val wData = Stream(LiteDramNativeWData(liteDramParameter))
|
||||
wData.arbitrationFrom(dataFork.throwWhen(dataFork.isRead))
|
||||
wData.data := dataFork.data
|
||||
wData.we := dataFork.mask
|
||||
io.output.wdata << wData.queueLowLatency(wdataFifoSize, latency = 1)
|
||||
} else {
|
||||
dataFork.ready := True
|
||||
io.output.wdata.valid := False
|
||||
io.output.wdata.data.assignDontCare()
|
||||
io.output.wdata.we.assignDontCare()
|
||||
}
|
||||
|
||||
val cmdContext = Stream(Context())
|
||||
cmdContext.valid := unburstified.cmd.fire
|
||||
cmdContext.context := unburstified.cmd.context
|
||||
cmdContext.source := unburstified.cmd.source
|
||||
cmdContext.isWrite := unburstified.cmd.isWrite
|
||||
halt := !cmdContext.ready
|
||||
|
||||
val rspContext = cmdContext.queue(rdataFifoSize)
|
||||
val rdataFifo = io.output.rdata.queueLowLatency(rdataFifoSize, latency = 1)
|
||||
val writeTocken = CounterUpDown(
|
||||
stateCount = rdataFifoSize*2,
|
||||
incWhen = io.output.wdata.fire,
|
||||
decWhen = rspContext.fire && rspContext.isWrite
|
||||
)
|
||||
val canRspWrite = writeTocken =/= 0
|
||||
val canRspRead = CombInit(rdataFifo.valid)
|
||||
|
||||
rdataFifo.ready := unburstified.rsp.fire && !rspContext.isWrite
|
||||
rspContext.ready := unburstified.rsp.fire
|
||||
unburstified.rsp.valid := rspContext.valid && (rspContext.isWrite ? canRspWrite | canRspRead)
|
||||
unburstified.rsp.setSuccess()
|
||||
unburstified.rsp.last := True
|
||||
unburstified.rsp.source := rspContext.source
|
||||
unburstified.rsp.context := rspContext.context
|
||||
unburstified.rsp.data := rdataFifo.data
|
||||
|
||||
|
||||
pendingRead := pendingRead + U(outputCmd.fire && !outputCmd.we) - U(rdataFifo.fire)
|
||||
}
|
||||
|
||||
object BmbToLiteDramTester extends App{
|
||||
import spinal.core.sim._
|
||||
SimConfig.withWave.compile(BmbToLiteDram(
|
||||
bmbParameter = BmbParameter(
|
||||
addressWidth = 20,
|
||||
dataWidth = 32,
|
||||
lengthWidth = 6,
|
||||
sourceWidth = 4,
|
||||
contextWidth = 16
|
||||
),
|
||||
liteDramParameter = LiteDramNativeParameter(
|
||||
addressWidth = 20,
|
||||
dataWidth = 128
|
||||
),
|
||||
wdataFifoSize = 16,
|
||||
rdataFifoSize = 16
|
||||
)).doSimUntilVoid(seed = 42){dut =>
|
||||
val tester = new BmbMemoryTester(dut.io.input, dut.clockDomain, rspCounterTarget = 3000)
|
||||
dut.io.output.simSlave(tester.memory.memory, dut.clockDomain)
|
||||
}
|
||||
}
|
||||
|
||||
case class BmbToLiteDramGenerator(mapping : AddressMapping)(implicit interconnect : BmbInterconnectGenerator) extends Generator{
|
||||
val liteDramParameter = createDependency[LiteDramNativeParameter]
|
||||
val bmb = produce(logic.io.input)
|
||||
val dram = produceIo(logic.io.output)
|
||||
|
||||
val accessSource = Handle[BmbAccessCapabilities]
|
||||
val accessRequirements = createDependency[BmbAccessParameter]
|
||||
interconnect.addSlave(
|
||||
accessSource = accessSource,
|
||||
accessCapabilities = accessSource,
|
||||
accessRequirements = accessRequirements,
|
||||
bus = bmb,
|
||||
mapping = mapping
|
||||
)
|
||||
val logic = add task BmbToLiteDram(
|
||||
bmbParameter = accessRequirements.toBmbParameter(),
|
||||
liteDramParameter = liteDramParameter,
|
||||
wdataFifoSize = 32,
|
||||
rdataFifoSize = 32
|
||||
)
|
||||
}
|
||||
|
||||
case class BmbToWishboneGenerator(mapping : AddressMapping)(implicit interconnect : BmbInterconnectGenerator) extends Generator{
|
||||
val bmb = produce(logic.io.input)
|
||||
val wishbone = produce(logic.io.output)
|
||||
|
||||
val accessSource = Handle[BmbAccessCapabilities]
|
||||
val accessRequirements = createDependency[BmbAccessParameter]
|
||||
interconnect.addSlave(
|
||||
accessSource = accessSource,
|
||||
accessCapabilities = accessSource,
|
||||
accessRequirements = accessRequirements,
|
||||
bus = bmb,
|
||||
mapping = mapping
|
||||
)
|
||||
val logic = add task BmbToWishbone(
|
||||
p = accessRequirements.toBmbParameter()
|
||||
)
|
||||
}
|
662
src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala
Normal file
662
src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala
Normal file
|
@ -0,0 +1,662 @@
|
|||
package vexriscv.demo.smp
|
||||
|
||||
import spinal.core
|
||||
import spinal.core._
|
||||
import spinal.core.sim.{onSimEnd, simSuccess}
|
||||
import spinal.lib._
|
||||
import spinal.lib.bus.bmb.sim.BmbMemoryAgent
|
||||
import spinal.lib.bus.bmb._
|
||||
import spinal.lib.bus.misc.{DefaultMapping, SizeMapping}
|
||||
import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig, WishboneToBmb, WishboneToBmbGenerator}
|
||||
import spinal.lib.com.jtag.{Jtag, JtagInstructionDebuggerGenerator, JtagTapInstructionCtrl}
|
||||
import spinal.lib.com.jtag.sim.JtagTcp
|
||||
import spinal.lib.com.jtag.xilinx.Bscane2BmbMasterGenerator
|
||||
import spinal.lib.generator.Handle
|
||||
import spinal.lib.misc.plic.PlicMapping
|
||||
import spinal.lib.system.debugger.SystemDebuggerConfig
|
||||
import vexriscv.ip.{DataCacheAck, DataCacheConfig, DataCacheMemBus, InstructionCache, InstructionCacheConfig}
|
||||
import vexriscv.plugin.{BranchPlugin, CsrAccess, CsrPlugin, CsrPluginConfig, DBusCachedPlugin, DBusSimplePlugin, DYNAMIC_TARGET, DebugPlugin, DecoderSimplePlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusCachedPlugin, IBusSimplePlugin, IntAluPlugin, MmuPlugin, MmuPortConfig, MulDivIterativePlugin, MulPlugin, RegFilePlugin, STATIC, SrcPlugin, YamlPlugin}
|
||||
import vexriscv.{Riscv, VexRiscv, VexRiscvBmbGenerator, VexRiscvConfig, plugin}
|
||||
|
||||
import scala.collection.mutable
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
import spinal.lib.generator._
|
||||
|
||||
case class VexRiscvSmpClusterParameter(cpuConfigs : Seq[VexRiscvConfig], withExclusiveAndInvalidation : Boolean)
|
||||
|
||||
class VexRiscvSmpClusterBase(p : VexRiscvSmpClusterParameter) extends Generator{
|
||||
val cpuCount = p.cpuConfigs.size
|
||||
|
||||
val debugCd = ClockDomainResetGenerator()
|
||||
debugCd.holdDuration.load(4095)
|
||||
debugCd.makeExternal()
|
||||
|
||||
val systemCd = ClockDomainResetGenerator()
|
||||
systemCd.holdDuration.load(63)
|
||||
systemCd.setInput(debugCd)
|
||||
|
||||
this.onClockDomain(systemCd.outputClockDomain)
|
||||
|
||||
implicit val interconnect = BmbInterconnectGenerator()
|
||||
|
||||
val debugBridge = JtagInstructionDebuggerGenerator() onClockDomain(debugCd.outputClockDomain)
|
||||
debugBridge.jtagClockDomain.load(ClockDomain.external("jtag", withReset = false))
|
||||
|
||||
val debugPort = debugBridge.produceIo(debugBridge.logic.jtagBridge.io.ctrl)
|
||||
|
||||
val dBusCoherent = BmbBridgeGenerator()
|
||||
val dBusNonCoherent = BmbBridgeGenerator()
|
||||
|
||||
val smp = p.withExclusiveAndInvalidation generate new Area{
|
||||
val exclusiveMonitor = BmbExclusiveMonitorGenerator()
|
||||
interconnect.addConnection(dBusCoherent.bmb, exclusiveMonitor.input)
|
||||
|
||||
val invalidationMonitor = BmbInvalidateMonitorGenerator()
|
||||
interconnect.addConnection(exclusiveMonitor.output, invalidationMonitor.input)
|
||||
interconnect.addConnection(invalidationMonitor.output, dBusNonCoherent.bmb)
|
||||
interconnect.masters(invalidationMonitor.output).withOutOfOrderDecoder()
|
||||
}
|
||||
|
||||
val noSmp = !p.withExclusiveAndInvalidation generate new Area{
|
||||
interconnect.addConnection(dBusCoherent.bmb, dBusNonCoherent.bmb)
|
||||
}
|
||||
|
||||
val cores = for(cpuId <- 0 until cpuCount) yield new Area{
|
||||
val cpu = VexRiscvBmbGenerator()
|
||||
cpu.config.load(p.cpuConfigs(cpuId))
|
||||
interconnect.addConnection(
|
||||
cpu.dBus -> List(dBusCoherent.bmb)
|
||||
)
|
||||
cpu.enableDebugBmb(
|
||||
debugCd = debugCd,
|
||||
resetCd = systemCd,
|
||||
mapping = SizeMapping(cpuId*0x1000, 0x1000)
|
||||
)
|
||||
interconnect.addConnection(debugBridge.bmb, cpu.debugBmb)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class VexRiscvSmpClusterWithPeripherals(p : VexRiscvSmpClusterParameter) extends VexRiscvSmpClusterBase(p) {
|
||||
val peripheralBridge = BmbToWishboneGenerator(DefaultMapping)
|
||||
val peripheral = peripheralBridge.produceIo(peripheralBridge.logic.io.output)
|
||||
interconnect.slaves(peripheralBridge.bmb).forceAccessSourceDataWidth(32)
|
||||
|
||||
val plic = BmbPlicGenerator()(interconnect = null)
|
||||
plic.priorityWidth.load(2)
|
||||
plic.mapping.load(PlicMapping.sifive)
|
||||
|
||||
val plicWishboneBridge = new Generator{
|
||||
dependencies += plic.ctrl
|
||||
|
||||
plic.accessRequirements.load(BmbAccessParameter(
|
||||
addressWidth = 22,
|
||||
dataWidth = 32
|
||||
).addSources(1, BmbSourceParameter(
|
||||
contextWidth = 0,
|
||||
lengthWidth = 2,
|
||||
alignment = BmbParameter.BurstAlignement.LENGTH
|
||||
)))
|
||||
|
||||
val logic = add task new Area{
|
||||
val bridge = WishboneToBmb(WishboneConfig(20, 32))
|
||||
bridge.io.output >> plic.ctrl
|
||||
}
|
||||
}
|
||||
val plicWishbone = plicWishboneBridge.produceIo(plicWishboneBridge.logic.bridge.io.input)
|
||||
|
||||
val clint = BmbClintGenerator(0)(interconnect = null)
|
||||
val clintWishboneBridge = new Generator{
|
||||
dependencies += clint.ctrl
|
||||
|
||||
clint.accessRequirements.load(BmbAccessParameter(
|
||||
addressWidth = 16,
|
||||
dataWidth = 32
|
||||
).addSources(1, BmbSourceParameter(
|
||||
contextWidth = 0,
|
||||
lengthWidth = 2,
|
||||
alignment = BmbParameter.BurstAlignement.LENGTH
|
||||
)))
|
||||
|
||||
val logic = add task new Area{
|
||||
val bridge = WishboneToBmb(WishboneConfig(14, 32))
|
||||
bridge.io.output >> clint.ctrl
|
||||
}
|
||||
}
|
||||
val clintWishbone = clintWishboneBridge.produceIo(clintWishboneBridge.logic.bridge.io.input)
|
||||
|
||||
val interrupts = add task (in Bits(32 bits))
|
||||
for(i <- 1 to 31) yield plic.addInterrupt(interrupts.derivate(_.apply(i)), i)
|
||||
|
||||
for ((core, cpuId) <- cores.zipWithIndex) {
|
||||
core.cpu.setTimerInterrupt(clint.timerInterrupt(cpuId))
|
||||
core.cpu.setSoftwareInterrupt(clint.softwareInterrupt(cpuId))
|
||||
plic.priorityWidth.load(2)
|
||||
plic.mapping.load(PlicMapping.sifive)
|
||||
plic.addTarget(core.cpu.externalInterrupt)
|
||||
plic.addTarget(core.cpu.externalSupervisorInterrupt)
|
||||
List(clint.logic, core.cpu.logic).produce {
|
||||
for (plugin <- core.cpu.config.plugins) plugin match {
|
||||
case plugin: CsrPlugin if plugin.utime != null => plugin.utime := clint.logic.io.time
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clint.cpuCount.load(cpuCount)
|
||||
}
|
||||
|
||||
|
||||
object VexRiscvSmpClusterGen {
|
||||
def vexRiscvConfig(hartId : Int,
|
||||
ioRange : UInt => Bool = (x => x(31 downto 28) === 0xF),
|
||||
resetVector : Long = 0x80000000l,
|
||||
iBusWidth : Int = 128,
|
||||
dBusWidth : Int = 64,
|
||||
coherency : Boolean = true,
|
||||
iCacheSize : Int = 8192,
|
||||
dCacheSize : Int = 8192,
|
||||
iCacheWays : Int = 2,
|
||||
dCacheWays : Int = 2,
|
||||
iBusRelax : Boolean = false,
|
||||
earlyBranch : Boolean = false) = {
|
||||
assert(iCacheSize/iCacheWays <= 4096, "Instruction cache ways can't be bigger than 4096 bytes")
|
||||
assert(dCacheSize/dCacheWays <= 4096, "Data cache ways can't be bigger than 4096 bytes")
|
||||
val config = VexRiscvConfig(
|
||||
plugins = List(
|
||||
new MmuPlugin(
|
||||
ioRange = ioRange
|
||||
),
|
||||
//Uncomment the whole IBusCachedPlugin and comment IBusSimplePlugin if you want cached iBus config
|
||||
new IBusCachedPlugin(
|
||||
resetVector = resetVector,
|
||||
compressedGen = false,
|
||||
prediction = vexriscv.plugin.NONE,
|
||||
historyRamSizeLog2 = 9,
|
||||
relaxPredictorAddress = true,
|
||||
injectorStage = false,
|
||||
relaxedPcCalculation = iBusRelax,
|
||||
config = InstructionCacheConfig(
|
||||
cacheSize = iCacheSize,
|
||||
bytePerLine = 64,
|
||||
wayCount = iCacheWays,
|
||||
addressWidth = 32,
|
||||
cpuDataWidth = 32,
|
||||
memDataWidth = iBusWidth,
|
||||
catchIllegalAccess = true,
|
||||
catchAccessFault = true,
|
||||
asyncTagMemory = false,
|
||||
twoCycleRam = false,
|
||||
twoCycleCache = true,
|
||||
reducedBankWidth = true
|
||||
),
|
||||
memoryTranslatorPortConfig = MmuPortConfig(
|
||||
portTlbSize = 4,
|
||||
latency = 1,
|
||||
earlyRequireMmuLockup = true,
|
||||
earlyCacheHits = true
|
||||
)
|
||||
),
|
||||
new DBusCachedPlugin(
|
||||
dBusCmdMasterPipe = dBusWidth == 32,
|
||||
dBusCmdSlavePipe = true,
|
||||
dBusRspSlavePipe = true,
|
||||
relaxedMemoryTranslationRegister = true,
|
||||
config = new DataCacheConfig(
|
||||
cacheSize = dCacheSize,
|
||||
bytePerLine = 64,
|
||||
wayCount = dCacheWays,
|
||||
addressWidth = 32,
|
||||
cpuDataWidth = 32,
|
||||
memDataWidth = dBusWidth,
|
||||
catchAccessError = true,
|
||||
catchIllegal = true,
|
||||
catchUnaligned = true,
|
||||
withLrSc = true,
|
||||
withAmo = true,
|
||||
withExclusive = coherency,
|
||||
withInvalidate = coherency,
|
||||
aggregationWidth = if(dBusWidth == 32) 0 else log2Up(dBusWidth/8)
|
||||
// )
|
||||
),
|
||||
memoryTranslatorPortConfig = MmuPortConfig(
|
||||
portTlbSize = 4,
|
||||
latency = 1,
|
||||
earlyRequireMmuLockup = true,
|
||||
earlyCacheHits = true
|
||||
)
|
||||
),
|
||||
new DecoderSimplePlugin(
|
||||
catchIllegalInstruction = true
|
||||
),
|
||||
new RegFilePlugin(
|
||||
regFileReadyKind = plugin.ASYNC,
|
||||
zeroBoot = false,
|
||||
x0Init = true
|
||||
),
|
||||
new IntAluPlugin,
|
||||
new SrcPlugin(
|
||||
separatedAddSub = false
|
||||
),
|
||||
new FullBarrelShifterPlugin(earlyInjection = true),
|
||||
// new LightShifterPlugin,
|
||||
new HazardSimplePlugin(
|
||||
bypassExecute = true,
|
||||
bypassMemory = true,
|
||||
bypassWriteBack = true,
|
||||
bypassWriteBackBuffer = true,
|
||||
pessimisticUseSrc = false,
|
||||
pessimisticWriteRegFile = false,
|
||||
pessimisticAddressMatch = false
|
||||
),
|
||||
new MulPlugin,
|
||||
new MulDivIterativePlugin(
|
||||
genMul = false,
|
||||
genDiv = true,
|
||||
mulUnrollFactor = 32,
|
||||
divUnrollFactor = 1
|
||||
),
|
||||
new CsrPlugin(CsrPluginConfig.openSbi(mhartid = hartId, misa = Riscv.misaToInt("imas")).copy(utimeAccess = CsrAccess.READ_ONLY)),
|
||||
new BranchPlugin(
|
||||
earlyBranch = earlyBranch,
|
||||
catchAddressMisaligned = true,
|
||||
fenceiGenAsAJump = false
|
||||
),
|
||||
new YamlPlugin(s"cpu$hartId.yaml")
|
||||
)
|
||||
)
|
||||
config
|
||||
}
|
||||
|
||||
|
||||
// def vexRiscvCluster(cpuCount : Int, resetVector : Long = 0x80000000l) = VexRiscvSmpCluster(
|
||||
// debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")),
|
||||
// p = VexRiscvSmpClusterParameter(
|
||||
// cpuConfigs = List.tabulate(cpuCount) {
|
||||
// vexRiscvConfig(_, resetVector = resetVector)
|
||||
// }
|
||||
// )
|
||||
// )
|
||||
// def main(args: Array[String]): Unit = {
|
||||
// SpinalVerilog {
|
||||
// vexRiscvCluster(4)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
//
|
||||
//
|
||||
//
|
||||
//object VexRiscvSmpClusterTestInfrastructure{
|
||||
// val REPORT_OFFSET = 0xF8000000
|
||||
// val REPORT_THREAD_ID = 0x00
|
||||
// val REPORT_THREAD_COUNT = 0x04
|
||||
// val REPORT_END = 0x08
|
||||
// val REPORT_BARRIER_START = 0x0C
|
||||
// val REPORT_BARRIER_END = 0x10
|
||||
// val REPORT_CONSISTENCY_VALUES = 0x14
|
||||
//
|
||||
// val PUTC = 0x00
|
||||
// val GETC = 0x04
|
||||
// val CLINT_ADDR = 0x10000
|
||||
// val CLINT_IPI_ADDR = CLINT_ADDR+0x0000
|
||||
// val CLINT_CMP_ADDR = CLINT_ADDR+0x4000
|
||||
// val CLINT_TIME_ADDR = CLINT_ADDR+0xBFF8
|
||||
//
|
||||
// def ram(dut : VexRiscvSmpCluster, withStall : Boolean) = {
|
||||
// import spinal.core.sim._
|
||||
// val cpuCount = dut.cpus.size
|
||||
// val ram = new BmbMemoryAgent(0x100000000l){
|
||||
// case class Report(hart : Int, code : Int, data : Int){
|
||||
// override def toString: String = {
|
||||
// f"CPU:$hart%2d ${code}%3x -> $data%3d"
|
||||
// }
|
||||
// }
|
||||
// val reports = ArrayBuffer.fill(cpuCount)(ArrayBuffer[Report]())
|
||||
//
|
||||
//
|
||||
// val writeTable = mutable.HashMap[Int, Int => Unit]()
|
||||
// val readTable = mutable.HashMap[Int, () => Int]()
|
||||
// def onWrite(address : Int)(body : Int => Unit) = writeTable(address) = body
|
||||
// def onRead(address : Int)(body : => Int) = readTable(address) = () => body
|
||||
//
|
||||
// var writeData = 0
|
||||
// var readData = 0
|
||||
// var reportWatchdog = 0
|
||||
// val cpuEnd = Array.fill(cpuCount)(false)
|
||||
// val barriers = mutable.HashMap[Int, Int]()
|
||||
// var consistancyCounter = 0
|
||||
// var consistancyLast = 0
|
||||
// var consistancyA = 0
|
||||
// var consistancyB = 0
|
||||
// var consistancyAB = 0
|
||||
// var consistancyNone = 0
|
||||
//
|
||||
// onSimEnd{
|
||||
// for((list, hart) <- reports.zipWithIndex){
|
||||
// println(f"\n\n**** CPU $hart%2d ****")
|
||||
// for((report, reportId) <- list.zipWithIndex){
|
||||
// println(f" $reportId%3d : ${report.code}%3x -> ${report.data}%3d")
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// println(s"consistancy NONE:$consistancyNone A:$consistancyA B:$consistancyB AB:$consistancyAB")
|
||||
// }
|
||||
//
|
||||
// override def setByte(address: Long, value: Byte): Unit = {
|
||||
// if((address & 0xF0000000l) != 0xF0000000l) return super.setByte(address, value)
|
||||
// val byteId = address & 3
|
||||
// val mask = 0xFF << (byteId*8)
|
||||
// writeData = (writeData & ~mask) | ((value.toInt << (byteId*8)) & mask)
|
||||
// if(byteId != 3) return
|
||||
// val offset = (address & ~0xF0000000l)-3
|
||||
// // println(s"W[0x${offset.toHexString}] = $writeData @${simTime()}")
|
||||
// offset match {
|
||||
// case _ if offset >= 0x8000000 && offset < 0x9000000 => {
|
||||
// val report = Report(
|
||||
// hart = ((offset & 0xFF0000) >> 16).toInt,
|
||||
// code = (offset & 0x00FFFF).toInt,
|
||||
// data = writeData
|
||||
// )
|
||||
//// println(report)
|
||||
// reports(report.hart) += report
|
||||
// reportWatchdog += 1
|
||||
// import report._
|
||||
// code match {
|
||||
// case REPORT_THREAD_ID => assert(data == hart)
|
||||
// case REPORT_THREAD_COUNT => assert(data == cpuCount)
|
||||
// case REPORT_END => assert(data == 0); assert(cpuEnd(hart) == false); cpuEnd(hart) = true; if(!cpuEnd.exists(_ == false)) simSuccess()
|
||||
// case REPORT_BARRIER_START => {
|
||||
// val counter = barriers.getOrElse(data, 0)
|
||||
// assert(counter < cpuCount)
|
||||
// barriers(data) = counter + 1
|
||||
// }
|
||||
// case REPORT_BARRIER_END => {
|
||||
// val counter = barriers.getOrElse(data, 0)
|
||||
// assert(counter == cpuCount)
|
||||
// }
|
||||
// case REPORT_CONSISTENCY_VALUES => consistancyCounter match {
|
||||
// case 0 => {
|
||||
// consistancyCounter = 1
|
||||
// consistancyLast = data
|
||||
// }
|
||||
// case 1 => {
|
||||
// consistancyCounter = 0
|
||||
// (data, consistancyLast) match {
|
||||
// case (666, 0) => consistancyA += 1
|
||||
// case (0, 666) => consistancyB += 1
|
||||
// case (666, 666) => consistancyAB += 1
|
||||
// case (0,0) => consistancyNone += 1; simFailure("Consistancy issue :(")
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// case _ => writeTable.get(offset.toInt) match {
|
||||
// case Some(x) => x(writeData)
|
||||
// case _ => simFailure(f"\n\nWrite at ${address-3}%8x with $writeData%8x")
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// override def getByte(address: Long): Byte = {
|
||||
// if((address & 0xF0000000l) != 0xF0000000l) return super.getByte(address)
|
||||
// val byteId = address & 3
|
||||
// val offset = (address & ~0xF0000000l)
|
||||
// if(byteId == 0) readData = readTable.get(offset.toInt) match {
|
||||
// case Some(x) => x()
|
||||
// case _ => simFailure(f"\n\nRead at $address%8x")
|
||||
// }
|
||||
// (readData >> (byteId*8)).toByte
|
||||
// }
|
||||
//
|
||||
// val clint = new {
|
||||
// val cmp = Array.fill(cpuCount)(0l)
|
||||
// var time = 0l
|
||||
// periodicaly(100){
|
||||
// time += 10
|
||||
// var timerInterrupts = 0l
|
||||
// for(i <- 0 until cpuCount){
|
||||
// if(cmp(i) < time) timerInterrupts |= 1l << i
|
||||
// }
|
||||
// dut.io.timerInterrupts #= timerInterrupts
|
||||
// }
|
||||
//
|
||||
//// delayed(200*1000000){
|
||||
//// dut.io.softwareInterrupts #= 0xE
|
||||
//// enableSimWave()
|
||||
//// println("force IPI")
|
||||
//// }
|
||||
// }
|
||||
//
|
||||
// onWrite(PUTC)(data => print(data.toChar))
|
||||
// onRead(GETC)( if(System.in.available() != 0) System.in.read() else -1)
|
||||
//
|
||||
// dut.io.softwareInterrupts #= 0
|
||||
// dut.io.timerInterrupts #= 0
|
||||
// dut.io.externalInterrupts #= 0
|
||||
// dut.io.externalSupervisorInterrupts #= 0
|
||||
// onRead(CLINT_TIME_ADDR)(clint.time.toInt)
|
||||
// onRead(CLINT_TIME_ADDR+4)((clint.time >> 32).toInt)
|
||||
// for(hartId <- 0 until cpuCount){
|
||||
// onWrite(CLINT_IPI_ADDR + hartId*4) {data =>
|
||||
// val mask = 1l << hartId
|
||||
// val value = (dut.io.softwareInterrupts.toLong & ~mask) | (if(data == 1) mask else 0)
|
||||
// dut.io.softwareInterrupts #= value
|
||||
// }
|
||||
//// onRead(CLINT_CMP_ADDR + hartId*8)(clint.cmp(hartId).toInt)
|
||||
//// onRead(CLINT_CMP_ADDR + hartId*8+4)((clint.cmp(hartId) >> 32).toInt)
|
||||
// onWrite(CLINT_CMP_ADDR + hartId*8){data => clint.cmp(hartId) = (clint.cmp(hartId) & 0xFFFFFFFF00000000l) | data}
|
||||
// onWrite(CLINT_CMP_ADDR + hartId*8+4){data => clint.cmp(hartId) = (clint.cmp(hartId) & 0x00000000FFFFFFFFl) | (data.toLong << 32)}
|
||||
// }
|
||||
//
|
||||
//
|
||||
//
|
||||
// }
|
||||
// dut.io.iMems.foreach(ram.addPort(_,0,dut.clockDomain,true, withStall))
|
||||
// ram.addPort(dut.io.dMem,0,dut.clockDomain,true, withStall)
|
||||
// ram
|
||||
// }
|
||||
// def init(dut : VexRiscvSmpCluster): Unit ={
|
||||
// import spinal.core.sim._
|
||||
// dut.clockDomain.forkStimulus(10)
|
||||
// dut.debugClockDomain.forkStimulus(10)
|
||||
// dut.io.debugBus.cmd.valid #= false
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//object VexRiscvSmpClusterTest extends App{
|
||||
// import spinal.core.sim._
|
||||
//
|
||||
// val simConfig = SimConfig
|
||||
// simConfig.withWave
|
||||
// simConfig.allOptimisation
|
||||
// simConfig.addSimulatorFlag("--threads 1")
|
||||
//
|
||||
// val cpuCount = 4
|
||||
// val withStall = true
|
||||
//
|
||||
// simConfig.compile(VexRiscvSmpClusterGen.vexRiscvCluster(cpuCount)).doSimUntilVoid(seed = 42){dut =>
|
||||
// disableSimWave()
|
||||
// SimTimeout(100000000l*10*cpuCount)
|
||||
// dut.clockDomain.forkSimSpeedPrinter(1.0)
|
||||
// VexRiscvSmpClusterTestInfrastructure.init(dut)
|
||||
// val ram = VexRiscvSmpClusterTestInfrastructure.ram(dut, withStall)
|
||||
// ram.memory.loadBin(0x80000000l, "src/test/cpp/raw/smp/build/smp.bin")
|
||||
// periodicaly(20000*10){
|
||||
// assert(ram.reportWatchdog != 0)
|
||||
// ram.reportWatchdog = 0
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//// echo "echo 10000 | dhrystone >> log" > test
|
||||
//// time sh test &
|
||||
//// top -b -n 1
|
||||
//
|
||||
//// TODO
|
||||
//// MultiChannelFifo.toStream arbitration
|
||||
//// BmbDecoderOutOfOrder arbitration
|
||||
//// DataCache to bmb invalidation that are more than single line
|
||||
//object VexRiscvSmpClusterOpenSbi extends App{
|
||||
// import spinal.core.sim._
|
||||
//
|
||||
// val simConfig = SimConfig
|
||||
// simConfig.withWave
|
||||
// simConfig.allOptimisation
|
||||
// simConfig.addSimulatorFlag("--threads 1")
|
||||
//
|
||||
// val cpuCount = 2
|
||||
// val withStall = false
|
||||
//
|
||||
// def gen = {
|
||||
// val dut = VexRiscvSmpClusterGen.vexRiscvCluster(cpuCount, resetVector = 0x80000000l)
|
||||
// dut.cpus.foreach{cpu =>
|
||||
// cpu.core.children.foreach{
|
||||
// case cache : InstructionCache => cache.io.cpu.decode.simPublic()
|
||||
// case _ =>
|
||||
// }
|
||||
// }
|
||||
// dut
|
||||
// }
|
||||
//
|
||||
// simConfig.workspaceName("rawr_4c").compile(gen).doSimUntilVoid(seed = 42){dut =>
|
||||
//// dut.clockDomain.forkSimSpeedPrinter(1.0)
|
||||
// VexRiscvSmpClusterTestInfrastructure.init(dut)
|
||||
// val ram = VexRiscvSmpClusterTestInfrastructure.ram(dut, withStall)
|
||||
//// ram.memory.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_payload.bin")
|
||||
//
|
||||
//// ram.memory.loadBin(0x40F00000l, "/media/data/open/litex_smp/litex_vexriscv_smp/images/fw_jump.bin")
|
||||
//// ram.memory.loadBin(0x40000000l, "/media/data/open/litex_smp/litex_vexriscv_smp/images/Image")
|
||||
//// ram.memory.loadBin(0x40EF0000l, "/media/data/open/litex_smp/litex_vexriscv_smp/images/dtb")
|
||||
//// ram.memory.loadBin(0x41000000l, "/media/data/open/litex_smp/litex_vexriscv_smp/images/rootfs.cpio")
|
||||
//
|
||||
// ram.memory.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin")
|
||||
// ram.memory.loadBin(0xC0000000l, "../buildroot/output/images/Image")
|
||||
// ram.memory.loadBin(0xC1000000l, "../buildroot/output/images/dtb")
|
||||
// ram.memory.loadBin(0xC2000000l, "../buildroot/output/images/rootfs.cpio")
|
||||
//
|
||||
// import spinal.core.sim._
|
||||
// var iMemReadBytes, dMemReadBytes, dMemWriteBytes, iMemSequencial,iMemRequests, iMemPrefetchHit = 0l
|
||||
// var reportTimer = 0
|
||||
// var reportCycle = 0
|
||||
// val iMemFetchDelta = mutable.HashMap[Long, Long]()
|
||||
// var iMemFetchDeltaSorted : Seq[(Long, Long)] = null
|
||||
// var dMemWrites, dMemWritesCached = 0l
|
||||
// val dMemWriteCacheCtx = List(4,8,16,32,64).map(bytes => new {
|
||||
// var counter = 0l
|
||||
// var address = 0l
|
||||
// val mask = ~((1 << log2Up(bytes))-1)
|
||||
// })
|
||||
//
|
||||
// import java.io._
|
||||
// val csv = new PrintWriter(new File("bench.csv" ))
|
||||
// val iMemCtx = Array.tabulate(cpuCount)(i => new {
|
||||
// var sequencialPrediction = 0l
|
||||
// val cache = dut.cpus(i).core.children.find(_.isInstanceOf[InstructionCache]).head.asInstanceOf[InstructionCache].io.cpu.decode
|
||||
// var lastAddress = 0l
|
||||
// })
|
||||
// dut.clockDomain.onSamplings{
|
||||
// dut.io.time #= simTime()/10
|
||||
//
|
||||
//
|
||||
// for(i <- 0 until cpuCount; iMem = dut.io.iMems(i); ctx = iMemCtx(i)){
|
||||
//// if(iMem.cmd.valid.toBoolean && iMem.cmd.ready.toBoolean){
|
||||
//// val length = iMem.cmd.length.toInt + 1
|
||||
//// val address = iMem.cmd.address.toLong
|
||||
//// iMemReadBytes += length
|
||||
//// iMemRequests += 1
|
||||
//// }
|
||||
// if(ctx.cache.isValid.toBoolean && !ctx.cache.mmuRefilling.toBoolean && !ctx.cache.mmuException.toBoolean){
|
||||
// val address = ctx.cache.physicalAddress.toLong
|
||||
// val length = ctx.cache.p.bytePerLine.toLong
|
||||
// val mask = ~(length-1)
|
||||
// if(ctx.cache.cacheMiss.toBoolean) {
|
||||
// iMemReadBytes += length
|
||||
// if ((address & mask) == (ctx.sequencialPrediction & mask)) {
|
||||
// iMemSequencial += 1
|
||||
// }
|
||||
// }
|
||||
// if(!ctx.cache.isStuck.toBoolean) {
|
||||
// ctx.sequencialPrediction = address + length
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if(iMem.cmd.valid.toBoolean && iMem.cmd.ready.toBoolean){
|
||||
// val address = iMem.cmd.address.toLong
|
||||
// iMemRequests += 1
|
||||
// if(iMemCtx(i).lastAddress + ctx.cache.p.bytePerLine == address){
|
||||
// iMemPrefetchHit += 1
|
||||
// }
|
||||
// val delta = address-iMemCtx(i).lastAddress
|
||||
// iMemFetchDelta(delta) = iMemFetchDelta.getOrElse(delta, 0l) + 1l
|
||||
// if(iMemRequests % 1000 == 999) iMemFetchDeltaSorted = iMemFetchDelta.toSeq.sortBy(_._1)
|
||||
// iMemCtx(i).lastAddress = address
|
||||
// }
|
||||
// }
|
||||
// if(dut.io.dMem.cmd.valid.toBoolean && dut.io.dMem.cmd.ready.toBoolean){
|
||||
// if(dut.io.dMem.cmd.opcode.toInt == Bmb.Cmd.Opcode.WRITE){
|
||||
// dMemWriteBytes += dut.io.dMem.cmd.length.toInt+1
|
||||
// val address = dut.io.dMem.cmd.address.toLong
|
||||
// dMemWrites += 1
|
||||
// for(ctx <- dMemWriteCacheCtx){
|
||||
// if((address & ctx.mask) == (ctx.address & ctx.mask)){
|
||||
// ctx.counter += 1
|
||||
// } else {
|
||||
// ctx.address = address
|
||||
// }
|
||||
// }
|
||||
// }else {
|
||||
// dMemReadBytes += dut.io.dMem.cmd.length.toInt+1
|
||||
// for(ctx <- dMemWriteCacheCtx) ctx.address = -1
|
||||
// }
|
||||
// }
|
||||
// reportTimer = reportTimer + 1
|
||||
// reportCycle = reportCycle + 1
|
||||
// if(reportTimer == 400000){
|
||||
// reportTimer = 0
|
||||
//// println(f"\n** c=${reportCycle} ir=${iMemReadBytes*1e-6}%5.2f dr=${dMemReadBytes*1e-6}%5.2f dw=${dMemWriteBytes*1e-6}%5.2f **\n")
|
||||
//
|
||||
//
|
||||
// csv.write(s"$reportCycle,$iMemReadBytes,$dMemReadBytes,$dMemWriteBytes,$iMemRequests,$iMemSequencial,$dMemWrites,${dMemWriteCacheCtx.map(_.counter).mkString(",")},$iMemPrefetchHit\n")
|
||||
// csv.flush()
|
||||
// reportCycle = 0
|
||||
// iMemReadBytes = 0
|
||||
// dMemReadBytes = 0
|
||||
// dMemWriteBytes = 0
|
||||
// iMemRequests = 0
|
||||
// iMemSequencial = 0
|
||||
// dMemWrites = 0
|
||||
// iMemPrefetchHit = 0
|
||||
// for(ctx <- dMemWriteCacheCtx) ctx.counter = 0
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
//// fork{
|
||||
//// disableSimWave()
|
||||
//// val atMs = 3790
|
||||
//// val durationMs = 5
|
||||
//// sleep(atMs*1000000)
|
||||
//// enableSimWave()
|
||||
//// println("** enableSimWave **")
|
||||
//// sleep(durationMs*1000000)
|
||||
//// println("** disableSimWave **")
|
||||
//// while(true) {
|
||||
//// disableSimWave()
|
||||
//// sleep(100000 * 10)
|
||||
//// enableSimWave()
|
||||
//// sleep( 100 * 10)
|
||||
//// }
|
||||
////// simSuccess()
|
||||
//// }
|
||||
//
|
||||
// fork{
|
||||
// while(true) {
|
||||
// disableSimWave()
|
||||
// sleep(100000 * 10)
|
||||
// enableSimWave()
|
||||
// sleep( 100 * 10)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
236
src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala
Normal file
236
src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala
Normal file
|
@ -0,0 +1,236 @@
|
|||
package vexriscv.demo.smp
|
||||
|
||||
import spinal.core._
|
||||
import spinal.lib.bus.bmb._
|
||||
import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping}
|
||||
import spinal.lib.bus.wishbone.{WishboneConfig, WishboneToBmbGenerator}
|
||||
import spinal.lib.sim.SparseMemory
|
||||
import vexriscv.demo.smp.VexRiscvSmpClusterGen.vexRiscvConfig
|
||||
import vexriscv.plugin.DBusCachedPlugin
|
||||
|
||||
|
||||
case class VexRiscvLitexSmpClusterParameter( cluster : VexRiscvSmpClusterParameter,
|
||||
liteDram : LiteDramNativeParameter,
|
||||
liteDramMapping : AddressMapping,
|
||||
coherentDma : Boolean)
|
||||
|
||||
|
||||
class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter) extends VexRiscvSmpClusterWithPeripherals(p.cluster) {
|
||||
val iArbiter = BmbBridgeGenerator()
|
||||
val iBridge = BmbToLiteDramGenerator(p.liteDramMapping)
|
||||
val dBridge = BmbToLiteDramGenerator(p.liteDramMapping)
|
||||
|
||||
for(core <- cores) interconnect.addConnection(core.cpu.iBus -> List(iArbiter.bmb))
|
||||
interconnect.addConnection(
|
||||
iArbiter.bmb -> List(iBridge.bmb, peripheralBridge.bmb),
|
||||
dBusNonCoherent.bmb -> List(dBridge.bmb, peripheralBridge.bmb)
|
||||
)
|
||||
|
||||
if(p.cluster.withExclusiveAndInvalidation) interconnect.masters(dBusNonCoherent.bmb).withOutOfOrderDecoder()
|
||||
|
||||
dBridge.liteDramParameter.load(p.liteDram)
|
||||
iBridge.liteDramParameter.load(p.liteDram)
|
||||
|
||||
// Coherent DMA interface
|
||||
val dma = p.coherentDma generate new Area {
|
||||
val bridge = WishboneToBmbGenerator()
|
||||
val wishbone = bridge.produceIo(bridge.logic.io.input)
|
||||
val dataWidth = p.cluster.cpuConfigs.head.find(classOf[DBusCachedPlugin]).get.config.memDataWidth
|
||||
bridge.config.load(WishboneConfig(
|
||||
addressWidth = 32 - log2Up(dataWidth / 8),
|
||||
dataWidth = dataWidth,
|
||||
useSTALL = true,
|
||||
selWidth = dataWidth/8
|
||||
))
|
||||
interconnect.addConnection(bridge.bmb, dBusCoherent.bmb)
|
||||
}
|
||||
|
||||
// Interconnect pipelining (FMax)
|
||||
for(core <- cores) {
|
||||
interconnect.setPipelining(core.cpu.dBus)(cmdValid = true, cmdReady = true, rspValid = true)
|
||||
interconnect.setPipelining(core.cpu.iBus)(cmdHalfRate = true, rspValid = true)
|
||||
interconnect.setPipelining(iArbiter.bmb)(cmdHalfRate = true, rspValid = true)
|
||||
}
|
||||
interconnect.setPipelining(dBusNonCoherent.bmb)(cmdValid = true, cmdReady = true, rspValid = true)
|
||||
interconnect.setPipelining(peripheralBridge.bmb)(cmdHalfRate = true, rspValid = true)
|
||||
}
|
||||
|
||||
|
||||
object VexRiscvLitexSmpClusterCmdGen extends App {
|
||||
var cpuCount = 1
|
||||
var iBusWidth = 64
|
||||
var dBusWidth = 64
|
||||
var iCacheSize = 8192
|
||||
var dCacheSize = 8192
|
||||
var iCacheWays = 2
|
||||
var dCacheWays = 2
|
||||
var liteDramWidth = 128
|
||||
var coherentDma = false
|
||||
var netlistDirectory = "."
|
||||
var netlistName = "VexRiscvLitexSmpCluster"
|
||||
assert(new scopt.OptionParser[Unit]("VexRiscvLitexSmpClusterCmdGen") {
|
||||
help("help").text("prints this usage text")
|
||||
opt[Unit]("coherent-dma") action { (v, c) => coherentDma = true }
|
||||
opt[String]("cpu-count") action { (v, c) => cpuCount = v.toInt }
|
||||
opt[String]("ibus-width") action { (v, c) => iBusWidth = v.toInt }
|
||||
opt[String]("dbus-width") action { (v, c) => dBusWidth = v.toInt }
|
||||
opt[String]("icache-size") action { (v, c) => iCacheSize = v.toInt }
|
||||
opt[String]("dcache-size") action { (v, c) => dCacheSize = v.toInt }
|
||||
opt[String]("icache-ways") action { (v, c) => iCacheWays = v.toInt }
|
||||
opt[String]("dcache-ways") action { (v, c) => dCacheWays = v.toInt }
|
||||
opt[String]("litedram-width") action { (v, c) => liteDramWidth = v.toInt }
|
||||
opt[String]("netlist-directory") action { (v, c) => netlistDirectory = v }
|
||||
opt[String]("netlist-name") action { (v, c) => netlistName = v }
|
||||
}.parse(args))
|
||||
|
||||
val coherency = coherentDma || cpuCount > 1
|
||||
def parameter = VexRiscvLitexSmpClusterParameter(
|
||||
cluster = VexRiscvSmpClusterParameter(
|
||||
cpuConfigs = List.tabulate(cpuCount) { hartId =>
|
||||
vexRiscvConfig(
|
||||
hartId = hartId,
|
||||
ioRange = address => address.msb,
|
||||
resetVector = 0,
|
||||
iBusWidth = iBusWidth,
|
||||
dBusWidth = dBusWidth,
|
||||
iCacheSize = iCacheSize,
|
||||
dCacheSize = dCacheSize,
|
||||
iCacheWays = iCacheWays,
|
||||
dCacheWays = dCacheWays,
|
||||
coherency = coherency
|
||||
)
|
||||
},
|
||||
withExclusiveAndInvalidation = coherency
|
||||
),
|
||||
liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = liteDramWidth),
|
||||
liteDramMapping = SizeMapping(0x40000000l, 0x40000000l),
|
||||
coherentDma = coherentDma
|
||||
)
|
||||
|
||||
def dutGen = {
|
||||
val toplevel = new VexRiscvLitexSmpCluster(
|
||||
p = parameter
|
||||
).toComponent()
|
||||
toplevel
|
||||
}
|
||||
|
||||
val genConfig = SpinalConfig(targetDirectory = netlistDirectory).addStandardMemBlackboxing(blackboxByteEnables)
|
||||
genConfig.generateVerilog(dutGen.setDefinitionName(netlistName))
|
||||
|
||||
}
|
||||
|
||||
|
||||
object VexRiscvLitexSmpClusterGen extends App {
|
||||
for(cpuCount <- List(1,2,4,8)) {
|
||||
def parameter = VexRiscvLitexSmpClusterParameter(
|
||||
cluster = VexRiscvSmpClusterParameter(
|
||||
cpuConfigs = List.tabulate(cpuCount) { hartId =>
|
||||
vexRiscvConfig(
|
||||
hartId = hartId,
|
||||
ioRange = address => address.msb,
|
||||
resetVector = 0
|
||||
)
|
||||
},
|
||||
withExclusiveAndInvalidation = true
|
||||
),
|
||||
liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128),
|
||||
liteDramMapping = SizeMapping(0x40000000l, 0x40000000l),
|
||||
coherentDma = false
|
||||
)
|
||||
|
||||
def dutGen = {
|
||||
val toplevel = new VexRiscvLitexSmpCluster(
|
||||
p = parameter
|
||||
).toComponent()
|
||||
toplevel
|
||||
}
|
||||
|
||||
val genConfig = SpinalConfig().addStandardMemBlackboxing(blackboxByteEnables)
|
||||
// genConfig.generateVerilog(Bench.compressIo(dutGen))
|
||||
genConfig.generateVerilog(dutGen.setDefinitionName(s"VexRiscvLitexSmpCluster_${cpuCount}c"))
|
||||
}
|
||||
}
|
||||
|
||||
////addAttribute("""mark_debug = "true"""")
|
||||
object VexRiscvLitexSmpClusterOpenSbi extends App{
|
||||
import spinal.core.sim._
|
||||
|
||||
val simConfig = SimConfig
|
||||
simConfig.withWave
|
||||
simConfig.allOptimisation
|
||||
|
||||
val cpuCount = 2
|
||||
|
||||
def parameter = VexRiscvLitexSmpClusterParameter(
|
||||
cluster = VexRiscvSmpClusterParameter(
|
||||
cpuConfigs = List.tabulate(cpuCount) { hartId =>
|
||||
vexRiscvConfig(
|
||||
hartId = hartId,
|
||||
ioRange = address => address(31 downto 28) === 0xF,
|
||||
resetVector = 0x80000000l
|
||||
)
|
||||
},
|
||||
withExclusiveAndInvalidation = true
|
||||
),
|
||||
liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128),
|
||||
liteDramMapping = SizeMapping(0x80000000l, 0x70000000l),
|
||||
coherentDma = false
|
||||
)
|
||||
|
||||
def dutGen = {
|
||||
val top = new VexRiscvLitexSmpCluster(
|
||||
p = parameter
|
||||
).toComponent()
|
||||
top.rework{
|
||||
top.clintWishbone.setAsDirectionLess.allowDirectionLessIo
|
||||
top.peripheral.setAsDirectionLess.allowDirectionLessIo.simPublic()
|
||||
|
||||
val hit = (top.peripheral.ADR <<2 >= 0xF0010000l && top.peripheral.ADR<<2 < 0xF0020000l)
|
||||
top.clintWishbone.CYC := top.peripheral.CYC && hit
|
||||
top.clintWishbone.STB := top.peripheral.STB
|
||||
top.clintWishbone.WE := top.peripheral.WE
|
||||
top.clintWishbone.ADR := top.peripheral.ADR.resized
|
||||
top.clintWishbone.DAT_MOSI := top.peripheral.DAT_MOSI
|
||||
top.peripheral.DAT_MISO := top.clintWishbone.DAT_MISO
|
||||
top.peripheral.ACK := top.peripheral.CYC && (!hit || top.clintWishbone.ACK)
|
||||
top.peripheral.ERR := False
|
||||
|
||||
// top.dMemBridge.unburstified.cmd.simPublic()
|
||||
}
|
||||
top
|
||||
}
|
||||
simConfig.compile(dutGen).doSimUntilVoid(seed = 42){dut =>
|
||||
dut.debugCd.inputClockDomain.get.forkStimulus(10)
|
||||
|
||||
val ram = SparseMemory()
|
||||
ram.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin")
|
||||
ram.loadBin(0xC0000000l, "../buildroot/output/images/Image")
|
||||
ram.loadBin(0xC1000000l, "../buildroot/output/images/dtb")
|
||||
ram.loadBin(0xC2000000l, "../buildroot/output/images/rootfs.cpio")
|
||||
|
||||
|
||||
dut.iBridge.dram.simSlave(ram, dut.debugCd.inputClockDomain)
|
||||
dut.dBridge.dram.simSlave(ram, dut.debugCd.inputClockDomain/*, dut.dMemBridge.unburstified*/)
|
||||
|
||||
dut.interrupts.get #= 0
|
||||
|
||||
dut.debugCd.inputClockDomain.get.onFallingEdges{
|
||||
if(dut.peripheral.CYC.toBoolean){
|
||||
(dut.peripheral.ADR.toLong << 2) match {
|
||||
case 0xF0000000l => print(dut.peripheral.DAT_MOSI.toLong.toChar)
|
||||
case 0xF0000004l => dut.peripheral.DAT_MISO #= (if(System.in.available() != 0) System.in.read() else 0xFFFFFFFFl)
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fork{
|
||||
while(true) {
|
||||
disableSimWave()
|
||||
sleep(100000 * 10)
|
||||
enableSimWave()
|
||||
sleep( 100 * 10)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
409
src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala
Normal file
409
src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala
Normal file
|
@ -0,0 +1,409 @@
|
|||
package vexriscv.demo.smp
|
||||
|
||||
import spinal.core._
|
||||
import spinal.lib.bus.bmb._
|
||||
import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping}
|
||||
import spinal.lib.bus.wishbone.{WishboneConfig, WishboneToBmbGenerator}
|
||||
import spinal.lib.sim.SparseMemory
|
||||
import vexriscv.demo.smp.VexRiscvSmpClusterGen.vexRiscvConfig
|
||||
|
||||
//case class VexRiscvLitexSmpMpClusterParameter( cluster : VexRiscvSmpClusterParameter,
|
||||
// liteDram : LiteDramNativeParameter,
|
||||
// liteDramMapping : AddressMapping)
|
||||
//
|
||||
//class VexRiscvLitexSmpMpCluster(p : VexRiscvLitexSmpMpClusterParameter) extends VexRiscvSmpClusterWithPeripherals(p.cluster) {
|
||||
// val iArbiter = BmbBridgeGenerator()
|
||||
// val iBridge = BmbToLiteDramGenerator(p.liteDramMapping)
|
||||
// val dBridge = BmbToLiteDramGenerator(p.liteDramMapping)
|
||||
//
|
||||
// for(core <- cores) interconnect.addConnection(core.cpu.iBus -> List(iArbiter.bmb))
|
||||
// interconnect.addConnection(
|
||||
// iArbiter.bmb -> List(iBridge.bmb, peripheralBridge.bmb),
|
||||
// invalidationMonitor.output -> List(dBridge.bmb, peripheralBridge.bmb)
|
||||
// )
|
||||
// interconnect.masters(invalidationMonitor.output).withOutOfOrderDecoder()
|
||||
//
|
||||
// dBridge.liteDramParameter.load(p.liteDram)
|
||||
// iBridge.liteDramParameter.load(p.liteDram)
|
||||
//
|
||||
// // Interconnect pipelining (FMax)
|
||||
// for(core <- cores) {
|
||||
// interconnect.setPipelining(core.cpu.dBus)(cmdValid = true, cmdReady = true, rspValid = true)
|
||||
// interconnect.setPipelining(core.cpu.iBus)(cmdHalfRate = true, rspValid = true)
|
||||
// interconnect.setPipelining(iArbiter.bmb)(cmdHalfRate = true, rspValid = true)
|
||||
// }
|
||||
// interconnect.setPipelining(invalidationMonitor.output)(cmdValid = true, cmdReady = true, rspValid = true)
|
||||
// interconnect.setPipelining(peripheralBridge.bmb)(cmdHalfRate = true, rspValid = true)
|
||||
//}
|
||||
//
|
||||
//
|
||||
//object VexRiscvLitexSmpMpClusterGen extends App {
|
||||
// for(cpuCount <- List(1,2,4,8)) {
|
||||
// def parameter = VexRiscvLitexSmpMpClusterParameter(
|
||||
// cluster = VexRiscvSmpClusterParameter(
|
||||
// cpuConfigs = List.tabulate(cpuCount) { hartId =>
|
||||
// vexRiscvConfig(
|
||||
// hartId = hartId,
|
||||
// ioRange = address => address.msb,
|
||||
// resetVector = 0
|
||||
// )
|
||||
// }
|
||||
// ),
|
||||
// liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128),
|
||||
// liteDramMapping = SizeMapping(0x40000000l, 0x40000000l)
|
||||
// )
|
||||
//
|
||||
// def dutGen = {
|
||||
// val toplevel = new VexRiscvLitexSmpMpCluster(
|
||||
// p = parameter
|
||||
// ).toComponent()
|
||||
// toplevel
|
||||
// }
|
||||
//
|
||||
// val genConfig = SpinalConfig().addStandardMemBlackboxing(blackboxByteEnables)
|
||||
// // genConfig.generateVerilog(Bench.compressIo(dutGen))
|
||||
// genConfig.generateVerilog(dutGen.setDefinitionName(s"VexRiscvLitexSmpMpCluster_${cpuCount}c"))
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
|
||||
//
|
||||
////addAttribute("""mark_debug = "true"""")
|
||||
//class VexRiscvLitexSmpMpCluster(val p : VexRiscvLitexSmpMpClusterParameter,
|
||||
// val debugClockDomain : ClockDomain,
|
||||
// val jtagClockDomain : ClockDomain) extends Component{
|
||||
//
|
||||
// val peripheralWishboneConfig = WishboneConfig(
|
||||
// addressWidth = 30,
|
||||
// dataWidth = 32,
|
||||
// selWidth = 4,
|
||||
// useERR = true,
|
||||
// useBTE = true,
|
||||
// useCTI = true
|
||||
// )
|
||||
//
|
||||
// val cpuCount = p.cluster.cpuConfigs.size
|
||||
//
|
||||
// val io = new Bundle {
|
||||
// val dMem = Vec(master(LiteDramNative(p.liteDram)), cpuCount)
|
||||
// val iMem = Vec(master(LiteDramNative(p.liteDram)), cpuCount)
|
||||
// val peripheral = master(Wishbone(peripheralWishboneConfig))
|
||||
// val clint = slave(Wishbone(Clint.getWisboneConfig()))
|
||||
// val plic = slave(Wishbone(WishboneConfig(addressWidth = 20, dataWidth = 32)))
|
||||
// val interrupts = in Bits(32 bits)
|
||||
// val jtagInstruction = slave(JtagTapInstructionCtrl())
|
||||
// val debugReset = out Bool()
|
||||
// }
|
||||
// val clint = Clint(cpuCount)
|
||||
// clint.driveFrom(WishboneSlaveFactory(io.clint))
|
||||
//
|
||||
// val cluster = VexRiscvSmpCluster(p.cluster, debugClockDomain)
|
||||
// cluster.io.debugReset <> io.debugReset
|
||||
// cluster.io.timerInterrupts <> B(clint.harts.map(_.timerInterrupt))
|
||||
// cluster.io.softwareInterrupts <> B(clint.harts.map(_.softwareInterrupt))
|
||||
// cluster.io.time := clint.time
|
||||
//
|
||||
// val debug = debugClockDomain on new Area{
|
||||
// val jtagConfig = SystemDebuggerConfig()
|
||||
//
|
||||
// val jtagBridge = new JtagBridgeNoTap(jtagConfig, jtagClockDomain)
|
||||
// jtagBridge.io.ctrl << io.jtagInstruction
|
||||
//
|
||||
// val debugger = new SystemDebugger(jtagConfig)
|
||||
// debugger.io.remote <> jtagBridge.io.remote
|
||||
//
|
||||
// cluster.io.debugBus << debugger.io.mem.toBmb()
|
||||
//
|
||||
//// io.jtagInstruction.allowDirectionLessIo.setAsDirectionLess
|
||||
//// val bridge = Bscane2BmbMaster(1)
|
||||
//// cluster.io.debugBus << bridge.io.bmb
|
||||
//
|
||||
//
|
||||
//// val bscane2 = BSCANE2(usedId)
|
||||
//// val jtagClockDomain = ClockDomain(bscane2.TCK)
|
||||
////
|
||||
//// val jtagBridge = new JtagBridgeNoTap(jtagConfig, jtagClockDomain)
|
||||
//// jtagBridge.io.ctrl << bscane2.toJtagTapInstructionCtrl()
|
||||
////
|
||||
//// val debugger = new SystemDebugger(jtagConfig)
|
||||
//// debugger.io.remote <> jtagBridge.io.remote
|
||||
////
|
||||
//// io.bmb << debugger.io.mem.toBmb()
|
||||
// }
|
||||
//
|
||||
// val dBusDecoder = BmbDecoderOutOfOrder(
|
||||
// p = cluster.io.dMem.p,
|
||||
// mappings = Seq(DefaultMapping, p.liteDramMapping),
|
||||
// capabilities = Seq(cluster.io.dMem.p, cluster.io.dMem.p),
|
||||
// pendingRspTransactionMax = 32
|
||||
// )
|
||||
//// val dBusDecoder = BmbDecoderOut(
|
||||
//// p = cluster.io.dMem.p,
|
||||
//// mappings = Seq(DefaultMapping, p.liteDramMapping),
|
||||
//// capabilities = Seq(cluster.io.dMem.p, cluster.io.dMem.p),
|
||||
//// pendingMax = 31
|
||||
//// )
|
||||
// dBusDecoder.io.input << cluster.io.dMem.pipelined(cmdValid = true, cmdReady = true, rspValid = true)
|
||||
//
|
||||
//
|
||||
// val perIBus = for(id <- 0 until cpuCount) yield new Area{
|
||||
// val decoder = BmbDecoder(
|
||||
// p = cluster.io.iMems(id).p,
|
||||
// mappings = Seq(DefaultMapping, p.liteDramMapping),
|
||||
// capabilities = Seq(cluster.io.iMems(id).p,cluster.io.iMems(id).p),
|
||||
// pendingMax = 15
|
||||
// )
|
||||
//
|
||||
// decoder.io.input << cluster.io.iMems(id)
|
||||
// io.iMem(id).fromBmb(decoder.io.outputs(1).pipelined(cmdHalfRate = true), wdataFifoSize = 0, rdataFifoSize = 32)
|
||||
// val toPeripheral = decoder.io.outputs(0).resize(dataWidth = 32).pipelined(cmdHalfRate = true, rspValid = true)
|
||||
// }
|
||||
//
|
||||
// val dBusDecoderToPeripheral = dBusDecoder.io.outputs(0).resize(dataWidth = 32).pipelined(cmdHalfRate = true, rspValid = true)
|
||||
//
|
||||
// val peripheralAccessLength = Math.max(perIBus(0).toPeripheral.p.lengthWidth, dBusDecoder.io.outputs(0).p.lengthWidth)
|
||||
// val peripheralArbiter = BmbArbiter(
|
||||
// p = dBusDecoder.io.outputs(0).p.copy(
|
||||
// sourceWidth = List(perIBus(0).toPeripheral, dBusDecoderToPeripheral).map(_.p.sourceWidth).max + log2Up(cpuCount + 1),
|
||||
// contextWidth = List(perIBus(0).toPeripheral, dBusDecoderToPeripheral).map(_.p.contextWidth).max,
|
||||
// lengthWidth = peripheralAccessLength,
|
||||
// dataWidth = 32
|
||||
// ),
|
||||
// portCount = cpuCount+1,
|
||||
// lowerFirstPriority = true
|
||||
// )
|
||||
//
|
||||
// for(id <- 0 until cpuCount){
|
||||
// peripheralArbiter.io.inputs(id) << perIBus(id).toPeripheral
|
||||
// }
|
||||
// peripheralArbiter.io.inputs(cpuCount) << dBusDecoderToPeripheral
|
||||
//
|
||||
// val peripheralWishbone = peripheralArbiter.io.output.pipelined(cmdValid = true).toWishbone()
|
||||
// io.peripheral << peripheralWishbone
|
||||
//
|
||||
//
|
||||
// val dBusDemux = BmbSourceDecoder(dBusDecoder.io.outputs(1).p)
|
||||
// dBusDemux.io.input << dBusDecoder.io.outputs(1).pipelined(cmdValid = true, cmdReady = true,rspValid = true)
|
||||
// val dMemBridge = for(id <- 0 until cpuCount) yield {
|
||||
// io.dMem(id).fromBmb(dBusDemux.io.outputs(id), wdataFifoSize = 32, rdataFifoSize = 32)
|
||||
// }
|
||||
//
|
||||
//
|
||||
// val plic = new Area{
|
||||
// val priorityWidth = 2
|
||||
//
|
||||
// val gateways = for(i <- 1 until 32) yield PlicGatewayActiveHigh(
|
||||
// source = io.interrupts(i),
|
||||
// id = i,
|
||||
// priorityWidth = priorityWidth
|
||||
// )
|
||||
//
|
||||
// val bus = WishboneSlaveFactory(io.plic)
|
||||
//
|
||||
// val targets = for(i <- 0 until cpuCount) yield new Area{
|
||||
// val machine = PlicTarget(
|
||||
// gateways = gateways,
|
||||
// priorityWidth = priorityWidth
|
||||
// )
|
||||
// val supervisor = PlicTarget(
|
||||
// gateways = gateways,
|
||||
// priorityWidth = priorityWidth
|
||||
// )
|
||||
//
|
||||
// cluster.io.externalInterrupts(i) := machine.iep
|
||||
// cluster.io.externalSupervisorInterrupts(i) := supervisor.iep
|
||||
// }
|
||||
//
|
||||
// val bridge = PlicMapper(bus, PlicMapping.sifive)(
|
||||
// gateways = gateways,
|
||||
// targets = targets.flatMap(t => List(t.machine, t.supervisor))
|
||||
// )
|
||||
// }
|
||||
////
|
||||
//// io.dMem.foreach(_.cmd.valid.addAttribute("""mark_debug = "true""""))
|
||||
//// io.dMem.foreach(_.cmd.ready.addAttribute("""mark_debug = "true""""))
|
||||
//// io.iMem.foreach(_.cmd.valid.addAttribute("""mark_debug = "true""""))
|
||||
//// io.iMem.foreach(_.cmd.ready.addAttribute("""mark_debug = "true""""))
|
||||
////
|
||||
//// cluster.io.dMem.cmd.valid.addAttribute("""mark_debug = "true"""")
|
||||
//// cluster.io.dMem.cmd.ready.addAttribute("""mark_debug = "true"""")
|
||||
//// cluster.io.dMem.rsp.valid.addAttribute("""mark_debug = "true"""")
|
||||
//// cluster.io.dMem.rsp.ready.addAttribute("""mark_debug = "true"""")
|
||||
//}
|
||||
//
|
||||
//object VexRiscvLitexSmpMpClusterGen extends App {
|
||||
// for(cpuCount <- List(1,2,4,8)) {
|
||||
// def parameter = VexRiscvLitexSmpMpClusterParameter(
|
||||
// cluster = VexRiscvSmpClusterParameter(
|
||||
// cpuConfigs = List.tabulate(cpuCount) { hartId =>
|
||||
// vexRiscvConfig(
|
||||
// hartId = hartId,
|
||||
// ioRange = address => address.msb,
|
||||
// resetVector = 0
|
||||
// )
|
||||
// }
|
||||
// ),
|
||||
// liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128),
|
||||
// liteDramMapping = SizeMapping(0x40000000l, 0x40000000l)
|
||||
// )
|
||||
//
|
||||
// def dutGen = {
|
||||
// val toplevel = new VexRiscvLitexSmpMpCluster(
|
||||
// p = parameter,
|
||||
// debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")),
|
||||
// jtagClockDomain = ClockDomain.external("jtag", withReset = false)
|
||||
// )
|
||||
// toplevel
|
||||
// }
|
||||
//
|
||||
// val genConfig = SpinalConfig().addStandardMemBlackboxing(blackboxByteEnables)
|
||||
// // genConfig.generateVerilog(Bench.compressIo(dutGen))
|
||||
// genConfig.generateVerilog(dutGen.setDefinitionName(s"VexRiscvLitexSmpMpCluster_${cpuCount}c"))
|
||||
// }
|
||||
//
|
||||
//}
|
||||
//
|
||||
//
|
||||
//object VexRiscvLitexSmpMpClusterOpenSbi extends App{
|
||||
// import spinal.core.sim._
|
||||
//
|
||||
// val simConfig = SimConfig
|
||||
// simConfig.withWave
|
||||
// simConfig.withFstWave
|
||||
// simConfig.allOptimisation
|
||||
//
|
||||
// val cpuCount = 2
|
||||
//
|
||||
// def parameter = VexRiscvLitexSmpMpClusterParameter(
|
||||
// cluster = VexRiscvSmpClusterParameter(
|
||||
// cpuConfigs = List.tabulate(cpuCount) { hartId =>
|
||||
// vexRiscvConfig(
|
||||
// hartId = hartId,
|
||||
// ioRange = address => address(31 downto 28) === 0xF,
|
||||
// resetVector = 0x80000000l
|
||||
// )
|
||||
// }
|
||||
// ),
|
||||
// liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128),
|
||||
// liteDramMapping = SizeMapping(0x80000000l, 0x70000000l)
|
||||
// )
|
||||
//
|
||||
// def dutGen = {
|
||||
// val top = new VexRiscvLitexSmpMpCluster(
|
||||
// p = parameter,
|
||||
// debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")),
|
||||
// jtagClockDomain = ClockDomain.external("jtag", withReset = false)
|
||||
// ){
|
||||
// io.jtagInstruction.allowDirectionLessIo.setAsDirectionLess
|
||||
// val jtag = slave(Jtag())
|
||||
// jtagClockDomain.readClockWire.setAsDirectionLess() := jtag.tck
|
||||
// val jtagLogic = jtagClockDomain on new Area{
|
||||
// val tap = new JtagTap(jtag, 4)
|
||||
// val idcodeArea = tap.idcode(B"x10001FFF")(1)
|
||||
// val wrapper = tap.map(io.jtagInstruction, instructionId = 2)
|
||||
// }
|
||||
// }
|
||||
// top.rework{
|
||||
// top.io.clint.setAsDirectionLess.allowDirectionLessIo
|
||||
// top.io.peripheral.setAsDirectionLess.allowDirectionLessIo.simPublic()
|
||||
//
|
||||
// val hit = (top.io.peripheral.ADR <<2 >= 0xF0010000l && top.io.peripheral.ADR<<2 < 0xF0020000l)
|
||||
// top.io.clint.CYC := top.io.peripheral.CYC && hit
|
||||
// top.io.clint.STB := top.io.peripheral.STB
|
||||
// top.io.clint.WE := top.io.peripheral.WE
|
||||
// top.io.clint.ADR := top.io.peripheral.ADR.resized
|
||||
// top.io.clint.DAT_MOSI := top.io.peripheral.DAT_MOSI
|
||||
// top.io.peripheral.DAT_MISO := top.io.clint.DAT_MISO
|
||||
// top.io.peripheral.ACK := top.io.peripheral.CYC && (!hit || top.io.clint.ACK)
|
||||
// top.io.peripheral.ERR := False
|
||||
//
|
||||
//// top.dMemBridge.unburstified.cmd.simPublic()
|
||||
// }
|
||||
// top
|
||||
// }
|
||||
// simConfig.compile(dutGen).doSimUntilVoid(seed = 42){dut =>
|
||||
// dut.clockDomain.forkStimulus(10)
|
||||
// fork {
|
||||
// dut.debugClockDomain.resetSim #= false
|
||||
// sleep (0)
|
||||
// dut.debugClockDomain.resetSim #= true
|
||||
// sleep (10)
|
||||
// dut.debugClockDomain.resetSim #= false
|
||||
// }
|
||||
//
|
||||
// JtagTcp(dut.jtag, 10*20)
|
||||
//
|
||||
// val ram = SparseMemory()
|
||||
// ram.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin")
|
||||
// ram.loadBin(0xC0000000l, "../buildroot/output/images/Image")
|
||||
// ram.loadBin(0xC1000000l, "../buildroot/output/images/dtb")
|
||||
// ram.loadBin(0xC2000000l, "../buildroot/output/images/rootfs.cpio")
|
||||
//
|
||||
// for(id <- 0 until cpuCount) {
|
||||
// dut.io.iMem(id).simSlave(ram, dut.clockDomain)
|
||||
// dut.io.dMem(id).simSlave(ram, dut.clockDomain)
|
||||
// }
|
||||
//
|
||||
// dut.io.interrupts #= 0
|
||||
//
|
||||
//
|
||||
//// val stdin = mutable.Queue[Byte]()
|
||||
//// def stdInPush(str : String) = stdin ++= str.toCharArray.map(_.toByte)
|
||||
//// fork{
|
||||
//// sleep(4000*1000000l)
|
||||
//// stdInPush("root\n")
|
||||
//// sleep(1000*1000000l)
|
||||
//// stdInPush("ping localhost -i 0.01 > /dev/null &\n")
|
||||
//// stdInPush("ping localhost -i 0.01 > /dev/null &\n")
|
||||
//// stdInPush("ping localhost -i 0.01 > /dev/null &\n")
|
||||
//// stdInPush("ping localhost -i 0.01 > /dev/null &\n")
|
||||
//// sleep(500*1000000l)
|
||||
//// while(true){
|
||||
//// sleep(500*1000000l)
|
||||
//// stdInPush("uptime\n")
|
||||
//// printf("\n** uptime **")
|
||||
//// }
|
||||
//// }
|
||||
// dut.clockDomain.onFallingEdges {
|
||||
// if (dut.io.peripheral.CYC.toBoolean) {
|
||||
// (dut.io.peripheral.ADR.toLong << 2) match {
|
||||
// case 0xF0000000l => print(dut.io.peripheral.DAT_MOSI.toLong.toChar)
|
||||
// case 0xF0000004l => dut.io.peripheral.DAT_MISO #= (if (System.in.available() != 0) System.in.read() else 0xFFFFFFFFl)
|
||||
// case _ =>
|
||||
// // case 0xF0000004l => {
|
||||
// // val c = if(stdin.nonEmpty) {
|
||||
// // stdin.dequeue().toInt & 0xFF
|
||||
// // } else {
|
||||
// // 0xFFFFFFFFl
|
||||
// // }
|
||||
// // dut.io.peripheral.DAT_MISO #= c
|
||||
// // }
|
||||
// // case _ =>
|
||||
// // }
|
||||
// // println(f"${dut.io.peripheral.ADR.toLong}%x")
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fork{
|
||||
// val at = 0
|
||||
// val duration = 1000
|
||||
// while(simTime() < at*1000000l) {
|
||||
// disableSimWave()
|
||||
// sleep(100000 * 10)
|
||||
// enableSimWave()
|
||||
// sleep( 200 * 10)
|
||||
// }
|
||||
// println("\n\n********************")
|
||||
// sleep(duration*1000000l)
|
||||
// println("********************\n\n")
|
||||
// while(true) {
|
||||
// disableSimWave()
|
||||
// sleep(100000 * 10)
|
||||
// enableSimWave()
|
||||
// sleep( 400 * 10)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
File diff suppressed because it is too large
Load diff
|
@ -5,7 +5,7 @@ import spinal.core._
|
|||
import spinal.lib._
|
||||
import spinal.lib.bus.amba4.axi.{Axi4Config, Axi4ReadOnly}
|
||||
import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig}
|
||||
import spinal.lib.bus.bmb.{Bmb, BmbParameter}
|
||||
import spinal.lib.bus.bmb.{Bmb, BmbAccessParameter, BmbParameter, BmbSourceParameter}
|
||||
import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig}
|
||||
import spinal.lib.bus.simple._
|
||||
import vexriscv.plugin.{IBusSimpleBus, IBusSimplePlugin}
|
||||
|
@ -22,7 +22,10 @@ case class InstructionCacheConfig( cacheSize : Int,
|
|||
asyncTagMemory : Boolean,
|
||||
twoCycleCache : Boolean = true,
|
||||
twoCycleRam : Boolean = false,
|
||||
preResetFlush : Boolean = false){
|
||||
twoCycleRamInnerMux : Boolean = false,
|
||||
preResetFlush : Boolean = false,
|
||||
bypassGen : Boolean = false,
|
||||
reducedBankWidth : Boolean = false){
|
||||
|
||||
assert(!(twoCycleRam && !twoCycleCache))
|
||||
|
||||
|
@ -68,15 +71,16 @@ case class InstructionCacheConfig( cacheSize : Int,
|
|||
)
|
||||
|
||||
def getBmbParameter() = BmbParameter(
|
||||
addressWidth = 32,
|
||||
dataWidth = 32,
|
||||
lengthWidth = log2Up(this.bytePerLine),
|
||||
sourceWidth = 0,
|
||||
contextWidth = 0,
|
||||
canRead = true,
|
||||
canWrite = false,
|
||||
alignment = BmbParameter.BurstAlignement.LENGTH,
|
||||
maximumPendingTransactionPerId = 1
|
||||
BmbAccessParameter(
|
||||
addressWidth = 32,
|
||||
dataWidth = memDataWidth
|
||||
).addSources(1, BmbSourceParameter(
|
||||
lengthWidth = log2Up(this.bytePerLine),
|
||||
contextWidth = 0,
|
||||
canWrite = false,
|
||||
alignment = BmbParameter.BurstAlignement.LENGTH,
|
||||
maximumPendingTransaction = 1
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -102,24 +106,23 @@ trait InstructionCacheCommons{
|
|||
val cacheMiss, error, mmuRefilling, mmuException, isUser : Bool
|
||||
}
|
||||
|
||||
case class InstructionCacheCpuFetch(p : InstructionCacheConfig) extends Bundle with IMasterSlave with InstructionCacheCommons {
|
||||
case class InstructionCacheCpuFetch(p : InstructionCacheConfig, mmuParameter : MemoryTranslatorBusParameter) extends Bundle with IMasterSlave with InstructionCacheCommons {
|
||||
val isValid = Bool()
|
||||
val isStuck = Bool()
|
||||
val isRemoved = Bool()
|
||||
val pc = UInt(p.addressWidth bits)
|
||||
val data = Bits(p.cpuDataWidth bits)
|
||||
val dataBypassValid = Bool()
|
||||
val dataBypass = Bits(p.cpuDataWidth bits)
|
||||
val mmuBus = MemoryTranslatorBus()
|
||||
val dataBypassValid = p.bypassGen generate Bool()
|
||||
val dataBypass = p.bypassGen generate Bits(p.cpuDataWidth bits)
|
||||
val mmuRsp = MemoryTranslatorRsp(mmuParameter)
|
||||
val physicalAddress = UInt(p.addressWidth bits)
|
||||
val cacheMiss, error, mmuRefilling, mmuException, isUser = ifGen(!p.twoCycleCache)(Bool)
|
||||
val haltIt = Bool
|
||||
|
||||
override def asMaster(): Unit = {
|
||||
out(isValid, isStuck, isRemoved, pc)
|
||||
inWithNull(error,mmuRefilling,mmuException,data, cacheMiss,physicalAddress, haltIt)
|
||||
inWithNull(error,mmuRefilling,mmuException,data, cacheMiss,physicalAddress)
|
||||
outWithNull(isUser, dataBypass, dataBypassValid)
|
||||
slaveWithNull(mmuBus)
|
||||
out(mmuRsp)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,9 +142,9 @@ case class InstructionCacheCpuDecode(p : InstructionCacheConfig) extends Bundle
|
|||
}
|
||||
}
|
||||
|
||||
case class InstructionCacheCpuBus(p : InstructionCacheConfig) extends Bundle with IMasterSlave{
|
||||
case class InstructionCacheCpuBus(p : InstructionCacheConfig, mmuParameter : MemoryTranslatorBusParameter) extends Bundle with IMasterSlave{
|
||||
val prefetch = InstructionCacheCpuPrefetch(p)
|
||||
val fetch = InstructionCacheCpuFetch(p)
|
||||
val fetch = InstructionCacheCpuFetch(p, mmuParameter)
|
||||
val decode = InstructionCacheCpuDecode(p)
|
||||
val fill = Flow(UInt(p.addressWidth bits))
|
||||
|
||||
|
@ -250,7 +253,7 @@ case class InstructionCacheMemBus(p : InstructionCacheConfig) extends Bundle wit
|
|||
|
||||
def toBmb() : Bmb = {
|
||||
val busParameter = p.getBmbParameter
|
||||
val bus = Bmb(busParameter)
|
||||
val bus = Bmb(busParameter).setCompositeName(this,"toBmb", true)
|
||||
bus.cmd.arbitrationFrom(cmd)
|
||||
bus.cmd.opcode := Bmb.Cmd.Opcode.READ
|
||||
bus.cmd.address := cmd.address.resized
|
||||
|
@ -275,34 +278,23 @@ case class InstructionCacheFlushBus() extends Bundle with IMasterSlave{
|
|||
}
|
||||
}
|
||||
|
||||
class InstructionCache(p : InstructionCacheConfig) extends Component{
|
||||
class InstructionCache(p : InstructionCacheConfig, mmuParameter : MemoryTranslatorBusParameter) extends Component{
|
||||
import p._
|
||||
assert(cpuDataWidth == memDataWidth, "Need testing")
|
||||
val io = new Bundle{
|
||||
val flush = in Bool()
|
||||
val cpu = slave(InstructionCacheCpuBus(p))
|
||||
val cpu = slave(InstructionCacheCpuBus(p, mmuParameter))
|
||||
val mem = master(InstructionCacheMemBus(p))
|
||||
}
|
||||
|
||||
val lineWidth = bytePerLine*8
|
||||
val lineCount = cacheSize/bytePerLine
|
||||
val wordWidth = Math.max(memDataWidth,32)
|
||||
val wordWidthLog2 = log2Up(wordWidth)
|
||||
val wordPerLine = lineWidth/wordWidth
|
||||
val cpuWordWidth = cpuDataWidth
|
||||
val memWordPerLine = lineWidth/memDataWidth
|
||||
val bytePerWord = wordWidth/8
|
||||
val bytePerMemWord = memDataWidth/8
|
||||
val bytePerCpuWord = cpuWordWidth/8
|
||||
val wayLineCount = lineCount/wayCount
|
||||
val wayLineLog2 = log2Up(wayLineCount)
|
||||
val wayWordCount = wayLineCount * wordPerLine
|
||||
|
||||
val tagRange = addressWidth-1 downto log2Up(wayLineCount*bytePerLine)
|
||||
val lineRange = tagRange.low-1 downto log2Up(bytePerLine)
|
||||
val wordRange = log2Up(bytePerLine)-1 downto log2Up(bytePerWord)
|
||||
val memWordRange = log2Up(bytePerLine)-1 downto log2Up(bytePerMemWord)
|
||||
val memWordToCpuWordRange = log2Up(bytePerMemWord)-1 downto log2Up(bytePerWord)
|
||||
val tagLineRange = tagRange.high downto lineRange.low
|
||||
val lineWordRange = lineRange.high downto wordRange.low
|
||||
|
||||
case class LineTag() extends Bundle{
|
||||
val valid = Bool
|
||||
|
@ -310,22 +302,28 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{
|
|||
val address = UInt(tagRange.length bit)
|
||||
}
|
||||
|
||||
val bankCount = wayCount
|
||||
val bankWidth = if(!reducedBankWidth) memDataWidth else Math.max(cpuDataWidth, memDataWidth/wayCount)
|
||||
val bankByteSize = cacheSize/bankCount
|
||||
val bankWordCount = bankByteSize*8/bankWidth
|
||||
val bankWordToCpuWordRange = log2Up(bankWidth/8)-1 downto log2Up(bytePerCpuWord)
|
||||
val memToBankRatio = bankWidth*bankCount / memDataWidth
|
||||
|
||||
val banks = Seq.fill(bankCount)(Mem(Bits(bankWidth bits), bankWordCount))
|
||||
|
||||
val ways = Seq.fill(wayCount)(new Area{
|
||||
val tags = Mem(LineTag(),wayLineCount)
|
||||
val datas = Mem(Bits(memDataWidth bits),wayWordCount)
|
||||
|
||||
if(preResetFlush){
|
||||
tags.initBigInt(List.fill(wayLineCount)(BigInt(0)))
|
||||
}
|
||||
})
|
||||
|
||||
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 address = KeepAttribute(Reg(UInt(addressWidth bits)))
|
||||
val hadError = RegInit(False) clearWhen(fire)
|
||||
val flushPending = RegInit(True)
|
||||
|
||||
|
@ -363,12 +361,12 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{
|
|||
io.mem.cmd.size := log2Up(p.bytePerLine)
|
||||
|
||||
val wayToAllocate = Counter(wayCount, !valid)
|
||||
val wordIndex = Reg(UInt(log2Up(memWordPerLine) bits)) init(0)
|
||||
val wordIndex = KeepAttribute(Reg(UInt(log2Up(memWordPerLine) bits)) init(0))
|
||||
|
||||
|
||||
val write = new Area{
|
||||
val tag = ways.map(_.tags.writePort)
|
||||
val data = ways.map(_.datas.writePort)
|
||||
val data = banks.map(_.writePort)
|
||||
}
|
||||
|
||||
for(wayId <- 0 until wayCount){
|
||||
|
@ -379,13 +377,24 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{
|
|||
tag.data.valid := flushCounter.msb
|
||||
tag.data.error := hadError || io.mem.rsp.error
|
||||
tag.data.address := address(tagRange)
|
||||
|
||||
val data = write.data(wayId)
|
||||
data.valid := io.mem.rsp.valid && wayHit
|
||||
data.address := address(lineRange) @@ wordIndex
|
||||
data.data := io.mem.rsp.data
|
||||
}
|
||||
|
||||
for((writeBank, bankId) <- write.data.zipWithIndex){
|
||||
if(!reducedBankWidth) {
|
||||
writeBank.valid := io.mem.rsp.valid && wayToAllocate === bankId
|
||||
writeBank.address := address(lineRange) @@ wordIndex
|
||||
writeBank.data := io.mem.rsp.data
|
||||
} else {
|
||||
val sel = U(bankId) - wayToAllocate.value
|
||||
val groupSel = wayToAllocate(log2Up(bankCount)-1 downto log2Up(bankCount/memToBankRatio))
|
||||
val subSel = sel(log2Up(bankCount/memToBankRatio) -1 downto 0)
|
||||
writeBank.valid := io.mem.rsp.valid && groupSel === (bankId >> log2Up(bankCount/memToBankRatio))
|
||||
writeBank.address := address(lineRange) @@ wordIndex @@ (subSel)
|
||||
writeBank.data := io.mem.rsp.data.subdivideIn(bankCount/memToBankRatio slices)(subSel)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
when(io.mem.rsp.valid) {
|
||||
wordIndex := (wordIndex + 1).resized
|
||||
hadError.setWhen(io.mem.rsp.error)
|
||||
|
@ -395,45 +404,47 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
val fetchStage = new Area{
|
||||
val read = new Area{
|
||||
val waysValues = for(way <- ways) yield new Area{
|
||||
val banksValue = for(bank <- banks) yield new Area{
|
||||
val dataMem = bank.readSync(io.cpu.prefetch.pc(lineRange.high downto log2Up(bankWidth/8)), !io.cpu.fetch.isStuck)
|
||||
val data = if(!twoCycleRamInnerMux) dataMem.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(bankWordToCpuWordRange)) else dataMem
|
||||
}
|
||||
|
||||
val waysValues = for((way, wayId) <- ways.zipWithIndex) yield new Area{
|
||||
val tag = if(asyncTagMemory) {
|
||||
way.tags.readAsync(io.cpu.fetch.pc(lineRange))
|
||||
}else {
|
||||
way.tags.readSync(io.cpu.prefetch.pc(lineRange), !io.cpu.fetch.isStuck)
|
||||
}
|
||||
val data = way.datas.readSync(io.cpu.prefetch.pc(lineRange.high downto memWordRange.low), !io.cpu.fetch.isStuck)
|
||||
// val data = CombInit(banksValue(wayId).data)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val hit = (!twoCycleRam) generate new Area{
|
||||
val hits = read.waysValues.map(way => way.tag.valid && way.tag.address === io.cpu.fetch.mmuBus.rsp.physicalAddress(tagRange))
|
||||
val hits = read.waysValues.map(way => way.tag.valid && way.tag.address === io.cpu.fetch.mmuRsp.physicalAddress(tagRange))
|
||||
val valid = Cat(hits).orR
|
||||
val id = OHToUInt(hits)
|
||||
val error = read.waysValues.map(_.tag.error).read(id)
|
||||
val data = read.waysValues.map(_.data).read(id)
|
||||
val word = data.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(memWordToCpuWordRange))
|
||||
io.cpu.fetch.data := (io.cpu.fetch.dataBypassValid ? io.cpu.fetch.dataBypass | word)
|
||||
val wayId = OHToUInt(hits)
|
||||
val bankId = if(!reducedBankWidth) wayId else (wayId >> log2Up(bankCount/memToBankRatio)) @@ ((wayId + (io.cpu.fetch.mmuRsp.physicalAddress(log2Up(bankWidth/8), log2Up(bankCount) bits))).resize(log2Up(bankCount/memToBankRatio)))
|
||||
val error = read.waysValues.map(_.tag.error).read(wayId)
|
||||
val data = read.banksValue.map(_.data).read(bankId)
|
||||
val word = if(cpuDataWidth == memDataWidth || !twoCycleRamInnerMux) CombInit(data) else data.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(bankWordToCpuWordRange))
|
||||
io.cpu.fetch.data := (if(p.bypassGen) (io.cpu.fetch.dataBypassValid ? io.cpu.fetch.dataBypass | word) else word)
|
||||
if(twoCycleCache){
|
||||
io.cpu.decode.data := RegNextWhen(io.cpu.fetch.data,!io.cpu.decode.isStuck)
|
||||
}
|
||||
}
|
||||
|
||||
if(twoCycleRam && wayCount == 1){
|
||||
io.cpu.fetch.data := (io.cpu.fetch.dataBypassValid ? io.cpu.fetch.dataBypass | read.waysValues.head.data.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(memWordToCpuWordRange)))
|
||||
val cacheData = if(cpuDataWidth == memDataWidth || !twoCycleRamInnerMux) CombInit(read.banksValue.head.data) else read.banksValue.head.data.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(bankWordToCpuWordRange))
|
||||
io.cpu.fetch.data := (if(p.bypassGen) (io.cpu.fetch.dataBypassValid ? io.cpu.fetch.dataBypass | cacheData) else cacheData)
|
||||
}
|
||||
|
||||
io.cpu.fetch.mmuBus.cmd.isValid := io.cpu.fetch.isValid
|
||||
io.cpu.fetch.mmuBus.cmd.virtualAddress := io.cpu.fetch.pc
|
||||
io.cpu.fetch.mmuBus.cmd.bypassTranslation := False
|
||||
io.cpu.fetch.mmuBus.end := !io.cpu.fetch.isStuck || io.cpu.fetch.isRemoved
|
||||
io.cpu.fetch.physicalAddress := io.cpu.fetch.mmuBus.rsp.physicalAddress
|
||||
io.cpu.fetch.physicalAddress := io.cpu.fetch.mmuRsp.physicalAddress
|
||||
|
||||
val resolution = ifGen(!twoCycleCache)( new Area{
|
||||
val mmuRsp = io.cpu.fetch.mmuBus.rsp
|
||||
val mmuRsp = io.cpu.fetch.mmuRsp
|
||||
|
||||
io.cpu.fetch.cacheMiss := !hit.valid
|
||||
io.cpu.fetch.error := hit.error
|
||||
|
@ -446,7 +457,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{
|
|||
|
||||
val decodeStage = ifGen(twoCycleCache) (new Area{
|
||||
def stage[T <: Data](that : T) = RegNextWhen(that,!io.cpu.decode.isStuck)
|
||||
val mmuRsp = stage(io.cpu.fetch.mmuBus.rsp)
|
||||
val mmuRsp = stage(io.cpu.fetch.mmuRsp)
|
||||
|
||||
val hit = if(!twoCycleRam) new Area{
|
||||
val valid = stage(fetchStage.hit.valid)
|
||||
|
@ -455,11 +466,12 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{
|
|||
val tags = fetchStage.read.waysValues.map(way => stage(way.tag))
|
||||
val hits = tags.map(tag => tag.valid && tag.address === mmuRsp.physicalAddress(tagRange))
|
||||
val valid = Cat(hits).orR
|
||||
val id = OHToUInt(hits)
|
||||
val error = tags(id).error
|
||||
val data = fetchStage.read.waysValues.map(way => stage(way.data)).read(id)
|
||||
val word = data.subdivideIn(cpuDataWidth bits).read(io.cpu.decode.pc(memWordToCpuWordRange))
|
||||
when(stage(io.cpu.fetch.dataBypassValid)){
|
||||
val wayId = OHToUInt(hits)
|
||||
val bankId = if(!reducedBankWidth) wayId else (wayId >> log2Up(bankCount/memToBankRatio)) @@ ((wayId + (mmuRsp.physicalAddress(log2Up(bankWidth/8), log2Up(bankCount) bits))).resize(log2Up(bankCount/memToBankRatio)))
|
||||
val error = tags(wayId).error
|
||||
val data = fetchStage.read.banksValue.map(bank => stage(bank.data)).read(bankId)
|
||||
val word = if(cpuDataWidth == memDataWidth || !twoCycleRamInnerMux) data else data.subdivideIn(cpuDataWidth bits).read(io.cpu.decode.pc(bankWordToCpuWordRange))
|
||||
if(p.bypassGen) when(stage(io.cpu.fetch.dataBypassValid)){
|
||||
word := stage(io.cpu.fetch.dataBypass)
|
||||
}
|
||||
io.cpu.decode.data := word
|
||||
|
|
|
@ -53,7 +53,8 @@ trait PredictionInterface{
|
|||
class BranchPlugin(earlyBranch : Boolean,
|
||||
catchAddressMisaligned : Boolean = false,
|
||||
fenceiGenAsAJump : Boolean = false,
|
||||
fenceiGenAsANop : Boolean = false) extends Plugin[VexRiscv] with PredictionInterface{
|
||||
fenceiGenAsANop : Boolean = false,
|
||||
decodeBranchSrc2 : Boolean = false) extends Plugin[VexRiscv] with PredictionInterface{
|
||||
|
||||
|
||||
def catchAddressMisalignedForReal = catchAddressMisaligned && !pipeline(RVC_GEN)
|
||||
|
@ -138,7 +139,10 @@ class BranchPlugin(earlyBranch : Boolean,
|
|||
}
|
||||
|
||||
val pcManagerService = pipeline.service(classOf[JumpService])
|
||||
jumpInterface = pcManagerService.createJumpInterface(branchStage)
|
||||
|
||||
//Priority -1, as DYNAMIC_TARGET misspredicted on non branch instruction should lose against other instructions
|
||||
//legitim branches, as MRET for instance
|
||||
jumpInterface = pcManagerService.createJumpInterface(branchStage, priority = -10)
|
||||
|
||||
|
||||
if (catchAddressMisalignedForReal) {
|
||||
|
@ -196,7 +200,7 @@ class BranchPlugin(earlyBranch : Boolean,
|
|||
).asUInt
|
||||
|
||||
val branchAdder = branch_src1 + branch_src2
|
||||
insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ "0"
|
||||
insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ U"0"
|
||||
}
|
||||
|
||||
//Apply branchs (JAL,JALR, Bxx)
|
||||
|
@ -273,7 +277,7 @@ class BranchPlugin(earlyBranch : Boolean,
|
|||
}
|
||||
}
|
||||
val branchAdder = branch_src1 + branch_src2
|
||||
insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ "0"
|
||||
insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ U"0"
|
||||
}
|
||||
|
||||
|
||||
|
@ -310,6 +314,8 @@ class BranchPlugin(earlyBranch : Boolean,
|
|||
//Do branch calculations (conditions + target PC)
|
||||
object NEXT_PC extends Stageable(UInt(32 bits))
|
||||
object TARGET_MISSMATCH extends Stageable(Bool)
|
||||
object BRANCH_SRC2 extends Stageable(UInt(32 bits))
|
||||
val branchSrc2Stage = if(decodeBranchSrc2) decode else execute
|
||||
execute plug new Area {
|
||||
import execute._
|
||||
|
||||
|
@ -328,16 +334,17 @@ class BranchPlugin(earlyBranch : Boolean,
|
|||
)
|
||||
)
|
||||
|
||||
val imm = IMM(input(INSTRUCTION))
|
||||
val branch_src1 = (input(BRANCH_CTRL) === BranchCtrlEnum.JALR) ? input(RS1).asUInt | input(PC)
|
||||
val branch_src2 = input(BRANCH_CTRL).mux(
|
||||
|
||||
val imm = IMM(branchSrc2Stage.input(INSTRUCTION))
|
||||
branchSrc2Stage.insert(BRANCH_SRC2) := branchSrc2Stage.input(BRANCH_CTRL).mux(
|
||||
BranchCtrlEnum.JAL -> imm.j_sext,
|
||||
BranchCtrlEnum.JALR -> imm.i_sext,
|
||||
default -> imm.b_sext
|
||||
).asUInt
|
||||
|
||||
val branchAdder = branch_src1 + branch_src2
|
||||
insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ "0"
|
||||
val branchAdder = branch_src1 + input(BRANCH_SRC2)
|
||||
insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ U"0"
|
||||
insert(NEXT_PC) := input(PC) + (if(pipeline(RVC_GEN)) ((input(IS_RVC)) ? U(2) | U(4)) else 4)
|
||||
insert(TARGET_MISSMATCH) := decode.input(PC) =/= input(BRANCH_CALC)
|
||||
}
|
||||
|
|
340
src/main/scala/vexriscv/plugin/CfuPlugin.scala
Normal file
340
src/main/scala/vexriscv/plugin/CfuPlugin.scala
Normal file
|
@ -0,0 +1,340 @@
|
|||
package vexriscv.plugin
|
||||
|
||||
import vexriscv.{DecoderService, ExceptionCause, ExceptionService, Stage, Stageable, VexRiscv}
|
||||
import spinal.core._
|
||||
import spinal.lib._
|
||||
import spinal.lib.bus.bmb.WeakConnector
|
||||
import spinal.lib.bus.misc.{AddressMapping, DefaultMapping}
|
||||
import vexriscv.Riscv.IMM
|
||||
|
||||
case class CfuPluginParameter(
|
||||
CFU_VERSION : Int,
|
||||
CFU_INTERFACE_ID_W : Int,
|
||||
CFU_FUNCTION_ID_W : Int,
|
||||
CFU_REORDER_ID_W : Int,
|
||||
CFU_REQ_RESP_ID_W : Int,
|
||||
CFU_INPUTS : Int,
|
||||
CFU_INPUT_DATA_W : Int,
|
||||
CFU_OUTPUTS : Int,
|
||||
CFU_OUTPUT_DATA_W : Int,
|
||||
CFU_FLOW_REQ_READY_ALWAYS : Boolean,
|
||||
CFU_FLOW_RESP_READY_ALWAYS : Boolean)
|
||||
|
||||
case class CfuBusParameter(CFU_VERSION : Int,
|
||||
CFU_INTERFACE_ID_W : Int,
|
||||
CFU_FUNCTION_ID_W : Int,
|
||||
CFU_REORDER_ID_W : Int,
|
||||
CFU_REQ_RESP_ID_W : Int,
|
||||
CFU_INPUTS : Int,
|
||||
CFU_INPUT_DATA_W : Int,
|
||||
CFU_OUTPUTS : Int,
|
||||
CFU_OUTPUT_DATA_W : Int,
|
||||
CFU_FLOW_REQ_READY_ALWAYS : Boolean,
|
||||
CFU_FLOW_RESP_READY_ALWAYS : Boolean)
|
||||
|
||||
case class CfuCmd( p : CfuBusParameter ) extends Bundle{
|
||||
val function_id = UInt(p.CFU_FUNCTION_ID_W bits)
|
||||
val reorder_id = UInt(p.CFU_REORDER_ID_W bits)
|
||||
val request_id = UInt(p.CFU_REQ_RESP_ID_W bits)
|
||||
val inputs = Vec(Bits(p.CFU_INPUT_DATA_W bits), p.CFU_INPUTS)
|
||||
|
||||
def weakAssignFrom(m : CfuCmd): Unit ={
|
||||
def s = this
|
||||
WeakConnector(m, s, m.function_id, s.function_id, defaultValue = null, allowUpSize = false, allowDownSize = true , allowDrop = true)
|
||||
WeakConnector(m, s, m.reorder_id, s.reorder_id, defaultValue = null, allowUpSize = false , allowDownSize = false, allowDrop = false)
|
||||
WeakConnector(m, s, m.request_id, s.request_id, defaultValue = null, allowUpSize = false, allowDownSize = false, allowDrop = false)
|
||||
s.inputs := m.inputs
|
||||
}
|
||||
}
|
||||
|
||||
case class CfuRsp(p : CfuBusParameter) extends Bundle{
|
||||
val response_ok = Bool()
|
||||
val response_id = UInt(p.CFU_REQ_RESP_ID_W bits)
|
||||
val outputs = Vec(Bits(p.CFU_OUTPUT_DATA_W bits), p.CFU_OUTPUTS)
|
||||
|
||||
def weakAssignFrom(m : CfuRsp): Unit ={
|
||||
def s = this
|
||||
s.response_ok := m.response_ok
|
||||
s.response_id := m.response_id
|
||||
s.outputs := m.outputs
|
||||
}
|
||||
}
|
||||
|
||||
case class CfuBus(p : CfuBusParameter) extends Bundle with IMasterSlave{
|
||||
val cmd = Stream(CfuCmd(p))
|
||||
val rsp = Stream(CfuRsp(p))
|
||||
|
||||
def <<(m : CfuBus) : Unit = {
|
||||
val s = this
|
||||
s.cmd.arbitrationFrom(m.cmd)
|
||||
m.rsp.arbitrationFrom(s.rsp)
|
||||
|
||||
s.cmd.weakAssignFrom(m.cmd)
|
||||
m.rsp.weakAssignFrom(s.rsp)
|
||||
}
|
||||
|
||||
override def asMaster(): Unit = {
|
||||
master(cmd)
|
||||
slave(rsp)
|
||||
}
|
||||
}
|
||||
|
||||
object CfuPlugin{
|
||||
object Input2Kind extends SpinalEnum{
|
||||
val RS, IMM_I = newElement()
|
||||
}
|
||||
}
|
||||
|
||||
case class CfuPluginEncoding(instruction : MaskedLiteral,
|
||||
functionId : List[Range],
|
||||
input2Kind : CfuPlugin.Input2Kind.E)
|
||||
|
||||
class CfuPlugin( val stageCount : Int,
|
||||
val allowZeroLatency : Boolean,
|
||||
val busParameter : CfuBusParameter,
|
||||
val encodings : List[CfuPluginEncoding] = null) extends Plugin[VexRiscv]{
|
||||
def p = busParameter
|
||||
|
||||
assert(p.CFU_INPUTS <= 2)
|
||||
assert(p.CFU_OUTPUTS == 1)
|
||||
// assert(p.CFU_FUNCTION_ID_W == 3)
|
||||
|
||||
var bus : CfuBus = null
|
||||
var joinException : Flow[ExceptionCause] = null
|
||||
|
||||
lazy val forkStage = pipeline.execute
|
||||
lazy val joinStage = pipeline.stages(Math.min(pipeline.stages.length - 1, pipeline.indexOf(forkStage) + stageCount))
|
||||
|
||||
|
||||
val CFU_ENABLE = new Stageable(Bool()).setCompositeName(this, "CFU_ENABLE")
|
||||
val CFU_IN_FLIGHT = new Stageable(Bool()).setCompositeName(this, "CFU_IN_FLIGHT")
|
||||
val CFU_ENCODING = new Stageable(UInt(log2Up(encodings.size) bits)).setCompositeName(this, "CFU_ENCODING")
|
||||
val CFU_INPUT_2_KIND = new Stageable(CfuPlugin.Input2Kind()).setCompositeName(this, "CFU_ENCODING")
|
||||
|
||||
override def setup(pipeline: VexRiscv): Unit = {
|
||||
import pipeline._
|
||||
import pipeline.config._
|
||||
|
||||
bus = master(CfuBus(p))
|
||||
joinException = pipeline.service(classOf[ExceptionService]).newExceptionPort(joinStage)
|
||||
|
||||
val decoderService = pipeline.service(classOf[DecoderService])
|
||||
decoderService.addDefault(CFU_ENABLE, False)
|
||||
|
||||
for((encoding, id) <- encodings.zipWithIndex){
|
||||
var actions = List(
|
||||
CFU_ENABLE -> True,
|
||||
REGFILE_WRITE_VALID -> True,
|
||||
BYPASSABLE_EXECUTE_STAGE -> Bool(stageCount == 0),
|
||||
BYPASSABLE_MEMORY_STAGE -> Bool(stageCount <= 1),
|
||||
RS1_USE -> True,
|
||||
CFU_ENCODING -> U(id),
|
||||
CFU_INPUT_2_KIND -> encoding.input2Kind()
|
||||
)
|
||||
|
||||
encoding.input2Kind match {
|
||||
case CfuPlugin.Input2Kind.RS =>
|
||||
actions :+= RS2_USE -> True
|
||||
case CfuPlugin.Input2Kind.IMM_I =>
|
||||
}
|
||||
|
||||
decoderService.add(
|
||||
key = encoding.instruction,
|
||||
values = actions
|
||||
)
|
||||
}
|
||||
|
||||
// decoderService.add(List(
|
||||
// //custom-0
|
||||
// M"-------------------------0001011" -> List(
|
||||
// CFU_ENABLE -> True,
|
||||
// REGFILE_WRITE_VALID -> True,
|
||||
// BYPASSABLE_EXECUTE_STAGE -> Bool(stageCount == 0),
|
||||
// BYPASSABLE_MEMORY_STAGE -> Bool(stageCount <= 1),
|
||||
// RS1_USE -> True,
|
||||
// RS2_USE -> True,
|
||||
// CFU_IMM -> False
|
||||
// ),
|
||||
//
|
||||
// //custom-1
|
||||
// M"-------------------------0101011" -> List(
|
||||
// CFU_ENABLE -> True,
|
||||
// REGFILE_WRITE_VALID -> True,
|
||||
// BYPASSABLE_EXECUTE_STAGE -> Bool(stageCount == 0),
|
||||
// BYPASSABLE_MEMORY_STAGE -> Bool(stageCount <= 1),
|
||||
// RS1_USE -> True,
|
||||
// CFU_IMM -> True
|
||||
// )
|
||||
// ))
|
||||
|
||||
|
||||
}
|
||||
|
||||
override def build(pipeline: VexRiscv): Unit = {
|
||||
import pipeline._
|
||||
import pipeline.config._
|
||||
|
||||
|
||||
forkStage plug new Area{
|
||||
import forkStage._
|
||||
val schedule = arbitration.isValid && input(CFU_ENABLE)
|
||||
val hold = RegInit(False) setWhen(schedule) clearWhen(bus.cmd.ready)
|
||||
val fired = RegInit(False) setWhen(bus.cmd.fire) clearWhen(!arbitration.isStuckByOthers)
|
||||
insert(CFU_IN_FLIGHT) := schedule || hold || fired
|
||||
|
||||
bus.cmd.valid := (schedule || hold) && !fired
|
||||
arbitration.haltItself setWhen(bus.cmd.valid && !bus.cmd.ready)
|
||||
|
||||
// bus.cmd.function_id := U(input(INSTRUCTION)(14 downto 12)).resized
|
||||
val functionsIds = encodings.map(e => U(Cat(e.functionId.map(r => input(INSTRUCTION)(r))), busParameter.CFU_FUNCTION_ID_W bits))
|
||||
bus.cmd.function_id := functionsIds.read(input(CFU_ENCODING))
|
||||
bus.cmd.reorder_id := 0
|
||||
bus.cmd.request_id := 0
|
||||
if(p.CFU_INPUTS >= 1) bus.cmd.inputs(0) := input(RS1)
|
||||
if(p.CFU_INPUTS >= 2) bus.cmd.inputs(1) := input(CFU_INPUT_2_KIND).mux(
|
||||
CfuPlugin.Input2Kind.RS -> input(RS2),
|
||||
CfuPlugin.Input2Kind.IMM_I -> IMM(input(INSTRUCTION)).i_sext
|
||||
)
|
||||
}
|
||||
|
||||
joinStage plug new Area{
|
||||
import joinStage._
|
||||
|
||||
//If the CFU interface can produce a result combinatorialy and the fork stage isn't the same than the join stage
|
||||
//Then it is required to add a buffer on rsp to not propagate the fork stage ready := False in the CPU pipeline.
|
||||
val rsp = if(p.CFU_FLOW_RESP_READY_ALWAYS){
|
||||
bus.rsp.toFlow.toStream.queueLowLatency(
|
||||
size = stageCount + 1,
|
||||
latency = 0
|
||||
)
|
||||
} else if(forkStage != joinStage && allowZeroLatency) {
|
||||
bus.rsp.m2sPipe()
|
||||
} else {
|
||||
bus.rsp.combStage()
|
||||
}
|
||||
|
||||
joinException.valid := False
|
||||
joinException.code := 15
|
||||
joinException.badAddr := 0
|
||||
|
||||
rsp.ready := False
|
||||
when(input(CFU_IN_FLIGHT)){
|
||||
arbitration.haltItself setWhen(!rsp.valid)
|
||||
rsp.ready := !arbitration.isStuckByOthers
|
||||
output(REGFILE_WRITE_DATA) := rsp.outputs(0)
|
||||
|
||||
when(arbitration.isValid){
|
||||
joinException.valid := !rsp.response_ok
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addPrePopTask(() => stages.dropWhile(_ != memory).reverse.dropWhile(_ != joinStage).foreach(s => s.input(CFU_IN_FLIGHT).init(False)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
object CfuTest{
|
||||
|
||||
// stageCount = 0,
|
||||
// allowZeroLatency = true,
|
||||
def getCfuParameter() = CfuBusParameter(
|
||||
CFU_VERSION = 0,
|
||||
CFU_INTERFACE_ID_W = 0,
|
||||
CFU_FUNCTION_ID_W = 3,
|
||||
CFU_REORDER_ID_W = 0,
|
||||
CFU_REQ_RESP_ID_W = 0,
|
||||
CFU_INPUTS = 2,
|
||||
CFU_INPUT_DATA_W = 32,
|
||||
CFU_OUTPUTS = 1,
|
||||
CFU_OUTPUT_DATA_W = 32,
|
||||
CFU_FLOW_REQ_READY_ALWAYS = false,
|
||||
CFU_FLOW_RESP_READY_ALWAYS = false
|
||||
)
|
||||
}
|
||||
case class CfuTest() extends Component{
|
||||
val io = new Bundle {
|
||||
val bus = slave(CfuBus(CfuTest.getCfuParameter()))
|
||||
}
|
||||
io.bus.rsp.arbitrationFrom(io.bus.cmd)
|
||||
io.bus.rsp.response_ok := True
|
||||
io.bus.rsp.response_id := io.bus.cmd.request_id
|
||||
io.bus.rsp.outputs(0) := ~(io.bus.cmd.inputs(0) & io.bus.cmd.inputs(1))
|
||||
}
|
||||
|
||||
|
||||
case class CfuBb(p : CfuBusParameter) extends BlackBox{
|
||||
val io = new Bundle {
|
||||
val clk, reset = in Bool()
|
||||
val bus = slave(CfuBus(p))
|
||||
}
|
||||
|
||||
mapCurrentClockDomain(io.clk, io.reset)
|
||||
}
|
||||
|
||||
//case class CfuGray(p : CfuBusParameter) extends BlackBox{
|
||||
// val req_function_id = in Bits(p.CFU_FUNCTION_ID_W)
|
||||
// val req_data = in Bits(p.CFU_REQ_INPUTS)
|
||||
// val resp_data = in Bits(p.CFU_FUNCTION_ID_W)
|
||||
// input `CFU_FUNCTION_ID req_function_id,
|
||||
// input [CFU_REQ_INPUTS-1:0]`CFU_REQ_DATA req_data,
|
||||
// output [CFU_RESP_OUTPUTS-1:0]`CFU_RESP_DATA resp_data
|
||||
// io.bus.rsp.arbitrationFrom(io.bus.cmd)
|
||||
// io.bus.rsp.response_ok := True
|
||||
// io.bus.rsp.response_id := io.bus.cmd.request_id
|
||||
// io.bus.rsp.outputs(0) := ~(io.bus.cmd.inputs(0) & io.bus.cmd.inputs(1))
|
||||
//}
|
||||
|
||||
|
||||
case class CfuDecoder(p : CfuBusParameter,
|
||||
mappings : Seq[AddressMapping],
|
||||
pendingMax : Int = 3) extends Component{
|
||||
val io = new Bundle {
|
||||
val input = slave(CfuBus(p))
|
||||
val outputs = Vec(master(CfuBus(p)), mappings.size)
|
||||
}
|
||||
val hasDefault = mappings.contains(DefaultMapping)
|
||||
val logic = if(hasDefault && mappings.size == 1){
|
||||
io.outputs(0) << io.input
|
||||
} else new Area {
|
||||
val hits = Vec(Bool, mappings.size)
|
||||
for (portId <- 0 until mappings.length) yield {
|
||||
val slaveBus = io.outputs(portId)
|
||||
val memorySpace = mappings(portId)
|
||||
val hit = hits(portId)
|
||||
hit := (memorySpace match {
|
||||
case DefaultMapping => !hits.filterNot(_ == hit).orR
|
||||
case _ => memorySpace.hit(io.input.cmd.function_id)
|
||||
})
|
||||
slaveBus.cmd.valid := io.input.cmd.valid && hit
|
||||
slaveBus.cmd.payload := io.input.cmd.payload.resized
|
||||
}
|
||||
val noHit = if (!hasDefault) !hits.orR else False
|
||||
io.input.cmd.ready := (hits, io.outputs).zipped.map(_ && _.cmd.ready).orR || noHit
|
||||
|
||||
val rspPendingCounter = Reg(UInt(log2Up(pendingMax + 1) bits)) init(0)
|
||||
rspPendingCounter := rspPendingCounter + U(io.input.cmd.fire) - U(io.input.rsp.fire)
|
||||
val rspHits = RegNextWhen(hits, io.input.cmd.fire)
|
||||
val rspPending = rspPendingCounter =/= 0
|
||||
val rspNoHitValid = if (!hasDefault) !rspHits.orR else False
|
||||
val rspNoHit = !hasDefault generate new Area{
|
||||
val doIt = RegInit(False) clearWhen(io.input.rsp.fire) setWhen(io.input.cmd.fire && noHit)
|
||||
val response_id = RegNextWhen(io.input.cmd.request_id, io.input.cmd.fire)
|
||||
}
|
||||
|
||||
io.input.rsp.valid := io.outputs.map(_.rsp.valid).orR || (rspPending && rspNoHitValid)
|
||||
io.input.rsp.payload := io.outputs.map(_.rsp.payload).read(OHToUInt(rspHits))
|
||||
if(!hasDefault) when(rspNoHit.doIt) {
|
||||
io.input.rsp.valid := True
|
||||
io.input.rsp.response_ok := False
|
||||
io.input.rsp.response_id := rspNoHit.response_id
|
||||
}
|
||||
for(output <- io.outputs) output.rsp.ready := io.input.rsp.ready
|
||||
|
||||
val cmdWait = (rspPending && (hits =/= rspHits || rspNoHitValid)) || rspPendingCounter === pendingMax
|
||||
when(cmdWait) {
|
||||
io.input.cmd.ready := False
|
||||
io.outputs.foreach(_.cmd.valid := False)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ import vexriscv.plugin.IntAluPlugin.{ALU_BITWISE_CTRL, ALU_CTRL, AluBitwiseCtrlE
|
|||
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
import scala.collection.mutable
|
||||
import spinal.core.sim._
|
||||
|
||||
/**
|
||||
* Created by spinalvm on 21.03.17.
|
||||
|
@ -38,7 +39,7 @@ case class CsrPluginConfig(
|
|||
marchid : BigInt,
|
||||
mimpid : BigInt,
|
||||
mhartid : BigInt,
|
||||
misaExtensionsInit : Int,
|
||||
misaExtensionsInit : Int,
|
||||
misaAccess : CsrAccess,
|
||||
mtvecAccess : CsrAccess,
|
||||
mtvecInit : BigInt,
|
||||
|
@ -65,11 +66,16 @@ case class CsrPluginConfig(
|
|||
scycleAccess : CsrAccess = CsrAccess.NONE,
|
||||
sinstretAccess : CsrAccess = CsrAccess.NONE,
|
||||
satpAccess : CsrAccess = CsrAccess.NONE,
|
||||
utimeAccess :CsrAccess = CsrAccess.NONE,
|
||||
medelegAccess : CsrAccess = CsrAccess.NONE,
|
||||
midelegAccess : CsrAccess = CsrAccess.NONE,
|
||||
withExternalMhartid : Boolean = false,
|
||||
mhartidWidth : Int = 0,
|
||||
pipelineCsrRead : Boolean = false,
|
||||
pipelinedInterrupt : Boolean = true,
|
||||
deterministicInteruptionEntry : Boolean = false //Only used for simulatation purposes
|
||||
csrOhDecoder : Boolean = true,
|
||||
deterministicInteruptionEntry : Boolean = false, //Only used for simulatation purposes
|
||||
wfiOutput : Boolean = false
|
||||
){
|
||||
assert(!ucycleAccess.canWrite)
|
||||
def privilegeGen = userGen || supervisorGen
|
||||
|
@ -81,6 +87,46 @@ object CsrPluginConfig{
|
|||
def all : CsrPluginConfig = all(0x00000020l)
|
||||
def small : CsrPluginConfig = small(0x00000020l)
|
||||
def smallest : CsrPluginConfig = smallest(0x00000020l)
|
||||
|
||||
def openSbi(mhartid : Int, misa : Int) = CsrPluginConfig(
|
||||
catchIllegalAccess = true,
|
||||
mvendorid = 0,
|
||||
marchid = 0,
|
||||
mimpid = 0,
|
||||
mhartid = mhartid,
|
||||
misaExtensionsInit = misa,
|
||||
misaAccess = CsrAccess.READ_ONLY,
|
||||
mtvecAccess = CsrAccess.READ_WRITE, //Could have been WRITE_ONLY :(
|
||||
mtvecInit = null,
|
||||
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 = false, //TODO
|
||||
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,
|
||||
medelegAccess = CsrAccess.READ_WRITE, //Could have been WRITE_ONLY :(
|
||||
midelegAccess = CsrAccess.READ_WRITE, //Could have been WRITE_ONLY :(
|
||||
pipelineCsrRead = false,
|
||||
deterministicInteruptionEntry = false
|
||||
)
|
||||
|
||||
def linuxMinimal(mtVecInit : BigInt) = CsrPluginConfig(
|
||||
catchIllegalAccess = true,
|
||||
mvendorid = 1,
|
||||
|
@ -260,14 +306,16 @@ 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 CsrDuringWrite(doThat :() => Unit)
|
||||
case class CsrOnRead(doThat : () => Unit)
|
||||
case class CsrMapping() extends CsrInterface{
|
||||
val mapping = mutable.HashMap[Int,ArrayBuffer[Any]]()
|
||||
val mapping = mutable.LinkedHashMap[Int,ArrayBuffer[Any]]()
|
||||
def addMappingAt(address : Int,that : Any) = mapping.getOrElseUpdate(address,new ArrayBuffer[Any]) += that
|
||||
override def r(csrAddress : Int, bitOffset : Int, that : Data): Unit = addMappingAt(csrAddress, CsrRead(that,bitOffset))
|
||||
override def w(csrAddress : Int, bitOffset : Int, that : Data): Unit = addMappingAt(csrAddress, CsrWrite(that,bitOffset))
|
||||
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 duringWrite(csrAddress: Int)(body: => Unit): Unit = addMappingAt(csrAddress, CsrDuringWrite(() => body))
|
||||
override def onRead(csrAddress: Int)(body: => Unit): Unit = addMappingAt(csrAddress, CsrOnRead(() => {body}))
|
||||
}
|
||||
|
||||
|
@ -275,6 +323,7 @@ case class CsrMapping() extends CsrInterface{
|
|||
trait CsrInterface{
|
||||
def onWrite(csrAddress : Int)(doThat : => Unit) : Unit
|
||||
def onRead(csrAddress : Int)(doThat : => Unit) : Unit
|
||||
def duringWrite(csrAddress: Int)(body: => Unit): Unit
|
||||
def r(csrAddress : Int, bitOffset : Int, that : Data): Unit
|
||||
def w(csrAddress : Int, bitOffset : Int, that : Data): Unit
|
||||
def rw(csrAddress : Int, bitOffset : Int,that : Data): Unit ={
|
||||
|
@ -311,8 +360,11 @@ trait CsrInterface{
|
|||
trait IContextSwitching{
|
||||
def isContextSwitching : Bool
|
||||
}
|
||||
trait IWake{
|
||||
def askWake() : Unit
|
||||
}
|
||||
|
||||
class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with ExceptionService with PrivilegeService with InterruptionInhibitor with ExceptionInhibitor with IContextSwitching with CsrInterface{
|
||||
class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with ExceptionService with PrivilegeService with InterruptionInhibitor with ExceptionInhibitor with IContextSwitching with CsrInterface with IWake{
|
||||
import config._
|
||||
import CsrAccess._
|
||||
|
||||
|
@ -322,7 +374,6 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
|
|||
|
||||
//Mannage ExceptionService calls
|
||||
val exceptionPortsInfos = ArrayBuffer[ExceptionPortInfo]()
|
||||
def exceptionCodeWidth = 4
|
||||
override def newExceptionPort(stage : Stage, priority : Int = 0) = {
|
||||
val interface = Flow(ExceptionCause())
|
||||
exceptionPortsInfos += ExceptionPortInfo(interface,stage,priority)
|
||||
|
@ -332,6 +383,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
|
|||
var exceptionPendings : Vec[Bool] = null
|
||||
override def isExceptionPending(stage : Stage): Bool = exceptionPendings(pipeline.stages.indexOf(stage))
|
||||
|
||||
var redoInterface : Flow[UInt] = null
|
||||
var jumpInterface : Flow[UInt] = null
|
||||
var timerInterrupt, externalInterrupt, softwareInterrupt : Bool = null
|
||||
var externalInterruptS : Bool = null
|
||||
|
@ -339,6 +391,13 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
|
|||
var privilege : UInt = null
|
||||
var selfException : Flow[ExceptionCause] = null
|
||||
var contextSwitching : Bool = null
|
||||
var thirdPartyWake : Bool = null
|
||||
var inWfi : Bool = null
|
||||
var externalMhartId : UInt = null
|
||||
var utime : UInt = null
|
||||
|
||||
override def askWake(): Unit = thirdPartyWake := True
|
||||
|
||||
override def isContextSwitching = contextSwitching
|
||||
|
||||
object EnvCtrlEnum extends SpinalEnum(binarySequential){
|
||||
|
@ -359,6 +418,17 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
|
|||
|
||||
val csrMapping = new CsrMapping()
|
||||
|
||||
//Print CSR mapping
|
||||
def printCsr() {
|
||||
for ((address, things) <- csrMapping.mapping) {
|
||||
println("0x" + address.toHexString + " => ")
|
||||
for (thing <- things) {
|
||||
println(" - " + thing)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//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])
|
||||
|
@ -374,11 +444,16 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
|
|||
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 duringWrite(csrAddress: Int)(body: => Unit): Unit = csrMapping.duringWrite(csrAddress)(body)
|
||||
override def onRead(csrAddress: Int)(body: => Unit): Unit = csrMapping.onRead(csrAddress)(body)
|
||||
|
||||
override def setup(pipeline: VexRiscv): Unit = {
|
||||
import pipeline.config._
|
||||
|
||||
inWfi = False.addTag(Verilator.public)
|
||||
|
||||
thirdPartyWake = False
|
||||
|
||||
val defaultEnv = List[(Stageable[_ <: BaseType],Any)](
|
||||
)
|
||||
|
||||
|
@ -422,6 +497,11 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
|
|||
jumpInterface.valid := False
|
||||
jumpInterface.payload.assignDontCare()
|
||||
|
||||
|
||||
if(supervisorGen) {
|
||||
redoInterface = pcManagerService.createJumpInterface(pipeline.execute, -1)
|
||||
}
|
||||
|
||||
exceptionPendings = Vec(Bool, pipeline.stages.length)
|
||||
timerInterrupt = in Bool() setName("timerInterrupt")
|
||||
externalInterrupt = in Bool() setName("externalInterrupt")
|
||||
|
@ -445,6 +525,9 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
|
|||
|
||||
|
||||
pipeline.update(MPP, UInt(2 bits))
|
||||
|
||||
if(withExternalMhartid) externalMhartId = in UInt(mhartidWidth bits)
|
||||
if(utimeAccess != CsrAccess.NONE) utime = in UInt(64 bits) setName("utime")
|
||||
}
|
||||
|
||||
def inhibateInterrupts() : Unit = allowInterrupts := False
|
||||
|
@ -459,6 +542,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
|
|||
import pipeline._
|
||||
import pipeline.config._
|
||||
val fetcher = service(classOf[IBusFetcher])
|
||||
val trapCodeWidth = log2Up((List(16) ++ interruptSpecs.map(_.id + 1) ++ exceptionPortsInfos.map(p => 1 << widthOf(p.port.code))).max)
|
||||
|
||||
//Define CSR mapping utilities
|
||||
implicit class CsrAccessPimper(csrAccess : CsrAccess){
|
||||
|
@ -511,7 +595,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
|
|||
val mscratch = if(mscratchGen) Reg(Bits(xlen bits)) else null
|
||||
val mcause = new Area{
|
||||
val interrupt = Reg(Bool)
|
||||
val exceptionCode = Reg(UInt(exceptionCodeWidth bits))
|
||||
val exceptionCode = Reg(UInt(trapCodeWidth bits))
|
||||
}
|
||||
val mtval = Reg(UInt(xlen bits))
|
||||
val mcycle = Reg(UInt(64 bits)) randBoot()
|
||||
|
@ -520,7 +604,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
|
|||
|
||||
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 mapping = mutable.LinkedHashMap(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)
|
||||
|
@ -529,7 +613,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
|
|||
if(mvendorid != null) READ_ONLY(CSR.MVENDORID, U(mvendorid))
|
||||
if(marchid != null) READ_ONLY(CSR.MARCHID , U(marchid ))
|
||||
if(mimpid != null) READ_ONLY(CSR.MIMPID , U(mimpid ))
|
||||
if(mhartid != null) READ_ONLY(CSR.MHARTID , U(mhartid ))
|
||||
if(mhartid != null && !withExternalMhartid) READ_ONLY(CSR.MHARTID , U(mhartid ))
|
||||
if(withExternalMhartid) READ_ONLY(CSR.MHARTID , externalMhartId)
|
||||
misaAccess(CSR.MISA, xlen-2 -> misa.base , 0 -> misa.extensions)
|
||||
|
||||
//Machine CSR
|
||||
|
@ -557,6 +642,11 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
|
|||
ucycleAccess(CSR.UCYCLE, mcycle(31 downto 0))
|
||||
ucycleAccess(CSR.UCYCLEH, mcycle(63 downto 32))
|
||||
|
||||
if(utimeAccess != CsrAccess.NONE) {
|
||||
utimeAccess(CSR.UTIME, utime(31 downto 0))
|
||||
utimeAccess(CSR.UTIMEH, utime(63 downto 32))
|
||||
}
|
||||
|
||||
pipeline(MPP) := mstatus.MPP
|
||||
}
|
||||
|
||||
|
@ -582,7 +672,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
|
|||
|
||||
val scause = new Area {
|
||||
val interrupt = Reg(Bool)
|
||||
val exceptionCode = Reg(UInt(exceptionCodeWidth bits))
|
||||
val exceptionCode = Reg(UInt(trapCodeWidth bits))
|
||||
}
|
||||
val stval = Reg(UInt(xlen bits))
|
||||
val sepc = Reg(UInt(xlen bits))
|
||||
|
@ -610,6 +700,16 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
|
|||
scauseAccess(CSR.SCAUSE, xlen-1 -> scause.interrupt, 0 -> scause.exceptionCode)
|
||||
sbadaddrAccess(CSR.SBADADDR, stval)
|
||||
satpAccess(CSR.SATP, 31 -> satp.MODE, 22 -> satp.ASID, 0 -> satp.PPN)
|
||||
|
||||
|
||||
if(supervisorGen) {
|
||||
redoInterface.valid := False
|
||||
redoInterface.payload := decode.input(PC)
|
||||
duringWrite(CSR.SATP){
|
||||
execute.arbitration.flushNext := True
|
||||
redoInterface.valid := True
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -647,7 +747,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
|
|||
|
||||
|
||||
//Aggregate all exception port and remove required instructions
|
||||
val exceptionPortCtrl = if(exceptionPortsInfos.nonEmpty) new Area{
|
||||
val exceptionPortCtrl = exceptionPortsInfos.nonEmpty generate new Area{
|
||||
val firstStageIndexWithExceptionPort = exceptionPortsInfos.map(i => indexOf(i.stage)).min
|
||||
val exceptionValids = Vec(stages.map(s => Bool().setPartialName(s.getName())))
|
||||
val exceptionValidsRegs = Vec(stages.map(s => Reg(Bool).init(False).setPartialName(s.getName()))).allowUnsetRegToAvoidLatch
|
||||
|
@ -724,7 +824,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
|
|||
//Avoid the PC register of the last stage to change durring an exception handleing (Used to fill Xepc)
|
||||
stages.last.dontSample.getOrElseUpdate(PC, ArrayBuffer[Bool]()) += exceptionValids.last
|
||||
exceptionPendings := exceptionValidsRegs
|
||||
} else null
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -733,12 +833,12 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
|
|||
//Process interrupt request, code and privilege
|
||||
val interrupt = new Area {
|
||||
val valid = if(pipelinedInterrupt) RegNext(False) init(False) else False
|
||||
val code = if(pipelinedInterrupt) Reg(UInt(4 bits)) else UInt(4 bits).assignDontCare()
|
||||
val code = if(pipelinedInterrupt) Reg(UInt(trapCodeWidth bits)) else UInt(trapCodeWidth bits).assignDontCare()
|
||||
var privilegs = if (supervisorGen) List(1, 3) else List(3)
|
||||
val targetPrivilege = if(pipelinedInterrupt) Reg(UInt(2 bits)) else UInt(2 bits).assignDontCare()
|
||||
val privilegeAllowInterrupts = mutable.HashMap[Int, Bool]()
|
||||
if (supervisorGen) privilegeAllowInterrupts += 1 -> ((sstatus.SIE && privilege === "01") || privilege < "01")
|
||||
privilegeAllowInterrupts += 3 -> (mstatus.MIE || privilege < "11")
|
||||
val privilegeAllowInterrupts = mutable.LinkedHashMap[Int, Bool]()
|
||||
if (supervisorGen) privilegeAllowInterrupts += 1 -> ((sstatus.SIE && privilege === U"01") || privilege < U"01")
|
||||
privilegeAllowInterrupts += 3 -> (mstatus.MIE || privilege < U"11")
|
||||
while (privilegs.nonEmpty) {
|
||||
val p = privilegs.head
|
||||
when(privilegeAllowInterrupts(p)) {
|
||||
|
@ -770,19 +870,31 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
|
|||
|
||||
//Used to make the pipeline empty softly (for interrupts)
|
||||
val pipelineLiberator = new Area{
|
||||
when(interrupt.valid && allowInterrupts){
|
||||
decode.arbitration.haltByOther := decode.arbitration.isValid
|
||||
val pcValids = Vec(RegInit(False), stagesFromExecute.length)
|
||||
val active = interrupt.valid && allowInterrupts && decode.arbitration.isValid
|
||||
when(active){
|
||||
decode.arbitration.haltByOther := True
|
||||
for((stage, reg, previous) <- (stagesFromExecute, pcValids, True :: pcValids.toList).zipped){
|
||||
when(!stage.arbitration.isStuck){
|
||||
reg := previous
|
||||
}
|
||||
}
|
||||
}
|
||||
when(!active || decode.arbitration.isRemoved) {
|
||||
pcValids.foreach(_ := False)
|
||||
}
|
||||
|
||||
val done = !stagesFromExecute.map(_.arbitration.isValid).orR && fetcher.pcValid(mepcCaptureStage)
|
||||
// val pcValids = for(stage <- stagesFromExecute) yield RegInit(False) clearWhen(!started) setWhen(!stage.arbitration.isValid)
|
||||
val done = CombInit(pcValids.last)
|
||||
if(exceptionPortCtrl != null) done.clearWhen(exceptionPortCtrl.exceptionValidsRegs.tail.orR)
|
||||
}
|
||||
|
||||
//Interrupt/Exception entry logic
|
||||
val interruptJump = Bool.addTag(Verilator.public)
|
||||
interruptJump := interrupt.valid && pipelineLiberator.done && allowInterrupts
|
||||
if(pipelinedInterrupt) interrupt.valid clearWhen(interruptJump) //avoid double fireing
|
||||
|
||||
val hadException = RegNext(exception) init(False)
|
||||
val hadException = RegNext(exception) init(False) addTag(Verilator.public)
|
||||
pipelineLiberator.done.clearWhen(hadException)
|
||||
|
||||
|
||||
|
@ -806,7 +918,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
|
|||
fetcher.haltIt() //Avoid having the fetch confused by the incomming privilege switch
|
||||
|
||||
jumpInterface.valid := True
|
||||
jumpInterface.payload := (if(!xtvecModeGen) xtvec.base @@ "00" else (xtvec.mode === 0 || hadException) ? (xtvec.base @@ "00") | ((xtvec.base + trapCause) @@ "00") )
|
||||
jumpInterface.payload := (if(!xtvecModeGen) xtvec.base @@ U"00" else (xtvec.mode === 0 || hadException) ? (xtvec.base @@ U"00") | ((xtvec.base + trapCause) @@ U"00") )
|
||||
lastStage.arbitration.flushNext := True
|
||||
|
||||
if(privilegeGen) privilegeReg := targetPrivilege
|
||||
|
@ -838,6 +950,10 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
|
|||
}
|
||||
}
|
||||
|
||||
if(exceptionPortCtrl == null){
|
||||
if(mbadaddrAccess == CsrAccess.READ_ONLY) mtval := 0
|
||||
if(sbadaddrAccess == CsrAccess.READ_ONLY) stval := 0
|
||||
}
|
||||
|
||||
lastStage plug new Area{
|
||||
import lastStage._
|
||||
|
@ -875,8 +991,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
|
|||
|
||||
val imm = IMM(input(INSTRUCTION))
|
||||
insert(CSR_WRITE_OPCODE) := ! (
|
||||
(input(INSTRUCTION)(14 downto 13) === "01" && input(INSTRUCTION)(rs1Range) === 0)
|
||||
|| (input(INSTRUCTION)(14 downto 13) === "11" && imm.z === 0)
|
||||
(input(INSTRUCTION)(14 downto 13) === B"01" && input(INSTRUCTION)(rs1Range) === 0)
|
||||
|| (input(INSTRUCTION)(14 downto 13) === B"11" && imm.z === 0)
|
||||
)
|
||||
insert(CSR_READ_OPCODE) := input(INSTRUCTION)(13 downto 7) =/= B"0100000"
|
||||
}
|
||||
|
@ -885,8 +1001,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
|
|||
execute plug new Area{
|
||||
import execute._
|
||||
//Manage WFI instructions
|
||||
val inWfi = False.addTag(Verilator.public)
|
||||
val wfiWake = RegNext(interruptSpecs.map(_.cond).orR) init(False)
|
||||
if(wfiOutput) out(inWfi)
|
||||
val wfiWake = RegNext(interruptSpecs.map(_.cond).orR || thirdPartyWake) init(False)
|
||||
if(wfiGenAsWait) when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.WFI){
|
||||
inWfi := True
|
||||
when(!wfiWake){
|
||||
|
@ -900,7 +1016,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
|
|||
execute plug new Area {
|
||||
import execute._
|
||||
def previousStage = decode
|
||||
val blockedBySideEffects = stagesFromExecute.tail.map(s => s.arbitration.isValid).asBits().orR // && s.input(HAS_SIDE_EFFECT) to improve be less pessimistic
|
||||
val blockedBySideEffects = stagesFromExecute.tail.map(s => s.arbitration.isValid).asBits().orR || pipeline.service(classOf[HazardService]).hazardOnExecuteRS// && s.input(HAS_SIDE_EFFECT) to improve be less pessimistic
|
||||
|
||||
val illegalAccess = True
|
||||
val illegalInstruction = False
|
||||
|
@ -941,22 +1057,11 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
|
|||
|
||||
val imm = IMM(input(INSTRUCTION))
|
||||
def writeSrc = input(SRC1)
|
||||
// val readDataValid = True
|
||||
val readData = B(0, 32 bits)
|
||||
val readData = Bits(32 bits)
|
||||
val writeInstruction = arbitration.isValid && input(IS_CSR) && input(CSR_WRITE_OPCODE)
|
||||
val readInstruction = arbitration.isValid && input(IS_CSR) && input(CSR_READ_OPCODE)
|
||||
val writeEnable = writeInstruction && ! blockedBySideEffects && !arbitration.isStuckByOthers// && readDataRegValid
|
||||
val readEnable = readInstruction && ! blockedBySideEffects && !arbitration.isStuckByOthers// && !readDataRegValid
|
||||
//arbitration.isStuckByOthers, in case of the hazardPlugin is in the executeStage
|
||||
|
||||
|
||||
// def readDataReg = memory.input(REGFILE_WRITE_DATA) //PIPE OPT
|
||||
// val readDataRegValid = Reg(Bool) setWhen(arbitration.isValid) clearWhen(!arbitration.isStuck)
|
||||
// val writeDataEnable = input(INSTRUCTION)(13) ? writeSrc | B"xFFFFFFFF"
|
||||
// val writeData = if(noCsrAlu) writeSrc else input(INSTRUCTION)(13).mux(
|
||||
// False -> writeSrc,
|
||||
// True -> Mux(input(INSTRUCTION)(12), ~writeSrc, writeSrc)
|
||||
// )
|
||||
val writeEnable = writeInstruction && ! blockedBySideEffects && !arbitration.isStuckByOthers
|
||||
val readEnable = readInstruction && ! blockedBySideEffects && !arbitration.isStuckByOthers
|
||||
|
||||
val readToWriteData = CombInit(readData)
|
||||
val writeData = if(noCsrAlu) writeSrc else input(INSTRUCTION)(13).mux(
|
||||
|
@ -964,11 +1069,6 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
|
|||
True -> Mux(input(INSTRUCTION)(12), readToWriteData & ~writeSrc, readToWriteData | writeSrc)
|
||||
)
|
||||
|
||||
|
||||
|
||||
// arbitration.haltItself setWhen(writeInstruction && !readDataRegValid)
|
||||
|
||||
|
||||
when(arbitration.isValid && input(IS_CSR)) {
|
||||
if(!pipelineCsrRead) output(REGFILE_WRITE_DATA) := readData
|
||||
arbitration.haltItself setWhen(blockedBySideEffects)
|
||||
|
@ -988,50 +1088,88 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
|
|||
|
||||
//Translation of the csrMapping into real logic
|
||||
val csrAddress = input(INSTRUCTION)(csrRange)
|
||||
Component.current.addPrePopTask(() => {
|
||||
switch(csrAddress) {
|
||||
for ((address, jobs) <- csrMapping.mapping) {
|
||||
is(address) {
|
||||
val withWrite = jobs.exists(j => j.isInstanceOf[CsrWrite] || j.isInstanceOf[CsrOnWrite])
|
||||
val withRead = jobs.exists(j => j.isInstanceOf[CsrRead] || j.isInstanceOf[CsrOnRead])
|
||||
if(withRead && withWrite) {
|
||||
illegalAccess := False
|
||||
} else {
|
||||
if (withWrite) illegalAccess.clearWhen(input(CSR_WRITE_OPCODE))
|
||||
if (withRead) illegalAccess.clearWhen(input(CSR_READ_OPCODE))
|
||||
}
|
||||
Component.current.afterElaboration{
|
||||
def doJobs(jobs : ArrayBuffer[Any]): Unit ={
|
||||
val withWrite = jobs.exists(j => j.isInstanceOf[CsrWrite] || j.isInstanceOf[CsrOnWrite] || j.isInstanceOf[CsrDuringWrite])
|
||||
val withRead = jobs.exists(j => j.isInstanceOf[CsrRead] || j.isInstanceOf[CsrOnRead])
|
||||
if(withRead && withWrite) {
|
||||
illegalAccess := False
|
||||
} else {
|
||||
if (withWrite) illegalAccess.clearWhen(input(CSR_WRITE_OPCODE))
|
||||
if (withRead) illegalAccess.clearWhen(input(CSR_READ_OPCODE))
|
||||
}
|
||||
|
||||
when(writeEnable) {
|
||||
for (element <- jobs) element match {
|
||||
case element: CsrWrite => element.that.assignFromBits(writeData(element.bitOffset, element.that.getBitsWidth bits))
|
||||
case element: CsrOnWrite =>
|
||||
element.doThat()
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
|
||||
for (element <- jobs) element match {
|
||||
case element: CsrRead if element.that.getBitsWidth != 0 => readData(element.bitOffset, element.that.getBitsWidth bits) := element.that.asBits
|
||||
case _ =>
|
||||
}
|
||||
for (element <- jobs) element match {
|
||||
case element : CsrDuringWrite => when(writeInstruction){element.doThat()}
|
||||
case _ =>
|
||||
}
|
||||
when(writeEnable) {
|
||||
for (element <- jobs) element match {
|
||||
case element: CsrWrite => element.that.assignFromBits(writeData(element.bitOffset, element.that.getBitsWidth bits))
|
||||
case element: CsrOnWrite => element.doThat()
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
|
||||
when(readEnable) {
|
||||
for (element <- jobs) element match {
|
||||
case element: CsrOnRead =>
|
||||
element.doThat()
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
when(readEnable) {
|
||||
for (element <- jobs) element match {
|
||||
case element: CsrOnRead =>
|
||||
element.doThat()
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch(csrAddress) {
|
||||
for ((address, jobs) <- csrMapping.mapping if jobs.exists(_.isInstanceOf[CsrReadToWriteOverride])) {
|
||||
is(address) {
|
||||
for (element <- jobs) element match {
|
||||
case element: CsrReadToWriteOverride if element.that.getBitsWidth != 0 => readToWriteData(element.bitOffset, element.that.getBitsWidth bits) := element.that.asBits
|
||||
case _ =>
|
||||
def doJobsOverride(jobs : ArrayBuffer[Any]): Unit ={
|
||||
for (element <- jobs) element match {
|
||||
case element: CsrReadToWriteOverride if element.that.getBitsWidth != 0 => readToWriteData(element.bitOffset, element.that.getBitsWidth bits) := element.that.asBits
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
|
||||
csrOhDecoder match {
|
||||
case false => {
|
||||
readData := 0
|
||||
switch(csrAddress) {
|
||||
for ((address, jobs) <- csrMapping.mapping) {
|
||||
is(address) {
|
||||
doJobs(jobs)
|
||||
for (element <- jobs) element match {
|
||||
case element: CsrRead if element.that.getBitsWidth != 0 => readData(element.bitOffset, element.that.getBitsWidth bits) := element.that.asBits
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
switch(csrAddress) {
|
||||
for ((address, jobs) <- csrMapping.mapping if jobs.exists(_.isInstanceOf[CsrReadToWriteOverride])) {
|
||||
is(address) {
|
||||
doJobsOverride(jobs)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case true => {
|
||||
val oh = csrMapping.mapping.keys.toList.distinct.map(address => address -> RegNextWhen(decode.input(INSTRUCTION)(csrRange) === address, !execute.arbitration.isStuck).setCompositeName(this, "csr_" + address)).toMap
|
||||
val readDatas = ArrayBuffer[Bits]()
|
||||
for ((address, jobs) <- csrMapping.mapping) {
|
||||
when(oh(address)){
|
||||
doJobs(jobs)
|
||||
}
|
||||
if(jobs.exists(_.isInstanceOf[CsrRead])) {
|
||||
val masked = B(0, 32 bits)
|
||||
when(oh(address)) (for (element <- jobs) element match {
|
||||
case element: CsrRead if element.that.getBitsWidth != 0 => masked(element.bitOffset, element.that.getBitsWidth bits) := element.that.asBits
|
||||
case _ =>
|
||||
})
|
||||
readDatas += masked
|
||||
}
|
||||
}
|
||||
readData := readDatas.reduceBalancedTree(_ | _)
|
||||
for ((address, jobs) <- csrMapping.mapping) {
|
||||
when(oh(address)){
|
||||
doJobsOverride(jobs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1039,8 +1177,23 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
|
|||
|
||||
illegalAccess setWhen(privilege < csrAddress(9 downto 8).asUInt)
|
||||
illegalAccess clearWhen(!arbitration.isValid || !input(IS_CSR))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class UserInterruptPlugin(interruptName : String, code : Int, privilege : Int = 3) extends Plugin[VexRiscv]{
|
||||
var interrupt, interruptEnable : Bool = null
|
||||
override def setup(pipeline: VexRiscv): Unit = {
|
||||
val csr = pipeline.service(classOf[CsrPlugin])
|
||||
interrupt = in.Bool().setName(interruptName)
|
||||
val interruptPending = RegNext(interrupt) init(False)
|
||||
val interruptEnable = RegInit(False).setName(interruptName + "_enable")
|
||||
csr.addInterrupt(interruptPending , code, privilege, Nil)
|
||||
csr.r(csrAddress = CSR.MIP, bitOffset = code,interruptPending)
|
||||
csr.rw(csrAddress = CSR.MIE, bitOffset = code, interruptEnable)
|
||||
}
|
||||
override def build(pipeline: VexRiscv): Unit = {}
|
||||
}
|
|
@ -26,7 +26,7 @@ class DBusCachedPlugin(val config : DataCacheConfig,
|
|||
relaxedMemoryTranslationRegister : Boolean = false,
|
||||
csrInfo : Boolean = false) extends Plugin[VexRiscv] with DBusAccessService {
|
||||
import config._
|
||||
|
||||
assert(!(config.withExternalAmo && !dBusRspSlavePipe))
|
||||
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)")
|
||||
|
||||
|
@ -49,6 +49,8 @@ class DBusCachedPlugin(val config : DataCacheConfig,
|
|||
object MEMORY_ADDRESS_LOW extends Stageable(UInt(2 bits))
|
||||
object MEMORY_LRSC extends Stageable(Bool)
|
||||
object MEMORY_AMO extends Stageable(Bool)
|
||||
object MEMORY_FENCE extends Stageable(Bool)
|
||||
object MEMORY_FORCE_CONSTISTENCY extends Stageable(Bool)
|
||||
object IS_DBUS_SHARING extends Stageable(Bool())
|
||||
object MEMORY_VIRTUAL_ADDRESS extends Stageable(UInt(32 bits))
|
||||
|
||||
|
@ -56,6 +58,8 @@ class DBusCachedPlugin(val config : DataCacheConfig,
|
|||
import Riscv._
|
||||
import pipeline.config._
|
||||
|
||||
dBus = master(DataCacheMemBus(this.config)).setName("dBus")
|
||||
|
||||
val decoderService = pipeline.service(classOf[DecoderService])
|
||||
|
||||
val stdActions = List[(Stageable[_ <: BaseType],Any)](
|
||||
|
@ -142,13 +146,19 @@ class DBusCachedPlugin(val config : DataCacheConfig,
|
|||
MEMORY_MANAGMENT -> True
|
||||
))
|
||||
|
||||
decoderService.add(FENCE, Nil)
|
||||
withWriteResponse match {
|
||||
case false => decoderService.add(FENCE, Nil)
|
||||
case true => {
|
||||
decoderService.addDefault(MEMORY_FENCE, False)
|
||||
decoderService.add(FENCE, List(MEMORY_FENCE -> True))
|
||||
}
|
||||
}
|
||||
|
||||
mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(MemoryTranslatorPort.PRIORITY_DATA ,memoryTranslatorPortConfig)
|
||||
redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(if(pipeline.writeBack != null) pipeline.writeBack else pipeline.execute)
|
||||
redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(if(pipeline.writeBack != null) pipeline.writeBack else pipeline.memory)
|
||||
|
||||
if(catchSomething)
|
||||
exceptionBus = pipeline.service(classOf[ExceptionService]).newExceptionPort(pipeline.writeBack)
|
||||
exceptionBus = pipeline.service(classOf[ExceptionService]).newExceptionPort(if(pipeline.writeBack == null) pipeline.memory else pipeline.writeBack)
|
||||
|
||||
if(pipeline.serviceExist(classOf[PrivilegeService]))
|
||||
privilegeService = pipeline.service(classOf[PrivilegeService])
|
||||
|
@ -160,15 +170,42 @@ class DBusCachedPlugin(val config : DataCacheConfig,
|
|||
import pipeline._
|
||||
import pipeline.config._
|
||||
|
||||
dBus = master(DataCacheMemBus(this.config)).setName("dBus")
|
||||
val twoStageMmu = mmuBus.p.latency match {
|
||||
case 0 => false
|
||||
case 1 => true
|
||||
}
|
||||
|
||||
val cache = new DataCache(this.config)
|
||||
val cache = new DataCache(
|
||||
this.config.copy(
|
||||
mergeExecuteMemory = writeBack == null
|
||||
),
|
||||
mmuParameter = mmuBus.p
|
||||
)
|
||||
|
||||
//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())
|
||||
cache.io.mem.rsp << (dBusRspSlavePipe match {
|
||||
case false => dBus.rsp
|
||||
case true if !withExternalAmo => dBus.rsp.m2sPipe()
|
||||
case true if withExternalAmo => {
|
||||
val rsp = Flow (DataCacheMemRsp(cache.p))
|
||||
rsp.valid := RegNext(dBus.rsp.valid) init(False)
|
||||
rsp.exclusive := RegNext(dBus.rsp.exclusive)
|
||||
rsp.error := RegNext(dBus.rsp.error)
|
||||
rsp.last := RegNext(dBus.rsp.last)
|
||||
rsp.aggregated := RegNext(dBus.rsp.aggregated)
|
||||
rsp.data := RegNextWhen(dBus.rsp.data, dBus.rsp.valid && !cache.io.cpu.writeBack.keepMemRspData)
|
||||
rsp
|
||||
}
|
||||
})
|
||||
|
||||
if(withInvalidate) {
|
||||
cache.io.mem.inv << dBus.inv
|
||||
cache.io.mem.ack >> dBus.ack
|
||||
cache.io.mem.sync << dBus.sync
|
||||
}
|
||||
|
||||
pipeline plug new Area{
|
||||
//Memory bandwidth counter
|
||||
|
@ -184,6 +221,16 @@ class DBusCachedPlugin(val config : DataCacheConfig,
|
|||
when(mmuBus.busy && arbitration.isValid && input(MEMORY_ENABLE)) {
|
||||
arbitration.haltItself := True
|
||||
}
|
||||
|
||||
|
||||
//Manage write to read hit ordering (ensure invalidation timings)
|
||||
val fence = new Area {
|
||||
insert(MEMORY_FORCE_CONSTISTENCY) := False
|
||||
when(input(INSTRUCTION)(25)) { //RL
|
||||
if (withLrSc) insert(MEMORY_FORCE_CONSTISTENCY) setWhen (input(MEMORY_LRSC))
|
||||
if (withAmo) insert(MEMORY_FORCE_CONSTISTENCY) setWhen (input(MEMORY_AMO))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
execute plug new Area {
|
||||
|
@ -200,9 +247,18 @@ class DBusCachedPlugin(val config : DataCacheConfig,
|
|||
)
|
||||
cache.io.cpu.execute.args.size := size
|
||||
|
||||
if(twoStageMmu) {
|
||||
mmuBus.cmd(0).isValid := cache.io.cpu.execute.isValid
|
||||
mmuBus.cmd(0).isStuck := arbitration.isStuck
|
||||
mmuBus.cmd(0).virtualAddress := input(SRC_ADD).asUInt
|
||||
mmuBus.cmd(0).bypassTranslation := False
|
||||
// KeepAttribute(mmuBus.cmd(0))
|
||||
// KeepAttribute(mmuBus.cmd(1))
|
||||
}
|
||||
|
||||
cache.io.cpu.flush.valid := arbitration.isValid && input(MEMORY_MANAGMENT)
|
||||
arbitration.haltItself setWhen(cache.io.cpu.flush.isStall)
|
||||
cache.io.cpu.execute.args.totalyConsistent := input(MEMORY_FORCE_CONSTISTENCY)
|
||||
arbitration.haltItself setWhen(cache.io.cpu.flush.isStall || cache.io.cpu.execute.haltIt)
|
||||
|
||||
if(withLrSc) {
|
||||
cache.io.cpu.execute.args.isLrsc := False
|
||||
|
@ -223,27 +279,64 @@ class DBusCachedPlugin(val config : DataCacheConfig,
|
|||
arbitration.haltItself := True
|
||||
}
|
||||
|
||||
if(relaxedMemoryTranslationRegister) insert(MEMORY_VIRTUAL_ADDRESS) := cache.io.cpu.execute.address
|
||||
if(relaxedMemoryTranslationRegister) {
|
||||
insert(MEMORY_VIRTUAL_ADDRESS) := cache.io.cpu.execute.address
|
||||
memory.input(MEMORY_VIRTUAL_ADDRESS)
|
||||
if(writeBack != null) addPrePopTask( () =>
|
||||
KeepAttribute(memory.input(MEMORY_VIRTUAL_ADDRESS).getDrivingReg)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
memory plug new Area{
|
||||
import memory._
|
||||
val mmuAndBufferStage = if(writeBack != null) memory else execute
|
||||
mmuAndBufferStage plug new Area {
|
||||
import mmuAndBufferStage._
|
||||
|
||||
cache.io.cpu.memory.isValid := arbitration.isValid && input(MEMORY_ENABLE)
|
||||
cache.io.cpu.memory.isStuck := arbitration.isStuck
|
||||
cache.io.cpu.memory.isRemoved := arbitration.removeIt
|
||||
cache.io.cpu.memory.address := (if(relaxedMemoryTranslationRegister) input(MEMORY_VIRTUAL_ADDRESS) else U(input(REGFILE_WRITE_DATA)))
|
||||
cache.io.cpu.memory.address := (if(relaxedMemoryTranslationRegister) input(MEMORY_VIRTUAL_ADDRESS) else if(mmuAndBufferStage == execute) cache.io.cpu.execute.address else U(input(REGFILE_WRITE_DATA)))
|
||||
|
||||
cache.io.cpu.memory.mmuBus <> mmuBus
|
||||
cache.io.cpu.memory.mmuBus.rsp.isIoAccess setWhen(pipeline(DEBUG_BYPASS_CACHE) && !cache.io.cpu.memory.isWrite)
|
||||
mmuBus.cmd.last.isValid := cache.io.cpu.memory.isValid
|
||||
mmuBus.cmd.last.isStuck := cache.io.cpu.memory.isStuck
|
||||
mmuBus.cmd.last.virtualAddress := cache.io.cpu.memory.address
|
||||
mmuBus.cmd.last.bypassTranslation := False
|
||||
mmuBus.end := !arbitration.isStuck || arbitration.removeIt
|
||||
cache.io.cpu.memory.mmuRsp := mmuBus.rsp
|
||||
cache.io.cpu.memory.mmuRsp.isIoAccess setWhen(pipeline(DEBUG_BYPASS_CACHE) && !cache.io.cpu.memory.isWrite)
|
||||
}
|
||||
|
||||
writeBack plug new Area{
|
||||
import writeBack._
|
||||
val managementStage = stages.last
|
||||
managementStage plug new Area{
|
||||
import managementStage._
|
||||
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() else False)
|
||||
cache.io.cpu.writeBack.address := U(input(REGFILE_WRITE_DATA))
|
||||
if(withLrSc) cache.io.cpu.writeBack.clearLrsc := service(classOf[IContextSwitching]).isContextSwitching
|
||||
|
||||
val fence = if(withInvalidate) {
|
||||
cache.io.cpu.writeBack.fence := input(INSTRUCTION)(31 downto 20).as(FenceFlags())
|
||||
val aquire = False
|
||||
if(withWriteResponse) when(input(INSTRUCTION)(26)) { //AQ
|
||||
if(withLrSc) when(input(MEMORY_LRSC)){
|
||||
aquire := True
|
||||
}
|
||||
if(withAmo) when(input(MEMORY_AMO)){
|
||||
aquire := True
|
||||
}
|
||||
}
|
||||
|
||||
when(aquire){
|
||||
cache.io.cpu.writeBack.fence.forceAll()
|
||||
}
|
||||
|
||||
when(!input(MEMORY_FENCE) || !arbitration.isFiring){
|
||||
cache.io.cpu.writeBack.fence.clearAll()
|
||||
}
|
||||
|
||||
when(arbitration.isValid && (input(MEMORY_FENCE) || aquire)){
|
||||
mmuAndBufferStage.arbitration.haltByOther := True //Ensure that the fence affect the memory stage instruction by stoping it
|
||||
}
|
||||
}
|
||||
|
||||
redoBranch.valid := False
|
||||
redoBranch.payload := input(PC)
|
||||
|
@ -321,12 +414,12 @@ class DBusCachedPlugin(val config : DataCacheConfig,
|
|||
}
|
||||
}
|
||||
execute.insert(IS_DBUS_SHARING) := dBusAccess.cmd.fire
|
||||
mmuBus.cmd.last.bypassTranslation setWhen(mmuAndBufferStage.input(IS_DBUS_SHARING))
|
||||
if(twoStageMmu) mmuBus.cmd(0).bypassTranslation setWhen(execute.input(IS_DBUS_SHARING))
|
||||
|
||||
|
||||
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)
|
||||
if(mmuAndBufferStage != execute) (cache.io.cpu.memory.isValid setWhen(mmuAndBufferStage.input(IS_DBUS_SHARING)))
|
||||
cache.io.cpu.writeBack.isValid setWhen(managementStage.input(IS_DBUS_SHARING))
|
||||
dBusAccess.rsp.valid := managementStage.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
|
||||
|
@ -334,10 +427,10 @@ class DBusCachedPlugin(val config : DataCacheConfig,
|
|||
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)
|
||||
if(mmuAndBufferStage != execute) mmuAndBufferStage.input(IS_DBUS_SHARING) init(False)
|
||||
managementStage.input(IS_DBUS_SHARING) init(False)
|
||||
when(dBusAccess.rsp.valid){
|
||||
writeBack.input(IS_DBUS_SHARING).getDrivingReg := False
|
||||
managementStage.input(IS_DBUS_SHARING).getDrivingReg := False
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,10 +83,7 @@ object DBusSimpleBus{
|
|||
lengthWidth = 2,
|
||||
sourceWidth = 0,
|
||||
contextWidth = 1,
|
||||
canRead = true,
|
||||
canWrite = true,
|
||||
alignment = BmbParameter.BurstAlignement.LENGTH,
|
||||
maximumPendingTransactionPerId = Int.MaxValue
|
||||
alignment = BmbParameter.BurstAlignement.LENGTH
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -106,17 +103,19 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{
|
|||
s
|
||||
}
|
||||
|
||||
def toAxi4Shared(stageCmd : Boolean = false): Axi4Shared = {
|
||||
def toAxi4Shared(stageCmd : Boolean = false, pendingWritesMax : Int = 7): Axi4Shared = {
|
||||
val axi = Axi4Shared(DBusSimpleBus.getAxi4Config())
|
||||
val pendingWritesMax = 7
|
||||
|
||||
val cmdPreFork = if (stageCmd) cmd.stage.stage().s2mPipe() else cmd
|
||||
|
||||
val pendingWrites = CounterUpDown(
|
||||
stateCount = pendingWritesMax + 1,
|
||||
incWhen = axi.sharedCmd.fire && axi.sharedCmd.write,
|
||||
incWhen = cmdPreFork.fire && cmdPreFork.wr,
|
||||
decWhen = axi.writeRsp.fire
|
||||
)
|
||||
|
||||
val cmdPreFork = if (stageCmd) cmd.stage.stage().s2mPipe() else cmd
|
||||
val (cmdFork, dataFork) = StreamFork2(cmdPreFork.haltWhen((pendingWrites =/= 0 && cmdPreFork.valid && !cmdPreFork.wr) || pendingWrites === pendingWritesMax))
|
||||
val hazard = (pendingWrites =/= 0 && cmdPreFork.valid && !cmdPreFork.wr) || pendingWrites === pendingWritesMax
|
||||
val (cmdFork, dataFork) = StreamFork2(cmdPreFork.haltWhen(hazard))
|
||||
axi.sharedCmd.arbitrationFrom(cmdFork)
|
||||
axi.sharedCmd.write := cmdFork.wr
|
||||
axi.sharedCmd.prot := "010"
|
||||
|
@ -296,7 +295,6 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false,
|
|||
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)
|
||||
|
@ -391,6 +389,8 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false,
|
|||
import pipeline._
|
||||
import pipeline.config._
|
||||
|
||||
object MMU_RSP extends Stageable(MemoryTranslatorRsp(mmuBus.p))
|
||||
|
||||
dBus = master(DBusSimpleBus()).setName("dBus")
|
||||
|
||||
|
||||
|
@ -446,9 +446,10 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false,
|
|||
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.cmd.last.isValid := arbitration.isValid && input(MEMORY_ENABLE)
|
||||
mmuBus.cmd.last.isStuck := arbitration.isStuck
|
||||
mmuBus.cmd.last.virtualAddress := input(SRC_ADD).asUInt
|
||||
mmuBus.cmd.last.bypassTranslation := False
|
||||
mmuBus.end := !arbitration.isStuck || arbitration.isRemoved
|
||||
dBus.cmd.address := mmuBus.rsp.physicalAddress
|
||||
|
||||
|
@ -467,13 +468,9 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false,
|
|||
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(arbitration.isFiring && input(MEMORY_ENABLE) && input(MEMORY_ATOMIC) && (if(mmuBus != null) !input(MMU_FAULT) else True) && !skipCmd){
|
||||
reserved := !input(MEMORY_STORE)
|
||||
}
|
||||
when(service(classOf[IContextSwitching]).isContextSwitching){
|
||||
reserved := False
|
||||
}
|
||||
|
||||
when(input(MEMORY_STORE) && input(MEMORY_ATOMIC) && !input(ATOMIC_HIT)){
|
||||
skipCmd := True
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package vexriscv.plugin
|
||||
|
||||
import spinal.lib.com.jtag.Jtag
|
||||
import spinal.lib.system.debugger.{JtagBridge, SystemDebugger, SystemDebuggerConfig}
|
||||
import spinal.lib.com.jtag.{Jtag, JtagTapInstructionCtrl}
|
||||
import spinal.lib.system.debugger.{JtagBridge, JtagBridgeNoTap, SystemDebugger, SystemDebuggerConfig, SystemDebuggerMemBus}
|
||||
import vexriscv.plugin.IntAluPlugin.{ALU_CTRL, AluCtrlEnum}
|
||||
import vexriscv._
|
||||
import vexriscv.ip._
|
||||
|
@ -9,6 +9,8 @@ import spinal.core._
|
|||
import spinal.lib._
|
||||
import spinal.lib.bus.amba3.apb.{Apb3, Apb3Config}
|
||||
import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig}
|
||||
import spinal.lib.bus.bmb.{Bmb, BmbAccessCapabilities, BmbAccessParameter, BmbParameter}
|
||||
import spinal.lib.bus.simple.PipelinedMemoryBus
|
||||
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
|
||||
|
@ -22,6 +24,15 @@ case class DebugExtensionRsp() extends Bundle{
|
|||
val data = Bits(32 bit)
|
||||
}
|
||||
|
||||
object DebugExtensionBus{
|
||||
def getBmbAccessParameter(source : BmbAccessCapabilities) = source.copy(
|
||||
addressWidth = 8,
|
||||
dataWidth = 32,
|
||||
lengthWidthMax = 2,
|
||||
alignment = BmbParameter.BurstAlignement.LENGTH
|
||||
)
|
||||
}
|
||||
|
||||
case class DebugExtensionBus() extends Bundle with IMasterSlave{
|
||||
val cmd = Stream(DebugExtensionCmd())
|
||||
val rsp = DebugExtensionRsp() //one cycle latency
|
||||
|
@ -63,6 +74,54 @@ case class DebugExtensionBus() extends Bundle with IMasterSlave{
|
|||
bus
|
||||
}
|
||||
|
||||
def fromPipelinedMemoryBus(): PipelinedMemoryBus ={
|
||||
val bus = PipelinedMemoryBus(32, 32)
|
||||
|
||||
cmd.arbitrationFrom(bus.cmd)
|
||||
cmd.wr := bus.cmd.write
|
||||
cmd.address := bus.cmd.address.resized
|
||||
cmd.data := bus.cmd.data
|
||||
|
||||
bus.rsp.valid := RegNext(cmd.fire) init(False)
|
||||
bus.rsp.data := rsp.data
|
||||
|
||||
bus
|
||||
}
|
||||
|
||||
def fromBmb(): Bmb ={
|
||||
val bus = Bmb(BmbParameter(
|
||||
addressWidth = 8,
|
||||
dataWidth = 32,
|
||||
lengthWidth = 2,
|
||||
sourceWidth = 0,
|
||||
contextWidth = 0
|
||||
))
|
||||
|
||||
cmd.arbitrationFrom(bus.cmd)
|
||||
cmd.wr := bus.cmd.isWrite
|
||||
cmd.address := bus.cmd.address
|
||||
cmd.data := bus.cmd.data
|
||||
|
||||
bus.rsp.valid := RegNext(cmd.fire) init(False)
|
||||
bus.rsp.data := rsp.data
|
||||
bus.rsp.last := True
|
||||
bus.rsp.setSuccess()
|
||||
|
||||
bus
|
||||
}
|
||||
|
||||
def from(c : SystemDebuggerConfig) : SystemDebuggerMemBus = {
|
||||
val mem = SystemDebuggerMemBus(c)
|
||||
cmd.valid := mem.cmd.valid
|
||||
cmd.wr := mem.cmd.wr
|
||||
cmd.data := mem.cmd.data
|
||||
cmd.address := mem.cmd.address.resized
|
||||
mem.cmd.ready := cmd.ready
|
||||
mem.rsp.valid := RegNext(cmd.fire).init(False)
|
||||
mem.rsp.payload := rsp.data
|
||||
mem
|
||||
}
|
||||
|
||||
def fromJtag(): Jtag ={
|
||||
val jtagConfig = SystemDebuggerConfig(
|
||||
memAddressWidth = 32,
|
||||
|
@ -72,16 +131,24 @@ case class DebugExtensionBus() extends Bundle with IMasterSlave{
|
|||
val jtagBridge = new JtagBridge(jtagConfig)
|
||||
val debugger = new SystemDebugger(jtagConfig)
|
||||
debugger.io.remote <> jtagBridge.io.remote
|
||||
debugger.io.mem.cmd.valid <> cmd.valid
|
||||
debugger.io.mem.cmd.ready <> cmd.ready
|
||||
debugger.io.mem.cmd.wr <> cmd.wr
|
||||
cmd.address := debugger.io.mem.cmd.address.resized
|
||||
debugger.io.mem.cmd.data <> cmd.data
|
||||
debugger.io.mem.rsp.valid <> RegNext(cmd.fire).init(False)
|
||||
debugger.io.mem.rsp.payload <> rsp.data
|
||||
debugger.io.mem <> this.from(jtagConfig)
|
||||
|
||||
jtagBridge.io.jtag
|
||||
}
|
||||
|
||||
def fromJtagInstructionCtrl(jtagClockDomain : ClockDomain): JtagTapInstructionCtrl ={
|
||||
val jtagConfig = SystemDebuggerConfig(
|
||||
memAddressWidth = 32,
|
||||
memDataWidth = 32,
|
||||
remoteCmdWidth = 1
|
||||
)
|
||||
val jtagBridge = new JtagBridgeNoTap(jtagConfig, jtagClockDomain)
|
||||
val debugger = new SystemDebugger(jtagConfig)
|
||||
debugger.io.remote <> jtagBridge.io.remote
|
||||
debugger.io.mem <> this.from(jtagConfig)
|
||||
|
||||
jtagBridge.io.ctrl
|
||||
}
|
||||
}
|
||||
|
||||
case class DebugExtensionIo() extends Bundle with IMasterSlave{
|
||||
|
@ -96,7 +163,7 @@ case class DebugExtensionIo() extends Bundle with IMasterSlave{
|
|||
|
||||
|
||||
|
||||
class DebugPlugin(val debugClockDomain : ClockDomain, hardwareBreakpointCount : Int = 0) extends Plugin[VexRiscv] {
|
||||
class DebugPlugin(var debugClockDomain : ClockDomain, hardwareBreakpointCount : Int = 0) extends Plugin[VexRiscv] {
|
||||
|
||||
var io : DebugExtensionIo = null
|
||||
val injectionAsks = ArrayBuffer[(Stage, Bool)]()
|
||||
|
@ -201,7 +268,6 @@ class DebugPlugin(val debugClockDomain : ClockDomain, hardwareBreakpointCount :
|
|||
execute.arbitration.haltByOther := True
|
||||
busReadDataReg := execute.input(PC).asBits
|
||||
when(stagesFromExecute.tail.map(_.arbitration.isValid).orR === False){
|
||||
iBusFetcher.flushIt()
|
||||
iBusFetcher.haltIt()
|
||||
execute.arbitration.flushIt := True
|
||||
execute.arbitration.flushNext := True
|
||||
|
@ -224,7 +290,7 @@ class DebugPlugin(val debugClockDomain : ClockDomain, hardwareBreakpointCount :
|
|||
//Avoid having two C instruction executed in a single step
|
||||
if(pipeline(RVC_GEN)){
|
||||
val cleanStep = RegNext(stepIt && decode.arbitration.isFiring) init(False)
|
||||
decode.arbitration.removeIt setWhen(cleanStep)
|
||||
execute.arbitration.flushNext setWhen(cleanStep)
|
||||
}
|
||||
|
||||
io.resetOut := RegNext(resetIt)
|
||||
|
@ -246,6 +312,11 @@ class DebugPlugin(val debugClockDomain : ClockDomain, hardwareBreakpointCount :
|
|||
}
|
||||
if(pipeline.things.contains(DEBUG_BYPASS_CACHE)) pipeline(DEBUG_BYPASS_CACHE) := True
|
||||
}
|
||||
|
||||
val wakeService = serviceElse(classOf[IWake], null)
|
||||
if(wakeService != null) when(haltIt){
|
||||
wakeService.askWake()
|
||||
}
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ class DecoderSimplePlugin(catchIllegalInstruction : Boolean = false,
|
|||
import pipeline.config._
|
||||
import pipeline.decode._
|
||||
|
||||
val stageables = (encodings.flatMap(_._2.map(_._1)) ++ defaults.map(_._1)).toSet.toList
|
||||
val stageables = (encodings.flatMap(_._2.map(_._1)) ++ defaults.map(_._1)).toList.distinct
|
||||
|
||||
val stupidDecoder = false
|
||||
if(stupidDecoder){
|
||||
|
@ -172,7 +172,7 @@ class DecoderSimplePlugin(catchIllegalInstruction : Boolean = false,
|
|||
}
|
||||
|
||||
if(catchIllegalInstruction){
|
||||
decodeExceptionPort.valid := arbitration.isValid && input(INSTRUCTION_READY) && !input(LEGAL_INSTRUCTION) // ?? HalitIt to alow decoder stage to wait valid data from 2 stages cache cache ??
|
||||
decodeExceptionPort.valid := arbitration.isValid && !input(LEGAL_INSTRUCTION) // ?? HalitIt to alow decoder stage to wait valid data from 2 stages cache cache ??
|
||||
decodeExceptionPort.code := 2
|
||||
decodeExceptionPort.badAddr := input(INSTRUCTION).asUInt
|
||||
}
|
||||
|
|
|
@ -16,12 +16,14 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
|
|||
val decodePcGen : Boolean,
|
||||
val compressedGen : Boolean,
|
||||
val cmdToRspStageCount : Int,
|
||||
val pcRegReusedForSecondStage : Boolean,
|
||||
val allowPcRegReusedForSecondStage : Boolean,
|
||||
val injectorReadyCutGen : Boolean,
|
||||
val prediction : BranchPrediction,
|
||||
val historyRamSizeLog2 : Int,
|
||||
val injectorStage : Boolean,
|
||||
val relaxPredictorAddress : Boolean) extends Plugin[VexRiscv] with JumpService with IBusFetcher{
|
||||
val relaxPredictorAddress : Boolean,
|
||||
val fetchRedoGen : Boolean,
|
||||
val predictionBuffer : Boolean = true) extends Plugin[VexRiscv] with JumpService with IBusFetcher{
|
||||
var prefetchExceptionPort : Flow[ExceptionCause] = null
|
||||
var decodePrediction : DecodePredictionBus = null
|
||||
var fetchPrediction : FetchPredictionBus = null
|
||||
|
@ -31,7 +33,6 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
|
|||
// assert(!(cmdToRspStageCount == 1 && !injectorStage))
|
||||
assert(!(compressedGen && !decodePcGen))
|
||||
var fetcherHalt : Bool = null
|
||||
var fetcherflushIt : Bool = null
|
||||
var pcValids : Vec[Bool] = null
|
||||
def pcValid(stage : Stage) = pcValids(pipeline.indexOf(stage))
|
||||
var incomingInstruction : Bool = null
|
||||
|
@ -42,12 +43,10 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
|
|||
injectionPort = Stream(Bits(32 bits))
|
||||
injectionPort
|
||||
}
|
||||
|
||||
def pcRegReusedForSecondStage = allowPcRegReusedForSecondStage && prediction != DYNAMIC_TARGET //TODO might not be required for DYNAMIC_TARGET
|
||||
var predictionJumpInterface : Flow[UInt] = null
|
||||
|
||||
override def haltIt(): Unit = fetcherHalt := True
|
||||
override def flushIt(): Unit = fetcherflushIt := True
|
||||
|
||||
case class JumpInfo(interface : Flow[UInt], stage: Stage, priority : Int)
|
||||
val jumpInfos = ArrayBuffer[JumpInfo]()
|
||||
override def createJumpInterface(stage: Stage, priority : Int = 0): Flow[UInt] = {
|
||||
|
@ -61,7 +60,6 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
|
|||
// var decodeExceptionPort : Flow[ExceptionCause] = null
|
||||
override def setup(pipeline: VexRiscv): Unit = {
|
||||
fetcherHalt = False
|
||||
fetcherflushIt = False
|
||||
incomingInstruction = False
|
||||
if(resetVector == null) externalResetVector = in(UInt(32 bits).setName("externalResetVector"))
|
||||
|
||||
|
@ -75,21 +73,33 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
|
|||
}
|
||||
case DYNAMIC_TARGET => {
|
||||
fetchPrediction = pipeline.service(classOf[PredictionInterface]).askFetchPrediction()
|
||||
if(compressedGen && cmdToRspStageCount > 1){
|
||||
dynamicTargetFailureCorrection = createJumpInterface(pipeline.decode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pcValids = Vec(Bool, pipeline.stages.size)
|
||||
}
|
||||
|
||||
object IBUS_RSP
|
||||
object DECOMPRESSOR
|
||||
object INJECTOR_M2S
|
||||
|
||||
def isDrivingDecode(s : Any): Boolean = {
|
||||
if(injectorStage) return s == INJECTOR_M2S
|
||||
s == IBUS_RSP || s == DECOMPRESSOR
|
||||
}
|
||||
|
||||
|
||||
|
||||
class FetchArea(pipeline : VexRiscv) extends Area {
|
||||
import pipeline._
|
||||
import pipeline.config._
|
||||
val externalFlush = stages.map(_.arbitration.flushNext).orR
|
||||
|
||||
//JumpService hardware implementation
|
||||
def getFlushAt(s : Any, lastCond : Boolean = true): Bool = {
|
||||
if(isDrivingDecode(s) && lastCond) pipeline.decode.arbitration.isRemoved else externalFlush
|
||||
}
|
||||
|
||||
//Arbitrate jump requests into pcLoad
|
||||
val jump = new Area {
|
||||
val sortedByStage = jumpInfos.sortWith((a, b) => {
|
||||
(pipeline.indexOf(a.stage) > pipeline.indexOf(b.stage)) ||
|
||||
|
@ -103,7 +113,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
|
|||
pcLoad.payload := MuxOH(OHMasking.first(valids.asBits), pcs)
|
||||
}
|
||||
|
||||
fetcherflushIt setWhen(stages.map(_.arbitration.flushNext).orR)
|
||||
|
||||
|
||||
//The fetchPC pcReg can also be use for the second stage of the fetch
|
||||
//When the fetcherHalt is set and the pipeline isn't stalled,, the pc is propagated to to the pcReg, which allow
|
||||
|
@ -112,12 +122,16 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
|
|||
//PC calculation without Jump
|
||||
val output = Stream(UInt(32 bits))
|
||||
val pcReg = Reg(UInt(32 bits)) init(if(resetVector != null) resetVector else externalResetVector) addAttribute(Verilator.public)
|
||||
val corrected = False
|
||||
val correction = False
|
||||
val correctionReg = RegInit(False) setWhen(correction) clearWhen(output.fire)
|
||||
val corrected = correction || correctionReg
|
||||
val pcRegPropagate = False
|
||||
val booted = RegNext(True) init (False)
|
||||
val inc = RegInit(False) clearWhen(corrected || pcRegPropagate) setWhen(output.fire) clearWhen(!output.valid && output.ready)
|
||||
val inc = RegInit(False) clearWhen(correction || pcRegPropagate) setWhen(output.fire) clearWhen(!output.valid && output.ready)
|
||||
val pc = pcReg + (inc ## B"00").asUInt
|
||||
val predictionPcLoad = ifGen(prediction == DYNAMIC_TARGET) (Flow(UInt(32 bits)))
|
||||
val redo = (fetchRedoGen || prediction == DYNAMIC_TARGET) generate Flow(UInt(32 bits))
|
||||
val flushed = False
|
||||
|
||||
if(compressedGen) when(inc) {
|
||||
pc(1) := False
|
||||
|
@ -125,22 +139,27 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
|
|||
|
||||
if(predictionPcLoad != null) {
|
||||
when(predictionPcLoad.valid) {
|
||||
corrected := True
|
||||
correction := True
|
||||
pc := predictionPcLoad.payload
|
||||
}
|
||||
}
|
||||
if(redo != null) when(redo.valid){
|
||||
correction := True
|
||||
pc := redo.payload
|
||||
flushed := True
|
||||
}
|
||||
when(jump.pcLoad.valid) {
|
||||
corrected := True
|
||||
correction := True
|
||||
pc := jump.pcLoad.payload
|
||||
flushed := True
|
||||
}
|
||||
|
||||
|
||||
when(booted && (output.ready || fetcherflushIt || pcRegPropagate)){
|
||||
when(booted && (output.ready || correction || pcRegPropagate)){
|
||||
pcReg := pc
|
||||
}
|
||||
|
||||
pc(0) := False
|
||||
if(!pipeline(RVC_GEN)) pc(1) := False
|
||||
if(!compressedGen) pc(1) := False
|
||||
|
||||
output.valid := !fetcherHalt && booted
|
||||
output.payload := pc
|
||||
|
@ -148,6 +167,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
|
|||
|
||||
val decodePc = ifGen(decodePcGen)(new Area {
|
||||
//PC calculation without Jump
|
||||
val flushed = False
|
||||
val pcReg = Reg(UInt(32 bits)) init(if(resetVector != null) resetVector else externalResetVector) addAttribute(Verilator.public)
|
||||
val pcPlus = if(compressedGen)
|
||||
pcReg + ((decode.input(IS_RVC)) ? U(2) | U(4))
|
||||
|
@ -170,6 +190,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
|
|||
//application of the selected jump request
|
||||
when(jump.pcLoad.valid && (!decode.arbitration.isStuck || decode.arbitration.isRemoved)) {
|
||||
pcReg := jump.pcLoad.payload
|
||||
flushed := True
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -177,116 +198,109 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
|
|||
case class FetchRsp() extends Bundle {
|
||||
val pc = UInt(32 bits)
|
||||
val rsp = IBusSimpleRsp()
|
||||
val isRvc = Bool
|
||||
val isRvc = Bool()
|
||||
}
|
||||
|
||||
|
||||
val iBusRsp = new Area {
|
||||
// val input = Stream(UInt(32 bits))
|
||||
// val inputPipeline = Vec(Stream(UInt(32 bits)), cmdToRspStageCount)
|
||||
// val inputPipelineHalt = Vec(False, cmdToRspStageCount-1)
|
||||
// for(i <- 0 until cmdToRspStageCount) {
|
||||
// inputPipeline(i) << {i match {
|
||||
// case 0 => input.m2sPipeWithFlush(flush, false, collapsBubble = false)
|
||||
// case _ => inputPipeline(i-1).haltWhen(inputPipelineHalt(i-1)).m2sPipeWithFlush(flush,collapsBubble = false)
|
||||
// }}
|
||||
// }
|
||||
|
||||
// val stages = Array.fill(cmdToRspStageCount)(Stream(UInt(32 bits)))
|
||||
val redoFetch = False
|
||||
val stages = Array.fill(cmdToRspStageCount + 1)(new Bundle {
|
||||
val input = Stream(UInt(32 bits))
|
||||
val output = Stream(UInt(32 bits))
|
||||
val halt = Bool
|
||||
val inputSample = Bool
|
||||
val halt = Bool()
|
||||
})
|
||||
|
||||
stages(0).input << fetchPc.output
|
||||
stages(0).inputSample := True
|
||||
for(s <- stages) {
|
||||
s.halt := False
|
||||
s.output << s.input.haltWhen(s.halt)
|
||||
}
|
||||
|
||||
if(fetchPc.redo != null) {
|
||||
fetchPc.redo.valid := redoFetch
|
||||
fetchPc.redo.payload := stages.last.input.payload
|
||||
}
|
||||
|
||||
val flush = (if(isDrivingDecode(IBUS_RSP)) pipeline.decode.arbitration.isRemoved || decode.arbitration.flushNext && !decode.arbitration.isStuck else externalFlush) || redoFetch
|
||||
for((s,sNext) <- (stages, stages.tail).zipped) {
|
||||
val sFlushed = if(s != stages.head) flush else False
|
||||
val sNextFlushed = flush
|
||||
if(s == stages.head && pcRegReusedForSecondStage) {
|
||||
sNext.input.arbitrationFrom(s.output.toEvent().m2sPipeWithFlush(fetcherflushIt, s != stages.head, collapsBubble = false))
|
||||
sNext.input.arbitrationFrom(s.output.toEvent().m2sPipeWithFlush(sNextFlushed, false, collapsBubble = false, flushInput = sFlushed))
|
||||
sNext.input.payload := fetchPc.pcReg
|
||||
fetchPc.pcRegPropagate setWhen(sNext.input.ready)
|
||||
} else {
|
||||
sNext.input << s.output.m2sPipeWithFlush(fetcherflushIt, s != stages.head, collapsBubble = false)
|
||||
sNext.input << s.output.m2sPipeWithFlush(sNextFlushed, false, collapsBubble = false, flushInput = sFlushed)
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// val pipeline = Vec(Stream(UInt(32 bits)), cmdToRspStageCount + 1)
|
||||
// val halts = Vec(False, cmdToRspStageCount)
|
||||
// for(i <- 0 until cmdToRspStageCount + 1) {
|
||||
// pipeline(i) << {i match {
|
||||
// case 0 => pipeline(0) << fetchPc.output.haltWhen(halts(i))
|
||||
// case 1 => pipeline(1).m2sPipeWithFlush(flush, false, collapsBubble = false)
|
||||
// case _ => inputPipeline(i-1).haltWhen(inputPipelineHalt(i-1)).m2sPipeWithFlush(flush,collapsBubble = false)
|
||||
// }}
|
||||
// }
|
||||
|
||||
// ...
|
||||
|
||||
val readyForError = True
|
||||
val output = Stream(FetchRsp())
|
||||
incomingInstruction setWhen(stages.tail.map(_.input.valid).reduce(_ || _))
|
||||
}
|
||||
|
||||
val decompressor = ifGen(decodePcGen)(new Area{
|
||||
def input = iBusRsp.output
|
||||
val input = iBusRsp.output.clearValidWhen(iBusRsp.redoFetch)
|
||||
val output = Stream(FetchRsp())
|
||||
val flush = getFlushAt(DECOMPRESSOR)
|
||||
val flushNext = if(isDrivingDecode(DECOMPRESSOR)) decode.arbitration.flushNext else False
|
||||
val consumeCurrent = if(isDrivingDecode(DECOMPRESSOR)) flushNext && output.ready else False
|
||||
|
||||
val bufferValid = RegInit(False)
|
||||
val bufferData = Reg(Bits(16 bits))
|
||||
|
||||
val isInputLowRvc = input.rsp.inst(1 downto 0) =/= 3
|
||||
val isInputHighRvc = input.rsp.inst(17 downto 16) =/= 3
|
||||
val throw2BytesReg = RegInit(False)
|
||||
val throw2Bytes = throw2BytesReg || input.pc(1)
|
||||
val unaligned = throw2Bytes || bufferValid
|
||||
def aligned = !unaligned
|
||||
val raw = Mux(
|
||||
sel = bufferValid,
|
||||
whenTrue = input.rsp.inst(15 downto 0) ## bufferData,
|
||||
whenFalse = input.rsp.inst(31 downto 16) ## (input.pc(1) ? input.rsp.inst(31 downto 16) | input.rsp.inst(15 downto 0))
|
||||
whenFalse = input.rsp.inst(31 downto 16) ## (throw2Bytes ? input.rsp.inst(31 downto 16) | input.rsp.inst(15 downto 0))
|
||||
)
|
||||
val isRvc = raw(1 downto 0) =/= 3
|
||||
val decompressed = RvcDecompressor(raw(15 downto 0))
|
||||
output.valid := (isRvc ? (bufferValid || input.valid) | (input.valid && (bufferValid || !input.pc(1))))
|
||||
output.valid := input.valid && !(throw2Bytes && !bufferValid && !isInputHighRvc)
|
||||
output.pc := input.pc
|
||||
output.isRvc := isRvc
|
||||
output.rsp.inst := isRvc ? decompressed | raw
|
||||
// input.ready := (bufferValid ? (!isRvc && output.ready) | (input.pc(1) || output.ready))
|
||||
input.ready := !output.valid || !(!output.ready || (isRvc && !input.pc(1) && input.rsp.inst(16, 2 bits) =/= 3) || (!isRvc && bufferValid && input.rsp.inst(16, 2 bits) =/= 3))
|
||||
addPrePopTask(() => {
|
||||
when(!input.ready && output.fire && !fetcherflushIt /* && ((isRvc && !bufferValid && !input.pc(1)) || (!isRvc && bufferValid && input.rsp.inst(16, 2 bits) =/= 3))*/) {
|
||||
input.pc.getDrivingReg(1) := True
|
||||
}
|
||||
})
|
||||
input.ready := output.ready && (!iBusRsp.stages.last.input.valid || flushNext || (!(bufferValid && isInputHighRvc) && !(aligned && isInputLowRvc && isInputHighRvc)))
|
||||
|
||||
bufferValid clearWhen(output.fire)
|
||||
val bufferFill = False
|
||||
when(input.fire){
|
||||
when(!(!isRvc && !input.pc(1) && !bufferValid) && !(isRvc && input.pc(1) && output.ready)) {
|
||||
bufferValid := True
|
||||
bufferFill := True
|
||||
} otherwise {
|
||||
bufferValid := False
|
||||
}
|
||||
bufferData := input.rsp.inst(31 downto 16)
|
||||
when(output.fire){
|
||||
throw2BytesReg := (aligned && isInputLowRvc && isInputHighRvc) || (bufferValid && isInputHighRvc)
|
||||
}
|
||||
val bufferFill = (aligned && isInputLowRvc && !isInputHighRvc) || (bufferValid && !isInputHighRvc) || (throw2Bytes && !isRvc && !isInputHighRvc)
|
||||
when(output.ready && input.valid){
|
||||
bufferValid := False
|
||||
}
|
||||
when(output.ready && input.valid){
|
||||
bufferData := input.rsp.inst(31 downto 16)
|
||||
bufferValid setWhen(bufferFill)
|
||||
}
|
||||
|
||||
when(flush || consumeCurrent){
|
||||
throw2BytesReg := False
|
||||
bufferValid := False
|
||||
}
|
||||
|
||||
if(fetchPc.redo != null) {
|
||||
fetchPc.redo.payload(1) setWhen(throw2BytesReg)
|
||||
}
|
||||
bufferValid.clearWhen(fetcherflushIt)
|
||||
iBusRsp.readyForError.clearWhen(bufferValid && isRvc) //Can't emit error, as there is a earlier instruction pending
|
||||
incomingInstruction setWhen(bufferValid && bufferData(1 downto 0) =/= 3)
|
||||
})
|
||||
|
||||
|
||||
def condApply[T](that : T, cond : Boolean)(func : (T) => T) = if(cond)func(that) else that
|
||||
val injector = new Area {
|
||||
val inputBeforeStage = condApply(if (decodePcGen) decompressor.output else iBusRsp.output, injectorReadyCutGen)(_.s2mPipe(fetcherflushIt))
|
||||
val inputBeforeStage = condApply(if (decodePcGen) decompressor.output else iBusRsp.output, injectorReadyCutGen)(_.s2mPipe(externalFlush))
|
||||
if (injectorReadyCutGen) {
|
||||
iBusRsp.readyForError.clearWhen(inputBeforeStage.valid) //Can't emit error if there is a instruction pending in the s2mPipe
|
||||
incomingInstruction setWhen (inputBeforeStage.valid)
|
||||
}
|
||||
val decodeInput = (if (injectorStage) {
|
||||
val decodeInput = inputBeforeStage.m2sPipeWithFlush(fetcherflushIt, collapsBubble = false)
|
||||
val flushStage = getFlushAt(INJECTOR_M2S)
|
||||
val decodeInput = inputBeforeStage.m2sPipeWithFlush(flushStage, false, collapsBubble = false, flushInput = externalFlush)
|
||||
decode.insert(INSTRUCTION_ANTICIPATED) := Mux(decode.arbitration.isStuck, decode.input(INSTRUCTION), inputBeforeStage.rsp.inst)
|
||||
iBusRsp.readyForError.clearWhen(decodeInput.valid) //Can't emit error when there is a instruction pending in the injector stage buffer
|
||||
incomingInstruction setWhen (decodeInput.valid)
|
||||
|
@ -298,16 +312,16 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
|
|||
if(!decodePcGen) iBusRsp.readyForError.clearWhen(!pcValid(decode)) //Need to wait a valid PC on the decode stage, as it is use to fill CSR xEPC
|
||||
|
||||
|
||||
def pcUpdatedGen(input : Bool, stucks : Seq[Bool], relaxedInput : Boolean) : Seq[Bool] = {
|
||||
def pcUpdatedGen(input : Bool, stucks : Seq[Bool], relaxedInput : Boolean, flush : Bool) : Seq[Bool] = {
|
||||
stucks.scanLeft(input)((i, stuck) => {
|
||||
val reg = RegInit(False)
|
||||
if(!relaxedInput) when(fetcherflushIt) {
|
||||
if(!relaxedInput) when(flush) {
|
||||
reg := False
|
||||
}
|
||||
when(!stuck) {
|
||||
reg := i
|
||||
}
|
||||
if(relaxedInput || i != input) when(fetcherflushIt) {
|
||||
if(relaxedInput || i != input) when(flush) {
|
||||
reg := False
|
||||
}
|
||||
reg
|
||||
|
@ -316,20 +330,17 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
|
|||
|
||||
val stagesFromExecute = stages.dropWhile(_ != execute).toList
|
||||
val nextPcCalc = if (decodePcGen) new Area{
|
||||
val valids = pcUpdatedGen(True, False :: stagesFromExecute.map(_.arbitration.isStuck), true)
|
||||
val valids = pcUpdatedGen(True, False :: stagesFromExecute.map(_.arbitration.isStuck), true, decodePc.flushed)
|
||||
pcValids := Vec(valids.takeRight(stages.size))
|
||||
} else new Area{
|
||||
val valids = pcUpdatedGen(True, iBusRsp.stages.tail.map(!_.input.ready) ++ (if (injectorStage) List(!decodeInput.ready) else Nil) ++ stagesFromExecute.map(_.arbitration.isStuck), false)
|
||||
val valids = pcUpdatedGen(True, iBusRsp.stages.tail.map(!_.input.ready) ++ (if (injectorStage) List(!decodeInput.ready) else Nil) ++ stagesFromExecute.map(_.arbitration.isStuck), false, fetchPc.flushed)
|
||||
pcValids := Vec(valids.takeRight(stages.size))
|
||||
}
|
||||
|
||||
val decodeRemoved = RegInit(False) setWhen(decode.arbitration.isRemoved) clearWhen(fetcherflushIt) //!decode.arbitration.isStuck || decode.arbitration.isFlushed
|
||||
|
||||
decodeInput.ready := !decode.arbitration.isStuck
|
||||
decode.arbitration.isValid := decodeInput.valid && !decodeRemoved
|
||||
decode.arbitration.isValid := decodeInput.valid
|
||||
decode.insert(PC) := (if (decodePcGen) decodePc.pcReg else decodeInput.pc)
|
||||
decode.insert(INSTRUCTION) := decodeInput.rsp.inst
|
||||
decode.insert(INSTRUCTION_READY) := True
|
||||
if (compressedGen) decode.insert(IS_RVC) := decodeInput.isRvc
|
||||
|
||||
if (injectionPort != null) {
|
||||
|
@ -415,18 +426,15 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
|
|||
}
|
||||
}
|
||||
|
||||
def stage1ToInjectorPipe[T <: Data](input : T): (T,T) ={
|
||||
def stage1ToInjectorPipe[T <: Data](input : T): (T, T, T) ={
|
||||
val iBusRspContext = iBusRsp.stages.drop(1).dropRight(1).foldLeft(input)((data,stage) => RegNextWhen(data, stage.output.ready))
|
||||
// val decompressorContext = ifGen(compressedGen)(new Area{
|
||||
// val lastContext = RegNextWhen(iBusRspContext, decompressor.input.fire)
|
||||
// val output = decompressor.bufferValid ? lastContext | iBusRspContext
|
||||
// })
|
||||
val decompressorContext = cloneOf(input)
|
||||
decompressorContext := iBusRspContext
|
||||
val injectorContext = Delay(if(compressedGen) decompressorContext else iBusRspContext, cycleCount=if(injectorStage) 1 else 0, when=injector.decodeInput.ready)
|
||||
|
||||
val iBusRspContextOutput = cloneOf(input)
|
||||
iBusRspContextOutput := iBusRspContext
|
||||
val injectorContext = Delay(iBusRspContextOutput, cycleCount=if(injectorStage) 1 else 0, when=injector.decodeInput.ready)
|
||||
val injectorContextWire = cloneOf(input) //Allow combinatorial override
|
||||
injectorContextWire := injectorContext
|
||||
(ifGen(compressedGen)(decompressorContext), injectorContextWire)
|
||||
(iBusRspContext, iBusRspContextOutput, injectorContextWire)
|
||||
}
|
||||
|
||||
val predictor = prediction match {
|
||||
|
@ -449,10 +457,10 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
|
|||
}
|
||||
val fetchContext = DynamicContext()
|
||||
fetchContext.hazard := hazard
|
||||
fetchContext.line := historyCache.readSync((fetchPc.output.payload >> 2).resized, iBusRsp.stages(0).output.ready || fetcherflushIt)
|
||||
fetchContext.line := historyCache.readSync((fetchPc.output.payload >> 2).resized, iBusRsp.stages(0).output.ready || externalFlush)
|
||||
|
||||
object PREDICTION_CONTEXT extends Stageable(DynamicContext())
|
||||
decode.insert(PREDICTION_CONTEXT) := stage1ToInjectorPipe(fetchContext)._2
|
||||
decode.insert(PREDICTION_CONTEXT) := stage1ToInjectorPipe(fetchContext)._3
|
||||
val decodeContextPrediction = decode.input(PREDICTION_CONTEXT).line.history.msb
|
||||
|
||||
val branchStage = decodePrediction.stage
|
||||
|
@ -488,13 +496,11 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
|
|||
}
|
||||
|
||||
//TODO no more fireing depedancies
|
||||
predictionJumpInterface.valid := decode.arbitration.isValid && decodePrediction.cmd.hadBranch //TODO OH Doublon de priorité
|
||||
predictionJumpInterface.valid := decode.arbitration.isValid && decodePrediction.cmd.hadBranch
|
||||
predictionJumpInterface.payload := decode.input(PC) + ((decode.input(BRANCH_CTRL) === BranchCtrlEnum.JAL) ? imm.j_sext | imm.b_sext).asUInt
|
||||
if(relaxPredictorAddress) KeepAttribute(predictionJumpInterface.payload)
|
||||
decode.arbitration.flushNext setWhen(predictionJumpInterface.valid)
|
||||
|
||||
when(predictionJumpInterface.valid && decode.arbitration.isFiring){
|
||||
flushIt()
|
||||
}
|
||||
if(relaxPredictorAddress) KeepAttribute(predictionJumpInterface.payload)
|
||||
}
|
||||
case DYNAMIC_TARGET => new Area{
|
||||
// assert(!compressedGen || cmdToRspStageCount == 1, "Can't combine DYNAMIC_TARGET and RVC as it could stop the instruction fetch mid-air")
|
||||
|
@ -502,26 +508,40 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
|
|||
case class BranchPredictorLine() extends Bundle{
|
||||
val source = Bits(30 - historyRamSizeLog2 bits)
|
||||
val branchWish = UInt(2 bits)
|
||||
val last2Bytes = ifGen(compressedGen)(Bool)
|
||||
val target = UInt(32 bits)
|
||||
val unaligned = ifGen(compressedGen)(Bool)
|
||||
}
|
||||
|
||||
val history = Mem(BranchPredictorLine(), 1 << historyRamSizeLog2)
|
||||
val historyWrite = history.writePort
|
||||
val historyWriteDelayPatched = history.writePort
|
||||
val historyWrite = cloneOf(historyWriteDelayPatched)
|
||||
historyWriteDelayPatched.valid := historyWrite.valid
|
||||
historyWriteDelayPatched.address := (if(predictionBuffer) historyWrite.address - 1 else historyWrite.address)
|
||||
historyWriteDelayPatched.data := historyWrite.data
|
||||
|
||||
val line = history.readSync((iBusRsp.stages(0).input.payload >> 2).resized, iBusRsp.stages(0).output.ready || fetcherflushIt)
|
||||
val hit = line.source === (iBusRsp.stages(1).input.payload.asBits >> 2 + historyRamSizeLog2) && (if(compressedGen)(!(!line.unaligned && iBusRsp.stages(1).input.payload(1))) else True)
|
||||
|
||||
//Avoid stoping instruction fetch in the middle patch
|
||||
if(compressedGen && cmdToRspStageCount == 1){
|
||||
hit clearWhen(!decompressor.output.valid)
|
||||
}
|
||||
val writeLast = RegNextWhen(historyWriteDelayPatched, iBusRsp.stages(0).output.ready)
|
||||
|
||||
//Avoid write to read hazard
|
||||
val historyWriteLast = RegNextWhen(historyWrite, iBusRsp.stages(0).output.ready)
|
||||
val hazard = historyWriteLast.valid && historyWriteLast.address === (iBusRsp.stages(1).input.payload >> 2).resized
|
||||
//TODO improve predictionPcLoad way of doing things
|
||||
fetchPc.predictionPcLoad.valid := line.branchWish.msb && hit && !hazard && iBusRsp.stages(1).output.valid //XXX && !(!line.unaligned && iBusRsp.inputPipeline(0).payload(1))
|
||||
val buffer = predictionBuffer generate new Area{
|
||||
val line = history.readSync((iBusRsp.stages(0).input.payload >> 2).resized, iBusRsp.stages(0).output.ready)
|
||||
val pcCorrected = RegNextWhen(fetchPc.corrected, iBusRsp.stages(0).input.ready)
|
||||
val hazard = (writeLast.valid && writeLast.address === (iBusRsp.stages(1).input.payload >> 2).resized)
|
||||
}
|
||||
|
||||
val (line, hazard) = predictionBuffer match {
|
||||
case true =>
|
||||
(RegNextWhen(buffer.line, iBusRsp.stages(0).output.ready),
|
||||
RegNextWhen(buffer.hazard, iBusRsp.stages(0).output.ready) || buffer.pcCorrected)
|
||||
case false =>
|
||||
(history.readSync((iBusRsp.stages(0).input.payload >> 2).resized,
|
||||
iBusRsp.stages(0).output.ready), writeLast.valid && writeLast.address === (iBusRsp.stages(1).input.payload >> 2).resized)
|
||||
}
|
||||
|
||||
val hit = line.source === (iBusRsp.stages(1).input.payload.asBits >> 2 + historyRamSizeLog2)
|
||||
if(compressedGen) hit clearWhen(!line.last2Bytes && iBusRsp.stages(1).input.payload(1))
|
||||
|
||||
fetchPc.predictionPcLoad.valid := line.branchWish.msb && hit && !hazard && iBusRsp.stages(1).input.valid
|
||||
fetchPc.predictionPcLoad.payload := line.target
|
||||
|
||||
case class PredictionResult() extends Bundle{
|
||||
|
@ -535,22 +555,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
|
|||
fetchContext.hit := hit
|
||||
fetchContext.line := line
|
||||
|
||||
val (decompressorContext, injectorContext) = stage1ToInjectorPipe(fetchContext)
|
||||
if(compressedGen) {
|
||||
//prediction hit on the right instruction into words
|
||||
decompressorContext.hit clearWhen(decompressorContext.line.unaligned && (decompressor.bufferValid || (decompressor.isRvc && !decompressor.input.pc(1))))
|
||||
|
||||
// if(compressedGen) injectorContext.hit clearWhen(decodePc.pcReg(1) =/= injectorContext.line.unaligned)
|
||||
|
||||
decodePc.predictionPcLoad.valid := injectorContext.line.branchWish.msb && injectorContext.hit && !injectorContext.hazard && injector.decodeInput.fire
|
||||
decodePc.predictionPcLoad.payload := injectorContext.line.target
|
||||
|
||||
|
||||
when(decompressorContext.line.branchWish.msb && decompressorContext.hit && !decompressorContext.hazard && decompressor.output.fire){
|
||||
decompressor.bufferValid := False
|
||||
decompressor.input.ready := True
|
||||
}
|
||||
}
|
||||
val (iBusRspContext, iBusRspContextOutput, injectorContext) = stage1ToInjectorPipe(fetchContext)
|
||||
|
||||
object PREDICTION_CONTEXT extends Stageable(PredictionResult())
|
||||
pipeline.decode.insert(PREDICTION_CONTEXT) := injectorContext
|
||||
|
@ -565,7 +570,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
|
|||
historyWrite.address := fetchPrediction.rsp.sourceLastWord(2, historyRamSizeLog2 bits)
|
||||
historyWrite.data.source := fetchPrediction.rsp.sourceLastWord.asBits >> 2 + historyRamSizeLog2
|
||||
historyWrite.data.target := fetchPrediction.rsp.finalPc
|
||||
if(compressedGen) historyWrite.data.unaligned := !fetchPrediction.stage.input(PC)(1) ^ fetchPrediction.stage.input(IS_RVC)
|
||||
if(compressedGen) historyWrite.data.last2Bytes := fetchPrediction.stage.input(PC)(1) && fetchPrediction.stage.input(IS_RVC)
|
||||
|
||||
when(fetchPrediction.rsp.wasRight) {
|
||||
historyWrite.valid := branchContext.hit
|
||||
|
@ -582,27 +587,31 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
|
|||
|
||||
historyWrite.valid clearWhen(branchContext.hazard || !branchStage.arbitration.isFiring)
|
||||
|
||||
val compressor = compressedGen generate new Area{
|
||||
val predictionBranch = iBusRspContext.hit && !iBusRspContext.hazard && iBusRspContext.line.branchWish(1)
|
||||
val unalignedWordIssue = iBusRsp.output.valid && predictionBranch && iBusRspContext.line.last2Bytes && Mux(decompressor.unaligned, !decompressor.isInputHighRvc, decompressor.isInputLowRvc && !decompressor.isInputHighRvc)
|
||||
|
||||
|
||||
val predictionFailure = ifGen(compressedGen && cmdToRspStageCount > 1)(new Area{
|
||||
val predictionBranch = decompressorContext.hit && !decompressorContext.hazard && decompressorContext.line.branchWish(1)
|
||||
val unalignedWordIssue = decompressor.bufferFill && decompressor.input.rsp.inst(17 downto 16) === 3 && predictionBranch
|
||||
val decompressorFailure = RegInit(False) setWhen(unalignedWordIssue) clearWhen(fetcherflushIt)
|
||||
val injectorFailure = Delay(decompressorFailure, cycleCount=if(injectorStage) 1 else 0, when=injector.decodeInput.ready)
|
||||
val bypassFailure = if(!injectorStage) False else decompressorFailure && !injector.decodeInput.valid
|
||||
|
||||
dynamicTargetFailureCorrection.valid := False
|
||||
dynamicTargetFailureCorrection.payload := decode.input(PC)
|
||||
when(injectorFailure || bypassFailure){
|
||||
when(unalignedWordIssue){
|
||||
historyWrite.valid := True
|
||||
historyWrite.address := (decode.input(PC) >> 2).resized
|
||||
historyWrite.address := (iBusRsp.stages(1).input.payload >> 2).resized
|
||||
historyWrite.data.branchWish := 0
|
||||
|
||||
decode.arbitration.isValid := False
|
||||
decode.arbitration.flushNext := True
|
||||
dynamicTargetFailureCorrection.valid := True
|
||||
iBusRsp.redoFetch := True
|
||||
}
|
||||
})
|
||||
|
||||
//Do not trigger prediction hit when it is one for the upper RVC word and we aren't there yet
|
||||
iBusRspContextOutput.hit clearWhen(iBusRspContext.line.last2Bytes && (decompressor.bufferValid || (!decompressor.throw2Bytes && decompressor.isInputLowRvc)))
|
||||
|
||||
decodePc.predictionPcLoad.valid := injectorContext.line.branchWish.msb && injectorContext.hit && !injectorContext.hazard && injector.decodeInput.fire
|
||||
decodePc.predictionPcLoad.payload := injectorContext.line.target
|
||||
|
||||
//Clean the RVC buffer when a prediction was made
|
||||
when(iBusRspContext.line.branchWish.msb && iBusRspContextOutput.hit && !iBusRspContext.hazard && decompressor.output.fire){
|
||||
decompressor.bufferValid := False
|
||||
decompressor.throw2BytesReg := False
|
||||
decompressor.input.ready := True //Drop the remaining byte if any
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ class HazardSimplePlugin(bypassExecute : Boolean = false,
|
|||
}
|
||||
|
||||
if(withWriteBackStage) trackHazardWithStage(writeBack,bypassWriteBack,null)
|
||||
if(withMemoryStage) trackHazardWithStage(memory ,bypassMemory ,BYPASSABLE_MEMORY_STAGE)
|
||||
if(withMemoryStage) trackHazardWithStage(memory ,bypassMemory, if(stages.last == memory) null else BYPASSABLE_MEMORY_STAGE)
|
||||
if(readStage != execute) trackHazardWithStage(execute ,bypassExecute , if(stages.last == execute) null else BYPASSABLE_EXECUTE_STAGE)
|
||||
|
||||
|
||||
|
|
|
@ -35,18 +35,21 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
|
|||
memoryTranslatorPortConfig : Any = null,
|
||||
injectorStage : Boolean = false,
|
||||
withoutInjectorStage : Boolean = false,
|
||||
relaxPredictorAddress : Boolean = true) extends IBusFetcherImpl(
|
||||
relaxPredictorAddress : Boolean = true,
|
||||
predictionBuffer : Boolean = true) extends IBusFetcherImpl(
|
||||
resetVector = resetVector,
|
||||
keepPcPlus4 = keepPcPlus4,
|
||||
decodePcGen = compressedGen,
|
||||
compressedGen = compressedGen,
|
||||
cmdToRspStageCount = (if(config.twoCycleCache) 2 else 1) + (if(relaxedPcCalculation) 1 else 0),
|
||||
pcRegReusedForSecondStage = true,
|
||||
allowPcRegReusedForSecondStage = true,
|
||||
injectorReadyCutGen = false,
|
||||
prediction = prediction,
|
||||
historyRamSizeLog2 = historyRamSizeLog2,
|
||||
injectorStage = (!config.twoCycleCache && !withoutInjectorStage) || injectorStage,
|
||||
relaxPredictorAddress = relaxPredictorAddress){
|
||||
relaxPredictorAddress = relaxPredictorAddress,
|
||||
fetchRedoGen = true,
|
||||
predictionBuffer = predictionBuffer){
|
||||
import config._
|
||||
|
||||
assert(isPow2(cacheSize))
|
||||
|
@ -58,10 +61,9 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
|
|||
var iBus : InstructionCacheMemBus = null
|
||||
var mmuBus : MemoryTranslatorBus = null
|
||||
var privilegeService : PrivilegeService = null
|
||||
var redoBranch : Flow[UInt] = null
|
||||
var decodeExceptionPort : Flow[ExceptionCause] = null
|
||||
val tightlyCoupledPorts = ArrayBuffer[TightlyCoupledPort]()
|
||||
|
||||
def tightlyGen = tightlyCoupledPorts.nonEmpty
|
||||
|
||||
def newTightlyCoupledPort(p : TightlyCoupledPortParameter) = {
|
||||
val port = TightlyCoupledPort(p, null)
|
||||
|
@ -86,9 +88,6 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
|
|||
FLUSH_ALL -> True
|
||||
))
|
||||
|
||||
|
||||
redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(pipeline.decode, priority = 1) //Priority 1 will win against branch predictor
|
||||
|
||||
if(catchSomething) {
|
||||
val exceptionService = pipeline.service(classOf[ExceptionService])
|
||||
decodeExceptionPort = exceptionService.newExceptionPort(pipeline.decode,1)
|
||||
|
@ -125,7 +124,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
|
|||
import pipeline.config._
|
||||
|
||||
pipeline plug new FetchArea(pipeline) {
|
||||
val cache = new InstructionCache(IBusCachedPlugin.this.config)
|
||||
val cache = new InstructionCache(IBusCachedPlugin.this.config.copy(bypassGen = tightlyGen), if(mmuBus != null) mmuBus.p else MemoryTranslatorBusParameter(0,0))
|
||||
iBus = master(new InstructionCacheMemBus(IBusCachedPlugin.this.config)).setName("iBus")
|
||||
iBus <> cache.io.mem
|
||||
iBus.cmd.address.allowOverride := cache.io.mem.cmd.address
|
||||
|
@ -156,8 +155,13 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
|
|||
cache.io.cpu.prefetch.pc := stages(0).input.payload
|
||||
stages(0).halt setWhen (cache.io.cpu.prefetch.haltIt)
|
||||
|
||||
|
||||
cache.io.cpu.fetch.isRemoved := fetcherflushIt
|
||||
if(mmuBus != null && mmuBus.p.latency == 1) {
|
||||
stages(0).halt setWhen(mmuBus.busy)
|
||||
mmuBus.cmd(0).isValid := cache.io.cpu.prefetch.isValid
|
||||
mmuBus.cmd(0).isStuck := !stages(0).input.ready
|
||||
mmuBus.cmd(0).virtualAddress := cache.io.cpu.prefetch.pc
|
||||
mmuBus.cmd(0).bypassTranslation := False
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -165,16 +169,23 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
|
|||
val tightlyCoupledHits = RegNextWhen(s0.tightlyCoupledHits, stages(1).input.ready)
|
||||
val tightlyCoupledHit = RegNextWhen(s0.tightlyCoupledHit, stages(1).input.ready)
|
||||
|
||||
cache.io.cpu.fetch.dataBypassValid := tightlyCoupledHit
|
||||
cache.io.cpu.fetch.dataBypass := (if(tightlyCoupledPorts.isEmpty) B(0) else MuxOH(tightlyCoupledHits, tightlyCoupledPorts.map(e => CombInit(e.bus.data))))
|
||||
if(tightlyGen) cache.io.cpu.fetch.dataBypassValid := tightlyCoupledHit
|
||||
if(tightlyGen) cache.io.cpu.fetch.dataBypass := MuxOH(tightlyCoupledHits, tightlyCoupledPorts.map(e => CombInit(e.bus.data)))
|
||||
|
||||
//Connect fetch cache side
|
||||
cache.io.cpu.fetch.isValid := stages(1).input.valid && !tightlyCoupledHit
|
||||
cache.io.cpu.fetch.isStuck := !stages(1).input.ready
|
||||
cache.io.cpu.fetch.pc := stages(1).input.payload
|
||||
|
||||
if(mmuBus != null) {
|
||||
mmuBus.cmd.last.isValid := cache.io.cpu.fetch.isValid
|
||||
mmuBus.cmd.last.isStuck := !stages(1).input.ready
|
||||
mmuBus.cmd.last.virtualAddress := cache.io.cpu.fetch.pc
|
||||
mmuBus.cmd.last.bypassTranslation := False
|
||||
mmuBus.end := stages(1).input.ready || externalFlush
|
||||
if (mmuBus.p.latency == 0) stages(1).halt setWhen (mmuBus.busy)
|
||||
}
|
||||
|
||||
stages(1).halt setWhen(cache.io.cpu.fetch.haltIt)
|
||||
|
||||
if (!twoCycleCache) {
|
||||
cache.io.cpu.fetch.isUser := privilegeService.isUser()
|
||||
|
@ -211,7 +222,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
|
|||
if (catchSomething) {
|
||||
decodeExceptionPort.valid := False
|
||||
decodeExceptionPort.code.assignDontCare()
|
||||
decodeExceptionPort.badAddr := cacheRsp.pc(31 downto 2) @@ "00"
|
||||
decodeExceptionPort.badAddr := cacheRsp.pc(31 downto 2) @@ U"00"
|
||||
}
|
||||
|
||||
when(cacheRsp.isValid && cacheRsp.mmuRefilling && !issueDetected) {
|
||||
|
@ -237,19 +248,9 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
|
|||
decodeExceptionPort.code := 1
|
||||
}
|
||||
|
||||
when(!iBusRsp.readyForError){
|
||||
redoFetch := False
|
||||
cache.io.cpu.fill.valid := False
|
||||
when(redoFetch) {
|
||||
iBusRsp.redoFetch := True
|
||||
}
|
||||
// when(pipeline.stages.map(_.arbitration.flushIt).orR){
|
||||
// cache.io.cpu.fill.valid := False
|
||||
// }
|
||||
|
||||
|
||||
|
||||
redoBranch.valid := redoFetch
|
||||
redoBranch.payload := (if (decodePcGen) decode.input(PC) else cacheRsp.pc)
|
||||
decode.arbitration.flushNext setWhen(redoBranch.valid)
|
||||
|
||||
|
||||
cacheRspArbitration.halt setWhen (issueDetected || iBusRspOutputHalt)
|
||||
|
@ -260,16 +261,15 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
|
|||
}
|
||||
|
||||
if (mmuBus != null) {
|
||||
cache.io.cpu.fetch.mmuBus <> mmuBus
|
||||
cache.io.cpu.fetch.mmuRsp <> mmuBus.rsp
|
||||
} 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.isIoAccess := False
|
||||
cache.io.cpu.fetch.mmuBus.rsp.exception := False
|
||||
cache.io.cpu.fetch.mmuBus.rsp.refilling := False
|
||||
cache.io.cpu.fetch.mmuBus.busy := False
|
||||
cache.io.cpu.fetch.mmuRsp.physicalAddress := cache.io.cpu.fetch.pc
|
||||
cache.io.cpu.fetch.mmuRsp.allowExecute := True
|
||||
cache.io.cpu.fetch.mmuRsp.allowRead := True
|
||||
cache.io.cpu.fetch.mmuRsp.allowWrite := True
|
||||
cache.io.cpu.fetch.mmuRsp.isIoAccess := False
|
||||
cache.io.cpu.fetch.mmuRsp.exception := False
|
||||
cache.io.cpu.fetch.mmuRsp.refilling := False
|
||||
}
|
||||
|
||||
val flushStage = decode
|
||||
|
|
|
@ -83,7 +83,7 @@ object IBusSimpleBus{
|
|||
canRead = true,
|
||||
canWrite = false,
|
||||
alignment = BmbParameter.BurstAlignement.LENGTH,
|
||||
maximumPendingTransactionPerId = if(plugin != null) plugin.pendingMax else Int.MaxValue
|
||||
maximumPendingTransaction = if(plugin != null) plugin.pendingMax else Int.MaxValue
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -233,27 +233,31 @@ class IBusSimplePlugin( resetVector : BigInt,
|
|||
val rspHoldValue : Boolean = false,
|
||||
val singleInstructionPipeline : Boolean = false,
|
||||
val memoryTranslatorPortConfig : Any = null,
|
||||
relaxPredictorAddress : Boolean = true
|
||||
relaxPredictorAddress : Boolean = true,
|
||||
predictionBuffer : Boolean = true
|
||||
) extends IBusFetcherImpl(
|
||||
resetVector = resetVector,
|
||||
keepPcPlus4 = keepPcPlus4,
|
||||
decodePcGen = compressedGen,
|
||||
compressedGen = compressedGen,
|
||||
cmdToRspStageCount = busLatencyMin + (if(cmdForkOnSecondStage) 1 else 0),
|
||||
pcRegReusedForSecondStage = !(cmdForkOnSecondStage && cmdForkPersistence),
|
||||
allowPcRegReusedForSecondStage = !(cmdForkOnSecondStage && cmdForkPersistence),
|
||||
injectorReadyCutGen = false,
|
||||
prediction = prediction,
|
||||
historyRamSizeLog2 = historyRamSizeLog2,
|
||||
injectorStage = injectorStage,
|
||||
relaxPredictorAddress = relaxPredictorAddress){
|
||||
relaxPredictorAddress = relaxPredictorAddress,
|
||||
fetchRedoGen = memoryTranslatorPortConfig != null,
|
||||
predictionBuffer = predictionBuffer){
|
||||
|
||||
var iBus : IBusSimpleBus = null
|
||||
var decodeExceptionPort : Flow[ExceptionCause] = null
|
||||
val catchSomething = memoryTranslatorPortConfig != null || catchAccessFault
|
||||
var mmuBus : MemoryTranslatorBus = null
|
||||
var redoBranch : Flow[UInt] = null
|
||||
|
||||
if(rspHoldValue) assert(busLatencyMin <= 1)
|
||||
// if(rspHoldValue) assert(busLatencyMin <= 1)
|
||||
assert(!rspHoldValue, "rspHoldValue not supported yet")
|
||||
assert(!singleInstructionPipeline)
|
||||
|
||||
override def setup(pipeline: VexRiscv): Unit = {
|
||||
super.setup(pipeline)
|
||||
|
@ -268,7 +272,6 @@ class IBusSimplePlugin( resetVector : BigInt,
|
|||
|
||||
if(memoryTranslatorPortConfig != null) {
|
||||
mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(MemoryTranslatorPort.PRIORITY_INSTRUCTION, memoryTranslatorPortConfig)
|
||||
redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(pipeline.decode, priority = 1) //Priority 1 will win against branch predictor
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -282,9 +285,12 @@ class IBusSimplePlugin( resetVector : BigInt,
|
|||
iBus.cmd << (if(cmdWithS2mPipe) cmd.s2mPipe() else cmd)
|
||||
|
||||
//Avoid sending to many iBus cmd
|
||||
val pendingCmd = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0)
|
||||
val pendingCmdNext = pendingCmd + cmd.fire.asUInt - iBus.rsp.fire.asUInt
|
||||
pendingCmd := pendingCmdNext
|
||||
val pending = new Area{
|
||||
val inc, dec = Bool()
|
||||
val value = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0)
|
||||
val next = value + U(inc) - U(dec)
|
||||
value := next
|
||||
}
|
||||
|
||||
val secondStagePersistence = cmdForkPersistence && cmdForkOnSecondStage && !cmdWithS2mPipe
|
||||
def cmdForkStage = if(!secondStagePersistence) iBusRsp.stages(if(cmdForkOnSecondStage) 1 else 0) else iBusRsp.stages(1)
|
||||
|
@ -292,104 +298,98 @@ class IBusSimplePlugin( resetVector : BigInt,
|
|||
val cmdFork = if(!secondStagePersistence) new Area {
|
||||
//This implementation keep the cmd on the bus until it's executed or the the pipeline is flushed
|
||||
def stage = cmdForkStage
|
||||
stage.halt setWhen(stage.input.valid && (!cmd.valid || !cmd.ready))
|
||||
if(singleInstructionPipeline) {
|
||||
cmd.valid := stage.input.valid && pendingCmd =/= pendingMax && !stages.map(_.arbitration.isValid).orR
|
||||
assert(injectorStage == false)
|
||||
assert(iBusRsp.stages.dropWhile(_ != stage).length <= 2)
|
||||
}else {
|
||||
cmd.valid := stage.input.valid && stage.output.ready && pendingCmd =/= pendingMax
|
||||
}
|
||||
val canEmit = stage.output.ready && pending.value =/= pendingMax
|
||||
stage.halt setWhen(stage.input.valid && (!canEmit || !cmd.ready))
|
||||
cmd.valid := stage.input.valid && canEmit
|
||||
pending.inc := cmd.fire
|
||||
} else new Area{
|
||||
//This implementation keep the cmd on the bus until it's executed, even if the pipeline is flushed
|
||||
def stage = cmdForkStage
|
||||
val pendingFull = pendingCmd === pendingMax
|
||||
val cmdKeep = RegInit(False) setWhen(cmd.valid) clearWhen(cmd.ready)
|
||||
val pendingFull = pending.value === pendingMax
|
||||
val enterTheMarket = Bool()
|
||||
val cmdKeep = RegInit(False) setWhen(enterTheMarket) clearWhen(cmd.ready)
|
||||
val cmdFired = RegInit(False) setWhen(cmd.fire) clearWhen(stage.input.ready)
|
||||
stage.halt setWhen(cmd.isStall || (pendingFull && !cmdFired))
|
||||
cmd.valid := (stage.input.valid || cmdKeep) && !pendingFull && !cmdFired
|
||||
enterTheMarket := stage.input.valid && !pendingFull && !cmdFired && !cmdKeep
|
||||
// stage.halt setWhen(cmd.isStall || (pendingFull && !cmdFired)) //(cmd.isStall)
|
||||
stage.halt setWhen(pendingFull && !cmdFired && !cmdKeep)
|
||||
stage.halt setWhen(!cmd.ready && !cmdFired)
|
||||
cmd.valid := enterTheMarket || cmdKeep
|
||||
pending.inc := enterTheMarket
|
||||
}
|
||||
|
||||
val mmu = (mmuBus != null) generate new Area {
|
||||
mmuBus.cmd.isValid := cmdForkStage.input.valid
|
||||
mmuBus.cmd.virtualAddress := cmdForkStage.input.payload
|
||||
mmuBus.cmd.bypassTranslation := False
|
||||
mmuBus.end := cmdForkStage.output.fire || fetcherflushIt
|
||||
mmuBus.cmd.last.isValid := cmdForkStage.input.valid
|
||||
mmuBus.cmd.last.virtualAddress := cmdForkStage.input.payload
|
||||
mmuBus.cmd.last.bypassTranslation := False
|
||||
mmuBus.end := cmdForkStage.output.fire || externalFlush
|
||||
|
||||
cmd.pc := mmuBus.rsp.physicalAddress(31 downto 2) @@ "00"
|
||||
cmd.pc := mmuBus.rsp.physicalAddress(31 downto 2) @@ U"00"
|
||||
|
||||
//do not emit memory request if MMU miss
|
||||
when(mmuBus.rsp.exception || mmuBus.rsp.refilling){
|
||||
cmdForkStage.halt := False
|
||||
cmd.valid := False
|
||||
}
|
||||
|
||||
when(mmuBus.busy){
|
||||
cmdForkStage.input.valid := False
|
||||
cmdForkStage.input.ready := False
|
||||
//do not emit memory request if MMU had issues
|
||||
when(cmdForkStage.input.valid) {
|
||||
when(mmuBus.rsp.refilling) {
|
||||
cmdForkStage.halt := True
|
||||
cmd.valid := False
|
||||
}
|
||||
when(mmuBus.rsp.exception) {
|
||||
cmdForkStage.halt := False
|
||||
cmd.valid := False
|
||||
}
|
||||
}
|
||||
|
||||
val joinCtx = stageXToIBusRsp(cmdForkStage, mmuBus.rsp)
|
||||
}
|
||||
|
||||
val mmuLess = (mmuBus == null) generate new Area{
|
||||
cmd.pc := cmdForkStage.input.payload(31 downto 2) @@ "00"
|
||||
cmd.pc := cmdForkStage.input.payload(31 downto 2) @@ U"00"
|
||||
}
|
||||
|
||||
val rspJoin = new Area {
|
||||
import iBusRsp._
|
||||
//Manage flush for iBus transactions in flight
|
||||
val discardCounter = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0)
|
||||
discardCounter := discardCounter - (iBus.rsp.fire && discardCounter =/= 0).asUInt
|
||||
when(fetcherflushIt) {
|
||||
if(secondStagePersistence)
|
||||
discardCounter := pendingCmd + cmd.valid.asUInt - iBus.rsp.fire.asUInt
|
||||
else
|
||||
discardCounter := (if(cmdForkOnSecondStage) pendingCmdNext else pendingCmd - iBus.rsp.fire.asUInt)
|
||||
}
|
||||
|
||||
val rspBufferOutput = Stream(IBusSimpleRsp())
|
||||
|
||||
val rspBuffer = if(!rspHoldValue) new Area{
|
||||
val rspBuffer = new Area {
|
||||
val output = Stream(IBusSimpleRsp())
|
||||
val c = StreamFifoLowLatency(IBusSimpleRsp(), busLatencyMin + (if(cmdForkOnSecondStage && cmdForkPersistence) 1 else 0))
|
||||
c.io.push << iBus.rsp.throwWhen(discardCounter =/= 0).toStream
|
||||
c.io.flush := fetcherflushIt
|
||||
rspBufferOutput << c.io.pop
|
||||
} else new Area{
|
||||
val rspStream = iBus.rsp.throwWhen(discardCounter =/= 0).toStream
|
||||
val validReg = RegInit(False) setWhen(rspStream.valid) clearWhen(rspBufferOutput.ready)
|
||||
rspBufferOutput << rspStream
|
||||
rspBufferOutput.valid setWhen(validReg)
|
||||
val discardCounter = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0)
|
||||
discardCounter := discardCounter - (c.io.pop.valid && discardCounter =/= 0).asUInt
|
||||
when(iBusRsp.flush) {
|
||||
discardCounter := (if(cmdForkOnSecondStage) pending.next else pending.value - U(pending.dec))
|
||||
}
|
||||
|
||||
c.io.push << iBus.rsp.toStream
|
||||
// if(compressedGen) c.io.flush setWhen(decompressor.consumeCurrent)
|
||||
// if(!compressedGen && isDrivingDecode(IBUS_RSP)) c.io.flush setWhen(decode.arbitration.flushNext && iBusRsp.output.ready)
|
||||
val flush = discardCounter =/= 0 || iBusRsp.flush
|
||||
output.valid := c.io.pop.valid && discardCounter === 0
|
||||
output.payload := c.io.pop.payload
|
||||
c.io.pop.ready := output.ready || flush
|
||||
|
||||
pending.dec := c.io.pop.fire // iBus.rsp.valid && flush || c.io.pop.valid && output.ready instead to avoid unecessary dependancies ?
|
||||
}
|
||||
|
||||
val fetchRsp = FetchRsp()
|
||||
fetchRsp.pc := stages.last.output.payload
|
||||
fetchRsp.rsp := rspBufferOutput.payload
|
||||
fetchRsp.rsp.error.clearWhen(!rspBufferOutput.valid) //Avoid interference with instruction injection from the debug plugin
|
||||
|
||||
fetchRsp.rsp := rspBuffer.output.payload
|
||||
fetchRsp.rsp.error.clearWhen(!rspBuffer.output.valid) //Avoid interference with instruction injection from the debug plugin
|
||||
|
||||
val join = Stream(FetchRsp())
|
||||
val exceptionDetected = False
|
||||
val redoRequired = False
|
||||
join.valid := stages.last.output.valid && rspBufferOutput.valid
|
||||
join.valid := stages.last.output.valid && rspBuffer.output.valid
|
||||
join.payload := fetchRsp
|
||||
stages.last.output.ready := stages.last.output.valid ? join.fire | join.ready
|
||||
rspBufferOutput.ready := join.fire
|
||||
output << join.haltWhen(exceptionDetected || redoRequired)
|
||||
rspBuffer.output.ready := join.fire
|
||||
output << join.haltWhen(exceptionDetected)
|
||||
|
||||
if(memoryTranslatorPortConfig != null){
|
||||
redoRequired setWhen( stages.last.input.valid && mmu.joinCtx.refilling)
|
||||
redoBranch.valid := redoRequired && iBusRsp.readyForError
|
||||
redoBranch.payload := decode.input(PC)
|
||||
|
||||
decode.arbitration.flushIt setWhen(redoBranch.valid)
|
||||
decode.arbitration.flushNext setWhen(redoBranch.valid)
|
||||
when(stages.last.input.valid && mmu.joinCtx.refilling) {
|
||||
iBusRsp.redoFetch := True
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(catchSomething){
|
||||
decodeExceptionPort.code.assignDontCare()
|
||||
decodeExceptionPort.badAddr := join.pc(31 downto 2) @@ "00"
|
||||
decodeExceptionPort.badAddr := join.pc(31 downto 2) @@ U"00"
|
||||
|
||||
if(catchAccessFault) when(join.valid && join.rsp.error){
|
||||
decodeExceptionPort.code := 1
|
||||
|
|
|
@ -22,8 +22,8 @@ class MemoryTranslatorPlugin(tlbSize : Int,
|
|||
val portsInfo = ArrayBuffer[MemoryTranslatorPort]()
|
||||
|
||||
override def newTranslationPort(priority : Int,args : Any): MemoryTranslatorBus = {
|
||||
// val exceptionBus = pipeline.service(classOf[ExceptionService]).newExceptionPort(stage)
|
||||
val port = MemoryTranslatorPort(MemoryTranslatorBus(),priority,args.asInstanceOf[MemoryTranslatorPortConfig]/*,exceptionBus*/)
|
||||
val config = args.asInstanceOf[MemoryTranslatorPortConfig]
|
||||
val port = MemoryTranslatorPort(MemoryTranslatorBus(MemoryTranslatorBusParameter(wayCount = 0)),priority, config/*,exceptionBus*/)
|
||||
portsInfo += port
|
||||
port.bus
|
||||
}
|
||||
|
@ -70,17 +70,17 @@ class MemoryTranslatorPlugin(tlbSize : Int,
|
|||
|
||||
val ports = for ((port, portId) <- sortedPortsInfo.zipWithIndex) yield new Area {
|
||||
val cache = Vec(Reg(CacheLine()) init, port.args.portTlbSize)
|
||||
val cacheHits = cache.map(line => line.valid && line.virtualAddress === port.bus.cmd.virtualAddress(31 downto 12))
|
||||
val cacheHits = cache.map(line => line.valid && line.virtualAddress === port.bus.cmd.last.virtualAddress(31 downto 12))
|
||||
val cacheHit = cacheHits.asBits.orR
|
||||
val cacheLine = MuxOH(cacheHits, cache)
|
||||
val isInMmuRange = virtualRange(port.bus.cmd.virtualAddress) && !port.bus.cmd.bypassTranslation
|
||||
val isInMmuRange = virtualRange(port.bus.cmd.last.virtualAddress) && !port.bus.cmd.last.bypassTranslation
|
||||
|
||||
val sharedMiss = RegInit(False)
|
||||
val sharedIterator = Reg(UInt(log2Up(tlbSize + 1) bits))
|
||||
val sharedAccessed = RegInit(B"00")
|
||||
val entryToReplace = Counter(port.args.portTlbSize)
|
||||
|
||||
val sharedAccessAsked = RegNext(port.bus.cmd.isValid && !cacheHit && sharedIterator < tlbSize && isInMmuRange)
|
||||
val sharedAccessAsked = RegNext(port.bus.cmd.last.isValid && !cacheHit && sharedIterator < tlbSize && isInMmuRange)
|
||||
val sharedAccessGranted = sharedAccessAsked && shared.free
|
||||
when(sharedAccessGranted) {
|
||||
shared.readAddr := sharedIterator.resized
|
||||
|
@ -92,7 +92,7 @@ class MemoryTranslatorPlugin(tlbSize : Int,
|
|||
}
|
||||
|
||||
when(sharedAccessed.msb){
|
||||
when(shared.readData.virtualAddress === port.bus.cmd.virtualAddress(31 downto 12)){
|
||||
when(shared.readData.virtualAddress === port.bus.cmd.last.virtualAddress(31 downto 12)){
|
||||
cache(entryToReplace) := shared.readData
|
||||
entryToReplace.increment()
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ class MemoryTranslatorPlugin(tlbSize : Int,
|
|||
|
||||
|
||||
when(isInMmuRange) {
|
||||
port.bus.rsp.physicalAddress := cacheLine.physicalAddress @@ port.bus.cmd.virtualAddress(11 downto 0)
|
||||
port.bus.rsp.physicalAddress := cacheLine.physicalAddress @@ port.bus.cmd.last.virtualAddress(11 downto 0)
|
||||
port.bus.rsp.allowRead := cacheLine.allowRead
|
||||
port.bus.rsp.allowWrite := cacheLine.allowWrite
|
||||
port.bus.rsp.allowExecute := cacheLine.allowExecute
|
||||
|
@ -116,7 +116,7 @@ class MemoryTranslatorPlugin(tlbSize : Int,
|
|||
// 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.physicalAddress := port.bus.cmd.last.virtualAddress
|
||||
port.bus.rsp.allowRead := True
|
||||
port.bus.rsp.allowWrite := True
|
||||
port.bus.rsp.allowExecute := True
|
||||
|
|
|
@ -50,7 +50,7 @@ object RvcDecompressor{
|
|||
ret := (i(11 downto 7) === 2) ? addi16sp | lui
|
||||
}
|
||||
is(12){
|
||||
val isImmediate = i(11 downto 10) =/= "11"
|
||||
val isImmediate = i(11 downto 10) =/= B"11"
|
||||
val isShift = !i(11)
|
||||
val func3 = i(11 downto 10).mux(
|
||||
0 -> B"101",
|
||||
|
@ -64,7 +64,7 @@ object RvcDecompressor{
|
|||
)
|
||||
)
|
||||
val msbs = Mux(
|
||||
sel = i(11 downto 10) === "10",
|
||||
sel = i(11 downto 10) === B"10",
|
||||
whenTrue = B((6 downto 0) -> i(12)), //andi
|
||||
whenFalse = B"0" ## (i(11 downto 10) === B"01" || (i(11 downto 10) === B"11" && i(6 downto 5) === B"00")) ## B"00000"
|
||||
)
|
||||
|
@ -122,7 +122,7 @@ object StreamForkVex{
|
|||
|
||||
object StreamVexPimper{
|
||||
implicit class StreamFlushPimper[T <: Data](pimped : Stream[T]){
|
||||
def m2sPipeWithFlush(flush : Bool, discardInput : Boolean = true, collapsBubble : Boolean = true): Stream[T] = {
|
||||
def m2sPipeWithFlush(flush : Bool, discardInput : Boolean = true, collapsBubble : Boolean = true, flushInput : Bool = null): Stream[T] = {
|
||||
val ret = cloneOf(pimped)
|
||||
|
||||
val rValid = RegInit(False)
|
||||
|
@ -132,7 +132,10 @@ object StreamVexPimper{
|
|||
pimped.ready := (Bool(collapsBubble) && !ret.valid) || ret.ready
|
||||
|
||||
when(pimped.ready) {
|
||||
rValid := pimped.valid
|
||||
if(flushInput == null)
|
||||
rValid := pimped.valid
|
||||
else
|
||||
rValid := pimped.valid && !flushInput
|
||||
rData := pimped.payload
|
||||
}
|
||||
|
||||
|
|
|
@ -34,9 +34,9 @@ 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 MmuPort(bus : MemoryTranslatorBus, priority : Int, args : MmuPortConfig, id : Int)
|
||||
|
||||
case class MmuPortConfig(portTlbSize : Int)
|
||||
case class MmuPortConfig(portTlbSize : Int, latency : Int = 0, earlyRequireMmuLockup : Boolean = false, earlyCacheHits : Boolean = false)
|
||||
|
||||
class MmuPlugin(ioRange : UInt => Bool,
|
||||
virtualRange : UInt => Bool = address => True,
|
||||
|
@ -47,7 +47,8 @@ class MmuPlugin(ioRange : UInt => Bool,
|
|||
val portsInfo = ArrayBuffer[MmuPort]()
|
||||
|
||||
override def newTranslationPort(priority : Int,args : Any): MemoryTranslatorBus = {
|
||||
val port = MmuPort(MemoryTranslatorBus(),priority,args.asInstanceOf[MmuPortConfig], portsInfo.length)
|
||||
val config = args.asInstanceOf[MmuPortConfig]
|
||||
val port = MmuPort(MemoryTranslatorBus(MemoryTranslatorBusParameter(wayCount = config.portTlbSize, latency = config.latency)),priority, config, portsInfo.length)
|
||||
portsInfo += port
|
||||
port.bus
|
||||
}
|
||||
|
@ -71,7 +72,7 @@ class MmuPlugin(ioRange : UInt => Bool,
|
|||
val csrService = pipeline.service(classOf[CsrInterface])
|
||||
|
||||
//Sorted by priority
|
||||
val sortedPortsInfo = portsInfo.sortWith((a,b) => a.priority > b.priority)
|
||||
val sortedPortsInfo = portsInfo.sortBy(_.priority)
|
||||
|
||||
case class CacheLine() extends Bundle {
|
||||
val valid, exception, superPage = Bool
|
||||
|
@ -103,33 +104,55 @@ class MmuPlugin(ioRange : UInt => Bool,
|
|||
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
|
||||
val cache = Vec(Reg(CacheLine()) init, port.args.portTlbSize)
|
||||
val dirty = RegInit(False).allowUnsetRegToAvoidLatch
|
||||
if(port.args.earlyRequireMmuLockup){
|
||||
dirty clearWhen(!port.bus.cmd.last.isStuck)
|
||||
}
|
||||
|
||||
def toRsp[T <: Data](data : T, from : MemoryTranslatorCmd) : T = from match {
|
||||
case _ if from == port.bus.cmd.last => data
|
||||
case _ => {
|
||||
val next = port.bus.cmd.dropWhile(_ != from)(1)
|
||||
toRsp(RegNextWhen(data, !next.isStuck), next)
|
||||
}
|
||||
}
|
||||
val requireMmuLockupCmd = port.bus.cmd.takeRight(if(port.args.earlyRequireMmuLockup) 2 else 1).head
|
||||
|
||||
val requireMmuLockupCalc = virtualRange(requireMmuLockupCmd.virtualAddress) && !requireMmuLockupCmd.bypassTranslation && csr.satp.mode
|
||||
if(!enableMmuInMachineMode) {
|
||||
requireMmuLockup clearWhen(!csr.status.mprv && privilegeService.isMachine())
|
||||
requireMmuLockupCalc clearWhen(!csr.status.mprv && privilegeService.isMachine())
|
||||
when(privilegeService.isMachine()) {
|
||||
if (port.priority == MmuPort.PRIORITY_DATA) {
|
||||
requireMmuLockup clearWhen (!csr.status.mprv || pipeline(MPP) === 3)
|
||||
requireMmuLockupCalc clearWhen (!csr.status.mprv || pipeline(MPP) === 3)
|
||||
} else {
|
||||
requireMmuLockup := False
|
||||
requireMmuLockupCalc := False
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val cacheHitsCmd = port.bus.cmd.takeRight(if(port.args.earlyCacheHits) 2 else 1).head
|
||||
val cacheHitsCalc = B(cache.map(line => line.valid && line.virtualAddress(1) === cacheHitsCmd.virtualAddress(31 downto 22) && (line.superPage || line.virtualAddress(0) === cacheHitsCmd.virtualAddress(21 downto 12))))
|
||||
|
||||
|
||||
val requireMmuLockup = toRsp(requireMmuLockupCalc, requireMmuLockupCmd)
|
||||
val cacheHits = toRsp(cacheHitsCalc, cacheHitsCmd)
|
||||
|
||||
val cacheHit = cacheHits.asBits.orR
|
||||
val cacheLine = MuxOH(cacheHits, cache)
|
||||
val entryToReplace = Counter(port.args.portTlbSize)
|
||||
|
||||
|
||||
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.physicalAddress := cacheLine.physicalAddress(1) @@ (cacheLine.superPage ? port.bus.cmd.last.virtualAddress(21 downto 12) | cacheLine.physicalAddress(0)) @@ port.bus.cmd.last.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
|
||||
port.bus.rsp.exception := !dirty && cacheHit && (cacheLine.exception || cacheLine.allowUser && privilegeService.isSupervisor() && !csr.status.sum || !cacheLine.allowUser && privilegeService.isUser())
|
||||
port.bus.rsp.refilling := dirty || !cacheHit
|
||||
} otherwise {
|
||||
port.bus.rsp.physicalAddress := port.bus.cmd.virtualAddress
|
||||
port.bus.rsp.physicalAddress := port.bus.cmd.last.virtualAddress
|
||||
port.bus.rsp.allowRead := True
|
||||
port.bus.rsp.allowWrite := True
|
||||
port.bus.rsp.allowExecute := True
|
||||
|
@ -138,6 +161,12 @@ class MmuPlugin(ioRange : UInt => Bool,
|
|||
}
|
||||
port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress)
|
||||
|
||||
port.bus.rsp.bypassTranslation := !requireMmuLockup
|
||||
for(wayId <- 0 until port.args.portTlbSize){
|
||||
port.bus.rsp.ways(wayId).sel := cacheHits(wayId)
|
||||
port.bus.rsp.ways(wayId).physical := cache(wayId).physicalAddress(1) @@ (cache(wayId).superPage ? port.bus.cmd.last.virtualAddress(21 downto 12) | cache(wayId).physicalAddress(0)) @@ port.bus.cmd.last.virtualAddress(11 downto 0)
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
@ -155,21 +184,23 @@ class MmuPlugin(ioRange : UInt => Bool,
|
|||
}
|
||||
val state = RegInit(State.IDLE)
|
||||
val vpn = Reg(Vec(UInt(10 bits), UInt(10 bits)))
|
||||
val portId = Reg(UInt(log2Up(portsInfo.length) bits))
|
||||
val portSortedOh = Reg(Bits(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 dBusRspStaged = dBusAccess.rsp.stage()
|
||||
val dBusRsp = new Area{
|
||||
val pte = PTE()
|
||||
pte.assignFromBits(dBusAccess.rsp.data)
|
||||
val exception = !pte.V || (!pte.R && pte.W) || dBusAccess.rsp.error
|
||||
pte.assignFromBits(dBusRspStaged.data)
|
||||
val exception = !pte.V || (!pte.R && pte.W) || dBusRspStaged.error
|
||||
val leaf = pte.R || pte.X
|
||||
}
|
||||
|
||||
val pteBuffer = RegNextWhen(dBusRsp.pte, dBusAccess.rsp.valid && !dBusAccess.rsp.redo)
|
||||
val pteBuffer = RegNextWhen(dBusRsp.pte, dBusRspStaged.valid && !dBusRspStaged.redo)
|
||||
|
||||
dBusAccess.cmd.valid := False
|
||||
dBusAccess.cmd.write := False
|
||||
|
@ -177,16 +208,25 @@ class MmuPlugin(ioRange : UInt => Bool,
|
|||
dBusAccess.cmd.address.assignDontCare()
|
||||
dBusAccess.cmd.data.assignDontCare()
|
||||
dBusAccess.cmd.writeMask.assignDontCare()
|
||||
|
||||
val refills = OHMasking.last(B(ports.map(port => port.handle.bus.cmd.last.isValid && port.requireMmuLockup && !port.dirty && !port.cacheHit)))
|
||||
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
|
||||
}
|
||||
when(refills.orR){
|
||||
portSortedOh := refills
|
||||
state := State.L1_CMD
|
||||
val address = MuxOH(refills, sortedPortsInfo.map(_.bus.cmd.last.virtualAddress))
|
||||
vpn(1) := address(31 downto 22)
|
||||
vpn(0) := address(21 downto 12)
|
||||
}
|
||||
// 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
|
||||
|
@ -196,12 +236,12 @@ class MmuPlugin(ioRange : UInt => Bool,
|
|||
}
|
||||
}
|
||||
is(State.L1_RSP){
|
||||
when(dBusAccess.rsp.valid){
|
||||
when(dBusRspStaged.valid){
|
||||
state := State.L0_CMD
|
||||
when(dBusRsp.leaf || dBusRsp.exception){
|
||||
state := State.IDLE
|
||||
}
|
||||
when(dBusAccess.rsp.redo){
|
||||
when(dBusRspStaged.redo){
|
||||
state := State.L1_CMD
|
||||
}
|
||||
}
|
||||
|
@ -214,23 +254,26 @@ class MmuPlugin(ioRange : UInt => Bool,
|
|||
}
|
||||
}
|
||||
is(State.L0_RSP){
|
||||
when(dBusAccess.rsp.valid) {
|
||||
when(dBusRspStaged.valid) {
|
||||
state := State.IDLE
|
||||
when(dBusAccess.rsp.redo){
|
||||
when(dBusRspStaged.redo){
|
||||
state := State.L0_CMD
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(port <- ports) {
|
||||
port.handle.bus.busy := state =/= State.IDLE && portId === port.id
|
||||
for((port, id) <- sortedPortsInfo.zipWithIndex) {
|
||||
port.bus.busy := state =/= State.IDLE && portSortedOh(id)
|
||||
}
|
||||
|
||||
when(dBusAccess.rsp.valid && !dBusAccess.rsp.redo && (dBusRsp.leaf || dBusRsp.exception)){
|
||||
for(port <- ports){
|
||||
when(portId === port.id) {
|
||||
when(dBusRspStaged.valid && !dBusRspStaged.redo && (dBusRsp.leaf || dBusRsp.exception)){
|
||||
for((port, id) <- ports.zipWithIndex) {
|
||||
when(portSortedOh(id)) {
|
||||
port.entryToReplace.increment()
|
||||
if(port.handle.args.earlyRequireMmuLockup) {
|
||||
port.dirty := True
|
||||
} //Avoid having non coherent TLB lookup
|
||||
for ((line, lineId) <- port.cache.zipWithIndex) {
|
||||
when(port.entryToReplace === lineId){
|
||||
val superPage = state === State.L1_RSP
|
||||
|
@ -254,9 +297,16 @@ class MmuPlugin(ioRange : UInt => Bool,
|
|||
val fenceStage = stages.last
|
||||
fenceStage plug new Area{
|
||||
import fenceStage._
|
||||
when(arbitration.isValid && input(IS_SFENCE_VMA)){ // || csrService.isWriting(CSR.SATP)
|
||||
when(arbitration.isValid && input(IS_SFENCE_VMA)){
|
||||
for(port <- core.ports; line <- port.cache) line.valid := False //Assume that the instruction already fetched into the pipeline are ok
|
||||
}
|
||||
|
||||
csrService.duringWrite(CSR.SATP){
|
||||
for(port <- core.ports; line <- port.cache) line.valid := False
|
||||
core.ports.filter(_.handle.args.earlyRequireMmuLockup).foreach{p =>
|
||||
p.dirty := True
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
119
src/main/scala/vexriscv/plugin/Mul16Plugin.scala
Normal file
119
src/main/scala/vexriscv/plugin/Mul16Plugin.scala
Normal file
|
@ -0,0 +1,119 @@
|
|||
package vexriscv.plugin
|
||||
|
||||
import vexriscv._
|
||||
import vexriscv.plugin._
|
||||
import spinal.core._
|
||||
|
||||
/**
|
||||
* A multiplication plugin using only 16-bit multiplications
|
||||
*/
|
||||
class Mul16Plugin extends Plugin[VexRiscv]{
|
||||
|
||||
object MUL_LL extends Stageable(UInt(32 bits))
|
||||
object MUL_LH extends Stageable(UInt(32 bits))
|
||||
object MUL_HL extends Stageable(UInt(32 bits))
|
||||
object MUL_HH extends Stageable(UInt(32 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 a,b = Bits(32 bit)
|
||||
|
||||
a := input(SRC1)
|
||||
b := input(SRC2)
|
||||
|
||||
val aLow = a(15 downto 0).asUInt
|
||||
val bLow = b(15 downto 0).asUInt
|
||||
val aHigh = a(31 downto 16).asUInt
|
||||
val bHigh = b(31 downto 16).asUInt
|
||||
|
||||
insert(MUL_LL) := aLow * bLow
|
||||
insert(MUL_LH) := aLow * bHigh
|
||||
insert(MUL_HL) := aHigh * bLow
|
||||
insert(MUL_HH) := aHigh * bHigh
|
||||
}
|
||||
|
||||
memory plug new Area {
|
||||
import memory._
|
||||
|
||||
val ll = UInt(32 bits)
|
||||
val lh = UInt(33 bits)
|
||||
val hl = UInt(32 bits)
|
||||
val hh = UInt(32 bits)
|
||||
|
||||
ll := input(MUL_LL)
|
||||
lh := input(MUL_LH).resized
|
||||
hl := input(MUL_HL)
|
||||
hh := input(MUL_HH)
|
||||
|
||||
val hllh = lh + hl
|
||||
insert(MUL) := ((hh ## ll(31 downto 16)).asUInt + hllh) ## ll(15 downto 0)
|
||||
}
|
||||
|
||||
writeBack plug new Area {
|
||||
import writeBack._
|
||||
val aSigned,bSigned = Bool
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
val a = (aSigned && input(SRC1).msb) ? input(SRC2).asUInt | U(0)
|
||||
val b = (bSigned && input(SRC2).msb) ? input(SRC1).asUInt | U(0)
|
||||
|
||||
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)).asUInt + ~a) + (~b + 2)).asBits
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -31,7 +31,7 @@ class MulDivIterativePlugin(genMul : Boolean = true,
|
|||
SRC1_CTRL -> Src1CtrlEnum.RS,
|
||||
SRC2_CTRL -> Src2CtrlEnum.RS,
|
||||
REGFILE_WRITE_VALID -> True,
|
||||
BYPASSABLE_EXECUTE_STAGE -> False,
|
||||
BYPASSABLE_EXECUTE_STAGE -> Bool(pipeline.stages.last == pipeline.execute),
|
||||
BYPASSABLE_MEMORY_STAGE -> True,
|
||||
RS1_USE -> True,
|
||||
RS2_USE -> True
|
||||
|
@ -69,21 +69,28 @@ class MulDivIterativePlugin(genMul : Boolean = true,
|
|||
import pipeline.config._
|
||||
if(!genMul && !genDiv) return
|
||||
|
||||
memory plug new Area {
|
||||
import memory._
|
||||
val flushStage = if(memory != null) memory else execute
|
||||
flushStage plug new Area {
|
||||
import flushStage._
|
||||
|
||||
//Shared ressources
|
||||
val rs1 = Reg(UInt(33 bits))
|
||||
val rs2 = Reg(UInt(32 bits))
|
||||
val accumulator = Reg(UInt(65 bits))
|
||||
|
||||
//FrontendOK is only used for CPU configs without memory/writeback stages, were it is required to wait one extra cycle
|
||||
// to let's the frontend process rs1 rs2 registers
|
||||
val frontendOk = if(flushStage != execute) True else RegInit(False) setWhen(arbitration.isValid && !pipeline.service(classOf[HazardService]).hazardOnExecuteRS && ((if(genDiv) input(IS_DIV) else False) || (if(genMul) input(IS_MUL) else False))) clearWhen(arbitration.isMoving)
|
||||
|
||||
val mul = ifGen(genMul) (if(customMul != null) customMul(rs1,rs2,memory,pipeline) else new Area{
|
||||
assert(isPow2(mulUnrollFactor))
|
||||
val counter = Counter(32 / mulUnrollFactor + 1)
|
||||
val done = counter.willOverflowIfInc
|
||||
when(arbitration.isValid && input(IS_MUL)){
|
||||
when(!done){
|
||||
when(!frontendOk || !done){
|
||||
arbitration.haltItself := True
|
||||
}
|
||||
when(frontendOk && !done){
|
||||
arbitration.haltItself := True
|
||||
counter.increment()
|
||||
rs2 := rs2 |>> mulUnrollFactor
|
||||
|
@ -101,7 +108,7 @@ class MulDivIterativePlugin(genMul : Boolean = true,
|
|||
|
||||
val div = ifGen(genDiv) (new Area{
|
||||
assert(isPow2(divUnrollFactor))
|
||||
|
||||
def area = this
|
||||
//register allocation
|
||||
def numerator = rs1(31 downto 0)
|
||||
def denominator = rs2
|
||||
|
@ -112,8 +119,10 @@ class MulDivIterativePlugin(genMul : Boolean = true,
|
|||
val done = Reg(Bool) setWhen(counter === counter.end-1) clearWhen(!arbitration.isStuck)
|
||||
val result = Reg(Bits(32 bits))
|
||||
when(arbitration.isValid && input(IS_DIV)){
|
||||
when(!done){
|
||||
when(!frontendOk || !done){
|
||||
arbitration.haltItself := True
|
||||
}
|
||||
when(frontendOk && !done){
|
||||
counter.increment()
|
||||
|
||||
def stages(inNumerator: UInt, inRemainder: UInt, stage: Int): Unit = stage match {
|
||||
|
@ -121,13 +130,13 @@ class MulDivIterativePlugin(genMul : Boolean = true,
|
|||
numerator := inNumerator
|
||||
remainder := inRemainder
|
||||
}
|
||||
case _ => {
|
||||
case _ => new Area {
|
||||
val remainderShifted = (inRemainder ## inNumerator.msb).asUInt
|
||||
val remainderMinusDenominator = remainderShifted - denominator
|
||||
val outRemainder = !remainderMinusDenominator.msb ? remainderMinusDenominator.resize(32 bits) | remainderShifted.resize(32 bits)
|
||||
val outNumerator = (inNumerator ## !remainderMinusDenominator.msb).asUInt.resize(32 bits)
|
||||
stages(outNumerator, outRemainder, stage - 1)
|
||||
}
|
||||
}.setCompositeName(area, "stage_" + (divUnrollFactor-stage))
|
||||
}
|
||||
|
||||
stages(numerator, remainder, divUnrollFactor)
|
||||
|
@ -139,16 +148,11 @@ class MulDivIterativePlugin(genMul : Boolean = true,
|
|||
}
|
||||
|
||||
output(REGFILE_WRITE_DATA) := result
|
||||
// when(input(INSTRUCTION)(13 downto 12) === "00" && counter === 0 && rs2 =/= 0 && rs1 < 16 && rs2 < 16 && !input(RS1).msb && !input(RS2).msb) {
|
||||
// output(REGFILE_WRITE_DATA) := B(rs1(3 downto 0) / rs2(3 downto 0)).resized
|
||||
// counter.willIncrement := False
|
||||
// arbitration.haltItself := False
|
||||
// }
|
||||
}
|
||||
})
|
||||
|
||||
//Execute stage logic to drive memory stage's input regs
|
||||
when(!arbitration.isStuck){
|
||||
when(if(flushStage != execute) !arbitration.isStuck else !frontendOk){
|
||||
accumulator := 0
|
||||
def twoComplement(that : Bits, enable: Bool): UInt = (Mux(enable, ~that, that).asUInt + enable.asUInt)
|
||||
val rs2NeedRevert = execute.input(RS2).msb && execute.input(IS_RS2_SIGNED)
|
||||
|
@ -163,7 +167,7 @@ class MulDivIterativePlugin(genMul : Boolean = true,
|
|||
}
|
||||
|
||||
if(dhrystoneOpt) {
|
||||
execute.insert(FAST_DIV_VALID) := execute.input(IS_DIV) && execute.input(INSTRUCTION)(13 downto 12) === "00" && !execute.input(RS1).msb && !execute.input(RS2).msb && execute.input(RS1).asUInt < 16 && execute.input(RS2).asUInt < 16 && execute.input(RS2) =/= 0
|
||||
execute.insert(FAST_DIV_VALID) := execute.input(IS_DIV) && execute.input(INSTRUCTION)(13 downto 12) === B"00" && !execute.input(RS1).msb && !execute.input(RS2).msb && execute.input(RS1).asUInt < 16 && execute.input(RS2).asUInt < 16 && execute.input(RS2) =/= 0
|
||||
execute.insert(FAST_DIV_VALUE) := (0 to 15).flatMap(n => (0 to 15).map(d => U(if (d == 0) 0 else n / d, 4 bits))).read(U(execute.input(RS1)(3 downto 0)) @@ U(execute.input(RS2)(3 downto 0))) //(U(execute.input(RS1)(3 downto 0)) / U(execute.input(RS2)(3 downto 0))
|
||||
when(execute.input(FAST_DIV_VALID)) {
|
||||
execute.output(IS_DIV) := False
|
||||
|
|
|
@ -2,8 +2,10 @@ package vexriscv.plugin
|
|||
import vexriscv._
|
||||
import vexriscv.VexRiscv
|
||||
import spinal.core._
|
||||
import spinal.lib.KeepAttribute
|
||||
|
||||
class MulPlugin extends Plugin[VexRiscv]{
|
||||
//Input buffer generaly avoid the FPGA synthesis to duplicate reg inside the DSP cell, which could stress timings quite much.
|
||||
class MulPlugin(inputBuffer : Boolean = false) extends Plugin[VexRiscv]{
|
||||
object MUL_LL extends Stageable(UInt(32 bits))
|
||||
object MUL_LH extends Stageable(SInt(34 bits))
|
||||
object MUL_HL extends Stageable(SInt(34 bits))
|
||||
|
@ -19,8 +21,8 @@ class MulPlugin extends Plugin[VexRiscv]{
|
|||
|
||||
|
||||
val actions = List[(Stageable[_ <: BaseType],Any)](
|
||||
SRC1_CTRL -> Src1CtrlEnum.RS,
|
||||
SRC2_CTRL -> Src2CtrlEnum.RS,
|
||||
// SRC1_CTRL -> Src1CtrlEnum.RS,
|
||||
// SRC2_CTRL -> Src2CtrlEnum.RS,
|
||||
REGFILE_WRITE_VALID -> True,
|
||||
BYPASSABLE_EXECUTE_STAGE -> False,
|
||||
BYPASSABLE_MEMORY_STAGE -> False,
|
||||
|
@ -48,8 +50,26 @@ class MulPlugin extends Plugin[VexRiscv]{
|
|||
val aSigned,bSigned = Bool
|
||||
val a,b = Bits(32 bit)
|
||||
|
||||
a := input(SRC1)
|
||||
b := input(SRC2)
|
||||
// a := input(SRC1)
|
||||
// b := input(SRC2)
|
||||
|
||||
val withInputBuffer = inputBuffer generate new Area{
|
||||
val rs1 = RegNext(input(RS1))
|
||||
val rs2 = RegNext(input(RS2))
|
||||
a := rs1
|
||||
b := rs2
|
||||
|
||||
val delay = RegNext(arbitration.isStuck)
|
||||
when(arbitration.isValid && input(IS_MUL) && !delay){
|
||||
arbitration.haltItself := True
|
||||
}
|
||||
}
|
||||
|
||||
val noInputBuffer = (!inputBuffer) generate new Area{
|
||||
a := input(RS1)
|
||||
b := input(RS2)
|
||||
}
|
||||
|
||||
switch(input(INSTRUCTION)(13 downto 12)) {
|
||||
is(B"01") {
|
||||
aSigned := True
|
||||
|
@ -75,6 +95,12 @@ class MulPlugin extends Plugin[VexRiscv]{
|
|||
insert(MUL_LH) := aSLow * bHigh
|
||||
insert(MUL_HL) := aHigh * bSLow
|
||||
insert(MUL_HH) := aHigh * bHigh
|
||||
|
||||
Component.current.afterElaboration{
|
||||
//Avoid synthesis tools to retime RS1 RS2 from execute stage to decode stage leading to bad timings (ex : Vivado, even if retiming is disabled)
|
||||
KeepAttribute(input(RS1))
|
||||
KeepAttribute(input(RS2))
|
||||
}
|
||||
}
|
||||
|
||||
//First aggregation of partial multiplication
|
||||
|
|
|
@ -19,8 +19,8 @@ class MulSimplePlugin extends Plugin[VexRiscv]{
|
|||
SRC1_CTRL -> Src1CtrlEnum.RS,
|
||||
SRC2_CTRL -> Src2CtrlEnum.RS,
|
||||
REGFILE_WRITE_VALID -> True,
|
||||
BYPASSABLE_EXECUTE_STAGE -> False,
|
||||
BYPASSABLE_MEMORY_STAGE -> False,
|
||||
BYPASSABLE_EXECUTE_STAGE -> Bool(pipeline.stages.last == pipeline.execute),
|
||||
BYPASSABLE_MEMORY_STAGE -> Bool(pipeline.stages.last == pipeline.memory),
|
||||
RS1_USE -> True,
|
||||
RS2_USE -> True,
|
||||
IS_MUL -> True
|
||||
|
@ -66,14 +66,16 @@ class MulSimplePlugin extends Plugin[VexRiscv]{
|
|||
insert(MUL_OPB) := ((bSigned ? b.msb | False) ## b).asSInt
|
||||
}
|
||||
|
||||
memory plug new Area {
|
||||
import memory._
|
||||
val injectionStage = if(pipeline.memory != null) pipeline.memory else pipeline.execute
|
||||
injectionStage plug new Area {
|
||||
import injectionStage._
|
||||
|
||||
insert(MUL) := (input(MUL_OPA) * input(MUL_OPB))(63 downto 0).asBits
|
||||
}
|
||||
|
||||
writeBack plug new Area {
|
||||
import writeBack._
|
||||
val memStage = stages.last
|
||||
memStage plug new Area {
|
||||
import memStage._
|
||||
|
||||
when(arbitration.isValid && input(IS_MUL)){
|
||||
switch(input(INSTRUCTION)(13 downto 12)){
|
||||
|
|
|
@ -8,19 +8,6 @@ import scala.collection.mutable.ArrayBuffer
|
|||
|
||||
|
||||
|
||||
object KeepAttribute{
|
||||
object syn_keep_verilog extends AttributeFlag("synthesis syn_keep = 1", COMMENT_ATTRIBUTE){
|
||||
override def isLanguageReady(language: Language) : Boolean = language == Language.VERILOG || language == Language.SYSTEM_VERILOG
|
||||
}
|
||||
|
||||
object syn_keep_vhdl extends AttributeFlag("syn_keep"){
|
||||
override def isLanguageReady(language: Language) : Boolean = language == Language.VHDL
|
||||
}
|
||||
object keep extends AttributeFlag("keep")
|
||||
|
||||
def apply[T <: Data](that : T) = that.addAttribute(keep).addAttribute(syn_keep_verilog).addAttribute(syn_keep_vhdl)
|
||||
}
|
||||
|
||||
|
||||
class PcManagerSimplePlugin(resetVector : BigInt,
|
||||
relaxedPcCalculation : Boolean = false,
|
||||
|
|
|
@ -96,6 +96,11 @@ class RegFilePlugin(regFileReadyKind : RegFileReadKind,
|
|||
regFileWrite.address := U(shadowPrefix(output(INSTRUCTION)(rdRange)))
|
||||
regFileWrite.data := output(REGFILE_WRITE_DATA)
|
||||
|
||||
//Ensure no boot glitches modify X0
|
||||
if(!x0Init && zeroBoot) when(regFileWrite.address === 0){
|
||||
regFileWrite.valid := False
|
||||
}
|
||||
|
||||
//CPU will initialise constant register zero in the first cycle
|
||||
if(x0Init) {
|
||||
val boot = RegNext(False) init (True)
|
||||
|
|
|
@ -9,7 +9,9 @@ class SingleInstructionLimiterPlugin() extends Plugin[VexRiscv] {
|
|||
override def build(pipeline: VexRiscv): Unit = {
|
||||
import pipeline._
|
||||
import pipeline.config._
|
||||
|
||||
decode.arbitration.haltByOther.setWhen(List(decode,execute,memory,writeBack).map(_.arbitration.isValid).orR)
|
||||
val fetcher = pipeline.service(classOf[IBusFetcher])
|
||||
when(fetcher.incoming() || List(decode,execute,memory,writeBack).map(_.arbitration.isValid).orR) {
|
||||
fetcher.haltIt()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package vexriscv.plugin
|
|||
|
||||
import vexriscv._
|
||||
import spinal.core._
|
||||
import spinal.lib.KeepAttribute
|
||||
|
||||
|
||||
class SrcPlugin(separatedAddSub : Boolean = false, executeInsertion : Boolean = false, decodeAddSub : Boolean = false) extends Plugin[VexRiscv]{
|
||||
|
|
|
@ -11,8 +11,7 @@ class StaticMemoryTranslatorPlugin(ioRange : UInt => Bool) extends Plugin[VexRis
|
|||
val portsInfo = ArrayBuffer[StaticMemoryTranslatorPort]()
|
||||
|
||||
override def newTranslationPort(priority : Int,args : Any): MemoryTranslatorBus = {
|
||||
// val exceptionBus = pipeline.service(classOf[ExceptionService]).newExceptionPort(stage)
|
||||
val port = StaticMemoryTranslatorPort(MemoryTranslatorBus(),priority)
|
||||
val port = StaticMemoryTranslatorPort(MemoryTranslatorBus(MemoryTranslatorBusParameter(wayCount = 0)),priority)
|
||||
portsInfo += port
|
||||
port.bus
|
||||
}
|
||||
|
@ -27,7 +26,7 @@ class StaticMemoryTranslatorPlugin(ioRange : UInt => Bool) extends Plugin[VexRis
|
|||
|
||||
val core = pipeline plug new Area {
|
||||
val ports = for ((port, portId) <- portsInfo.zipWithIndex) yield new Area {
|
||||
port.bus.rsp.physicalAddress := port.bus.cmd.virtualAddress
|
||||
port.bus.rsp.physicalAddress := port.bus.cmd.last.virtualAddress
|
||||
port.bus.rsp.allowRead := True
|
||||
port.bus.rsp.allowWrite := True
|
||||
port.bus.rsp.allowExecute := True
|
||||
|
|
|
@ -401,7 +401,7 @@ public:
|
|||
sdramIo->ADDR = &top->io_sdram_ADDR ;
|
||||
sdramIo->DQ_read = (CData*)&top->io_sdram_DQ_read ;
|
||||
sdramIo->DQ_write = (CData*)&top->io_sdram_DQ_write ;
|
||||
sdramIo->DQ_writeEnable = &top->io_sdram_DQ_writeEnable;
|
||||
sdramIo->DQ_writeEnable = (CData*)&top->io_sdram_DQ_writeEnable;
|
||||
Sdram *sdram = new Sdram(sdramConfig, sdramIo);
|
||||
|
||||
axiClk->add(sdram);
|
||||
|
|
|
@ -40,7 +40,7 @@ OBJS := $(addprefix $(OBJDIR)/,$(OBJS))
|
|||
|
||||
|
||||
|
||||
all: $(OBJDIR)/$(PROJ_NAME).elf $(OBJDIR)/$(PROJ_NAME).hex $(OBJDIR)/$(PROJ_NAME).asm
|
||||
all: $(OBJDIR)/$(PROJ_NAME).elf $(OBJDIR)/$(PROJ_NAME).hex $(OBJDIR)/$(PROJ_NAME).asm $(OBJDIR)/$(PROJ_NAME).bin
|
||||
@echo "done"
|
||||
|
||||
$(OBJDIR)/%.elf: $(OBJS) | $(OBJDIR)
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,122 +1,174 @@
|
|||
:0200000480007A
|
||||
:10000000930E1000970000009380C06F73905030E3
|
||||
:10001000970000009380807273905010B71001F029
|
||||
:100020001301000023A02000130E1000170F000082
|
||||
:10003000130FCF0073000000130E2000B720000044
|
||||
:10004000938000801301000073B0003073200130F2
|
||||
:1000500097000000938040017390103473002030AB
|
||||
:100060006F008068170F0000130F4F02730000002D
|
||||
:100070006F008067130E3000170F0000130F0F0181
|
||||
:10008000832010006F004066130E4000B720000070
|
||||
:1000900093800080371100001301018073B000309D
|
||||
:1000A000732001309700000093804001739010345A
|
||||
:1000B000730020306F004063170F0000130F0F0113
|
||||
:1000C000832010006F004062130E5000B720000024
|
||||
:1000D000938000801301000073B000307320013062
|
||||
:1000E000970000009380400173901034730020301B
|
||||
:1000F0006F00805F170F0000130F0F0183201000A7
|
||||
:100100006F00805E130E600093000001739020303A
|
||||
:10011000130E7000170F0000130F0F018320100043
|
||||
:100120006F00805C130E8000170F0000130FCF03C9
|
||||
:10013000B720000093800080371100001301018078
|
||||
:1001400073B00030732001309700000093804001AD
|
||||
:1001500073901034730020306F000059832010001A
|
||||
:100160006F008058130E9000170F0000130F8F03BD
|
||||
:10017000B7200000938000801301000073B00030AE
|
||||
:100180007320013097000000938040017390103479
|
||||
:10019000730020306F004055832010006F00C05462
|
||||
:1001A000130EA000170F0000130FCF03B71001F0BC
|
||||
:1001B0001301000023A02000930080007390003002
|
||||
:1001C000B71000009380008073904030B71001F0AA
|
||||
:1001D0001301100023A02000730050106F00C050C6
|
||||
:1001E000130EB000170F0000130F8F06B71001F0A9
|
||||
:1001F0001301000023A020009300800073900030C2
|
||||
:10020000B71000009380008073904030B72000004A
|
||||
:1002100093800080371100001301018073B000301B
|
||||
:1002200073200130970000009380400173901034D8
|
||||
:10023000730020306F00404BB71001F01301100025
|
||||
:1002400023A02000730050106F00004A130EC0005E
|
||||
:10025000170F0000130F4F06B71001F01301000035
|
||||
:1002600023A020009300800073900030B71000009E
|
||||
:100270009380008073904030B7200000938000800E
|
||||
:100280001301000073B000307320013097000000AC
|
||||
:100290009380400173901034730020306F00C0448D
|
||||
:1002A000B71001F01301100023A0200073005010BC
|
||||
:1002B0006F0080439300200073900010130EE00045
|
||||
:1002C000170F0000130F0F04B72001F013010000F7
|
||||
:1002D00023A02000930020007390003093000020A2
|
||||
:1002E00073904030930E0000B72001F0130110000E
|
||||
:1002F00023A02000930040069380F0FFE34E10FE01
|
||||
:10030000130EF000170F0000130F8F06B72001F037
|
||||
:100310001301000023A02000930020007390003000
|
||||
:100320009300002073904030B7200000938000803D
|
||||
:10033000371100001301018073B0003073200130C9
|
||||
:1003400097000000938040017390103473002030B8
|
||||
:100350006F008039930E1000B72001F013011000D8
|
||||
:1003600023A02000730050106F000038130E00010E
|
||||
:10037000170F0000130F0F06B72001F01301000044
|
||||
:1003800023A02000930020007390003093000020F1
|
||||
:1003900073904030B720000093800080130100006C
|
||||
:1003A00073B000307320013097000000938040014B
|
||||
:1003B00073901034730020306F000033B72001F0C9
|
||||
:1003C0001301100023A02000730050106F00C031F3
|
||||
:1003D000130E10019300002073903030170F0000AF
|
||||
:1003E000130F0F04B72001F01301000023A0200019
|
||||
:1003F00093002000739000309300002073904030F1
|
||||
:10040000930E0000B72001F01301100023A020007C
|
||||
:10041000930040069380F0FFE34E10FE130E200180
|
||||
:10042000170F0000130F8F06B72001F01301000013
|
||||
:1004300023A0200093002000739000309300002040
|
||||
:1004400073904030B7200000938000803711000087
|
||||
:100450001301018073B00030732001309700000059
|
||||
:100460009380400173901034730020306F00C027D8
|
||||
:10047000930E1000B72001F01301100023A02000FC
|
||||
:10048000730050106F004026130E3001170F00004C
|
||||
:10049000130F0F06B72001F01301000023A0200066
|
||||
:1004A0009300200073900030930000207390403040
|
||||
:1004B000B7200000938000801301000073B000306B
|
||||
:1004C0007320013097000000938040017390103436
|
||||
:1004D000730020306F004021B72001F0130110009D
|
||||
:1004E00023A02000730050106F000020B72001F0FF
|
||||
:1004F0001301000023A02000130E4001170F00007D
|
||||
:10050000130F0F039300200073900030930000201E
|
||||
:1005100073904030930E00009300002073A04014AD
|
||||
:10052000930040069380F0FFE34E10FE130E50013F
|
||||
:10053000170F0000130F0F069300002073B0401434
|
||||
:10054000930020007390003093000020739040309F
|
||||
:10055000B720000093800080371100001301018054
|
||||
:1005600073B0003073200130970000009380400189
|
||||
:1005700073901034730020306F000017930E10003A
|
||||
:100580009300002073A04014730050106F00C0153A
|
||||
:10059000130E6001170F0000130F8F05930000204A
|
||||
:1005A00073B040149300200073900030930000203B
|
||||
:1005B000739040309300002073A04014B7200000D7
|
||||
:1005C000938000801301000073B00030732001306D
|
||||
:1005D0009700000093804001739010347300203026
|
||||
:1005E0006F008010730050106F000010130E700128
|
||||
:1005F000930E0000B72001F01301000023A020009B
|
||||
:100600009300002073B04014F3214034B72001F070
|
||||
:100610001301100023A020009300002073B04014A9
|
||||
:10062000F3214034B72001F01301000023A0200083
|
||||
:100630009300002073B04014F3214034B72001F040
|
||||
:100640001301000023A020009300002073A0401499
|
||||
:10065000F3214034B72001F01301100023A0200043
|
||||
:100660009300002073A04014F3214034B72001F020
|
||||
:100670001301000023A02000130E8001930020002E
|
||||
:1006800073A0403073A0403473A00030930E10006C
|
||||
:10069000170F0000130FCF03B720000093800080D6
|
||||
:1006A000371100001301018073B000307320013056
|
||||
:1006B0009700000093804001739010347300203045
|
||||
:1006C0006F008002730050106F000002130E900143
|
||||
:1006D000170F0000130F4F017360043073005010A8
|
||||
:1006E0006F0080006F000001370110F0130141F22C
|
||||
:1006F0002320C101370110F0130101F22320010072
|
||||
:10070000E3840EFEF3202034F3201034F320003075
|
||||
:10071000F32030349300000873B0003093002000C1
|
||||
:10072000E38A1EFCB72000009380008073A0003095
|
||||
:1007300073101F3473002030E3880EFAF320201466
|
||||
:10074000F3201014F3200010F32030147300000085
|
||||
:10075000130000001300000013000000130000004D
|
||||
:0807600013000000130000006B
|
||||
:10000000930E1000971000009380C0A3739050309F
|
||||
:1000100097100000938080A673905010B71001F0E5
|
||||
:100020001301000023A020001300000013000000B3
|
||||
:100030001300000013000000130000001300000074
|
||||
:100040001300000013000000130E1000170F000033
|
||||
:10005000130FCF0073000000130E2000B720000024
|
||||
:10006000938000801301000073B0003073200130D2
|
||||
:10007000970000009380400173901034730020308B
|
||||
:100080006F00901A170F0000130F4F02730000004B
|
||||
:100090006F009019130E3000170F0000130F0F019F
|
||||
:1000A000832010006F005018130E4000B72000008E
|
||||
:1000B00093800080371100001301018073B000307D
|
||||
:1000C000732001309700000093804001739010343A
|
||||
:1000D000730020306F005015170F0000130F0F0131
|
||||
:1000E000832010006F005014130E5000B720000042
|
||||
:1000F000938000801301000073B000307320013042
|
||||
:1001000097000000938040017390103473002030FA
|
||||
:100110006F009011170F0000130F0F0183201000C4
|
||||
:100120006F009010130E6000930000017390203058
|
||||
:10013000130E7000170F0000130F0F018320100023
|
||||
:100140006F00900E130E8000170F0000130FCF03E7
|
||||
:10015000B720000093800080371100001301018058
|
||||
:1001600073B000307320013097000000938040018D
|
||||
:1001700073901034730020306F00100B8320100038
|
||||
:100180006F00900A130E9000170F0000130F8F03DB
|
||||
:10019000B7200000938000801301000073B000308E
|
||||
:1001A0007320013097000000938040017390103459
|
||||
:1001B000730020306F005007832010006F00D006BE
|
||||
:1001C000130EA000170F0000130FCF07B71001F098
|
||||
:1001D0001301000023A02000130000001300000002
|
||||
:1001E00013000000130000001300000013000000C3
|
||||
:1001F0001300000013000000930080007390003093
|
||||
:10020000B71000009380008073904030B71001F069
|
||||
:100210001301100023A020001300000013000000B1
|
||||
:100220001300000013000000130000001300000082
|
||||
:100230001300000013000000730050106F00C07E18
|
||||
:10024000130EB000170F0000130F8F0AB71001F044
|
||||
:100250001301000023A02000130000001300000081
|
||||
:100260001300000013000000130000001300000042
|
||||
:100270001300000013000000930080007390003012
|
||||
:10028000B71000009380008073904030B7200000CA
|
||||
:1002900093800080371100001301018073B000309B
|
||||
:1002A0007320013097000000938040017390103458
|
||||
:1002B000730020306F004077B71001F01301100079
|
||||
:1002C00023A0200013000000130000001300000012
|
||||
:1002D00013000000130000001300000013000000D2
|
||||
:1002E00013000000730050106F000074130EC00064
|
||||
:1002F000170F0000130F4F0AB71001F01301000091
|
||||
:1003000023A02000130000001300000013000000D1
|
||||
:100310001300000013000000130000001300000091
|
||||
:10032000130000009300800073900030B7100000AD
|
||||
:100330009380008073904030B7200000938000804D
|
||||
:100340001301000073B000307320013097000000EB
|
||||
:100350009380400173901034730020306F00C06CA4
|
||||
:10036000B71001F01301100023A0200013000000BB
|
||||
:100370001300000013000000130000001300000031
|
||||
:100380001300000013000000130000007300501061
|
||||
:100390006F0080699300200073900010130EE0003E
|
||||
:1003A000170F0000130F0F08B72001F01301000012
|
||||
:1003B00023A0200013000000130000001300000021
|
||||
:1003C00013000000130000001300000013000000E1
|
||||
:1003D0001300000093002000739000309300002071
|
||||
:1003E00073904030930E0000B72001F0130110000D
|
||||
:1003F00023A02000130000001300000013000000E1
|
||||
:1004000013000000130000001300000013000000A0
|
||||
:1004100013000000930040069380F0FFE34E10FEAF
|
||||
:10042000130EF000170F0000130F8F0AB72001F012
|
||||
:100430001301000023A0200013000000130000009F
|
||||
:100440001300000013000000130000001300000060
|
||||
:100450001300000013000000930020007390003090
|
||||
:100460009300002073904030B720000093800080FC
|
||||
:10047000371100001301018073B000307320013088
|
||||
:100480009700000093804001739010347300203077
|
||||
:100490006F008059930E1000B72001F01301100077
|
||||
:1004A00023A0200013000000130000001300000030
|
||||
:1004B00013000000130000001300000013000000F0
|
||||
:1004C00013000000730050106F000056130E00015F
|
||||
:1004D000170F0000130F0F0AB72001F013010000DF
|
||||
:1004E00023A02000130000001300000013000000F0
|
||||
:1004F00013000000130000001300000013000000B0
|
||||
:10050000130000009300200073900030930000203F
|
||||
:1005100073904030B72000009380008013010000EA
|
||||
:1005200073B00030732001309700000093804001C9
|
||||
:1005300073901034730020306F00004FB72001F02B
|
||||
:100540001301100023A0200013000000130000007E
|
||||
:10055000130000001300000013000000130000004F
|
||||
:100560001300000013000000730050106F00C04B18
|
||||
:10057000130E10019300002073903030170F00000D
|
||||
:10058000130F0F08B72001F01301000023A0200073
|
||||
:10059000130000001300000013000000130000000F
|
||||
:1005A00013000000130000001300000013000000FF
|
||||
:1005B000930020007390003093000020739040302F
|
||||
:1005C000930E0000B72001F01301100023A02000BB
|
||||
:1005D00013000000130000001300000013000000CF
|
||||
:1005E00013000000130000001300000013000000BF
|
||||
:1005F000930040069380F0FFE34E10FE130E20019F
|
||||
:10060000170F0000130F8F0AB72001F0130100002D
|
||||
:1006100023A02000130000001300000013000000BE
|
||||
:10062000130000001300000013000000130000007E
|
||||
:10063000130000009300200073900030930000200E
|
||||
:1006400073904030B7200000938000803711000085
|
||||
:100650001301018073B00030732001309700000057
|
||||
:100660009380400173901034730020306F00C03BC2
|
||||
:10067000930E1000B72001F01301100023A02000FA
|
||||
:10068000130000001300000013000000130000001E
|
||||
:10069000130000001300000013000000130000000E
|
||||
:1006A000730050106F004038130E3001170F000018
|
||||
:1006B000130F0F0AB72001F01301000023A0200040
|
||||
:1006C00013000000130000001300000013000000DE
|
||||
:1006D00013000000130000001300000013000000CE
|
||||
:1006E00093002000739000309300002073904030FE
|
||||
:1006F000B7200000938000801301000073B0003029
|
||||
:1007000073200130970000009380400173901034F3
|
||||
:10071000730020306F004031B72001F0130110004A
|
||||
:1007200023A02000130000001300000013000000AD
|
||||
:10073000130000001300000013000000130000006D
|
||||
:1007400013000000730050106F00002EB72001F05E
|
||||
:100750001301000023A0200013000000130000007C
|
||||
:10076000130000001300000013000000130000003D
|
||||
:100770001300000013000000130E4001170F0000CB
|
||||
:10078000130F0F039300200073900030930000209C
|
||||
:1007900073904030930E00009300002073A040142B
|
||||
:1007A000930040069380F0FFE34E10FE130E5001BD
|
||||
:1007B000170F0000130F0F069300002073B04014B2
|
||||
:1007C000930020007390003093000020739040301D
|
||||
:1007D000B7200000938000803711000013010180D2
|
||||
:1007E00073B0003073200130970000009380400107
|
||||
:1007F00073901034730020306F000023930E1000AC
|
||||
:100800009300002073A04014730050106F00C021AB
|
||||
:10081000130E6001170F0000130F8F0593000020C7
|
||||
:1008200073B04014930020007390003093000020B8
|
||||
:10083000739040309300002073A04014B720000054
|
||||
:10084000938000801301000073B0003073200130EA
|
||||
:1008500097000000938040017390103473002030A3
|
||||
:100860006F00801C730050106F00001C130E70018D
|
||||
:10087000930E0000B72001F01301000023A0200018
|
||||
:10088000130000001300000013000000130000001C
|
||||
:10089000130000001300000013000000130000000C
|
||||
:1008A0009300002073B04014F3214034B72001F0CE
|
||||
:1008B0001301100023A0200013000000130000000B
|
||||
:1008C00013000000130000001300000013000000DC
|
||||
:1008D00013000000130000009300002073B04014C8
|
||||
:1008E000F3214034B72001F01301000023A02000C1
|
||||
:1008F00013000000130000001300000013000000AC
|
||||
:10090000130000001300000013000000130000009B
|
||||
:100910009300002073B04014F3214034B72001F05D
|
||||
:100920001301000023A020001300000013000000AA
|
||||
:10093000130000001300000013000000130000006B
|
||||
:1009400013000000130000009300002073A0401467
|
||||
:10095000F3214034B72001F01301100023A0200040
|
||||
:10096000130000001300000013000000130000003B
|
||||
:10097000130000001300000013000000130000002B
|
||||
:100980009300002073A04014F3214034B72001F0FD
|
||||
:100990001301000023A0200013000000130000003A
|
||||
:1009A00013000000130000001300000013000000FB
|
||||
:1009B0001300000013000000130E800193002000BC
|
||||
:1009C00073A0403073A0403473A00030930E100029
|
||||
:1009D000170F0000130FCF03B72000009380008093
|
||||
:1009E000371100001301018073B000307320013013
|
||||
:1009F0009700000093804001739010347300203002
|
||||
:100A00006F008002730050106F000002130E9001FF
|
||||
:100A1000170F0000130F4F01736004307300501064
|
||||
:100A20006F0080006F000001370110F0130141F2E8
|
||||
:100A30002320C101370110F0130101F2232001002E
|
||||
:100A4000E3840EFEF3202034F3201034F320003032
|
||||
:100A5000F32030349300000873B00030930020007E
|
||||
:100A6000E38A1EFCB72000009380008073A0003052
|
||||
:100A700073101F3473002030E3880EFAF320201423
|
||||
:100A8000F3201014F3200010F32030147300000042
|
||||
:100A9000130000001300000013000000130000000A
|
||||
:080AA000130000001300000028
|
||||
:040000058000000077
|
||||
:00000001FF
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue