mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-22 13:17:41 -04:00
Compare commits
400 commits
20240827.f
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
733743da0f | ||
|
30811d1e7e | ||
|
8bcb14a2df | ||
|
f7fae486ff | ||
|
b9da1d9e2d | ||
|
7b3054156e | ||
|
4a1bffa87a | ||
|
1342bc960b | ||
|
75bc12d01b | ||
|
a165a2bb50 | ||
|
b258d27816 | ||
|
79c7c2c681 | ||
|
d94db10fb1 | ||
|
21506e4c66 | ||
|
b38c259c8c | ||
|
0e2e5128b2 | ||
|
2b1f45cad9 | ||
|
45e845d165 | ||
|
3a389af151 | ||
|
c3fe25aeda | ||
|
f984dc347f | ||
|
028ce43fce | ||
|
c511b21911 | ||
|
aae9b2eb66 | ||
|
d971232cd7 | ||
|
ab89beaebb | ||
|
14ef741bae | ||
|
3e73712c3e | ||
|
6e0cf8d730 | ||
|
bac134b7b5 | ||
|
dfdc72cb5a | ||
|
2d411b2dc8 | ||
|
a55db35bd1 | ||
|
e4c28b0b03 | ||
|
be7c8746c6 | ||
|
373401537e | ||
|
07bb91f5a2 | ||
|
abf21ee221 | ||
|
7b759a8b71 | ||
|
1bc415391a | ||
|
2ef1c1b1fc | ||
|
fd8c890def | ||
|
70972dad54 | ||
|
10fced1c99 | ||
|
0ec65198bc | ||
|
a3372c51f0 | ||
|
07f19ea319 | ||
|
59822e7ad1 | ||
|
be5ac20e46 | ||
|
3e8eb88e88 | ||
|
542fe39adc | ||
|
fb4a8d4472 | ||
|
3ebb510374 | ||
|
9d039197d1 | ||
|
024b8eada8 | ||
|
cbb08e8d19 | ||
|
3ce44b1b4e | ||
|
664c515b22 | ||
|
c19a3c1ace | ||
|
45aa060b5c | ||
|
14998fc161 | ||
|
f80c507aea | ||
|
b9886a27a2 | ||
|
02092dbcf0 | ||
|
24c6a891b8 | ||
|
fb899feec1 | ||
|
b6b259914a | ||
|
023e67e9be | ||
|
98604b5920 | ||
|
7bdfa5f63e | ||
|
8e5872c03b | ||
|
3d2ff00b1c | ||
|
e840a61e80 | ||
|
7af0f2e4d1 | ||
|
41c22069a0 | ||
|
5518a41c08 | ||
|
21b247dca7 | ||
|
86c53c5334 | ||
|
cb5c623e50 | ||
|
b28545ef78 | ||
|
a12d511432 | ||
|
db568f3e1d | ||
|
71f96d4329 | ||
|
ee58bfab94 | ||
|
1c6b89df5b | ||
|
837b204753 | ||
|
5a484fce42 | ||
|
6268d28939 | ||
|
e55f25d23c | ||
|
bca4e1544f | ||
|
31008fc4b9 | ||
|
eab88770ec | ||
|
2155d0e9c4 | ||
|
86a80f0eaa | ||
|
446defb900 | ||
|
4b9cbf9223 | ||
|
b4a037d33b | ||
|
73bae85e0c | ||
|
d4b337851c | ||
|
f7dd49efa5 | ||
|
b5caf14c50 | ||
|
a4cec295a8 | ||
|
c5bde40636 | ||
|
f4355fa49b | ||
|
fd213fc19e | ||
|
66ae110a51 | ||
|
ed89c717f7 | ||
|
5ff6b2d32e | ||
|
f7eb9c1e7b | ||
|
de0ebf0409 | ||
|
23355d29f0 | ||
|
b5b316ad12 | ||
|
9877af5eb6 | ||
|
ba8ac715d8 | ||
|
84e3a39dde | ||
|
aa62eec15c | ||
|
820a8c6e01 | ||
|
b718824e1e | ||
|
dd649f28ad | ||
|
160c322f53 | ||
|
7c326f5407 | ||
|
6ee7a7d0c2 | ||
|
5b1c194cb7 | ||
|
2157aaa926 | ||
|
f800707738 | ||
|
7eb33df0ac | ||
|
c389382c89 | ||
|
8a84f788d6 | ||
|
25f2f3190d | ||
|
7ee22cd93a | ||
|
6a8d1f422e | ||
|
e571c1ced1 | ||
|
2f81dba77f | ||
|
e7f27c1300 | ||
|
a283d3eea2 | ||
|
33c5d77bd8 | ||
|
f54b9d4152 | ||
|
2d9936d171 | ||
|
7eb59c3e16 | ||
|
43edcd467e | ||
|
6a86ebd2af | ||
|
16f37b95e6 | ||
|
4f5492d341 | ||
|
7ae45e1b96 | ||
|
5bc34d73a9 | ||
|
485c382b23 | ||
|
67f185cac5 | ||
|
4619a67fc6 | ||
|
65285e5498 | ||
|
aea4e3d174 | ||
|
a48fe03f0e | ||
|
f2d88cddc6 | ||
|
4604195f52 | ||
|
6bbc1e6d35 | ||
|
01845dd76b | ||
|
3d267f9344 | ||
|
3a9c2aa1ba | ||
|
51543db607 | ||
|
9676d230fb | ||
|
0687510f02 | ||
|
7aad781b74 | ||
|
aeb0b646bf | ||
|
9e670f64c6 | ||
|
ab2283c075 | ||
|
01c636dd55 | ||
|
61c38ea459 | ||
|
9ceab195fd | ||
|
6fc8d60c14 | ||
|
8a457272b7 | ||
|
ce24338d5b | ||
|
fd6037fefe | ||
|
37a9cf733b | ||
|
9cfadbeded | ||
|
1d0076eec3 | ||
|
8e605df1f9 | ||
|
4ca7a3ae38 | ||
|
45eaace82b | ||
|
0877e8e446 | ||
|
20b64e8939 | ||
|
21dc824040 | ||
|
53472eb026 | ||
|
b4d000bb77 | ||
|
c1c2f9d922 | ||
|
67a6ae966c | ||
|
0bf937a772 | ||
|
cff48e4c75 | ||
|
48480c72d0 | ||
|
a0f9deabff | ||
|
be4a6ee364 | ||
|
7394941220 | ||
|
1de0da8d96 | ||
|
dff627162b | ||
|
c8f2c39e48 | ||
|
9c3aea232f | ||
|
7ae870e02f | ||
|
5131fb030c | ||
|
0649adc0b5 | ||
|
fea98c65de | ||
|
2b3a82f2cc | ||
|
b744f9bb09 | ||
|
e7f423404f | ||
|
2ec24264e4 | ||
|
8f06d41850 | ||
|
08c81658ec | ||
|
4a642d35d9 | ||
|
51653c6377 | ||
|
969c1518f2 | ||
|
44072bfd83 | ||
|
ff01467041 | ||
|
c6ae849f7a | ||
|
6ccd8d8bfa | ||
|
56532c6963 | ||
|
860f47fed7 | ||
|
967fc5d021 | ||
|
923d9c2e8f | ||
|
164d7c7fc9 | ||
|
bc7eeb7b01 | ||
|
f974e105bf | ||
|
8070febca0 | ||
|
6a4af755aa | ||
|
e9382ba3ac | ||
|
6561f2c641 | ||
|
ea3a55450b | ||
|
9362816e1c | ||
|
d577aaf850 | ||
|
8ef28596d5 | ||
|
111df66d27 | ||
|
a66efad475 | ||
|
668829de6e | ||
|
776e0137b6 | ||
|
6249bd1929 | ||
|
004f819c14 | ||
|
0d2097be0c | ||
|
faf4536b37 | ||
|
53b51ac5a7 | ||
|
339d3dd851 | ||
|
064cec2066 | ||
|
4c36aafaf0 | ||
|
37b58243fa | ||
|
28affa2346 | ||
|
76e5b40961 | ||
|
12f41b52ac | ||
|
051ba348f9 | ||
|
89eb77a249 | ||
|
834e3e74d5 | ||
|
d2889fa174 | ||
|
e5618977d1 | ||
|
4f45b575aa | ||
|
9b576c1200 | ||
|
af4e3744d4 | ||
|
4b51643826 | ||
|
7435cb310e | ||
|
3059b1cb25 | ||
|
0c60bc6e3d | ||
|
ce4b25c51a | ||
|
14fd617455 | ||
|
2e0a202440 | ||
|
12be3adb81 | ||
|
81671e39fa | ||
|
6269f72b63 | ||
|
d4b62d7372 | ||
|
4e9abb284c | ||
|
bed9a17880 | ||
|
8dcdf8fb56 | ||
|
6a649d6515 | ||
|
2249202769 | ||
|
a4583a6e4d | ||
|
934823d89c | ||
|
211af02e5e | ||
|
96b0508525 | ||
|
b438a8ba8e | ||
|
e9648eaf8c | ||
|
fd489a16fb | ||
|
631513eda8 | ||
|
1e48237a7a | ||
|
3deb95af21 | ||
|
335c91cc08 | ||
|
4c48a60804 | ||
|
846e1a1269 | ||
|
4ff16f9da3 | ||
|
14be0af7f0 | ||
|
7181278223 | ||
|
118f353f54 | ||
|
04ebfbd713 | ||
|
d4809a7e2b | ||
|
2acf5ba407 | ||
|
4b2b6e2983 | ||
|
aa4ced4a8a | ||
|
77c6cc328d | ||
|
4a223bee46 | ||
|
8d413b7c54 | ||
|
95049c4a3d | ||
|
5f8605838e | ||
|
8c70976759 | ||
|
6c0e3f82c5 | ||
|
8aa0f634f6 | ||
|
c4b4216981 | ||
|
0cbd894a7a | ||
|
71653038d7 | ||
|
da1c7477ed | ||
|
e53c669df1 | ||
|
3e62b0b910 | ||
|
8fa590b5c3 | ||
|
5fcc39dbee | ||
|
18bfc238f9 | ||
|
48ef515ba0 | ||
|
2dcb7417b4 | ||
|
214444cc93 | ||
|
dc9dc150e7 | ||
|
58d490b461 | ||
|
d9a7fdb836 | ||
|
f44655809f | ||
|
c50012ac76 | ||
|
b6a3aa1b03 | ||
|
7c351b3c8e | ||
|
0c58e39987 | ||
|
37d93a3758 | ||
|
51114ee0a1 | ||
|
6044454a07 | ||
|
67dba2cad3 | ||
|
4df49a6b0f | ||
|
051a2f94ff | ||
|
0bd8b8693a | ||
|
2616d5e649 | ||
|
9900d5fd19 | ||
|
246961b3c3 | ||
|
d98ac1490a | ||
|
66caecdfe6 | ||
|
702fedf23f | ||
|
ace1643e91 | ||
|
f18bac51b3 | ||
|
9ebe42f033 | ||
|
3874c41320 | ||
|
0721ebb609 | ||
|
636e6aff47 | ||
|
aa5d7f8217 | ||
|
ce1e889716 | ||
|
ced13a56b1 | ||
|
33ab2efa83 | ||
|
88f13c5874 | ||
|
398778a1ba | ||
|
3f62e343fb | ||
|
21383ce16d | ||
|
ee0847e30a | ||
|
fe1a19fca7 | ||
|
21733e55d7 | ||
|
96ae8ed223 | ||
|
318be6dcde | ||
|
89568b0c10 | ||
|
17ea49439f | ||
|
c92245b20b | ||
|
9df64701bd | ||
|
c78ede91f9 | ||
|
c93587b1f9 | ||
|
db088159eb | ||
|
802066bfd3 | ||
|
7e8e2c931f | ||
|
205872acc6 | ||
|
3ed5e78c91 | ||
|
212c14e4b4 | ||
|
d83b3f6ffd | ||
|
3d00079c19 | ||
|
3fccfba900 | ||
|
e3943f5913 | ||
|
cb6211bbb8 | ||
|
e26267b220 | ||
|
77264cd572 | ||
|
105d3601b6 | ||
|
8164828913 | ||
|
b1850a8cb7 | ||
|
361b17e7b0 | ||
|
d5b7cc77ff | ||
|
6c0cf186fc | ||
|
2c48fccb52 | ||
|
fa2a676007 | ||
|
36098bf827 | ||
|
fa9a36860c | ||
|
27aab922b9 | ||
|
4e2baff507 | ||
|
dec70a18c5 | ||
|
db6e0c9696 | ||
|
c36837142f | ||
|
27836559ae | ||
|
28e94e5ce3 | ||
|
367fe5850a | ||
|
bc7149adc7 | ||
|
f57a6c0106 | ||
|
4391fc4b14 | ||
|
546a8c26da | ||
|
91871d97f3 | ||
|
2266f75f2d | ||
|
9d02734bd1 | ||
|
afb3265296 | ||
|
7ccf82ce76 | ||
|
dc000d6c37 | ||
|
feb35f2b88 | ||
|
eac60af1a9 | ||
|
424eca6f63 | ||
|
ade4c85e13 | ||
|
592487ffa0 |
708 changed files with 87072 additions and 52179 deletions
35
.github/workflows/ci.yml
vendored
35
.github/workflows/ci.yml
vendored
|
@ -17,6 +17,12 @@ jobs:
|
|||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Get specific submodule hash
|
||||
id: core-v-submodule-hash
|
||||
run: |
|
||||
cd verif/core-v-verif
|
||||
echo "hash=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache toolchain
|
||||
id: cache-toolchain
|
||||
uses: actions/cache@v3
|
||||
|
@ -42,9 +48,7 @@ jobs:
|
|||
cache-name: cache-spike
|
||||
with:
|
||||
path: tools/spike/
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('verif/regress/install-spike.sh',
|
||||
'verif/core-v-verif/vendor/riscv/riscv-isa-sim/**/*',
|
||||
'verif/core-v-verif/vendor/riscv/riscv-isa-sim/*') }}
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('verif/regress/install-spike.sh')}}-${{ steps.core-v-submodule-hash.outputs.hash }}
|
||||
|
||||
- name: Prepare
|
||||
run: |
|
||||
|
@ -59,12 +63,15 @@ jobs:
|
|||
strategy:
|
||||
matrix:
|
||||
testcase: [ cv64a6_imafdc_tests ]
|
||||
config: [ cv64a6_imafdc_sv39_hpdcache, cv64a6_imafdc_sv39_wb, cv64a6_imafdc_sv39 ]
|
||||
config: [ cv64a6_imafdc_sv39_hpdcache, cv64a6_imafdc_sv39_hpdcache_wb, cv64a6_imafdc_sv39_wb, cv64a6_imafdc_sv39 ]
|
||||
simulator: [ veri-testharness ]
|
||||
include:
|
||||
- testcase: dv-riscv-arch-test
|
||||
config: cv64a6_imafdc_sv39_hpdcache
|
||||
simulator: veri-testharness
|
||||
- testcase: dv-riscv-arch-test
|
||||
config: cv64a6_imafdc_sv39_hpdcache_wb
|
||||
simulator: veri-testharness
|
||||
needs:
|
||||
build-riscv-tests
|
||||
steps:
|
||||
|
@ -72,6 +79,12 @@ jobs:
|
|||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Get specific submodule hash
|
||||
id: core-v-submodule-hash
|
||||
run: |
|
||||
cd verif/core-v-verif
|
||||
echo "hash=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache toolchain
|
||||
id: cache-toolchain
|
||||
uses: actions/cache@v3
|
||||
|
@ -97,9 +110,7 @@ jobs:
|
|||
cache-name: cache-spike
|
||||
with:
|
||||
path: tools/spike/
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('verif/regress/install-spike.sh',
|
||||
'verif/core-v-verif/vendor/riscv/riscv-isa-sim/**/*',
|
||||
'verif/core-v-verif/vendor/riscv/riscv-isa-sim/*') }}
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('verif/regress/install-spike.sh')}}-${{ steps.core-v-submodule-hash.outputs.hash }}
|
||||
|
||||
- name: Run Tests
|
||||
run: |
|
||||
|
@ -134,6 +145,12 @@ jobs:
|
|||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Get specific submodule hash
|
||||
id: core-v-submodule-hash
|
||||
run: |
|
||||
cd verif/core-v-verif
|
||||
echo "hash=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache toolchain
|
||||
id: cache-toolchain
|
||||
uses: actions/cache@v3
|
||||
|
@ -159,9 +176,7 @@ jobs:
|
|||
cache-name: cache-spike
|
||||
with:
|
||||
path: tools/spike/
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('verif/regress/install-spike.sh',
|
||||
'verif/core-v-verif/vendor/riscv/riscv-isa-sim/**/*',
|
||||
'verif/core-v-verif/vendor/riscv/riscv-isa-sim/*') }}
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('verif/regress/install-spike.sh')}}-${{ steps.core-v-submodule-hash.outputs.hash }}
|
||||
|
||||
- name: Run Tests
|
||||
run: |
|
||||
|
|
1
.github/workflows/verible.yml
vendored
1
.github/workflows/verible.yml
vendored
|
@ -21,3 +21,4 @@ jobs:
|
|||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
files: '$(find core -regex ".*\.\(v\|sv\)$" | grep -v "^core/include/.*_config_pkg.sv$")'
|
||||
fail_on_formatting_suggestions: true
|
||||
|
|
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -1,3 +1,5 @@
|
|||
*.swp
|
||||
*.swo
|
||||
site/*
|
||||
*.ucdb
|
||||
covhtmlreport/*
|
||||
|
@ -45,8 +47,8 @@ __pycache__
|
|||
.bender/
|
||||
Bender.lock
|
||||
/tools/
|
||||
/util/gcc-toolchain-builder/src/
|
||||
/util/gcc-toolchain-builder/build/
|
||||
/util/toolchain-builder/src/
|
||||
/util/toolchain-builder/build/
|
||||
# Both following lines are needed to list contents of ISA manual build dir.
|
||||
!/vendor/riscv/riscv-isa-manual/build/
|
||||
!/vendor/riscv/riscv-isa-manual/build/*
|
||||
|
|
247
.gitlab-ci.yml
247
.gitlab-ci.yml
|
@ -25,6 +25,10 @@ include:
|
|||
- project: '$CI_PROJECT_NAMESPACE/setup-ci'
|
||||
ref: '$SETUP_CI_CVV_BRANCH'
|
||||
file: 'cva6/core-v-verif-cva6.yml'
|
||||
- local: '.gitlab-ci-custom.yml'
|
||||
rules:
|
||||
- exists:
|
||||
- '.gitlab-ci-custom.yml'
|
||||
|
||||
workflow:
|
||||
rules:
|
||||
|
@ -34,6 +38,9 @@ workflow:
|
|||
- if: $CI_COMMIT_BRANCH == "master"
|
||||
variables:
|
||||
CI_KIND: regress
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
variables:
|
||||
CI_KIND: regress
|
||||
- if: $CI_COMMIT_BRANCH =~ /.*_PR_.*/
|
||||
variables:
|
||||
CI_KIND: dev
|
||||
|
@ -49,7 +56,7 @@ variables:
|
|||
DV_TARGET: cv32a65x
|
||||
|
||||
default:
|
||||
tags: [$TAGS_RUNNER]
|
||||
tags: [$TAGS_RUNNER_SIMU]
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
|
@ -65,6 +72,7 @@ stages:
|
|||
|
||||
.setup_job:
|
||||
stage: setup
|
||||
tags: [$TAGS_RUNNER]
|
||||
variables:
|
||||
GIT_SUBMODULE_STRATEGY: none
|
||||
rules: &on_dev
|
||||
|
@ -107,28 +115,32 @@ build_tools:
|
|||
- mkdir -p artifacts/tools/
|
||||
- mv tools/spike artifacts/tools/
|
||||
|
||||
.copy_spike_artifacts: ©_spike_artifacts
|
||||
- mkdir -p tools
|
||||
- mv artifacts/tools/spike tools
|
||||
- /sbin/ldconfig -N tools/spike/lib
|
||||
|
||||
.fe_smoke_test:
|
||||
stage: light tests
|
||||
rules: *on_dev
|
||||
before_script:
|
||||
- git -C verif/core-v-verif fetch --unshallow
|
||||
- mkdir -p tools
|
||||
- mv artifacts/tools/spike tools
|
||||
- git -C verif/core-v-verif fetch --unshallow || git -C verif/core-v-verif fetch --all
|
||||
- !reference [.copy_spike_artifacts]
|
||||
- rm -rf artifacts/
|
||||
- mkdir -p artifacts/{reports,logs}
|
||||
- python3 .gitlab-ci/scripts/report_fail.py
|
||||
- echo $SYN_VCS_BASHRC; source $SYN_VCS_BASHRC
|
||||
|
||||
.simu_after_script: &simu_after_script
|
||||
- for i in $(find verif/sim/out*/[vq]*_sim -type f \( -name "*.csv" -o -name "*.iss" \)) ; do head -10000 $i > artifacts/logs/$(basename $i).head ; done
|
||||
- head -10000 verif/sim/logfile.log > artifacts/logs/logfile.log.head
|
||||
- python3 .gitlab-ci/scripts/report_simu.py verif/sim/logfile.log
|
||||
- for i in $(find verif/sim/out*/[vq]*_sim -type f \( -name "*.csv" -o -name "*.iss" -o -name "*.yaml" \)) ; do tail -10000 $i > artifacts/logs/$(basename $i) ; done
|
||||
- tail -10000 verif/sim/logfile.log > artifacts/logs/logfile.log
|
||||
- if [ -n "$SPIKE_TANDEM" ]; then python3 .gitlab-ci/scripts/report_tandem.py verif/sim/out*/"$DV_SIMULATORS"_sim; else python3 .gitlab-ci/scripts/report_simu.py verif/sim/logfile.log; fi
|
||||
|
||||
smoke:
|
||||
smoke-tests:
|
||||
extends:
|
||||
- .fe_smoke_test
|
||||
variables:
|
||||
DASHBOARD_JOB_TITLE: "Smoke test $DV_SIMULATORS"
|
||||
DASHBOARD_JOB_TITLE: "Smoke test $DV_SIMULATORS $DV_TARGET"
|
||||
DASHBOARD_JOB_DESCRIPTION: "Short tests to challenge most architectures with most testbenchs configurations"
|
||||
DASHBOARD_SORT_INDEX: 0
|
||||
DASHBOARD_JOB_CATEGORY: "Basic"
|
||||
|
@ -136,17 +148,16 @@ smoke:
|
|||
COLLECT_SIMU_LOGS: 1
|
||||
parallel:
|
||||
matrix:
|
||||
- DV_SIMULATORS:
|
||||
- "veri-testharness,spike"
|
||||
- "vcs-testharness,spike"
|
||||
- "questa-testharness,spike"
|
||||
- "vcs-uvm,spike"
|
||||
- DV_SIMULATORS: ["vcs-testharness", "questa-testharness"]
|
||||
DV_TARGET: ["cv32a6_imac_sv32", "cv64a6_imafdc_sv39"]
|
||||
- DV_SIMULATORS: "vcs-uvm"
|
||||
DV_TARGET: "cv32a65x"
|
||||
script:
|
||||
- source $QUESTA_BASHRC
|
||||
- bash verif/regress/smoke-tests.sh
|
||||
- if [[ $DV_SIMULATORS == *"questa"* ]]; then source $QUESTA_BASHRC; fi
|
||||
- bash verif/regress/smoke-tests-$DV_TARGET.sh
|
||||
- !reference [.simu_after_script]
|
||||
|
||||
gen_smoke:
|
||||
smoke-gen:
|
||||
extends:
|
||||
- .fe_smoke_test
|
||||
variables:
|
||||
|
@ -154,25 +165,34 @@ gen_smoke:
|
|||
DASHBOARD_JOB_DESCRIPTION: "Short generated tests to challenge the CVA6-DV on STEP1 configuration"
|
||||
DASHBOARD_SORT_INDEX: 0
|
||||
DASHBOARD_JOB_CATEGORY: "Basic"
|
||||
DV_SIMULATORS: "vcs-uvm,spike"
|
||||
DV_SIMULATORS: "vcs-uvm"
|
||||
COLLECT_SIMU_LOGS: 1
|
||||
SPIKE_TANDEM: 1
|
||||
script:
|
||||
- bash verif/regress/smoke-gen_tests.sh
|
||||
- cp verif/sim/seedlist.yaml artifacts/logs/
|
||||
- cp verif/sim/uvm_seed.log artifacts/logs/
|
||||
- !reference [.simu_after_script]
|
||||
|
||||
coremark:
|
||||
smoke-bench:
|
||||
extends:
|
||||
- .fe_smoke_test
|
||||
variables:
|
||||
DASHBOARD_JOB_TITLE: "CoreMark"
|
||||
DASHBOARD_JOB_TITLE: "smoke-bench $DV_TARGET"
|
||||
DASHBOARD_JOB_DESCRIPTION: "Performance indicator"
|
||||
DASHBOARD_SORT_INDEX: 5
|
||||
DASHBOARD_JOB_CATEGORY: "Performance"
|
||||
SPIKE_TANDEM: 1
|
||||
BENCH: "dhrystone"
|
||||
parallel:
|
||||
matrix:
|
||||
- DV_TARGET: "cv32a60x"
|
||||
- DV_TARGET: "cv32a65x"
|
||||
script:
|
||||
- bash verif/regress/coremark.sh --no-print
|
||||
- python3 .gitlab-ci/scripts/report_benchmark.py --coremark verif/sim/out_*/veri-testharness_sim/core_main.*.log
|
||||
- bash verif/regress/"$BENCH"_smoke.sh --no-print
|
||||
- python3 .gitlab-ci/scripts/report_benchmark.py --"$BENCH"_"$DV_TARGET" verif/sim/out_*/vcs-uvm_sim/"$BENCH"_main.*.log
|
||||
|
||||
hwconfig:
|
||||
smoke-hwconfig:
|
||||
extends:
|
||||
- .fe_smoke_test
|
||||
variables:
|
||||
|
@ -180,29 +200,14 @@ hwconfig:
|
|||
DASHBOARD_JOB_DESCRIPTION: "Short tests to challenge target configurations"
|
||||
DASHBOARD_SORT_INDEX: 1
|
||||
DASHBOARD_JOB_CATEGORY: "Basic"
|
||||
DV_SIMULATORS: "veri-testharness,spike"
|
||||
DV_HWCONFIG_OPTS: "cv32a60x"
|
||||
DV_SIMULATORS: "vcs-uvm"
|
||||
SPIKE_TANDEM: 1
|
||||
DV_TARGET: "hwconfig"
|
||||
DV_HWCONFIG_OPTS: "cv32a65x"
|
||||
script:
|
||||
- source verif/regress/hwconfig_tests.sh
|
||||
- python3 .gitlab-ci/scripts/report_pass.py
|
||||
|
||||
spyglass:
|
||||
extends:
|
||||
- .fe_smoke_test
|
||||
variables:
|
||||
DV_TARGET: cv32a65x
|
||||
DASHBOARD_JOB_TITLE: "Report Spyglass Lint Errors"
|
||||
DASHBOARD_JOB_DESCRIPTION: "Report lint errors and warnings detected by Spyglass"
|
||||
DASHBOARD_SORT_INDEX: 5
|
||||
DASHBOARD_JOB_CATEGORY: "Lint Check"
|
||||
script:
|
||||
- echo $SYN_SG_BASHRC; source $SYN_SG_BASHRC
|
||||
- mkdir -p artifacts/lint_reports
|
||||
- make -C spyglass design_read
|
||||
- make -C spyglass lint_check
|
||||
- mv spyglass/sg_run_results/cva6_sg_reports/cva6_lint_lint_rtl artifacts/lint_reports
|
||||
- python3 .gitlab-ci/scripts/report_spyglass_lint.py spyglass/reference_summary.rpt artifacts/lint_reports/cva6_lint_lint_rtl/summary.rpt
|
||||
|
||||
.synthesis_test:
|
||||
stage: heavy tests
|
||||
timeout: 2 hours
|
||||
|
@ -220,9 +225,42 @@ spyglass:
|
|||
- when: manual
|
||||
allow_failure: true
|
||||
|
||||
spyglass:
|
||||
extends:
|
||||
- .synthesis_test
|
||||
variables:
|
||||
DV_TARGET: cv32a65x
|
||||
DASHBOARD_JOB_TITLE: "Report Spyglass Lint Errors"
|
||||
DASHBOARD_JOB_DESCRIPTION: "Report lint errors and warnings detected by Spyglass"
|
||||
DASHBOARD_SORT_INDEX: 5
|
||||
DASHBOARD_JOB_CATEGORY: "Lint Check"
|
||||
script:
|
||||
- echo $SYN_SG_BASHRC; source $SYN_SG_BASHRC
|
||||
- mkdir -p artifacts/lint_reports
|
||||
- make -C spyglass design_read
|
||||
- make -C spyglass lint_check
|
||||
- mv spyglass/sg_run_results/cva6_sg_reports/cva6_lint_lint_rtl artifacts/lint_reports
|
||||
- cp spyglass/reference_summary.rpt artifacts/lint_reports
|
||||
- python3 .gitlab-ci/scripts/report_spyglass_lint.py spyglass/reference_summary.rpt artifacts/lint_reports/cva6_lint_lint_rtl/summary.rpt
|
||||
|
||||
cvxif-regression:
|
||||
extends:
|
||||
- .synthesis_test
|
||||
variables:
|
||||
DASHBOARD_JOB_TITLE: "CVXIF non-regression test $DV_SIMULATORS"
|
||||
DASHBOARD_JOB_DESCRIPTION: "Short tests to challenge most CoreV-X-Interface in testharness"
|
||||
DASHBOARD_SORT_INDEX: 5
|
||||
DASHBOARD_JOB_CATEGORY: "Basic"
|
||||
COLLECT_SIMU_LOGS: 1
|
||||
script:
|
||||
- bash verif/regress/cvxif_verif_regression.sh
|
||||
- if [[ $DV_SIMULATORS == *"spike"* ]]; then unset SPIKE_TANDEM; fi # dirty hack to do trace comparison between tandem execution and spike standalone
|
||||
- !reference [.simu_after_script]
|
||||
|
||||
asic-synthesis:
|
||||
extends:
|
||||
- .synthesis_test
|
||||
tags: [$TAGS_RUNNER_SYNTH]
|
||||
variables:
|
||||
DASHBOARD_JOB_TITLE: "ASIC Synthesis $DV_TARGET"
|
||||
DASHBOARD_JOB_DESCRIPTION: "Synthesis indicator with specific Techno"
|
||||
|
@ -234,7 +272,8 @@ asic-synthesis:
|
|||
- echo $PERIOD
|
||||
- echo $DV_TARGET
|
||||
- source ./verif/sim/setup-env.sh
|
||||
- git clone ${SYNTH_SCRIPT} ${SYNTH_SCRIPT_PATH}
|
||||
- git clone ${SYNTH_SCRIPT} ${SYNTH_SCRIPT_PATH} -b ${SYNTH_SCRIPT_BRANCH}
|
||||
- git -C ${SYNTH_SCRIPT_PATH} checkout cce5ea41
|
||||
- cp -r ${SYNTH_SCRIPT_PATH}/cva6/ ../
|
||||
- git apply ${SYNTH_SCRIPT_PATH}/patches/*.patch
|
||||
- echo $SYN_DCSHELL_BASHRC; source $SYN_DCSHELL_BASHRC
|
||||
|
@ -255,15 +294,29 @@ fpga-build:
|
|||
DASHBOARD_JOB_DESCRIPTION: "Test of FPGA build flow"
|
||||
DASHBOARD_SORT_INDEX: 9
|
||||
DASHBOARD_JOB_CATEGORY: "Synthesis"
|
||||
TARGET: cv32a60x
|
||||
TARGET: cv32a6_imac_sv32
|
||||
script:
|
||||
- source $VIVADO_SETUP
|
||||
- source ./verif/sim/setup-env.sh
|
||||
- mkdir -p artifacts/logs
|
||||
- make fpga target=$TARGET |& tail -20 > artifacts/logs/logfile.log.tail
|
||||
- make fpga target=$TARGET &> artifacts/logs/logfile.log
|
||||
- mkdir -p artifacts/reports
|
||||
- mv corev_apu/fpga/work-fpga/ariane_xilinx.bit artifacts/ariane_xilinx_$TARGET.bit
|
||||
- python3 .gitlab-ci/scripts/report_fpga.py corev_apu/fpga/reports/ariane.utilization.rpt artifacts/logs/logfile.log.tail
|
||||
- python3 .gitlab-ci/scripts/report_fpga.py corev_apu/fpga/reports/ariane.utilization.rpt
|
||||
|
||||
pmp_tests:
|
||||
timeout : 2 hours
|
||||
extends:
|
||||
- .synthesis_test
|
||||
variables:
|
||||
DASHBOARD_JOB_TITLE: "PMP $DV_TARGET"
|
||||
DASHBOARD_JOB_DESCRIPTION: "Physical Memory Protection tests"
|
||||
DASHBOARD_SORT_INDEX: 2
|
||||
DASHBOARD_JOB_CATEGORY: "Test suites"
|
||||
DV_SIMULATORS: "vcs-uvm"
|
||||
SPIKE_TANDEM: 1
|
||||
script: source verif/regress/pmp_cv32a65x_tests.sh
|
||||
after_script: *simu_after_script
|
||||
|
||||
.regress_test:
|
||||
stage: heavy tests
|
||||
|
@ -275,17 +328,32 @@ fpga-build:
|
|||
- when: manual
|
||||
allow_failure: true
|
||||
|
||||
dhrystone:
|
||||
benchmarks:
|
||||
extends:
|
||||
- .regress_test
|
||||
variables:
|
||||
DASHBOARD_JOB_TITLE: "Dhrystone"
|
||||
DASHBOARD_JOB_TITLE: "benchmark $BENCH $ISSUE"
|
||||
DASHBOARD_JOB_DESCRIPTION: "Performance indicator"
|
||||
DASHBOARD_SORT_INDEX: 5
|
||||
DASHBOARD_JOB_CATEGORY: "Performance"
|
||||
SPIKE_TANDEM: 1
|
||||
parallel:
|
||||
matrix:
|
||||
- BENCH: "dhrystone"
|
||||
ISSUE: "single"
|
||||
DV_HWCONFIG_OPTS: ["cv32a60x IcacheByteSize=16384 IcacheSetAssoc=8 DcacheByteSize=32768 DcacheSetAssoc=8 BHTEntries=128 NrScoreboardEntries=8 DCacheType=config_pkg::WT"]
|
||||
- BENCH: "dhrystone"
|
||||
ISSUE: "dual"
|
||||
DV_HWCONFIG_OPTS: ["cv32a65x IcacheByteSize=16384 IcacheSetAssoc=8 DcacheByteSize=32768 DcacheSetAssoc=8 BHTEntries=128 NrScoreboardEntries=8 DCacheType=config_pkg::WT"]
|
||||
- BENCH: "coremark"
|
||||
ISSUE: "single"
|
||||
DV_HWCONFIG_OPTS: ["cv32a60x IcacheByteSize=16384 IcacheSetAssoc=8 DcacheByteSize=32768 DcacheSetAssoc=8 BHTEntries=128 NrScoreboardEntries=8 DCacheType=config_pkg::WT"]
|
||||
- BENCH: "coremark"
|
||||
ISSUE: "dual"
|
||||
DV_HWCONFIG_OPTS: ["cv32a65x IcacheByteSize=16384 IcacheSetAssoc=8 DcacheByteSize=32768 DcacheSetAssoc=8 BHTEntries=128 NrScoreboardEntries=8 DCacheType=config_pkg::WT"]
|
||||
script:
|
||||
- bash verif/regress/dhrystone.sh
|
||||
- python3 .gitlab-ci/scripts/report_benchmark.py --dhrystone verif/sim/out_*/veri-testharness_sim/dhrystone_main.*.log
|
||||
- bash verif/regress/"$BENCH".sh
|
||||
- python3 .gitlab-ci/scripts/report_benchmark.py --"$BENCH"_"$ISSUE" verif/sim/out_*/vcs-uvm_sim/"$BENCH"_main.*.log
|
||||
|
||||
riscv_arch_test:
|
||||
extends:
|
||||
|
@ -295,12 +363,13 @@ riscv_arch_test:
|
|||
DASHBOARD_JOB_DESCRIPTION: "Compliance regression suite"
|
||||
DASHBOARD_SORT_INDEX: 0
|
||||
DASHBOARD_JOB_CATEGORY: "Test suites"
|
||||
DV_SIMULATORS: "veri-testharness,spike"
|
||||
COLLECT_SIMU_LOGS: 1
|
||||
DV_SIMULATORS: "vcs-testharness"
|
||||
SPIKE_TANDEM: 1
|
||||
script: source verif/regress/dv-riscv-arch-test.sh
|
||||
after_script: *simu_after_script
|
||||
|
||||
compliance:
|
||||
timeout : 2 hours
|
||||
extends:
|
||||
- .regress_test
|
||||
variables:
|
||||
|
@ -308,12 +377,13 @@ compliance:
|
|||
DASHBOARD_JOB_DESCRIPTION: "Compliance regression suite"
|
||||
DASHBOARD_SORT_INDEX: 2
|
||||
DASHBOARD_JOB_CATEGORY: "Test suites"
|
||||
DV_SIMULATORS: "veri-testharness,spike"
|
||||
COLLECT_SIMU_LOGS: 1
|
||||
DV_SIMULATORS: "vcs-testharness"
|
||||
SPIKE_TANDEM: 1
|
||||
script: source verif/regress/dv-riscv-compliance.sh
|
||||
after_script: *simu_after_script
|
||||
|
||||
riscv-tests-v:
|
||||
timeout : 2 hours
|
||||
extends:
|
||||
- .regress_test
|
||||
variables:
|
||||
|
@ -324,7 +394,6 @@ riscv-tests-v:
|
|||
DV_SIMULATORS: "veri-testharness,spike"
|
||||
DV_TARGET: cv64a6_imafdc_sv39
|
||||
DV_TESTLISTS: "../tests/testlist_riscv-tests-$DV_TARGET-v.yaml"
|
||||
COLLECT_SIMU_LOGS: 1
|
||||
script: source verif/regress/dv-riscv-tests.sh
|
||||
after_script: *simu_after_script
|
||||
|
||||
|
@ -336,9 +405,9 @@ riscv-tests-p:
|
|||
DASHBOARD_JOB_DESCRIPTION: "Riscv-test regression suite (physical)"
|
||||
DASHBOARD_SORT_INDEX: 4
|
||||
DASHBOARD_JOB_CATEGORY: "Test suites"
|
||||
DV_SIMULATORS: "veri-testharness,spike"
|
||||
DV_SIMULATORS: "vcs-testharness"
|
||||
SPIKE_TANDEM: 1
|
||||
DV_TESTLISTS: "../tests/testlist_riscv-tests-$DV_TARGET-p.yaml"
|
||||
COLLECT_SIMU_LOGS: 1
|
||||
script: source verif/regress/dv-riscv-tests.sh
|
||||
after_script: *simu_after_script
|
||||
|
||||
|
@ -361,7 +430,7 @@ mmu_sv32_tests:
|
|||
DASHBOARD_SORT_INDEX: 0
|
||||
DASHBOARD_JOB_CATEGORY: "Test suites"
|
||||
DV_SIMULATORS: "veri-testharness,spike"
|
||||
DV_TARGET: cv32a60x
|
||||
DV_TARGET: cv32a6_imac_sv32
|
||||
script: source verif/regress/dv-riscv-mmu-sv32-test.sh
|
||||
after_script: *simu_after_script
|
||||
|
||||
|
@ -371,6 +440,8 @@ generated_tests:
|
|||
variables:
|
||||
DASHBOARD_SORT_INDEX: 11
|
||||
DASHBOARD_JOB_CATEGORY: "Code Coverage"
|
||||
SPIKE_TANDEM: 1
|
||||
DV_SIMULATORS: "vcs-uvm"
|
||||
parallel:
|
||||
matrix:
|
||||
- list_num: 1
|
||||
|
@ -396,14 +467,17 @@ generated_tests:
|
|||
- source verif/regress/dv-generated-tests.sh
|
||||
- mv verif/sim/vcs_results/default/vcs.d/simv.vdb artifacts/coverage
|
||||
- mv verif/sim/seedlist.yaml artifacts/coverage
|
||||
- mv verif/sim/uvm_seed.log artifacts/coverage
|
||||
- python3 .gitlab-ci/scripts/report_pass.py
|
||||
|
||||
generated_xif_tests:
|
||||
.generated_xif_tests:
|
||||
extends:
|
||||
- .verif_test
|
||||
variables:
|
||||
DASHBOARD_SORT_INDEX: 12
|
||||
DASHBOARD_JOB_CATEGORY: "Code Coverage"
|
||||
SPIKE_TANDEM: 1
|
||||
DV_SIMULATORS: "vcs-uvm"
|
||||
parallel:
|
||||
matrix:
|
||||
- list_num: 1
|
||||
|
@ -414,6 +488,7 @@ generated_xif_tests:
|
|||
- source verif/regress/dv-generated-xif-tests.sh
|
||||
- mv verif/sim/vcs_results/default/vcs.d/simv.vdb artifacts/coverage
|
||||
- mv verif/sim/seedlist.yaml artifacts/coverage
|
||||
- mv verif/sim/uvm_seed.log artifacts/coverage
|
||||
- python3 .gitlab-ci/scripts/report_pass.py
|
||||
|
||||
directed_isacov-tests:
|
||||
|
@ -422,6 +497,8 @@ directed_isacov-tests:
|
|||
variables:
|
||||
DASHBOARD_SORT_INDEX: 13
|
||||
DASHBOARD_JOB_CATEGORY: "Functional Coverage"
|
||||
SPIKE_TANDEM: 1
|
||||
DV_SIMULATORS: "vcs-uvm"
|
||||
parallel:
|
||||
matrix:
|
||||
- list_num: 0
|
||||
|
@ -431,6 +508,7 @@ directed_isacov-tests:
|
|||
- mkdir -p artifacts/coverage
|
||||
- source verif/regress/dv-generated-tests.sh
|
||||
- mv verif/sim/vcs_results/default/vcs.d/simv.vdb artifacts/coverage
|
||||
- mv verif/sim/uvm_seed.log artifacts/coverage
|
||||
- python3 .gitlab-ci/scripts/report_pass.py
|
||||
|
||||
csr_embedded_tests:
|
||||
|
@ -442,11 +520,13 @@ csr_embedded_tests:
|
|||
DASHBOARD_SORT_INDEX: 15
|
||||
DASHBOARD_JOB_CATEGORY: "CSR tests"
|
||||
DV_SIMULATORS: "vcs-uvm"
|
||||
SPIKE_TANDEM: 1
|
||||
script:
|
||||
- mkdir -p artifacts/coverage
|
||||
- source verif/regress/dv-csr-embedded-tests.sh
|
||||
- mv verif/sim/vcs_results/default/vcs.d/simv.vdb artifacts/coverage
|
||||
- python3 .gitlab-ci/scripts/report_pass.py
|
||||
- mv verif/sim/uvm_seed.log artifacts/coverage
|
||||
- python3 .gitlab-ci/scripts/report_tandem.py verif/sim/out*/"$DV_SIMULATORS"_sim
|
||||
|
||||
.backend_test:
|
||||
stage: backend tests
|
||||
|
@ -463,8 +543,7 @@ simu-gate:
|
|||
- asic-synthesis
|
||||
parallel:
|
||||
matrix:
|
||||
- SIMU_PERIOD: ["20"] # 50 Mhz
|
||||
PERIOD: ["15"] # 66 Mhz
|
||||
- PROG_NAME: ["dhrystone_smoke"]
|
||||
variables:
|
||||
DASHBOARD_JOB_TITLE: "Gate Level Simulation $DV_TARGET"
|
||||
DASHBOARD_JOB_DESCRIPTION: "Tests to check netlist from ASIC synthesis and power consumption over different patterns"
|
||||
|
@ -472,29 +551,41 @@ simu-gate:
|
|||
DASHBOARD_JOB_CATEGORY: "Post Synthesis"
|
||||
DV_TARGET: cv32a65x
|
||||
TARGET: $DV_TARGET
|
||||
TOP: "cva6"
|
||||
SPIKE_TANDEM: 1
|
||||
SIMU_PERIOD: "20" # 50 Mhz
|
||||
PERIOD: "15" # 66 Mhz
|
||||
script:
|
||||
- git -C verif/core-v-verif fetch --unshallow
|
||||
- mkdir -p tools
|
||||
- mv artifacts/tools/spike tools
|
||||
- echo $SYN_VCS_BASHRC; source $SYN_VCS_BASHRC
|
||||
- mkdir -p artifacts/{reports,logs}
|
||||
- git -C verif/core-v-verif fetch --unshallow || git -C verif/core-v-verif fetch --all
|
||||
- !reference [.copy_spike_artifacts]
|
||||
- echo $PERIOD
|
||||
- source ./verif/sim/setup-env.sh
|
||||
- git clone ${SYNTH_SCRIPT} ${SYNTH_SCRIPT_PATH}
|
||||
- git clone ${SYNTH_SCRIPT} ${SYNTH_SCRIPT_PATH} -b ${SYNTH_SCRIPT_BRANCH}
|
||||
- git -C ${SYNTH_SCRIPT_PATH} checkout cce5ea41
|
||||
- cp -r ${SYNTH_SCRIPT_PATH}/cva6/ ../
|
||||
- git apply ${SYNTH_SCRIPT_PATH}/patches/*.patch
|
||||
- source verif/regress/install-riscv-tests.sh
|
||||
- mv artifacts/cva6_${DV_TARGET} pd/synth/
|
||||
- mv artifacts/cva6_${DV_TARGET}_synth.v pd/synth/
|
||||
- mv artifacts/cva6_${DV_TARGET}_synth.sdf pd/synth/
|
||||
- mkdir -p pd/synth/cva6_${DV_TARGET}/outputs/
|
||||
- python3 ${SYNTH_SCRIPT_PATH}/scharm -p configs/modules/CVA6.yml --runner=True --compaign="simu-gate" --name=$PROG_NAME
|
||||
- mv artifacts/${TOP}_${DV_TARGET} pd/synth/
|
||||
- mv artifacts/${TOP}_${DV_TARGET}_synth.v pd/synth/
|
||||
- mv artifacts/${TOP}_${DV_TARGET}_synth.sdf pd/synth/
|
||||
- mkdir -p pd/synth/${TOP}_${DV_TARGET}/outputs/
|
||||
- export DV_SIMULATORS="spike"
|
||||
- bash verif/regress/${PROG_NAME}.sh
|
||||
- cp verif/sim/out_*/directed_tests/*.o verif/sim/testelf.o
|
||||
- python3 ${SYNTH_SCRIPT_PATH}/scharm -p configs/modules/CVA6.yml --runner=True --compaign="simu-gate" --name=testelf
|
||||
- grep "Simulation terminated" verif/sim/out_*/*/*.log.iss
|
||||
- mv ${SYNTH_SCRIPT_PATH}/artifacts/ artifacts/artifacts_gate/
|
||||
after_script: *simu_after_script
|
||||
- rm artifacts/artifacts_gate/*/build/*.fsdb
|
||||
- mkdir -p verif/sim/out_reports
|
||||
- mkdir -p artifacts/sim_artifacts
|
||||
- for i in verif/sim/out*/vcs-uvm-gate*/*; do cp $i $(dirname $(dirname $i))/vcs-uvm_sim/gate.$(basename $i); done
|
||||
- python3 .gitlab-ci/scripts/report_tandem.py verif/sim/out*/vcs-uvm_sim
|
||||
|
||||
fpga-boot:
|
||||
extends:
|
||||
- .backend_test
|
||||
tags: [fpga,shell]
|
||||
tags: [$TAGS_RUNNER_FPGA]
|
||||
needs:
|
||||
- build_tools
|
||||
- fpga-build
|
||||
|
@ -507,11 +598,12 @@ fpga-boot:
|
|||
- source ./verif/sim/setup-env.sh
|
||||
- source $VIVADO2022_SETUP
|
||||
- mkdir -p corev_apu/fpga/work-fpga
|
||||
- mv artifacts/ariane_xilinx_cv32a60x.bit corev_apu/fpga/work-fpga/ariane_xilinx.bit
|
||||
- mv artifacts/ariane_xilinx_cv32a6_imac_sv32.bit corev_apu/fpga/work-fpga/ariane_xilinx.bit
|
||||
- cd corev_apu/fpga/scripts
|
||||
- source check_fpga_boot.sh
|
||||
- cd -
|
||||
- python3 .gitlab-ci/scripts/report_fpga_boot.py corev_apu/fpga/scripts/fpga_boot.rpt
|
||||
retry: 1
|
||||
|
||||
code_coverage-report:
|
||||
extends:
|
||||
|
@ -519,7 +611,7 @@ code_coverage-report:
|
|||
needs:
|
||||
- generated_tests
|
||||
- directed_isacov-tests
|
||||
- generated_xif_tests
|
||||
# - generated_xif_tests
|
||||
- csr_embedded_tests
|
||||
variables:
|
||||
DASHBOARD_JOB_TITLE: "Report merge coverage"
|
||||
|
@ -532,12 +624,14 @@ code_coverage-report:
|
|||
- mkdir -p verif/sim/vcs_results/default/vcs.d
|
||||
- mv artifacts/coverage/simv.vdb verif/sim/vcs_results/default/vcs.d/
|
||||
- mv artifacts/coverage/seedlist.yaml verif/sim/seedlist.yaml
|
||||
- mv artifacts/coverage/uvm_seed.log verif/sim/uvm_seed.log
|
||||
- make -C verif/sim generate_cov_dash
|
||||
- mv verif/sim/urgReport artifacts/cov_reports/
|
||||
- python3 .gitlab-ci/scripts/report_coverage.py artifacts/cov_reports/urgReport/hierarchy.txt artifacts/cov_reports/urgReport/"feature.CVA6 Verification Master Plan1.7.-1268999905.txt"
|
||||
|
||||
check gitlab jobs status:
|
||||
stage: find failures
|
||||
tags: [$TAGS_RUNNER]
|
||||
rules:
|
||||
- if: $DASHBOARD_URL && $CI_KIND != "none"
|
||||
when: on_failure
|
||||
|
@ -554,6 +648,7 @@ check gitlab jobs status:
|
|||
|
||||
merge reports:
|
||||
stage: report
|
||||
tags: [$TAGS_RUNNER]
|
||||
variables:
|
||||
GIT_SUBMODULE_STRATEGY: none
|
||||
rules:
|
||||
|
|
|
@ -1,4 +1,2 @@
|
|||
cv32a6_embedded:
|
||||
gates: 110095
|
||||
cv32a65x:
|
||||
gates: 128136
|
||||
gates: 184679
|
||||
|
|
|
@ -3,6 +3,7 @@ This module makes it possible to trigger GitHub workflows.
|
|||
"""
|
||||
|
||||
from os import environ as env
|
||||
import time
|
||||
import requests
|
||||
|
||||
def api_url(owner, repo):
|
||||
|
@ -52,6 +53,7 @@ class DashboardDone(Workflow):
|
|||
'pr_number': str(pr),
|
||||
'success': success,
|
||||
}
|
||||
time.sleep(120)
|
||||
return self._trigger(inputs)
|
||||
|
||||
def send_success(self, pr):
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
#
|
||||
# Original Author: Côme Allart
|
||||
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
import report_builder as rb
|
||||
|
||||
path = None
|
||||
|
@ -17,54 +19,57 @@ iterations = None
|
|||
# Keep it up-to-date with compiler version and core performance improvements
|
||||
# Will fail if the number of cycles is different from this one
|
||||
valid_cycles = {
|
||||
'dhrystone': 217900,
|
||||
'coremark': 665193,
|
||||
"dhrystone_dual": 18935,
|
||||
"dhrystone_single": 24127,
|
||||
"coremark_dual": 1001191,
|
||||
"coremark_single": 1300030,
|
||||
"dhrystone_cv32a65x": 31976,
|
||||
"dhrystone_cv32a60x": 39449,
|
||||
}
|
||||
|
||||
for arg in sys.argv[1:]:
|
||||
if arg == '--dhrystone':
|
||||
mode = 'dhrystone'
|
||||
# Standard value for Dhrystone
|
||||
iterations = 500
|
||||
elif arg == '--coremark':
|
||||
mode = 'coremark'
|
||||
# Defined in verif/regress/coremark.sh
|
||||
iterations = 2
|
||||
if "--dhrystone" in arg or "--coremark" in arg:
|
||||
if "--dhrystone" in arg:
|
||||
iterations = 50
|
||||
else:
|
||||
if "--coremark" in arg:
|
||||
iterations = 4
|
||||
mode = arg.replace("-", "")
|
||||
else:
|
||||
path = arg
|
||||
|
||||
# We do not want to have a report without a check
|
||||
assert mode is not None
|
||||
|
||||
with open(path, 'r') as f:
|
||||
with open(path, "r") as f:
|
||||
log = [l.strip() for l in f.readlines()]
|
||||
|
||||
stopwatch = []
|
||||
for index, line in enumerate(log):
|
||||
if line.split()[-1] == 'mcycle' or line.split()[-2] == 'mcycle,':
|
||||
if line.split()[-1] == "mcycle" or line.split()[-2] == "mcycle,":
|
||||
stopwatch.append(int(log[index + 1].split()[-1], 16))
|
||||
# There might be > 2 matches, we use the two at the center
|
||||
N = len(stopwatch)
|
||||
assert N % 2 == 0
|
||||
cycles = stopwatch[N//2] - stopwatch[N//2-1]
|
||||
cycles = stopwatch[N // 2] - stopwatch[N // 2 - 1]
|
||||
|
||||
score_metric = rb.TableMetric('Performance results')
|
||||
score_metric.add_value('cycles', cycles)
|
||||
score_metric = rb.TableMetric("Performance results")
|
||||
score_metric.add_value("cycles", cycles)
|
||||
|
||||
if iterations is not None:
|
||||
ipmhz = iterations * 1000000 / cycles
|
||||
if mode == 'dhrystone':
|
||||
score_metric.add_value('Dhrystone/MHz', ipmhz)
|
||||
score_metric.add_value('DMIPS/MHz', ipmhz / 1757)
|
||||
if mode == 'coremark':
|
||||
score_metric.add_value('CoreMark/MHz', ipmhz)
|
||||
if "dhrystone" in mode:
|
||||
score_metric.add_value("Dhrystone/MHz", ipmhz)
|
||||
score_metric.add_value("DMIPS/MHz", ipmhz / 1757)
|
||||
if "coremark" in mode:
|
||||
score_metric.add_value("CoreMark/MHz", ipmhz)
|
||||
|
||||
diff = cycles - valid_cycles[mode]
|
||||
if diff != 0:
|
||||
score_metric.fail()
|
||||
score_metric.add_value('Cycles diff', diff)
|
||||
score_metric.add_value("Cycles diff", diff)
|
||||
|
||||
report = rb.Report(f'{cycles//1000} kCycles')
|
||||
report = rb.Report(f"{cycles//1000} kCycles")
|
||||
report.add_metric(score_metric)
|
||||
report.dump()
|
||||
|
||||
|
|
|
@ -172,12 +172,19 @@ class Report:
|
|||
|
||||
def dump(self, path=None):
|
||||
"""
|
||||
Create report file
|
||||
Print results and create report file
|
||||
|
||||
By default the output path is build from $CI_JOB_NAME
|
||||
"""
|
||||
for metric in self.metrics:
|
||||
print(metric.values)
|
||||
|
||||
if path is None:
|
||||
filename = re.sub(r'[^\w\.\\\/]', '_', os.environ["CI_JOB_NAME"])
|
||||
path = 'artifacts/reports/'+filename+'.yml'
|
||||
with open(path, 'w') as f:
|
||||
yaml.dump(self.to_doc(), f)
|
||||
ci_job_name = os.environ.get("CI_JOB_NAME")
|
||||
if ci_job_name is not None:
|
||||
filename = re.sub(r'[^\w\.\\\/]', '_', ci_job_name)
|
||||
path = 'artifacts/reports/'+filename+'.yml'
|
||||
|
||||
if path is not None:
|
||||
with open(path, 'w') as f:
|
||||
yaml.dump(self.to_doc(), f)
|
||||
|
|
|
@ -15,9 +15,6 @@ import report_builder as rb
|
|||
with open(str(sys.argv[1]), "r") as f:
|
||||
log = f.read()
|
||||
|
||||
with open(str(sys.argv[2]), "r") as f:
|
||||
outputlog = f.read()
|
||||
|
||||
pattern = re.compile(
|
||||
"\|(?P<ind> +)(?P<Instance>[\w()\[\].]+) +\| +(?P<Module>[\w()\[\].]+) \| +(?P<TotalLUTs>\d+) \| +(?P<LogicLUTs>\d+) \| +(?P<LUTRAMs>\d+) \| +(?P<SRLs>\d+) \| +(?P<FFs>\d+) \| +(?P<RAMB36>\d+) \| +(?P<RAMB18>\d+) \| +(?P<DSP48Blocks>\d+) \|"
|
||||
)
|
||||
|
@ -50,8 +47,5 @@ for i in data:
|
|||
i["DSP48Blocks"] + " DSP48Blocks",
|
||||
)
|
||||
|
||||
log_metric = rb.LogMetric("Last lines of logfile")
|
||||
log_metric.values = outputlog.splitlines()
|
||||
|
||||
report.add_metric(metric, log_metric)
|
||||
report.add_metric(metric)
|
||||
report.dump()
|
||||
|
|
|
@ -18,7 +18,7 @@ with open(str(sys.argv[1]), 'r') as f:
|
|||
with_logs = os.environ.get("COLLECT_SIMU_LOGS") != None
|
||||
|
||||
pattern = re.compile(
|
||||
r'(?:\w{3}, \d{2} \w{3} \d{4} \d{2}:\d{2}:\d{2} INFO )(?:Processing regression test list : (?:.*)/testlist_(.*-.*)(?:.yaml), test: (\S*)$[\s\S]*?^(?:\w{3}, \d{2} \w{3} \d{4} \d{2}:\d{2}:\d{2} INFO )Compiling (.*):.*$|Compiling (.*): .*(tests\S*))$[\s\S]*?^(?:\w{3}, \d{2} \w{3} \d{4} \d{2}:\d{2}:\d{2} INFO )Found matching ISS: (\S*)$[\s\S]*?^(?:\w{3}, \d{2} \w{3} \d{4} \d{2}:\d{2}:\d{2} INFO )Target: (\S*)$[\s\S]*?^(?:\w{3}, \d{2} \w{3} \d{4} \d{2}:\d{2}:\d{2}(?: INFO ))ISA (\S*)$[\s\S]*?^(?:\w{3}, \d{2} \w{3} \d{4} \d{2}:\d{2}:\d{2} (?:(?:INFO )\[(\w*)\]: (\d*) matched(?:, (\d*) mismatch)?)|(?:^(?:\w{3}, \d{2} \w{3} \d{4} \d{2}:\d{2}:\d{2})(?: ERROR )(\D{5})(?:.*)$))',
|
||||
r'(?:.*Compiling test: (.*))$[\s\S]*?(?:^.*Target: (.*)$)$[\s\S]*?(?:^.*ISA (.*)$)[\s\S]*?(?:^.*Found matching ISS: (.*)$)[\s\S]*?(?:^.*\[(PASSED|FAILED)\].*$)',
|
||||
re.MULTILINE)
|
||||
list_of_tests = pattern.findall(log)
|
||||
|
||||
|
@ -27,7 +27,6 @@ metric = rb.TableStatusMetric('')
|
|||
metric.add_column("TARGET", "text")
|
||||
metric.add_column("ISA", "text")
|
||||
metric.add_column("TEST", "text")
|
||||
metric.add_column("TEST LIST", "text")
|
||||
|
||||
if with_logs:
|
||||
metric.add_column("OUTPUT", "log")
|
||||
|
@ -40,22 +39,20 @@ job_test_total = 0
|
|||
for i in list_of_tests:
|
||||
job_test_total += 1
|
||||
|
||||
target = i[6]
|
||||
isa = i[7]
|
||||
test = i[1] or i[4].split("/")[-1].split(".")[0]
|
||||
testsuite = i[0] or "custom test"
|
||||
test_type = i[2] or i[4]
|
||||
target = i[1]
|
||||
isa = i[2]
|
||||
test = i[0]
|
||||
|
||||
if with_logs:
|
||||
logsPath = "logs/" + os.environ.get("CI_JOB_ID") + "/artifacts/logs/"
|
||||
output_log = logsPath + 'logfile.log.head'
|
||||
tb_log = logsPath + test + "." + target + '.log.iss.head'
|
||||
disassembly = logsPath + test + "." + target + '.csv.head'
|
||||
col = [target, isa, test, testsuite, output_log, tb_log, disassembly]
|
||||
output_log = logsPath + 'logfile.log'
|
||||
tb_log = logsPath + test + "." + target + '.log.iss'
|
||||
disassembly = logsPath + test + "." + target + '.csv'
|
||||
col = [target, isa, test, output_log, tb_log, disassembly]
|
||||
else:
|
||||
col = [target, isa, test, testsuite]
|
||||
col = [target, isa, test]
|
||||
|
||||
if i[8] == "PASSED":
|
||||
if i[4] == "PASSED":
|
||||
metric.add_pass(*col)
|
||||
job_test_pass += 1
|
||||
else:
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
import re
|
||||
import sys
|
||||
|
||||
import report_builder as rb
|
||||
|
||||
|
||||
|
@ -69,11 +68,17 @@ def compare_summaries(baseline_info, new_info):
|
|||
message = (
|
||||
f"Count changed from {baseline_dict[key][0]} to {new_dict[key][0]}"
|
||||
)
|
||||
comparison_results.append((*key, *value, "PASS", message))
|
||||
if key[0] == "ERROR" and new_dict[key][0] > baseline_dict[key][0]:
|
||||
comparison_results.append((*key, *value, "FAIL", message))
|
||||
else:
|
||||
comparison_results.append((*key, *value, "PASS", message))
|
||||
|
||||
severity_order = {"ERROR": 1, "WARNING": 2, "INFO": 3}
|
||||
comparison_results.sort(key=lambda x: severity_order[x[0]])
|
||||
return comparison_results
|
||||
|
||||
|
||||
def report_spyglass_lint(comparison_results):
|
||||
def generate_spyglass_lint_report(comparison_results):
|
||||
metric = rb.TableStatusMetric("")
|
||||
metric.add_column("SEVERITY", "text")
|
||||
metric.add_column("RULE NAME", "text")
|
||||
|
@ -90,7 +95,10 @@ def report_spyglass_lint(comparison_results):
|
|||
|
||||
report = rb.Report()
|
||||
report.add_metric(metric)
|
||||
report.dump()
|
||||
|
||||
for value in metric.values:
|
||||
print(" | ".join(map(str, value)))
|
||||
return report
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -103,4 +111,8 @@ if __name__ == "__main__":
|
|||
baseline_info = extract_info(summary_ref_results)
|
||||
new_info = extract_info(summary_rpt)
|
||||
comparison_results = compare_summaries(baseline_info, new_info)
|
||||
report_spyglass_lint(comparison_results)
|
||||
report = generate_spyglass_lint_report(comparison_results)
|
||||
print(report.failed)
|
||||
report.dump()
|
||||
if report.failed:
|
||||
sys.exit(1)
|
||||
|
|
|
@ -82,7 +82,7 @@ hier_metric = rb.TableMetric('Hierarchies details')
|
|||
for i in hier:
|
||||
hier_metric.add_value(
|
||||
i[0], # hier
|
||||
f"{int(float(i[1])/kgate_ratio)} kGates", # area
|
||||
f"{float(i[1])/kgate_ratio:.3f} kGates", # area
|
||||
f"{int(float(i[2]))} %", # %
|
||||
#int(float(i[3]))/int(float(i[1])*100), # % combi
|
||||
#int(float(i[4]))/int(float(i[1])*100), # % reg
|
||||
|
|
107
.gitlab-ci/scripts/report_tandem.py
Normal file
107
.gitlab-ci/scripts/report_tandem.py
Normal file
|
@ -0,0 +1,107 @@
|
|||
# Copyright 2024 Thales DIS France SAS
|
||||
#
|
||||
# Licensed under the Solderpad Hardware Licence, Version 0.51 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
||||
# You may obtain a copy of the License at https://solderpad.org/licenses/
|
||||
#
|
||||
# Original Author: Valentin Thomazic (valentin.thomazic@thalesgroup.com)
|
||||
|
||||
import sys
|
||||
import report_builder
|
||||
import os
|
||||
import glob
|
||||
import yaml
|
||||
|
||||
|
||||
def main():
|
||||
with_logs = os.environ.get("COLLECT_SIMU_LOGS") != None
|
||||
metrics_table = report_builder.TableStatusMetric('')
|
||||
|
||||
check_provided_args()
|
||||
add_table_legend(metrics_table, with_logs)
|
||||
passed_tests_count, total_tests_count = fill_table(sys.argv[1], metrics_table, with_logs)
|
||||
|
||||
if not report(metrics_table, passed_tests_count, total_tests_count):
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def check_provided_args():
|
||||
if len(sys.argv) != 2:
|
||||
sys.exit("Usage : python report_tandem.py path/to/log/dir")
|
||||
|
||||
if not os.path.exists(sys.argv[1]):
|
||||
sys.exit("No valid log directory provided!")
|
||||
|
||||
if len(list(glob.iglob(sys.argv[1] + "/*.yaml"))) == 0:
|
||||
sys.exit("No reports in log directory!")
|
||||
|
||||
|
||||
def add_table_legend(metrics_table, with_logs):
|
||||
metrics_table.add_column("TARGET", "text")
|
||||
metrics_table.add_column("ISA", "text")
|
||||
metrics_table.add_column("TEST", "text")
|
||||
metrics_table.add_column("TEST LIST", "text")
|
||||
metrics_table.add_column("SIMULATOR", "text")
|
||||
metrics_table.add_column("MISMATCHES", "text")
|
||||
|
||||
if with_logs:
|
||||
metrics_table.add_column("OUTPUT", "log")
|
||||
metrics_table.add_column("TANDEM REPORT", "log")
|
||||
metrics_table.add_column("TB LOGS", "log")
|
||||
metrics_table.add_column("DISASSEMBLY", "log")
|
||||
|
||||
|
||||
def fill_table(reports_dir, metrics_table, with_logs):
|
||||
simulation_reports = glob.iglob(reports_dir + "/*.yaml")
|
||||
test_passed = 0
|
||||
test_count = 0
|
||||
|
||||
for report in simulation_reports:
|
||||
test_passed += add_test_row(report, metrics_table, with_logs)
|
||||
test_count += 1
|
||||
if test_passed != test_count:
|
||||
metrics_table.fail()
|
||||
return test_passed, test_count
|
||||
|
||||
|
||||
def add_test_row(report_file, metrics_table, with_logs):
|
||||
try:
|
||||
with open(report_file) as f:
|
||||
report = yaml.safe_load(f)
|
||||
mismatches_count = str(report["mismatches_count"]) if "mismatches_count" in report else "Not found"
|
||||
|
||||
row = [report["target"], report["isa"], report["test"], report["testlist"], report["simulator"], mismatches_count]
|
||||
|
||||
if with_logs:
|
||||
logs_path = "logs/" + os.environ.get("CI_JOB_ID") + "/artifacts/logs/"
|
||||
output_log = logs_path + "logfile.log"
|
||||
log_prefix = logs_path + report['test'] + "_" + str(report["iteration"]) + "." + report["target"] \
|
||||
if "iteration" in report else logs_path + report['test'] + "." + report["target"]
|
||||
tb_log = log_prefix + '.log.iss'
|
||||
disassembly = log_prefix + '.log.csv'
|
||||
tandem_report = log_prefix + '.log.yaml'
|
||||
|
||||
row.append(output_log)
|
||||
row.append(tandem_report)
|
||||
row.append(tb_log)
|
||||
row.append(disassembly)
|
||||
|
||||
if report["exit_cause"] == "SUCCESS" and report["exit_code"] == 0:
|
||||
metrics_table.add_pass(*row)
|
||||
return 1
|
||||
|
||||
metrics_table.add_fail(*row)
|
||||
return 0
|
||||
except (TypeError, KeyError):
|
||||
sys.exit("Invalid yaml file in log directory! Is the log directory correct?")
|
||||
|
||||
def report(metrics_table, passed_test_count, total_test_count):
|
||||
report = report_builder.Report(f'{passed_test_count}/{total_test_count}')
|
||||
report.add_metric(metrics_table)
|
||||
report.dump()
|
||||
return not report.failed
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
8
.gitmodules
vendored
8
.gitmodules
vendored
|
@ -47,5 +47,11 @@
|
|||
path = verif/sim/dv
|
||||
url = https://github.com/google/riscv-dv.git
|
||||
[submodule "docs/06_cv32a65x_riscv/riscv-isa-manual"]
|
||||
path = docs/06_cv32a65x_riscv/riscv-isa-manual
|
||||
path = docs/riscv-isa/riscv-isa-manual
|
||||
url = https://github.com/riscv/riscv-isa-manual.git
|
||||
[submodule "corev_apu/fpga/src/apb"]
|
||||
path = corev_apu/fpga/src/apb
|
||||
url = https://github.com/pulp-platform/apb.git
|
||||
[submodule "corev_apu/fpga/src/gpio"]
|
||||
path = corev_apu/fpga/src/gpio
|
||||
url = https://github.com/pulp-platform/gpio.git
|
||||
|
|
|
@ -4,10 +4,30 @@
|
|||
|
||||
version: 2
|
||||
|
||||
submodules:
|
||||
include:
|
||||
- docs/riscv-isa/riscv-isa-manual
|
||||
recursive: true
|
||||
|
||||
build:
|
||||
os: "ubuntu-20.04"
|
||||
tools:
|
||||
python: "3.9"
|
||||
nodejs: "20"
|
||||
ruby: "3.3"
|
||||
apt_packages:
|
||||
- cmake
|
||||
- bison
|
||||
- flex
|
||||
- libpango1.0-dev
|
||||
- libgdk-pixbuf2.0-0
|
||||
- libgtk2.0-dev
|
||||
jobs:
|
||||
post_install:
|
||||
- npm install docs/riscv-isa/riscv-isa-manual/dependencies
|
||||
- gem install -g docs/riscv-isa/riscv-isa-manual/dependencies/Gemfile
|
||||
pre_build:
|
||||
- PATH=$PWD/node_modules/.bin:$PATH make -C docs prepare
|
||||
|
||||
# Build from the docs directory with Sphinx
|
||||
sphinx:
|
||||
|
|
12
Bender.yml
12
Bender.yml
|
@ -1,5 +1,5 @@
|
|||
package:
|
||||
name: ariane
|
||||
name: cva6
|
||||
authors:
|
||||
- "Florian Zaruba <zarubaf@iis.ee.ethz.ch>"
|
||||
- "Michael Schaffner <schaffner@iis.ee.ethz.ch>"
|
||||
|
@ -68,6 +68,7 @@ sources:
|
|||
- target: any(cv64a6_imafdcv_sv39, cv64a6_imafdc_sv39, cv64a6_imafdc_sv39_wb, cv64a6_imafdch_sv39, cv64a6_imafdch_sv39_wb, cv32a6_imac_sv0, cv32a6_imac_sv32, cv32a6_imafc_sv32)
|
||||
files:
|
||||
- core/cva6_mmu/cva6_tlb.sv
|
||||
- core/cva6_mmu/cva6_shared_tlb.sv
|
||||
- core/cva6_mmu/cva6_mmu.sv
|
||||
- core/cva6_mmu/cva6_ptw.sv
|
||||
|
||||
|
@ -76,9 +77,10 @@ sources:
|
|||
- core/include/std_cache_pkg.sv
|
||||
|
||||
# Extension Interface
|
||||
- core/include/cvxif_pkg.sv
|
||||
- core/cvxif_example/include/cvxif_instr_pkg.sv
|
||||
- core/cvxif_fu.sv
|
||||
- core/cvxif_issue_register_commit_if_driver.sv
|
||||
- core/cvxif_compressed_if_driver.sv
|
||||
- core/cvxif_example/cvxif_example_coprocessor.sv
|
||||
- core/cvxif_example/instr_decoder.sv
|
||||
|
||||
|
@ -96,6 +98,7 @@ sources:
|
|||
- core/csr_regfile.sv
|
||||
- core/decoder.sv
|
||||
- core/ex_stage.sv
|
||||
- core/acc_dispatcher.sv
|
||||
- core/instr_realign.sv
|
||||
- core/id_stage.sv
|
||||
- core/issue_read_operands.sv
|
||||
|
@ -119,6 +122,7 @@ sources:
|
|||
# Frontend (i.e., fetch, decode, dispatch)
|
||||
- core/frontend/btb.sv
|
||||
- core/frontend/bht.sv
|
||||
- core/frontend/bht2lvl.sv
|
||||
- core/frontend/ras.sv
|
||||
- core/frontend/instr_scan.sv
|
||||
- core/frontend/instr_queue.sv
|
||||
|
@ -143,6 +147,7 @@ sources:
|
|||
# Physical Memory Protection
|
||||
- core/pmp/src/pmp.sv
|
||||
- core/pmp/src/pmp_entry.sv
|
||||
- core/pmp/src/pmp_data_if.sv
|
||||
|
||||
- include_dirs:
|
||||
- common/local/util
|
||||
|
@ -154,12 +159,15 @@ sources:
|
|||
- common/local/util
|
||||
files:
|
||||
- common/local/util/tc_sram_wrapper.sv
|
||||
- common/local/util/sram_cache.sv
|
||||
|
||||
- target: all(fpga, xilinx)
|
||||
include_dirs:
|
||||
- common/local/util
|
||||
files:
|
||||
- common/local/util/sram_cache.sv
|
||||
- common/local/util/tc_sram_fpga_wrapper.sv
|
||||
- vendor/pulp-platform/fpga-support/rtl/SyncSpRamBeNx64.sv
|
||||
|
||||
- target: not(synthesis)
|
||||
include_dirs:
|
||||
|
|
13
CODEOWNERS
13
CODEOWNERS
|
@ -1,5 +1,5 @@
|
|||
# Global Owners
|
||||
* @JeanRochCoulon @zarubaf
|
||||
* @JeanRochCoulon
|
||||
|
||||
# Core
|
||||
|
||||
|
@ -7,9 +7,18 @@ core/mmu_sv39 @sjthales
|
|||
core/cvxif_example @Gchauvon
|
||||
core/cvxif_fu.sv @Gchauvon
|
||||
|
||||
# APU
|
||||
# HPDCache
|
||||
|
||||
core/cache_subsystem/hpdcache @cfuguet
|
||||
core/cache_subsystem/cva6_hpdcache* @cfuguet
|
||||
core/include/cv64a6_imafdc_sv39_hpdcache_config_pkg.sv @cfuguet
|
||||
core/include/cv64a6_imafdc_sv39_hpdcache_wb_config_pkg.sv @cfuguet
|
||||
|
||||
# OpenPiton
|
||||
|
||||
corev_apu/openpiton @Jbalkind
|
||||
core/cache_subsystem/wt_l15_adapter.sv @Jbalkind
|
||||
core/include/cv64a6_imafdc_sv39_openpiton_config_pkg.sv @Jbalkind
|
||||
|
||||
## Documentation
|
||||
|
||||
|
|
|
@ -22,8 +22,8 @@ Therefore here are guidelines to help the CVA6 team accept new contributions:
|
|||
* If you do not know how to contact us already, get in touch through info@openhwgroup.org or open an issue in GitHub.
|
||||
|
||||
- Specific recommendations:
|
||||
* Always consider using the CV-X-IF interface if your contribution is an instruction-set extension.
|
||||
- and talk to the team if it's not possible.
|
||||
* For instruction set extensions, talk to the team to assess the relevance of including it into the core or as a coprocessor on the CV-X-IF interface.
|
||||
- If the extension is custom (not a RISC-V specified extension), a coprocessor on CV-X-IF is definitely its place.
|
||||
* Your contribution shall be optional and fully disabled by default.
|
||||
- so that projects already using CVA6 are not impacted (no functionality change, no extra silicon...).
|
||||
* To configure your contribution, System Verilog top-level parameters are preferred.
|
||||
|
@ -34,6 +34,12 @@ Therefore here are guidelines to help the CVA6 team accept new contributions:
|
|||
* Your complete contribution shall be identifiable with parameters (or `directives / templating if together we decide to go this way).
|
||||
- If at some point we need to revert it, e.g. if there is no-one maintaining nor using it and it has become a burden to the project.
|
||||
- We call this the "parachute" rule: The CVA6 team does not want to use it but is far more comfortable getting one.
|
||||
- Also, this allows not to lose code coverage in verification when your contribution is not enabled (with some tweaks in the coverage tool).
|
||||
- This rule also applies to CSRs which are specific to your contribution.
|
||||
* To ease maintenance, all common code lines shall exist only once.
|
||||
- Counter-example: CVA6 used to have two different MMU modules (Sv32 and Sv39) for CV32A6 and CV64A6.
|
||||
- It took time to refactor both in a joint design to ease maintenance.
|
||||
- Related reading for reference: [DRY principle](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)
|
||||
* Your contribution shall pass the Continuous Integration (CI) flow
|
||||
- When the contribution is disabled: in all cases, to ensure you have not broken the design.
|
||||
- When the contribution is disabled: the line and condition code coverage shall not be impacted.
|
||||
|
@ -61,6 +67,12 @@ See the [Git Cheats](https://github.com/openhwgroup/core-v-verif/blob/master/Git
|
|||
6. Push feature branch: `git push origin <my_branch>`
|
||||
7. From GitHub: submit a pull request
|
||||
|
||||
Please note that we do not accept outdated pull requests.
|
||||
This makes sure the CI flow has run in the to-be version of the master.
|
||||
|
||||
To allow us to update the pull request before merging it, please consider checking the "Allow edits from maintainers" checkbox.
|
||||
Note that this can only be done with pull requests from your personal repository (it is impossible from organization repositories).
|
||||
|
||||
## Coding Style
|
||||
|
||||
For RTL coding, the OpenHW Group has adopted the [lowRISC Style Guides](https://github.com/lowRISC/style-guides/).
|
||||
|
|
|
@ -72,6 +72,7 @@ core/decoder.sv
|
|||
core/ex_stage.sv
|
||||
core/frontend/btb.sv
|
||||
core/frontend/bht.sv
|
||||
core/frontend/bht2lvl.sv
|
||||
core/frontend/ras.sv
|
||||
core/frontend/instr_scan.sv
|
||||
core/frontend/instr_queue.sv
|
||||
|
@ -160,6 +161,7 @@ vendor/openhwgroup/cvfpu/src/fpnew_rounding.sv
|
|||
vendor/openhwgroup/cvfpu/src/fpnew_top.sv
|
||||
core/pmp/src/pmp.sv
|
||||
core/pmp/src/pmp_entry.sv
|
||||
core/pmp/src/pmp_data_if.sv
|
||||
common/local/util/instr_tracer.sv
|
||||
core/cvxif_example/cvxif_example_coprocessor.sv
|
||||
core/cvxif_example/instr_decoder.sv
|
||||
|
|
190
Makefile
190
Makefile
|
@ -40,7 +40,10 @@ torture-logs :=
|
|||
elf_file ?= tmp/riscv-tests/build/benchmarks/dhrystone.riscv
|
||||
# board name for bitstream generation. Currently supported: kc705, genesys2, nexys_video
|
||||
BOARD ?= genesys2
|
||||
|
||||
ALTERA_BOARD ?= DK-DEV-AGF014E3ES
|
||||
ALTERA_FAMILY ?= "AGILEX"
|
||||
ALTERA_PART ?= AGFB014R24B2E2V
|
||||
PLATFORM = "PLAT_XILINX"
|
||||
# root path
|
||||
mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||
root-dir := $(dir $(mkfile_path))
|
||||
|
@ -142,7 +145,7 @@ CFLAGS += -I$(QUESTASIM_HOME)/include \
|
|||
-I$(VL_INC_DIR)/vltstd \
|
||||
-I$(RISCV)/include \
|
||||
-I$(SPIKE_INSTALL_DIR)/include \
|
||||
-std=c++17 -I../corev_apu/tb/dpi -O3
|
||||
-std=c++17 -I$(CVA6_REPO_DIR)/corev_apu/tb/dpi -O3
|
||||
|
||||
ifdef XCELIUM_HOME
|
||||
CFLAGS += -I$(XCELIUM_HOME)/tools/include
|
||||
|
@ -151,13 +154,13 @@ $(warning XCELIUM_HOME not set which is necessary for compiling DPIs when using
|
|||
endif
|
||||
|
||||
# this list contains the standalone components
|
||||
src := core/include/$(target)_config_pkg.sv \
|
||||
$(if $(spike-tandem),verif/tb/core/uvma_core_cntrl_pkg.sv) \
|
||||
src := $(if $(spike-tandem),verif/tb/core/uvma_core_cntrl_pkg.sv) \
|
||||
$(if $(spike-tandem),verif/tb/core/uvma_cva6pkg_utils_pkg.sv) \
|
||||
$(if $(spike-tandem),verif/tb/core/uvma_rvfi_pkg.sv) \
|
||||
$(if $(spike-tandem),verif/tb/core/uvmc_rvfi_reference_model_pkg.sv) \
|
||||
$(if $(spike-tandem),verif/tb/core/uvmc_rvfi_scoreboard_pkg.sv) \
|
||||
$(if $(spike-tandem),corev_apu/tb/common/spike.sv) \
|
||||
core/cva6_rvfi.sv \
|
||||
corev_apu/src/ariane.sv \
|
||||
$(wildcard corev_apu/bootrom/*.sv) \
|
||||
$(wildcard corev_apu/clint/*.sv) \
|
||||
|
@ -166,24 +169,18 @@ src := core/include/$(target)_config_pkg.sv
|
|||
$(wildcard corev_apu/fpga/src/axi_slice/src/*.sv) \
|
||||
$(wildcard corev_apu/src/axi_riscv_atomics/src/*.sv) \
|
||||
$(wildcard corev_apu/axi_mem_if/src/*.sv) \
|
||||
$(wildcard corev_apu/riscv-dbg/src/*.sv) \
|
||||
corev_apu/rv_plic/rtl/rv_plic_target.sv \
|
||||
corev_apu/rv_plic/rtl/rv_plic_gateway.sv \
|
||||
corev_apu/rv_plic/rtl/plic_regmap.sv \
|
||||
corev_apu/rv_plic/rtl/plic_top.sv \
|
||||
corev_apu/riscv-dbg/src/dmi_cdc.sv \
|
||||
corev_apu/riscv-dbg/src/dmi_jtag.sv \
|
||||
corev_apu/riscv-dbg/src/dmi_jtag_tap.sv \
|
||||
corev_apu/riscv-dbg/src/dm_csrs.sv \
|
||||
corev_apu/riscv-dbg/src/dm_mem.sv \
|
||||
corev_apu/riscv-dbg/src/dm_sba.sv \
|
||||
corev_apu/riscv-dbg/src/dm_top.sv \
|
||||
corev_apu/riscv-dbg/debug_rom/debug_rom.sv \
|
||||
corev_apu/register_interface/src/apb_to_reg.sv \
|
||||
vendor/pulp-platform/axi/src/axi_multicut.sv \
|
||||
vendor/pulp-platform/common_cells/src/rstgen_bypass.sv \
|
||||
vendor/pulp-platform/common_cells/src/rstgen.sv \
|
||||
vendor/pulp-platform/common_cells/src/addr_decode.sv \
|
||||
vendor/pulp-platform/common_cells/src/stream_register.sv \
|
||||
vendor/pulp-platform/common_cells/src/stream_register.sv \
|
||||
vendor/pulp-platform/axi/src/axi_cut.sv \
|
||||
vendor/pulp-platform/axi/src/axi_join.sv \
|
||||
vendor/pulp-platform/axi/src/axi_delayer.sv \
|
||||
|
@ -217,11 +214,73 @@ copro_src := core/cvxif_example/include/cvxif_instr_pkg.sv \
|
|||
$(wildcard core/cvxif_example/*.sv)
|
||||
copro_src := $(addprefix $(root-dir), $(copro_src))
|
||||
|
||||
uart_src := $(wildcard corev_apu/fpga/src/apb_uart/src/*.vhd)
|
||||
uart_src := $(wildcard corev_apu/fpga/src/apb_uart/src/vhdl_orig/*.vhd)
|
||||
uart_src := $(addprefix $(root-dir), $(uart_src))
|
||||
|
||||
fpga_src := $(wildcard corev_apu/fpga/src/*.sv) $(wildcard corev_apu/fpga/src/ariane-ethernet/*.sv) common/local/util/tc_sram_fpga_wrapper.sv vendor/pulp-platform/fpga-support/rtl/SyncSpRamBeNx64.sv
|
||||
fpga_src := $(addprefix $(root-dir), $(fpga_src)) src/bootrom/bootrom_$(XLEN).sv
|
||||
uart_src_sv:= corev_apu/fpga/src/apb_uart/src/slib_clock_div.sv \
|
||||
corev_apu/fpga/src/apb_uart/src/slib_counter.sv \
|
||||
corev_apu/fpga/src/apb_uart/src/slib_edge_detect.sv \
|
||||
corev_apu/fpga/src/apb_uart/src/slib_fifo.sv \
|
||||
corev_apu/fpga/src/apb_uart/src/slib_input_filter.sv \
|
||||
corev_apu/fpga/src/apb_uart/src/slib_input_sync.sv \
|
||||
corev_apu/fpga/src/apb_uart/src/slib_mv_filter.sv \
|
||||
corev_apu/fpga/src/apb_uart/src/uart_baudgen.sv \
|
||||
corev_apu/fpga/src/apb_uart/src/uart_interrupt.sv \
|
||||
corev_apu/fpga/src/apb_uart/src/uart_receiver.sv \
|
||||
corev_apu/fpga/src/apb_uart/src/uart_transmitter.sv \
|
||||
corev_apu/fpga/src/apb_uart/src/apb_uart.sv \
|
||||
corev_apu/fpga/src/apb_uart/src/apb_uart_wrap.sv
|
||||
uart_src_sv := $(addprefix $(root-dir), $(uart_src_sv))
|
||||
|
||||
fpga_src := $(wildcard corev_apu/fpga/src/*.sv) $(wildcard corev_apu/fpga/src/ariane-ethernet/*.sv) common/local/util/tc_sram_fpga_wrapper.sv common/local/util/hpdcache_sram_1rw.sv common/local/util/hpdcache_sram_wbyteenable_1rw.sv vendor/pulp-platform/fpga-support/rtl/SyncSpRamBeNx64.sv vendor/pulp-platform/fpga-support/rtl/SyncSpRamBeNx32.sv vendor/pulp-platform/fpga-support/rtl/SyncSpRam.sv
|
||||
|
||||
altera_src := $(shell find $(root-dir)/corev_apu/altera/src -type f \( -name "*.v" -o -name "*.sv" -o -name "*.svh" \) -print | sed 's|//|/|g')
|
||||
altera_src += $(src)
|
||||
altera_src += $(shell find $(root-dir)/corev_apu/fpga/src -type f \( -name "*.v" -o -name "*.sv" \) -print | sed 's|//|/|g')
|
||||
altera_src += $(shell find $(root-dir)core/cvfpu/src/common_cells/src/ -maxdepth 1 -type f \( -name "*.v" -o -name "*.sv" -o -name "*.vhd" -o -name "*.svh" \) -print)
|
||||
altera_axi_src := $(shell find $(root-dir)/vendor/pulp-platform/axi/src -type f \( -name "*.v" -o -name "*.sv" \) -print | sed 's|//|/|g')
|
||||
|
||||
altera_src += $(root-dir)corev_apu/rv_plic/rtl/top_pkg.sv \
|
||||
$(root-dir)corev_apu/rv_plic/rtl/tlul_pkg.sv \
|
||||
$(root-dir)corev_apu/rv_plic/rtl/rv_plic_reg_top.sv \
|
||||
$(root-dir)corev_apu/rv_plic/rtl/rv_plic_reg_pkg.sv \
|
||||
$(root-dir)corev_apu/rv_plic/rtl/rv_plic.sv \
|
||||
$(root-dir)corev_apu/rv_plic/rtl/prim_subreg_ext.sv \
|
||||
$(root-dir)corev_apu/rv_plic/rtl/prim_subreg.sv \
|
||||
$(root-dir)vendor/pulp-platform/common_cells/src/cdc_fifo_gray.sv \
|
||||
$(root-dir)riscv-dbg/src/dm_obi_top.sv \
|
||||
$(root-dir)core/include/instr_tracer_pkg.sv \
|
||||
$(root-dir)core/cvfpu/src/fpu_div_sqrt_mvp/hdl/div_sqrt_mvp_wrapper.sv \
|
||||
$(root-dir)core/cache_subsystem/amo_alu.sv
|
||||
|
||||
altera_filter := corev_apu/tb/ariane_testharness.sv \
|
||||
corev_apu/tb/ariane_peripherals.sv \
|
||||
corev_apu/tb/rvfi_tracer.sv \
|
||||
corev_apu/tb/common/uart.sv \
|
||||
corev_apu/tb/common/SimDTM.sv \
|
||||
corev_apu/tb/common/SimJTAG.sv \
|
||||
corev_apu/fpga/src/apb/src/apb_test.sv \
|
||||
corev_apu/fpga/src/ariane_xilinx.sv \
|
||||
corev_apu/fpga/ariane_peripherals_xilinx.sv \
|
||||
corev_apu/fpga/src/apb/test/tb_apb_cdc.sv \
|
||||
corev_apu/fpga/src/apb/test/tb_apb_regs.sv \
|
||||
corev_apu/fpga/src/apb/test/tb_apb_demux.sv \
|
||||
corev_apu/fpga/src/gpio/test/tb_gpio.sv \
|
||||
vendor/pulp-platform/axi/src/axi_test.sv \
|
||||
corev_apu/riscv-dbg/src/dm_pkg.sv \
|
||||
corev_apu/riscv-dbg/src/dmi_jtag_tap.sv \
|
||||
corev_apu/riscv-dbg/src/dmi_jtag.sv \
|
||||
corev_apu/fpga/src/apb_uart/src/reg_uart_wrap.sv
|
||||
|
||||
altera_filter := $(addprefix $(root-dir), $(altera_filter))
|
||||
xil_debug_filter = $(addprefix $(root-dir), corev_apu/riscv-dbg/src/dm_obi_top.sv)
|
||||
xil_debug_filter += $(addprefix $(root-dir), corev_apu/riscv-dbg/src/dm_pkg.sv)
|
||||
xil_debug_filter += $(addprefix $(root-dir), corev_apu/riscv-dbg/src/dmi_vjtag_tap.sv)
|
||||
xil_debug_filter += $(addprefix $(root-dir), corev_apu/riscv-dbg/src/dmi_vjtag.sv)
|
||||
src := $(filter-out $(xil_debug_filter), $(src))
|
||||
|
||||
fpga_src += corev_apu/fpga/src/bootrom/bootrom_$(XLEN).sv
|
||||
fpga_src := $(addprefix $(root-dir), $(fpga_src))
|
||||
|
||||
# look for testbenches
|
||||
tbs := $(top_level_path) corev_apu/tb/ariane_testharness.sv core/cva6_rvfi.sv
|
||||
|
@ -256,11 +315,18 @@ incdir := $(CVA6_REPO_DIR)/vendor/pulp-platform/common_cells/include/ $(CVA6_REP
|
|||
$(SPIKE_INSTALL_DIR)/include/disasm/
|
||||
|
||||
# Compile and sim flags
|
||||
compile_flag += -incr -64 -nologo -quiet -suppress 13262 -suppress 8607 -permissive -svinputport=compat +define+$(defines) -suppress 8386 -suppress vlog-2577
|
||||
compile_flag += -incr -64 -nologo -quiet -suppress 13262 -suppress 8607 +permissive -svinputport=compat +define+$(defines) -suppress 8386 -suppress vlog-2577
|
||||
vopt_flag += -suppress 2085 -suppress 7063 -suppress 2698 -suppress 13262
|
||||
|
||||
ifdef config-file
|
||||
spike-yaml-plusarg = +config_file=$(spike_yaml)
|
||||
endif
|
||||
|
||||
uvm-flags += +UVM_NO_RELNOTES +UVM_VERBOSITY=UVM_LOW
|
||||
questa-flags += -t 1ns -64 $(gui-sim) $(QUESTASIM_FLAGS) +tohost_addr=$(tohost_addr) +define+QUESTA -suppress 3356 -suppress 3579
|
||||
questa-flags += -t 1ns -64 $(gui-sim) $(QUESTASIM_FLAGS) \
|
||||
+tohost_addr=$(shell ${RISCV}/bin/${CV_SW_PREFIX}nm -B $(elf) | grep -w tohost | cut -d' ' -f1) \
|
||||
+core_name=$(target) +define+QUESTA -suppress 3356 -suppress 3579 +report_file=$(report_file) \
|
||||
$(spike-yaml-plusarg)
|
||||
compile_flag_vhd += -64 -nologo -quiet -2008
|
||||
|
||||
# Iterate over all include directories and write them with +incdir+ prefixed
|
||||
|
@ -290,7 +356,7 @@ ifdef preload
|
|||
endif
|
||||
|
||||
ifdef spike-tandem
|
||||
questa-cmd += -gblso $(SPIKE_INSTALL_DIR)/lib/libriscv.so
|
||||
questa-cmd += -gblso $(SPIKE_INSTALL_DIR)/lib/libyaml-cpp.so -gblso $(SPIKE_INSTALL_DIR)/lib/libriscv.so
|
||||
endif
|
||||
|
||||
# remote bitbang is enabled
|
||||
|
@ -307,23 +373,23 @@ vcs_build: $(dpi-library)/ariane_dpi.so
|
|||
cd $(vcs-library) &&\
|
||||
vlogan $(if $(VERDI), -kdb,) -full64 -nc -sverilog +define+$(defines) -assert svaext -f $(flist) $(list_incdir) ../corev_apu/tb/common/mock_uart.sv -timescale=1ns/1ns &&\
|
||||
vlogan $(if $(VERDI), -kdb,) -full64 -nc -sverilog +define+$(defines) $(filter %.sv,$(ariane_pkg)) +incdir+core/include/+$(VCS_HOME)/etc/uvm-1.2/dpi &&\
|
||||
vhdlan $(if $(VERDI), -kdb,) -full64 -nc $(filter %.vhd,$(uart_src)) &&\
|
||||
vlogan $(if $(VERDI), -kdb,) -full64 -nc -sverilog $(uart_src_sv) &&\
|
||||
vlogan $(if $(VERDI), -kdb,) -full64 -nc -sverilog -assert svaext +define+$(defines) +incdir+$(VCS_HOME)/etc/uvm/src $(VCS_HOME)/etc/uvm/src/uvm_pkg.sv $(filter %.sv,$(src)) $(list_incdir) &&\
|
||||
vlogan $(if $(VERDI), -kdb,) -full64 -nc -sverilog -ntb_opts uvm-1.2 &&\
|
||||
vlogan $(if $(VERDI), -kdb,) -full64 -nc -sverilog -ntb_opts uvm-1.2 $(tbs) +define+$(defines) $(list_incdir) &&\
|
||||
vcs $(if $(DEBUG), -debug_access+all $(if $(VERDI), -kdb),) $(if $(TRACE_COMPACT),+vcs+fsdbon) -ignore initializer_driver_checks -timescale=1ns/1ns -ntb_opts uvm-1.2 work.$(top_level) -error="IWNF" \
|
||||
vcs -full64 $(if $(DEBUG), -debug_access+all $(if $(VERDI), -kdb),) $(if $(TRACE_COMPACT),+vcs+fsdbon) -ignore initializer_driver_checks -timescale=1ns/1ns -ntb_opts uvm-1.2 work.$(top_level) -error="IWNF" \
|
||||
$(if $(gate), -sdf Max:ariane_gate_tb.i_ariane.i_cva6:$(CVA6_REPO_DIR)/pd/synth/cva6_$(TARGET)_synth.sdf +neg_tchk, +notimingcheck)
|
||||
|
||||
vcs: vcs_build
|
||||
cd $(vcs-library) && \
|
||||
./simv +permissive $(if $(VERDI), -verdi -do $(root-dir)/init_testharness.do,) \
|
||||
+elf_file=$(elf_file) ++$(elf_file) $(if $(spike-tandem),-sv_lib $(SPIKE_INSTALL_DIR)/libriscv) \
|
||||
+elf_file=$(elf_file) ++$(elf_file) $(if $(spike-tandem), -sv_lib $(SPIKE_INSTALL_DIR)/libyaml-cpp) -sv_lib $(SPIKE_INSTALL_DIR)/libriscv \
|
||||
-sv_lib ../work-dpi/ariane_dpi | tee vcs.log
|
||||
|
||||
# Build the TB and module using QuestaSim
|
||||
build: $(library) $(library)/.build-srcs $(library)/.build-tb $(dpi-library)/ariane_dpi.so
|
||||
# Optimize top level
|
||||
$(VOPT) -64 -work $(library) $(top_level) -o $(top_level)_optimized +acc -check_synthesis -dpilib $(SPIKE_INSTALL_DIR)/lib/libriscv -dpilib $(SPIKE_INSTALL_DIR)/lib/lifesvr $(vopt_flag)
|
||||
$(VOPT) -64 -work $(library) $(top_level) -o $(top_level)_optimized +acc -check_synthesis -dpilib $(SPIKE_INSTALL_DIR)/lib/libriscv -dpilib $(SPIKE_INSTALL_DIR)/lib/libfesvr -dpilib $(SPIKE_INSTALL_DIR)/lib/libyaml-cpp $(vopt_flag)
|
||||
|
||||
# src files
|
||||
$(library)/.build-srcs: $(library)
|
||||
|
@ -351,7 +417,13 @@ $(dpi-library)/%.o: corev_apu/tb/dpi/%.cc $(dpi_hdr)
|
|||
$(dpi-library)/ariane_dpi.so: $(dpi)
|
||||
mkdir -p $(dpi-library)
|
||||
# Compile C-code and generate .so file
|
||||
$(CXX) -shared -m64 -o $(dpi-library)/ariane_dpi.so $? -L$(RISCV)/lib -L$(SPIKE_INSTALL_DIR)/lib -Wl,-rpath,$(RISCV)/lib -Wl,-rpath,$(SPIKE_INSTALL_DIR)/lib -lfesvr -lriscv
|
||||
$(CXX) -shared -m64 -o $(dpi-library)/ariane_dpi.so $? -L$(RISCV)/lib -L$(SPIKE_INSTALL_DIR)/lib -Wl,-rpath,$(RISCV)/lib -Wl,-rpath,$(SPIKE_INSTALL_DIR)/lib -lfesvr -lriscv -lyaml-cpp
|
||||
|
||||
$(dpi-library)/xrun_ariane_dpi.so: $(dpi)
|
||||
# Make Dir work-dpi
|
||||
mkdir -p $(dpi-library)
|
||||
# Compile C-code and generate .so file
|
||||
$(CXX) -shared -m64 -o $(dpi-library)/xrun_ariane_dpi.so $? -L$(RISCV)/lib -L$(SPIKE_INSTALL_DIR)/lib -Wl,-rpath,$(RISCV)/lib -Wl,-rpath,$(SPIKE_INSTALL_DIR)/lib -lfesvr -lriscv -lyaml-cpp
|
||||
|
||||
# single test runs on Questa can be started by calling make <testname>, e.g. make towers.riscv
|
||||
# the test names are defined in ci/riscv-asm-tests.list, and in ci/riscv-benchmarks.list
|
||||
|
@ -363,8 +435,8 @@ generate-trace-vsim:
|
|||
|
||||
sim: build
|
||||
$(VSIM) +permissive $(questa-flags) $(questa-cmd) -lib $(library) +MAX_CYCLES=$(max_cycles) +UVM_TESTNAME=$(test_case) \
|
||||
+BASEDIR=$(riscv-test-dir) $(uvm-flags) -sv_lib $(SPIKE_INSTALL_DIR)/lib/libriscv -sv_lib $(SPIKE_INSTALL_DIR)/lib/libfesvr \
|
||||
-sv_lib $(SPIKE_INSTALL_DIR)/lib/libdisasm \
|
||||
+BASEDIR=$(riscv-test-dir) $(uvm-flags) -sv_lib $(SPIKE_INSTALL_DIR)/lib/libyaml-cpp -sv_lib $(SPIKE_INSTALL_DIR)/lib/libriscv -sv_lib $(SPIKE_INSTALL_DIR)/lib/libfesvr \
|
||||
-sv_lib $(SPIKE_INSTALL_DIR)/lib/libdisasm \
|
||||
${top_level}_optimized +permissive-off +elf_file=$(elf_file) ++$(elf_file) ++$(target-options)
|
||||
|
||||
$(riscv-asm-tests): build
|
||||
|
@ -429,24 +501,25 @@ check-benchmarks:
|
|||
XRUN ?= xrun
|
||||
XRUN_WORK_DIR ?= xrun_work
|
||||
XRUN_RESULTS_DIR ?= xrun_results
|
||||
XRUN_UVMHOME_ARG ?= CDNS-1.2-ML
|
||||
##XRUN_UVMHOME_ARG ?= CDNS-1.2-ML
|
||||
XRUN_UVMHOME_ARG ?= CDNS-1.2
|
||||
XRUN_COMPL_LOG ?= xrun_compl.log
|
||||
XRUN_RUN_LOG ?= xrun_run.log
|
||||
CVA6_HOME ?= $(realpath -s $(root-dir))
|
||||
|
||||
XRUN_INCDIR :=+incdir+$(CVA6_HOME)/src/axi_node \
|
||||
+incdir+$(CVA6_HOME)/src/common_cells/include \
|
||||
+incdir+$(CVA6_HOME)/src/util
|
||||
XRUN_INCDIR :=+incdir+$(CVA6_HOME)/core/include \
|
||||
+incdir+$(CVA6_HOME)/vendor/pulp-platform/axi/include/ \
|
||||
+incdir+$(CVA6_HOME)/corev_apu/register_interface/include
|
||||
|
||||
XRUN_TB := $(addprefix $(CVA6_HOME)/, corev_apu/tb/ariane_tb.sv)
|
||||
|
||||
XRUN_COMP_FLAGS ?= -64bit -disable_sem2009 -access +rwc \
|
||||
-sv -v93 -uvm -uvmhome $(XRUN_UVMHOME_ARG) \
|
||||
-sv_lib $(CVA6_HOME)/$(dpi-library)/ariane_dpi.so \
|
||||
XRUN_COMP_FLAGS ?= -64bit -v200x -disable_sem2009 -access +rwc \
|
||||
-sv -uvm -uvmhome $(XRUN_UVMHOME_ARG) \
|
||||
-sv_lib $(CVA6_HOME)/$(dpi-library)/xrun_ariane_dpi.so \
|
||||
-smartorder -sv -top worklib.$(top_level) \
|
||||
-xceligen on=1903 +define+$(defines) -timescale 1ns/1ps \
|
||||
-timescale 1ns/1ps
|
||||
|
||||
XRUN_RUN_FLAGS := -R -64bit -disable_sem2009 -access +rwc -timescale 1ns/1ps \
|
||||
-sv_lib $(CVA6_HOME)/$(dpi-library)/ariane_dpi.so -xceligen on=1903 \
|
||||
XRUN_RUN_FLAGS := -R -messages -status -64bit -licqueue -noupdate -uvmhome CDNS-1.2 -sv_lib $(CVA6_HOME)/$(dpi-library)/xrun_ariane_dpi.so +UVM_VERBOSITY=UVM_LOW
|
||||
|
||||
XRUN_DISABLED_WARNINGS := BIGWIX \
|
||||
ZROMCW \
|
||||
|
@ -460,21 +533,21 @@ XRUN_DISABLED_WARNINGS := $(patsubst %, -nowarn %, $(XRUN_DISABLED_WARNINGS))
|
|||
XRUN_COMP = $(XRUN_COMP_FLAGS) \
|
||||
$(XRUN_DISABLED_WARNINGS) \
|
||||
$(XRUN_INCDIR) \
|
||||
-f ../core/Flist.cva6 \
|
||||
$(filter %.sv, $(ariane_pkg)) \
|
||||
$(filter %.vhd, $(uart_src)) \
|
||||
$(filter %.sv, $(src)) \
|
||||
-f ../core/Flist.cva6 \
|
||||
$(filter %.sv, $(XRUN_TB)) \
|
||||
$(filter %.vhd, $(uart_src)) \
|
||||
$(filter %.sv, $(XRUN_TB))
|
||||
|
||||
XRUN_RUN = $(XRUN_RUN_FLAGS) \
|
||||
$(XRUN_DISABLED_WARNINGS) \
|
||||
$(XRUN_DISABLED_WARNINGS)
|
||||
|
||||
xrun_clean:
|
||||
@echo "[XRUN] clean up"
|
||||
rm -rf $(XRUN_RESULTS_DIR)
|
||||
rm -rf $(dpi-library)
|
||||
|
||||
xrun_comp: $(dpi-library)/ariane_dpi.so
|
||||
xrun_comp: $(dpi-library)/xrun_ariane_dpi.so
|
||||
@echo "[XRUN] Building Model"
|
||||
mkdir -p $(XRUN_RESULTS_DIR)
|
||||
cd $(XRUN_RESULTS_DIR) && $(XRUN) \
|
||||
|
@ -491,11 +564,13 @@ xrun_sim: xrun_comp
|
|||
$(XRUN_RUN) \
|
||||
+MAX_CYCLES=$(max_cycles) \
|
||||
+UVM_TESTNAME=$(test_case) \
|
||||
-l $(XRUN_RUN_LOG) \
|
||||
+time_out=200000000000 \
|
||||
+tohost_addr=$(shell ${RISCV}/bin/${CV_SW_PREFIX}nm -B $(elf) | grep -w tohost | cut -d' ' -f1) \
|
||||
-log $(XRUN_RUN_LOG) \
|
||||
+gui \
|
||||
+permissive-off \
|
||||
++$(elf_file)
|
||||
|
||||
#-e "set_severity_pack_assert_off {warning}; set_pack_assert_off {numeric_std}" TODO: This will remove assertion warning at the beginning of the simulation.
|
||||
+elf_file=$(elf) \
|
||||
++$(elf)
|
||||
|
||||
xrun_all: xrun_clean xrun_comp xrun_sim
|
||||
|
||||
|
@ -592,7 +667,7 @@ verilate_command := $(verilator) --no-timing verilator_config.vlt
|
|||
$(if $(DEBUG), --trace-structs,) \
|
||||
$(if $(TRACE_COMPACT), --trace-fst $(VL_INC_DIR)/verilated_fst_c.cpp) \
|
||||
$(if $(TRACE_FAST), --trace $(VL_INC_DIR)/verilated_vcd_c.cpp) \
|
||||
-LDFLAGS "-L$(RISCV)/lib -L$(SPIKE_INSTALL_DIR)/lib -Wl,-rpath,$(RISCV)/lib -Wl,-rpath,$(SPIKE_INSTALL_DIR)/lib -lfesvr -lriscv -ldisasm $(if $(PROFILE), -g -pg,) -lpthread $(if $(TRACE_COMPACT), -lz,)" \
|
||||
-LDFLAGS "-L$(RISCV)/lib -L$(SPIKE_INSTALL_DIR)/lib -Wl,-rpath,$(RISCV)/lib -Wl,-rpath,$(SPIKE_INSTALL_DIR)/lib -lfesvr -lriscv -ldisasm -lyaml-cpp $(if $(PROFILE), -g -pg,) -lpthread $(if $(TRACE_COMPACT), -lz,)" \
|
||||
-CFLAGS "$(CFLAGS)$(if $(PROFILE), -g -pg,) -DVL_DEBUG -I$(SPIKE_INSTALL_DIR)" \
|
||||
$(if $(SPIKE_TANDEM), +define+SPIKE_TANDEM, ) \
|
||||
--cc --vpi \
|
||||
|
@ -700,9 +775,14 @@ fpga_filter += $(addprefix $(root-dir), src/util/instr_trace_item.sv)
|
|||
fpga_filter += $(addprefix $(root-dir), common/local/util/instr_tracer.sv)
|
||||
fpga_filter += $(addprefix $(root-dir), vendor/pulp-platform/tech_cells_generic/src/rtl/tc_sram.sv)
|
||||
fpga_filter += $(addprefix $(root-dir), common/local/util/tc_sram_wrapper.sv)
|
||||
fpga_filter += $(addprefix $(root-dir), corev_apu/tb/ariane_peripherals.sv)
|
||||
fpga_filter += $(addprefix $(root-dir), corev_apu/tb/ariane_testharness.sv)
|
||||
fpga_filter += $(addprefix $(root-dir), core/cache_subsystem/hpdcache/rtl/src/common/macros/behav/hpdcache_sram_1rw.sv)
|
||||
fpga_filter += $(addprefix $(root-dir), core/cache_subsystem/hpdcache/rtl/src/common/macros/behav/hpdcache_sram_wbyteenable_1rw.sv)
|
||||
fpga_filter += $(addprefix $(root-dir), core/cache_subsystem/hpdcache/rtl/src/common/macros/behav/hpdcache_sram_wmask_1rw.sv)
|
||||
|
||||
src/bootrom/bootrom_$(XLEN).sv:
|
||||
$(MAKE) -C corev_apu/fpga/src/bootrom BOARD=$(BOARD) XLEN=$(XLEN) bootrom_$(XLEN).sv
|
||||
$(addprefix $(root-dir), corev_apu/fpga/src/bootrom/bootrom_$(XLEN).sv):
|
||||
$(MAKE) -C corev_apu/fpga/src/bootrom BOARD=$(BOARD) XLEN=$(XLEN) PLATFORM=$(PLATFORM) bootrom_$(XLEN).sv
|
||||
|
||||
fpga: $(ariane_pkg) $(src) $(fpga_src) $(uart_src) $(src_flist)
|
||||
@echo "[FPGA] Generate sources"
|
||||
|
@ -714,6 +794,19 @@ fpga: $(ariane_pkg) $(src) $(fpga_src) $(uart_src) $(src_flist)
|
|||
@echo "[FPGA] Generate Bitstream"
|
||||
$(MAKE) -C corev_apu/fpga BOARD=$(BOARD) XILINX_PART=$(XILINX_PART) XILINX_BOARD=$(XILINX_BOARD) CLK_PERIOD_NS=$(CLK_PERIOD_NS)
|
||||
|
||||
altera: PLATFORM := "PLAT_AGILEX"
|
||||
|
||||
altera: $(ariane_pkg) $(src) $(fpga_src) $(src_flist)
|
||||
@echo "[FPGA] Generate sources"
|
||||
@echo $(ariane_pkg) > corev_apu/altera/sourcelist.txt
|
||||
@echo $(filter-out $(fpga_filter), $(src_flist)) >> corev_apu/altera/sourcelist.txt
|
||||
@echo $(filter-out $(fpga_filter) $(altera_filter), $(src)) >> corev_apu/altera/sourcelist.txt
|
||||
@echo $(filter-out $(altera_filter), $(fpga_src)) >> corev_apu/altera/sourcelist.txt
|
||||
@echo $(filter-out $(fpga_filter) $(altera_filter) $(uart_src_sv), $(altera_src)) >> corev_apu/altera/sourcelist.txt
|
||||
@echo $(filter-out $(fpga_filter) $(altera_filter), $(altera_axi_src)) >> corev_apu/altera/sourcelist.txt
|
||||
@echo "[FPGA] Generate Bitstream"
|
||||
$(MAKE) -C corev_apu/altera ALTERA_PART=$(ALTERA_PART) ALTERA_BOARD=$(ALTERA_BOARD) CLK_PERIOD_NS=$(CLK_PERIOD_NS)
|
||||
|
||||
.PHONY: fpga
|
||||
|
||||
build-spike:
|
||||
|
@ -726,6 +819,9 @@ clean:
|
|||
$(MAKE) -C corev_apu/fpga clean
|
||||
$(MAKE) -C corev_apu/fpga/src/bootrom BOARD=$(BOARD) XLEN=$(XLEN) clean
|
||||
|
||||
clean-altera: clean
|
||||
$(MAKE) -C corev_apu/altera clean
|
||||
|
||||
.PHONY:
|
||||
build sim sim-verilate clean \
|
||||
$(riscv-asm-tests) $(addsuffix _verilator,$(riscv-asm-tests)) \
|
||||
|
|
171
README.md
171
README.md
|
@ -1,12 +1,12 @@
|
|||

|
||||
|
||||
|
||||
# CVA6 RISC-V CPU
|
||||
# CVA6 RISC-V CPU [](https://github.com/openhwgroup/cva6/actions/workflows/ci.yml) [](https://riscv-ci.pages.thales-invia.fr/dashboard/dashboard_cva6.html) [](https://docs.openhwgroup.org/projects/cva6-user-manual/?badge=latest) [](https://github.com/openhwgroup/cva6/releases/)
|
||||
|
||||
CVA6 is a 6-stage, single-issue, in-order CPU which implements the 64-bit RISC-V instruction set. It fully implements I, M, A and C extensions as specified in Volume I: User-Level ISA V 2.3 as well as the draft privilege extension 1.10. It implements three privilege levels M, S, U to fully support a Unix-like operating system. Furthermore, it is compliant to the draft external debug spec 0.13.
|
||||
|
||||
It has a configurable size, separate TLBs, a hardware PTW and branch-prediction (branch target buffer and branch history table). The primary design goal was on reducing critical path length.
|
||||
|
||||
A performance model of CVA6 is available in the `perf-model/` folder of this repository.
|
||||
It can be used to investigate performance-related micro-architecture changes.
|
||||
|
||||
<img src="docs/03_cva6_design/_static/ariane_overview.drawio.png"/>
|
||||
|
||||
|
||||
|
@ -27,16 +27,18 @@ cd cva6
|
|||
git submodule update --init --recursive
|
||||
```
|
||||
|
||||
2. Install the GCC Toolchain [build prerequisites](util/gcc-toolchain-builder/README.md#Prerequisites) then [the toolchain itself](util/gcc-toolchain-builder/README.md#Getting-started).
|
||||
2. Install the GCC Toolchain [build prerequisites](util/toolchain-builder/README.md#Prerequisites) then [the toolchain itself](util/toolchain-builder/README.md#Getting-started).
|
||||
|
||||
:warning: It is **strongly recommended** to use the toolchain built with the provided scripts.
|
||||
|
||||
3. Set the RISCV environment variable.
|
||||
3. Install `cmake`, version 3.14 or higher.
|
||||
|
||||
4. Set the RISCV environment variable.
|
||||
```sh
|
||||
export RISCV=/path/to/toolchain/installation/directory
|
||||
```
|
||||
|
||||
4. Install `help2man` and `device-tree-compiler` packages.
|
||||
5. Install `help2man` and `device-tree-compiler` packages.
|
||||
|
||||
For Debian-based Linux distributions, run :
|
||||
|
||||
|
@ -44,13 +46,13 @@ For Debian-based Linux distributions, run :
|
|||
sudo apt-get install help2man device-tree-compiler
|
||||
```
|
||||
|
||||
5. Install the riscv-dv requirements:
|
||||
6. Install the riscv-dv requirements:
|
||||
|
||||
```sh
|
||||
pip3 install -r verif/sim/dv/requirements.txt
|
||||
```
|
||||
|
||||
6. Run these commands to install a custom Spike and Verilator (i.e. these versions must be used to simulate the CVA6) and [these](#running-regression-tests-simulations) tests suites.
|
||||
7. Run these commands to install a custom Spike and Verilator (i.e. these versions must be used to simulate the CVA6) and [these](#running-regression-tests-simulations) tests suites.
|
||||
```sh
|
||||
# DV_SIMULATORS is detailed in the next section
|
||||
export DV_SIMULATORS=veri-testharness,spike
|
||||
|
@ -93,7 +95,7 @@ cd ./verif/sim
|
|||
|
||||
python3 cva6.py --target cv32a60x --iss=$DV_SIMULATORS --iss_yaml=cva6.yaml \
|
||||
--c_tests ../tests/custom/hello_world/hello_world.c \
|
||||
--linker=../tests/custom/common/test.ld \
|
||||
--linker=../../config/gen_from_riscv_config/linker/link.ld \
|
||||
--gcc_opts="-static -mcmodel=medany -fvisibility=hidden -nostdlib \
|
||||
-nostartfiles -g ../tests/custom/common/syscalls.c \
|
||||
../tests/custom/common/crt.S -lgcc \
|
||||
|
@ -168,9 +170,14 @@ To generate VCD waveforms of the `smoke-tests` regression suite using Verilator,
|
|||
```sh
|
||||
export DV_SIMULATORS=veri-testharness,spike
|
||||
export TRACE_FAST=1
|
||||
bash verif/regress/smoke-tests.sh
|
||||
bash verif/regress/smoke-tests-<cpu_version>.sh
|
||||
```
|
||||
|
||||
Where `<cpu_version>` is one of the following, depending on the CPU variant you want to use.
|
||||
- `cv32a65x`.
|
||||
- `cv32a6_imac_sv32`.
|
||||
- `cv64a6_imafdc_sv39`.
|
||||
|
||||
After each simulation run involving Verilator or VCS, the generated waveforms
|
||||
will be copied to the directory containing the log files (see above,) with
|
||||
the name of the current HW configuration added to the file name right before
|
||||
|
@ -206,29 +213,67 @@ python3 cva6.py --testlist=../tests/testlist_riscv-tests-cv64a6_imafdc_sv39-p.ya
|
|||
|
||||
# COREV-APU FPGA Emulation
|
||||
|
||||
We currently only provide support for the [Genesys 2 board](https://reference.digilentinc.com/reference/programmable-logic/genesys-2/reference-manual). We provide pre-build bitstream and memory configuration files for the Genesys 2 [here](https://github.com/openhwgroup/cva6/releases).
|
||||
We currently provide support for the [Genesys 2 board](https://reference.digilentinc.com/reference/programmable-logic/genesys-2/reference-manual) and the [Agilex 7 Development Kit](https://www.intel.la/content/www/xl/es/products/details/fpga/development-kits/agilex/agf014.html).
|
||||
|
||||
Tested on Vivado 2018.2. The FPGA currently contains the following peripherals:
|
||||
- **Genesys 2**
|
||||
|
||||
We provide pre-build bitstream and memory configuration files for the Genesys 2 [here](https://github.com/openhwgroup/cva6/releases).
|
||||
|
||||
- DDR3 memory controller
|
||||
- SPI controller to conncet to an SDCard
|
||||
- Ethernet controller
|
||||
- JTAG port (see debugging section below)
|
||||
- Bootrom containing zero stage bootloader and device tree.
|
||||
Tested on Vivado 2018.2. The FPGA currently contains the following peripherals:
|
||||
|
||||
- DDR3 memory controller
|
||||
- SPI controller to conncet to an SDCard
|
||||
- Ethernet controller
|
||||
- JTAG port (see debugging section below)
|
||||
- Bootrom containing zero stage bootloader and device tree.
|
||||
- UART
|
||||
- GPIOs connected to LEDs
|
||||
|
||||
> The ethernet controller and the corresponding network connection is still work in progress and not functional at the moment. Expect some updates soon-ish.
|
||||
|
||||
- **Agilex 7**
|
||||
|
||||
Tested on Quartus Prime Version 24.1.0 Pro Edition. The FPGA currently contains the following peripherals:
|
||||
|
||||
- DDR4 memory controller
|
||||
- JTAG port (see debugging section below)
|
||||
- Bootrom containing zero stage bootloader
|
||||
- UART
|
||||
- GPIOs connected to LEDs
|
||||
|
||||
## Programming the Memory Configuration File
|
||||
> The ethernet controller and the corresponding network connection, as well as the SD Card connection and the capability to boot linux are still work in progress and not functional at the moment. Expect some updates soon-ish.
|
||||
|
||||
- Open Vivado
|
||||
- Open the hardware manager and open the target board (Genesys II - `xc7k325t`)
|
||||
- Tools - Add Configuration Memory Device
|
||||
- Select the following Spansion SPI flash `s25fl256xxxxxx0`
|
||||
- Add `ariane_xilinx.mcs`
|
||||
- Press Ok. Flashing will take a couple of minutes.
|
||||
- Right click on the FPGA device - Boot from Configuration Memory Device (or press the program button on the FPGA)
|
||||
|
||||
## Programming the Memory Configuration File or bitstream
|
||||
|
||||
- **Genesys 2**
|
||||
|
||||
- Open Vivado
|
||||
- Open the hardware manager and open the target board (Genesys II - `xc7k325t`)
|
||||
- Tools - Add Configuration Memory Device
|
||||
- Select the following Spansion SPI flash `s25fl256xxxxxx0`
|
||||
- Add `ariane_xilinx.mcs`
|
||||
- Press Ok. Flashing will take a couple of minutes.
|
||||
- Right click on the FPGA device - Boot from Configuration Memory Device (or press the program button on the FPGA)
|
||||
|
||||
- **Agilex 7**
|
||||
|
||||
- Open Quartus programmer
|
||||
- Configure HW Setup by selecting the AGF FPGA Development Kit
|
||||
- Click Auto-Detect to scan the JTAG chain
|
||||
- In the device list, right click over device AGFB014R24B and add file (.sof)
|
||||
- Click on Start button to program the FPGA
|
||||
- Right now only baremetal is supported, so right after programming you can connect to the UART and see your CVA6 alive on Agilex!
|
||||
- For this you need to use the JTAG UART provided with Quartus installation
|
||||
|
||||
```
|
||||
.$quartus_installation_path/qprogrammer/quartus/bin/juart-terminal
|
||||
juart-terminal: connected to hardware target using JTAG UART on cable
|
||||
juart-terminal: "AGF FPGA Development Kit [1-3]", device 1, instance 0
|
||||
juart-terminal: (Use the IDE stop button or Ctrl-C to terminate)
|
||||
|
||||
Hello World!
|
||||
```
|
||||
|
||||
## Preparing the SD Card
|
||||
|
||||
|
@ -246,6 +291,8 @@ After you've inserted the SD Card and programmed the FPGA you can connect to the
|
|||
|
||||
## Generating a Bitstream
|
||||
|
||||
- **Genesys 2**
|
||||
|
||||
To generate the FPGA bitstream (and memory configuration) yourself for the Genesys II board run:
|
||||
|
||||
```
|
||||
|
@ -254,9 +301,27 @@ make fpga
|
|||
|
||||
This will produce a bitstream file and memory configuration file (in `fpga/work-fpga`) which you can permanently flash by running the above commands.
|
||||
|
||||
- **Agilex 7**
|
||||
|
||||
To generate the FPGA bitstream yourself for the Agilex 7 board run:
|
||||
|
||||
```
|
||||
make altera
|
||||
```
|
||||
|
||||
We recommend to set the parameter FpgaAlteraEn (and also FpgaEn) to benefit from the FPGA optimizations.
|
||||
|
||||
This will produce a bitstream file (in `altera/output_files`) which you can program following the previous instructions. **Note: Bear in mind that you need a Quartus Pro Licence to be able to generate this bitstream**
|
||||
|
||||
To clean the project after generating the bitstream, use
|
||||
|
||||
```
|
||||
make clean-altera
|
||||
```
|
||||
|
||||
## Debugging
|
||||
|
||||
- **Genesys 2**
|
||||
You can debug (and program) the FPGA using [OpenOCD](http://openocd.org/doc/html/Architecture-and-Core-Commands.html). We provide two example scripts for OpenOCD below.
|
||||
|
||||
To get started, connect the micro USB port that is labeled with JTAG to your machine. This port is attached to the FTDI 2232 USB-to-serial chip on the Genesys 2 board, and is usually used to access the native JTAG interface of the Kintex-7 FPGA (e.g. to program the device using Vivado). However, the FTDI chip also exposes a second serial link that is routed to GPIO pins on the FPGA, and we leverage this to wire up the JTAG from the RISC-V debug module.
|
||||
|
@ -294,11 +359,59 @@ Info : Listening on port 6666 for tcl connections
|
|||
Info : Listening on port 4444 for telnet connections
|
||||
Info : accepting 'gdb' connection on tcp/3333
|
||||
```
|
||||
- **Agilex 7**
|
||||
|
||||
You can debug (and program) the FPGA using a modified version of OpenOCD included with Quartus installation ($quartus_installation_path/qprogrammer/quartus/bin/openocd).
|
||||
|
||||
To get started, connect the micro USB port that is labeled with J13 to your machine. It is the same port that is used for the UART. Both use the JTAG interface and connect to the System Level Debugging (SLD) Hub instantiated inside the FPGA. Then the debugger connection goes to the virtual JTAG IP (vJTAG) which can be accessed with the modified version of OpenOCD.
|
||||
|
||||
You can start openocd with the `altera/cva6.cfg` configuration file:
|
||||
|
||||
```
|
||||
./$quartus_installation_path/qprogrammer/quartus/bin/openocd -f altera/cva6.cfg
|
||||
Open On-Chip Debugger 0.11.0-R22.4
|
||||
Licensed under GNU GPL v2
|
||||
For bug reports, read
|
||||
http://openocd.org/doc/doxygen/bugs.html
|
||||
Info : only one transport option; autoselect 'jtag'
|
||||
Info : Application name is OpenOCD.20241016093010
|
||||
Info : No cable specified, so will be searching for cables
|
||||
|
||||
Info : At present, The first hardware cable will be used [1 cable(s) detected]
|
||||
Info : Cable 1: device_name=(null), hw_name=AGF FPGA Development Kit, server=(null), port=1-3, chain_id=0x559319c8cde0, persistent_id=1, chain_type=1, features=34816, server_version_info=Version 24.1.0 Build 115 03/21/2024 SC Pro Edition
|
||||
Info : TAP position 0 (C341A0DD) has 3 SLD nodes
|
||||
Info : node 0 idcode=00406E00 position_n=0
|
||||
Info : node 1 idcode=30006E00 position_n=0
|
||||
Info : node 2 idcode=0C006E00 position_n=0
|
||||
Info : TAP position 1 (20D10DD) has 1 SLD nodes
|
||||
Info : node 0 idcode=0C206E00 position_n=0
|
||||
Info : Discovered 2 TAP devices
|
||||
Info : Detected device (tap_position=0) device_id=c341a0dd, instruction_length=10, features=12, device_name=AGFB014R24A(.|R1|R2)/..
|
||||
Info : Found an Intel device at tap_position 0.Currently assuming it is SLD Hub
|
||||
Info : Detected device (tap_position=1) device_id=020d10dd, instruction_length=10, features=4, device_name=VTAP10
|
||||
Info : Found an Intel device at tap_position 1.Currently assuming it is SLD Hub
|
||||
Info : This adapter doesn't support configurable speed
|
||||
Info : JTAG tap: agilex7.fpga.tap tap/device found: 0xc341a0dd (mfg: 0x06e (Altera), part: 0x341a, ver: 0xc)
|
||||
Info : JTAG tap: auto0.tap tap/device found: 0x020d10dd (mfg: 0x06e (Altera), part: 0x20d1, ver: 0x0)
|
||||
Info : JTAG tap: agilex7.fpga.tap Parent Tap found: 0xc341a0dd (mfg: 0x06e (Altera), part: 0x341a, ver: 0xc)
|
||||
Info : Virtual Tap/SLD node 0x00406E00 found at tap position 0 vtap position 0
|
||||
Warn : AUTO auto0.tap - use "jtag newtap auto0 tap -irlen 10 -expected-id 0x020d10dd"
|
||||
Info : datacount=2 progbufsize=8
|
||||
Info : Examined RISC-V core; found 1 harts
|
||||
Info : hart 0: XLEN=32, misa=0x40141107
|
||||
Info : starting gdb server for agilex7.cva6.0 on 3333
|
||||
Info : Listening on port 3333 for gdb connections
|
||||
Ready for Remote Connections
|
||||
Info : Listening on port 6666 for tcl connections
|
||||
Info : Listening on port 4444 for telnet connections
|
||||
```
|
||||
|
||||
- **Common for both boards**
|
||||
|
||||
Then you will be able to either connect through `telnet` or with `gdb`:
|
||||
|
||||
```
|
||||
riscv64-unknown-elf-gdb /path/to/elf
|
||||
risc-none-elf-gdb /path/to/elf
|
||||
|
||||
(gdb) target remote localhost:3333
|
||||
(gdb) load
|
||||
|
@ -413,6 +526,10 @@ If you use CVA6 in your academic work you can cite us:
|
|||
<br/>
|
||||
|
||||
|
||||
# Resources and Ecosystem
|
||||
|
||||
The CVA6 core is part of a vivid ecosystem. In [this document](RESOURCES.md), we gather pointers to this ecosystem (building blocks, designs, partners...)
|
||||
|
||||
# Acknowledgements
|
||||
|
||||
Check out the [acknowledgements](ACKNOWLEDGEMENTS.md).
|
||||
|
|
131
RESOURCES.md
Normal file
131
RESOURCES.md
Normal file
|
@ -0,0 +1,131 @@
|
|||
# CVA6 Ecosystem and Resources
|
||||
|
||||
The CORE-V CVA6 core is part of a large open-source ecosystem. In this page, we collect pointers to this ecosystem, so that CVA6 users can find their way.
|
||||
|
||||
Please help improve this page, by filing an [issue](https://github.com/openhwgroup/cva6/issues) or a [pull request](https://github.com/openhwgroup/cva6/pulls). For pull requests, you need to sign the [Eclipse Contributor Agreement](https://www.eclipse.org/legal/ECA.php).
|
||||
|
||||
> [!NOTE]
|
||||
> We only collect here pointers to resources that are mature enough to be used by external users.
|
||||
> Resources that reach the TRL-5 maturity (ready to integrate into productions ICs) are clearly mentioned.
|
||||
> Otherwise, you can assume a TRL-4 maturity.
|
||||
|
||||
> [!WARNING]
|
||||
> The CVA6 team is not liable for the other repositories.
|
||||
> Assess their content and make sure they fit your needs and are mature enough for your design.
|
||||
> Plese direct your issues or pull requests to these external repositories.
|
||||
|
||||
## Our legacy
|
||||
|
||||
CVA6 was designed by the **[PULP Platform team](https://www.pulp-platform.org/)**. You can integrate it with many other PULP designs from [github.com/pulp-platform](https://github.com/pulp-platform).
|
||||
|
||||
## Technical resources
|
||||
|
||||
### SW Tools and OSes
|
||||
|
||||
**RISC-V tools** for CVA6 and **Buildroot Linux** support are available [here](https://github.com/openhwgroup/cva6-sdk).
|
||||
|
||||
**Yocto Linux** support for CVA6 is available [here](https://github.com/openhwgroup/meta-cva6-yocto).
|
||||
|
||||
**FreeRTOS** support for CVA6 is available [here](https://github.com/FreeRTOS/FreeRTOS-Partner-Supported-Demos/tree/main/RISC-V_cva6).
|
||||
|
||||
**Zephyr** support for CV64A6 will soon be available.
|
||||
|
||||
**Bao** ([repository](https://github.com/bao-project/bao-hypervisor), [documentation](https://github.com/bao-project/bao-docs)) is an embedded hypervisor targetting strong isolation and real-time guarantees, leveraging CV64A6 optional hypervisor support.
|
||||
|
||||
**seL4**, secure, formally verified microkernel supports CVA6 (still by its old ARIANE name) [here](https://docs.sel4.systems/Hardware/ariane.html).
|
||||
|
||||
This [tutorial](https://github.com/ThalesGroup/cva6-eclipse-demo) offers resources to debug CVA6 under **Eclipse IDE**.
|
||||
|
||||
The OS ports above are usually on Digilent Genesys 2 board.
|
||||
|
||||
### Related building blocks
|
||||
|
||||
These building blocks fit very nicely with CVA6:
|
||||
|
||||
**[OpenPiton](https://github.com/PrincetonUniversity/openpiton)** is a many-core framework that supports CVA6.
|
||||
|
||||
**[Culsans/CV-TCCC](https://github.com/pulp-platform/culsans)** is a multi-core infrastructure for a few CVA6 cores.
|
||||
|
||||
**[ARA/CV-VEC](https://github.com/pulp-platform/ara)** is a vector unit for CVA6.
|
||||
|
||||
**[HPDcache](https://github.com/openhwgroup/cv-hpdcache)** is a flexible (highly configurable) and high-throughput L1 cache.
|
||||
|
||||
**[IOMMU](https://github.com/zero-day-labs/riscv-iommu)** supports the RISC-V Input/Output Memory Management Unit (IOMMU) Specification, including the hypervisor privilege.
|
||||
|
||||
**[IOPMP](https://github.com/zero-day-labs/riscv-iopmp)** supports the RISC-V Input/Output Physical Memory Protection (IOPMP) Specification.
|
||||
|
||||
**[AIA](https://github.com/zero-day-labs/riscv-aia)** supports the RISC-V Advanced Interrupt Architecture (AIA) specification.
|
||||
|
||||
### Design examples (FPGA)
|
||||
|
||||
The CVA6 repository contains the CVA6 core and a basic CPU design, the "APU" and its implementation on a Digilent Genesys 2 FPGA board. Here is a list of other CVA6-based FPGA designs:
|
||||
|
||||
The [technical kits](https://github.com/thalesgroup/cva6-softcore-contest) of a **student contest** organized in France can be used as educational resources or as an easy way to get CVA6 up and running with a cheaper Digilent Zybo Z7-20 board. You will find in it:
|
||||
- The 2020-2021 contest, focusing on PPA optimization;
|
||||
- The 2021-2022 contest, focusing on energy optimization;
|
||||
- The 2022-2023 contest, focusing on cybersecurity, including a port of Zephyr OS;
|
||||
- The 2023-2024 contest, focusing on the acceleration of the MNIST digit recognition with custom extensions;
|
||||
- The 2024-2025 contest, focusing on the frequency increase;
|
||||
- A treat with the support of Linux and a VGA output.
|
||||
|
||||
**[CVA6 with Xilinx Ethernet](https://github.com/cispa/CVA6-Vivado-Project-with-Xilinx-AXI-Ethernet/)** is an alternative design which implements Xilinx 1G/2.5G Ethernet Subsystem on the Digilent Genesys 2 FPGA board. It has been tested with TFTP boot in u-boot and SSH in Linux.
|
||||
|
||||
### Platforms, subsystems and systems
|
||||
|
||||
These are large subsystems and systems that are more complex than the "APU". They can be a starting point for your design:
|
||||
|
||||
**Cheshire** ([repository](https://github.com/pulp-platform/cheshire), [documentation](https://pulp-platform.github.io/cheshire/))
|
||||
is a light-weight, open-source (including peripherals), linux-capable RISC-V system built around CVA6.
|
||||
It can be integrated as Linux-capable host in larger, heterogeneous systems.
|
||||
|
||||
**Carfield** ([repository](https://github.com/pulp-platform/carfield), [documentation](https://pulp-platform.github.io/carfield/))
|
||||
is a mixed-criticality platform targeting automotive applications with several safety, security,
|
||||
and predictability features built around Cheshire and CVA6.
|
||||
|
||||
**AlSaqr** ([repository](https://github.com/AlSaqr-platform/he-soc/tree/master))
|
||||
is as secure system for Nano-UAV navigation based on CVA6 and Culsans.
|
||||
|
||||
### Designs (ASIC) and chiplets
|
||||
|
||||
Here are open-source ASIC designs based on CVA6, that have been prototyped on silicon:
|
||||
|
||||
**[Polara APU](https://github.com/openhwgroup/core-v-polara-apu)**
|
||||
is a 4-core processor made with OpenPiton, ARA and CVA6.
|
||||
|
||||
**[Basilisk](https://github.com/pulp-platform/cheshire-ihp130-o)**
|
||||
is an end-to-end open-source, Linux-capable chip based on Cheshire, CVA6, Yosys and OpenRoad.
|
||||
|
||||
**Occamy** ([repository](https://github.com/pulp-platform/occamy),
|
||||
[article](https://pulp-platform.org/occamy/),
|
||||
[paper](https://doi.org/10.1109/VLSITechnologyandCir46783.2024.10631529))
|
||||
is a 432-core, 2.5D chiplet RISC-V system with CVA6 as manager core.
|
||||
|
||||
## Business resources
|
||||
|
||||
### Service offer
|
||||
|
||||
These companies are OpenHW members, have a good CVA6 knowledge, and offer CVA6-related service:
|
||||
|
||||
**Zero-Day Labs** provides design and development services primarily related to embedded software/firmware security and hardware (RTL) for RISC-V.
|
||||
With major contributions in the scope of RISC-V virtualization, the company has developed and maintains the RISC-V Hypervisor extension in CVA6
|
||||
and has recently made open-source the RISC-V AIA and IOMMU IPs.
|
||||
Contact: [geral@zero-day-labs.com](mailto:geral@zero-day-labs.com).
|
||||
|
||||
RISC-V made easy - experienced ASIC/FPGA service providers, [**PlanV**](https://planv.tech/) will help you navigate the IP landscape,
|
||||
optimize your design workflows, and bring your RISC-V chip to life.
|
||||
|
||||
[**MU-Electronics**](https://www.mu-e.com/) is a services company having its design center in Rabat-Morocco since 2003, specialized in ICs design from datasheet to GDSII generation
|
||||
(RTL design, DFT, verification, full custom layout, place and route), firmware, driver & application development, test & validation, security implementation & support to certification.
|
||||
MU-E has designed IPs and Chips down to 7nm. MU-E is participating in the European TRISTAN project and working for Thales on the verification of CVA6.
|
||||
|
||||
[**10xEngineers**](https://10xengineers.ai/) is a design and verification services company focused on RISC-V. We contribute to compiler enablement, RTL design,
|
||||
and verification efforts within the OpenHW ecosystem. Our work on CVA6 includes architectural and microarchitectural verification of MMU
|
||||
and implementation of multiple RISC-V extensions, such as Bitmanip, Zicond, Zcb, and Zcmp. Our expert team assists companies in integrating,
|
||||
customizing, and optimizing CVA6 to meet their unique requirements.
|
||||
|
||||
_(To be completed based on companies's requests. Max 1 URL and 70 words per company)_
|
||||
|
||||
### Product ICs
|
||||
|
||||
If you have integrated CVA6 into a production IC, we'd like to hear from you and mention it here.
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
#!/bin/bash
|
||||
|
||||
echo 'deb http://download.opensuse.org/repositories/home:/phiwag:/edatools/xUbuntu_20.04/ /' | sudo tee /etc/apt/sources.list.d/home:phiwag:edatools.list
|
||||
curl -fsSL https://download.opensuse.org/repositories/home:phiwag:edatools/xUbuntu_20.04/Release.key | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/home_phiwag_edatools.gpg > /dev/null
|
||||
curl -fsSL https://download.opensuse.org/repositories/home:phiwag:edatools/Debian_Unstable/Release.key | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/home_phiwag_edatools.gpg > /dev/null
|
||||
|
||||
sudo apt update
|
||||
sudo apt install device-tree-compiler libfl-dev help2man
|
||||
|
|
46
common/local/util/hpdcache_sram_1rw.sv
Normal file
46
common/local/util/hpdcache_sram_1rw.sv
Normal file
|
@ -0,0 +1,46 @@
|
|||
// Copyright 2025 Thales DIS France SAS
|
||||
//
|
||||
// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0
|
||||
// You may obtain a copy of the License at https://solderpad.org/licenses/
|
||||
//
|
||||
// Original Author: Yannick Casamatta - Thales
|
||||
// Date: 22/10/2024
|
||||
|
||||
module hpdcache_sram_1rw
|
||||
#(
|
||||
parameter int unsigned ADDR_SIZE = 0,
|
||||
parameter int unsigned DATA_SIZE = 0,
|
||||
parameter int unsigned DEPTH = 2**ADDR_SIZE
|
||||
)
|
||||
(
|
||||
input logic clk,
|
||||
input logic rst_n,
|
||||
input logic cs,
|
||||
input logic we,
|
||||
input logic [ADDR_SIZE-1:0] addr,
|
||||
input logic [DATA_SIZE-1:0] wdata,
|
||||
output logic [DATA_SIZE-1:0] rdata
|
||||
);
|
||||
|
||||
SyncSpRam #(
|
||||
.ADDR_WIDTH(ADDR_SIZE),
|
||||
.DATA_DEPTH(DEPTH), // usually 2**ADDR_WIDTH, but can be lower
|
||||
.DATA_WIDTH(DATA_SIZE),
|
||||
.OUT_REGS (0),
|
||||
.SIM_INIT (1) // for simulation only, will not be synthesized
|
||||
// 0: no init, 1: zero init, 2: random init
|
||||
// note: on verilator, 2 is not supported. define the VERILATOR macro to work around.
|
||||
)SyncSpRam_i(
|
||||
.Clk_CI (clk),
|
||||
.Rst_RBI (rst_n),
|
||||
.CSel_SI (cs),
|
||||
.WrEn_SI (we),
|
||||
.Addr_DI (addr),
|
||||
.WrData_DI(wdata),
|
||||
.RdData_DO(rdata)
|
||||
);
|
||||
|
||||
|
||||
endmodule : hpdcache_sram_1rw
|
114
common/local/util/hpdcache_sram_wbyteenable_1rw.sv
Normal file
114
common/local/util/hpdcache_sram_wbyteenable_1rw.sv
Normal file
|
@ -0,0 +1,114 @@
|
|||
// Copyright 2025 Thales DIS France SAS
|
||||
//
|
||||
// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0
|
||||
// You may obtain a copy of the License at https://solderpad.org/licenses/
|
||||
//
|
||||
// Original Author: Yannick Casamatta - Thales
|
||||
// Date: 22/10/2024
|
||||
|
||||
module hpdcache_sram_wbyteenable_1rw
|
||||
#(
|
||||
parameter int unsigned ADDR_SIZE = 0,
|
||||
parameter int unsigned DATA_SIZE = 0,
|
||||
parameter int unsigned DEPTH = 2**ADDR_SIZE
|
||||
)
|
||||
(
|
||||
input logic clk,
|
||||
input logic rst_n,
|
||||
input logic cs,
|
||||
input logic we,
|
||||
input logic [ADDR_SIZE-1:0] addr,
|
||||
input logic [DATA_SIZE-1:0] wdata,
|
||||
input logic [DATA_SIZE/8-1:0] wbyteenable,
|
||||
output logic [DATA_SIZE-1:0] rdata
|
||||
);
|
||||
|
||||
if (DATA_SIZE == 128) begin
|
||||
// Découpage des données en deux moitiés de 64 bits
|
||||
logic [DATA_SIZE/2-1:0] wdata_low, wdata_high;
|
||||
logic [DATA_SIZE/2-1:0] rdata_low, rdata_high;
|
||||
logic [7:0] be_low, be_high;
|
||||
assign wdata_low = wdata[63:0];
|
||||
assign wdata_high = wdata[127:64];
|
||||
assign be_low = wbyteenable[7:0];
|
||||
assign be_high = wbyteenable[15:8];
|
||||
|
||||
SyncSpRamBeNx64 #(
|
||||
.ADDR_WIDTH(ADDR_SIZE),
|
||||
.DATA_DEPTH(DEPTH),
|
||||
.OUT_REGS (0),
|
||||
.SIM_INIT (1)
|
||||
) SyncSpRam_0 (
|
||||
.Clk_CI (clk),
|
||||
.Rst_RBI (rst_n),
|
||||
.CSel_SI (cs),
|
||||
.WrEn_SI (we), // Ecriture sur la banque basse
|
||||
.BEn_SI (be_low),
|
||||
.Addr_DI (addr),
|
||||
.WrData_DI(wdata_low),
|
||||
.RdData_DO(rdata_low)
|
||||
);
|
||||
|
||||
SyncSpRamBeNx64 #(
|
||||
.ADDR_WIDTH(ADDR_SIZE),
|
||||
.DATA_DEPTH(DEPTH),
|
||||
.OUT_REGS (0),
|
||||
.SIM_INIT (1)
|
||||
) SyncSpRam_1 (
|
||||
.Clk_CI (clk),
|
||||
.Rst_RBI (rst_n),
|
||||
.CSel_SI (cs),
|
||||
.WrEn_SI (we), // Ecriture sur la banque haute
|
||||
.BEn_SI (be_high),
|
||||
.Addr_DI (addr),
|
||||
.WrData_DI(wdata_high),
|
||||
.RdData_DO(rdata_high)
|
||||
);
|
||||
|
||||
assign rdata = {rdata_high, rdata_low};
|
||||
|
||||
end else if (DATA_SIZE == 64) begin
|
||||
SyncSpRamBeNx64 #(
|
||||
.ADDR_WIDTH(ADDR_SIZE),
|
||||
.DATA_DEPTH(DEPTH), // usually 2**ADDR_WIDTH, but can be lower
|
||||
.OUT_REGS (0),
|
||||
.SIM_INIT (1) // for simulation only, will not be synthesized
|
||||
// 0: no init, 1: zero init, 2: random init
|
||||
// note: on verilator, 2 is not supported. define the VERILATOR macro to work around.
|
||||
)SyncSpRam_i(
|
||||
.Clk_CI (clk),
|
||||
.Rst_RBI (rst_n),
|
||||
.CSel_SI (cs),
|
||||
.WrEn_SI (we),
|
||||
.BEn_SI (wbyteenable),
|
||||
.Addr_DI (addr),
|
||||
.WrData_DI(wdata),
|
||||
.RdData_DO(rdata)
|
||||
);
|
||||
end else if (DATA_SIZE == 32) begin
|
||||
SyncSpRamBeNx32 #(
|
||||
.ADDR_WIDTH(ADDR_SIZE),
|
||||
.DATA_DEPTH(DEPTH), // usually 2**ADDR_WIDTH, but can be lower
|
||||
.OUT_REGS (0),
|
||||
.SIM_INIT (1) // for simulation only, will not be synthesized
|
||||
// 0: no init, 1: zero init, 2: random init
|
||||
// note: on verilator, 2 is not supported. define the VERILATOR macro to work around.
|
||||
)SyncSpRam_i(
|
||||
.Clk_CI (clk),
|
||||
.Rst_RBI (rst_n),
|
||||
.CSel_SI (cs),
|
||||
.WrEn_SI (we),
|
||||
.BEn_SI (wbyteenable),
|
||||
.Addr_DI (addr),
|
||||
.WrData_DI(wdata),
|
||||
.RdData_DO(rdata)
|
||||
);
|
||||
|
||||
end else begin
|
||||
$fatal(1, "DATASIZE=%d, in not supported " ,DATA_SIZE);
|
||||
end
|
||||
|
||||
|
||||
endmodule : hpdcache_sram_wbyteenable_1rw
|
|
@ -20,37 +20,37 @@
|
|||
module instr_tracer #(
|
||||
parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty,
|
||||
parameter type bp_resolve_t = logic,
|
||||
parameter type scoreboard_entry_t = logic,
|
||||
parameter type scoreboard_entry_t = logic[303:0], // Fix for xcelium bug at runtime: does not have enough memory space reserved for scoreboard_entry
|
||||
parameter type interrupts_t = logic,
|
||||
parameter type exception_t = logic,
|
||||
parameter interrupts_t INTERRUPTS = '0
|
||||
)(
|
||||
input logic pck,
|
||||
input logic rstn,
|
||||
input logic flush_unissued,
|
||||
input logic flush_all,
|
||||
input logic [31:0] instruction,
|
||||
input logic fetch_valid,
|
||||
input logic fetch_ack,
|
||||
input logic issue_ack, // issue acknowledged
|
||||
input scoreboard_entry_t issue_sbe, // issue scoreboard entry
|
||||
input logic [1:0][4:0] waddr, // WB stage
|
||||
input logic [1:0][63:0] wdata,
|
||||
input logic [1:0] we_gpr,
|
||||
input logic [1:0] we_fpr,
|
||||
input scoreboard_entry_t [1:0] commit_instr, // commit instruction
|
||||
input logic [1:0] commit_ack,
|
||||
input logic st_valid, // stores - address translation
|
||||
input logic [CVA6Cfg.PLEN-1:0] st_paddr,
|
||||
input logic ld_valid, // loads
|
||||
input logic ld_kill,
|
||||
input logic [CVA6Cfg.PLEN-1:0] ld_paddr,
|
||||
input bp_resolve_t resolve_branch, // misprediction
|
||||
input exception_t commit_exception,
|
||||
input riscv::priv_lvl_t priv_lvl, // current privilege level
|
||||
input logic debug_mode,
|
||||
input logic pck,
|
||||
input logic rstn,
|
||||
input logic flush_unissued,
|
||||
input logic flush_all,
|
||||
input logic [31:0] instruction [CVA6Cfg.NrIssuePorts-1:0],
|
||||
input logic [CVA6Cfg.NrIssuePorts-1:0] fetch_valid,
|
||||
input logic [CVA6Cfg.NrIssuePorts-1:0] fetch_ack,
|
||||
input logic [CVA6Cfg.NrIssuePorts-1:0] issue_ack, // issue acknowledged
|
||||
input scoreboard_entry_t [CVA6Cfg.NrIssuePorts-1:0] issue_sbe, // issue scoreboard entry
|
||||
input logic [CVA6Cfg.NrCommitPorts-1:0][4:0] waddr, // WB stage
|
||||
input logic [CVA6Cfg.NrCommitPorts-1:0][63:0] wdata,
|
||||
input logic [CVA6Cfg.NrCommitPorts-1:0] we_gpr,
|
||||
input logic [CVA6Cfg.NrCommitPorts-1:0] we_fpr,
|
||||
input scoreboard_entry_t [CVA6Cfg.NrCommitPorts-1:0] commit_instr, // commit instruction
|
||||
input logic [CVA6Cfg.NrCommitPorts-1:0] commit_ack,
|
||||
input logic st_valid, // stores - address translation
|
||||
input logic [CVA6Cfg.PLEN-1:0] st_paddr,
|
||||
input logic ld_valid, // loads
|
||||
input logic ld_kill,
|
||||
input logic [CVA6Cfg.PLEN-1:0] ld_paddr,
|
||||
input bp_resolve_t resolve_branch, // misprediction
|
||||
input exception_t commit_exception,
|
||||
input riscv::priv_lvl_t priv_lvl, // current privilege level
|
||||
input logic debug_mode,
|
||||
|
||||
input logic[CVA6Cfg.XLEN-1:0] hart_id_i
|
||||
input logic[CVA6Cfg.XLEN-1:0] hart_id_i
|
||||
);
|
||||
|
||||
// keep the decoded instructions in a queue
|
||||
|
@ -94,7 +94,7 @@ module instr_tracer #(
|
|||
forever begin
|
||||
automatic bp_resolve_t bp_instruction = '0;
|
||||
// new cycle, we are only interested if reset is de-asserted
|
||||
@(pck) if (rstn !== 1'b1) begin
|
||||
@(posedge pck) if (rstn !== 1'b1) begin
|
||||
flush();
|
||||
continue;
|
||||
end
|
||||
|
@ -106,20 +106,24 @@ module instr_tracer #(
|
|||
// Instruction Decode
|
||||
// -------------------
|
||||
// we are decoding an instruction
|
||||
if (fetch_valid && fetch_ack) begin
|
||||
decode_instruction = instruction;
|
||||
decode_queue.push_back(decode_instruction);
|
||||
for (int unsigned i = 0; i < CVA6Cfg.NrIssuePorts; ++i) begin
|
||||
if (fetch_valid[i] && fetch_ack[i]) begin
|
||||
decode_instruction = instruction[i];
|
||||
decode_queue.push_back(decode_instruction);
|
||||
end
|
||||
end
|
||||
// -------------------
|
||||
// Instruction Issue
|
||||
// -------------------
|
||||
// we got a new issue ack, so put the element from the decode queue to
|
||||
// the issue queue
|
||||
if (issue_ack && !flush_unissued) begin
|
||||
issue_instruction = decode_queue.pop_front();
|
||||
issue_queue.push_back(issue_instruction);
|
||||
// also save the scoreboard entry to a separate issue queue
|
||||
issue_sbe_queue.push_back(scoreboard_entry_t'(issue_sbe));
|
||||
for (int unsigned i = 0; i < CVA6Cfg.NrIssuePorts; ++i) begin
|
||||
if (issue_ack[i] && !flush_unissued) begin
|
||||
issue_instruction = decode_queue.pop_front();
|
||||
issue_queue.push_back(issue_instruction);
|
||||
// also save the scoreboard entry to a separate issue queue
|
||||
issue_sbe_queue.push_back(scoreboard_entry_t'(issue_sbe[i]));
|
||||
end
|
||||
end
|
||||
|
||||
// --------------------
|
||||
|
|
|
@ -106,8 +106,8 @@ end
|
|||
// synthesis translate_off
|
||||
begin: i_tc_sram_wrapper_user
|
||||
begin: i_tc_sram
|
||||
logic init_val;
|
||||
localparam type data_t = logic [63:0];
|
||||
data_t init_val [0:0];
|
||||
data_t sram [NUM_WORDS-1:0] /* verilator public_flat */;
|
||||
end
|
||||
end
|
||||
|
|
|
@ -33,21 +33,29 @@ pip3 install -r requirements.txt
|
|||
## Usage
|
||||
|
||||
```bash
|
||||
#Generate the Markdown-text /Restructred-text documentation for Control and Status Registers (CSR)
|
||||
python3 <scripts/riscv_config_gen>.py -s <../riscv-config/Config_Name/generated/isa_gen>.yaml -m <updaters/Config_Name/csr_updater>.yaml -t < Config_Name>
|
||||
#Generate Restructred-text documentation for Control and Status Registers (CSR)
|
||||
python3 <scripts/riscv_config_gen>.py -s <../riscv-config/Config_Name/generated/isa_gen>.yaml -c <../riscv-config/Config_Name/generated/custom_gen>.yaml -d <../riscv-config/Config_Name/generated/debug_gen>.yaml -m <updaters/Config_Name/csr_updater>.yaml -t < Config_Name>
|
||||
|
||||
#Generate the Markdown-text /Restructred-text documentation for ISA extensions
|
||||
#Generate Restructred-text documentation for ISA extensions
|
||||
python3 <scripts/riscv_config_gen>.py -s <../riscv-config/Config_Name/generated/isa_gen>.yaml -i <templates/isa_template>.yaml -m <updaters/Config_Name/isa_updater>.yaml -t < Config_Name>
|
||||
|
||||
#Generate the Yaml spike configuration file
|
||||
python3 <scripts/riscv_config_gen>.py -s <../riscv-config/Config_Name/generated/isa_gen>.yaml -c <../riscv-config/Config_Name/generated/custom_gen>.yaml -i <templates/spike>.mako -m <updaters/Config_Name/spike_updater>.yaml -t < Config_Name>
|
||||
|
||||
```
|
||||
|
||||
## Usage with cv32a65x
|
||||
|
||||
```bash
|
||||
#Generate the Markdown-text /Restructred-text documentation for Control and Status Registers (CSR)
|
||||
python3 scripts/riscv_config_gen.py -s ../riscv-config/cv32a65x/generated/isa_gen.yaml -m updaters/cv32a65x/csr_updater.yaml -t cv32a65x
|
||||
#Generate the Restructred-text documentation for Control and Status Registers (CSR)
|
||||
python3 scripts/riscv_config_gen.py -s ../riscv-config/cv32a65x/generated/isa_gen.yaml -c ../riscv-config/cv32a65x/generated/custom_gen.yaml -d ../riscv-config/cv32a65x/generated/debug_gen.yaml -m updaters/cv32a65x/csr_updater.yaml -t cv32a65x
|
||||
|
||||
#Generate the Markdown-text /Restructred-text documentation for ISA extensions
|
||||
#Generate the Restructred-text documentation for ISA extensions
|
||||
python3 scripts/riscv_config_gen.py -s ../riscv-config/cv32a65x/generated/isa_gen.yaml -i templates/isa_template.yaml -m updaters/cv32a65x/isa_updater.yaml -t cv32a65x
|
||||
|
||||
#Generate the Yaml spike configuration file
|
||||
python3 scripts/riscv_config_gen.py -s ../riscv-config/cv32a65x/generated/isa_gen.yaml -c ../riscv-config/cv32a65x/generated/custom_gen.yaml -i templates/spike.mako -m updaters/cv32a65x/spike_updater.yaml -t cv32a65x
|
||||
|
||||
```
|
||||
|
||||
You could find your output files in this directory :
|
||||
|
@ -58,10 +66,18 @@ if the output is ISA Documentation:
|
|||
if the output is CSR Documentation :
|
||||
`<Config_Name>/csr/`
|
||||
|
||||
|
||||
for more details about How to write CSR or ISA Updater,see [UPDATERS](##Updaters) section
|
||||
if the output is Spike yaml :
|
||||
`<Config_Name>/spike/`
|
||||
|
||||
|
||||
|
||||
|
||||
for more details about How to write CSR or ISA Updater,see [Updaters](#updaters) section
|
||||
|
||||
for more details about How to write ISA template ,see [Annexes2](#annexes2) section
|
||||
|
||||
for more details about How to write spike template , see [mako](https://www.makotemplates.org/) section
|
||||
|
||||
for more details about How to write ISA template ,see [Annexes2](##Annexes2) section
|
||||
|
||||
|
||||
|
||||
|
@ -126,7 +142,7 @@ Example : ISA_Updater.yaml
|
|||
|
||||
-If you want to modify any parameter for registers in RISC CONFIG YAML :
|
||||
|
||||
Format :
|
||||
- Format :
|
||||
|
||||
Register name :
|
||||
sub_feature :
|
||||
|
@ -142,7 +158,7 @@ Example : ISA_Updater.yaml
|
|||
|
||||
-If you want to exclude any registers base on condition :
|
||||
|
||||
Format :
|
||||
- Format :
|
||||
|
||||
exclude :
|
||||
|
||||
|
@ -151,7 +167,7 @@ Example : ISA_Updater.yaml
|
|||
sub_key : sub_value (if exist if not dont include it )
|
||||
|
||||
cond: value
|
||||
Exemple :
|
||||
- Exemple :
|
||||
|
||||
exclude :
|
||||
|
||||
|
@ -164,12 +180,12 @@ Example : ISA_Updater.yaml
|
|||
|
||||
Example : (PMPADDR , MHPMCOUNTER, ...)
|
||||
|
||||
Format :
|
||||
- Format :
|
||||
|
||||
Register Name :
|
||||
|
||||
range : number
|
||||
Exemple :
|
||||
- Exemple :
|
||||
|
||||
pmpaddr :
|
||||
|
||||
|
@ -180,6 +196,56 @@ CSR/ISA Updater read RISC-CONFIG.yaml and update the registers so if you want to
|
|||
|
||||
|
||||
|
||||
### SPIKE Updater
|
||||
|
||||
|
||||
-If you want to modify any parameter Spike yaml:
|
||||
|
||||
- Format :
|
||||
|
||||
<parameter name> : <parameter value>
|
||||
|
||||
- Example :
|
||||
|
||||
|
||||
bootrom: false
|
||||
|
||||
-If you want to to modify any parameter in core config in Spike yaml :
|
||||
|
||||
- Format :
|
||||
|
||||
cores:
|
||||
|
||||
<parameter name> : <parameter value>
|
||||
- Exemple :
|
||||
|
||||
Bootroom : true
|
||||
- Exemple :
|
||||
|
||||
cores:
|
||||
isa: rv32imc_zba_zbb_zbs_zbc_zicsr_zifencei
|
||||
boot_addr: 0x80000000
|
||||
marchid: 0x3
|
||||
misa_we: false
|
||||
misa_we_enable: true
|
||||
pmpaddr0: 0x0
|
||||
pmpcfg0: 0x0
|
||||
pmpregions: 0x40
|
||||
usable_pmpregions : 0x8
|
||||
priv: M
|
||||
status_fs_field_we: false
|
||||
status_fs_field_we_enable: false
|
||||
status_vs_field_we: false
|
||||
status_vs_field_we_enable: false
|
||||
misa_we: false
|
||||
mstatus_write_mask: 0x00000088
|
||||
mstatus_override_mask: 0x00001800
|
||||
mtval_write_mask: 0x00000000
|
||||
unified_traps: true
|
||||
|
||||
|
||||
Spike Updater read spike.yaml and update the parameters so if you want to add parameter in spike.yaml you need to respect it architecture.
|
||||
|
||||
|
||||
## Annexes
|
||||
|
||||
|
|
|
@ -23,13 +23,29 @@ SECTIONS
|
|||
|
||||
/* text: test code section */
|
||||
. = 0x80000000;
|
||||
_start_text = .;
|
||||
.text.init : { *(.text.init) }
|
||||
|
||||
. = ALIGN(0x1000);
|
||||
.tohost : { *(.tohost) }
|
||||
|
||||
. = ALIGN(0x1000);
|
||||
.uvmif : { *(.uvmif) }
|
||||
|
||||
. = ALIGN(0x1000);
|
||||
.text : { *(.text) }
|
||||
. = ALIGN(0x1000);
|
||||
.text.startup : { *(.text.startup) }
|
||||
. = ALIGN(0x1000);
|
||||
_end_text = .;
|
||||
. = ALIGN(0x1000);
|
||||
.rodata : { *(.rodata*)}
|
||||
. = ALIGN(0x8);
|
||||
. = ALIGN(0x1000);
|
||||
.page_table : { *(.page_table) }
|
||||
.user_stack : { *(.user_stack) }
|
||||
.kernel_data : { *(.kernel_data) }
|
||||
.kernel_stack : { *(.kernel_stack) }
|
||||
|
||||
/* data segment */
|
||||
.data : { *(.data) }
|
54
config/gen_from_riscv_config/cv32a60x/spike/spike.yaml
Normal file
54
config/gen_from_riscv_config/cv32a60x/spike/spike.yaml
Normal file
|
@ -0,0 +1,54 @@
|
|||
spike_param_tree:
|
||||
bootrom: true
|
||||
bootrom_base: 65536
|
||||
bootrom_size: 4096
|
||||
dram: true
|
||||
dram_base: 2147483648
|
||||
dram_size: 1073741824
|
||||
generic_core_config: false
|
||||
max_steps: 200000
|
||||
max_steps_enabled: false
|
||||
isa: rv32imczicsr_zcb_zba_zbb_zbc_zbs
|
||||
priv: M
|
||||
core_configs:
|
||||
-
|
||||
isa: rv32imczicsr_zcb_zba_zbb_zbc_zbs
|
||||
extensions: cv32a60x,cvxif
|
||||
boot_addr: 2147483648
|
||||
marchid_override_mask: 0xFFFFFFFF
|
||||
marchid_override_value: 0x3
|
||||
misa_write_mask: 0x0
|
||||
pmp_granularity: 8
|
||||
pmpaddr0: 0
|
||||
pmpcfg0: 0
|
||||
pmpregions_max: 64
|
||||
pmpregions_writable: 8
|
||||
priv: M
|
||||
status_fs_field_we: false
|
||||
status_fs_field_we_enable: false
|
||||
status_vs_field_we: false
|
||||
status_vs_field_we_enable: false
|
||||
mstatus_write_mask: 136
|
||||
mstatus_override_mask: 6144
|
||||
mie_write_mask: 0x00000880
|
||||
mie_override_mask: 0xfffff77f
|
||||
mie_override_value: 0x00000000
|
||||
mip_write_mask: 0x00000000
|
||||
mip_override_mask: 0xfffff77f
|
||||
mip_override_value: 0x00000000
|
||||
mtval_write_mask: 0
|
||||
tinfo_accessible: 0
|
||||
mscontext_accessible: 0
|
||||
mcontext_accessible: 0
|
||||
tdata1_accessible: 0
|
||||
tdata2_accessible: 0
|
||||
tdata3_accessible: 0
|
||||
tselect_accessible: 0
|
||||
mhartid: 0
|
||||
mvendorid_override_mask : 0xFFFFFFFF
|
||||
mvendorid_override_value: 1538
|
||||
csr_counters_injection: true
|
||||
interrupts_injection: true
|
||||
unified_traps: true
|
||||
mcycleh_implemented: false
|
||||
mhpmevent31_implemented: false
|
537
config/gen_from_riscv_config/cv32a65x/csr/csr.adoc
Normal file
537
config/gen_from_riscv_config/cv32a65x/csr/csr.adoc
Normal file
|
@ -0,0 +1,537 @@
|
|||
////
|
||||
Copyright (c) 2024 OpenHW Group
|
||||
Copyright (c) 2024 Thales
|
||||
SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
||||
Author: Abdessamii Oukalrazqou
|
||||
////
|
||||
|
||||
=== csr
|
||||
|
||||
==== Conventions
|
||||
|
||||
In the subsequent sections, register fields are labeled with one of the following abbreviations:
|
||||
|
||||
* WPRI (Writes Preserve Values, Reads Ignore Values): read/write field reserved
|
||||
for future use. For forward compatibility, implementations that do not
|
||||
furnish these fields must make them read-only zero.
|
||||
* WLRL (Write/Read Only Legal Values): read/write CSR field that specifies
|
||||
behavior for only a subset of possible bit encodings, with other bit encodings
|
||||
reserved.
|
||||
* WARL (Write Any Values, Reads Legal Values): read/write CSR fields which are
|
||||
only defined for a subset of bit encodings, but allow any value to be written
|
||||
while guaranteeing to return a legal value whenever read.
|
||||
* ROCST (Read-Only Constant): A special case of WARL field which admits only one
|
||||
legal value, and therefore, behaves as a constant field that silently ignores
|
||||
writes.
|
||||
* ROVAR (Read-Only Variable): A special case of WARL field which can take
|
||||
multiple legal values but cannot be modified by software and depends only on
|
||||
the architectural state of the hart.
|
||||
|
||||
In particular, a register that is not internally divided
|
||||
into multiple fields can be considered as containing a single field of XLEN bits.
|
||||
This allows to clearly represent read-write registers holding a single legal value
|
||||
(typically zero).
|
||||
|
||||
==== Register Summary
|
||||
|
||||
|===
|
||||
|Address | Register Name | Privilege | Description
|
||||
|
||||
|0x300| `<<_MSTATUS,MSTATUS>>`|MRW|The mstatus register keeps track of and controls the hart's current operating state.
|
||||
|0x301| `<<_MISA,MISA>>`|MRW|misa is a read-write register reporting the ISA supported by the hart.
|
||||
|0x304| `<<_MIE,MIE>>`|MRW|The mie register is an MXLEN-bit read/write register containing interrupt enable bits.
|
||||
|0x305| `<<_MTVEC,MTVEC>>`|MRW|MXLEN-bit read/write register that holds trap vector configuration.
|
||||
|0x310| `<<_MSTATUSH,MSTATUSH>>`|MRW|The mstatush register keeps track of and controls the hart’s current operating state.
|
||||
|0x323-0x33f| `<<_MHPMEVENT3-31,MHPMEVENT[3-31]>>`|MRW|The mhpmevent is a MXLEN-bit event register which controls mhpmcounter3.
|
||||
|0x340| `<<_MSCRATCH,MSCRATCH>>`|MRW|The mscratch register is an MXLEN-bit read/write register dedicated for use by machine mode.
|
||||
|0x341| `<<_MEPC,MEPC>>`|MRW|The mepc is a warl register that must be able to hold all valid physical and virtual addresses.
|
||||
|0x342| `<<_MCAUSE,MCAUSE>>`|MRW|The mcause register stores the information regarding the trap.
|
||||
|0x343| `<<_MTVAL,MTVAL>>`|MRW|The mtval is a warl register that holds the address of the instruction which caused the exception.
|
||||
|0x344| `<<_MIP,MIP>>`|MRW|The mip register is an MXLEN-bit read/write register containing information on pending interrupts.
|
||||
|0x3a0-0x3a1| `<<_PMPCFG0-1,PMPCFG[0-1]>>`|MRW|PMP configuration register
|
||||
|0x3a2-0x3af| `<<_PMPCFG2-15,PMPCFG[2-15]>>`|MRW|PMP configuration register
|
||||
|0x3b0-0x3b7| `<<_PMPADDR0-7,PMPADDR[0-7]>>`|MRW|Physical memory protection address register
|
||||
|0x3b8-0x3ef| `<<_PMPADDR8-63,PMPADDR[8-63]>>`|MRW|Physical memory protection address register
|
||||
|0x7c0| `<<_ICACHE,ICACHE>>`|MRW|the register controls the operation of the i-cache unit.
|
||||
|0x7c1| `<<_DCACHE,DCACHE>>`|MRW|the register controls the operation of the d-cache unit.
|
||||
|0xb00| `<<_MCYCLE,MCYCLE>>`|MRW|Counts the number of clock cycles executed from an arbitrary point in time.
|
||||
|0xb02| `<<_MINSTRET,MINSTRET>>`|MRW|Counts the number of instructions completed from an arbitrary point in time.
|
||||
|0xb03-0xb1f| `<<_MHPMCOUNTER3-31,MHPMCOUNTER[3-31]>>`|MRW|The mhpmcounter is a 64-bit counter. Returns lower 32 bits in RV32I mode.
|
||||
|0xb80| `<<_MCYCLEH,MCYCLEH>>`|MRW|upper 32 bits of mcycle
|
||||
|0xb82| `<<_MINSTRETH,MINSTRETH>>`|MRW|Upper 32 bits of minstret.
|
||||
|0xb83-0xb9f| `<<_MHPMCOUNTER3-31H,MHPMCOUNTER[3-31]H>>`|MRW|The mhpmcounterh returns the upper half word in RV32I systems.
|
||||
|0xf11| `<<_MVENDORID,MVENDORID>>`|MRO|32-bit read-only register providing the JEDEC manufacturer ID of the provider of the core.
|
||||
|0xf12| `<<_MARCHID,MARCHID>>`|MRO|MXLEN-bit read-only register encoding the base microarchitecture of the hart.
|
||||
|0xf13| `<<_MIMPID,MIMPID>>`|MRO|Provides a unique encoding of the version of the processor implementation.
|
||||
|0xf14| `<<_MHARTID,MHARTID>>`|MRO|MXLEN-bit read-only register containing the integer ID of the hardware thread running the code.
|
||||
|0xf15| `<<_MCONFIGPTR,MCONFIGPTR>>`|MRO|MXLEN-bit read-only register that holds the physical address of a configuration data structure.
|
||||
|===
|
||||
|
||||
==== Register Description
|
||||
|
||||
[[_MSTATUS]]
|
||||
===== MSTATUS
|
||||
|
||||
Address:: 0x300
|
||||
Reset Value:: 0x00001800
|
||||
Privilege:: MRW
|
||||
Description:: The mstatus register keeps track of and controls the hart's current operating state.
|
||||
|
||||
|===
|
||||
| Bits | Field Name | Reset Value | Type | Legal Values | Description
|
||||
|
||||
| 0 | UIE | 0x0 | ROCST | 0x0 | Stores the state of the user mode interrupts.
|
||||
| 1 | SIE | 0x0 | ROCST | 0x0 | Stores the state of the supervisor mode interrupts.
|
||||
| 2 | RESERVED_2 | 0x0 | WPRI | | _Reserved_
|
||||
| 3 | MIE | 0x0 | WLRL | 0x0 - 0x1 | Stores the state of the machine mode interrupts.
|
||||
| 4 | UPIE | 0x0 | ROCST | 0x0 | Stores the state of the user mode interrupts prior to the trap.
|
||||
| 5 | SPIE | 0x0 | ROCST | 0x0 | Stores the state of the supervisor mode interrupts prior to the trap.
|
||||
| 6 | UBE | 0x0 | ROCST | 0x0 | control the endianness of memory accesses other than instruction fetches for user mode
|
||||
| 7 | MPIE | 0x0 | WLRL | 0x0 - 0x1 | Stores the state of the machine mode interrupts prior to the trap.
|
||||
| 8 | SPP | 0x0 | ROCST | 0x0 | Stores the previous priority mode for supervisor.
|
||||
| [10:9] | RESERVED_9 | 0x0 | WPRI | | _Reserved_
|
||||
| [12:11] | MPP | 0x3 | WARL | 0x3 | Stores the previous priority mode for machine.
|
||||
| [14:13] | FS | 0x0 | ROCST | 0x0 | Encodes the status of the floating-point unit, including the CSR fcsr and floating-point data registers.
|
||||
| [16:15] | XS | 0x0 | ROCST | 0x0 | Encodes the status of additional user-mode extensions and associated state.
|
||||
| 17 | MPRV | 0x0 | ROCST | 0x0 | Modifies the privilege level at which loads and stores execute in all privilege modes.
|
||||
| 18 | SUM | 0x0 | ROCST | 0x0 | Modifies the privilege with which S-mode loads and stores access virtual memory.
|
||||
| 19 | MXR | 0x0 | ROCST | 0x0 | Modifies the privilege with which loads access virtual memory.
|
||||
| 20 | TVM | 0x0 | ROCST | 0x0 | Supports intercepting supervisor virtual-memory management operations.
|
||||
| 21 | TW | 0x0 | ROCST | 0x0 | Supports intercepting the WFI instruction.
|
||||
| 22 | TSR | 0x0 | ROCST | 0x0 | Supports intercepting the supervisor exception return instruction.
|
||||
| 23 | SPELP | 0x0 | ROCST | 0x0 | Supervisor mode previous expected-landing-pad (ELP) state.
|
||||
| [30:24] | RESERVED_24 | 0x0 | WPRI | | _Reserved_
|
||||
| 31 | SD | 0x0 | ROCST | 0x0 | Read-only bit that summarizes whether either the FS field or XS field signals the presence of some dirty state.
|
||||
|===
|
||||
|
||||
[[_MISA]]
|
||||
===== MISA
|
||||
|
||||
Address:: 0x301
|
||||
Reset Value:: 0x40001106
|
||||
Privilege:: MRW
|
||||
Description:: misa is a read-write register reporting the ISA supported by the hart.
|
||||
|
||||
|===
|
||||
| Bits | Field Name | Reset Value | Type | Legal Values | Description
|
||||
|
||||
| [25:0] | EXTENSIONS | 0x1106 | ROCST | 0x1106 | Encodes the presence of the standard extensions, with a single bit per letter of the alphabet.
|
||||
| [29:26] | RESERVED_26 | 0x0 | WPRI | | _Reserved_
|
||||
| [31:30] | MXL | 0x1 | WARL | 0x1 | Encodes the native base integer ISA width.
|
||||
|===
|
||||
|
||||
[[_MIE]]
|
||||
===== MIE
|
||||
|
||||
Address:: 0x304
|
||||
Reset Value:: 0x00000000
|
||||
Privilege:: MRW
|
||||
Description:: The mie register is an MXLEN-bit read/write register containing interrupt enable bits.
|
||||
|
||||
|===
|
||||
| Bits | Field Name | Reset Value | Type | Legal Values | Description
|
||||
|
||||
| 0 | USIE | 0x0 | ROCST | 0x0 | User Software Interrupt enable.
|
||||
| 1 | SSIE | 0x0 | ROCST | 0x0 | Supervisor Software Interrupt enable.
|
||||
| 2 | VSSIE | 0x0 | ROCST | 0x0 | VS-level Software Interrupt enable.
|
||||
| 3 | MSIE | 0x0 | ROCST | 0x0 | Machine Software Interrupt enable.
|
||||
| 4 | UTIE | 0x0 | ROCST | 0x0 | User Timer Interrupt enable.
|
||||
| 5 | STIE | 0x0 | ROCST | 0x0 | Supervisor Timer Interrupt enable.
|
||||
| 6 | VSTIE | 0x0 | ROCST | 0x0 | VS-level Timer Interrupt enable.
|
||||
| 7 | MTIE | 0x0 | WLRL | 0x0 - 0x1 | Machine Timer Interrupt enable.
|
||||
| 8 | UEIE | 0x0 | ROCST | 0x0 | User External Interrupt enable.
|
||||
| 9 | SEIE | 0x0 | ROCST | 0x0 | Supervisor External Interrupt enable.
|
||||
| 10 | VSEIE | 0x0 | ROCST | 0x0 | VS-level External Interrupt enable.
|
||||
| 11 | MEIE | 0x0 | WLRL | 0x0 - 0x1 | Machine External Interrupt enable.
|
||||
| 12 | SGEIE | 0x0 | ROCST | 0x0 | HS-level External Interrupt enable.
|
||||
| [31:13] | RESERVED_13 | 0x0 | WPRI | | _Reserved_
|
||||
|===
|
||||
|
||||
[[_MTVEC]]
|
||||
===== MTVEC
|
||||
|
||||
Address:: 0x305
|
||||
Reset Value:: 0x80010000
|
||||
Privilege:: MRW
|
||||
Description:: MXLEN-bit read/write register that holds trap vector configuration.
|
||||
|
||||
|===
|
||||
| Bits | Field Name | Reset Value | Type | Legal Values | Description
|
||||
|
||||
| [1:0] | MODE | 0x0 | WARL | 0x0 | Vector mode.
|
||||
| [31:2] | BASE | 0x20004000 | WARL | 0x00000000 - 0x3FFFFFFF | Vector base address.
|
||||
|===
|
||||
|
||||
[[_MSTATUSH]]
|
||||
===== MSTATUSH
|
||||
|
||||
Address:: 0x310
|
||||
Reset Value:: 0x00000000
|
||||
Privilege:: MRW
|
||||
Description:: The mstatush register keeps track of and controls the hart’s current operating state.
|
||||
|
||||
|===
|
||||
| Bits | Field Name | Reset Value | Type | Legal Values | Description
|
||||
|
||||
| [3:0] | RESERVED_0 | 0x0 | WPRI | | _Reserved_
|
||||
| 4 | SBE | 0x0 | ROCST | 0x0 | control the endianness of memory accesses other than instruction fetches for supervisor mode
|
||||
| 5 | MBE | 0x0 | ROCST | 0x0 | control the endianness of memory accesses other than instruction fetches for machine mode
|
||||
| 6 | GVA | 0x0 | ROCST | 0x0 | Stores the state of the supervisor mode interrupts.
|
||||
| 7 | MPV | 0x0 | ROCST | 0x0 | Stores the state of the user mode interrupts.
|
||||
| 8 | RESERVED_8 | 0x0 | WPRI | | _Reserved_
|
||||
| 9 | MPELP | 0x0 | ROCST | 0x0 | Machine mode previous expected-landing-pad (ELP) state.
|
||||
| [31:10] | RESERVED_10 | 0x0 | WPRI | | _Reserved_
|
||||
|===
|
||||
|
||||
[[_MHPMEVENT3-31]]
|
||||
===== MHPMEVENT[3-31]
|
||||
|
||||
Address:: 0x323-0x33f
|
||||
Reset Value:: 0x00000000
|
||||
Privilege:: MRW
|
||||
Description:: The mhpmevent is a MXLEN-bit event register which controls mhpmcounter3.
|
||||
|
||||
|===
|
||||
| Bits | Field Name | Reset Value | Type | Legal Values | Description
|
||||
|
||||
| [31:0] | MHPMEVENT[I] | 0x00000000 | ROCST | 0x0 | The mhpmevent is a MXLEN-bit event register which controls mhpmcounter3.
|
||||
|===
|
||||
|
||||
[[_MSCRATCH]]
|
||||
===== MSCRATCH
|
||||
|
||||
Address:: 0x340
|
||||
Reset Value:: 0x00000000
|
||||
Privilege:: MRW
|
||||
Description:: The mscratch register is an MXLEN-bit read/write register dedicated for use by machine mode.
|
||||
|
||||
|===
|
||||
| Bits | Field Name | Reset Value | Type | Legal Values | Description
|
||||
|
||||
| [31:0] | MSCRATCH | 0x00000000 | WARL | 0x00000000 - 0xFFFFFFFF | The mscratch register is an MXLEN-bit read/write register dedicated for use by machine mode.
|
||||
|===
|
||||
|
||||
[[_MEPC]]
|
||||
===== MEPC
|
||||
|
||||
Address:: 0x341
|
||||
Reset Value:: 0x00000000
|
||||
Privilege:: MRW
|
||||
Description:: The mepc is a warl register that must be able to hold all valid physical and virtual addresses.
|
||||
|
||||
|===
|
||||
| Bits | Field Name | Reset Value | Type | Legal Values | Description
|
||||
|
||||
| [31:0] | MEPC | 0x00000000 | WARL | 0x00000000 - 0xFFFFFFFF | The mepc is a warl register that must be able to hold all valid physical and virtual addresses.
|
||||
|===
|
||||
|
||||
[[_MCAUSE]]
|
||||
===== MCAUSE
|
||||
|
||||
Address:: 0x342
|
||||
Reset Value:: 0x00000000
|
||||
Privilege:: MRW
|
||||
Description:: The mcause register stores the information regarding the trap.
|
||||
|
||||
|===
|
||||
| Bits | Field Name | Reset Value | Type | Legal Values | Description
|
||||
|
||||
| [30:0] | EXCEPTION_CODE | 0x0 | WLRL | 0x0 - 0x8, 0xb | Encodes the exception code.
|
||||
| 31 | INTERRUPT | 0x0 | WLRL | 0x0 - 0x1 | Indicates whether the trap was due to an interrupt.
|
||||
|===
|
||||
|
||||
[[_MTVAL]]
|
||||
===== MTVAL
|
||||
|
||||
Address:: 0x343
|
||||
Reset Value:: 0x00000000
|
||||
Privilege:: MRW
|
||||
Description:: The mtval is a warl register that holds the address of the instruction which caused the exception.
|
||||
|
||||
|===
|
||||
| Bits | Field Name | Reset Value | Type | Legal Values | Description
|
||||
|
||||
| [31:0] | MTVAL | 0x00000000 | ROCST | 0x0 | The mtval is a warl register that holds the address of the instruction which caused the exception.
|
||||
|===
|
||||
|
||||
[[_MIP]]
|
||||
===== MIP
|
||||
|
||||
Address:: 0x344
|
||||
Reset Value:: 0x00000000
|
||||
Privilege:: MRW
|
||||
Description:: The mip register is an MXLEN-bit read/write register containing information on pending interrupts.
|
||||
|
||||
|===
|
||||
| Bits | Field Name | Reset Value | Type | Legal Values | Description
|
||||
|
||||
| 0 | USIP | 0x0 | ROCST | 0x0 | User Software Interrupt Pending.
|
||||
| 1 | SSIP | 0x0 | ROCST | 0x0 | Supervisor Software Interrupt Pending.
|
||||
| 2 | VSSIP | 0x0 | ROCST | 0x0 | VS-level Software Interrupt Pending.
|
||||
| 3 | MSIP | 0x0 | ROCST | 0x0 | Machine Software Interrupt Pending.
|
||||
| 4 | UTIP | 0x0 | ROCST | 0x0 | User Timer Interrupt Pending.
|
||||
| 5 | STIP | 0x0 | ROCST | 0x0 | Supervisor Timer Interrupt Pending.
|
||||
| 6 | VSTIP | 0x0 | ROCST | 0x0 | VS-level Timer Interrupt Pending.
|
||||
| 7 | MTIP | 0x0 | ROVAR | 0x0 - 0x1 | Machine Timer Interrupt Pending.
|
||||
| 8 | UEIP | 0x0 | ROCST | 0x0 | User External Interrupt Pending.
|
||||
| 9 | SEIP | 0x0 | ROCST | 0x0 | Supervisor External Interrupt Pending.
|
||||
| 10 | VSEIP | 0x0 | ROCST | 0x0 | VS-level External Interrupt Pending.
|
||||
| 11 | MEIP | 0x0 | ROVAR | 0x0 - 0x1 | Machine External Interrupt Pending.
|
||||
| 12 | SGEIP | 0x0 | ROCST | 0x0 | HS-level External Interrupt Pending.
|
||||
| [31:13] | RESERVED_13 | 0x0 | WPRI | | _Reserved_
|
||||
|===
|
||||
|
||||
[[_PMPCFG0-1]]
|
||||
===== PMPCFG[0-1]
|
||||
|
||||
Address:: 0x3a0-0x3a1
|
||||
Reset Value:: 0x00000000
|
||||
Privilege:: MRW
|
||||
Description:: PMP configuration register
|
||||
|
||||
|===
|
||||
| Bits | Field Name | Reset Value | Type | Legal Values | Description
|
||||
|
||||
| [2:0] | PMP[I*4 +0]CFG.RWX | 0x0 | WARL | 0x0, 0x1, 0x3, 0x4, 0x5, 0x7 | PMP[I*4 +0]CFG collective R, W and X field (R is bit 0, X is bit 2)
|
||||
| [5:4] | PMP[I*4 +0]CFG.A | 0x0 | WARL | 0x0 - 0x1 | PMP[I*4 +0]CFG address-matching mode (A)
|
||||
| 7 | PMP[I*4 +0]CFG.L | 0x0 | WARL | 0x0 - 0x1 | PMP[I*4 +0]CFG entry locked (L)
|
||||
| [2:0] | PMP[I*4 +1]CFG | 0x0 | WARL | 0x0, 0x1, 0x3, 0x4, 0x5, 0x7 | PMP[I*4 +1]CFG collective R, W and X field (R is bit 0, X is bit 2)
|
||||
| [13:12] | PMP[I*4 +1]CFG | 0x0 | WARL | 0x0 - 0x1 | PMP[I*4 +1]CFG address-matching mode (A)
|
||||
| 15 | PMP[I*4 +1]CFG | 0x0 | WARL | 0x0 - 0x1 | PMP[I*4 +1]CFG entry locked (L)
|
||||
| [18:16] | PMP[I*4 +2]CFG | 0x0 | WARL | 0x0, 0x1, 0x3, 0x4, 0x5, 0x7 | PMP[I*4 +2]CFG collective R, W and X field (R is bit 0, X is bit 2)
|
||||
| [21:20] | PMP[I*4 +2]CFG | 0x0 | WARL | 0x0 - 0x1 | PMP[I*4 +2]CFG address-matching mode (A)
|
||||
| 23 | PMP[I*4 +2]CFG | 0x0 | WARL | 0x0 - 0x1 | PMP[I*4 +2]CFG entry locked (L)
|
||||
| [26:24] | PMP[I*4 +3]CFG | 0x0 | WARL | 0x0, 0x1, 0x3, 0x4, 0x5, 0x7 | PMP[I*4 +3]CFG collective R, W and X field (R is bit 0, X is bit 2)
|
||||
| [29:28] | PMP[I*4 +3]CFG | 0x0 | WARL | 0x0 - 0x1 | PMP[I*4 +3]CFG address matching mode (A)
|
||||
| 31 | PMP[I*4 +3]CFG | 0x0 | WARL | 0x0 - 0x1 | PMP[I*4 +3]CFG entry locked (L)
|
||||
|===
|
||||
|
||||
[[_PMPCFG2-15]]
|
||||
===== PMPCFG[2-15]
|
||||
|
||||
Address:: 0x3a2-0x3af
|
||||
Reset Value:: 0x00000000
|
||||
Privilege:: MRW
|
||||
Description:: PMP configuration register
|
||||
|
||||
|===
|
||||
| Bits | Field Name | Reset Value | Type | Legal Values | Description
|
||||
|
||||
| [7:0] | PMP[I*4 +0]CFG | 0x0 | ROCST | 0x0 | pmp configuration bits
|
||||
| [15:8] | PMP[I*4 +1]CFG | 0x0 | ROCST | 0x0 | pmp configuration bits
|
||||
| [23:16] | PMP[I*4 +2]CFG | 0x0 | ROCST | 0x0 | pmp configuration bits
|
||||
| [31:24] | PMP[I*4 +3]CFG | 0x0 | ROCST | 0x0 | pmp configuration bits
|
||||
|===
|
||||
|
||||
[[_PMPADDR0-7]]
|
||||
===== PMPADDR[0-7]
|
||||
|
||||
Address:: 0x3b0-0x3b7
|
||||
Reset Value:: 0x00000000
|
||||
Privilege:: MRW
|
||||
Description:: Physical memory protection address register
|
||||
|
||||
|===
|
||||
| Bits | Field Name | Reset Value | Type | Legal Values | Description
|
||||
|
||||
| [31:0] | PMPADDR[I] | 0x00000000 | WARL | masked: & 0xFFFFFFFE \| 0x0 | Physical memory protection address register
|
||||
|===
|
||||
|
||||
[[_PMPADDR8-63]]
|
||||
===== PMPADDR[8-63]
|
||||
|
||||
Address:: 0x3b8-0x3ef
|
||||
Reset Value:: 0x00000000
|
||||
Privilege:: MRW
|
||||
Description:: Physical memory protection address register
|
||||
|
||||
|===
|
||||
| Bits | Field Name | Reset Value | Type | Legal Values | Description
|
||||
|
||||
| [31:0] | PMPADDR[I] | 0x00000000 | ROCST | 0x0 | Physical memory protection address register
|
||||
|===
|
||||
|
||||
[[_ICACHE]]
|
||||
===== ICACHE
|
||||
|
||||
Address:: 0x7c0
|
||||
Reset Value:: 0x00000001
|
||||
Privilege:: MRW
|
||||
Description:: the register controls the operation of the i-cache unit.
|
||||
|
||||
|===
|
||||
| Bits | Field Name | Reset Value | Type | Legal Values | Description
|
||||
|
||||
| 0 | ICACHE | 0x1 | RW | 0x1 | bit for cache-enable of instruction cache
|
||||
| [31:1] | RESERVED_1 | 0x0 | WPRI | | _Reserved_
|
||||
|===
|
||||
|
||||
[[_DCACHE]]
|
||||
===== DCACHE
|
||||
|
||||
Address:: 0x7c1
|
||||
Reset Value:: 0x00000001
|
||||
Privilege:: MRW
|
||||
Description:: the register controls the operation of the d-cache unit.
|
||||
|
||||
|===
|
||||
| Bits | Field Name | Reset Value | Type | Legal Values | Description
|
||||
|
||||
| 0 | DCACHE | 0x1 | RW | 0x1 | bit for cache-enable of data cache
|
||||
| [31:1] | RESERVED_1 | 0x0 | WPRI | | _Reserved_
|
||||
|===
|
||||
|
||||
[[_MCYCLE]]
|
||||
===== MCYCLE
|
||||
|
||||
Address:: 0xb00
|
||||
Reset Value:: 0x00000000
|
||||
Privilege:: MRW
|
||||
Description:: Counts the number of clock cycles executed from an arbitrary point in time.
|
||||
|
||||
|===
|
||||
| Bits | Field Name | Reset Value | Type | Legal Values | Description
|
||||
|
||||
| [31:0] | MCYCLE | 0x00000000 | WARL | 0x00000000 - 0xFFFFFFFF | Counts the number of clock cycles executed from an arbitrary point in time.
|
||||
|===
|
||||
|
||||
[[_MINSTRET]]
|
||||
===== MINSTRET
|
||||
|
||||
Address:: 0xb02
|
||||
Reset Value:: 0x00000000
|
||||
Privilege:: MRW
|
||||
Description:: Counts the number of instructions completed from an arbitrary point in time.
|
||||
|
||||
|===
|
||||
| Bits | Field Name | Reset Value | Type | Legal Values | Description
|
||||
|
||||
| [31:0] | MINSTRET | 0x00000000 | WARL | 0x00000000 - 0xFFFFFFFF | Counts the number of instructions completed from an arbitrary point in time.
|
||||
|===
|
||||
|
||||
[[_MHPMCOUNTER3-31]]
|
||||
===== MHPMCOUNTER[3-31]
|
||||
|
||||
Address:: 0xb03-0xb1f
|
||||
Reset Value:: 0x00000000
|
||||
Privilege:: MRW
|
||||
Description:: The mhpmcounter is a 64-bit counter. Returns lower 32 bits in RV32I mode.
|
||||
|
||||
|===
|
||||
| Bits | Field Name | Reset Value | Type | Legal Values | Description
|
||||
|
||||
| [31:0] | MHPMCOUNTER[I] | 0x00000000 | ROCST | 0x0 | The mhpmcounter is a 64-bit counter. Returns lower 32 bits in RV32I mode.
|
||||
|===
|
||||
|
||||
[[_MCYCLEH]]
|
||||
===== MCYCLEH
|
||||
|
||||
Address:: 0xb80
|
||||
Reset Value:: 0x00000000
|
||||
Privilege:: MRW
|
||||
Description:: upper 32 bits of mcycle
|
||||
|
||||
|===
|
||||
| Bits | Field Name | Reset Value | Type | Legal Values | Description
|
||||
|
||||
| [31:0] | MCYCLEH | 0x00000000 | WARL | 0x00000000 - 0xFFFFFFFF | upper 32 bits of mcycle
|
||||
|===
|
||||
|
||||
[[_MINSTRETH]]
|
||||
===== MINSTRETH
|
||||
|
||||
Address:: 0xb82
|
||||
Reset Value:: 0x00000000
|
||||
Privilege:: MRW
|
||||
Description:: Upper 32 bits of minstret.
|
||||
|
||||
|===
|
||||
| Bits | Field Name | Reset Value | Type | Legal Values | Description
|
||||
|
||||
| [31:0] | MINSTRETH | 0x00000000 | WARL | 0x00000000 - 0xFFFFFFFF | Upper 32 bits of minstret.
|
||||
|===
|
||||
|
||||
[[_MHPMCOUNTER3-31H]]
|
||||
===== MHPMCOUNTER[3-31]H
|
||||
|
||||
Address:: 0xb83-0xb9f
|
||||
Reset Value:: 0x00000000
|
||||
Privilege:: MRW
|
||||
Description:: The mhpmcounterh returns the upper half word in RV32I systems.
|
||||
|
||||
|===
|
||||
| Bits | Field Name | Reset Value | Type | Legal Values | Description
|
||||
|
||||
| [31:0] | MHPMCOUNTER[I]H | 0x00000000 | ROCST | 0x0 | The mhpmcounterh returns the upper half word in RV32I systems.
|
||||
|===
|
||||
|
||||
[[_MVENDORID]]
|
||||
===== MVENDORID
|
||||
|
||||
Address:: 0xf11
|
||||
Reset Value:: 0x00000602
|
||||
Privilege:: MRO
|
||||
Description:: 32-bit read-only register providing the JEDEC manufacturer ID of the provider of the core.
|
||||
|
||||
|===
|
||||
| Bits | Field Name | Reset Value | Type | Legal Values | Description
|
||||
|
||||
| [31:0] | MVENDORID | 0x00000602 | ROCST | 0x602 | 32-bit read-only register providing the JEDEC manufacturer ID of the provider of the core.
|
||||
|===
|
||||
|
||||
[[_MARCHID]]
|
||||
===== MARCHID
|
||||
|
||||
Address:: 0xf12
|
||||
Reset Value:: 0x00000003
|
||||
Privilege:: MRO
|
||||
Description:: MXLEN-bit read-only register encoding the base microarchitecture of the hart.
|
||||
|
||||
|===
|
||||
| Bits | Field Name | Reset Value | Type | Legal Values | Description
|
||||
|
||||
| [31:0] | MARCHID | 0x00000003 | ROCST | 0x3 | MXLEN-bit read-only register encoding the base microarchitecture of the hart.
|
||||
|===
|
||||
|
||||
[[_MIMPID]]
|
||||
===== MIMPID
|
||||
|
||||
Address:: 0xf13
|
||||
Reset Value:: 0x00000000
|
||||
Privilege:: MRO
|
||||
Description:: Provides a unique encoding of the version of the processor implementation.
|
||||
|
||||
|===
|
||||
| Bits | Field Name | Reset Value | Type | Legal Values | Description
|
||||
|
||||
| [31:0] | MIMPID | 0x00000000 | ROCST | 0x0 | Provides a unique encoding of the version of the processor implementation.
|
||||
|===
|
||||
|
||||
[[_MHARTID]]
|
||||
===== MHARTID
|
||||
|
||||
Address:: 0xf14
|
||||
Reset Value:: 0x00000000
|
||||
Privilege:: MRO
|
||||
Description:: MXLEN-bit read-only register containing the integer ID of the hardware thread running the code.
|
||||
|
||||
|===
|
||||
| Bits | Field Name | Reset Value | Type | Legal Values | Description
|
||||
|
||||
| [31:0] | MHARTID | 0x00000000 | ROCST | 0x0 | MXLEN-bit read-only register containing the integer ID of the hardware thread running the code.
|
||||
|===
|
||||
|
||||
[[_MCONFIGPTR]]
|
||||
===== MCONFIGPTR
|
||||
|
||||
Address:: 0xf15
|
||||
Reset Value:: 0x00000000
|
||||
Privilege:: MRO
|
||||
Description:: MXLEN-bit read-only register that holds the physical address of a configuration data structure.
|
||||
|
||||
|===
|
||||
| Bits | Field Name | Reset Value | Type | Legal Values | Description
|
||||
|
||||
| [31:0] | MCONFIGPTR | 0x00000000 | ROCST | 0x0 | MXLEN-bit read-only register that holds the physical address of a configuration data structure.
|
||||
|===
|
||||
|
|
@ -1,353 +0,0 @@
|
|||
<!--Copyright (c) 2024 OpenHW Group
|
||||
Copyright (c) 2024 Thales
|
||||
SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
||||
Author: Abdessamii Oukalrazqou
|
||||
-->
|
||||
|
||||
# csr
|
||||
|
||||
|
||||
|
||||
## Registers Summary
|
||||
|
||||
|Address|Register Name|Description|
|
||||
| :--- | :--- | :--- |
|
||||
|0x300|[MSTATUS](#MSTATUS)|The mstatus register keeps track of and controls the hart’s current operating state.|
|
||||
|0x300|[MSTATUSH](#MSTATUSH)|The mstatush register keeps track of and controls the hart’s current operating state.|
|
||||
|0x301|[MISA](#MISA)|misa is a read-write register reporting the ISA supported by the hart.|
|
||||
|0x304|[MIE](#MIE)|The mie register is an MXLEN-bit read/write register containing interrupt enable bits.|
|
||||
|0x305|[MTVEC](#MTVEC)|MXLEN-bit read/write register that holds trap vector configuration.|
|
||||
|0x323-0x33f|[MHPMEVENT[3-31]](#MHPMEVENT[3-31])|The mhpmevent is a MXLEN-bit event register which controls mhpmcounter3.|
|
||||
|0x340|[MSCRATCH](#MSCRATCH)|The mscratch register is an MXLEN-bit read/write register dedicated for use by machine mode.|
|
||||
|0x341|[MEPC](#MEPC)|The mepc is a warl register that must be able to hold all valid physical and virtual addresses.|
|
||||
|0x342|[MCAUSE](#MCAUSE)|The mcause register stores the information regarding the trap.|
|
||||
|0x343|[MTVAL](#MTVAL)|The mtval is a warl register that holds the address of the instruction which caused the exception.|
|
||||
|0x344|[MIP](#MIP)|The mip register is an MXLEN-bit read/write register containing information on pending interrupts.|
|
||||
|0x3a0-0x3a1|[PMPCFG[0-1]](#PMPCFG[0-1])|PMP configuration register|
|
||||
|0x3b0-0x3b7|[PMPADDR[0-7]](#PMPADDR[0-7])|Physical memory protection address register|
|
||||
|0xb00|[MCYCLE](#MCYCLE)|Counts the number of clock cycles executed from an arbitrary point in time.|
|
||||
|0xb02|[MINSTRET](#MINSTRET)|Counts the number of instructions completed from an arbitrary point in time.|
|
||||
|0xb03-0xb1f|[MHPMCOUNTER[3-31]](#MHPMCOUNTER[3-31])|The mhpmcounter is a 64-bit counter. Returns lower 32 bits in RV32I mode.|
|
||||
|0xb80|[MCYCLEH](#MCYCLEH)|upper 32 bits of mcycle|
|
||||
|0xb82|[MINSTRETH](#MINSTRETH)|Upper 32 bits of minstret.|
|
||||
|0xb83-0xb9f|[MHPMCOUNTER[3-31]H](#MHPMCOUNTER[3-31]H)|The mhpmcounterh returns the upper half word in RV32I systems.|
|
||||
|0xf11|[MVENDORID](#MVENDORID)|32-bit read-only register providing the JEDEC manufacturer ID of the provider of the core.|
|
||||
|0xf12|[MARCHID](#MARCHID)|MXLEN-bit read-only register encoding the base microarchitecture of the hart.|
|
||||
|0xf13|[MIMPID](#MIMPID)|Provides a unique encoding of the version of the processor implementation.|
|
||||
|0xf14|[MHARTID](#MHARTID)|MXLEN-bit read-only register containing the integer ID of the hardware thread running the code.|
|
||||
|
||||
### Registers Description
|
||||
|
||||
#### MSTATUS
|
||||
|
||||
---
|
||||
**Address** 0x300
|
||||
**Reset Value** 0x1800
|
||||
**Privilege Mode** M
|
||||
**Description** The mstatus register keeps track of and controls the hart’s current operating state.
|
||||
|Bits|Field Name|Legal Values|Reset|Type|Description|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|0|UIE||0x0|WARL|Stores the state of the user mode interrupts.|
|
||||
|1|SIE||0x0|WARL|Stores the state of the supervisor mode interrupts.|
|
||||
|2|RESERVED_2||0x0|WPRI|RESERVED|
|
||||
|3|MIE|[0 , 1]|0x0|WLRL|Stores the state of the machine mode interrupts.|
|
||||
|4|UPIE||0x0|WARL|Stores the state of the user mode interrupts prior to the trap.|
|
||||
|5|SPIE||0x0|WARL|Stores the state of the supervisor mode interrupts prior to the trap.|
|
||||
|6|RESERVED_6||0x0|WPRI|RESERVED|
|
||||
|7|MPIE|[0 , 1]|0x0|WLRL|Stores the state of the machine mode interrupts prior to the trap.|
|
||||
|8|SPP||0x0|WARL|Stores the previous priority mode for supervisor.|
|
||||
|[10:9]|RESERVED_9||0x0|WPRI|RESERVED|
|
||||
|[12:11]|MPP|[0x3]|0x3|WARL|Stores the previous priority mode for machine.|
|
||||
|[14:13]|FS||0x0|WARL|Encodes the status of the floating-point unit, including the CSR fcsr and floating-point data registers.|
|
||||
|[16:15]|XS||0x0|WARL|Encodes the status of additional user-mode extensions and associated state.|
|
||||
|17|MPRV||0x0|WARL|Modifies the privilege level at which loads and stores execute in all privilege modes.|
|
||||
|18|SUM||0x0|WARL|Modifies the privilege with which S-mode loads and stores access virtual memory.|
|
||||
|19|MXR||0x0|WARL|Modifies the privilege with which loads access virtual memory.|
|
||||
|20|TVM||0x0|WARL|Supports intercepting supervisor virtual-memory management operations.|
|
||||
|21|TW||0x0|WARL|Supports intercepting the WFI instruction.|
|
||||
|22|TSR||0x0|WARL|Supports intercepting the supervisor exception return instruction.|
|
||||
|23|SPELP||0x0|WARL|Supervisor mode previous expected-landing-pad (ELP) state.|
|
||||
|[30:24]|RESERVED_24||0x0|WPRI|RESERVED|
|
||||
|31|SD||0x0|WARL|Read-only bit that summarizes whether either the FS field or XS field signals the presence of some dirty state.|
|
||||
|
||||
#### MSTATUSH
|
||||
|
||||
---
|
||||
**Address** 0x300
|
||||
**Reset Value** 0x0
|
||||
**Privilege Mode** M
|
||||
**Description** The mstatush register keeps track of and controls the hart’s current operating state.
|
||||
|Bits|Field Name|Legal Values|Reset|Type|Description|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|[3:0]|RESERVED_0||0x0|WPRI|RESERVED|
|
||||
|4|SBE||0x0|WARL|control the endianness of memory accesses other than instruction fetches for supervisor mode|
|
||||
|5|MBE||0x0|WARL|control the endianness of memory accesses other than instruction fetches for machine mode|
|
||||
|6|GVA||0x0|WARL|Stores the state of the supervisor mode interrupts.|
|
||||
|7|MPV||0x0|WARL|Stores the state of the user mode interrupts.|
|
||||
|8|RESERVED_8||0x0|WPRI|RESERVED|
|
||||
|9|MPELP||0x0|WARL|Machine mode previous expected-landing-pad (ELP) state.|
|
||||
|[31:10]|RESERVED_10||0x0|WPRI|RESERVED|
|
||||
|
||||
#### MISA
|
||||
|
||||
---
|
||||
**Address** 0x301
|
||||
**Reset Value** 0x40001106
|
||||
**Privilege Mode** M
|
||||
**Description** misa is a read-write register reporting the ISA supported by the hart.
|
||||
|Bits|Field Name|Legal Values|Reset|Type|Description|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|[25:0]|EXTENSIONS|[0x0000000:0x3FFFFFF]|0x1106|WARL|Encodes the presence of the standard extensions, with a single bit per letter of the alphabet.|
|
||||
|[29:26]|RESERVED_26||0x0|WPRI|RESERVED|
|
||||
|[31:30]|MXL|[0x1]|0x1|WARL|Encodes the native base integer ISA width.|
|
||||
|
||||
#### MIE
|
||||
|
||||
---
|
||||
**Address** 0x304
|
||||
**Reset Value** 0x0
|
||||
**Privilege Mode** M
|
||||
**Description** The mie register is an MXLEN-bit read/write register containing interrupt enable bits.
|
||||
|Bits|Field Name|Legal Values|Reset|Type|Description|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|0|USIE||0x0|WARL|User Software Interrupt enable.|
|
||||
|1|SSIE||0x0|WARL|Supervisor Software Interrupt enable.|
|
||||
|2|VSSIE||0x0|WARL|VS-level Software Interrupt enable.|
|
||||
|3|MSIE|[0x0 , 0x1]|0x0|WLRL|Machine Software Interrupt enable.|
|
||||
|4|UTIE||0x0|WARL|User Timer Interrupt enable.|
|
||||
|5|STIE||0x0|WARL|Supervisor Timer Interrupt enable.|
|
||||
|6|VSTIE||0x0|WARL|VS-level Timer Interrupt enable.|
|
||||
|7|MTIE|[0 , 1]|0x0|WLRL|Machine Timer Interrupt enable.|
|
||||
|8|UEIE||0x0|WARL|User External Interrupt enable.|
|
||||
|9|SEIE||0x0|WARL|Supervisor External Interrupt enable.|
|
||||
|10|VSEIE||0x0|WARL|VS-level External Interrupt enable.|
|
||||
|11|MEIE|[0 , 1]|0x0|WLRL|Machine External Interrupt enable.|
|
||||
|12|SGEIE||0x0|WARL|HS-level External Interrupt enable.|
|
||||
|[31:13]|RESERVED_13||0x0|WPRI|RESERVED|
|
||||
|
||||
#### MTVEC
|
||||
|
||||
---
|
||||
**Address** 0x305
|
||||
**Reset Value** 0x80010000
|
||||
**Privilege Mode** M
|
||||
**Description** MXLEN-bit read/write register that holds trap vector configuration.
|
||||
|Bits|Field Name|Legal Values|Reset|Type|Description|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|[1:0]|MODE|[0x0]|0x0|WARL|Vector mode.|
|
||||
|[31:2]|BASE|[0x3FFFFFFF, 0x00000000]|0x20004000|WARL|Vector base address.|
|
||||
|
||||
#### MHPMEVENT[3-31]
|
||||
|
||||
---
|
||||
**Address** 0x323-0x33f
|
||||
**Reset Value** 0x0
|
||||
**Privilege Mode** M
|
||||
**Description** The mhpmevent is a MXLEN-bit event register which controls mhpmcounter3.
|
||||
|Bits|Field Name|Legal Values|Reset|Type|Description|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|[31:0]|MHPMEVENT[I]|[0x00000000 , 0xFFFFFFFF]|0x00000000|WARL|The mhpmevent is a MXLEN-bit event register which controls mhpmcounter3.|
|
||||
|
||||
#### MSCRATCH
|
||||
|
||||
---
|
||||
**Address** 0x340
|
||||
**Reset Value** 0x0
|
||||
**Privilege Mode** M
|
||||
**Description** The mscratch register is an MXLEN-bit read/write register dedicated for use by machine mode.
|
||||
|Bits|Field Name|Legal Values|Reset|Type|Description|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|[31:0]|MSCRATCH|[0x00000000 , 0xFFFFFFFF]|0x00000000|WARL|The mscratch register is an MXLEN-bit read/write register dedicated for use by machine mode.|
|
||||
|
||||
#### MEPC
|
||||
|
||||
---
|
||||
**Address** 0x341
|
||||
**Reset Value** 0x0
|
||||
**Privilege Mode** M
|
||||
**Description** The mepc is a warl register that must be able to hold all valid physical and virtual addresses.
|
||||
|Bits|Field Name|Legal Values|Reset|Type|Description|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|[31:0]|MEPC|[0x00000000 , 0xFFFFFFFF]|0x00000000|WARL|The mepc is a warl register that must be able to hold all valid physical and virtual addresses.|
|
||||
|
||||
#### MCAUSE
|
||||
|
||||
---
|
||||
**Address** 0x342
|
||||
**Reset Value** 0x0
|
||||
**Privilege Mode** M
|
||||
**Description** The mcause register stores the information regarding the trap.
|
||||
|Bits|Field Name|Legal Values|Reset|Type|Description|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|[30:0]|EXCEPTION_CODE|[0 , 15]|0x0|WLRL|Encodes the exception code.|
|
||||
|31|INTERRUPT|[0x0 , 0x1]|0x0|WLRL|Indicates whether the trap was due to an interrupt.|
|
||||
|
||||
#### MTVAL
|
||||
|
||||
---
|
||||
**Address** 0x343
|
||||
**Reset Value** 0x0
|
||||
**Privilege Mode** M
|
||||
**Description** The mtval is a warl register that holds the address of the instruction which caused the exception.
|
||||
|Bits|Field Name|Legal Values|Reset|Type|Description|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|[31:0]|MTVAL|[0x00000000 , 0xFFFFFFFF]|0x00000000|WARL|The mtval is a warl register that holds the address of the instruction which caused the exception.|
|
||||
|
||||
#### MIP
|
||||
|
||||
---
|
||||
**Address** 0x344
|
||||
**Reset Value** 0x0
|
||||
**Privilege Mode** M
|
||||
**Description** The mip register is an MXLEN-bit read/write register containing information on pending interrupts.
|
||||
|Bits|Field Name|Legal Values|Reset|Type|Description|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|0|USIP||0x0|WARL|User Software Interrupt Pending.|
|
||||
|1|SSIP||0x0|WARL|Supervisor Software Interrupt Pending.|
|
||||
|2|VSSIP||0x0|WARL|VS-level Software Interrupt Pending.|
|
||||
|3|MSIP|0x1|0x0|RO_VARIABLE|Machine Software Interrupt Pending.|
|
||||
|4|UTIP||0x0|WARL|User Timer Interrupt Pending.|
|
||||
|5|STIP||0x0|WARL|Supervisor Timer Interrupt Pending.|
|
||||
|6|VSTIP||0x0|WARL|VS-level Timer Interrupt Pending.|
|
||||
|7|MTIP|0x1|0x0|RO_VARIABLE|Machine Timer Interrupt Pending.|
|
||||
|8|UEIP||0x0|WARL|User External Interrupt Pending.|
|
||||
|9|SEIP||0x0|WARL|Supervisor External Interrupt Pending.|
|
||||
|10|VSEIP||0x0|WARL|VS-level External Interrupt Pending.|
|
||||
|11|MEIP|0x1|0x0|RO_VARIABLE|Machine External Interrupt Pending.|
|
||||
|12|SGEIP||0x0|WARL|HS-level External Interrupt Pending.|
|
||||
|[31:13]|RESERVED_13||0x0|WPRI|RESERVED|
|
||||
|
||||
#### PMPCFG[0-1]
|
||||
|
||||
---
|
||||
**Address** 0x3a0-0x3a1
|
||||
**Reset Value** 0x0
|
||||
**Privilege Mode** M
|
||||
**Description** PMP configuration register
|
||||
|Bits|Field Name|Legal Values|Reset|Type|Description|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|[7:0]|PMP[I*4 + 0]CFG|[0x00:0xFF]|0x0|WARL|pmp configuration bits|
|
||||
|[15:8]|PMP[I*4 + 1]CFG|[0x00:0xFF]|0x0|WARL|pmp configuration bits|
|
||||
|[23:16]|PMP[I*4 + 2]CFG|[0x00:0xFF]|0x0|WARL|pmp configuration bits|
|
||||
|[31:24]|PMP[I*4 + 3]CFG|[0x00:0xFF]|0x0|WARL|pmp configuration bits|
|
||||
|
||||
#### PMPADDR[0-7]
|
||||
|
||||
---
|
||||
**Address** 0x3b0-0x3b7
|
||||
**Reset Value** 0x0
|
||||
**Privilege Mode** M
|
||||
**Description** Physical memory protection address register
|
||||
|Bits|Field Name|Legal Values|Reset|Type|Description|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|[31:0]|PMPADDR[I]|[0x00000000 , 0xFFFFFFFF]|0x00000000|WARL|Physical memory protection address register|
|
||||
|
||||
#### MCYCLE
|
||||
|
||||
---
|
||||
**Address** 0xb00
|
||||
**Reset Value** 0x0
|
||||
**Privilege Mode** M
|
||||
**Description** Counts the number of clock cycles executed from an arbitrary point in time.
|
||||
|Bits|Field Name|Legal Values|Reset|Type|Description|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|[31:0]|MCYCLE|[0x00000000 , 0xFFFFFFFF]|0x00000000|WARL|Counts the number of clock cycles executed from an arbitrary point in time.|
|
||||
|
||||
#### MINSTRET
|
||||
|
||||
---
|
||||
**Address** 0xb02
|
||||
**Reset Value** 0x0
|
||||
**Privilege Mode** M
|
||||
**Description** Counts the number of instructions completed from an arbitrary point in time.
|
||||
|Bits|Field Name|Legal Values|Reset|Type|Description|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|[31:0]|MINSTRET|[0x00000000 , 0xFFFFFFFF]|0x00000000|WARL|Counts the number of instructions completed from an arbitrary point in time.|
|
||||
|
||||
#### MHPMCOUNTER[3-31]
|
||||
|
||||
---
|
||||
**Address** 0xb03-0xb1f
|
||||
**Reset Value** 0x0
|
||||
**Privilege Mode** M
|
||||
**Description** The mhpmcounter is a 64-bit counter. Returns lower 32 bits in RV32I mode.
|
||||
|Bits|Field Name|Legal Values|Reset|Type|Description|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|[31:0]|MHPMCOUNTER[I]|[0x00000000 , 0xFFFFFFFF]|0x00000000|WARL|The mhpmcounter is a 64-bit counter. Returns lower 32 bits in RV32I mode.|
|
||||
|
||||
#### MCYCLEH
|
||||
|
||||
---
|
||||
**Address** 0xb80
|
||||
**Reset Value** 0x0
|
||||
**Privilege Mode** M
|
||||
**Description** upper 32 bits of mcycle
|
||||
|Bits|Field Name|Legal Values|Reset|Type|Description|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|[31:0]|MCYCLEH|[0x00000000 , 0xFFFFFFFF]|0x00000000|WARL|upper 32 bits of mcycle|
|
||||
|
||||
#### MINSTRETH
|
||||
|
||||
---
|
||||
**Address** 0xb82
|
||||
**Reset Value** 0x0
|
||||
**Privilege Mode** M
|
||||
**Description** Upper 32 bits of minstret.
|
||||
|Bits|Field Name|Legal Values|Reset|Type|Description|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|[31:0]|MINSTRETH|[0x00000000 , 0xFFFFFFFF]|0x00000000|WARL|Upper 32 bits of minstret.|
|
||||
|
||||
#### MHPMCOUNTER[3-31]H
|
||||
|
||||
---
|
||||
**Address** 0xb83-0xb9f
|
||||
**Reset Value** 0x0
|
||||
**Privilege Mode** M
|
||||
**Description** The mhpmcounterh returns the upper half word in RV32I systems.
|
||||
|Bits|Field Name|Legal Values|Reset|Type|Description|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|[31:0]|MHPMCOUNTER[I]H|[0x00000000 , 0xFFFFFFFF]|0x00000000|WARL|The mhpmcounterh returns the upper half word in RV32I systems.|
|
||||
|
||||
#### MVENDORID
|
||||
|
||||
---
|
||||
**Address** 0xf11
|
||||
**Reset Value** 0x602
|
||||
**Privilege Mode** M
|
||||
**Description** 32-bit read-only register providing the JEDEC manufacturer ID of the provider of the core.
|
||||
|Bits|Field Name|Legal Values|Reset|Type|Description|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|[31:0]|MVENDORID|0x00000602|0x00000602|RO_CONSTANT|32-bit read-only register providing the JEDEC manufacturer ID of the provider of the core.|
|
||||
|
||||
#### MARCHID
|
||||
|
||||
---
|
||||
**Address** 0xf12
|
||||
**Reset Value** 0x3
|
||||
**Privilege Mode** M
|
||||
**Description** MXLEN-bit read-only register encoding the base microarchitecture of the hart.
|
||||
|Bits|Field Name|Legal Values|Reset|Type|Description|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|[31:0]|MARCHID|0x00000003|0x00000003|RO_CONSTANT|MXLEN-bit read-only register encoding the base microarchitecture of the hart.|
|
||||
|
||||
#### MIMPID
|
||||
|
||||
---
|
||||
**Address** 0xf13
|
||||
**Reset Value** 0x0
|
||||
**Privilege Mode** M
|
||||
**Description** Provides a unique encoding of the version of the processor implementation.
|
||||
|Bits|Field Name|Legal Values|Reset|Type|Description|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|[31:0]|MIMPID|0x00000000|0x00000000|RO_CONSTANT|Provides a unique encoding of the version of the processor implementation.|
|
||||
|
||||
#### MHARTID
|
||||
|
||||
---
|
||||
**Address** 0xf14
|
||||
**Reset Value** 0x0
|
||||
**Privilege Mode** M
|
||||
**Description** MXLEN-bit read-only register containing the integer ID of the hardware thread running the code.
|
||||
|Bits|Field Name|Legal Values|Reset|Type|Description|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|[31:0]|MHARTID|0x00000000|0x00000000|RO_CONSTANT|MXLEN-bit read-only register containing the integer ID of the hardware thread running the code.|
|
File diff suppressed because it is too large
Load diff
223
config/gen_from_riscv_config/cv32a65x/isa/isa.adoc
Normal file
223
config/gen_from_riscv_config/cv32a65x/isa/isa.adoc
Normal file
|
@ -0,0 +1,223 @@
|
|||
////
|
||||
Copyright (c) 2024 OpenHW Group
|
||||
Copyright (c) 2024 Thales
|
||||
SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
||||
Author: Abdessamii Oukalrazqou
|
||||
////
|
||||
|
||||
=== isa
|
||||
|
||||
==== Instructions
|
||||
|
||||
|===
|
||||
|Subset Name | Name | Description
|
||||
|
||||
|I | RV32I Base Integer Instructions | the base integer instruction set, also known as the 'RV32I' or 'RV64I' instruction set , depending on the address space size, provides the core functionality required for general-purpose computing .it includes instructions for arithmetic, logical, and control operations, as well as memory accessand manipulation
|
||||
|M | RV32M Multiplication and Division Instructions | the standard integer multiplication and division instruction extension, which is named “M” and contains instructions that multiply or divide values held in two integer registers.
|
||||
|C | RV32C Compressed Instructions | RVC uses a simple compression scheme that offers shorter 16-bit versions of common 32-bit RISC-V instructions when: the immediate or address offset is small; one of the registers is the zero register (x0), the ABI link register (x1), or the ABI stack pointer (x2); the destination register and the first source register are identical; the registers used are the 8 most popular ones.The C extension is compatible with all other standard instruction extensions. The C extension allows 16-bit instructions to be freely intermixed with 32-bit instructions, with the latter now able to start on any 16-bit boundary. With the addition of the C extension, JAL and JALR instructions will no longer raise an instruction misaligned exception
|
||||
|Zicsr | RV32Zicsr Control and Status Register Instructions | All CSR instructions atomically read-modify-write a single CSR, whose CSR specifier is encoded in the 12-bit csr field of the instruction held in bits 31–20. The immediate forms use a 5-bit zero-extended immediate encoded in the rs1 field.
|
||||
|Zcb | RV32Zcb Code Size Reduction Instructions | Zcb belongs to the group of extensions called RISC-V Code Size Reduction Extension (Zc*). Zc* has become the superset of the Standard C extension adding more 16-bit instructions to the ISA. Zcb includes the 16-bit version of additional Integer (I), Multiply (M), and Bit-Manipulation (Zbb) Instructions. All the Zcb instructions require at least standard C extension support as a prerequisite, along with M and Zbb extensions for the 16-bit version of the respective instructions.
|
||||
|Zba | RVZba Address generation instructions | The Zba instructions can be used to accelerate the generation of addresses that index into arrays of basic types (halfword, word, doubleword) using both unsigned word-sized and XLEN-sized indices: a shifted index is added to a base address. The shift and add instructions do a left shift of 1, 2, or 3 because these are commonly found in real-world code and because they can be implemented with a minimal amount of additional hardware beyond that of the simple adder. This avoids lengthening the critical path in implementations. While the shift and add instructions are limited to a maximum left shift of 3, the slli instruction (from the base ISA) can be used to perform similar shifts for indexing into arrays of wider elements. The slli.uw added in this extension can be used when the index is to be interpreted as an unsigned word.
|
||||
|Zbb | RVZbb Basic bit-manipulation | The bit-manipulation (bitmanip) extension collection is comprised of several component extensions to the base RISC-V architecture that are intended to provide some combination of code size reduction, performance improvement, and energy reduction. While the instructions are intended to have general use, some instructions are more useful in some domains than others. Hence, several smaller bitmanip extensions are provided. Each of these smaller extensions is grouped by common function and use case, and each has its own Zb*-extension name.
|
||||
|Zbc | RVZbc Carry-less multiplication | Carry-less multiplication is the multiplication in the polynomial ring over GF(2).clmul produces the lower half of the carry-less product and clmulh produces the upper half of the 2✕XLEN carry-less product.clmulr produces bits 2✕XLEN−2:XLEN-1 of the 2✕XLEN carry-less product.
|
||||
|Zbs | RVZbs Single bit Instructions | The single-bit instructions provide a mechanism to set, clear, invert, or extract a single bit in a register. The bit is specified by its index.
|
||||
|Zicntr | Zicntr | No info found yet for extension Zicntr
|
||||
|Zbkb | RVZbkb Bitmanip instructions for Cryptography | The Zbkb extension is a part of the RISC-V Bit-Manipulation (bitmanip) extensions, specifically targeting cryptographic applications. It introduces a set of instructions designed to facilitate operations commonly used in cryptographic algorithms, such as interleaving, packing, and reordering of bits.
|
||||
|===
|
||||
|
||||
==== RV32I Base Integer Instructions
|
||||
|
||||
|===
|
||||
| Name | Format | Pseudocode|Invalid_values | Exception_raised | Description| Op Name
|
||||
|
||||
| ADDI | addi rd, rs1, imm[11:0] | x[rd] = x[rs1] + sext(imm[11:0]) | NONE | NONE | add sign-extended 12-bit immediate to register rs1, and store the result in register rd. | Integer_Register_Immediate_Operations
|
||||
| ANDI | andi rd, rs1, imm[11:0] | x[rd] = x[rs1] & sext(imm[11:0]) | NONE | NONE | perform bitwise AND on register rs1 and the sign-extended 12-bit immediate and place the result in rd. | Integer_Register_Immediate_Operations
|
||||
| ORI | ori rd, rs1, imm[11:0] | x[rd] = x[rs1] \| sext(imm[11:0]) | NONE | NONE | perform bitwise OR on register rs1 and the sign-extended 12-bit immediate and place the result in rd. | Integer_Register_Immediate_Operations
|
||||
| XORI | xori rd, rs1, imm[11:0] | x[rd] = x[rs1] ^ sext(imm[11:0]) | NONE | NONE | perform bitwise XOR on register rs1 and the sign-extended 12-bit immediate and place the result in rd. | Integer_Register_Immediate_Operations
|
||||
| SLTI | slti rd, rs1, imm[11:0] | if (x[rs1] < sext(imm[11:0])) x[rd] = 1 else x[rd] = 0 | NONE | NONE | set register rd to 1 if register rs1 is less than the sign extended immediate when both are treated as signed numbers, else 0 is written to rd. | Integer_Register_Immediate_Operations
|
||||
| SLTIU | sltiu rd, rs1, imm[11:0] | if (x[rs1] <u sext(imm[11:0])) x[rd] = 1 else x[rd] = 0 | NONE | NONE | set register rd to 1 if register rs1 is less than the sign extended immediate when both are treated as unsigned numbers, else 0 is written to rd." | Integer_Register_Immediate_Operations
|
||||
| SLLI | slli rd, rs1, imm[4:0] | x[rd] = x[rs1] << imm[4:0] | NONE | NONE | logical left shift (zeros are shifted into the lower bits). | Integer_Register_Immediate_Operations
|
||||
| SRLI | srli rd, rs1, imm[4:0] | x[rd] = x[rs1] >> imm[4:0] | NONE | NONE | logical right shift (zeros are shifted into the upper bits). | Integer_Register_Immediate_Operations
|
||||
| SRAI | srai rd, rs1, imm[4:0] | x[rd] = x[rs1] >>s imm[4:0] | NONE | NONE | arithmetic right shift (the original sign bit is copied into the vacated upper bits). | Integer_Register_Immediate_Operations
|
||||
| LUI | lui rd, imm[19:0] | x[rd] = sext(imm[31:12] << 12) | NONE | NONE | place the immediate value in the top 20 bits of the destination register rd, filling in the lowest 12 bits with zeros. | Integer_Register_Immediate_Operations
|
||||
| AUIPC | auipc rd, imm[19:0] | x[rd] = pc + sext(immediate[31:12] << 12) | NONE | NONE | form a 32-bit offset from the 20-bit immediate, filling in the lowest 12 bits with zeros, adds this offset to the pc, then place the result in register rd. | Integer_Register_Immediate_Operations
|
||||
| ADD | add rd, rs1, rs2 | x[rd] = x[rs1] + x[rs2] | NONE | NONE | add rs2 to register rs1, and store the result in register rd. | Integer_Register_Register_Operations
|
||||
| SUB | sub rd, rs1, rs2 | x[rd] = x[rs1] - x[rs2] | NONE | NONE | subtract rs2 from register rs1, and store the result in register rd. | Integer_Register_Register_Operations
|
||||
| AND | and rd, rs1, rs2 | x[rd] = x[rs1] & x[rs2] | NONE | NONE | perform bitwise AND on register rs1 and rs2 and place the result in rd. | Integer_Register_Register_Operations
|
||||
| OR | or rd, rs1, rs2 | x[rd] = x[rs1] \| x[rs2] | NONE | NONE | perform bitwise OR on register rs1 and rs2 and place the result in rd. | Integer_Register_Register_Operations
|
||||
| XOR | xor rd, rs1, rs2 | x[rd] = x[rs1] ^ x[rs2] | NONE | NONE | perform bitwise XOR on register rs1 and rs2 and place the result in rd. | Integer_Register_Register_Operations
|
||||
| SLT | slt rd, rs1, rs2 | if (x[rs1] < x[rs2]) x[rd] = 1 else x[rd] = 0 | NONE | NONE | set register rd to 1 if register rs1 is less than rs2 when both are treated as signed numbers, else 0 is written to rd. | Integer_Register_Register_Operations
|
||||
| SLTU | sltu rd, rs1, rs2 | if (x[rs1] <u x[rs2]) x[rd] = 1 else x[rd] = 0 | NONE | NONE | set register rd to 1 if register rs1 is less than rs2 when both are treated as unsigned numbers, else 0 is written to rd. | Integer_Register_Register_Operations
|
||||
| SLL | sll rd, rs1, rs2 | x[rd] = x[rs1] << x[rs2] | NONE | NONE | logical left shift (zeros are shifted into the lower bits). | Integer_Register_Register_Operations
|
||||
| SRL | srl rd, rs1, rs2 | x[rd] = x[rs1] >> x[rs2] | NONE | NONE | logical right shift (zeros are shifted into the upper bits). | Integer_Register_Register_Operations
|
||||
| SRA | sra rd, rs1, rs2 | x[rd] = x[rs1] >>s x[rs2] | NONE | NONE | arithmetic right shift (the original sign bit is copied into the vacated upper bits). | Integer_Register_Register_Operations
|
||||
| JAL | jal rd, imm[20:1] | x[rd] = pc+4; pc += sext(imm[20:1]) | NONE | jumps to an unaligned address (4-byte or 2-byte boundary) will usually raise an exception. | offset is sign-extended and added to the pc to form the jump target address (pc is calculated using signed arithmetic), then setting the least-significant bit of the result to zero, and store the address of instruction following the jump (pc+4) into register rd. | Control_Transfer_Operations-Unconditional_Jumps
|
||||
| JALR | jalr rd, rs1, imm[11:0] | t = pc+4; pc = (x[rs1]+sext(imm[11:0]))&∼1 ; x[rd] = t | NONE | jumps to an unaligned address (4-byte or 2-byte boundary) will usually raise an exception. | target address is obtained by adding the 12-bit signed immediate to the register rs1 (pc is calculated using signed arithmetic), then setting the least-significant bit of the result to zero, and store the address of instruction following the jump (pc+4) into register rd. | Control_Transfer_Operations-Unconditional_Jumps
|
||||
| BEQ | beq rs1, rs2, imm[12:1] | if (x[rs1] == x[rs2]) pc += sext({imm[12:1], 1’b0}) else pc += 4 | NONE | no instruction fetch misaligned exception is generated for a conditional branch that is not taken. An Instruction address misaligned exception is raised if the target address is not aligned on 4-byte or 2-byte boundary, because the core supports compressed instructions. | takes the branch (pc is calculated using signed arithmetic) if registers rs1 and rs2 are equal. | Control_Transfer_Operations-Conditional_Branches
|
||||
| BNE | bne rs1, rs2, imm[12:1] | if (x[rs1] != x[rs2]) pc += sext({imm[12:1], 1’b0}) else pc += 4 | NONE | no instruction fetch misaligned exception is generated for a conditional branch that is not taken. An Instruction address misaligned exception is raised if the target address is not aligned on 4-byte or 2-byte boundary, because the core supports compressed instructions. | takes the branch (pc is calculated using signed arithmetic) if registers rs1 and rs2 are not equal. | Control_Transfer_Operations-Conditional_Branches
|
||||
| BLT | blt rs1, rs2, imm[12:1] | if (x[rs1] < x[rs2]) pc += sext({imm[12:1], 1’b0}) else pc += 4 | NONE | no instruction fetch misaligned exception is generated for a conditional branch that is not taken. An Instruction address misaligned exception is raised if the target address is not aligned on 4-byte or 2-byte boundary, because the core supports compressed instructions. | takes the branch (pc is calculated using signed arithmetic) if registers rs1 less than rs2 (using signed comparison). | Control_Transfer_Operations-Conditional_Branches
|
||||
| BLTU | bltu rs1, rs2, imm[12:1] | if (x[rs1] <u x[rs2]) pc += sext({imm[12:1], 1’b0}) else pc += 4 | NONE | no instruction fetch misaligned exception is generated for a conditional branch that is not taken. An Instruction address misaligned exception is raised if the target address is not aligned on 4-byte or 2-byte boundary, because the core supports compressed instructions. | takes the branch (pc is calculated using signed arithmetic) if registers rs1 less than rs2 (using unsigned comparison). | Control_Transfer_Operations-Conditional_Branches
|
||||
| BGE | bge rs1, rs2, imm[12:1] | if (x[rs1] >= x[rs2]) pc += sext({imm[12:1], 1’b0}) else pc += 4 | NONE | no instruction fetch misaligned exception is generated for a conditional branch that is not taken. An Instruction address misaligned exception is raised if the target address is not aligned on 4-byte or 2-byte boundary, because the core supports compressed instructions. | takes the branch (pc is calculated using signed arithmetic) if registers rs1 is greater than or equal rs2 (using signed comparison). | Control_Transfer_Operations-Conditional_Branches
|
||||
| BGEU | bgeu rs1, rs2, imm[12:1] | if (x[rs1] >=u x[rs2]) pc += sext({imm[12:1], 1’b0}) else pc += 4 | NONE | no instruction fetch misaligned exception is generated for a conditional branch that is not taken. An Instruction address misaligned exception is raised if the target address is not aligned on 4-byte or 2-byte boundary, because the core supports compressed instructions. | takes the branch (pc is calculated using signed arithmetic) if registers rs1 is greater than or equal rs2 (using unsigned comparison). | Control_Transfer_Operations-Conditional_Branches
|
||||
| LB | lb rd, imm(rs1) | x[rd] = sext(M[x[rs1] + sext(imm[11:0])][7:0]) | NONE | loads with a destination of x0 must still raise any exceptions and action any other side effects even though the load value is discarded. | loads a 8-bit value from memory, then sign-extends to 32-bit before storing in rd (rd is calculated using signed arithmetic), the effective address is obtained by adding register rs1 to the sign-extended 12-bit offset. | Load_and_Store_Instructions
|
||||
| LH | lh rd, imm(rs1) | x[rd] = sext(M[x[rs1] + sext(imm[11:0])][15:0]) | NONE | loads with a destination of x0 must still raise any exceptions and action any other side effects even though the load value is discarded, also an exception is raised if the memory address isn't aligned (2-byte boundary). | loads a 16-bit value from memory, then sign-extends to 32-bit before storing in rd (rd is calculated using signed arithmetic), the effective address is obtained by adding register rs1 to the sign-extended 12-bit offset. | Load_and_Store_Instructions
|
||||
| LW | lw rd, imm(rs1) | x[rd] = sext(M[x[rs1] + sext(imm[11:0])][31:0]) | NONE | loads with a destination of x0 must still raise any exceptions and action any other side effects even though the load value is discarded, also an exception is raised if the memory address isn't aligned (4-byte boundary). | loads a 32-bit value from memory, then storing in rd (rd is calculated using signed arithmetic). The effective address is obtained by adding register rs1 to the sign-extended 12-bit offset. | Load_and_Store_Instructions
|
||||
| LBU | lbu rd, imm(rs1) | x[rd] = zext(M[x[rs1] + sext(imm[11:0])][7:0]) | NONE | loads with a destination of x0 must still raise any exceptions and action any other side effects even though the load value is discarded. | loads a 8-bit value from memory, then zero-extends to 32-bit before storing in rd (rd is calculated using unsigned arithmetic), the effective address is obtained by adding register rs1 to the sign-extended 12-bit offset. | Load_and_Store_Instructions
|
||||
| LHU | lhu rd, imm(rs1) | x[rd] = zext(M[x[rs1] + sext(imm[11:0])][15:0]) | NONE | loads with a destination of x0 must still raise any exceptions and action any other side effects even though the load value is discarded, also an exception is raised if the memory address isn't aligned (2-byte boundary). | loads a 16-bit value from memory, then zero-extends to 32-bit before storing in rd (rd is calculated using unsigned arithmetic), the effective address is obtained by adding register rs1 to the sign-extended 12-bit offset. | Load_and_Store_Instructions
|
||||
| SB | sb rs2, imm(rs1) | M[x[rs1] + sext(imm[11:0])][7:0] = x[rs2][7:0] | NONE | NONE | stores a 8-bit value from the low bits of register rs2 to memory, the effective address is obtained by adding register rs1 to the sign-extended 12-bit offset. | Load_and_Store_Instructions
|
||||
| SH | sh rs2, imm(rs1) | M[x[rs1] + sext(imm[11:0])][15:0] = x[rs2][15:0] | NONE | an exception is raised if the memory address isn't aligned (2-byte boundary). | stores a 16-bit value from the low bits of register rs2 to memory, the effective address is obtained by adding register rs1 to the sign-extended 12-bit offset. | Load_and_Store_Instructions
|
||||
| SW | sw rs2, imm(rs1) | M[x[rs1] + sext(imm[11:0])][31:0] = x[rs2][31:0] | NONE | an exception is raised if the memory address isn't aligned (4-byte boundary). | stores a 32-bit value from register rs2 to memory, the effective address is obtained by adding register rs1 to the sign-extended 12-bit offset. | Load_and_Store_Instructions
|
||||
| FENCE | fence pre, succ | No operation (nop) | NONE | NONE | order device I/O and memory accesses as viewed by other RISC-V harts and external devices or coprocessors. Any combination of device input (I), device output (O), memory reads (R), and memory writes (W) may be ordered with respect to any combination of the same. Informally, no other RISC-V hart or external device can observe any operation in the successor set following a FENCE before any operation in the predecessor set preceding the FENCE, as the core support 1 hart, the fence instruction has no effect so we can considerate it as a nop instruction. | Memory_Ordering
|
||||
| ECALL | ecall | RaiseException(EnvironmentCall) | NONE | Raise an Environment Call exception. | make a request to the supporting execution environment, which is usually an operating system. The ABI for the system will define how parameters for the environment request are passed, but usually these will be in defined locations in the integer register file. | Environment_Call_and_Breakpoints
|
||||
| EBREAK | ebreak | x[8 + rd'] = sext(x[8 + rd'][7:0]) | NONE | NONE | This instruction takes a single source/destination operand. It sign-extends the least-significant byte in the operand by copying the most-significant bit in the byte (i.e., bit 7) to all of the more-significant bits. It also requires Bit-Manipulation (Zbb) extension support. | Environment_Call_and_Breakpoints
|
||||
|===
|
||||
|
||||
==== RV32M Multiplication and Division Instructions
|
||||
|
||||
|===
|
||||
| Name | Format | Pseudocode|Invalid_values | Exception_raised | Description| Op Name
|
||||
|
||||
| MUL | mul rd, rs1, rs2 | x[rd] = x[rs1] * x[rs2] | NONE | NONE | performs a 32-bit × 32-bit multiplication and places the lower 32 bits in the destination register (Both rs1 and rs2 treated as signed numbers). | Multiplication Operations
|
||||
| MULH | mulh rd, rs1, rs2 | x[rd] = (x[rs1] s*s x[rs2]) >>s 32 | NONE | NONE | performs a 32-bit × 32-bit multiplication and places the upper 32 bits in the destination register of the 64-bit product (Both rs1 and rs2 treated as signed numbers). | Multiplication Operations
|
||||
| MULHU | mulhu rd, rs1, rs2 | x[rd] = (x[rs1] u*u x[rs2]) >>u 32 | NONE | NONE | performs a 32-bit × 32-bit multiplication and places the upper 32 bits in the destination register of the 64-bit product (Both rs1 and rs2 treated as unsigned numbers). | Multiplication Operations
|
||||
| MULHSU | mulhsu rd, rs1, rs2 | x[rd] = (x[rs1] s*u x[rs2]) >>s 32 | NONE | NONE | performs a 32-bit × 32-bit multiplication and places the upper 32 bits in the destination register of the 64-bit product (rs1 treated as signed number, rs2 treated as unsigned number). | Multiplication Operations
|
||||
| DIV | div rd, rs1, rs2 | x[rd] = x[rs1] /s x[rs2] | NONE | NONE | perform signed integer division of 32 bits by 32 bits (rounding towards zero). | Division Operations
|
||||
| DIVU | divu rd, rs1, rs2 | x[rd] = x[rs1] /u x[rs2] | NONE | NONE | perform unsigned integer division of 32 bits by 32 bits (rounding towards zero). | Division Operations
|
||||
| REM | rem rd, rs1, rs2 | x[rd] = x[rs1] %s x[rs2] | NONE | NONE | provide the remainder of the corresponding division operation DIV (the sign of rd equals the sign of rs1). | Division Operations
|
||||
| REMU | rem rd, rs1, rs2 | x[rd] = x[rs1] %u x[rs2] | NONE | NONE | provide the remainder of the corresponding division operation DIVU. | Division Operations
|
||||
|===
|
||||
|
||||
==== RV32C Compressed Instructions
|
||||
|
||||
|===
|
||||
| Name | Format | Pseudocode|Invalid_values | Exception_raised | Description| Op Name
|
||||
|
||||
| C.LI | c.li rd, imm[5:0] | x[rd] = sext(imm[5:0]) | rd = x0 | NONE | loads the sign-extended 6-bit immediate, imm, into register rd. | Integer Computational Instructions
|
||||
| C.LUI | c.lui rd, nzimm[17:12] | x[rd] = sext(nzimm[17:12] << 12) | rd = x0 & rd = x2 & nzimm = 0 | NONE | loads the non-zero 6-bit immediate field into bits 17–12 of the destination register, clears the bottom 12 bits, and sign-extends bit 17 into all higher bits of the destination. | Integer Computational Instructions
|
||||
| C.ADDI | c.addi rd, nzimm[5:0] | x[rd] = x[rd] + sext(nzimm[5:0]) | rd = x0 & nzimm = 0 | NONE | adds the non-zero sign-extended 6-bit immediate to the value in register rd then writes the result to rd. | Integer Computational Instructions
|
||||
| C.ADDI16SP | c.addi16sp nzimm[9:4] | x[2] = x[2] + sext(nzimm[9:4]) | rd != x2 & nzimm = 0 | NONE | adds the non-zero sign-extended 6-bit immediate to the value in the stack pointer (sp=x2), where the immediate is scaled to represent multiples of 16 in the range (-512,496). C.ADDI16SP is used to adjust the stack pointer in procedure prologues and epilogues. C.ADDI16SP shares the opcode with C.LUI, but has a destination field of x2. | Integer Computational Instructions
|
||||
| C.ADDI4SPN | c.addi4spn rd', nzimm[9:2] | x[8 + rd'] = x[2] + zext(nzimm[9:2]) | nzimm = 0 | NONE | adds a zero-extended non-zero immediate, scaled by 4, to the stack pointer, x2, and writes the result to rd'. This instruction is used to generate pointers to stack-allocated variables. | Integer Computational Instructions
|
||||
| C.SLLI | c.slli rd, uimm[5:0] | x[rd] = x[rd] << uimm[5:0] | rd = x0 & uimm[5] = 0 | NONE | performs a logical left shift (zeros are shifted into the lower bits). | Integer Computational Instructions
|
||||
| C.SRLI | c.srli rd', uimm[5:0] | x[8 + rd'] = x[8 + rd'] >> uimm[5:0] | uimm[5] = 0 | NONE | performs a logical right shift (zeros are shifted into the upper bits). | Integer Computational Instructions
|
||||
| C.SRAI | c.srai rd', uimm[5:0] | x[8 + rd'] = x[8 + rd'] >>s uimm[5:0] | uimm[5] = 0 | NONE | performs an arithmetic right shift (sign bits are shifted into the upper bits). | Integer Computational Instructions
|
||||
| C.ANDI | c.andi rd', imm[5:0] | x[8 + rd'] = x[8 + rd'] & sext(imm[5:0]) | NONE | NONE | computes the bitwise AND of the value in register rd', and the sign-extended 6-bit immediate, then writes the result to rd'. | Integer Computational Instructions
|
||||
| C.ADD | c.add rd, rs2 | x[rd] = x[rd] + x[rs2] | rd = x0 & rs2 = x0 | NONE | adds the values in registers rd and rs2 and writes the result to register rd. | Integer Computational Instructions
|
||||
| C.MV | c.mv rd, rs2 | x[rd] = x[rs2] | rd = x0 & rs2 = x0 | NONE | copies the value in register rs2 into register rd. | Integer Computational Instructions
|
||||
| C.AND | c.and rd', rs2' | x[8 + rd'] = x[8 + rd'] & x[8 + rs2'] | NONE | NONE | computes the bitwise AND of of the value in register rd', and register rs2', then writes the result to rd'. | Integer Computational Instructions
|
||||
| C.OR | c.or rd', rs2' | x[8 + rd'] = x[8 + rd'] \| x[8 + rs2'] | NONE | NONE | computes the bitwise OR of of the value in register rd', and register rs2', then writes the result to rd'. | Integer Computational Instructions
|
||||
| C.XOR | c.and rd', rs2' | x[8 + rd'] = x[8 + rd'] ^ x[8 + rs2'] | NONE | NONE | computes the bitwise XOR of of the value in register rd', and register rs2', then writes the result to rd'. | Integer Computational Instructions
|
||||
| C.SUB | c.sub rd', rs2' | x[8 + rd'] = x[8 + rd'] - x[8 + rs2'] | NONE | NONE | subtracts the value in registers rs2' from value in rd' and writes the result to register rd'. | Integer Computational Instructions
|
||||
| C.EBREAK | c.ebreak | RaiseException(Breakpoint) | NONE | Raise a Breakpoint exception. | cause control to be transferred back to the debugging environment. | Integer Computational Instructions
|
||||
| C.J | c.j imm[11:1] | pc += sext(imm[11:1]) | NONE | jumps to an unaligned address (4-byte or 2-byte boundary) will usually raise an exception. | performs an unconditional control transfer. The offset is sign-extended and added to the pc to form the jump target address. | Control Transfer Instructions
|
||||
| C.JAL | c.jal imm[11:1] | x[1] = pc+2; pc += sext(imm[11:1]) | NONE | jumps to an unaligned address (4-byte or 2-byte boundary) will usually raise an exception. | performs the same operation as C.J, but additionally writes the address of the instruction following the jump (pc+2) to the link register, x1. | Control Transfer Instructions
|
||||
| C.JR | c.jr rs1 | pc = x[rs1] | rs1 = x0 | jumps to an unaligned address (4-byte or 2-byte boundary) will usually raise an exception. | performs an unconditional control transfer to the address in register rs1. | Control Transfer Instructions
|
||||
| C.JALR | c.jalr rs1 | t = pc+2; pc = x[rs1]; x[1] = t | rs1 = x0 | jumps to an unaligned address (4-byte or 2-byte boundary) will usually raise an exception. | performs the same operation as C.JR, but additionally writes the address of the instruction following the jump (pc+2) to the link register, x1. | Control Transfer Instructions
|
||||
| C.BEQZ | c.beqz rs1', imm[8:1] | if (x[8+rs1'] == 0) pc += sext(imm[8:1]) | NONE | no instruction fetch misaligned exception is generated for a conditional branch that is not taken. An Instruction address misaligned exception is raised if the target address is not aligned on 4-byte or 2-byte boundary, because the core supports compressed instructions. | performs conditional control transfers. The offset is sign-extended and added to the pc to form the branch target address. C.BEQZ takes the branch if the value in register rs1' is zero. | Control Transfer Instructions
|
||||
| C.BNEZ | c.bnez rs1', imm[8:1] | if (x[8+rs1'] != 0) pc += sext(imm[8:1]) | NONE | no instruction fetch misaligned exception is generated for a conditional branch that is not taken. An Instruction address misaligned exception is raised if the target address is not aligned on 4-byte or 2-byte boundary, because the core supports compressed instructions. | performs conditional control transfers. The offset is sign-extended and added to the pc to form the branch target address. C.BEQZ takes the branch if the value in register rs1' isn't zero. | Control Transfer Instructions
|
||||
| C.LWSP | c.lwsp rd, uimm(x2) | x[rd] = M[x[2] + zext(uimm[7:2])][31:0] | rd = x0 | loads with a destination of x0 must still raise any exceptions, also an exception if the memory address isn't aligned (4-byte boundary). | loads a 32-bit value from memory into register rd. It computes an effective address by adding the zero-extended offset, scaled by 4, to the stack pointer, x2. | Load and Store Instructions
|
||||
| C.SWSP | c.swsp rd, uimm(x2) | M[x[2] + zext(uimm[7:2])][31:0] = x[rs2] | NONE | an exception raised if the memory address isn't aligned (4-byte boundary). | stores a 32-bit value in register rs2 to memory. It computes an effective address by adding the zero-extended offset, scaled by 4, to the stack pointer, x2. | Load and Store Instructions
|
||||
| C.LW | c.lw rd', uimm(rs1') | x[8+rd'] = M[x[8+rs1'] + zext(uimm[6:2])][31:0]) | NONE | an exception raised if the memory address isn't aligned (4-byte boundary). | loads a 32-bit value from memory into register rd'. It computes an effective address by adding the zero-extended offset, scaled by 4, to the base address in register rs1'. | Load and Store Instructions
|
||||
| C.SW | c.sw rs2', uimm(rs1') | M[x[8+rs1'] + zext(uimm[6:2])][31:0] = x[8+rs2'] | NONE | an exception raised if the memory address isn't aligned (4-byte boundary). | stores a 32-bit value from memory into register rd'. It computes an effective address by adding the zero-extended offset, scaled by 4, to the base address in register rs1'. | Load and Store Instructions
|
||||
|===
|
||||
|
||||
==== RV32Zicsr Control and Status Register Instructions
|
||||
|
||||
|===
|
||||
| Name | Format | Pseudocode|Invalid_values | Exception_raised | Description| Op Name
|
||||
|
||||
| CSRRW | csrrw rd, csr, rs1 | t = CSRs[csr]; CSRs[csr] = x[rs1]; x[rd] = t | NONE | Attempts to access a non-existent CSR raise an illegal instruction exception. Attempts to access a CSR without appropriate privilege level or to write a read-only register also raise illegal instruction exceptions. | Reads the old value of the CSR, zero-extends the value to 32 bits, then writes it to integer register rd. The initial value in rs1 is written to the CSR. If rd=x0, then the instruction shall not read the CSR and shall not cause any of the side-effects that might occur on a CSR read. | Control and Status Register Operations
|
||||
| CSRRS | csrrs rd, csr, rs1 | t = CSRs[csr]; CSRs[csr] = t \| x[rs1]; x[rd] = t | NONE | Attempts to access a non-existent CSR raise an illegal instruction exception. Attempts to access a CSR without appropriate privilege level or to write a read-only register also raise illegal instruction exceptions. | Reads the value of the CSR, zero-extends the value to 32 bits, and writes it to integer register rd. The initial value in integer register rs1 is treated as a bit mask that specifies bit positions to be set in the CSR. Any bit that is high in rs1 will cause the corresponding bit to be set in the CSR, if that CSR bit is writable. Other bits in the CSR are unaffected (though CSRs might have side effects when written). If rs1=x0, then the instruction will not write to the CSR at all, and so shall not cause any of the side effects that might otherwise occur on a CSR write, such as raising illegal instruction exceptions on accesses to read-only CSRs. | Control and Status Register Operations
|
||||
| CSRRC | csrrc rd, csr, rs1 | t = CSRs[csr]; CSRs[csr] = t & ∼x[rs1]; x[rd] = t | NONE | Attempts to access a non-existent CSR raise an illegal instruction exception. Attempts to access a CSR without appropriate privilege level or to write a read-only register also raise illegal instruction exceptions. | Reads the value of the CSR, zero-extends the value to 32 bits, and writes it to integer register rd. The initial value in integer register rs1 is treated as a bit mask that specifies bit positions to be cleared in the CSR. Any bit that is high in rs1 will cause the corresponding bit to be set in the CSR, if that CSR bit is writable. Other bits in the CSR are unaffected (though CSRs might have side effects when written). If rs1=x0, then the instruction will not write to the CSR at all, and so shall not cause any of the side effects that might otherwise occur on a CSR write, such as raising illegal instruction exceptions on accesses to read-only CSRs. | Control and Status Register Operations
|
||||
| CSRRWI | csrrwi rd, csr, uimm[4:0] | x[rd] = CSRs[csr]; CSRs[csr] = zext(uimm[4:0]) | NONE | Attempts to access a non-existent CSR raise an illegal instruction exception. Attempts to access a CSR without appropriate privilege level or to write a read-only register also raise illegal instruction exceptions. | Reads the old value of the CSR, zero-extends the value to 32 bits, then writes it to integer register rd. The zero-extends immediate is written to the CSR. If rd=x0, then the instruction shall not read the CSR and shall not cause any of the side-effects that might occur on a CSR read. | Control and Status Register Operations
|
||||
| CSRRSI | csrrsi rd, csr, uimm[4:0] | t = CSRs[csr]; CSRs[csr] = t \| zext(uimm[4:0]); x[rd] = t | NONE | Attempts to access a non-existent CSR raise an illegal instruction exception. Attempts to access a CSR without appropriate privilege level or to write a read-only register also raise illegal instruction exceptions. | Reads the value of the CSR, zero-extends the value to 32 bits, and writes it to integer register rd. The zero-extends immediate value is treated as a bit mask that specifies bit positions to be set in the CSR. Any bit that is high in zero-extends immediate will cause the corresponding bit to be set in the CSR, if that CSR bit is writable. Other bits in the CSR are unaffected (though CSRs might have side effects when written). If the uimm[4:0] field is zero, then these instructions will not write to the CSR, and shall not cause any of the side effects that might otherwise occur on a CSR write. | Control and Status Register Operations
|
||||
| CSRRCI | csrrci rd, csr, uimm[4:0] | t = CSRs[csr]; CSRs[csr] = t & ∼zext(uimm[4:0]); x[rd] = t | NONE | Attempts to access a non-existent CSR raise an illegal instruction exception. Attempts to access a CSR without appropriate privilege level or to write a read-only register also raise illegal instruction exceptions. | Reads the value of the CSR, zero-extends the value to 32 bits, and writes it to integer register rd. The zero-extends immediate value is treated as a bit mask that specifies bit positions to be cleared in the CSR. Any bit that is high in zero-extends immediate will cause the corresponding bit to be set in the CSR, if that CSR bit is writable. Other bits in the CSR are unaffected (though CSRs might have side effects when written). If the uimm[4:0] field is zero, then these instructions will not write to the CSR, and shall not cause any of the side effects that might otherwise occur on a CSR write. | Control and Status Register Operations
|
||||
|===
|
||||
|
||||
==== RV32Zcb Code Size Reduction Instructions
|
||||
|
||||
|===
|
||||
| Name | Format | Pseudocode|Invalid_values | Exception_raised | Description| Op Name
|
||||
|
||||
| C.ZEXT.B | c.zext.b rd' | x[8 + rd'] = zext(x[8 + rd'][7:0]) | NONE | NONE | This instruction takes a single source/destination operand. It zero-extends the least-significant byte of the operand by inserting zeros into all of the bits more significant than 7. | Code Size Reduction Operations
|
||||
| C.SEXT.B | c.sext.b rd' | x[8 + rd'] = sext(x[8 + rd'][7:0]) | NONE | NONE | This instruction takes a single source/destination operand. It sign-extends the least-significant byte in the operand by copying the most-significant bit in the byte (i.e., bit 7) to all of the more-significant bits. It also requires Bit-Manipulation (Zbb) extension support. | Code Size Reduction Operations
|
||||
| C.ZEXT.H | c.zext.h rd' | x[8 + rd'] = zext(x[8 + rd'][15:0]) | NONE | NONE | This instruction takes a single source/destination operand. It zero-extends the least-significant halfword of the operand by inserting zeros into all of the bits more significant than 15. It also requires Bit-Manipulation (Zbb) extension support. | Code Size Reduction Operations
|
||||
| C.SEXT.H | c.sext.h rd' | x[8 + rd'] = sext(x[8 + rd'][15:0]) | NONE | NONE | This instruction takes a single source/destination operand. It sign-extends the least-significant halfword in the operand by copying the most-significant bit in the halfword (i.e., bit 15) to all of the more-significant bits. It also requires Bit-Manipulation (Zbb) extension support. | Code Size Reduction Operations
|
||||
| C.NOT | c.not rd' | x[8 + rd'] = x[8 + rd'] ^ -1 | NONE | NONE | This instruction takes the one’s complement of rd'/rs1' and writes the result to the same register. | Code Size Reduction Operations
|
||||
| C.MUL | c.mul rd', rs2' | x[8 + rd'] = (x[8 + rd'] * x[8 + rs2'])[31:0] | NONE | NONE | performs a 32-bit × 32-bit multiplication and places the lower 32 bits in the destination register (Both rd' and rs2' treated as signed numbers). It also requires M extension support. | Code Size Reduction Operations
|
||||
| C.LHU | c.lhu rd', uimm(rs1') | x[8+rd'] = zext(M[x[8+rs1'] + zext(uimm[1])][15:0]) | NONE | an exception raised if the memory address isn't aligned (2-byte boundary). | This instruction loads a halfword from the memory address formed by adding rs1' to the zero extended immediate uimm. The resulting halfword is zero extended and is written to rd'. | Code Size Reduction Operations
|
||||
| C.LH | c.lh rd', uimm(rs1') | x[8+rd'] = sext(M[x[8+rs1'] + zext(uimm[1])][15:0]) | NONE | an exception raised if the memory address isn't aligned (2-byte boundary). | This instruction loads a halfword from the memory address formed by adding rs1' to the zero extended immediate uimm. The resulting halfword is sign extended and is written to rd'. | Code Size Reduction Operations
|
||||
| C.LBU | c.lbu rd', uimm(rs1') | x[8+rd'] = zext(M[x[8+rs1'] + zext(uimm[1:0])][7:0]) | NONE | NONE | This instruction loads a byte from the memory address formed by adding rs1' to the zero extended immediate uimm. The resulting byte is zero extended and is written to rd'. | Code Size Reduction Operations
|
||||
| C.SH | c.sh rs2', uimm(rs1') | M[x[8+rs1'] + zext(uimm[1])][15:0] = x[8+rs2'] | NONE | an exception raised if the memory address isn't aligned (2-byte boundary). | This instruction stores the least significant halfword of rs2' to the memory address formed by adding rs1' to the zero extended immediate uimm. | Code Size Reduction Operations
|
||||
| C.SB | c.sb rs2', uimm(rs1') | M[x[8+rs1'] + zext(uimm[1:0])][7:0] = x[8+rs2'] | NONE | NONE | This instruction stores the least significant byte of rs2' to the memory address formed by adding rs1' to the zero extended immediate uimm. | Code Size Reduction Operations
|
||||
|===
|
||||
|
||||
==== RVZba Address generation instructions
|
||||
|
||||
|===
|
||||
| Name | Format | Pseudocode|Invalid_values | Exception_raised | Description| Op Name
|
||||
|
||||
| ADD.UW | add.uw rd, rs1, rs2 | X(rd) = rs2 + EXTZ(X(rs1)[31..0]) | NONE | NONE | This instruction performs an XLEN-wide addition between rs2 and the zero-extended least-significant word of rs1. | Address generation instructions
|
||||
| SH1ADD | sh1add rd, rs1, rs2 | X(rd) = X(rs2) + (X(rs1) << 1) | NONE | NONE | This instruction shifts rs1 to the left by 1 bit and adds it to rs2. | Address generation instructions
|
||||
| SH1ADD.UW | sh1add.uw rd, rs1, rs2 | X(rd) = rs2 + (EXTZ(X(rs1)[31..0]) << 1) | NONE | NONE | This instruction performs an XLEN-wide addition of two addends. The first addend is rs2. The second addend is the unsigned value formed by extracting the least-significant word of rs1 and shifting it left by 1 place. | Address generation instructions
|
||||
| SH2ADD | sh2add rd, rs1, rs2 | X(rd) = X(rs2) + (X(rs1) << 2) | NONE | NONE | This instruction shifts rs1 to the left by 2 bit and adds it to rs2. | Address generation instructions
|
||||
| SH2ADD.UW | sh2add.uw rd, rs1, rs2 | X(rd) = rs2 + (EXTZ(X(rs1)[31..0]) << 2) | NONE | NONE | This instruction performs an XLEN-wide addition of two addends. The first addend is rs2. The second addend is the unsigned value formed by extracting the least-significant word of rs1 and shifting it left by 2 places. | Address generation instructions
|
||||
| SH3ADD | sh3add rd, rs1, rs2 | X(rd) = X(rs2) + (X(rs1) << 3) | NONE | NONE | This instruction shifts rs1 to the left by 3 bit and adds it to rs2. | Address generation instructions
|
||||
| SH3ADD.UW | sh3add.uw rd, rs1, rs2 | X(rd) = rs2 + (EXTZ(X(rs1)[31..0]) << 3) | NONE | NONE | This instruction performs an XLEN-wide addition of two addends. The first addend is rs2. The second addend is the unsigned value formed by extracting the least-significant word of rs1 and shifting it left by 3 places. | Address generation instructions
|
||||
| SLLI.UW | slli.uw rd, rs1, imm | X(rd) = (EXTZ(X(rs)[31..0]) << imm) | NONE | NONE | This instruction takes the least-significant word of rs1, zero-extends it, and shifts it left by the immediate. | Address generation instructions
|
||||
|===
|
||||
|
||||
==== RVZbb Basic bit-manipulation
|
||||
|
||||
|===
|
||||
| Name | Format | Pseudocode|Invalid_values | Exception_raised | Description| Op Name
|
||||
|
||||
| ANDN | andn rd, rs1, rs2 | X(rd) = X(rs1) & ~X(rs2) | NONE | NONE | Performs bitwise AND operation between rs1 and bitwise inversion of rs2. | Logical_with_negate
|
||||
| ORN | orn rd, rs1, rs2 | X(rd) = X(rs1) \| ~X(rs2) | NONE | NONE | Performs bitwise OR operation between rs1 and bitwise inversion of rs2. | Logical_with_negate
|
||||
| XNOR | xnor rd, rs1, rs2 | X(rd) = ~(X(rs1) ^ X(rs2)) | NONE | NONE | Performs bitwise XOR operation between rs1 and rs2, then complements the result. | Logical_with_negate
|
||||
| CLZ | clz rd, rs | if [x[i]] == 1 then return(i) else return -1 | NONE | NONE | Counts leading zero bits in rs. | Count_leading_trailing_zero_bits
|
||||
| CTZ | ctz rd, rs | if [x[i]] == 1 then return(i) else return xlen; | NONE | NONE | Counts trailing zero bits in rs. | Count_leading_trailing_zero_bits
|
||||
| CLZW | clzw rd, rs | if [x[i]] == 1 then return(i) else return -1 | NONE | NONE | Counts leading zero bits in the least-significant word of rs. | Count_leading_trailing_zero_bits
|
||||
| CTZW | ctzw rd, rs | if [x[i]] == 1 then return(i) else return 32; | NONE | NONE | Counts trailing zero bits in the least-significant word of rs. | Count_leading_trailing_zero_bits
|
||||
| CPOP | cpop rd, rs | if rs[i] == 1 then bitcount = bitcount + 1 else () | NONE | NONE | Counts set bits in rs. | Count_population
|
||||
| CPOPW | cpopw rd, rs | if rs[i] == 0b1 then bitcount = bitcount + 1 else () | NONE | NONE | Counts set bits in the least-significant word of rs. | Count_population
|
||||
| MAX | max rd, rs1, rs2 | if rs1_val <_s rs2_val then rs2_val else rs1_val | NONE | NONE | Returns the larger of two signed integers. | Integer_minimum_maximum
|
||||
| MAXU | maxu rd, rs1, rs2 | if rs1_val <_u rs2_val then rs2_val else rs1_val | NONE | NONE | Returns the larger of two unsigned integers. | Integer_minimum_maximum
|
||||
| MIN | min rd, rs1, rs2 | if rs1_val <_s rs2_val then rs1_val else rs2_val | NONE | NONE | Returns the smaller of two signed integers. | Integer_minimum_maximum
|
||||
| MINU | minu rd, rs1, rs2 | if rs1_val <_u rs2_val then rs1_val else rs2_val | NONE | NONE | Returns the smaller of two unsigned integers. | Integer_minimum_maximum
|
||||
| SEXT.B | sext.b rd, rs | X(rd) = EXTS(X(rs)[7..0]) | NONE | NONE | Sign-extends the least-significant byte in the source to XLEN. | Sign_and_zero_extension
|
||||
| SEXT.H | sext.h rd, rs | X(rd) = EXTS(X(rs)[15..0]) | NONE | NONE | Sign-extends the least-significant halfword in rs to XLEN. | Sign_and_zero_extension
|
||||
| ZEXT.H | zext.h rd, rs | X(rd) = EXTZ(X(rs)[15..0]) | NONE | NONE | Zero-extends the least-significant halfword of the source to XLEN. | Sign_and_zero_extension
|
||||
| ROL | rol rd, rs1, rs2 | (X(rs1) << log2(XLEN)) \| (X(rs1) >> (xlen - log2(XLEN))) | NONE | NONE | Performs a rotate left of rs1 by the amount in least-significant log2(XLEN) bits of rs2. | Bitwise_rotation
|
||||
| ROR | ror rd, rs1, rs2 | (X(rs1) >> log2(XLEN)) \| (X(rs1) << (xlen - log2(XLEN))) | NONE | NONE | Performs a rotate right of rs1 by the amount in least-significant log2(XLEN) bits of rs2. | Bitwise_rotation
|
||||
| RORI | rori rd, rs1, shamt | (X(rs1) >> log2(XLEN)) \| (X(rs1) << (xlen - log2(XLEN))) | NONE | NONE | Performs a rotate right of rs1 by the amount in least-significant log2(XLEN) bits of shamt. | Bitwise_rotation
|
||||
| ROLW | rolw rd, rs1, rs2 | EXTS((rs1 << X(rs2)[4..0]) \| (rs1 >> (32 - X(rs2)[4..0]))) | NONE | NONE | Performs a rotate left on the least-significant word of rs1 by the amount in least-significant 5 bits of rs2. | Bitwise_rotation
|
||||
| RORIW | roriw rd, rs1, shamt | (rs1_data >> shamt[4..0]) \| (rs1_data << (32 - shamt[4..0])) | NONE | NONE | Performs a rotate right on the least-significant word of rs1 by the amount in least-significant log2(XLEN) bits of shamt. | Bitwise_rotation
|
||||
| RORW | rorw rd, rs1, rs2 | (rs1 >> X(rs2)[4..0]) \| (rs1 << (32 - X(rs2)[4..0])) | NONE | NONE | Performs a rotate right on the least-significant word of rs1 by the amount in least-significant 5 bits of rs2. | Bitwise_rotation
|
||||
| ORC.b | orc.b rd, rs | if { input[(i + 7)..i] == 0 then 0b00000000 else 0b11111111 | NONE | NONE | Sets the bits of each byte in rd to all zeros if no bit within the respective byte of rs is set, or to all ones if any bit within the respective byte of rs is set. | OR_Combine
|
||||
| REV8 | rev8 rd, rs | output[i..(i + 7)] = input[(j - 7)..j] | NONE | NONE | Reverses the order of the bytes in rs. | Byte_reverse
|
||||
|===
|
||||
|
||||
==== RVZbc Carry-less multiplication
|
||||
|
||||
|===
|
||||
| Name | Format | Pseudocode|Invalid_values | Exception_raised | Description| Op Name
|
||||
|
||||
| CLMUL | clmul rd, rs1, rs2 | foreach (i from 1 to xlen by 1) { output = if ((rs2 >> i) & 1) then output ^ (rs1 << i); else output;} | NONE | NONE | clmul produces the lower half of the 2.XLEN carry-less product. | Carry-less multiplication Operations
|
||||
| CLMULH | clmulh rd, rs1, rs2 | foreach (i from 1 to xlen by 1) { output = if ((rs2_val >> i) & 1) then output ^ (rs1_val >> (xlen - i)) else output} | NONE | NONE | clmulh produces the upper half of the 2.XLEN carry-less product. | Carry-less multiplication Operations
|
||||
| CLMULR | clmulr rd, rs1, rs2 | foreach (i from 0 to (xlen - 1) by 1) { output = if ((rs2_val >> i) & 1) then output ^ (rs1_val >> (xlen - i - 1)) else output} | NONE | NONE | clmulr produces bits 2.XLEN-2:XLEN-1 of the 2.XLEN carry-less product. | Carry-less multiplication Operations
|
||||
|===
|
||||
|
||||
==== RVZbs Single bit Instructions
|
||||
|
||||
|===
|
||||
| Name | Format | Pseudocode|Invalid_values | Exception_raised | Description| Op Name
|
||||
|
||||
| BCLR | bclr rd, rs1, rs2 | X(rd) = X(rs1) & ~(1 << (X(rs2) & (XLEN - 1))) | NONE | NONE | This instruction returns rs1 with a single bit cleared at the index specified in rs2. The index is read from the lower log2(XLEN) bits of rs2. | Single_bit_Operations
|
||||
| BCLRI | bclri rd, rs1, shamt | X(rd) = X(rs1) & ~(1 << (shamt & (XLEN - 1))) | NONE | NONE | This instruction returns rs1 with a single bit cleared at the index specified in shamt. The index is read from the lower log2(XLEN) bits of shamt. For RV32, the encodings corresponding to shamt[5]=1 are reserved. | Single_bit_Operations
|
||||
| BEXT | bext rd, rs1, rs2 | X(rd) = (X(rs1) >> (X(rs2) & (XLEN - 1))) & 1 | NONE | NONE | This instruction returns a single bit extracted from rs1 at the index specified in rs2. The index is read from the lower log2(XLEN) bits of rs2. | Single_bit_Operations
|
||||
| BEXTI | bexti rd, rs1, shamt | X(rd) = (X(rs1) >> (shamt & (XLEN - 1))) & 1 | NONE | NONE | This instruction returns a single bit extracted from rs1 at the index specified in rs2. The index is read from the lower log2(XLEN) bits of shamt. For RV32, the encodings corresponding to shamt[5]=1 are reserved. | Single_bit_Operations
|
||||
| BINV | binv rd, rs1, rs2 | X(rd) = X(rs1) ^ (1 << (X(rs2) & (XLEN - 1))) | NONE | NONE | This instruction returns rs1 with a single bit inverted at the index specified in rs2. The index is read from the lower log2(XLEN) bits of rs2. | Single_bit_Operations
|
||||
| BINVI | binvi rd, rs1, shamt | X(rd) = X(rs1) ^ (1 << (shamt & (XLEN - 1))) | NONE | NONE | This instruction returns rs1 with a single bit inverted at the index specified in shamt. The index is read from the lower log2(XLEN) bits of shamt. For RV32, the encodings corresponding to shamt[5]=1 are reserved. | Single_bit_Operations
|
||||
| BSET | bset rd, rs1, rs2 | X(rd) = X(rs1) \| (1 << (X(rs2) & (XLEN - 1))) | NONE | NONE | This instruction returns rs1 with a single bit set at the index specified in rs2. The index is read from the lower log2(XLEN) bits of rs2. | Single_bit_Operations
|
||||
| BSETI | bseti rd, rs1, shamt | X(rd) = X(rs1) \| (1 << (shamt & (XLEN - 1))) | NONE | NONE | This instruction returns rs1 with a single bit set at the index specified in shamt. The index is read from the lower log2(XLEN) bits of shamt. For RV32, the encodings corresponding to shamt[5]=1 are reserved. | Single_bit_Operations
|
||||
|===
|
|
@ -1,210 +0,0 @@
|
|||
<!--Copyright (c) 2024 OpenHW Group
|
||||
Copyright (c) 2024 Thales
|
||||
SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
||||
Author: Abdessamii Oukalrazqou
|
||||
-->
|
||||
|
||||
# isa
|
||||
|
||||
|
||||
|
||||
## Instructions
|
||||
|
||||
|Subset Name|Name |Description|
|
||||
| :--- | :--- | :--- |
|
||||
|I|[RV32I Base Integer Instructions](#RV32I Base Integer Instructions)|the base integer instruction set, also known as the 'RV32I' or 'RV64I' instruction set , depending on the address space size, provides the core functionality required for general-purpose computing . it includes instructions for arithmetic, logical, and control operations, as well as memory access and manipulation |
|
||||
|M|[RV32M Multiplication and Division Instructions](#RV32M Multiplication and Division Instructions)|the standard integer multiplication and division instruction extension, which is named “M” and contains instructions that multiply or divide values held in two integer registers. |
|
||||
|C|[RV32C Compressed Instructions](#RV32C Compressed Instructions)|RVC uses a simple compression scheme that offers shorter 16-bit versions of common 32-bit RISC-V instructions when: the immediate or address offset is small; one of the registers is the zero register (x0), the ABI link register (x1), or the ABI stack pointer (x2); the destination register and the first source register are identical; the registers used are the 8 most popular ones. The C extension is compatible with all other standard instruction extensions. The C extension allows 16-bit instructions to be freely intermixed with 32-bit instructions, with the latter now able to start on any 16-bit boundary. With the addition of the C extension, JAL and JALR instructions will no longer raise an instruction misaligned exception |
|
||||
|Zicsr|[RV32Zicsr Control and Status Register Instructions](#RV32Zicsr Control and Status Register Instructions)|All CSR instructions atomically read-modify-write a single CSR, whose CSR specifier is encoded in the 12-bit csr field of the instruction held in bits 31–20. The immediate forms use a 5-bit zero-extended immediate encoded in the rs1 field. |
|
||||
|Zifencei|[RVZifencei Instruction Fetch Fence](#RVZifencei Instruction Fetch Fence)|FENCE.I instruction that provides explicit synchronization between writes to instruction memory and instruction fetches on the same hart. Currently, this instruction is the only standard mechanism to ensure that stores visible to a hart will also be visible to it instruction fetches. |
|
||||
|Zba|[RVZba Address generation instructions](#RVZba Address generation instructions)|The Zba instructions can be used to accelerate the generation of addresses that index into arrays of basic types (halfword, word, doubleword) using both unsigned word-sized and XLEN-sized indices: a shifted index is added to a base address. The shift and add instructions do a left shift of 1, 2, or 3 because these are commonly found in real-world code and because they can be implemented with a minimal amount of additional hardware beyond that of the simple adder. This avoids lengthening the critical path in implementations. While the shift and add instructions are limited to a maximum left shift of 3, the slli instruction (from the base ISA) can be used to perform similar shifts for indexing into arrays of wider elements. The slli.uw added in this extension can be used when the index is to be interpreted as an unsigned word. |
|
||||
|Zbb|[RVZbb Basic bit-manipulation](#RVZbb Basic bit-manipulation)|The bit-manipulation (bitmanip) extension collection is comprised of several component extensions to the base RISC-V architecture that are intended to provide some combination of code size reduction, performance improvement, and energy reduction. While the instructions are intended to have general use, some instructions are more useful in some domains than others. Hence, several smaller bitmanip extensions are provided. Each of these smaller extensions is grouped by common function and use case, and each has its own Zb*-extension name. |
|
||||
|Zbc|[RVZbc Carry-less multiplication](#RVZbc Carry-less multiplication)|Carry-less multiplication is the multiplication in the polynomial ring over GF(2). clmul produces the lower half of the carry-less product and clmulh produces the upper half of the 2✕XLEN carry-less product. clmulr produces bits 2✕XLEN−2:XLEN-1 of the 2✕XLEN carry-less product. |
|
||||
|Zbs|[RVZbs Single bit Instructions](#RVZbs Single bit Instructions)|The single-bit instructions provide a mechanism to set, clear, invert, or extract a single bit in a register. The bit is specified by its index. |
|
||||
|Zcb|[RV32Zcb Code Size Reduction Instructions](#RV32Zcb Code Size Reduction Instructions)|Zcb belongs to the group of extensions called RISC-V Code Size Reduction Extension (Zc*). Zc* has become the superset of the Standard C extension adding more 16-bit instructions to the ISA. Zcb includes the 16-bit version of additional Integer (I), Multiply (M), and Bit-Manipulation (Zbb) Instructions. All the Zcb instructions require at least standard C extension support as a prerequisite, along with M and Zbb extensions for the 16-bit version of the respective instructions. |
|
||||
|Zicntr|[Zicntr](#Zicntr)|No info found yet for extension Zicntr|
|
||||
|
||||
### RV32I Base Integer Instructions
|
||||
|
||||
|Name|Format|Pseudocode|Invalid_values|Exception_raised|Description|Op Name|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|ADDI |[addi rd, rs1, imm[11:0]](#addi rd, rs1, imm[11:0])|x[rd] = x[rs1] + sext(imm[11:0])|NONE|NONE |add sign-extended 12-bit immediate to register rs1, and store the result in register rd.|Integer_Register_Immediate_Operations|
|
||||
|ANDI |[andi rd, rs1, imm[11:0]](#andi rd, rs1, imm[11:0])|x[rd] = x[rs1] & sext(imm[11:0])|NONE|NONE |perform bitwise AND on register rs1 and the sign-extended 12-bit immediate and place the result in rd.|Integer_Register_Immediate_Operations|
|
||||
|ORI |[ori rd, rs1, imm[11:0]](#ori rd, rs1, imm[11:0])|x[rd] = x[rs1] \| sext(imm[11:0])|NONE|NONE |perform bitwise OR on register rs1 and the sign-extended 12-bit immediate and place the result in rd.|Integer_Register_Immediate_Operations|
|
||||
|XORI |[xori rd, rs1, imm[11:0]](#xori rd, rs1, imm[11:0])|x[rd] = x[rs1] ^ sext(imm[11:0])|NONE|NONE |perform bitwise XOR on register rs1 and the sign-extended 12-bit immediate and place the result in rd.|Integer_Register_Immediate_Operations|
|
||||
|SLTI |[slti rd, rs1, imm[11:0]](#slti rd, rs1, imm[11:0])|if (x[rs1] < sext(imm[11:0])) x[rd] = 1 else x[rd] = 0|NONE|NONE |set register rd to 1 if register rs1 is less than the sign extended immediate when both are treated as signed numbers, else 0 is written to rd.|Integer_Register_Immediate_Operations|
|
||||
|SLTIU |[sltiu rd, rs1, imm[11:0]](#sltiu rd, rs1, imm[11:0])|if (x[rs1] <u sext(imm[11:0])) x[rd] = 1 else x[rd] = 0|NONE|NONE |set register rd to 1 if register rs1 is less than the sign extended immediate when both are treated as unsigned numbers, else 0 is written to rd."|Integer_Register_Immediate_Operations|
|
||||
|SLLI |[slli rd, rs1, imm[4:0]](#slli rd, rs1, imm[4:0])|x[rd] = x[rs1] << imm[4:0]|NONE|NONE |logical left shift (zeros are shifted into the lower bits).|Integer_Register_Immediate_Operations|
|
||||
|SRLI |[srli rd, rs1, imm[4:0]](#srli rd, rs1, imm[4:0])|x[rd] = x[rs1] >> imm[4:0]|NONE|NONE |logical right shift (zeros are shifted into the upper bits).|Integer_Register_Immediate_Operations|
|
||||
|SRAI |[srai rd, rs1, imm[4:0]](#srai rd, rs1, imm[4:0])|x[rd] = x[rs1] >>s imm[4:0]|NONE|NONE |arithmetic right shift (the original sign bit is copied into the vacated upper bits).|Integer_Register_Immediate_Operations|
|
||||
|LUI |[lui rd, imm[19:0]](#lui rd, imm[19:0])|x[rd] = sext(imm[31:12] << 12)|NONE|NONE |place the immediate value in the top 20 bits of the destination register rd, filling in the lowest 12 bits with zeros.|Integer_Register_Immediate_Operations|
|
||||
|AUIPC |[auipc rd, imm[19:0]](#auipc rd, imm[19:0])|x[rd] = pc + sext(immediate[31:12] << 12)|NONE|NONE |form a 32-bit offset from the 20-bit immediate, filling in the lowest 12 bits with zeros, adds this offset to the pc, then place the result in register rd.|Integer_Register_Immediate_Operations|
|
||||
|ADD |[add rd, rs1, rs2](#add rd, rs1, rs2)|x[rd] = x[rs1] + x[rs2]|NONE|NONE |add rs2 to register rs1, and store the result in register rd.|Integer_Register_Register_Operations|
|
||||
|SUB |[sub rd, rs1, rs2](#sub rd, rs1, rs2)|x[rd] = x[rs1] - x[rs2]|NONE|NONE |subtract rs2 from register rs1, and store the result in register rd.|Integer_Register_Register_Operations|
|
||||
|AND |[and rd, rs1, rs2](#and rd, rs1, rs2)|x[rd] = x[rs1] & x[rs2]|NONE|NONE |perform bitwise AND on register rs1 and rs2 and place the result in rd.|Integer_Register_Register_Operations|
|
||||
|OR |[or rd, rs1, rs2](#or rd, rs1, rs2)|x[rd] = x[rs1] \| x[rs2]|NONE|NONE |perform bitwise OR on register rs1 and rs2 and place the result in rd.|Integer_Register_Register_Operations|
|
||||
|XOR |[xor rd, rs1, rs2](#xor rd, rs1, rs2)|x[rd] = x[rs1] ^ x[rs2]|NONE|NONE |perform bitwise XOR on register rs1 and rs2 and place the result in rd.|Integer_Register_Register_Operations|
|
||||
|SLT |[slt rd, rs1, rs2](#slt rd, rs1, rs2)|if (x[rs1] < x[rs2]) x[rd] = 1 else x[rd] = 0|NONE|NONE |set register rd to 1 if register rs1 is less than rs2 when both are treated as signed numbers, else 0 is written to rd.|Integer_Register_Register_Operations|
|
||||
|SLTU |[sltu rd, rs1, rs2](#sltu rd, rs1, rs2)|if (x[rs1] <u x[rs2]) x[rd] = 1 else x[rd] = 0|NONE|NONE |set register rd to 1 if register rs1 is less than rs2 when both are treated as unsigned numbers, else 0 is written to rd.|Integer_Register_Register_Operations|
|
||||
|SLL |[sll rd, rs1, rs2](#sll rd, rs1, rs2)|x[rd] = x[rs1] << x[rs2]|NONE|NONE |logical left shift (zeros are shifted into the lower bits).|Integer_Register_Register_Operations|
|
||||
|SRL |[srl rd, rs1, rs2](#srl rd, rs1, rs2)|x[rd] = x[rs1] >> x[rs2]|NONE|NONE |logical right shift (zeros are shifted into the upper bits).|Integer_Register_Register_Operations|
|
||||
|SRA |[sra rd, rs1, rs2](#sra rd, rs1, rs2)|x[rd] = x[rs1] >>s x[rs2]|NONE|NONE |arithmetic right shift (the original sign bit is copied into the vacated upper bits).|Integer_Register_Register_Operations|
|
||||
|JAL |[jal rd, imm[20:1]](#jal rd, imm[20:1])|x[rd] = pc+4; pc += sext(imm[20:1])|NONE|jumps to an unaligned address (4-byte or 2-byte boundary) will usually raise an exception.|offset is sign-extended and added to the pc to form the jump target address (pc is calculated using signed arithmetic), then setting the least-significant bit of the result to zero, and store the address of instruction following the jump (pc+4) into register rd.|Control_Transfer_Operations-Unconditional_Jumps|
|
||||
|JALR |[jalr rd, rs1, imm[11:0]](#jalr rd, rs1, imm[11:0])|t = pc+4; pc = (x[rs1]+sext(imm[11:0]))&∼1 ; x[rd] = t|NONE|jumps to an unaligned address (4-byte or 2-byte boundary) will usually raise an exception.|target address is obtained by adding the 12-bit signed immediate to the register rs1 (pc is calculated using signed arithmetic), then setting the least-significant bit of the result to zero, and store the address of instruction following the jump (pc+4) into register rd.|Control_Transfer_Operations-Unconditional_Jumps|
|
||||
|BEQ |[beq rs1, rs2, imm[12:1]](#beq rs1, rs2, imm[12:1])|if (x[rs1] == x[rs2]) pc += sext({imm[12:1], 1’b0}) else pc += 4|NONE|no instruction fetch misaligned exception is generated for a conditional branch that is not taken. An Instruction address misaligned exception is raised if the target address is not aligned on 4-byte or 2-byte boundary, because the core supports compressed instructions.|takes the branch (pc is calculated using signed arithmetic) if registers rs1 and rs2 are equal.|Control_Transfer_Operations-Conditional_Branches|
|
||||
|BNE |[bne rs1, rs2, imm[12:1]](#bne rs1, rs2, imm[12:1])|if (x[rs1] != x[rs2]) pc += sext({imm[12:1], 1’b0}) else pc += 4|NONE|no instruction fetch misaligned exception is generated for a conditional branch that is not taken. An Instruction address misaligned exception is raised if the target address is not aligned on 4-byte or 2-byte boundary, because the core supports compressed instructions.|takes the branch (pc is calculated using signed arithmetic) if registers rs1 and rs2 are not equal.|Control_Transfer_Operations-Conditional_Branches|
|
||||
|BLT |[blt rs1, rs2, imm[12:1]](#blt rs1, rs2, imm[12:1])|if (x[rs1] < x[rs2]) pc += sext({imm[12:1], 1’b0}) else pc += 4|NONE|no instruction fetch misaligned exception is generated for a conditional branch that is not taken. An Instruction address misaligned exception is raised if the target address is not aligned on 4-byte or 2-byte boundary, because the core supports compressed instructions.|takes the branch (pc is calculated using signed arithmetic) if registers rs1 less than rs2 (using signed comparison).|Control_Transfer_Operations-Conditional_Branches|
|
||||
|BLTU |[bltu rs1, rs2, imm[12:1]](#bltu rs1, rs2, imm[12:1])|if (x[rs1] <u x[rs2]) pc += sext({imm[12:1], 1’b0}) else pc += 4|NONE|no instruction fetch misaligned exception is generated for a conditional branch that is not taken. An Instruction address misaligned exception is raised if the target address is not aligned on 4-byte or 2-byte boundary, because the core supports compressed instructions.|takes the branch (pc is calculated using signed arithmetic) if registers rs1 less than rs2 (using unsigned comparison).|Control_Transfer_Operations-Conditional_Branches|
|
||||
|BGE |[bge rs1, rs2, imm[12:1]](#bge rs1, rs2, imm[12:1])|if (x[rs1] >= x[rs2]) pc += sext({imm[12:1], 1’b0}) else pc += 4|NONE|no instruction fetch misaligned exception is generated for a conditional branch that is not taken. An Instruction address misaligned exception is raised if the target address is not aligned on 4-byte or 2-byte boundary, because the core supports compressed instructions.|takes the branch (pc is calculated using signed arithmetic) if registers rs1 is greater than or equal rs2 (using signed comparison).|Control_Transfer_Operations-Conditional_Branches|
|
||||
|BGEU |[bgeu rs1, rs2, imm[12:1]](#bgeu rs1, rs2, imm[12:1])|if (x[rs1] >=u x[rs2]) pc += sext({imm[12:1], 1’b0}) else pc += 4|NONE|no instruction fetch misaligned exception is generated for a conditional branch that is not taken. An Instruction address misaligned exception is raised if the target address is not aligned on 4-byte or 2-byte boundary, because the core supports compressed instructions.|takes the branch (pc is calculated using signed arithmetic) if registers rs1 is greater than or equal rs2 (using unsigned comparison).|Control_Transfer_Operations-Conditional_Branches|
|
||||
|LB |[lb rd, imm(rs1)](#lb rd, imm(rs1))|x[rd] = sext(M[x[rs1] + sext(imm[11:0])][7:0])|NONE|loads with a destination of x0 must still raise any exceptions and action any other side effects even though the load value is discarded.|loads a 8-bit value from memory, then sign-extends to 32-bit before storing in rd (rd is calculated using signed arithmetic), the effective address is obtained by adding register rs1 to the sign-extended 12-bit offset.|Load_and_Store_Instructions|
|
||||
|LH |[lh rd, imm(rs1)](#lh rd, imm(rs1))|x[rd] = sext(M[x[rs1] + sext(imm[11:0])][15:0])|NONE|loads with a destination of x0 must still raise any exceptions and action any other side effects even though the load value is discarded, also an exception is raised if the memory address isn't aligned (2-byte boundary).|loads a 16-bit value from memory, then sign-extends to 32-bit before storing in rd (rd is calculated using signed arithmetic), the effective address is obtained by adding register rs1 to the sign-extended 12-bit offset.|Load_and_Store_Instructions|
|
||||
|LW |[lw rd, imm(rs1)](#lw rd, imm(rs1))|x[rd] = sext(M[x[rs1] + sext(imm[11:0])][31:0])|NONE|loads with a destination of x0 must still raise any exceptions and action any other side effects even though the load value is discarded, also an exception is raised if the memory address isn't aligned (4-byte boundary).|loads a 32-bit value from memory, then storing in rd (rd is calculated using signed arithmetic). The effective address is obtained by adding register rs1 to the sign-extended 12-bit offset.|Load_and_Store_Instructions|
|
||||
|LBU |[lbu rd, imm(rs1)](#lbu rd, imm(rs1))|x[rd] = zext(M[x[rs1] + sext(imm[11:0])][7:0])|NONE|loads with a destination of x0 must still raise any exceptions and action any other side effects even though the load value is discarded.|loads a 8-bit value from memory, then zero-extends to 32-bit before storing in rd (rd is calculated using unsigned arithmetic), the effective address is obtained by adding register rs1 to the sign-extended 12-bit offset.|Load_and_Store_Instructions|
|
||||
|LHU |[lhu rd, imm(rs1)](#lhu rd, imm(rs1))|x[rd] = zext(M[x[rs1] + sext(imm[11:0])][15:0])|NONE|loads with a destination of x0 must still raise any exceptions and action any other side effects even though the load value is discarded, also an exception is raised if the memory address isn't aligned (2-byte boundary).|loads a 16-bit value from memory, then zero-extends to 32-bit before storing in rd (rd is calculated using unsigned arithmetic), the effective address is obtained by adding register rs1 to the sign-extended 12-bit offset.|Load_and_Store_Instructions|
|
||||
|SB |[sb rs2, imm(rs1)](#sb rs2, imm(rs1))|M[x[rs1] + sext(imm[11:0])][7:0] = x[rs2][7:0]|NONE|NONE |stores a 8-bit value from the low bits of register rs2 to memory, the effective address is obtained by adding register rs1 to the sign-extended 12-bit offset.|Load_and_Store_Instructions|
|
||||
|SH |[sh rs2, imm(rs1)](#sh rs2, imm(rs1))|M[x[rs1] + sext(imm[11:0])][15:0] = x[rs2][15:0]|NONE|an exception is raised if the memory address isn't aligned (2-byte boundary).|stores a 16-bit value from the low bits of register rs2 to memory, the effective address is obtained by adding register rs1 to the sign-extended 12-bit offset.|Load_and_Store_Instructions|
|
||||
|SW |[sw rs2, imm(rs1)](#sw rs2, imm(rs1))|M[x[rs1] + sext(imm[11:0])][31:0] = x[rs2][31:0]|NONE|an exception is raised if the memory address isn't aligned (4-byte boundary).|stores a 32-bit value from register rs2 to memory, the effective address is obtained by adding register rs1 to the sign-extended 12-bit offset.|Load_and_Store_Instructions|
|
||||
|FENCE |[fence pre, succ](#fence pre, succ)|No operation (nop)|NONE|NONE |order device I/O and memory accesses as viewed by other RISC-V harts and external devices or coprocessors. Any combination of device input (I), device output (O), memory reads (R), and memory writes (W) may be ordered with respect to any combination of the same. Informally, no other RISC-V hart or external device can observe any operation in the successor set following a FENCE before any operation in the predecessor set preceding the FENCE, as the core support 1 hart, the fence instruction has no effect so we can considerate it as a nop instruction.|Memory_Ordering|
|
||||
|ECALL |[ecall](#ecall)|RaiseException(EnvironmentCall)|NONE|Raise an Environment Call exception. |make a request to the supporting execution environment, which is usually an operating system. The ABI for the system will define how parameters for the environment request are passed, but usually these will be in defined locations in the integer register file.|Environment_Call_and_Breakpoints|
|
||||
|EBREAK |[ebreak](#ebreak)|x[8 + rd'] = sext(x[8 + rd'][7:0])|NONE|NONE |This instruction takes a single source/destination operand. It sign-extends the least-significant byte in the operand by copying the most-significant bit in the byte (i.e., bit 7) to all of the more-significant bits. It also requires Bit-Manipulation (Zbb) extension support. |Environment_Call_and_Breakpoints|
|
||||
|
||||
### RV32M Multiplication and Division Instructions
|
||||
|
||||
|Name|Format|Pseudocode|Invalid_values|Exception_raised|Description|Op Name|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|MUL |[mul rd, rs1, rs2](#mul rd, rs1, rs2)|x[rd] = x[rs1] * x[rs2]|NONE|NONE |performs a 32-bit × 32-bit multiplication and places the lower 32 bits in the destination register (Both rs1 and rs2 treated as signed numbers).|Multiplication Operations|
|
||||
|MULH |[mulh rd, rs1, rs2](#mulh rd, rs1, rs2)|x[rd] = (x[rs1] s*s x[rs2]) >>s 32|NONE|NONE |performs a 32-bit × 32-bit multiplication and places the upper 32 bits in the destination register of the 64-bit product (Both rs1 and rs2 treated as signed numbers).|Multiplication Operations|
|
||||
|MULHU |[mulhu rd, rs1, rs2](#mulhu rd, rs1, rs2)|x[rd] = (x[rs1] u*u x[rs2]) >>u 32|NONE|NONE |performs a 32-bit × 32-bit multiplication and places the upper 32 bits in the destination register of the 64-bit product (Both rs1 and rs2 treated as unsigned numbers).|Multiplication Operations|
|
||||
|MULHSU |[mulhsu rd, rs1, rs2](#mulhsu rd, rs1, rs2)|x[rd] = (x[rs1] s*u x[rs2]) >>s 32|NONE|NONE |performs a 32-bit × 32-bit multiplication and places the upper 32 bits in the destination register of the 64-bit product (rs1 treated as signed number, rs2 treated as unsigned number).|Multiplication Operations|
|
||||
|DIV |[div rd, rs1, rs2](#div rd, rs1, rs2)|x[rd] = x[rs1] /s x[rs2]|NONE|NONE |perform signed integer division of 32 bits by 32 bits (rounding towards zero).|Division Operations|
|
||||
|DIVU |[divu rd, rs1, rs2](#divu rd, rs1, rs2)|x[rd] = x[rs1] /u x[rs2]|NONE|NONE |perform unsigned integer division of 32 bits by 32 bits (rounding towards zero).|Division Operations|
|
||||
|REM |[rem rd, rs1, rs2](#rem rd, rs1, rs2)|x[rd] = x[rs1] %s x[rs2]|NONE|NONE |provide the remainder of the corresponding division operation DIV (the sign of rd equals the sign of rs1).|Division Operations|
|
||||
|REMU |[rem rd, rs1, rs2](#rem rd, rs1, rs2)|x[rd] = x[rs1] %u x[rs2]|NONE|NONE |provide the remainder of the corresponding division operation DIVU.|Division Operations|
|
||||
|
||||
### RV32C Compressed Instructions
|
||||
|
||||
|Name|Format|Pseudocode|Invalid_values|Exception_raised|Description|Op Name|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|C.LI |[c.li rd, imm[5:0]](#c.li rd, imm[5:0])|x[rd] = sext(imm[5:0])|rd = x0|NONE |loads the sign-extended 6-bit immediate, imm, into register rd.|Integer Computational Instructions|
|
||||
|C.LUI |[c.lui rd, nzimm[17:12]](#c.lui rd, nzimm[17:12])|x[rd] = sext(nzimm[17:12] << 12)|rd = x0 & rd = x2 & nzimm = 0|NONE |loads the non-zero 6-bit immediate field into bits 17–12 of the destination register, clears the bottom 12 bits, and sign-extends bit 17 into all higher bits of the destination.|Integer Computational Instructions|
|
||||
|C.ADDI |[c.addi rd, nzimm[5:0]](#c.addi rd, nzimm[5:0])|x[rd] = x[rd] + sext(nzimm[5:0])|rd = x0 & nzimm = 0|NONE |adds the non-zero sign-extended 6-bit immediate to the value in register rd then writes the result to rd.|Integer Computational Instructions|
|
||||
|C.ADDI16SP |[c.addi16sp nzimm[9:4]](#c.addi16sp nzimm[9:4])|x[2] = x[2] + sext(nzimm[9:4])|rd != x2 & nzimm = 0|NONE |adds the non-zero sign-extended 6-bit immediate to the value in the stack pointer (sp=x2), where the immediate is scaled to represent multiples of 16 in the range (-512,496). C.ADDI16SP is used to adjust the stack pointer in procedure prologues and epilogues. C.ADDI16SP shares the opcode with C.LUI, but has a destination field of x2.|Integer Computational Instructions|
|
||||
|C.ADDI4SPN |[c.addi4spn rd', nzimm[9:2]](#c.addi4spn rd', nzimm[9:2])|x[8 + rd'] = x[2] + zext(nzimm[9:2])|nzimm = 0|NONE |adds a zero-extended non-zero immediate, scaled by 4, to the stack pointer, x2, and writes the result to rd'. This instruction is used to generate pointers to stack-allocated variables.|Integer Computational Instructions|
|
||||
|C.SLLI |[c.slli rd, uimm[5:0]](#c.slli rd, uimm[5:0])|x[rd] = x[rd] << uimm[5:0]|rd = x0 & uimm[5] = 0|NONE |performs a logical left shift (zeros are shifted into the lower bits).|Integer Computational Instructions|
|
||||
|C.SRLI |[c.srli rd', uimm[5:0]](#c.srli rd', uimm[5:0])|x[8 + rd'] = x[8 + rd'] >> uimm[5:0]|uimm[5] = 0|NONE |performs a logical right shift (zeros are shifted into the upper bits).|Integer Computational Instructions|
|
||||
|C.SRAI |[c.srai rd', uimm[5:0]](#c.srai rd', uimm[5:0])|x[8 + rd'] = x[8 + rd'] >>s uimm[5:0]|uimm[5] = 0|NONE |performs an arithmetic right shift (sign bits are shifted into the upper bits).|Integer Computational Instructions|
|
||||
|C.ANDI |[c.andi rd', imm[5:0]](#c.andi rd', imm[5:0])|x[8 + rd'] = x[8 + rd'] & sext(imm[5:0])|NONE|NONE |computes the bitwise AND of the value in register rd', and the sign-extended 6-bit immediate, then writes the result to rd'.|Integer Computational Instructions|
|
||||
|C.ADD |[c.add rd, rs2](#c.add rd, rs2)|x[rd] = x[rd] + x[rs2]|rd = x0 & rs2 = x0|NONE |adds the values in registers rd and rs2 and writes the result to register rd.|Integer Computational Instructions|
|
||||
|C.MV |[c.mv rd, rs2](#c.mv rd, rs2)|x[rd] = x[rs2]|rd = x0 & rs2 = x0|NONE |copies the value in register rs2 into register rd.|Integer Computational Instructions|
|
||||
|C.AND |[c.and rd', rs2'](#c.and rd', rs2')|x[8 + rd'] = x[8 + rd'] & x[8 + rs2']|NONE|NONE |computes the bitwise AND of of the value in register rd', and register rs2', then writes the result to rd'.|Integer Computational Instructions|
|
||||
|C.OR |[c.or rd', rs2'](#c.or rd', rs2')|x[8 + rd'] = x[8 + rd'] \| x[8 + rs2']|NONE|NONE |computes the bitwise OR of of the value in register rd', and register rs2', then writes the result to rd'.|Integer Computational Instructions|
|
||||
|C.XOR |[c.and rd', rs2'](#c.and rd', rs2')|x[8 + rd'] = x[8 + rd'] ^ x[8 + rs2']|NONE|NONE |computes the bitwise XOR of of the value in register rd', and register rs2', then writes the result to rd'.|Integer Computational Instructions|
|
||||
|C.SUB |[c.sub rd', rs2'](#c.sub rd', rs2')|x[8 + rd'] = x[8 + rd'] - x[8 + rs2']|NONE|NONE |subtracts the value in registers rs2' from value in rd' and writes the result to register rd'.|Integer Computational Instructions|
|
||||
|C.EBREAK |[c.ebreak](#c.ebreak)|RaiseException(Breakpoint)|NONE|Raise a Breakpoint exception. |cause control to be transferred back to the debugging environment.|Integer Computational Instructions|
|
||||
|C.J |[c.j imm[11:1]](#c.j imm[11:1])|pc += sext(imm[11:1])|NONE|jumps to an unaligned address (4-byte or 2-byte boundary) will usually raise an exception.|performs an unconditional control transfer. The offset is sign-extended and added to the pc to form the jump target address.|Control Transfer Instructions|
|
||||
|C.JAL |[c.jal imm[11:1]](#c.jal imm[11:1])|x[1] = pc+2; pc += sext(imm[11:1])|NONE|jumps to an unaligned address (4-byte or 2-byte boundary) will usually raise an exception.|performs the same operation as C.J, but additionally writes the address of the instruction following the jump (pc+2) to the link register, x1.|Control Transfer Instructions|
|
||||
|C.JR |[c.jr rs1](#c.jr rs1)|pc = x[rs1]|rs1 = x0|jumps to an unaligned address (4-byte or 2-byte boundary) will usually raise an exception.|performs an unconditional control transfer to the address in register rs1.|Control Transfer Instructions|
|
||||
|C.JALR |[c.jalr rs1](#c.jalr rs1)|t = pc+2; pc = x[rs1]; x[1] = t|rs1 = x0|jumps to an unaligned address (4-byte or 2-byte boundary) will usually raise an exception.|performs the same operation as C.JR, but additionally writes the address of the instruction following the jump (pc+2) to the link register, x1.|Control Transfer Instructions|
|
||||
|C.BEQZ |[c.beqz rs1', imm[8:1]](#c.beqz rs1', imm[8:1])|if (x[8+rs1'] == 0) pc += sext(imm[8:1])|NONE|no instruction fetch misaligned exception is generated for a conditional branch that is not taken. An Instruction address misaligned exception is raised if the target address is not aligned on 4-byte or 2-byte boundary, because the core supports compressed instructions.|performs conditional control transfers. The offset is sign-extended and added to the pc to form the branch target address. C.BEQZ takes the branch if the value in register rs1' is zero.|Control Transfer Instructions|
|
||||
|C.BNEZ |[c.bnez rs1', imm[8:1]](#c.bnez rs1', imm[8:1])|if (x[8+rs1'] != 0) pc += sext(imm[8:1])|NONE|no instruction fetch misaligned exception is generated for a conditional branch that is not taken. An Instruction address misaligned exception is raised if the target address is not aligned on 4-byte or 2-byte boundary, because the core supports compressed instructions.|performs conditional control transfers. The offset is sign-extended and added to the pc to form the branch target address. C.BEQZ takes the branch if the value in register rs1' isn't zero.|Control Transfer Instructions|
|
||||
|C.LWSP |[c.lwsp rd, uimm(x2)](#c.lwsp rd, uimm(x2))|x[rd] = M[x[2] + zext(uimm[7:2])][31:0]|rd = x0|loads with a destination of x0 must still raise any exceptions, also an exception if the memory address isn't aligned (4-byte boundary).|loads a 32-bit value from memory into register rd. It computes an effective address by adding the zero-extended offset, scaled by 4, to the stack pointer, x2.|Load and Store Instructions|
|
||||
|C.SWSP |[c.swsp rd, uimm(x2)](#c.swsp rd, uimm(x2))|M[x[2] + zext(uimm[7:2])][31:0] = x[rs2]|NONE|an exception raised if the memory address isn't aligned (4-byte boundary).|stores a 32-bit value in register rs2 to memory. It computes an effective address by adding the zero-extended offset, scaled by 4, to the stack pointer, x2.|Load and Store Instructions|
|
||||
|C.LW |[c.lw rd', uimm(rs1')](#c.lw rd', uimm(rs1'))|x[8+rd'] = M[x[8+rs1'] + zext(uimm[6:2])][31:0])|NONE|an exception raised if the memory address isn't aligned (4-byte boundary).|loads a 32-bit value from memory into register rd'. It computes an effective address by adding the zero-extended offset, scaled by 4, to the base address in register rs1'.|Load and Store Instructions|
|
||||
|C.SW |[c.sw rs2', uimm(rs1')](#c.sw rs2', uimm(rs1'))|M[x[8+rs1'] + zext(uimm[6:2])][31:0] = x[8+rs2']|NONE|an exception raised if the memory address isn't aligned (4-byte boundary).|stores a 32-bit value from memory into register rd'. It computes an effective address by adding the zero-extended offset, scaled by 4, to the base address in register rs1'.|Load and Store Instructions|
|
||||
|
||||
### RV32Zicsr Control and Status Register Instructions
|
||||
|
||||
|Name|Format|Pseudocode|Invalid_values|Exception_raised|Description|Op Name|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|CSRRW |[csrrw rd, csr, rs1](#csrrw rd, csr, rs1)|t = CSRs[csr]; CSRs[csr] = x[rs1]; x[rd] = t|NONE|Attempts to access a non-existent CSR raise an illegal instruction exception. Attempts to access a CSR without appropriate privilege level or to write a read-only register also raise illegal instruction exceptions. |Reads the old value of the CSR, zero-extends the value to 32 bits, then writes it to integer register rd. The initial value in rs1 is written to the CSR. If rd=x0, then the instruction shall not read the CSR and shall not cause any of the side-effects that might occur on a CSR read. |Control and Status Register Operations|
|
||||
|CSRRS |[csrrs rd, csr, rs1](#csrrs rd, csr, rs1)|t = CSRs[csr]; CSRs[csr] = t \| x[rs1]; x[rd] = t|NONE|Attempts to access a non-existent CSR raise an illegal instruction exception. Attempts to access a CSR without appropriate privilege level or to write a read-only register also raise illegal instruction exceptions. |Reads the value of the CSR, zero-extends the value to 32 bits, and writes it to integer register rd. The initial value in integer register rs1 is treated as a bit mask that specifies bit positions to be set in the CSR. Any bit that is high in rs1 will cause the corresponding bit to be set in the CSR, if that CSR bit is writable. Other bits in the CSR are unaffected (though CSRs might have side effects when written). If rs1=x0, then the instruction will not write to the CSR at all, and so shall not cause any of the side effects that might otherwise occur on a CSR write, such as raising illegal instruction exceptions on accesses to read-only CSRs. |Control and Status Register Operations|
|
||||
|CSRRC |[csrrc rd, csr, rs1](#csrrc rd, csr, rs1)|t = CSRs[csr]; CSRs[csr] = t & ∼x[rs1]; x[rd] = t|NONE|Attempts to access a non-existent CSR raise an illegal instruction exception. Attempts to access a CSR without appropriate privilege level or to write a read-only register also raise illegal instruction exceptions. |Reads the value of the CSR, zero-extends the value to 32 bits, and writes it to integer register rd. The initial value in integer register rs1 is treated as a bit mask that specifies bit positions to be cleared in the CSR. Any bit that is high in rs1 will cause the corresponding bit to be set in the CSR, if that CSR bit is writable. Other bits in the CSR are unaffected (though CSRs might have side effects when written). If rs1=x0, then the instruction will not write to the CSR at all, and so shall not cause any of the side effects that might otherwise occur on a CSR write, such as raising illegal instruction exceptions on accesses to read-only CSRs. |Control and Status Register Operations|
|
||||
|CSRRWI |[csrrwi rd, csr, uimm[4:0]](#csrrwi rd, csr, uimm[4:0])|x[rd] = CSRs[csr]; CSRs[csr] = zext(uimm[4:0])|NONE|Attempts to access a non-existent CSR raise an illegal instruction exception. Attempts to access a CSR without appropriate privilege level or to write a read-only register also raise illegal instruction exceptions. |Reads the old value of the CSR, zero-extends the value to 32 bits, then writes it to integer register rd. The zero-extends immediate is written to the CSR. If rd=x0, then the instruction shall not read the CSR and shall not cause any of the side-effects that might occur on a CSR read. |Control and Status Register Operations|
|
||||
|CSRRSI |[csrrsi rd, csr, uimm[4:0]](#csrrsi rd, csr, uimm[4:0])|t = CSRs[csr]; CSRs[csr] = t \| zext(uimm[4:0]); x[rd] = t|NONE|Attempts to access a non-existent CSR raise an illegal instruction exception. Attempts to access a CSR without appropriate privilege level or to write a read-only register also raise illegal instruction exceptions. |Reads the value of the CSR, zero-extends the value to 32 bits, and writes it to integer register rd. The zero-extends immediate value is treated as a bit mask that specifies bit positions to be set in the CSR. Any bit that is high in zero-extends immediate will cause the corresponding bit to be set in the CSR, if that CSR bit is writable. Other bits in the CSR are unaffected (though CSRs might have side effects when written). If the uimm[4:0] field is zero, then these instructions will not write to the CSR, and shall not cause any of the side effects that might otherwise occur on a CSR write. |Control and Status Register Operations|
|
||||
|CSRRCI |[csrrci rd, csr, uimm[4:0]](#csrrci rd, csr, uimm[4:0])|t = CSRs[csr]; CSRs[csr] = t & ∼zext(uimm[4:0]); x[rd] = t|NONE|Attempts to access a non-existent CSR raise an illegal instruction exception. Attempts to access a CSR without appropriate privilege level or to write a read-only register also raise illegal instruction exceptions. |Reads the value of the CSR, zero-extends the value to 32 bits, and writes it to integer register rd. The zero-extends immediate value is treated as a bit mask that specifies bit positions to be cleared in the CSR. Any bit that is high in zero-extends immediate will cause the corresponding bit to be set in the CSR, if that CSR bit is writable. Other bits in the CSR are unaffected (though CSRs might have side effects when written). If the uimm[4:0] field is zero, then these instructions will not write to the CSR, and shall not cause any of the side effects that might otherwise occur on a CSR write. |Control and Status Register Operations|
|
||||
|
||||
### RVZifencei Instruction Fetch Fence
|
||||
|
||||
|Name|Format|Pseudocode|Invalid_values|Exception_raised|Description|Op Name|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|FENCE.I |[fence.i](#fence.i)|Fence(Store, Fetch)|NONE|NONE |The FENCE.I instruction is used to synchronize the instruction and data streams. RISC-V does not guarantee that stores to instruction memory will be made visible to instruction fetches on the same RISC-V hart until a FENCE.I instruction is executed. A FENCE.I instruction only ensures that a subsequent instruction fetch on a RISC-V hart will see any previous data stores already visible to the same RISC-V hart. |Fetch Fence Operations|
|
||||
|
||||
### RVZba Address generation instructions
|
||||
|
||||
|Name|Format|Pseudocode|Invalid_values|Exception_raised|Description|Op Name|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|ADD.UW |[add.uw rd, rs1, rs2](#add.uw rd, rs1, rs2)|X(rd) = rs2 + EXTZ(X(rs1)[31..0])|NONE|NONE |This instruction performs an XLEN-wide addition between rs2 and the zero-extended least-significant word of rs1. |Address generation instructions|
|
||||
|SH1ADD |[sh1add rd, rs1, rs2](#sh1add rd, rs1, rs2)|X(rd) = X(rs2) + (X(rs1) << 1)|NONE|NONE |This instruction shifts rs1 to the left by 1 bit and adds it to rs2. |Address generation instructions|
|
||||
|SH1ADD.UW |[sh1add.uw rd, rs1, rs2](#sh1add.uw rd, rs1, rs2)|X(rd) = rs2 + (EXTZ(X(rs1)[31..0]) << 1)|NONE|NONE |This instruction performs an XLEN-wide addition of two addends. The first addend is rs2. The second addend is the unsigned value formed by extracting the least-significant word of rs1 and shifting it left by 1 place. |Address generation instructions|
|
||||
|SH2ADD |[sh2add rd, rs1, rs2](#sh2add rd, rs1, rs2)|X(rd) = X(rs2) + (X(rs1) << 2)|NONE|NONE |This instruction shifts rs1 to the left by 2 bit and adds it to rs2. |Address generation instructions|
|
||||
|SH2ADD.UW |[sh2add.uw rd, rs1, rs2](#sh2add.uw rd, rs1, rs2)|X(rd) = rs2 + (EXTZ(X(rs1)[31..0]) << 2)|NONE|NONE |This instruction performs an XLEN-wide addition of two addends. The first addend is rs2. The second addend is the unsigned value formed by extracting the least-significant word of rs1 and shifting it left by 2 places. |Address generation instructions|
|
||||
|SH3ADD |[sh3add rd, rs1, rs2](#sh3add rd, rs1, rs2)|X(rd) = X(rs2) + (X(rs1) << 3)|NONE|NONE |This instruction shifts rs1 to the left by 3 bit and adds it to rs2. |Address generation instructions|
|
||||
|SH3ADD.UW |[sh3add.uw rd, rs1, rs2](#sh3add.uw rd, rs1, rs2)|X(rd) = rs2 + (EXTZ(X(rs1)[31..0]) << 3)|NONE|NONE |This instruction performs an XLEN-wide addition of two addends. The first addend is rs2. The second addend is the unsigned value formed by extracting the least-significant word of rs1 and shifting it left by 3 places. |Address generation instructions|
|
||||
|SLLI.UW |[slli.uw rd, rs1, imm](#slli.uw rd, rs1, imm)|X(rd) = (EXTZ(X(rs)[31..0]) << imm)|NONE|NONE |This instruction takes the least-significant word of rs1, zero-extends it, and shifts it left by the immediate. |Address generation instructions|
|
||||
|
||||
### RVZbb Basic bit-manipulation
|
||||
|
||||
|Name|Format|Pseudocode|Invalid_values|Exception_raised|Description|Op Name|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|ANDN |[andn rd, rs1, rs2](#andn rd, rs1, rs2)|X(rd) = X(rs1) & ~X(rs2)|NONE|NONE |Performs bitwise AND operation between rs1 and bitwise inversion of rs2.|Logical_with_negate|
|
||||
|ORN |[orn rd, rs1, rs2](#orn rd, rs1, rs2)|X(rd) = X(rs1) \| ~X(rs2)|NONE|NONE |Performs bitwise OR operation between rs1 and bitwise inversion of rs2.|Logical_with_negate|
|
||||
|XNOR |[xnor rd, rs1, rs2](#xnor rd, rs1, rs2)|X(rd) = ~(X(rs1) ^ X(rs2))|NONE|NONE |Performs bitwise XOR operation between rs1 and rs2, then complements the result.|Logical_with_negate|
|
||||
|CLZ |[clz rd, rs](#clz rd, rs)|if [x[i]] == 1 then return(i) else return -1|NONE|NONE |Counts leading zero bits in rs.|Count_leading_trailing_zero_bits|
|
||||
|CTZ |[ctz rd, rs](#ctz rd, rs)|if [x[i]] == 1 then return(i) else return xlen;|NONE|NONE |Counts trailing zero bits in rs.|Count_leading_trailing_zero_bits|
|
||||
|CLZW |[clzw rd, rs](#clzw rd, rs)|if [x[i]] == 1 then return(i) else return -1|NONE|NONE |Counts leading zero bits in the least-significant word of rs.|Count_leading_trailing_zero_bits|
|
||||
|CTZW |[ctzw rd, rs](#ctzw rd, rs)|if [x[i]] == 1 then return(i) else return 32;|NONE|NONE |Counts trailing zero bits in the least-significant word of rs.|Count_leading_trailing_zero_bits|
|
||||
|CPOP |[cpop rd, rs](#cpop rd, rs)|if rs[i] == 1 then bitcount = bitcount + 1 else ()|NONE|NONE |Counts set bits in rs.|Count_population|
|
||||
|CPOPW |[cpopw rd, rs](#cpopw rd, rs)|if rs[i] == 0b1 then bitcount = bitcount + 1 else ()|NONE|NONE |Counts set bits in the least-significant word of rs.|Count_population|
|
||||
|MAX |[max rd, rs1, rs2](#max rd, rs1, rs2)|if rs1_val <_s rs2_val then rs2_val else rs1_val|NONE|NONE |Returns the larger of two signed integers.|Integer_minimum_maximum|
|
||||
|MAXU |[maxu rd, rs1, rs2](#maxu rd, rs1, rs2)|if rs1_val <_u rs2_val then rs2_val else rs1_val|NONE|NONE |Returns the larger of two unsigned integers.|Integer_minimum_maximum|
|
||||
|MIN |[min rd, rs1, rs2](#min rd, rs1, rs2)|if rs1_val <_s rs2_val then rs1_val else rs2_val|NONE|NONE |Returns the smaller of two signed integers.|Integer_minimum_maximum|
|
||||
|MINU |[minu rd, rs1, rs2](#minu rd, rs1, rs2)|if rs1_val <_u rs2_val then rs1_val else rs2_val|NONE|NONE |Returns the smaller of two unsigned integers.|Integer_minimum_maximum|
|
||||
|SEXT.B |[sext.b rd, rs](#sext.b rd, rs)|X(rd) = EXTS(X(rs)[7..0])|NONE|NONE |Sign-extends the least-significant byte in the source to XLEN.|Sign_and_zero_extension|
|
||||
|SEXT.H |[sext.h rd, rs](#sext.h rd, rs)|X(rd) = EXTS(X(rs)[15..0])|NONE|NONE |Sign-extends the least-significant halfword in rs to XLEN.|Sign_and_zero_extension|
|
||||
|ZEXT.H |[zext.h rd, rs](#zext.h rd, rs)|X(rd) = EXTZ(X(rs)[15..0])|NONE|NONE |Zero-extends the least-significant halfword of the source to XLEN.|Sign_and_zero_extension|
|
||||
|ROL |[rol rd, rs1, rs2](#rol rd, rs1, rs2)|(X(rs1) << log2(XLEN)) \| (X(rs1) >> (xlen - log2(XLEN)))|NONE|NONE |Performs a rotate left of rs1 by the amount in least-significant log2(XLEN) bits of rs2.|Bitwise_rotation|
|
||||
|ROR |[ror rd, rs1, rs2](#ror rd, rs1, rs2)|(X(rs1) >> log2(XLEN)) \| (X(rs1) << (xlen - log2(XLEN)))|NONE|NONE |Performs a rotate right of rs1 by the amount in least-significant log2(XLEN) bits of rs2.|Bitwise_rotation|
|
||||
|RORI |[rori rd, rs1, shamt](#rori rd, rs1, shamt)|(X(rs1) >> log2(XLEN)) \| (X(rs1) << (xlen - log2(XLEN)))|NONE|NONE |Performs a rotate right of rs1 by the amount in least-significant log2(XLEN) bits of shamt.|Bitwise_rotation|
|
||||
|ROLW |[rolw rd, rs1, rs2](#rolw rd, rs1, rs2)|EXTS((rs1 << X(rs2)[4..0]) \| (rs1 >> (32 - X(rs2)[4..0])))|NONE|NONE |Performs a rotate left on the least-significant word of rs1 by the amount in least-significant 5 bits of rs2.|Bitwise_rotation|
|
||||
|RORIW |[roriw rd, rs1, shamt](#roriw rd, rs1, shamt)|(rs1_data >> shamt[4..0]) \| (rs1_data << (32 - shamt[4..0]))|NONE|NONE |Performs a rotate right on the least-significant word of rs1 by the amount in least-significant log2(XLEN) bits of shamt.|Bitwise_rotation|
|
||||
|RORW |[rorw rd, rs1, rs2](#rorw rd, rs1, rs2)|(rs1 >> X(rs2)[4..0]) \| (rs1 << (32 - X(rs2)[4..0]))|NONE|NONE |Performs a rotate right on the least-significant word of rs1 by the amount in least-significant 5 bits of rs2.|Bitwise_rotation|
|
||||
|ORC.b |[orc.b rd, rs](#orc.b rd, rs)|if { input[(i + 7)..i] == 0 then 0b00000000 else 0b11111111|NONE|NONE |Sets the bits of each byte in rd to all zeros if no bit within the respective byte of rs is set, or to all ones if any bit within the respective byte of rs is set.|OR_Combine|
|
||||
|REV8 |[rev8 rd, rs](#rev8 rd, rs)|output[i..(i + 7)] = input[(j - 7)..j]|NONE|NONE |Reverses the order of the bytes in rs.|Byte_reverse|
|
||||
|
||||
### RVZbc Carry-less multiplication
|
||||
|
||||
|Name|Format|Pseudocode|Invalid_values|Exception_raised|Description|Op Name|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|CLMUL |[clmul rd, rs1, rs2](#clmul rd, rs1, rs2)|foreach (i from 1 to xlen by 1) { output = if ((rs2 >> i) & 1) then output ^ (rs1 << i); else output; } |NONE|NONE |clmul produces the lower half of the 2.XLEN carry-less product. |Carry-less multiplication Operations|
|
||||
|CLMULH |[clmulh rd, rs1, rs2](#clmulh rd, rs1, rs2)|foreach (i from 1 to xlen by 1) { output = if ((rs2_val >> i) & 1) then output ^ (rs1_val >> (xlen - i)) else output } |NONE|NONE |clmulh produces the upper half of the 2.XLEN carry-less product. |Carry-less multiplication Operations|
|
||||
|CLMULR |[clmulr rd, rs1, rs2](#clmulr rd, rs1, rs2)|foreach (i from 0 to (xlen - 1) by 1) { output = if ((rs2_val >> i) & 1) then output ^ (rs1_val >> (xlen - i - 1)) else output } |NONE|NONE |clmulr produces bits 2.XLEN-2:XLEN-1 of the 2.XLEN carry-less product. |Carry-less multiplication Operations|
|
||||
|
||||
### RVZbs Single bit Instructions
|
||||
|
||||
|Name|Format|Pseudocode|Invalid_values|Exception_raised|Description|Op Name|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|BCLR |[bclr rd, rs1, rs2](#bclr rd, rs1, rs2)|X(rd) = X(rs1) & ~(1 << (X(rs2) & (XLEN - 1)))|NONE|NONE |This instruction returns rs1 with a single bit cleared at the index specified in rs2. The index is read from the lower log2(XLEN) bits of rs2. |Single_bit_Operations|
|
||||
|BCLRI |[bclri rd, rs1, shamt](#bclri rd, rs1, shamt)|X(rd) = X(rs1) & ~(1 << (shamt & (XLEN - 1)))|NONE|NONE |This instruction returns rs1 with a single bit cleared at the index specified in shamt. The index is read from the lower log2(XLEN) bits of shamt. For RV32, the encodings corresponding to shamt[5]=1 are reserved. |Single_bit_Operations|
|
||||
|BEXT |[bext rd, rs1, rs2](#bext rd, rs1, rs2)|X(rd) = (X(rs1) >> (X(rs2) & (XLEN - 1))) & 1|NONE|NONE |This instruction returns a single bit extracted from rs1 at the index specified in rs2. The index is read from the lower log2(XLEN) bits of rs2. |Single_bit_Operations|
|
||||
|BEXTI |[bexti rd, rs1, shamt](#bexti rd, rs1, shamt)|X(rd) = (X(rs1) >> (shamt & (XLEN - 1))) & 1|NONE|NONE |This instruction returns a single bit extracted from rs1 at the index specified in rs2. The index is read from the lower log2(XLEN) bits of shamt. For RV32, the encodings corresponding to shamt[5]=1 are reserved. |Single_bit_Operations|
|
||||
|BINV |[binv rd, rs1, rs2](#binv rd, rs1, rs2)|X(rd) = X(rs1) ^ (1 << (X(rs2) & (XLEN - 1)))|NONE|NONE |This instruction returns rs1 with a single bit inverted at the index specified in rs2. The index is read from the lower log2(XLEN) bits of rs2. |Single_bit_Operations|
|
||||
|BINVI |[binvi rd, rs1, shamt](#binvi rd, rs1, shamt)|X(rd) = X(rs1) ^ (1 << (shamt & (XLEN - 1)))|NONE|NONE |This instruction returns rs1 with a single bit inverted at the index specified in shamt. The index is read from the lower log2(XLEN) bits of shamt. For RV32, the encodings corresponding to shamt[5]=1 are reserved. |Single_bit_Operations|
|
||||
|BSET |[bset rd, rs1, rs2](#bset rd, rs1, rs2)|X(rd) = X(rs1) \| (1 << (X(rs2) & (XLEN - 1)))|NONE|NONE |This instruction returns rs1 with a single bit set at the index specified in rs2. The index is read from the lower log2(XLEN) bits of rs2. |Single_bit_Operations|
|
||||
|BSETI |[bseti rd, rs1, shamt](#bseti rd, rs1, shamt)|X(rd) = X(rs1) \| (1 << (shamt & (XLEN - 1)))|NONE|NONE |This instruction returns rs1 with a single bit set at the index specified in shamt. The index is read from the lower log2(XLEN) bits of shamt. For RV32, the encodings corresponding to shamt[5]=1 are reserved. |Single_bit_Operations|
|
||||
|
||||
### RV32Zcb Code Size Reduction Instructions
|
||||
|
||||
|Name|Format|Pseudocode|Invalid_values|Exception_raised|Description|Op Name|
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
|C.ZEXT.B |[c.zext.b rd'](#c.zext.b rd')|x[8 + rd'] = zext(x[8 + rd'][7:0])|NONE|NONE |This instruction takes a single source/destination operand. It zero-extends the least-significant byte of the operand by inserting zeros into all of the bits more significant than 7. |Code Size Reduction Operations|
|
||||
|C.SEXT.B |[c.sext.b rd'](#c.sext.b rd')|x[8 + rd'] = sext(x[8 + rd'][7:0])|NONE|NONE |This instruction takes a single source/destination operand. It sign-extends the least-significant byte in the operand by copying the most-significant bit in the byte (i.e., bit 7) to all of the more-significant bits. It also requires Bit-Manipulation (Zbb) extension support. |Code Size Reduction Operations|
|
||||
|C.ZEXT.H |[c.zext.h rd'](#c.zext.h rd')|x[8 + rd'] = zext(x[8 + rd'][15:0])|NONE|NONE |This instruction takes a single source/destination operand. It zero-extends the least-significant halfword of the operand by inserting zeros into all of the bits more significant than 15. It also requires Bit-Manipulation (Zbb) extension support. |Code Size Reduction Operations|
|
||||
|C.SEXT.H |[c.sext.h rd'](#c.sext.h rd')|x[8 + rd'] = sext(x[8 + rd'][15:0])|NONE|NONE |This instruction takes a single source/destination operand. It sign-extends the least-significant halfword in the operand by copying the most-significant bit in the halfword (i.e., bit 15) to all of the more-significant bits. It also requires Bit-Manipulation (Zbb) extension support. |Code Size Reduction Operations|
|
||||
|C.NOT |[c.not rd'](#c.not rd')|x[8 + rd'] = x[8 + rd'] ^ -1|NONE|NONE |This instruction takes the one’s complement of rd'/rs1' and writes the result to the same register. |Code Size Reduction Operations|
|
||||
|C.MUL |[c.mul rd', rs2'](#c.mul rd', rs2')|x[8 + rd'] = (x[8 + rd'] * x[8 + rs2'])[31:0]|NONE|NONE |performs a 32-bit × 32-bit multiplication and places the lower 32 bits in the destination register (Both rd' and rs2' treated as signed numbers). It also requires M extension support. |Code Size Reduction Operations|
|
||||
|C.LHU |[c.lhu rd', uimm(rs1')](#c.lhu rd', uimm(rs1'))|x[8+rd'] = zext(M[x[8+rs1'] + zext(uimm[1])][15:0])|NONE|an exception raised if the memory address isn't aligned (2-byte boundary).|This instruction loads a halfword from the memory address formed by adding rs1' to the zero extended immediate uimm. The resulting halfword is zero extended and is written to rd'. |Code Size Reduction Operations|
|
||||
|C.LH |[c.lh rd', uimm(rs1')](#c.lh rd', uimm(rs1'))|x[8+rd'] = sext(M[x[8+rs1'] + zext(uimm[1])][15:0])|NONE|an exception raised if the memory address isn't aligned (2-byte boundary).|This instruction loads a halfword from the memory address formed by adding rs1' to the zero extended immediate uimm. The resulting halfword is sign extended and is written to rd'. |Code Size Reduction Operations|
|
||||
|C.LBU |[c.lbu rd', uimm(rs1')](#c.lbu rd', uimm(rs1'))|x[8+rd'] = zext(M[x[8+rs1'] + zext(uimm[1:0])][7:0])|NONE|NONE |This instruction loads a byte from the memory address formed by adding rs1' to the zero extended immediate uimm. The resulting byte is zero extended and is written to rd'. |Code Size Reduction Operations|
|
||||
|C.SH |[c.sh rs2', uimm(rs1')](#c.sh rs2', uimm(rs1'))|M[x[8+rs1'] + zext(uimm[1])][15:0] = x[8+rs2']|NONE|an exception raised if the memory address isn't aligned (2-byte boundary).|This instruction stores the least significant halfword of rs2' to the memory address formed by adding rs1' to the zero extended immediate uimm. |Code Size Reduction Operations|
|
||||
|C.SB |[c.sb rs2', uimm(rs1')](#c.sb rs2', uimm(rs1'))|M[x[8+rs1'] + zext(uimm[1:0])][7:0] = x[8+rs2']|NONE|NONE |This instruction stores the least significant byte of rs2' to the memory address formed by adding rs1' to the zero extended immediate uimm. |Code Size Reduction Operations|
|
|
@ -32,8 +32,7 @@ Instructions
|
|||
+---------------+-----------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Zicsr | RV32Zicsr Control and Status Register Instructions_ | All CSR instructions atomically read-modify-write a single CSR, whose CSR specifier is encoded in the 12-bit csr field of the instruction held in bits 31–20. The immediate forms use a 5-bit zero-extended immediate encoded in the rs1 field. |
|
||||
+---------------+-----------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Zifencei | RVZifencei Instruction Fetch Fence_ | FENCE.I instruction that provides explicit synchronization between writes to instruction memory and instruction fetches on the same hart. |
|
||||
| | | Currently, this instruction is the only standard mechanism to ensure that stores visible to a hart will also be visible to it instruction fetches. |
|
||||
| Zcb | RV32Zcb Code Size Reduction Instructions_ | Zcb belongs to the group of extensions called RISC-V Code Size Reduction Extension (Zc*). Zc* has become the superset of the Standard C extension adding more 16-bit instructions to the ISA. Zcb includes the 16-bit version of additional Integer (I), Multiply (M), and Bit-Manipulation (Zbb) Instructions. All the Zcb instructions require at least standard C extension support as a prerequisite, along with M and Zbb extensions for the 16-bit version of the respective instructions. |
|
||||
+---------------+-----------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Zba | RVZba Address generation instructions_ | The Zba instructions can be used to accelerate the generation of addresses that index into arrays of basic types (halfword, word, doubleword) using both unsigned word-sized and XLEN-sized indices: a shifted index is added to a base address. The shift and add instructions do a left shift of 1, 2, or 3 because these are commonly found in real-world code and because they can be implemented with a minimal amount of additional hardware beyond that of the simple adder. This avoids lengthening the critical path in implementations. While the shift and add instructions are limited to a maximum left shift of 3, the slli instruction (from the base ISA) can be used to perform similar shifts for indexing into arrays of wider elements. The slli.uw added in this extension can be used when the index is to be interpreted as an unsigned word. |
|
||||
+---------------+-----------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
|
@ -46,10 +45,10 @@ Instructions
|
|||
+---------------+-----------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Zbs | RVZbs Single bit Instructions_ | The single-bit instructions provide a mechanism to set, clear, invert, or extract a single bit in a register. The bit is specified by its index. |
|
||||
+---------------+-----------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Zcb | RV32Zcb Code Size Reduction Instructions_ | Zcb belongs to the group of extensions called RISC-V Code Size Reduction Extension (Zc*). Zc* has become the superset of the Standard C extension adding more 16-bit instructions to the ISA. Zcb includes the 16-bit version of additional Integer (I), Multiply (M), and Bit-Manipulation (Zbb) Instructions. All the Zcb instructions require at least standard C extension support as a prerequisite, along with M and Zbb extensions for the 16-bit version of the respective instructions. |
|
||||
+---------------+-----------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Zicntr | Zicntr_ | No info found yet for extension Zicntr |
|
||||
+---------------+-----------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Zbkb | RVZbkb Bitmanip instructions for Cryptography_ | The Zbkb extension is a part of the RISC-V Bit-Manipulation (bitmanip) extensions, specifically targeting cryptographic applications. It introduces a set of instructions designed to facilitate operations commonly used in cryptographic algorithms, such as interleaving, packing, and reordering of bits. |
|
||||
+---------------+-----------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
|
||||
RV32I Base Integer Instructions
|
||||
-------------------------------
|
||||
|
@ -243,15 +242,35 @@ RV32Zicsr Control and Status Register Instructions
|
|||
| CSRRCI | csrrci rd, csr, uimm[4:0] | t = CSRs[csr]; CSRs[csr] = t & ∼zext(uimm[4:0]); x[rd] = t | NONE | Attempts to access a non-existent CSR raise an illegal instruction exception. Attempts to access a CSR without appropriate privilege level or to write a read-only register also raise illegal instruction exceptions. | Reads the value of the CSR, zero-extends the value to 32 bits, and writes it to integer register rd. The zero-extends immediate value is treated as a bit mask that specifies bit positions to be cleared in the CSR. Any bit that is high in zero-extends immediate will cause the corresponding bit to be set in the CSR, if that CSR bit is writable. Other bits in the CSR are unaffected (though CSRs might have side effects when written). If the uimm[4:0] field is zero, then these instructions will not write to the CSR, and shall not cause any of the side effects that might otherwise occur on a CSR write. | Control and Status Register Operations |
|
||||
+--------+---------------------------+------------------------------------------------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------+
|
||||
|
||||
RVZifencei Instruction Fetch Fence
|
||||
----------------------------------
|
||||
RV32Zcb Code Size Reduction Instructions
|
||||
----------------------------------------
|
||||
|
||||
|
||||
+---------+----------+---------------------+------------------+--------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------+
|
||||
| Name | Format | Pseudocode | Invalid_values | Exception_raised | Description | Op Name |
|
||||
+=========+==========+=====================+==================+====================+==============================================================================================================================================================================================================================================================================================================================================================================================================================+========================+
|
||||
| FENCE.I | fence.i | Fence(Store, Fetch) | NONE | NONE | The FENCE.I instruction is used to synchronize the instruction and data streams. RISC-V does not guarantee that stores to instruction memory will be made visible to instruction fetches on the same RISC-V hart until a FENCE.I instruction is executed. A FENCE.I instruction only ensures that a subsequent instruction fetch on a RISC-V hart will see any previous data stores already visible to the same RISC-V hart. | Fetch Fence Operations |
|
||||
+---------+----------+---------------------+------------------+--------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------+
|
||||
+----------+-----------------------+------------------------------------------------------+------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+
|
||||
| Name | Format | Pseudocode | Invalid_values | Exception_raised | Description | Op Name |
|
||||
+==========+=======================+======================================================+==================+============================================================================+==============================================================================================================================================================================================================================================================================================+================================+
|
||||
| C.ZEXT.B | c.zext.b rd' | x[8 + rd'] = zext(x[8 + rd'][7:0]) | NONE | NONE | This instruction takes a single source/destination operand. It zero-extends the least-significant byte of the operand by inserting zeros into all of the bits more significant than 7. | Code Size Reduction Operations |
|
||||
+----------+-----------------------+------------------------------------------------------+------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+
|
||||
| C.SEXT.B | c.sext.b rd' | x[8 + rd'] = sext(x[8 + rd'][7:0]) | NONE | NONE | This instruction takes a single source/destination operand. It sign-extends the least-significant byte in the operand by copying the most-significant bit in the byte (i.e., bit 7) to all of the more-significant bits. It also requires Bit-Manipulation (Zbb) extension support. | Code Size Reduction Operations |
|
||||
+----------+-----------------------+------------------------------------------------------+------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+
|
||||
| C.ZEXT.H | c.zext.h rd' | x[8 + rd'] = zext(x[8 + rd'][15:0]) | NONE | NONE | This instruction takes a single source/destination operand. It zero-extends the least-significant halfword of the operand by inserting zeros into all of the bits more significant than 15. It also requires Bit-Manipulation (Zbb) extension support. | Code Size Reduction Operations |
|
||||
+----------+-----------------------+------------------------------------------------------+------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+
|
||||
| C.SEXT.H | c.sext.h rd' | x[8 + rd'] = sext(x[8 + rd'][15:0]) | NONE | NONE | This instruction takes a single source/destination operand. It sign-extends the least-significant halfword in the operand by copying the most-significant bit in the halfword (i.e., bit 15) to all of the more-significant bits. It also requires Bit-Manipulation (Zbb) extension support. | Code Size Reduction Operations |
|
||||
+----------+-----------------------+------------------------------------------------------+------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+
|
||||
| C.NOT | c.not rd' | x[8 + rd'] = x[8 + rd'] ^ -1 | NONE | NONE | This instruction takes the one’s complement of rd'/rs1' and writes the result to the same register. | Code Size Reduction Operations |
|
||||
+----------+-----------------------+------------------------------------------------------+------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+
|
||||
| C.MUL | c.mul rd', rs2' | x[8 + rd'] = (x[8 + rd'] * x[8 + rs2'])[31:0] | NONE | NONE | performs a 32-bit × 32-bit multiplication and places the lower 32 bits in the destination register (Both rd' and rs2' treated as signed numbers). It also requires M extension support. | Code Size Reduction Operations |
|
||||
+----------+-----------------------+------------------------------------------------------+------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+
|
||||
| C.LHU | c.lhu rd', uimm(rs1') | x[8+rd'] = zext(M[x[8+rs1'] + zext(uimm[1])][15:0]) | NONE | an exception raised if the memory address isn't aligned (2-byte boundary). | This instruction loads a halfword from the memory address formed by adding rs1' to the zero extended immediate uimm. The resulting halfword is zero extended and is written to rd'. | Code Size Reduction Operations |
|
||||
+----------+-----------------------+------------------------------------------------------+------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+
|
||||
| C.LH | c.lh rd', uimm(rs1') | x[8+rd'] = sext(M[x[8+rs1'] + zext(uimm[1])][15:0]) | NONE | an exception raised if the memory address isn't aligned (2-byte boundary). | This instruction loads a halfword from the memory address formed by adding rs1' to the zero extended immediate uimm. The resulting halfword is sign extended and is written to rd'. | Code Size Reduction Operations |
|
||||
+----------+-----------------------+------------------------------------------------------+------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+
|
||||
| C.LBU | c.lbu rd', uimm(rs1') | x[8+rd'] = zext(M[x[8+rs1'] + zext(uimm[1:0])][7:0]) | NONE | NONE | This instruction loads a byte from the memory address formed by adding rs1' to the zero extended immediate uimm. The resulting byte is zero extended and is written to rd'. | Code Size Reduction Operations |
|
||||
+----------+-----------------------+------------------------------------------------------+------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+
|
||||
| C.SH | c.sh rs2', uimm(rs1') | M[x[8+rs1'] + zext(uimm[1])][15:0] = x[8+rs2'] | NONE | an exception raised if the memory address isn't aligned (2-byte boundary). | This instruction stores the least significant halfword of rs2' to the memory address formed by adding rs1' to the zero extended immediate uimm. | Code Size Reduction Operations |
|
||||
+----------+-----------------------+------------------------------------------------------+------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+
|
||||
| C.SB | c.sb rs2', uimm(rs1') | M[x[8+rs1'] + zext(uimm[1:0])][7:0] = x[8+rs2'] | NONE | NONE | This instruction stores the least significant byte of rs2' to the memory address formed by adding rs1' to the zero extended immediate uimm. | Code Size Reduction Operations |
|
||||
+----------+-----------------------+------------------------------------------------------+------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+
|
||||
|
||||
RVZba Address generation instructions
|
||||
-------------------------------------
|
||||
|
@ -376,34 +395,3 @@ RVZbs Single bit Instructions
|
|||
+--------+----------------------+------------------------------------------------+------------------+--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------+
|
||||
| BSETI | bseti rd, rs1, shamt | X(rd) = X(rs1) | (1 << (shamt & (XLEN - 1))) | NONE | NONE | This instruction returns rs1 with a single bit set at the index specified in shamt. The index is read from the lower log2(XLEN) bits of shamt. For RV32, the encodings corresponding to shamt[5]=1 are reserved. | Single_bit_Operations |
|
||||
+--------+----------------------+------------------------------------------------+------------------+--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------+
|
||||
|
||||
RV32Zcb Code Size Reduction Instructions
|
||||
----------------------------------------
|
||||
|
||||
|
||||
+----------+-----------------------+------------------------------------------------------+------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+
|
||||
| Name | Format | Pseudocode | Invalid_values | Exception_raised | Description | Op Name |
|
||||
+==========+=======================+======================================================+==================+============================================================================+==============================================================================================================================================================================================================================================================================================+================================+
|
||||
| C.ZEXT.B | c.zext.b rd' | x[8 + rd'] = zext(x[8 + rd'][7:0]) | NONE | NONE | This instruction takes a single source/destination operand. It zero-extends the least-significant byte of the operand by inserting zeros into all of the bits more significant than 7. | Code Size Reduction Operations |
|
||||
+----------+-----------------------+------------------------------------------------------+------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+
|
||||
| C.SEXT.B | c.sext.b rd' | x[8 + rd'] = sext(x[8 + rd'][7:0]) | NONE | NONE | This instruction takes a single source/destination operand. It sign-extends the least-significant byte in the operand by copying the most-significant bit in the byte (i.e., bit 7) to all of the more-significant bits. It also requires Bit-Manipulation (Zbb) extension support. | Code Size Reduction Operations |
|
||||
+----------+-----------------------+------------------------------------------------------+------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+
|
||||
| C.ZEXT.H | c.zext.h rd' | x[8 + rd'] = zext(x[8 + rd'][15:0]) | NONE | NONE | This instruction takes a single source/destination operand. It zero-extends the least-significant halfword of the operand by inserting zeros into all of the bits more significant than 15. It also requires Bit-Manipulation (Zbb) extension support. | Code Size Reduction Operations |
|
||||
+----------+-----------------------+------------------------------------------------------+------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+
|
||||
| C.SEXT.H | c.sext.h rd' | x[8 + rd'] = sext(x[8 + rd'][15:0]) | NONE | NONE | This instruction takes a single source/destination operand. It sign-extends the least-significant halfword in the operand by copying the most-significant bit in the halfword (i.e., bit 15) to all of the more-significant bits. It also requires Bit-Manipulation (Zbb) extension support. | Code Size Reduction Operations |
|
||||
+----------+-----------------------+------------------------------------------------------+------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+
|
||||
| C.NOT | c.not rd' | x[8 + rd'] = x[8 + rd'] ^ -1 | NONE | NONE | This instruction takes the one’s complement of rd'/rs1' and writes the result to the same register. | Code Size Reduction Operations |
|
||||
+----------+-----------------------+------------------------------------------------------+------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+
|
||||
| C.MUL | c.mul rd', rs2' | x[8 + rd'] = (x[8 + rd'] * x[8 + rs2'])[31:0] | NONE | NONE | performs a 32-bit × 32-bit multiplication and places the lower 32 bits in the destination register (Both rd' and rs2' treated as signed numbers). It also requires M extension support. | Code Size Reduction Operations |
|
||||
+----------+-----------------------+------------------------------------------------------+------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+
|
||||
| C.LHU | c.lhu rd', uimm(rs1') | x[8+rd'] = zext(M[x[8+rs1'] + zext(uimm[1])][15:0]) | NONE | an exception raised if the memory address isn't aligned (2-byte boundary). | This instruction loads a halfword from the memory address formed by adding rs1' to the zero extended immediate uimm. The resulting halfword is zero extended and is written to rd'. | Code Size Reduction Operations |
|
||||
+----------+-----------------------+------------------------------------------------------+------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+
|
||||
| C.LH | c.lh rd', uimm(rs1') | x[8+rd'] = sext(M[x[8+rs1'] + zext(uimm[1])][15:0]) | NONE | an exception raised if the memory address isn't aligned (2-byte boundary). | This instruction loads a halfword from the memory address formed by adding rs1' to the zero extended immediate uimm. The resulting halfword is sign extended and is written to rd'. | Code Size Reduction Operations |
|
||||
+----------+-----------------------+------------------------------------------------------+------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+
|
||||
| C.LBU | c.lbu rd', uimm(rs1') | x[8+rd'] = zext(M[x[8+rs1'] + zext(uimm[1:0])][7:0]) | NONE | NONE | This instruction loads a byte from the memory address formed by adding rs1' to the zero extended immediate uimm. The resulting byte is zero extended and is written to rd'. | Code Size Reduction Operations |
|
||||
+----------+-----------------------+------------------------------------------------------+------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+
|
||||
| C.SH | c.sh rs2', uimm(rs1') | M[x[8+rs1'] + zext(uimm[1])][15:0] = x[8+rs2'] | NONE | an exception raised if the memory address isn't aligned (2-byte boundary). | This instruction stores the least significant halfword of rs2' to the memory address formed by adding rs1' to the zero extended immediate uimm. | Code Size Reduction Operations |
|
||||
+----------+-----------------------+------------------------------------------------------+------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+
|
||||
| C.SB | c.sb rs2', uimm(rs1') | M[x[8+rs1'] + zext(uimm[1:0])][7:0] = x[8+rs2'] | NONE | NONE | This instruction stores the least significant byte of rs2' to the memory address formed by adding rs1' to the zero extended immediate uimm. | Code Size Reduction Operations |
|
||||
+----------+-----------------------+------------------------------------------------------+------------------+----------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+
|
||||
|
||||
|
|
82
config/gen_from_riscv_config/cv32a65x/linker/link.ld
Normal file
82
config/gen_from_riscv_config/cv32a65x/linker/link.ld
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*======================================================================*/
|
||||
/* Proxy kernel linker script */
|
||||
/*======================================================================*/
|
||||
/* This is the linker script used when building the proxy kernel. */
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Setup */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
/* The OUTPUT_ARCH command specifies the machine architecture where the
|
||||
argument is one of the names used in the BFD library. More
|
||||
specifically one of the entires in bfd/cpu-mips.c */
|
||||
|
||||
OUTPUT_ARCH( "riscv" )
|
||||
ENTRY(_start)
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Sections */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
|
||||
/* text: test code section */
|
||||
. = 0x80000000;
|
||||
_start_text = .;
|
||||
.text.init : { *(.text.init) }
|
||||
|
||||
. = ALIGN(0x1000);
|
||||
.tohost : { *(.tohost) }
|
||||
|
||||
. = ALIGN(0x1000);
|
||||
.uvmif : { *(.uvmif) }
|
||||
|
||||
. = ALIGN(0x1000);
|
||||
.text : { *(.text) }
|
||||
. = ALIGN(0x1000);
|
||||
.text.startup : { *(.text.startup) }
|
||||
. = ALIGN(0x1000);
|
||||
_end_text = .;
|
||||
. = ALIGN(0x1000);
|
||||
.rodata : { *(.rodata*)}
|
||||
. = ALIGN(0x8);
|
||||
. = ALIGN(0x1000);
|
||||
.page_table : { *(.page_table) }
|
||||
.user_stack : { *(.user_stack) }
|
||||
.kernel_data : { *(.kernel_data) }
|
||||
.kernel_stack : { *(.kernel_stack) }
|
||||
|
||||
/* data segment */
|
||||
.data : { *(.data) }
|
||||
|
||||
.sdata : {
|
||||
__global_pointer$ = . + 0x800;
|
||||
*(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata*)
|
||||
*(.sdata .sdata.* .gnu.linkonce.s.*)
|
||||
}
|
||||
|
||||
/* bss segment */
|
||||
.sbss : {
|
||||
*(.sbss .sbss.* .gnu.linkonce.sb.*)
|
||||
*(.scommon)
|
||||
}
|
||||
.bss : { *(.bss) }
|
||||
|
||||
/* thread-local data segment */
|
||||
.tdata :
|
||||
{
|
||||
_tdata_begin = .;
|
||||
*(.tdata)
|
||||
_tdata_end = .;
|
||||
}
|
||||
.tbss :
|
||||
{
|
||||
*(.tbss)
|
||||
_tbss_end = .;
|
||||
}
|
||||
|
||||
/* End of uninitalized data segement */
|
||||
_end = .;
|
||||
}
|
||||
|
|
@ -1,28 +1,63 @@
|
|||
spike_param_tree:
|
||||
bootrom: true
|
||||
bootrom_base: 0x10000
|
||||
bootrom_size: 0x1000
|
||||
bootrom_base: 65536
|
||||
bootrom_size: 4096
|
||||
dram: true
|
||||
dram_base: 0x80000000
|
||||
dram_size: 0x40000000
|
||||
dram_base: 2147483648
|
||||
dram_size: 1073741824
|
||||
generic_core_config: false
|
||||
max_steps: 200000
|
||||
max_steps_enabled: false
|
||||
isa: rv32imc_zba_zbb_zbs_zbc_zicsr_zifencei
|
||||
priv: MSU
|
||||
isa: rv32imczicsr_zcb_zba_zbb_zbc_zbs
|
||||
priv: M
|
||||
core_configs:
|
||||
- isa: rv32imc_zba_zbb_zbs_zbc_zicsr_zifencei
|
||||
marchid: 0x3
|
||||
misa_we: false
|
||||
misa_we_enable: true
|
||||
misaligned: false
|
||||
mmu_mode: sv39
|
||||
mvendorid: 0x00000602
|
||||
pmpaddr0: 0x0
|
||||
pmpcfg0: 0x0
|
||||
pmpregions: 0x0
|
||||
priv: MSU
|
||||
-
|
||||
isa: rv32imczicsr_zcb_zba_zbb_zbc_zbs
|
||||
extensions: cv32a60x,cvxif
|
||||
boot_addr: 2147483648
|
||||
marchid_override_mask: 0xFFFFFFFF
|
||||
marchid_override_value: 0x3
|
||||
misa_write_mask: 0x0
|
||||
pmp_granularity: 8
|
||||
pmpaddr0: 0
|
||||
pmpcfg0: 0
|
||||
pmpregions_max: 64
|
||||
pmpregions_writable: 8
|
||||
priv: M
|
||||
status_fs_field_we: false
|
||||
status_fs_field_we_enable: false
|
||||
status_vs_field_we: false
|
||||
status_vs_field_we_enable: false
|
||||
mstatus_write_mask: 136
|
||||
mstatus_override_mask: 6144
|
||||
mie_write_mask: 0x00000880
|
||||
mie_override_mask: 0xfffff77f
|
||||
mie_override_value: 0x00000000
|
||||
mip_write_mask: 0x00000000
|
||||
mip_override_mask: 0xfffff77f
|
||||
mip_override_value: 0x00000000
|
||||
mtval_write_mask: 0
|
||||
tinfo_accessible: 0
|
||||
mscontext_accessible: 0
|
||||
mcontext_accessible: 0
|
||||
tdata1_accessible: 0
|
||||
tdata2_accessible: 0
|
||||
tdata3_accessible: 0
|
||||
tselect_accessible: 0
|
||||
pmpaddr0_write_mask: 0xFFFFFFFE
|
||||
pmpaddr1_write_mask: 0xFFFFFFFE
|
||||
pmpaddr2_write_mask: 0xFFFFFFFE
|
||||
pmpaddr3_write_mask: 0xFFFFFFFE
|
||||
pmpaddr4_write_mask: 0xFFFFFFFE
|
||||
pmpaddr5_write_mask: 0xFFFFFFFE
|
||||
pmpaddr6_write_mask: 0xFFFFFFFE
|
||||
pmpaddr7_write_mask: 0xFFFFFFFE
|
||||
mtvec_write_mask: 0xFFFFFFFE
|
||||
mhartid: 0
|
||||
mvendorid_override_mask : 0xFFFFFFFF
|
||||
mvendorid_override_value: 1538
|
||||
csr_counters_injection: true
|
||||
interrupts_injection: true
|
||||
unified_traps: true
|
||||
mcycleh_implemented: false
|
||||
mhpmevent31_implemented: false
|
||||
|
|
|
@ -24,6 +24,8 @@ SECTIONS
|
|||
. = ALIGN(0x1000);
|
||||
.tohost : { *(.tohost) }
|
||||
. = ALIGN(0x1000);
|
||||
.uvmif : { *(.uvmif) }
|
||||
. = ALIGN(0x1000);
|
||||
.text : { *(.text) }
|
||||
. = ALIGN(0x1000);
|
||||
.text.startup : { *(.text.startup) }
|
|
@ -3,4 +3,5 @@ pyyaml
|
|||
mdutils
|
||||
restructuredtext-lint
|
||||
rstcloth
|
||||
regex
|
||||
regex
|
||||
Mako
|
|
@ -1,478 +0,0 @@
|
|||
|
||||
|
||||
|
||||
[BASIC]
|
||||
|
||||
# Naming style matching correct argument names.
|
||||
argument-naming-style= any
|
||||
variable-naming-style= any
|
||||
# Regular expression matching correct argument names. Overrides argument-
|
||||
# naming-style. If left empty, argument names will be checked with the set
|
||||
# naming style.
|
||||
#argument-rgx=
|
||||
|
||||
# Naming style matching correct attribute names.
|
||||
attr-naming-style=any
|
||||
|
||||
# Regular expression matching correct attribute names. Overrides attr-naming-
|
||||
# style. If left empty, attribute names will be checked with the set naming
|
||||
# style.
|
||||
#attr-rgx=
|
||||
|
||||
# Bad variable names which should always be refused, separated by a comma.
|
||||
bad-names=foo,
|
||||
bar,
|
||||
baz,
|
||||
toto,
|
||||
tutu,
|
||||
tata
|
||||
|
||||
# Bad variable names regexes, separated by a comma. If names match any regex,
|
||||
# they will always be refused
|
||||
bad-names-rgxs=
|
||||
|
||||
# Naming style matching correct class attribute names.
|
||||
class-attribute-naming-style=any
|
||||
|
||||
# Regular expression matching correct class attribute names. Overrides class-
|
||||
# attribute-naming-style. If left empty, class attribute names will be checked
|
||||
# with the set naming style.
|
||||
#class-attribute-rgx=
|
||||
|
||||
# Naming style matching correct class constant names.
|
||||
class-const-naming-style=UPPER_CASE
|
||||
|
||||
# Regular expression matching correct class constant names. Overrides class-
|
||||
# const-naming-style. If left empty, class constant names will be checked with
|
||||
# the set naming style.
|
||||
#class-const-rgx=
|
||||
|
||||
# Naming style matching correct class names.
|
||||
class-naming-style=PascalCase
|
||||
|
||||
# Regular expression matching correct class names. Overrides class-naming-
|
||||
# style. If left empty, class names will be checked with the set naming style.
|
||||
#class-rgx=
|
||||
|
||||
# Naming style matching correct constant names.
|
||||
const-naming-style= any
|
||||
|
||||
# Regular expression matching correct constant names. Overrides const-naming-
|
||||
# style. If left empty, constant names will be checked with the set naming
|
||||
# style.
|
||||
#const-rgx=
|
||||
|
||||
# Minimum line length for functions/classes that require docstrings, shorter
|
||||
# ones are exempt.
|
||||
docstring-min-length=-1
|
||||
|
||||
# Naming style matching correct function names.
|
||||
function-naming-style=any
|
||||
|
||||
# Regular expression matching correct function names. Overrides function-
|
||||
# naming-style. If left empty, function names will be checked with the set
|
||||
# naming style.
|
||||
#function-rgx=
|
||||
|
||||
# Good variable names which should always be accepted, separated by a comma.
|
||||
good-names=i,
|
||||
j,
|
||||
k,
|
||||
ex,
|
||||
Run,
|
||||
_
|
||||
|
||||
# Good variable names regexes, separated by a comma. If names match any regex,
|
||||
# they will always be accepted
|
||||
good-names-rgxs=
|
||||
|
||||
# Include a hint for the correct naming format with invalid-name.
|
||||
include-naming-hint=no
|
||||
|
||||
# Naming style matching correct inline iteration names.
|
||||
inlinevar-naming-style=any
|
||||
|
||||
# Regular expression matching correct inline iteration names. Overrides
|
||||
# inlinevar-naming-style. If left empty, inline iteration names will be checked
|
||||
# with the set naming style.
|
||||
#inlinevar-rgx=
|
||||
|
||||
# Naming style matching correct method names.
|
||||
method-naming-style= any
|
||||
|
||||
# Regular expression matching correct method names. Overrides method-naming-
|
||||
# style. If left empty, method names will be checked with the set naming style.
|
||||
#method-rgx=
|
||||
|
||||
# Naming style matching correct module names.
|
||||
module-naming-style= any
|
||||
|
||||
|
||||
|
||||
[DESIGN]
|
||||
|
||||
# List of regular expressions of class ancestor names to ignore when counting
|
||||
# public methods (see R0903)
|
||||
exclude-too-few-public-methods= yes
|
||||
|
||||
# List of qualified class names to ignore when counting class parents (see
|
||||
# R0901)
|
||||
ignored-parents=
|
||||
|
||||
# Maximum number of arguments for function / method.
|
||||
max-args=50
|
||||
|
||||
# Maximum number of attributes for a class (see R0902).
|
||||
max-attributes=10
|
||||
|
||||
# Maximum number of boolean expressions in an if statement (see R0916).
|
||||
max-bool-expr=5
|
||||
|
||||
# Maximum number of branch for function / method body.
|
||||
max-branches=50
|
||||
|
||||
# Maximum number of locals for function / method body.
|
||||
max-locals=50
|
||||
|
||||
# Maximum number of parents for a class (see R0901).
|
||||
max-parents=7
|
||||
|
||||
# Maximum number of public methods for a class (see R0904).
|
||||
max-public-methods=20
|
||||
|
||||
# Maximum number of return / yield for function / method body.
|
||||
max-returns=6
|
||||
|
||||
# Maximum number of statements in function / method body.
|
||||
max-statements=150
|
||||
|
||||
# Minimum number of public methods for a class (see R0903).
|
||||
min-public-methods=2
|
||||
|
||||
|
||||
[EXCEPTIONS]
|
||||
|
||||
# Exceptions that will emit a warning when caught.
|
||||
overgeneral-exceptions=builtins.BaseException,builtins.Exception
|
||||
|
||||
|
||||
[FORMAT]
|
||||
|
||||
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
|
||||
expected-line-ending-format=
|
||||
|
||||
# Regexp for a line that is allowed to be longer than the limit.
|
||||
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
|
||||
|
||||
# Number of spaces of indent required inside a hanging or continued line.
|
||||
indent-after-paren=4
|
||||
|
||||
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
|
||||
# tab).
|
||||
indent-string=' '
|
||||
|
||||
# Maximum number of characters on a single line.
|
||||
max-line-length=3000
|
||||
|
||||
# Maximum number of lines in a module.
|
||||
max-module-lines=1000
|
||||
|
||||
# Allow the body of a class to be on the same line as the declaration if body
|
||||
# contains single statement.
|
||||
single-line-class-stmt=no
|
||||
|
||||
# Allow the body of an if to be on the same line as the test if there is no
|
||||
# else.
|
||||
single-line-if-stmt=no
|
||||
|
||||
|
||||
[IMPORTS]
|
||||
|
||||
# List of modules that can be imported at any level, not just the top level
|
||||
# one.
|
||||
allow-any-import-level=
|
||||
|
||||
# Allow explicit reexports by alias from a package __init__.
|
||||
allow-reexport-from-package=no
|
||||
|
||||
# Allow wildcard imports from modules that define __all__.
|
||||
allow-wildcard-with-all=no
|
||||
|
||||
# Deprecated modules which should not be used, separated by a comma.
|
||||
deprecated-modules=
|
||||
|
||||
# Output a graph (.gv or any supported image format) of external dependencies
|
||||
# to the given file (report RP0402 must not be disabled).
|
||||
ext-import-graph=
|
||||
|
||||
# Output a graph (.gv or any supported image format) of all (i.e. internal and
|
||||
# external) dependencies to the given file (report RP0402 must not be
|
||||
# disabled).
|
||||
import-graph=
|
||||
|
||||
# Output a graph (.gv or any supported image format) of internal dependencies
|
||||
# to the given file (report RP0402 must not be disabled).
|
||||
int-import-graph=
|
||||
|
||||
# Force import order to recognize a module as part of the standard
|
||||
# compatibility libraries.
|
||||
known-standard-library=
|
||||
|
||||
# Force import order to recognize a module as part of a third party library.
|
||||
known-third-party=enchant
|
||||
|
||||
# Couples of modules and preferred modules, separated by a comma.
|
||||
preferred-modules=
|
||||
|
||||
|
||||
[LOGGING]
|
||||
|
||||
# The type of string formatting that logging methods do. `old` means using %
|
||||
# formatting, `new` is for `{}` formatting.
|
||||
logging-format-style=old
|
||||
|
||||
# Logging modules to check that the string format arguments are in logging
|
||||
# function parameter format.
|
||||
logging-modules=logging
|
||||
|
||||
|
||||
[MESSAGES CONTROL]
|
||||
|
||||
# Only show warnings with the listed confidence levels. Leave empty to show
|
||||
# all. Valid levels: HIGH, CONTROL_FLOW, INFERENCE, INFERENCE_FAILURE,
|
||||
# UNDEFINED.
|
||||
confidence=HIGH,
|
||||
CONTROL_FLOW,
|
||||
INFERENCE,
|
||||
INFERENCE_FAILURE,
|
||||
UNDEFINED
|
||||
|
||||
# Disable the message, report, category or checker with the given id(s). You
|
||||
# can either give multiple identifiers separated by comma (,) or put this
|
||||
# option multiple times (only on the command line, not in the configuration
|
||||
# file where it should appear only once). You can also use "--disable=all" to
|
||||
# disable everything first and then re-enable specific checks. For example, if
|
||||
# you want to run only the similarities checker, you can use "--disable=all
|
||||
# --enable=similarities". If you want to run only the classes checker, but have
|
||||
# no Warning level messages displayed, use "--disable=all --enable=classes
|
||||
# --disable=W".
|
||||
disable=raw-checker-failed,
|
||||
bad-inline-option,
|
||||
locally-disabled,
|
||||
file-ignored,
|
||||
suppressed-message,
|
||||
useless-suppression,
|
||||
deprecated-pragma,
|
||||
use-symbolic-message-instead,
|
||||
use-implicit-booleaness-not-comparison-to-string,
|
||||
use-implicit-booleaness-not-comparison-to-zero
|
||||
|
||||
# Enable the message, report, category or checker with the given id(s). You can
|
||||
# either give multiple identifier separated by comma (,) or put this option
|
||||
# multiple time (only on the command line, not in the configuration file where
|
||||
# it should appear only once). See also the "--disable" option for examples.
|
||||
enable=
|
||||
|
||||
|
||||
[METHOD_ARGS]
|
||||
|
||||
# List of qualified names (i.e., library.method) which require a timeout
|
||||
# parameter e.g. 'requests.api.get,requests.api.post'
|
||||
timeout-methods=requests.api.delete,requests.api.get,requests.api.head,requests.api.options,requests.api.patch,requests.api.post,requests.api.put,requests.api.request
|
||||
|
||||
|
||||
[MISCELLANEOUS]
|
||||
|
||||
# List of note tags to take in consideration, separated by a comma.
|
||||
notes=FIXME,
|
||||
XXX,
|
||||
TODO
|
||||
|
||||
# Regular expression of note tags to take in consideration.
|
||||
notes-rgx=
|
||||
|
||||
|
||||
[REFACTORING]
|
||||
|
||||
# Maximum number of nested blocks for function / method body
|
||||
max-nested-blocks=25
|
||||
|
||||
# Complete name of functions that never returns. When checking for
|
||||
# inconsistent-return-statements if a never returning function is called then
|
||||
# it will be considered as an explicit return statement and no message will be
|
||||
# printed.
|
||||
never-returning-functions=sys.exit,argparse.parse_error
|
||||
|
||||
# Let 'consider-using-join' be raised when the separator to join on would be
|
||||
# non-empty (resulting in expected fixes of the type: ``"- " + " -
|
||||
# ".join(items)``)
|
||||
suggest-join-with-non-empty-separator=yes
|
||||
|
||||
|
||||
[REPORTS]
|
||||
|
||||
# Python expression which should return a score less than or equal to 10. You
|
||||
# have access to the variables 'fatal', 'error', 'warning', 'refactor',
|
||||
# 'convention', and 'info' which contain the number of messages in each
|
||||
# category, as well as 'statement' which is the total number of statements
|
||||
# analyzed. This score is used by the global evaluation report (RP0004).
|
||||
evaluation=max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10))
|
||||
|
||||
# Template used to display messages. This is a python new-style format string
|
||||
# used to format the message information. See doc for all details.
|
||||
msg-template=
|
||||
|
||||
# Set the output format. Available formats are: text, parseable, colorized,
|
||||
# json2 (improved json format), json (old json format) and msvs (visual
|
||||
# studio). You can also give a reporter class, e.g.
|
||||
# mypackage.mymodule.MyReporterClass.
|
||||
#output-format=
|
||||
|
||||
# Tells whether to display a full report or only the messages.
|
||||
reports=no
|
||||
|
||||
# Activate the evaluation score.
|
||||
score=yes
|
||||
|
||||
|
||||
[SIMILARITIES]
|
||||
|
||||
# Comments are removed from the similarity computation
|
||||
ignore-comments=yes
|
||||
|
||||
# Docstrings are removed from the similarity computation
|
||||
ignore-docstrings=yes
|
||||
|
||||
# Imports are removed from the similarity computation
|
||||
ignore-imports=yes
|
||||
|
||||
# Signatures are removed from the similarity computation
|
||||
ignore-signatures=yes
|
||||
|
||||
# Minimum lines number of a similarity.
|
||||
min-similarity-lines=4
|
||||
|
||||
|
||||
[SPELLING]
|
||||
|
||||
# Limits count of emitted suggestions for spelling mistakes.
|
||||
max-spelling-suggestions=4
|
||||
|
||||
# Spelling dictionary name. No available dictionaries : You need to install
|
||||
# both the python package and the system dependency for enchant to work.
|
||||
spelling-dict=
|
||||
|
||||
# List of comma separated words that should be considered directives if they
|
||||
# appear at the beginning of a comment and should not be checked.
|
||||
spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy:
|
||||
|
||||
# List of comma separated words that should not be checked.
|
||||
spelling-ignore-words=
|
||||
|
||||
# A path to a file that contains the private dictionary; one word per line.
|
||||
spelling-private-dict-file=
|
||||
|
||||
# Tells whether to store unknown words to the private dictionary (see the
|
||||
# --spelling-private-dict-file option) instead of raising a message.
|
||||
spelling-store-unknown-words=no
|
||||
|
||||
|
||||
[STRING]
|
||||
|
||||
# This flag controls whether inconsistent-quotes generates a warning when the
|
||||
# character used as a quote delimiter is used inconsistently within a module.
|
||||
check-quote-consistency=no
|
||||
|
||||
# This flag controls whether the implicit-str-concat should generate a warning
|
||||
# on implicit string concatenation in sequences defined over several lines.
|
||||
check-str-concat-over-line-jumps=no
|
||||
|
||||
|
||||
[TYPECHECK]
|
||||
|
||||
# List of decorators that produce context managers, such as
|
||||
# contextlib.contextmanager. Add to this list to register other decorators that
|
||||
# produce valid context managers.
|
||||
contextmanager-decorators=contextlib.contextmanager
|
||||
|
||||
# List of members which are set dynamically and missed by pylint inference
|
||||
# system, and so shouldn't trigger E1101 when accessed. Python regular
|
||||
# expressions are accepted.
|
||||
generated-members=
|
||||
|
||||
# Tells whether to warn about missing members when the owner of the attribute
|
||||
# is inferred to be None.
|
||||
ignore-none=yes
|
||||
|
||||
# This flag controls whether pylint should warn about no-member and similar
|
||||
# checks whenever an opaque object is returned when inferring. The inference
|
||||
# can return multiple potential results while evaluating a Python object, but
|
||||
# some branches might not be evaluated, which results in partial inference. In
|
||||
# that case, it might be useful to still emit no-member and other checks for
|
||||
# the rest of the inferred objects.
|
||||
ignore-on-opaque-inference=yes
|
||||
|
||||
# List of symbolic message names to ignore for Mixin members.
|
||||
ignored-checks-for-mixins=no-member,
|
||||
not-async-context-manager,
|
||||
not-context-manager,
|
||||
attribute-defined-outside-init
|
||||
|
||||
# List of class names for which member attributes should not be checked (useful
|
||||
# for classes with dynamically set attributes). This supports the use of
|
||||
# qualified names.
|
||||
ignored-classes=optparse.Values,thread._local,_thread._local,argparse.Namespace
|
||||
|
||||
# Show a hint with possible names when a member name was not found. The aspect
|
||||
# of finding the hint is based on edit distance.
|
||||
missing-member-hint=yes
|
||||
|
||||
# The minimum edit distance a name should have in order to be considered a
|
||||
# similar match for a missing member name.
|
||||
missing-member-hint-distance=1
|
||||
|
||||
# The total number of similar names that should be taken in consideration when
|
||||
# showing a hint for a missing member.
|
||||
missing-member-max-choices=1
|
||||
|
||||
# Regex pattern to define which classes are considered mixins.
|
||||
mixin-class-rgx=.*[Mm]ixin
|
||||
|
||||
# List of decorators that change the signature of a decorated function.
|
||||
signature-mutators=
|
||||
|
||||
|
||||
[VARIABLES]
|
||||
|
||||
# List of additional names supposed to be defined in builtins. Remember that
|
||||
# you should avoid defining new builtins when possible.
|
||||
additional-builtins=
|
||||
|
||||
# Tells whether unused global variables should be treated as a violation.
|
||||
allow-global-unused-variables=yes
|
||||
|
||||
# List of names allowed to shadow builtins
|
||||
allowed-redefined-builtins=
|
||||
|
||||
# List of strings which can identify a callback function by name. A callback
|
||||
# name must start or end with one of those strings.
|
||||
callbacks=cb_,
|
||||
_cb
|
||||
|
||||
# A regular expression matching the name of dummy variables (i.e. expected to
|
||||
# not be used).
|
||||
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
|
||||
|
||||
# Argument names that match this expression will be ignored.
|
||||
ignored-argument-names=_.*|^ignored_|^unused_
|
||||
|
||||
# Tells whether we should check for unused import in __init__ files.
|
||||
init-import=no
|
||||
|
||||
# List of qualified module names which can have objects that can redefine
|
||||
# builtins.
|
||||
redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
|
||||
|
||||
|
||||
[MASTER]
|
||||
disable = C0116,
|
|
@ -24,6 +24,7 @@ def address_to_key(address):
|
|||
|
||||
def factorizer(yaml_data):
|
||||
privname = None
|
||||
legalname= None
|
||||
fieldname = []
|
||||
regname = []
|
||||
regdescr = []
|
||||
|
@ -37,9 +38,9 @@ def factorizer(yaml_data):
|
|||
suffix_address = []
|
||||
suffix_number = []
|
||||
key_to_remove = []
|
||||
for key, value in yaml_data["hart0"].items():
|
||||
for key, value in yaml_data.items():
|
||||
if isinstance(value, dict):
|
||||
regelement = yaml_data["hart0"].get(key, {})
|
||||
regelement = yaml_data.get(key, {})
|
||||
if regelement.get("address", None):
|
||||
regaddress = hex(regelement.get("address", None))
|
||||
else:
|
||||
|
@ -49,11 +50,16 @@ def factorizer(yaml_data):
|
|||
else:
|
||||
desc = ""
|
||||
if regelement.get("rv32", "")["accessible"]:
|
||||
fields = regelement.get("rv32", "").get("fields", [])
|
||||
if not fields :
|
||||
legal = regelement.get("rv32", "").get("type", None).keys() if regelement.get("rv32", "").get("type", None) is not None else None
|
||||
else :
|
||||
legal = [regelement.get("rv32", "").get(item, {}).get("type").keys()for item in fields if not isinstance(item, list) and regelement.get("rv32", "").get(item, {}).get("type") is not None]
|
||||
pattern = r"(\D+)(\d+)(.*)"
|
||||
match = re.search(pattern, key)
|
||||
if match:
|
||||
key_to_remove.append(key)
|
||||
if privname and match.group(1) == privname.group(1):
|
||||
if privname and match.group(1) == privname.group(1) and legalname == legal:
|
||||
if len(match.group(3)) > 0:
|
||||
suffix_name.append(match.group(0))
|
||||
field_suffix.append(match.group(1))
|
||||
|
@ -75,7 +81,7 @@ def factorizer(yaml_data):
|
|||
start_address = hex(int(regadress[0], 16))
|
||||
desc = str(regdescr[0])
|
||||
desc = re.sub(str(regname[0]), fieldname[0], desc)
|
||||
modified_data = yaml_data["hart0"][regname[0]].copy()
|
||||
modified_data = yaml_data[regname[0]].copy()
|
||||
modified_data["address"] = (
|
||||
f"{str(start_address)}-{str(regadress[-1])}"
|
||||
)
|
||||
|
@ -98,13 +104,14 @@ def factorizer(yaml_data):
|
|||
suffix_address = sorted(suffix_address, key=address_to_key)
|
||||
desc = str(suffix_descr[0])
|
||||
desc = re.sub(str(suffix_name[0]), field_suffix[0], desc)
|
||||
modified_data = yaml_data["hart0"][suffix_name[0]].copy()
|
||||
modified_data = yaml_data[suffix_name[0]].copy()
|
||||
modified_data["address"] = (
|
||||
f"{str(suffix_address[0])}-{str(suffix_address[-1])}"
|
||||
)
|
||||
new_regname.append(
|
||||
f"{field_suffix[0]}[{suffix_number[0]}-{suffix_number[-1]}]h"
|
||||
)
|
||||
print(new_regname)
|
||||
data.append(modified_data)
|
||||
suffix_name = []
|
||||
field_suffix = []
|
||||
|
@ -112,12 +119,13 @@ def factorizer(yaml_data):
|
|||
suffix_number = [match.group(2)]
|
||||
suffix_address = []
|
||||
privname = match
|
||||
legalname = legal
|
||||
if regname:
|
||||
start_address = hex(int(regadress[0], 16))
|
||||
end_address = str(regadress[-1])
|
||||
desc = str(regdescr[0])
|
||||
desc = re.sub(str(regname[0]), fieldname[0], desc)
|
||||
modified_data = yaml_data["hart0"][regname[0]].copy()
|
||||
modified_data = yaml_data[regname[0]].copy()
|
||||
modified_data["description"] = desc
|
||||
modified_data["address"] = f"{str(start_address)}-{str(end_address)}"
|
||||
new_regname.append(f"{fieldname[0]}[{reg_number[0]}-{reg_number[-1]}]")
|
||||
|
@ -129,7 +137,7 @@ def factorizer(yaml_data):
|
|||
if suffix_name:
|
||||
desc = str(suffix_descr[0])
|
||||
desc = re.sub(str(suffix_name[0]), field_suffix[0], desc)
|
||||
modified_data = yaml_data["hart0"][suffix_name[0]].copy()
|
||||
modified_data = yaml_data[suffix_name[0]].copy()
|
||||
modified_data["description"] = desc
|
||||
modified_data["address"] = (
|
||||
f"{str(hex(int(suffix_address[0],16)))}-{str(suffix_address[-1])}"
|
||||
|
@ -143,7 +151,7 @@ def factorizer(yaml_data):
|
|||
regdescr = []
|
||||
regadress = []
|
||||
for index, reg in enumerate(new_regname):
|
||||
yaml_data["hart0"][reg] = data[index]
|
||||
yaml_data[reg] = data[index]
|
||||
for key in key_to_remove:
|
||||
del yaml_data["hart0"][key]
|
||||
return yaml_data["hart0"]
|
||||
del yaml_data[key]
|
||||
return yaml_data
|
||||
|
|
|
@ -1,19 +1,3 @@
|
|||
# Copyright 2024 Thales DIS France SAS
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Original Author: Oukalrazqou Abdessamii
|
||||
""" Module is used to update csr based on yaml file called csr updater """
|
||||
import re
|
||||
import yaml
|
||||
|
||||
|
@ -22,45 +6,46 @@ def csr_recursive_update(original_dict, csr_update):
|
|||
"""
|
||||
Gets the data of the RISC-V Config Yaml file and
|
||||
update the value of sub key in RISC-V Config Yaml file
|
||||
(ex: reset-val , shadow_type)
|
||||
(ex: reset-val , address)
|
||||
:param original_dict : parsed data of RISC-V Config Yaml file
|
||||
csr_update : parsed data of CSR updater
|
||||
:return: data of RISC-V Config Yaml file updated
|
||||
"""
|
||||
for key, value in csr_update.items():
|
||||
if key in original_dict.keys():
|
||||
if isinstance(value, dict):
|
||||
csr_recursive_update(original_dict[key], value)
|
||||
elif isinstance(value, bool):
|
||||
if isinstance(original_dict[key], dict):
|
||||
for k in original_dict[key]:
|
||||
print(k)
|
||||
if isinstance(original_dict[key][k], dict):
|
||||
|
||||
for sub_key in original_dict[key][k]:
|
||||
original_dict[key][k][sub_key] = value
|
||||
else:
|
||||
original_dict[key][k] = value
|
||||
else:
|
||||
if key in original_dict:
|
||||
if isinstance(value, dict) and isinstance(original_dict[key], dict):
|
||||
if key == "rv32":
|
||||
original_dict[key] = value
|
||||
else:
|
||||
csr_recursive_update(original_dict[key], value)
|
||||
else:
|
||||
original_dict[key] = value
|
||||
|
||||
|
||||
def csr_formatter(srcfile, modifile):
|
||||
# Read original dictionary from YAML Source file
|
||||
def csr_formatter(srcfile, customfile, debugfile, modifile):
|
||||
# Read original dictionary from YAML source file
|
||||
with open(srcfile, "r", encoding="utf-8") as file:
|
||||
original_dict = yaml.safe_load(file)
|
||||
updated_values = {}
|
||||
with open(customfile, "r", encoding="utf-8") as file:
|
||||
custom_dict = yaml.safe_load(file)
|
||||
debug_dict = {}
|
||||
riscv_config_data = original_dict.copy()
|
||||
if debugfile is not None:
|
||||
with open(debugfile, "r", encoding="utf-8") as file:
|
||||
debug_dict = yaml.safe_load(file)
|
||||
if debug_dict["hart0"]["debug_mode"]:
|
||||
riscv_config_data["hart0"].update(debug_dict["hart0"])
|
||||
riscv_config_data["hart0"].update(custom_dict["hart0"])
|
||||
update_dict = {}
|
||||
if modifile is not None:
|
||||
with open(modifile, "r", encoding="utf-8") as file:
|
||||
updated_values = yaml.safe_load(file)
|
||||
update_dict = yaml.safe_load(file)
|
||||
print(riscv_config_data["hart0"])
|
||||
# Update original_dict with values from updated_values recursively
|
||||
csr_recursive_update(original_dict["hart0"], updated_values)
|
||||
|
||||
csr_recursive_update(riscv_config_data["hart0"], update_dict)
|
||||
# Identify and remove keys within the range specified for each register
|
||||
keys_to_remove = []
|
||||
for key, value in updated_values.items():
|
||||
for key, value in update_dict.items():
|
||||
if "range" in value:
|
||||
range_value = value["range"]
|
||||
pattern = rf"{key}(\d+)"
|
||||
|
@ -71,7 +56,7 @@ def csr_formatter(srcfile, modifile):
|
|||
if index >= range_value:
|
||||
keys_to_remove.append(k)
|
||||
# Remove excluded keys based on the condition
|
||||
exclude_data = updated_values.get("exclude")
|
||||
exclude_data = update_dict.get("exclude")
|
||||
if exclude_data:
|
||||
exclude_key = exclude_data.get("key")
|
||||
sub_key = exclude_data.get("sub_key")
|
||||
|
@ -91,12 +76,12 @@ def csr_formatter(srcfile, modifile):
|
|||
for k in keys_to_remove:
|
||||
dictionary.pop(k)
|
||||
|
||||
remove_keys_recursive(original_dict["hart0"])
|
||||
remove_keys_recursive(original_dict["hart0"])
|
||||
remove_keys_recursive(riscv_config_data["hart0"])
|
||||
remove_keys_recursive(riscv_config_data["hart0"])
|
||||
# Remove keys from original_dict
|
||||
for k in keys_to_remove:
|
||||
original_dict["hart0"].pop(k, None)
|
||||
riscv_config_data["hart0"].pop(k, None)
|
||||
# Remove keys from original_dict
|
||||
for k in keys_to_remove:
|
||||
original_dict.pop(k, None)
|
||||
return original_dict
|
||||
riscv_config_data.pop(k, None)
|
||||
return riscv_config_data["hart0"]
|
||||
|
|
74
config/gen_from_riscv_config/scripts/libs/spike_updater.py
Normal file
74
config/gen_from_riscv_config/scripts/libs/spike_updater.py
Normal file
|
@ -0,0 +1,74 @@
|
|||
# Copyright 2024 Thales DIS France SAS
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Original Author: Oukalrazqou Abdessamii
|
||||
|
||||
|
||||
""" Module is used to update Spike based on yaml file called spike updater """
|
||||
import re
|
||||
import yaml
|
||||
from yaml import BaseLoader
|
||||
|
||||
|
||||
def spike_recursive_update(original_dict, spike_update):
|
||||
"""
|
||||
Gets the data of the RISC-V Config Yaml file and
|
||||
update the value of sub key in RISC-V Config Yaml file
|
||||
(ex: priv , pmpaddr)
|
||||
:param original_dict : parsed data of Spike Yaml file
|
||||
spike_update : parsed data of Spike updaters
|
||||
:return: data of Spike Yaml file updated
|
||||
"""
|
||||
for key, value in spike_update.items():
|
||||
if key in original_dict:
|
||||
if isinstance(value, dict) and isinstance(original_dict[key], dict):
|
||||
if key == "cores":
|
||||
original_dict[key] = value
|
||||
else:
|
||||
csr_recursive_update(original_dict[key], value)
|
||||
else:
|
||||
original_dict[key] = value
|
||||
|
||||
|
||||
def is_hex_string(s):
|
||||
return bool(re.match(r"'?(0x[0-9a-fA-F]+)'?", s))
|
||||
|
||||
|
||||
def custom_convert(data):
|
||||
if isinstance(data, dict):
|
||||
return {k: custom_convert(v) for k, v in data.items()}
|
||||
elif isinstance(data, list):
|
||||
return [custom_convert(item) for item in data]
|
||||
elif isinstance(data, str):
|
||||
if data.lower() == "true":
|
||||
return True
|
||||
elif data.lower() == "false":
|
||||
return False
|
||||
elif data.isdigit():
|
||||
return int(data)
|
||||
elif is_hex_string(data.strip()):
|
||||
return int(data, 16)
|
||||
return data
|
||||
|
||||
|
||||
def spike_formatter(original_dict, modifile):
|
||||
# Read original dictionary from YAML Source file
|
||||
updated_values = {}
|
||||
if modifile is not None:
|
||||
with open(modifile, "r", encoding="utf-8") as file:
|
||||
updated_values = yaml.load(file, Loader=BaseLoader)
|
||||
# Update original_dict with values from updated_values recursively
|
||||
spike_recursive_update(original_dict["spike_param_tree"], updated_values)
|
||||
original_dict = custom_convert(original_dict)
|
||||
return original_dict
|
|
@ -14,28 +14,31 @@
|
|||
#
|
||||
# Original Author: Oukalrazqou Abdessamii
|
||||
|
||||
""" Module is used to gather all utils and function to generate the csr and isa documents"""
|
||||
"""Module is used to gather all utils and function to generate the csr and isa documents"""
|
||||
|
||||
import io
|
||||
import os
|
||||
import re
|
||||
import yaml
|
||||
from yaml import BaseLoader
|
||||
import rstcloth
|
||||
import json
|
||||
from mako.template import Template
|
||||
import libs.isa_updater
|
||||
import libs.csr_updater
|
||||
import libs.spike_updater
|
||||
import libs.csr_factorizer
|
||||
from rstcloth import RstCloth
|
||||
from mdutils.mdutils import MdUtils
|
||||
from libs.isa_updater import isa_filter
|
||||
from libs.csr_updater import csr_formatter
|
||||
from libs.spike_updater import spike_formatter
|
||||
from libs.csr_factorizer import factorizer
|
||||
|
||||
pattern_warl = (
|
||||
r"\b(?:warl|wlrl|ro_constant|ro_variable)\b" # pattern to detect warl in field
|
||||
)
|
||||
pattern_warl = r"\b(?:warl|wlrl|ro_constant|ro_variable|rw|ro)\b" # pattern to detect warl in field
|
||||
pattern_legal_dict = r"\[(0x[0-9A-Fa-f]+)(.*?(0x[0-9A-Fa-f]+))?\]" # pattern to detect if warl field is dict
|
||||
pattern_legal_list = r"\[(0x[0-9A-Fa-f]+)(.*?(0x[0-9A-Fa-f]+))?\]" # pattern to detect if warl field is a list
|
||||
Factorizer_pattern = r".*(\d).*" # pattern to detect factorized fields
|
||||
Factorizer_pattern = r"\d+" # pattern to detect factorized fields
|
||||
|
||||
|
||||
class DocumentClass:
|
||||
|
@ -111,6 +114,8 @@ class Field:
|
|||
bitWidth,
|
||||
fieldDesc,
|
||||
fieldaccess,
|
||||
andMask=None,
|
||||
orMask=None,
|
||||
):
|
||||
self.name = name
|
||||
self.bitlegal = bitlegal
|
||||
|
@ -120,6 +125,126 @@ class Field:
|
|||
self.bitWidth = bitWidth
|
||||
self.fieldDesc = fieldDesc
|
||||
self.fieldaccess = fieldaccess
|
||||
self.andMask = andMask
|
||||
self.orMask = orMask
|
||||
|
||||
|
||||
# --------------------------------------------------------------#
|
||||
class Render:
|
||||
"""Collection of general rendering methods which can be overridden if needed
|
||||
for a specific output format."""
|
||||
|
||||
@staticmethod
|
||||
def is_decimal(value):
|
||||
"""return a bool checking if value is decimal"""
|
||||
try:
|
||||
int(
|
||||
value
|
||||
) # Alternatively, use float(value) if you want to check for floating point numbers
|
||||
return True
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def range(start, end):
|
||||
"""Return a string representing the range START..END, inclusive.
|
||||
START and END are strings representing numerical values."""
|
||||
if Render.is_decimal(start):
|
||||
start = hex(int(start))
|
||||
if Render.is_decimal(end):
|
||||
end = hex(int(end))
|
||||
return f"{start} - {end}"
|
||||
|
||||
@staticmethod
|
||||
def value_set(values):
|
||||
"""Return a string representing the set of values in VALUES.
|
||||
VALUES is a list of strings."""
|
||||
# values = [hex(int(value, 16)) if '0x' in value and '-' not in value else value for value in values]
|
||||
return ", ".join(values)
|
||||
|
||||
@staticmethod
|
||||
def bitmask(andMask, orMask):
|
||||
"""Return a string representing the masking pattern defined by ANDMASK and ORMASK.
|
||||
ANDMASK and ORMASK are strings representing AND and OR mask values, respectively.
|
||||
"""
|
||||
return f"masked: & {andMask} | {orMask}"
|
||||
|
||||
@staticmethod
|
||||
def fieldtype(typ):
|
||||
"""Return a string representing the printable type of a register field."""
|
||||
upcased = typ.upper()
|
||||
if upcased == "RO_CONSTANT":
|
||||
return "ROCST"
|
||||
elif upcased == "RO_VARIABLE":
|
||||
return "ROVAR"
|
||||
else:
|
||||
return upcased
|
||||
|
||||
|
||||
class CoreConfig:
|
||||
def __init__(
|
||||
self,
|
||||
isa,
|
||||
marchid,
|
||||
misa_we,
|
||||
misa_we_enable,
|
||||
misaligned,
|
||||
mmu_mode,
|
||||
mvendorid,
|
||||
pmpaddr0,
|
||||
pmpcfg0,
|
||||
pmpregions,
|
||||
priv,
|
||||
status_fs_field_we,
|
||||
status_fs_field_we_enable,
|
||||
status_vs_field_we,
|
||||
status_vs_field_we_enable,
|
||||
):
|
||||
self.isa = isa
|
||||
self.marchid = marchid
|
||||
self.misa_we = misa_we
|
||||
self.misa_we_enable = misa_we_enable
|
||||
self.misaligned = misaligned
|
||||
self.mmu_mode = mmu_mode
|
||||
self.mvendorid = mvendorid
|
||||
self.pmpaddr0 = pmpaddr0
|
||||
self.pmpcfg0 = pmpcfg0
|
||||
self.pmpregions = pmpregions
|
||||
self.priv = priv
|
||||
self.status_fs_field_we = status_fs_field_we
|
||||
self.status_fs_field_we_enable = status_fs_field_we_enable
|
||||
self.status_vs_field_we = status_vs_field_we
|
||||
self.status_vs_field_we_enable = status_vs_field_we_enable
|
||||
|
||||
|
||||
class Spike:
|
||||
def __init__(
|
||||
self,
|
||||
bootrom,
|
||||
bootrom_base,
|
||||
bootrom_size,
|
||||
dram,
|
||||
dram_base,
|
||||
dram_size,
|
||||
generic_core_config,
|
||||
max_steps,
|
||||
max_steps_enabled,
|
||||
isa,
|
||||
priv,
|
||||
core_configs,
|
||||
):
|
||||
self.bootrom = bootrom
|
||||
self.bootrom_base = bootrom_base
|
||||
self.bootrom_size = bootrom_size
|
||||
self.dram = dram
|
||||
self.dram_base = dram_base
|
||||
self.dram_size = dram_size
|
||||
self.generic_core_config = generic_core_config
|
||||
self.max_steps = max_steps
|
||||
self.max_steps_enabled = max_steps_enabled
|
||||
self.isa = isa
|
||||
self.priv = priv
|
||||
self.core_configs = core_configs
|
||||
|
||||
|
||||
# --------------------------------------------------------------#
|
||||
|
@ -135,7 +260,7 @@ class ISAdocumentClass:
|
|||
|
||||
|
||||
class InstructionMapClass:
|
||||
"""ISA instruction map class"""
|
||||
"""ISA instruction map c.2n lass"""
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
@ -210,11 +335,22 @@ class RstAddressBlock(AddressBlockClass):
|
|||
return int(start, 16), int(end, 16)
|
||||
return int(reg.address, 16), int(reg.address, 16)
|
||||
|
||||
def get_access_privilege(self, reg):
|
||||
"""Registers with address bits [11:10] == 2'b11 are Read-Only
|
||||
as per privileged ISA spec."""
|
||||
# Handle register address ranges separated by dashes.
|
||||
if (int(reg.address.split("-")[0], 0) & 0xC00) == 0xC00:
|
||||
return "RO"
|
||||
else:
|
||||
return "RW"
|
||||
|
||||
def returnAsString(self):
|
||||
registerlist = sorted(self.registerList, key=lambda reg: reg.address)
|
||||
r = RstCloth(io.StringIO()) # with default parameter, sys.stdout is used
|
||||
regNameList = [reg.name for reg in registerlist]
|
||||
regNameList = [reg.name.upper() for reg in registerlist]
|
||||
regAddressList = [reg.address for reg in registerlist]
|
||||
regPrivModeList = [reg.access for reg in registerlist]
|
||||
regPrivAccessList = [self.get_access_privilege(reg) for reg in registerlist]
|
||||
regDescrList = [reg.desc for reg in registerlist]
|
||||
regRV32List = [reg.RV32 for reg in registerlist]
|
||||
regRV64List = [reg.RV64 for reg in registerlist]
|
||||
|
@ -229,6 +365,47 @@ class RstAddressBlock(AddressBlockClass):
|
|||
)
|
||||
r.title(self.name) # Use the name of the addressBlock as title
|
||||
r.newline()
|
||||
r.h2("Conventions")
|
||||
r.newline()
|
||||
r.content(
|
||||
"""In the subsequent sections, register fields are labeled with one of the
|
||||
following abbreviations:
|
||||
"""
|
||||
)
|
||||
r.newline()
|
||||
r.li(
|
||||
"""WPRI (Writes Preserve Values, Reads Ignore Values): read/write field reserved
|
||||
for future use. For forward compatibility, implementations that do not
|
||||
furnish these fields must make them read-only zero."""
|
||||
)
|
||||
r.li(
|
||||
"""WLRL (Write/Read Only Legal Values): read/write CSR field that specifies
|
||||
behavior for only a subset of possible bit encodings, with other bit encodings
|
||||
reserved."""
|
||||
)
|
||||
r.li(
|
||||
"""WARL (Write Any Values, Reads Legal Values): read/write CSR fields which are
|
||||
only defined for a subset of bit encodings, but allow any value to be written
|
||||
while guaranteeing to return a legal value whenever read."""
|
||||
)
|
||||
r.li(
|
||||
"""ROCST (Read-Only Constant): A special case of WARL field which admits only one
|
||||
legal value, and therefore, behaves as a constant field that silently ignores
|
||||
writes."""
|
||||
)
|
||||
r.li(
|
||||
"""ROVAR (Read-Only Variable): A special case of WARL field which can take
|
||||
multiple legal values but cannot be modified by software and depends only on
|
||||
the architectural state of the hart."""
|
||||
)
|
||||
r.newline()
|
||||
r.content(
|
||||
"""In particular, a register that is not internally divided
|
||||
into multiple fields can be considered as containing a single field of XLEN bits.
|
||||
This allows to clearly represent read-write registers holding a single legal value
|
||||
(typically zero)."""
|
||||
)
|
||||
r.newline()
|
||||
r.h2("Register Summary")
|
||||
summary_table = []
|
||||
for i, _ in enumerate(regNameList):
|
||||
|
@ -236,17 +413,26 @@ class RstAddressBlock(AddressBlockClass):
|
|||
summary_table.append(
|
||||
[
|
||||
regAddressList[i],
|
||||
str(regNameList[i]).upper(),
|
||||
f"`{regNameList[i]} <#{regNameList[i]}>`_",
|
||||
# RW or RO privileges are set in the official RISC-V specification
|
||||
# and are encoded in bits [11:10] of the reg's address (2'b11 == "RO").
|
||||
# See Tables 4 through 8 in section 2.2 of the Priv spec v20240411.
|
||||
regPrivModeList[i] + regPrivAccessList[i],
|
||||
str(regDescrList[i]),
|
||||
]
|
||||
)
|
||||
r.table(header=["Address", "Register Name", "Description"], data=summary_table)
|
||||
r.table(
|
||||
header=["Address", "Register Name", "Privilege", "Description"],
|
||||
data=summary_table,
|
||||
)
|
||||
|
||||
r.h2("Register Description")
|
||||
for reg in registerlist:
|
||||
if reg.RV32 | reg.RV64:
|
||||
reg_table = []
|
||||
r.h2(reg.name.upper())
|
||||
r.newline()
|
||||
r.directive(".. _" + reg.name.upper() + ":")
|
||||
r.h3(reg.name.upper())
|
||||
r.newline()
|
||||
r.field("Address", (reg.address))
|
||||
if reg.resetValue:
|
||||
|
@ -255,7 +441,8 @@ class RstAddressBlock(AddressBlockClass):
|
|||
"Reset Value",
|
||||
"0x" + f"{reg.resetValue[2:].zfill(int(reg.size/4))}",
|
||||
)
|
||||
r.field("Privilege Mode", reg.access)
|
||||
# RO/RW privileges are encoded in register address.
|
||||
r.field("Privilege", reg.access + self.get_access_privilege(reg))
|
||||
r.field("Description", reg.desc)
|
||||
for field in reg.field:
|
||||
if field.bitWidth == 1: # only one bit -> no range needed
|
||||
|
@ -265,13 +452,13 @@ class RstAddressBlock(AddressBlockClass):
|
|||
_line = [
|
||||
bits,
|
||||
field.name.upper(),
|
||||
field.bitlegal,
|
||||
field.fieldreset,
|
||||
field.fieldaccess,
|
||||
field.bitlegal,
|
||||
]
|
||||
_line.append(field.fieldDesc)
|
||||
reg_table.append(_line)
|
||||
_headers = ["Bits", "Field Name", "Legal Values", "Reset", "Type"]
|
||||
_headers = ["Bits", "Field Name", "Reset Value", "Type", "Legal Values"]
|
||||
_headers.append("Description")
|
||||
reg_table = sorted(
|
||||
reg_table, key=lambda x: int(x[0].strip("[]").split(":")[0])
|
||||
|
@ -348,9 +535,196 @@ class InstrstBlock(InstructionBlockClass):
|
|||
r.table(header=_headers, data=reg_table)
|
||||
return r.data
|
||||
|
||||
class AdocAddressBlock(AddressBlockClass):
|
||||
"""Generates an AsciiDoc file from a IP-XACT register description"""
|
||||
|
||||
def __init__(self, name):
|
||||
super().__init__("csr")
|
||||
self.name = name
|
||||
self.registerList = []
|
||||
self.suffix = ".adoc"
|
||||
|
||||
def get_access_privilege(self, reg):
|
||||
"""Registers with address bits [11:10] == 2'b11 are Read-Only
|
||||
as per privileged ISA spec."""
|
||||
# Handle register address ranges separated by dashes.
|
||||
if (int(reg.address.split("-")[0], 0) & 0xC00) == 0xC00:
|
||||
return "RO"
|
||||
else:
|
||||
return "RW"
|
||||
|
||||
def generate_label(self, name):
|
||||
return "_" + name.replace('[','').replace(']','').upper()
|
||||
|
||||
def returnAsString(self):
|
||||
registerlist = sorted(self.registerList, key=lambda reg: reg.address)
|
||||
r = ""
|
||||
regNameList = [reg.name.upper() for reg in registerlist]
|
||||
regAddressList = [reg.address for reg in registerlist]
|
||||
regPrivModeList = [reg.access for reg in registerlist]
|
||||
regPrivAccessList = [self.get_access_privilege(reg) for reg in registerlist]
|
||||
regDescrList = [reg.desc for reg in registerlist]
|
||||
regRV32List = [reg.RV32 for reg in registerlist]
|
||||
regRV64List = [reg.RV64 for reg in registerlist]
|
||||
|
||||
r += "////\n"
|
||||
r += " Copyright (c) 2024 OpenHW Group\n"
|
||||
r += " Copyright (c) 2024 Thales\n"
|
||||
r += " SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1\n"
|
||||
r += " Author: Abdessamii Oukalrazqou\n"
|
||||
r += "////\n\n"
|
||||
|
||||
r += "=== %s\n\n"%self.name
|
||||
r += "==== Conventions\n\n"
|
||||
|
||||
r += "In the subsequent sections, register fields are labeled with one of the following abbreviations:\n\n"
|
||||
|
||||
r += "* WPRI (Writes Preserve Values, Reads Ignore Values): read/write field reserved\n"
|
||||
r += "for future use. For forward compatibility, implementations that do not\n"
|
||||
r += "furnish these fields must make them read-only zero.\n"
|
||||
|
||||
r += "* WLRL (Write/Read Only Legal Values): read/write CSR field that specifies\n"
|
||||
r += "behavior for only a subset of possible bit encodings, with other bit encodings\n"
|
||||
r += "reserved.\n"
|
||||
|
||||
r += "* WARL (Write Any Values, Reads Legal Values): read/write CSR fields which are\n"
|
||||
r += "only defined for a subset of bit encodings, but allow any value to be written\n"
|
||||
r += "while guaranteeing to return a legal value whenever read.\n"
|
||||
|
||||
r += "* ROCST (Read-Only Constant): A special case of WARL field which admits only one\n"
|
||||
r += "legal value, and therefore, behaves as a constant field that silently ignores\n"
|
||||
r += "writes.\n"
|
||||
|
||||
r += "* ROVAR (Read-Only Variable): A special case of WARL field which can take\n"
|
||||
r += "multiple legal values but cannot be modified by software and depends only on\n"
|
||||
r += "the architectural state of the hart.\n\n"
|
||||
|
||||
r += "In particular, a register that is not internally divided\n"
|
||||
r += "into multiple fields can be considered as containing a single field of XLEN bits.\n"
|
||||
r += "This allows to clearly represent read-write registers holding a single legal value\n"
|
||||
r += "(typically zero).\n\n"
|
||||
|
||||
r += "==== Register Summary\n\n"
|
||||
|
||||
r += "|===\n"
|
||||
r += "|Address | Register Name | Privilege | Description\n\n"
|
||||
for i, _ in enumerate(regNameList):
|
||||
if regRV32List[i] | regRV64List[i]:
|
||||
r += "|" + regAddressList[i] + \
|
||||
f"| `<<{self.generate_label(regNameList[i])},{regNameList[i].upper()}>>`" + \
|
||||
"|" + regPrivModeList[i] + regPrivAccessList[i] + \
|
||||
"|" + str(regDescrList[i]) + "\n"
|
||||
r += "|===\n\n"
|
||||
|
||||
r += "==== Register Description\n\n"
|
||||
for reg in registerlist:
|
||||
if reg.RV32 | reg.RV64:
|
||||
r += "[[%s]]\n"%self.generate_label(reg.name)
|
||||
r += "===== %s\n\n"%reg.name.upper()
|
||||
|
||||
r += "Address:: %s\n"%reg.address
|
||||
if reg.resetValue:
|
||||
# display the resetvalue in hex notation in the full length of the register
|
||||
r += "Reset Value:: 0x%s\n"%f"{reg.resetValue[2:].zfill(int(reg.size/4))}"
|
||||
# RO/RW privileges are encoded in register address.
|
||||
r += "Privilege:: %s\n"%(reg.access + self.get_access_privilege(reg))
|
||||
r += "Description:: %s\n\n"%(reg.desc)
|
||||
|
||||
reg_table = []
|
||||
for field in reg.field:
|
||||
if field.bitWidth == 1: # only one bit -> no range needed
|
||||
bits = f"{field.bitlsb}"
|
||||
else:
|
||||
bits = f"[{field.bitmsb}:{field.bitlsb}]"
|
||||
_line = [
|
||||
bits,
|
||||
field.name.upper(),
|
||||
field.fieldreset,
|
||||
field.fieldaccess,
|
||||
(
|
||||
Render.bitmask(field.andMask, field.orMask)
|
||||
if field.andMask and field.orMask
|
||||
else field.bitlegal
|
||||
),
|
||||
]
|
||||
_line.append(field.fieldDesc)
|
||||
reg_table.append(_line)
|
||||
|
||||
reg_table = sorted(
|
||||
reg_table, key=lambda x: int(x[0].strip("[]").split(":")[0])
|
||||
)
|
||||
# table of the register
|
||||
r += "|===\n"
|
||||
r += "| Bits | Field Name | Reset Value | Type | Legal Values | Description\n\n"
|
||||
for reg in reg_table:
|
||||
for col in reg:
|
||||
if col == 'Reserved':
|
||||
col = "_Reserved_"
|
||||
r +="| %s "%col.replace('\n','').replace('|', '\|')
|
||||
r += "\n"
|
||||
r += "|===\n\n"
|
||||
|
||||
return r
|
||||
|
||||
class InstadocBlock(InstructionBlockClass):
|
||||
"""Generates a ISA AsciiDoc file from RISC-V Config Yaml register description"""
|
||||
|
||||
def __init__(self, name):
|
||||
super().__init__("isa")
|
||||
self.name = name
|
||||
self.Instructionlist = []
|
||||
self.suffix = ".adoc"
|
||||
|
||||
def returnAsString(self):
|
||||
r = ""
|
||||
InstrNameList = [reg.key for reg in self.Instructionlist]
|
||||
InstrDescrList = [reg.descr for reg in self.Instructionlist]
|
||||
InstrExtList = [reg.Extension_Name for reg in self.Instructionlist]
|
||||
|
||||
r += "////\n"
|
||||
r += " Copyright (c) 2024 OpenHW Group\n"
|
||||
r += " Copyright (c) 2024 Thales\n"
|
||||
r += " SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1\n"
|
||||
r += " Author: Abdessamii Oukalrazqou\n"
|
||||
r += "////\n\n"
|
||||
|
||||
r += "=== %s\n\n"%self.name
|
||||
r += "==== Instructions\n\n"
|
||||
|
||||
r += "|===\n"
|
||||
r += "|Subset Name | Name | Description\n\n"
|
||||
for i, _ in enumerate(InstrNameList):
|
||||
r += "|%s | %s | %s\n"%(str(InstrExtList[i]),
|
||||
str(InstrNameList[i]),
|
||||
str(InstrDescrList[i]).replace('\n',''))
|
||||
r += "|===\n\n"
|
||||
|
||||
for reg in self.Instructionlist:
|
||||
reg_table = []
|
||||
if len(reg.Name) > 0:
|
||||
r += "==== %s\n\n"%reg.key
|
||||
r += "|===\n"
|
||||
r += "| Name | Format | Pseudocode|Invalid_values | Exception_raised | Description| Op Name\n\n"
|
||||
|
||||
for fieldIndex in list(range(len(reg.Name))):
|
||||
_line = [
|
||||
reg.Name[fieldIndex],
|
||||
reg.Format[fieldIndex],
|
||||
reg.pseudocode[fieldIndex].replace('|','\|'),
|
||||
reg.invalid_values[fieldIndex],
|
||||
reg.exception_raised[fieldIndex],
|
||||
reg.Description[fieldIndex],
|
||||
]
|
||||
_line.append(reg.OperationName[fieldIndex])
|
||||
|
||||
for col in _line:
|
||||
r +="| %s "%col.replace('\n','')
|
||||
r += "\n"
|
||||
r += "|===\n\n"
|
||||
return r
|
||||
|
||||
class InstmdBlock(InstructionBlockClass):
|
||||
"""Generates a ISA Markdown file from a RISC Config Yaml register description"""
|
||||
"""Generates an ISA Markdown file from a RISC Config Yaml register description"""
|
||||
|
||||
def __init__(self, name):
|
||||
super().__init__("isa")
|
||||
|
@ -466,6 +840,12 @@ class MdAddressBlock(AddressBlockClass):
|
|||
regNameList = [reg.name for reg in registerlist if reg.RV32 | reg.RV64]
|
||||
regAddressList = [reg.address for reg in registerlist if reg.RV32 | reg.RV64]
|
||||
regDescrList = [reg.desc for reg in registerlist if reg.RV32 | reg.RV64]
|
||||
regAccessList = [
|
||||
self.get_access_privilege(reg)
|
||||
for reg in registerlist
|
||||
if reg.RV32 | reg.RV64
|
||||
]
|
||||
regPrivModeList = [reg.access for reg in registerlist if reg.RV32 | reg.RV64]
|
||||
licence = [
|
||||
"<!--Copyright (c) 2024 OpenHW Group",
|
||||
"Copyright (c) 2024 Thales",
|
||||
|
@ -480,8 +860,9 @@ class MdAddressBlock(AddressBlockClass):
|
|||
) # Use the name of the addressBlock as title
|
||||
self.mdFile.new_paragraph()
|
||||
self.mdFile.new_header(level=2, title="Registers Summary")
|
||||
self.mdFile.new_paragraph()
|
||||
# summary
|
||||
header = ["Address", "Register Name", "Description"]
|
||||
header = ["Address", "Register Name", "Privilege", "Description"]
|
||||
rows = []
|
||||
for i, _ in enumerate(regNameList):
|
||||
regDescrList[i] = str(regDescrList[i]).replace("\n", " ")
|
||||
|
@ -489,6 +870,7 @@ class MdAddressBlock(AddressBlockClass):
|
|||
[
|
||||
regAddressList[i],
|
||||
f"[{regNameList[i].upper()}](#{regNameList[i].upper()})",
|
||||
regPrivModeList[i] + regAccessList[i],
|
||||
str(regDescrList[i]),
|
||||
]
|
||||
)
|
||||
|
@ -503,7 +885,11 @@ class MdAddressBlock(AddressBlockClass):
|
|||
for reg in registerlist:
|
||||
if reg.RV64 | reg.RV32:
|
||||
self.returnMdRegDesc(
|
||||
reg.name, reg.address, reg.resetValue, reg.desc, reg.access
|
||||
reg.name,
|
||||
reg.address,
|
||||
reg.resetValue,
|
||||
reg.desc,
|
||||
reg.access + self.get_access_privilege(reg),
|
||||
)
|
||||
reg_table = []
|
||||
_line = []
|
||||
|
@ -516,13 +902,13 @@ class MdAddressBlock(AddressBlockClass):
|
|||
[
|
||||
bits,
|
||||
field.name.upper(),
|
||||
field.bitlegal,
|
||||
field.fieldreset,
|
||||
field.fieldaccess,
|
||||
field.bitlegal,
|
||||
field.fieldDesc,
|
||||
]
|
||||
)
|
||||
_headers = ["Bits", "Field Name", "Legal Values", "Reset", "Type"]
|
||||
_headers = ["Bits", "Field Name", "Reset Value", "Type", "Legal Values"]
|
||||
_headers.append("Description")
|
||||
reg_table = sorted(
|
||||
reg_table, key=lambda x: int(x[0].strip("[]").split(":")[0])
|
||||
|
@ -546,7 +932,7 @@ class MdAddressBlock(AddressBlockClass):
|
|||
if resetValue:
|
||||
# display the resetvalue in hex notation in the full length of the register
|
||||
self.mdFile.new_line("**Reset Value** " + resetValue)
|
||||
self.mdFile.new_line("**Privilege Mode** " + access)
|
||||
self.mdFile.new_line("**Privilege** " + access)
|
||||
self.mdFile.new_line("**Description** " + desc)
|
||||
|
||||
|
||||
|
@ -554,8 +940,10 @@ class MdAddressBlock(AddressBlockClass):
|
|||
class CsrParser:
|
||||
"""parse CSR RISC-V config yaml file"""
|
||||
|
||||
def __init__(self, srcFile, target, modiFile=None):
|
||||
def __init__(self, srcFile, customFile, debugfile, target, modiFile=None):
|
||||
self.srcFile = srcFile
|
||||
self.customFile = customFile
|
||||
self.debugfile = debugfile
|
||||
self.modiFile = modiFile
|
||||
self.target = target
|
||||
|
||||
|
@ -576,6 +964,8 @@ class CsrParser:
|
|||
field = []
|
||||
if len(fieldList) > 0:
|
||||
for item in fieldList:
|
||||
andMask = None
|
||||
orMask = None
|
||||
if not isinstance(item, list):
|
||||
fieldDesc = registerElem.get("rv32", "")[item].get(
|
||||
"description", ""
|
||||
|
@ -592,14 +982,20 @@ class CsrParser:
|
|||
)
|
||||
fieldaccess = ""
|
||||
legal = registerElem.get("rv32", "")[item].get("type", None)
|
||||
implemented = registerElem.get("rv32", "")[item].get(
|
||||
"implemented", None
|
||||
)
|
||||
if legal is None:
|
||||
bitlegal = ""
|
||||
fieldaccess = "WARL"
|
||||
if not implemented:
|
||||
bitlegal = "0x0"
|
||||
else:
|
||||
bitlegal = ""
|
||||
fieldaccess = "ROCST"
|
||||
fieldDesc = fieldDesc
|
||||
else:
|
||||
warl = re.findall(pattern_warl, str(legal.keys()))
|
||||
if warl:
|
||||
fieldaccess = warl[0].upper()
|
||||
fieldaccess = Render.fieldtype(warl[0])
|
||||
legal_2 = (
|
||||
registerElem.get("rv32", "")[item]
|
||||
.get("type", None)
|
||||
|
@ -609,21 +1005,68 @@ class CsrParser:
|
|||
bitlegal = "No Legal values"
|
||||
else:
|
||||
if isinstance(legal_2, dict):
|
||||
pattern = r"([\w\[\]:]+\s*\w+\s*)(\[\s*((?:0x)?[0-9A-Fa-f]+)\s*\D+\s*(?:((?:0x)?[0-9A-Fa-f]+))?\s*])"
|
||||
# TODO: Need a pattern that supports arbitrary lists of values in matches(3).
|
||||
pattern = r"([\w\[\]:]+)\s*(\w+)\s*(\[\s*((?:0x)?[0-9A-Fa-f]+)\s*\D+\s*(?:((?:0x)?[0-9A-Fa-f]+))?\s*])"
|
||||
matches = re.search(
|
||||
pattern, str(legal_2["legal"][0])
|
||||
)
|
||||
if matches:
|
||||
legal_value = matches.group(2)
|
||||
expr_type = str(matches.group(2))
|
||||
if expr_type == "bitmask":
|
||||
andMask = str(matches.group(4))
|
||||
orMask = str(matches.group(5))
|
||||
legal_value = Render.bitmask(
|
||||
andMask, orMask
|
||||
)
|
||||
elif expr_type == "in":
|
||||
if matches.group(3).find(",") >= 0:
|
||||
# list ==> set of values
|
||||
legal_value = Render.value_set(
|
||||
matches.group(3)
|
||||
.strip("[]")
|
||||
.split(",")
|
||||
)
|
||||
elif matches.group(3).find(":") >= 0:
|
||||
# Range
|
||||
(start, end) = (
|
||||
matches.group(3)
|
||||
.strip("[]")
|
||||
.split(":")
|
||||
)
|
||||
legal_value = Render.range(start, end)
|
||||
else:
|
||||
# Singleton
|
||||
legal_value = matches.group(3).strip(
|
||||
"[]"
|
||||
)
|
||||
else:
|
||||
legal_value = matches.group(3)
|
||||
bitlegal = legal_value
|
||||
elif isinstance(legal_2, list):
|
||||
pattern = r"\s*((?:0x)?[0-9A-Fa-f]+)\s*(.)\s*((?:0x)?[0-9A-Fa-f]+)\s*"
|
||||
matches = re.search(pattern, legal_2[0])
|
||||
if matches:
|
||||
legal_value = (
|
||||
f"[{matches.group(1)} , {matches.group(3)}]"
|
||||
)
|
||||
|
||||
pattern = r"\s*((?:0x)?[0-9A-Fa-f]+)\s*(:|,?)\s*((?:0x)?[0-9A-Fa-f]+)?"
|
||||
for value in legal_2:
|
||||
value_list = value.split(",")
|
||||
processed_values = []
|
||||
for val in value_list:
|
||||
matches = re.search(pattern, val)
|
||||
if matches:
|
||||
first_value = matches.group(1)
|
||||
separator = matches.group(2)
|
||||
second_value = (
|
||||
matches.group(3)
|
||||
if matches.group(3)
|
||||
else first_value
|
||||
)
|
||||
if separator == ":":
|
||||
processed_value = Render.range(
|
||||
first_value, second_value
|
||||
)
|
||||
else:
|
||||
processed_value = hex(
|
||||
int(first_value)
|
||||
)
|
||||
processed_values.append(processed_value)
|
||||
legal_value = Render.value_set(processed_values)
|
||||
bitlegal = legal_value
|
||||
else:
|
||||
legal_value = hex(legal_2)
|
||||
|
@ -633,9 +1076,13 @@ class CsrParser:
|
|||
if match:
|
||||
match_field = re.search(Factorizer_pattern, str(item))
|
||||
if match_field:
|
||||
if match_field.group(0) not in {"0", "1", "2", "3"}:
|
||||
field_number = int(match_field.group(0)) - 8
|
||||
else:
|
||||
field_number = match_field.group(0)
|
||||
fieldName = re.sub(
|
||||
match_field.group(1),
|
||||
f"[i*4 + {match_field.group(1)}]",
|
||||
Factorizer_pattern,
|
||||
f"[i*4 +{field_number}]",
|
||||
item,
|
||||
)
|
||||
else:
|
||||
|
@ -649,6 +1096,8 @@ class CsrParser:
|
|||
bitWidth,
|
||||
fieldDesc,
|
||||
fieldaccess,
|
||||
andMask,
|
||||
orMask,
|
||||
)
|
||||
field.append(f)
|
||||
elif isinstance(item, list):
|
||||
|
@ -659,7 +1108,7 @@ class CsrParser:
|
|||
legal = ""
|
||||
fieldaccess = "WPRI"
|
||||
bitWidth = int(item_[len(item_) - 1]) - int(item_[0]) + 1
|
||||
fieldDesc = "RESERVED"
|
||||
fieldDesc = "Reserved"
|
||||
bitlegal = legal
|
||||
fieldreset = hex(
|
||||
int(resetValue, 16) >> (bitlsb) & ((1 << ((bitWidth))) - 1)
|
||||
|
@ -699,6 +1148,8 @@ class CsrParser:
|
|||
bitlsb = registerElem.get("rv32", None).get("lsb", None)
|
||||
legal = registerElem.get("rv32", "").get("type", None)
|
||||
fieldaccess = ""
|
||||
andMask = None
|
||||
orMask = None
|
||||
if legal is None:
|
||||
bitlegal = ""
|
||||
bitmask = ""
|
||||
|
@ -706,7 +1157,7 @@ class CsrParser:
|
|||
else:
|
||||
warl = re.findall(pattern_warl, str(legal.keys()))
|
||||
if warl:
|
||||
fieldaccess = warl[0].upper()
|
||||
fieldaccess = Render.fieldtype(warl[0])
|
||||
legal_2 = (
|
||||
registerElem.get("rv32", "")
|
||||
.get("type", None)
|
||||
|
@ -716,28 +1167,64 @@ class CsrParser:
|
|||
bitlegal = "No Legal values"
|
||||
else:
|
||||
if isinstance(legal_2, dict):
|
||||
pattern = r"([\w\[\]:]+\s*\w+\s*)(\[\s*((?:0x)?[0-9A-Fa-f]+)\s*\D+\s*(?:((?:0x)?[0-9A-Fa-f]+))?\s*])"
|
||||
pattern = r"([\w\[\]:]+\s*(\w+)\s*)(\[\s*((?:0x)?[0-9A-Fa-f]+)\s*\D+\s*(?:((?:0x)?[0-9A-Fa-f]+))?\s*])"
|
||||
matches = re.search(pattern, str(legal_2["legal"][0]))
|
||||
if matches:
|
||||
legal_value = (
|
||||
f"[{matches.group(3)} , {matches.group(4)}]"
|
||||
legal_value = Render.range(
|
||||
matches.group(4), matches.group(5)
|
||||
)
|
||||
mask = matches.group(4)
|
||||
expr_type = str(matches.group(2))
|
||||
mask = matches.group(5)
|
||||
bitmask = mask
|
||||
bitlegal = legal_value
|
||||
if expr_type == "bitmask":
|
||||
andMask = str(matches.group(4))
|
||||
orMask = str(matches.group(5))
|
||||
elif expr_type == "in":
|
||||
if matches.group(3).find(",") >= 0:
|
||||
# list ==> set of values
|
||||
legal_value = Render.value_set(
|
||||
matches.group(3).strip("[]").split(",")
|
||||
)
|
||||
elif matches.group(3).find(":") >= 0:
|
||||
# Range
|
||||
(start, end) = (
|
||||
matches.group(3).strip("[]").split(":")
|
||||
)
|
||||
legal_value = Render.range(start, end)
|
||||
else:
|
||||
# Singleton
|
||||
legal_value = matches.group(3).strip("[]")
|
||||
else:
|
||||
legal_value = matches.group(3)
|
||||
bitlegal = legal_value
|
||||
elif isinstance(legal_2, list):
|
||||
pattern = r"([0-9A-Fa-f]+).*([0-9A-Fa-f]+)"
|
||||
matches = re.search(pattern, legal_2[0])
|
||||
if matches:
|
||||
legal_value = (
|
||||
f"[{matches.group(1)} , {matches.group(2)}]"
|
||||
)
|
||||
mask = matches.group(2)
|
||||
bitmask = mask
|
||||
pattern = r"\s*((?:0x)?[0-9A-Fa-f]+)\s*(:|,?)\s*((?:0x)?[0-9A-Fa-f]+)?"
|
||||
for value in legal_2:
|
||||
value_list = value.split(",")
|
||||
processed_values = []
|
||||
for val in value_list:
|
||||
matches = re.search(pattern, val)
|
||||
if matches:
|
||||
first_value = matches.group(1)
|
||||
separator = matches.group(2)
|
||||
second_value = (
|
||||
matches.group(3)
|
||||
if matches.group(3)
|
||||
else first_value
|
||||
)
|
||||
if separator == ":":
|
||||
processed_value = Render.range(
|
||||
first_value, second_value
|
||||
)
|
||||
else:
|
||||
processed_value = hex(int(first_value))
|
||||
processed_values.append(processed_value)
|
||||
legal_value = Render.value_set(processed_values)
|
||||
bitlegal = legal_value
|
||||
else:
|
||||
bitmask = 0
|
||||
bitlegal = "0x" + hex(legal_2)[2:].zfill(int(size / 4))
|
||||
legal_value = hex(legal_2)
|
||||
bitlegal = legal_value
|
||||
fieldDesc = regDesc
|
||||
fieldreset = "0x" + hex(int(resetValue, 16))[2:].zfill(int(size / 4))
|
||||
if bitlsb is None:
|
||||
|
@ -766,9 +1253,14 @@ class CsrParser:
|
|||
def returnDocument(self):
|
||||
with open(self.srcFile, "r", encoding="utf-8") as f:
|
||||
data = yaml.safe_load(f)
|
||||
data = csr_formatter(self.srcFile, self.modiFile)
|
||||
Registers = factorizer(data)
|
||||
docName = data["hart0"]
|
||||
size = int(
|
||||
data["hart0"].get("supported_xlen", "")[0]
|
||||
) # depends on architecture
|
||||
data = csr_formatter(
|
||||
self.srcFile, self.customFile, self.debugfile, self.modiFile
|
||||
)
|
||||
Registers = factorizer(data)
|
||||
d = DocumentClass(docName)
|
||||
m = MemoryMapClass(docName)
|
||||
a = AddressBlockClass("csr")
|
||||
|
@ -782,7 +1274,7 @@ class CsrParser:
|
|||
else hex(RegElement.get("address", None))
|
||||
)
|
||||
reset = hex(RegElement.get("reset-val", ""))
|
||||
size = int(data["hart0"].get("supported_xlen", "")[0])
|
||||
|
||||
access = RegElement.get("priv_mode", "")
|
||||
if Registers.get(register, {}).get("description", "") is not None:
|
||||
desc = Registers.get(register, {}).get("description", "")
|
||||
|
@ -898,6 +1390,96 @@ class IsaParser:
|
|||
return Inst
|
||||
|
||||
|
||||
class SpikeParser:
|
||||
"""A class to parse data related to Spike."""
|
||||
|
||||
def __init__(self, srcFile, target):
|
||||
self.srcFile = srcFile
|
||||
self.target = target
|
||||
|
||||
def returnDocument(self):
|
||||
with open(self.srcFile, "r", encoding="utf-8") as f:
|
||||
data = yaml.safe_load(f)
|
||||
core_configs = []
|
||||
pattern = r"pmpaddr(\d+)"
|
||||
index = 0
|
||||
bitWidth = 32
|
||||
isa = ""
|
||||
for entry in data["hart_ids"]:
|
||||
M = (
|
||||
"M"
|
||||
if data[f"hart{entry}"]
|
||||
.get("mstatus", {})
|
||||
.get("rv32", "")
|
||||
.get("accessible", [])
|
||||
else ""
|
||||
)
|
||||
S = (
|
||||
"S"
|
||||
if data[f"hart{entry}"]
|
||||
.get("sstatus", {})
|
||||
.get("rv32", "")
|
||||
.get("accessible", [])
|
||||
else ""
|
||||
)
|
||||
U = (
|
||||
"U"
|
||||
if data[f"hart{entry}"]
|
||||
.get("ustatus", {})
|
||||
.get("rv32", "")
|
||||
.get("accessible", [])
|
||||
else ""
|
||||
)
|
||||
for k in data[f"hart{entry}"].keys():
|
||||
match = re.search(pattern, str(k))
|
||||
if match:
|
||||
index += int(match.group(1))
|
||||
isa = data[f"hart{entry}"]["ISA"].lower()
|
||||
core_config = CoreConfig(
|
||||
isa=data[f"hart{entry}"]["ISA"].lower(),
|
||||
marchid=data[f"hart{entry}"].get("marchid", {}).get("reset-val", ""),
|
||||
misa_we=False,
|
||||
misa_we_enable=True,
|
||||
misaligned=data[f"hart{entry}"].get("hw_data_misaligned_support", ""),
|
||||
mmu_mode=(
|
||||
"bare"
|
||||
if not (
|
||||
(int(data[f"hart{entry}"].get("satp", {}).get("reset-val", "")))
|
||||
>> 31
|
||||
)
|
||||
else "sv32"
|
||||
),
|
||||
mvendorid=data[f"hart{entry}"]
|
||||
.get("mvendorid", {})
|
||||
.get("reset-val", ""),
|
||||
pmpaddr0=data[f"hart{entry}"].get("pmpaddr0", {}).get("reset-val", ""),
|
||||
pmpcfg0=data[f"hart{entry}"].get("pmpcfg0", {}).get("reset-val", ""),
|
||||
pmpregions=index,
|
||||
priv=f"{M}{S}{U}".format(M, S, U),
|
||||
status_fs_field_we=False,
|
||||
status_fs_field_we_enable=False,
|
||||
status_vs_field_we=False,
|
||||
status_vs_field_we_enable=False,
|
||||
)
|
||||
core_configs.append(core_config)
|
||||
S = Spike(
|
||||
bootrom=True,
|
||||
bootrom_base=0x10000,
|
||||
bootrom_size=0x1000,
|
||||
dram=True,
|
||||
dram_base=0x80000000,
|
||||
dram_size=0x40000000,
|
||||
generic_core_config=False,
|
||||
max_steps=200000,
|
||||
max_steps_enabled=False,
|
||||
isa=isa,
|
||||
priv=f"{M}{S}{U}".format(M, S, U),
|
||||
core_configs=core_configs,
|
||||
)
|
||||
|
||||
return S
|
||||
|
||||
|
||||
class IsaGenerator:
|
||||
"""generate isa folder with isa docs"""
|
||||
|
||||
|
@ -937,7 +1519,6 @@ class CsrGenerator:
|
|||
|
||||
def write(self, file_name, string):
|
||||
path = f"./{self.target}/csr/"
|
||||
print(path)
|
||||
if not os.path.exists(path):
|
||||
os.makedirs(path)
|
||||
_dest = os.path.join(path, file_name)
|
||||
|
@ -957,3 +1538,28 @@ class CsrGenerator:
|
|||
s = block.returnAsString()
|
||||
file_name = blockName + block.suffix
|
||||
self.write(file_name, s)
|
||||
|
||||
|
||||
class SpikeGenerator:
|
||||
"""Generate spike folder with spike docs"""
|
||||
|
||||
def __init__(self, target, temp, modiFile=None):
|
||||
self.target = target
|
||||
self.temp = temp
|
||||
self.modiFile = modiFile
|
||||
|
||||
def write(self, file_name, string):
|
||||
path = f"./{self.target}/spike/"
|
||||
if not os.path.exists(path):
|
||||
os.makedirs(path)
|
||||
_dest = os.path.join(path, file_name)
|
||||
print("writing file " + _dest)
|
||||
with open(_dest, "w", encoding="utf-8") as f:
|
||||
yaml.dump(string, f, default_flow_style=False, sort_keys=False)
|
||||
|
||||
def generateSpike(self, document):
|
||||
template = Template(filename=self.temp)
|
||||
s = template.render(spike=document)
|
||||
data = spike_formatter(yaml.load(s, Loader=BaseLoader), self.modiFile)
|
||||
file_name = "spike.yaml"
|
||||
self.write(file_name, data)
|
||||
|
|
|
@ -13,36 +13,64 @@
|
|||
# limitations under the License.
|
||||
#
|
||||
# Original Author: Oukalrazqou Abdessamii
|
||||
""" Module is used to factorize multiples registers with the same name to
|
||||
a specific format of registers """
|
||||
"""Module is used to factorize multiples registers with the same name to
|
||||
a specific format of registers"""
|
||||
|
||||
import argparse
|
||||
|
||||
from libs.utils import CsrParser
|
||||
from libs.utils import IsaParser
|
||||
from libs.utils import SpikeParser
|
||||
from libs.utils import IsaGenerator
|
||||
from libs.utils import CsrGenerator
|
||||
from libs.utils import SpikeGenerator
|
||||
from libs.utils import RstAddressBlock
|
||||
from libs.utils import AdocAddressBlock
|
||||
from libs.utils import MdAddressBlock
|
||||
from libs.utils import InstrstBlock
|
||||
from libs.utils import InstadocBlock
|
||||
from libs.utils import InstmdBlock
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="ipxact2rst")
|
||||
parser.add_argument("-s", "--srcFile", help="yaml input file")
|
||||
parser.add_argument("-d", "--destDir", help="write generated file to dir")
|
||||
parser = argparse.ArgumentParser(description="GEN From RISC-V Config")
|
||||
parser.add_argument("-s", "--srcFile", help="isa_gen yaml input file")
|
||||
parser.add_argument("-c", "--customFile", help=" custom_gen yaml input file")
|
||||
parser.add_argument("-d", "--debugFile", help=" debug_gen yaml input file")
|
||||
parser.add_argument("-m", "--modif", help="ISA /CSR Formatter if exist")
|
||||
parser.add_argument("-i", "--temp", help="Full ISA Template")
|
||||
parser.add_argument("-i", "--temp", help="Full ISA /SPIKETemplate")
|
||||
parser.add_argument("-t", "--target", help="Specifiy Config Name")
|
||||
parser.add_argument("-f", "--format", help="Specifiy format output")
|
||||
args, unknown_args = parser.parse_known_args()
|
||||
if args.temp:
|
||||
e = IsaParser(args.srcFile, args.temp, args.target, args.modif)
|
||||
document = e.returnDocument()
|
||||
generator = IsaGenerator(args.target)
|
||||
generator.generateISA(InstrstBlock, document)
|
||||
generator.generateISA(InstmdBlock, document)
|
||||
|
||||
if args.format in ['rst']:
|
||||
C_instrBlock = InstrstBlock
|
||||
C_AddressBlock = RstAddressBlock
|
||||
elif args.format in ['adoc']:
|
||||
C_instrBlock = InstadocBlock
|
||||
C_AddressBlock = AdocAddressBlock
|
||||
elif args.format in ['md']:
|
||||
C_instrBlock = InstmdBlock
|
||||
C_AddressBlock = MdAddressBlock
|
||||
else:
|
||||
e = CsrParser(args.srcFile, args.target, args.modif)
|
||||
C_instrBlock = InstrstBlock
|
||||
C_AddressBlock = RstAddressBlock
|
||||
|
||||
if args.temp:
|
||||
if "isa" in args.temp:
|
||||
e = IsaParser(args.srcFile, args.temp, args.target, args.modif)
|
||||
document = e.returnDocument()
|
||||
generator = IsaGenerator(args.target)
|
||||
generator.generateISA(C_instrBlock, document)
|
||||
elif "spike" in args.temp:
|
||||
e = SpikeParser(args.srcFile, args.target)
|
||||
document = e.returnDocument()
|
||||
spike_generator = SpikeGenerator(args.target, args.temp, args.modif)
|
||||
spike_generator.generateSpike(document)
|
||||
else:
|
||||
e = CsrParser(
|
||||
args.srcFile, args.customFile, args.debugFile, args.target, args.modif
|
||||
)
|
||||
document = e.returnDocument()
|
||||
generator = CsrGenerator(args.target)
|
||||
generator.generateCSR(RstAddressBlock, document)
|
||||
generator.generateCSR(MdAddressBlock, document)
|
||||
generator.generateCSR(C_AddressBlock, document)
|
||||
|
|
53
config/gen_from_riscv_config/templates/spike.mako
Normal file
53
config/gen_from_riscv_config/templates/spike.mako
Normal file
|
@ -0,0 +1,53 @@
|
|||
# Copyright 2024 Thales DIS France SAS
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Original Author: Oukalrazqou Abdessamii
|
||||
|
||||
<%!
|
||||
def format_hex(value):
|
||||
return f"0x{value:X}"
|
||||
|
||||
def format_bool(value):
|
||||
return "true" if value else "false"
|
||||
%>
|
||||
spike_param_tree:
|
||||
bootrom: ${format_bool(spike.bootrom)}
|
||||
bootrom_base: ${format_hex(spike.bootrom_base)}
|
||||
bootrom_size: ${format_hex(spike.bootrom_size)}
|
||||
dram: ${format_bool(spike.dram)}
|
||||
dram_base: ${format_hex(spike.dram_base)}
|
||||
dram_size: ${format_hex(spike.dram_size)}
|
||||
generic_core_config: ${format_bool(spike.generic_core_config)}
|
||||
max_steps: ${spike.max_steps}
|
||||
max_steps_enabled: ${format_bool(spike.max_steps_enabled)}
|
||||
isa: ${spike.isa}
|
||||
priv: ${spike.priv}
|
||||
core_configs:
|
||||
% for core in spike.core_configs:
|
||||
- isa: ${core.isa}
|
||||
marchid: ${format_hex(core.marchid)}
|
||||
misa_we: ${format_bool(core.misa_we)}
|
||||
misa_we_enable: ${format_bool(core.misa_we_enable)}
|
||||
misaligned: ${format_bool(core.misaligned)}
|
||||
mmu_mode: ${core.mmu_mode}
|
||||
mvendorid: ${format_hex(core.mvendorid)}
|
||||
pmpaddr0: ${format_hex(core.pmpaddr0)}
|
||||
pmpcfg0: ${format_hex(core.pmpcfg0)}
|
||||
pmpregions: ${format_hex(core.pmpregions)}
|
||||
priv: ${core.priv}
|
||||
status_fs_field_we: ${format_bool(core.status_fs_field_we)}
|
||||
status_fs_field_we_enable: ${format_bool(core.status_fs_field_we_enable)}
|
||||
status_vs_field_we: ${format_bool(core.status_vs_field_we)}
|
||||
status_vs_field_we_enable: ${format_bool(core.status_vs_field_we_enable)}
|
||||
% endfor
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,31 @@
|
|||
# Copyright (c) 2024 OpenHW Group
|
||||
# Copyright (c) 2024 Thales
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
||||
# Author: Abdessamii Oukalrazqou
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cores:
|
||||
- isa: rv32imc_zba_zbb_zbs_zbc_zicsr_zifencei
|
||||
boot_addr: 0x80000000
|
||||
marchid: 0x3
|
||||
misa_we: false
|
||||
misa_we_enable: true
|
||||
pmpaddr0: 0x0
|
||||
pmpcfg0: 0x0
|
||||
pmpregions: 0x40
|
||||
usable_pmpregions : 0x8
|
||||
priv: M
|
||||
status_fs_field_we: false
|
||||
status_fs_field_we_enable: false
|
||||
status_vs_field_we: false
|
||||
status_vs_field_we_enable: false
|
||||
priv: M
|
||||
misa_we: false
|
||||
mstatus_write_mask: 0x00000088
|
||||
mstatus_override_mask: 0x00001800
|
||||
mtval_write_mask: 0x00000000
|
||||
unified_traps: true
|
||||
|
|
@ -27,22 +27,16 @@ hart0:
|
|||
type:
|
||||
rw: true
|
||||
description: bit for cache-enable of instruction cache
|
||||
shadow:
|
||||
shadow_type:
|
||||
msb: 0
|
||||
lsb: 0
|
||||
reserved_0:
|
||||
implemented: true
|
||||
description: reserved for future use
|
||||
type:
|
||||
ro_constant: 0x0
|
||||
shadow:
|
||||
shadow_type:
|
||||
msb: 31
|
||||
lsb: 1
|
||||
fields:
|
||||
- icache
|
||||
- reserved_0
|
||||
-
|
||||
-
|
||||
- 1
|
||||
- 31
|
||||
description: the register controls the operation of the i-cache unit.
|
||||
address: 0x7c0
|
||||
priv_mode: M
|
||||
|
@ -61,18 +55,12 @@ hart0:
|
|||
shadow_type:
|
||||
msb: 0
|
||||
lsb: 0
|
||||
reserved_0:
|
||||
implemented: true
|
||||
description: reserved for future use
|
||||
type:
|
||||
ro_constant: 0x0
|
||||
shadow:
|
||||
shadow_type:
|
||||
msb: 31
|
||||
lsb: 1
|
||||
fields:
|
||||
- dcache
|
||||
- reserved_0
|
||||
-
|
||||
-
|
||||
- 1
|
||||
- 31
|
||||
description: the register controls the operation of the d-cache unit.
|
||||
address: 0x7c1
|
||||
priv_mode: M
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -21,6 +21,27 @@ reset:
|
|||
mtime:
|
||||
implemented: true
|
||||
address: 0x20000
|
||||
memory_map:
|
||||
-
|
||||
memory_region:
|
||||
name: bootrom
|
||||
base_addr: 0x10000
|
||||
size: 0x10000
|
||||
description: System boot ROM
|
||||
attributes:
|
||||
read_only: true
|
||||
cached: false
|
||||
-
|
||||
memory_region:
|
||||
name: dram
|
||||
base_addr: 0x80000000
|
||||
size: 0x40000000
|
||||
description: System (D)RAM
|
||||
attributes:
|
||||
executable: true
|
||||
cached: true
|
||||
non_idempotent: false
|
||||
read_only: false
|
||||
mtimecmp:
|
||||
implemented: false
|
||||
mtval_condition_writes:
|
||||
|
|
|
@ -27,19 +27,10 @@ hart0:
|
|||
type:
|
||||
rw: true
|
||||
description: bit for cache-enable of instruction cache
|
||||
shadow:
|
||||
shadow_type:
|
||||
msb: 0
|
||||
lsb: 0
|
||||
reserved_0:
|
||||
implemented: true
|
||||
description: reserved for future use
|
||||
type:
|
||||
ro_constant: 0x0
|
||||
shadow:
|
||||
shadow_type:
|
||||
msb: 31
|
||||
lsb: 1
|
||||
description: the register controls the operation of the i-cache unit.
|
||||
address: 0x7c0
|
||||
priv_mode: M
|
||||
|
@ -58,15 +49,6 @@ hart0:
|
|||
shadow_type:
|
||||
msb: 0
|
||||
lsb: 0
|
||||
reserved_0:
|
||||
implemented: true
|
||||
description: reserved for future use
|
||||
type:
|
||||
ro_constant: 0x0
|
||||
shadow:
|
||||
shadow_type:
|
||||
msb: 31
|
||||
lsb: 1
|
||||
description: the register controls the operation of the d-cache unit.
|
||||
address: 0x7c1
|
||||
priv_mode: M
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -19,5 +19,19 @@ nmi:
|
|||
reset:
|
||||
label: reset_vector
|
||||
mtime:
|
||||
implemented: True
|
||||
implemented: true
|
||||
address: 0x20000
|
||||
memory_map:
|
||||
- memory_region:
|
||||
name: bootrom
|
||||
base_addr: 0x10000
|
||||
size: 0x10000
|
||||
description: System boot ROM
|
||||
attributes:
|
||||
read_only: true
|
||||
cached: false
|
||||
- memory_region:
|
||||
name: dram
|
||||
base_addr: 0x80000000
|
||||
size: 0x40000000
|
||||
description: System (D)RAM
|
||||
|
|
55
config/riscv-config/cv64a60ax/spec/custom_spec.yaml
Normal file
55
config/riscv-config/cv64a60ax/spec/custom_spec.yaml
Normal file
|
@ -0,0 +1,55 @@
|
|||
# Copyright 2024 Thales DIS France SAS
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Original Author: Zbigniew CHAMSKI - Thales
|
||||
|
||||
hart_ids: [0]
|
||||
hart0:
|
||||
icache:
|
||||
reset-val: 0x1
|
||||
rv32:
|
||||
accessible: false
|
||||
rv64:
|
||||
accessible: true
|
||||
icache:
|
||||
implemented: true
|
||||
type:
|
||||
rw: true
|
||||
description: bit for cache-enable of instruction cache
|
||||
msb: 0
|
||||
lsb: 0
|
||||
shadow:
|
||||
shadow_type:
|
||||
description: the register controls the operation of the i-cache unit.
|
||||
address: 0x7c0
|
||||
priv_mode: M
|
||||
dcache:
|
||||
reset-val: 0x1
|
||||
rv32:
|
||||
accessible: false
|
||||
rv64:
|
||||
accessible: true
|
||||
dcache:
|
||||
implemented: true
|
||||
type:
|
||||
rw: true
|
||||
description: bit for cache-enable of data cache
|
||||
shadow:
|
||||
shadow_type:
|
||||
msb: 0
|
||||
lsb: 0
|
||||
description: the register controls the operation of the d-cache unit.
|
||||
address: 0x7c1
|
||||
priv_mode: M
|
||||
|
168
config/riscv-config/cv64a60ax/spec/debug_spec.yaml
Normal file
168
config/riscv-config/cv64a60ax/spec/debug_spec.yaml
Normal file
|
@ -0,0 +1,168 @@
|
|||
# Copyright 2024 Thales DIS France SAS
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Original Author: Zbigniew CHAMSKI - Thales
|
||||
# Updated from CV66 64 CEA - Tanuj Khandelwal - Thales
|
||||
|
||||
hart_ids: [0]
|
||||
hart0: &hart0
|
||||
Debug_Spec_Version: '1.0.0'
|
||||
supported_xlen: [64]
|
||||
debug_mode: true
|
||||
parking_loop: 0x800
|
||||
dcsr:
|
||||
reset-val: 0x40000413
|
||||
rv64:
|
||||
accessible: true
|
||||
debugver:
|
||||
implemented: true
|
||||
type:
|
||||
ro_constant: 0x4
|
||||
ebreakvs:
|
||||
implemented: false
|
||||
ebreakvu:
|
||||
implemented: false
|
||||
ebreakm:
|
||||
implemented: true
|
||||
ebreaks:
|
||||
implemented: true
|
||||
ebreaku:
|
||||
implemented: true
|
||||
stepie:
|
||||
implemented: true
|
||||
stopcount:
|
||||
implemented: true
|
||||
stoptime:
|
||||
implemented: true
|
||||
cause:
|
||||
implemented: true
|
||||
type:
|
||||
ro_variable: true
|
||||
v:
|
||||
implemented: true
|
||||
mprven:
|
||||
implemented: true
|
||||
nmip:
|
||||
implemented: true
|
||||
type:
|
||||
ro_variable: true
|
||||
step:
|
||||
implemented: true
|
||||
prv:
|
||||
implemented: true
|
||||
rv32:
|
||||
accessible: false
|
||||
dpc:
|
||||
rv64:
|
||||
accessible: true
|
||||
rv32:
|
||||
accessible: false
|
||||
tselect:
|
||||
rv32:
|
||||
accessible: False
|
||||
rv64:
|
||||
accessible: True
|
||||
type:
|
||||
warl:
|
||||
dependency_fields: []
|
||||
legal:
|
||||
- tselect[63:0] in [0x00000000:0x3]
|
||||
wr_illegal:
|
||||
- unchanged
|
||||
tinfo: #FIXME
|
||||
rv32:
|
||||
accessible: False
|
||||
rv64:
|
||||
accessible: True
|
||||
index_select_reg: tselect
|
||||
index_list:
|
||||
- reset-val: 0x78
|
||||
index_val: 0
|
||||
shadow:
|
||||
shadow_type:
|
||||
type:
|
||||
ro_constant: 0x78
|
||||
- reset-val: 0x8
|
||||
index_val: 1
|
||||
shadow:
|
||||
shadow_type:
|
||||
type:
|
||||
ro_constant: 0x8
|
||||
- reset-val: 0x10
|
||||
index_val: 2
|
||||
shadow:
|
||||
shadow_type:
|
||||
type:
|
||||
ro_constant: 0x10
|
||||
tdata1:
|
||||
rv32:
|
||||
accessible: False
|
||||
rv64:
|
||||
accessible: True
|
||||
index_select_reg: tselect
|
||||
index_list:
|
||||
- reset-val: 0xdeadbeef
|
||||
index_val: 0
|
||||
shadow:
|
||||
shadow_type:
|
||||
type:
|
||||
ro_constant: 0xdeadbeef
|
||||
- reset-val: 0
|
||||
index_val: 1
|
||||
shadow:
|
||||
shadow_type:
|
||||
type: &mywarl
|
||||
warl:
|
||||
dependency_fields: []
|
||||
legal:
|
||||
- writeval[63:0] in [0x0000000000000000:0xFFFFFFFFFFFFFFFF]
|
||||
wr_illegal:
|
||||
- Unchanged
|
||||
- reset-val: 0
|
||||
index_val: 2
|
||||
shadow:
|
||||
shadow_type:
|
||||
type:
|
||||
warl:
|
||||
dependency_fields: []
|
||||
legal:
|
||||
- writeval[63:0] in [0x0000000000000000:0xFFFFFFFFFFFFFFFF]
|
||||
wr_illegal:
|
||||
- Unchanged
|
||||
|
||||
#FIXME NTO SUPPORTED BY RISCV CNFIG
|
||||
# tdata2:
|
||||
# rv64:
|
||||
# accessible: true
|
||||
# type:
|
||||
# ro_variable: true
|
||||
# rv32:
|
||||
# accessible: false
|
||||
# tdata3:
|
||||
# rv64:
|
||||
# accessible: true
|
||||
# type:
|
||||
# ro_variable: true
|
||||
# rv32:
|
||||
# accessible: false
|
||||
dscratch0:
|
||||
rv64:
|
||||
accessible: true
|
||||
rv32:
|
||||
accessible: false
|
||||
dscratch1:
|
||||
rv64:
|
||||
accessible: true
|
||||
rv32:
|
||||
accessible: false
|
1863
config/riscv-config/cv64a60ax/spec/isa_spec.yaml
Normal file
1863
config/riscv-config/cv64a60ax/spec/isa_spec.yaml
Normal file
File diff suppressed because it is too large
Load diff
53
config/riscv-config/cv64a60ax/spec/platform_spec.yaml
Normal file
53
config/riscv-config/cv64a60ax/spec/platform_spec.yaml
Normal file
|
@ -0,0 +1,53 @@
|
|||
# Copyright 2024 Thales DIS France SAS
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Original Author: Tanuj Khandelwal CEA (copied from riscv-config examples)
|
||||
|
||||
nmi:
|
||||
label: nmi_vector
|
||||
# address: 12288
|
||||
reset:
|
||||
label: reset_vector
|
||||
# address: 16384
|
||||
mtime:
|
||||
implemented: false
|
||||
mtimecmp:
|
||||
implemented: false
|
||||
#mcause_non_standard:
|
||||
# implemented: true
|
||||
mtval_condition_writes:
|
||||
implemented: false
|
||||
scause_non_standard:
|
||||
implemented: false
|
||||
stval_condition_writes:
|
||||
implemented: false
|
||||
zicbo_cache_block_sz :
|
||||
implemented: true
|
||||
zicbom_sz: 64
|
||||
zicboz_sz: 64
|
||||
|
||||
#memory_map:
|
||||
# - memory_region:
|
||||
# name: bootrom
|
||||
# base_addr: 0x10000
|
||||
# size: 0x10000
|
||||
# description: System boot ROM
|
||||
# attributes:
|
||||
# read_only: true
|
||||
# cached: false
|
||||
# - memory_region:
|
||||
# name: dram
|
||||
# base_addr: 0x80000000
|
||||
# size: 0x40000000
|
||||
# description: System (D)RAM
|
|
@ -29,6 +29,8 @@
|
|||
${CVA6_REPO_DIR}/vendor/pulp-platform/fpga-support/rtl/SyncDpRam.sv
|
||||
${CVA6_REPO_DIR}/vendor/pulp-platform/fpga-support/rtl/AsyncDpRam.sv
|
||||
${CVA6_REPO_DIR}/vendor/pulp-platform/fpga-support/rtl/AsyncThreePortRam.sv
|
||||
${CVA6_REPO_DIR}/vendor/pulp-platform/fpga-support/rtl/SyncThreePortRam.sv
|
||||
${CVA6_REPO_DIR}/vendor/pulp-platform/fpga-support/rtl/SyncDpRam_ind_r_w.sv
|
||||
|
||||
+incdir+${CVA6_REPO_DIR}/core/include/
|
||||
+incdir+${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/include/
|
||||
|
@ -71,11 +73,14 @@ ${CVA6_REPO_DIR}/core/include/instr_tracer_pkg.sv
|
|||
${CVA6_REPO_DIR}/core/include/build_config_pkg.sv
|
||||
|
||||
//CVXIF
|
||||
${CVA6_REPO_DIR}/core/include/cvxif_pkg.sv
|
||||
${CVA6_REPO_DIR}/core/cvxif_compressed_if_driver.sv
|
||||
${CVA6_REPO_DIR}/core/cvxif_issue_register_commit_if_driver.sv
|
||||
${CVA6_REPO_DIR}/core/cvxif_example/include/cvxif_instr_pkg.sv
|
||||
${CVA6_REPO_DIR}/core/cvxif_fu.sv
|
||||
${CVA6_REPO_DIR}/core/cvxif_example/cvxif_example_coprocessor.sv
|
||||
${CVA6_REPO_DIR}/core/cvxif_example/instr_decoder.sv
|
||||
${CVA6_REPO_DIR}/core/cvxif_example/compressed_instr_decoder.sv
|
||||
${CVA6_REPO_DIR}/core/cvxif_example/copro_alu.sv
|
||||
|
||||
// Common Cells
|
||||
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/cf_math_pkg.sv
|
||||
|
@ -107,6 +112,7 @@ ${CVA6_REPO_DIR}/core/branch_unit.sv
|
|||
${CVA6_REPO_DIR}/core/compressed_decoder.sv
|
||||
${CVA6_REPO_DIR}/core/macro_decoder.sv
|
||||
${CVA6_REPO_DIR}/core/controller.sv
|
||||
${CVA6_REPO_DIR}/core/zcmt_decoder.sv
|
||||
${CVA6_REPO_DIR}/core/csr_buffer.sv
|
||||
${CVA6_REPO_DIR}/core/csr_regfile.sv
|
||||
${CVA6_REPO_DIR}/core/decoder.sv
|
||||
|
@ -138,6 +144,7 @@ ${CVA6_REPO_DIR}/core/cva6_fifo_v3.sv
|
|||
// What is "frontend"?
|
||||
${CVA6_REPO_DIR}/core/frontend/btb.sv
|
||||
${CVA6_REPO_DIR}/core/frontend/bht.sv
|
||||
${CVA6_REPO_DIR}/core/frontend/bht2lvl.sv
|
||||
${CVA6_REPO_DIR}/core/frontend/ras.sv
|
||||
${CVA6_REPO_DIR}/core/frontend/instr_scan.sv
|
||||
${CVA6_REPO_DIR}/core/frontend/instr_queue.sv
|
||||
|
@ -160,14 +167,13 @@ ${CVA6_REPO_DIR}/core/cache_subsystem/cva6_icache_axi_wrapper.sv
|
|||
${CVA6_REPO_DIR}/core/cache_subsystem/std_cache_subsystem.sv
|
||||
${CVA6_REPO_DIR}/core/cache_subsystem/std_nbdcache.sv
|
||||
-F ${HPDCACHE_DIR}/rtl/hpdcache.Flist
|
||||
${HPDCACHE_DIR}/rtl/src/utils/hpdcache_mem_req_read_arbiter.sv
|
||||
${HPDCACHE_DIR}/rtl/src/utils/hpdcache_mem_req_write_arbiter.sv
|
||||
${HPDCACHE_DIR}/rtl/src/utils/hpdcache_mem_resp_demux.sv
|
||||
${HPDCACHE_DIR}/rtl/src/utils/hpdcache_mem_to_axi_read.sv
|
||||
${HPDCACHE_DIR}/rtl/src/utils/hpdcache_mem_to_axi_write.sv
|
||||
${CVA6_REPO_DIR}/core/cache_subsystem/cva6_hpdcache_subsystem.sv
|
||||
${CVA6_REPO_DIR}/core/cache_subsystem/cva6_hpdcache_subsystem_axi_arbiter.sv
|
||||
${CVA6_REPO_DIR}/core/cache_subsystem/cva6_hpdcache_if_adapter.sv
|
||||
${CVA6_REPO_DIR}/core/cache_subsystem/cva6_hpdcache_wrapper.sv
|
||||
${HPDCACHE_DIR}/rtl/src/common/macros/behav/hpdcache_sram_1rw.sv
|
||||
${HPDCACHE_DIR}/rtl/src/common/macros/behav/hpdcache_sram_wbyteenable_1rw.sv
|
||||
${HPDCACHE_DIR}/rtl/src/common/macros/behav/hpdcache_sram_wmask_1rw.sv
|
||||
|
@ -176,6 +182,7 @@ ${HPDCACHE_DIR}/rtl/src/common/macros/behav/hpdcache_sram_wmask_1rw.sv
|
|||
// NOTE: pmp.sv modified for DSIM (unchanged for other simulators)
|
||||
${CVA6_REPO_DIR}/core/pmp/src/pmp.sv
|
||||
${CVA6_REPO_DIR}/core/pmp/src/pmp_entry.sv
|
||||
${CVA6_REPO_DIR}/core/pmp/src/pmp_data_if.sv
|
||||
|
||||
// Tracer (behavioral code, not RTL)
|
||||
${CVA6_REPO_DIR}/common/local/util/instr_tracer.sv
|
||||
|
|
|
@ -27,12 +27,11 @@ ${CVA6_REPO_DIR}/core/include/instr_tracer_pkg.sv
|
|||
${CVA6_REPO_DIR}/core/include/build_config_pkg.sv
|
||||
|
||||
//CVXIF
|
||||
${CVA6_REPO_DIR}/core/include/cvxif_pkg.sv
|
||||
${CVA6_REPO_DIR}/core/cvxif_example/include/cvxif_instr_pkg.sv
|
||||
${CVA6_REPO_DIR}/core/cvxif_fu.sv
|
||||
${CVA6_REPO_DIR}/core/cvxif_example/cvxif_example_coprocessor.sv
|
||||
${CVA6_REPO_DIR}/core/cvxif_example/instr_decoder.sv
|
||||
${CVA6_REPO_DIR}/core/cva6_fifo_v3.sv
|
||||
${CVA6_REPO_DIR}/core/cvxif_example/compressed_instr_decoder.sv
|
||||
${CVA6_REPO_DIR}/core/cvxif_example/copro_alu.sv
|
||||
|
||||
|
||||
// Common Cells
|
||||
|
@ -63,7 +62,7 @@ ${CVA6_REPO_DIR}/pd/synth/cva6_${TARGET_CFG}_synth.v
|
|||
# Dedicated to black box in caches, cv32a65x only
|
||||
${CVA6_REPO_DIR}/pd/synth/tc_sram_wrapper_256_64_00000008_00000001_00000001_none_0.sv
|
||||
${CVA6_REPO_DIR}/pd/synth/hpdcache_sram_wbyteenable_1rw_00000007_00000040_00000080.sv
|
||||
${CVA6_REPO_DIR}/pd/synth/hpdcache_sram_1rw_00000006_0000001a_00000040.sv
|
||||
${CVA6_REPO_DIR}/pd/synth/hpdcache_sram_1rw_00000006_0000001c_00000040.sv
|
||||
|
||||
${CVA6_REPO_DIR}/common/local/util/tc_sram_wrapper.sv
|
||||
${CVA6_REPO_DIR}/common/local/util/tc_sram_wrapper_cache_techno.sv
|
||||
|
|
|
@ -23,36 +23,12 @@ module acc_dispatcher
|
|||
parameter type exception_t = logic,
|
||||
parameter type fu_data_t = logic,
|
||||
parameter type scoreboard_entry_t = logic,
|
||||
localparam type accelerator_req_t = struct packed {
|
||||
logic req_valid;
|
||||
logic resp_ready;
|
||||
riscv::instruction_t insn;
|
||||
logic [CVA6Cfg.XLEN-1:0] rs1;
|
||||
logic [CVA6Cfg.XLEN-1:0] rs2;
|
||||
fpnew_pkg::roundmode_e frm;
|
||||
logic [CVA6Cfg.TRANS_ID_BITS-1:0] trans_id;
|
||||
logic store_pending;
|
||||
// Invalidation interface
|
||||
logic acc_cons_en;
|
||||
logic inval_ready;
|
||||
},
|
||||
parameter type acc_req_t = accelerator_req_t,
|
||||
parameter type acc_resp_t = struct packed {
|
||||
logic req_ready;
|
||||
logic resp_valid;
|
||||
logic [CVA6Cfg.XLEN-1:0] result;
|
||||
logic [CVA6Cfg.TRANS_ID_BITS-1:0] trans_id;
|
||||
logic error;
|
||||
// Metadata
|
||||
logic store_pending;
|
||||
logic store_complete;
|
||||
logic load_complete;
|
||||
logic [4:0] fflags;
|
||||
logic fflags_valid;
|
||||
// Invalidation interface
|
||||
logic inval_valid;
|
||||
logic [63:0] inval_addr;
|
||||
},
|
||||
parameter type acc_req_t = logic,
|
||||
parameter type acc_resp_t = logic,
|
||||
parameter type accelerator_req_t = logic,
|
||||
parameter type accelerator_resp_t = logic,
|
||||
parameter type acc_mmu_req_t = logic,
|
||||
parameter type acc_mmu_resp_t = logic,
|
||||
parameter type acc_cfg_t = logic,
|
||||
parameter acc_cfg_t AccCfg = '0
|
||||
) (
|
||||
|
@ -65,10 +41,11 @@ module acc_dispatcher
|
|||
// Interface with the CSRs
|
||||
input priv_lvl_t ld_st_priv_lvl_i,
|
||||
input logic sum_i,
|
||||
input pmpcfg_t [15:0] pmpcfg_i,
|
||||
input logic [15:0][CVA6Cfg.PLEN-3:0] pmpaddr_i,
|
||||
input pmpcfg_t [avoid_neg(CVA6Cfg.NrPMPEntries-1):0] pmpcfg_i,
|
||||
input logic [avoid_neg(CVA6Cfg.NrPMPEntries-1):0][CVA6Cfg.PLEN-3:0] pmpaddr_i,
|
||||
input logic [2:0] fcsr_frm_i,
|
||||
output logic dirty_v_state_o,
|
||||
input logic acc_mmu_en_i,
|
||||
// Interface with the issue stage
|
||||
input scoreboard_entry_t issue_instr_i,
|
||||
input logic issue_instr_hs_i,
|
||||
|
@ -88,6 +65,9 @@ module acc_dispatcher
|
|||
output logic acc_stall_st_pending_o,
|
||||
input logic acc_no_st_pending_i,
|
||||
input dcache_req_i_t [2:0] dcache_req_ports_i,
|
||||
// Interface with the MMU
|
||||
output acc_mmu_req_t acc_mmu_req_o,
|
||||
input acc_mmu_resp_t acc_mmu_resp_i,
|
||||
// Interface with the controller
|
||||
output logic ctrl_halt_o,
|
||||
input logic [11:0] csr_addr_i,
|
||||
|
@ -219,7 +199,7 @@ module acc_dispatcher
|
|||
end
|
||||
|
||||
// An accelerator instruction was issued.
|
||||
if (acc_req_o.req_valid) insn_ready_d[acc_req_o.trans_id] = 1'b0;
|
||||
if (acc_req_o.acc_req.req_valid) insn_ready_d[acc_req_o.acc_req.trans_id] = 1'b0;
|
||||
end : p_non_speculative_ff
|
||||
|
||||
/*************************
|
||||
|
@ -231,29 +211,31 @@ module acc_dispatcher
|
|||
logic acc_req_ready;
|
||||
|
||||
accelerator_req_t acc_req_int;
|
||||
fall_through_register #(
|
||||
spill_register #(
|
||||
.T(accelerator_req_t)
|
||||
) i_accelerator_req_register (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
.clr_i (1'b0),
|
||||
.testmode_i(1'b0),
|
||||
.data_i (acc_req),
|
||||
.valid_i (acc_req_valid),
|
||||
.ready_o (acc_req_ready),
|
||||
.data_o (acc_req_int),
|
||||
.valid_o (acc_req_o.req_valid),
|
||||
.ready_i (acc_resp_i.req_ready)
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
.data_i (acc_req),
|
||||
.valid_i(acc_req_valid),
|
||||
.ready_o(acc_req_ready),
|
||||
.data_o (acc_req_int),
|
||||
.valid_o(acc_req_o.acc_req.req_valid),
|
||||
.ready_i(acc_resp_i.acc_resp.req_ready)
|
||||
);
|
||||
|
||||
assign acc_req_o.insn = acc_req_int.insn;
|
||||
assign acc_req_o.rs1 = acc_req_int.rs1;
|
||||
assign acc_req_o.rs2 = acc_req_int.rs2;
|
||||
assign acc_req_o.frm = acc_req_int.frm;
|
||||
assign acc_req_o.trans_id = acc_req_int.trans_id;
|
||||
assign acc_req_o.store_pending = !acc_no_st_pending_i && acc_cons_en_i;
|
||||
assign acc_req_o.acc_cons_en = acc_cons_en_i;
|
||||
assign acc_req_o.inval_ready = inval_ready_i;
|
||||
assign acc_req_o.acc_req.insn = acc_req_int.insn;
|
||||
assign acc_req_o.acc_req.rs1 = acc_req_int.rs1;
|
||||
assign acc_req_o.acc_req.rs2 = acc_req_int.rs2;
|
||||
assign acc_req_o.acc_req.frm = acc_req_int.frm;
|
||||
assign acc_req_o.acc_req.trans_id = acc_req_int.trans_id;
|
||||
assign acc_req_o.acc_req.store_pending = !acc_no_st_pending_i && acc_cons_en_i;
|
||||
assign acc_req_o.acc_req.acc_cons_en = acc_cons_en_i;
|
||||
assign acc_req_o.acc_req.inval_ready = inval_ready_i;
|
||||
|
||||
// MMU interface
|
||||
assign acc_req_o.acc_mmu_resp = acc_mmu_resp_i;
|
||||
assign acc_req_o.acc_mmu_en = acc_mmu_en_i;
|
||||
|
||||
always_comb begin : accelerator_req_dispatcher
|
||||
// Do not fetch from the instruction queue
|
||||
|
@ -263,7 +245,7 @@ module acc_dispatcher
|
|||
acc_req = '0;
|
||||
acc_req_valid = 1'b0;
|
||||
|
||||
// Unpack fu_data_t into accelerator_req_t
|
||||
// Unpack fu_data_t into acc_req_t
|
||||
if (!acc_insn_queue_empty) begin
|
||||
acc_req = '{
|
||||
// Instruction is forwarded from the decoder as an immediate
|
||||
|
@ -285,7 +267,7 @@ module acc_dispatcher
|
|||
};
|
||||
// Wait until the instruction is no longer speculative.
|
||||
acc_req_valid = insn_ready_q[acc_insn_queue_o.trans_id] ||
|
||||
(acc_commit && insn_pending_q[acc_commit_trans_id]);
|
||||
(acc_commit && insn_pending_q[acc_commit_trans_id] && !flush_unissued_instr_i);
|
||||
acc_insn_queue_pop = acc_req_valid && acc_req_ready;
|
||||
end
|
||||
end
|
||||
|
@ -297,30 +279,27 @@ module acc_dispatcher
|
|||
logic acc_ld_disp;
|
||||
logic acc_st_disp;
|
||||
|
||||
assign acc_trans_id_o = acc_resp_i.acc_resp.trans_id;
|
||||
assign acc_result_o = acc_resp_i.acc_resp.result;
|
||||
assign acc_valid_o = acc_resp_i.acc_resp.resp_valid;
|
||||
assign acc_exception_o = acc_resp_i.acc_resp.exception;
|
||||
// Unpack the accelerator response
|
||||
assign acc_trans_id_o = acc_resp_i.trans_id;
|
||||
assign acc_result_o = acc_resp_i.result;
|
||||
assign acc_valid_o = acc_resp_i.resp_valid;
|
||||
assign acc_exception_o = '{
|
||||
cause: riscv::ILLEGAL_INSTR,
|
||||
tval : '0,
|
||||
tval2 : '0,
|
||||
tinst : '0,
|
||||
gva : '0,
|
||||
valid: acc_resp_i.error
|
||||
};
|
||||
assign acc_fflags_valid_o = acc_resp_i.fflags_valid;
|
||||
assign acc_fflags_o = acc_resp_i.fflags;
|
||||
assign acc_fflags_valid_o = acc_resp_i.acc_resp.fflags_valid;
|
||||
assign acc_fflags_o = acc_resp_i.acc_resp.fflags;
|
||||
|
||||
// MMU interface
|
||||
assign acc_mmu_req_o = acc_resp_i.acc_mmu_req;
|
||||
|
||||
// Always ready to receive responses
|
||||
assign acc_req_o.resp_ready = 1'b1;
|
||||
assign acc_req_o.acc_req.resp_ready = 1'b1;
|
||||
|
||||
// Signal dispatched load/store to issue stage
|
||||
assign acc_ld_disp = acc_req_valid && (acc_insn_queue_o.operation == ACCEL_OP_LOAD);
|
||||
assign acc_st_disp = acc_req_valid && (acc_insn_queue_o.operation == ACCEL_OP_STORE);
|
||||
|
||||
// Cache invalidation
|
||||
assign inval_valid_o = acc_resp_i.inval_valid;
|
||||
assign inval_addr_o = acc_resp_i.inval_addr;
|
||||
assign inval_valid_o = acc_resp_i.acc_resp.inval_valid;
|
||||
assign inval_addr_o = acc_resp_i.acc_resp.inval_addr;
|
||||
|
||||
/**************************
|
||||
* Accelerator commit *
|
||||
|
@ -358,8 +337,8 @@ module acc_dispatcher
|
|||
`FF(wait_acc_store_q, wait_acc_store_d, '0)
|
||||
|
||||
// Set on store barrier. Clear when no store is pending.
|
||||
assign wait_acc_store_d = (wait_acc_store_q | commit_st_barrier_i) & acc_resp_i.store_pending;
|
||||
assign ctrl_halt_o = wait_acc_store_q;
|
||||
assign wait_acc_store_d = (wait_acc_store_q | commit_st_barrier_i) & acc_resp_i.acc_resp.store_pending;
|
||||
assign ctrl_halt_o = wait_acc_store_q;
|
||||
|
||||
/**************************
|
||||
* Load/Store tracking *
|
||||
|
@ -397,9 +376,9 @@ module acc_dispatcher
|
|||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
.clear_i (1'b0),
|
||||
.en_i (acc_ld_disp ^ acc_resp_i.load_complete),
|
||||
.en_i (acc_ld_disp ^ acc_resp_i.acc_resp.load_complete),
|
||||
.load_i (1'b0),
|
||||
.down_i (acc_resp_i.load_complete),
|
||||
.down_i (acc_resp_i.acc_resp.load_complete),
|
||||
.d_i ('0),
|
||||
.q_o (acc_disp_loads_pending),
|
||||
.overflow_o(acc_disp_loads_overflow)
|
||||
|
@ -442,9 +421,9 @@ module acc_dispatcher
|
|||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
.clear_i (1'b0),
|
||||
.en_i (acc_st_disp ^ acc_resp_i.store_complete),
|
||||
.en_i (acc_st_disp ^ acc_resp_i.acc_resp.store_complete),
|
||||
.load_i (1'b0),
|
||||
.down_i (acc_resp_i.store_complete),
|
||||
.down_i (acc_resp_i.acc_resp.store_complete),
|
||||
.d_i ('0),
|
||||
.q_o (acc_disp_stores_pending),
|
||||
.overflow_o(acc_disp_stores_overflow)
|
||||
|
|
89
core/alu.sv
89
core/alu.sv
|
@ -22,6 +22,7 @@ module alu
|
|||
import ariane_pkg::*;
|
||||
#(
|
||||
parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty,
|
||||
parameter bit HasBranch = 1'b1,
|
||||
parameter type fu_data_t = logic
|
||||
) (
|
||||
// Subsystem Clock - SUBSYSTEM
|
||||
|
@ -50,6 +51,9 @@ module alu
|
|||
logic lz_tz_empty, lz_tz_wempty;
|
||||
logic [CVA6Cfg.XLEN-1:0] orcbw_result, rev8w_result;
|
||||
|
||||
logic [CVA6Cfg.XLEN-1:0] brev8_reversed;
|
||||
logic [ 31:0] unzip_gen;
|
||||
logic [ 31:0] zip_gen;
|
||||
// bit reverse operand_a for left shifts and bit counting
|
||||
generate
|
||||
genvar k;
|
||||
|
@ -68,15 +72,7 @@ module alu
|
|||
logic [CVA6Cfg.XLEN-1:0] adder_result;
|
||||
logic [CVA6Cfg.XLEN-1:0] operand_a_bitmanip, bit_indx;
|
||||
|
||||
always_comb begin
|
||||
adder_op_b_negate = 1'b0;
|
||||
|
||||
unique case (fu_data_i.operation)
|
||||
// ADDER OPS
|
||||
EQ, NE, SUB, SUBW, ANDN, ORN, XNOR: adder_op_b_negate = 1'b1;
|
||||
default: ;
|
||||
endcase
|
||||
end
|
||||
assign adder_op_b_negate = fu_data_i.operation inside {EQ, NE, SUB, SUBW, ANDN, ORN, XNOR};
|
||||
|
||||
always_comb begin
|
||||
operand_a_bitmanip = fu_data_i.operand_a;
|
||||
|
@ -110,21 +106,24 @@ module alu
|
|||
assign adder_in_b = operand_b_neg;
|
||||
|
||||
// actual adder
|
||||
assign adder_result_ext_o = $unsigned(adder_in_a) + $unsigned(adder_in_b);
|
||||
assign adder_result_ext_o = adder_in_a + adder_in_b;
|
||||
assign adder_result = adder_result_ext_o[CVA6Cfg.XLEN:1];
|
||||
assign adder_z_flag = ~|adder_result;
|
||||
|
||||
// get the right branch comparison result
|
||||
always_comb begin : branch_resolve
|
||||
// set comparison by default
|
||||
alu_branch_res_o = 1'b1;
|
||||
case (fu_data_i.operation)
|
||||
EQ: alu_branch_res_o = adder_z_flag;
|
||||
NE: alu_branch_res_o = ~adder_z_flag;
|
||||
LTS, LTU: alu_branch_res_o = less;
|
||||
GES, GEU: alu_branch_res_o = ~less;
|
||||
default: alu_branch_res_o = 1'b1;
|
||||
endcase
|
||||
if (HasBranch) begin
|
||||
always_comb begin : branch_resolve
|
||||
// set comparison by default
|
||||
case (fu_data_i.operation)
|
||||
EQ: alu_branch_res_o = adder_z_flag;
|
||||
NE: alu_branch_res_o = ~adder_z_flag;
|
||||
LTS, LTU: alu_branch_res_o = less;
|
||||
GES, GEU: alu_branch_res_o = ~less;
|
||||
default: alu_branch_res_o = 1'b1;
|
||||
endcase
|
||||
end
|
||||
end else begin
|
||||
assign alu_branch_res_o = 1'b0;
|
||||
end
|
||||
|
||||
// ---------
|
||||
|
@ -150,9 +149,9 @@ module alu
|
|||
|
||||
assign shift_amt = fu_data_i.operand_b;
|
||||
|
||||
assign shift_left = (fu_data_i.operation == SLL) | (fu_data_i.operation == SLLW);
|
||||
assign shift_left = (fu_data_i.operation == SLL) | (CVA6Cfg.IS_XLEN64 && fu_data_i.operation == SLLW);
|
||||
|
||||
assign shift_arithmetic = (fu_data_i.operation == SRA) | (fu_data_i.operation == SRAW);
|
||||
assign shift_arithmetic = (fu_data_i.operation == SRA) | (CVA6Cfg.IS_XLEN64 && fu_data_i.operation == SRAW);
|
||||
|
||||
// right shifts, we let the synthesizer optimize this
|
||||
logic [CVA6Cfg.XLEN:0] shift_op_a_64;
|
||||
|
@ -267,6 +266,29 @@ module alu
|
|||
end
|
||||
end
|
||||
|
||||
// ZKN gen block
|
||||
if (CVA6Cfg.ZKN && CVA6Cfg.RVB) begin : zkn_gen_block
|
||||
genvar i, m, n;
|
||||
// Generate brev8_reversed by reversing bits within each byte
|
||||
for (i = 0; i < (CVA6Cfg.XLEN / 8); i++) begin : brev8_gen
|
||||
for (m = 0; m < 8; m++) begin : reverse_bits
|
||||
// Reversing the order of bits within a single byte
|
||||
assign brev8_reversed[(i<<3)+m] = fu_data_i.operand_a[(i<<3)+(7-m)];
|
||||
end
|
||||
end
|
||||
// Generate zip and unzip results
|
||||
if (CVA6Cfg.IS_XLEN32) begin
|
||||
for (n = 0; n < 16; n++) begin : zip_unzip_gen
|
||||
// Assigning lower and upper half of operand into the even and odd positions of result
|
||||
assign zip_gen[n<<1] = fu_data_i.operand_a[n];
|
||||
assign zip_gen[(n<<1)+1] = fu_data_i.operand_a[n+16];
|
||||
// Assigning even and odd bits of operand into lower and upper halves of result
|
||||
assign unzip_gen[n] = fu_data_i.operand_a[n<<1];
|
||||
assign unzip_gen[n+16] = fu_data_i.operand_a[(n<<1)+1];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// -----------
|
||||
// Result MUX
|
||||
// -----------
|
||||
|
@ -300,10 +322,10 @@ module alu
|
|||
if (CVA6Cfg.RVB) begin
|
||||
// Index for Bitwise Rotation
|
||||
bit_indx = 1 << (fu_data_i.operand_b & (CVA6Cfg.XLEN - 1));
|
||||
// rolw, roriw, rorw
|
||||
rolw = ({{CVA6Cfg.XLEN-32{1'b0}},fu_data_i.operand_a[31:0]} << fu_data_i.operand_b[4:0]) | ({{CVA6Cfg.XLEN-32{1'b0}},fu_data_i.operand_a[31:0]} >> (CVA6Cfg.XLEN-32-fu_data_i.operand_b[4:0]));
|
||||
rorw = ({{CVA6Cfg.XLEN-32{1'b0}},fu_data_i.operand_a[31:0]} >> fu_data_i.operand_b[4:0]) | ({{CVA6Cfg.XLEN-32{1'b0}},fu_data_i.operand_a[31:0]} << (CVA6Cfg.XLEN-32-fu_data_i.operand_b[4:0]));
|
||||
if (CVA6Cfg.IS_XLEN64) begin
|
||||
// rolw, roriw, rorw
|
||||
rolw = ({{CVA6Cfg.XLEN-32{1'b0}},fu_data_i.operand_a[31:0]} << fu_data_i.operand_b[4:0]) | ({{CVA6Cfg.XLEN-32{1'b0}},fu_data_i.operand_a[31:0]} >> (CVA6Cfg.XLEN-32-fu_data_i.operand_b[4:0]));
|
||||
rorw = ({{CVA6Cfg.XLEN-32{1'b0}},fu_data_i.operand_a[31:0]} >> fu_data_i.operand_b[4:0]) | ({{CVA6Cfg.XLEN-32{1'b0}},fu_data_i.operand_a[31:0]} << (CVA6Cfg.XLEN-32-fu_data_i.operand_b[4:0]));
|
||||
unique case (fu_data_i.operation)
|
||||
CLZW, CTZW:
|
||||
result_o = (lz_tz_wempty) ? 32 : {{CVA6Cfg.XLEN - 5{1'b0}}, lz_tz_wcount}; // change
|
||||
|
@ -362,5 +384,22 @@ module alu
|
|||
default: ; // default case to suppress unique warning
|
||||
endcase
|
||||
end
|
||||
// ZKN instructions
|
||||
if (CVA6Cfg.ZKN && CVA6Cfg.RVB) begin
|
||||
unique case (fu_data_i.operation)
|
||||
PACK:
|
||||
result_o = (CVA6Cfg.IS_XLEN32) ? ({fu_data_i.operand_b[15:0], fu_data_i.operand_a[15:0]}) : ({fu_data_i.operand_b[31:0], fu_data_i.operand_a[31:0]});
|
||||
PACK_H:
|
||||
result_o = (CVA6Cfg.IS_XLEN32) ? ({16'b0, fu_data_i.operand_b[7:0], fu_data_i.operand_a[7:0]}) : ({48'b0, fu_data_i.operand_b[7:0], fu_data_i.operand_a[7:0]});
|
||||
BREV8: result_o = brev8_reversed;
|
||||
default: ;
|
||||
endcase
|
||||
if (fu_data_i.operation == PACK_W && CVA6Cfg.IS_XLEN64)
|
||||
result_o = {
|
||||
{32{fu_data_i.operand_b[15]}}, {fu_data_i.operand_b[15:0]}, {fu_data_i.operand_a[15:0]}
|
||||
};
|
||||
if (fu_data_i.operation == UNZIP && CVA6Cfg.IS_XLEN32) result_o = unzip_gen;
|
||||
if (fu_data_i.operation == ZIP && CVA6Cfg.IS_XLEN32) result_o = zip_gen;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// Copyright 2018 ETH Zurich and University of Bologna.
|
||||
// Copyright 2024 - PlanV Technologies for additionnal contribution.
|
||||
// Copyright and related rights are licensed under the Solderpad Hardware
|
||||
// License, Version 0.51 (the "License"); you may not use this file except in
|
||||
// compliance with the License. You may obtain a copy of the License at
|
||||
|
@ -15,7 +16,7 @@
|
|||
// Noam Gallmann - gnoam@live.com
|
||||
// Felipe Lisboa Malaquias
|
||||
// Henry Suzukawa
|
||||
//
|
||||
// Angela Gonzalez - PlanV Technologies
|
||||
//
|
||||
// Description: This register file is optimized for implementation on
|
||||
// FPGAs. The register file features one distributed RAM block per implemented
|
||||
|
@ -50,11 +51,16 @@ module ariane_regfile_fpga #(
|
|||
localparam LOG_NR_WRITE_PORTS = CVA6Cfg.NrCommitPorts == 1 ? 1 : $clog2(CVA6Cfg.NrCommitPorts);
|
||||
|
||||
// Distributed RAM usually supports one write port per block - duplicate for each write port.
|
||||
logic [ NUM_WORDS-1:0][ DATA_WIDTH-1:0] mem [CVA6Cfg.NrCommitPorts];
|
||||
logic [NUM_WORDS-1:0][DATA_WIDTH-1:0] mem[CVA6Cfg.NrCommitPorts];
|
||||
|
||||
logic [CVA6Cfg.NrCommitPorts-1:0][ NUM_WORDS-1:0] we_dec;
|
||||
logic [ NUM_WORDS-1:0][LOG_NR_WRITE_PORTS-1:0] mem_block_sel;
|
||||
logic [ NUM_WORDS-1:0][LOG_NR_WRITE_PORTS-1:0] mem_block_sel_q;
|
||||
logic [CVA6Cfg.NrCommitPorts-1:0][NUM_WORDS-1:0] we_dec;
|
||||
logic [NUM_WORDS-1:0][LOG_NR_WRITE_PORTS-1:0] mem_block_sel;
|
||||
logic [NUM_WORDS-1:0][LOG_NR_WRITE_PORTS-1:0] mem_block_sel_q;
|
||||
logic [CVA6Cfg.NrCommitPorts-1:0][DATA_WIDTH-1:0] wdata_reg;
|
||||
logic [NR_READ_PORTS-1:0] read_after_write;
|
||||
|
||||
logic [NR_READ_PORTS-1:0][4:0] raddr_q;
|
||||
logic [NR_READ_PORTS-1:0][4:0] raddr;
|
||||
|
||||
// write adress decoder (for block selector)
|
||||
always_comb begin
|
||||
|
@ -88,36 +94,55 @@ module ariane_regfile_fpga #(
|
|||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
mem_block_sel_q <= '0;
|
||||
raddr_q <= '0;
|
||||
end else begin
|
||||
mem_block_sel_q <= mem_block_sel;
|
||||
if (CVA6Cfg.FpgaAlteraEn) raddr_q <= raddr_i;
|
||||
else raddr_q <= '0;
|
||||
end
|
||||
end
|
||||
|
||||
// distributed RAM blocks
|
||||
logic [NR_READ_PORTS-1:0][DATA_WIDTH-1:0] mem_read[CVA6Cfg.NrCommitPorts];
|
||||
logic [NR_READ_PORTS-1:0][DATA_WIDTH-1:0] mem_read_sync[CVA6Cfg.NrCommitPorts];
|
||||
for (genvar j = 0; j < CVA6Cfg.NrCommitPorts; j++) begin : regfile_ram_block
|
||||
always_ff @(posedge clk_i) begin
|
||||
if (we_i[j] && ~waddr_i[j] != 0) begin
|
||||
mem[j][waddr_i[j]] <= wdata_i[j];
|
||||
if (CVA6Cfg.FpgaAlteraEn)
|
||||
wdata_reg[j] <= wdata_i[j]; // register data written in case is needed to read next cycle
|
||||
else wdata_reg[j] <= '0;
|
||||
end
|
||||
if (CVA6Cfg.FpgaAlteraEn) begin
|
||||
for (int k = 0; k < NR_READ_PORTS; k++) begin : block_read
|
||||
mem_read_sync[j][k] = mem[j][raddr_i[k]]; // synchronous RAM
|
||||
read_after_write[k] <= '0;
|
||||
if (waddr_i[j] == raddr_i[k])
|
||||
read_after_write[k] <= we_i[j] && ~waddr_i[j] != 0; // Identify if we need to read the content that was written
|
||||
end
|
||||
end
|
||||
end
|
||||
for (genvar k = 0; k < NR_READ_PORTS; k++) begin : block_read
|
||||
assign mem_read[j][k] = mem[j][raddr_i[k]];
|
||||
assign mem_read[j][k] = CVA6Cfg.FpgaAlteraEn ? ( read_after_write[k] ? wdata_reg[j]: mem_read_sync[j][k]) : mem[j][raddr_i[k]];
|
||||
end
|
||||
end
|
||||
//with synchronous ram there is the need to adjust which address is used at the output MUX
|
||||
assign raddr = CVA6Cfg.FpgaAlteraEn ? raddr_q : raddr_i;
|
||||
|
||||
// output MUX
|
||||
logic [NR_READ_PORTS-1:0][LOG_NR_WRITE_PORTS-1:0] block_addr;
|
||||
for (genvar k = 0; k < NR_READ_PORTS; k++) begin : regfile_read_port
|
||||
assign block_addr[k] = mem_block_sel_q[raddr_i[k]];
|
||||
assign rdata_o[k] = (ZERO_REG_ZERO && raddr_i[k] == '0) ? '0 : mem_read[block_addr[k]][k];
|
||||
assign block_addr[k] = mem_block_sel_q[raddr[k]];
|
||||
assign rdata_o[k] = (ZERO_REG_ZERO && raddr[k] == '0) ? '0 : mem_read[block_addr[k]][k];
|
||||
end
|
||||
|
||||
// random initialization of the memory to suppress assert warnings on Questa.
|
||||
initial begin
|
||||
for (int i = 0; i < CVA6Cfg.NrCommitPorts; i++) begin
|
||||
for (int j = 0; j < NUM_WORDS; j++) begin
|
||||
mem[i][j] = $random();
|
||||
if (!CVA6Cfg.FpgaAlteraEn)
|
||||
mem[i][j] = $random(); //quartus does not support this random statement on synthesis
|
||||
else mem[i][j] = '0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -31,10 +31,10 @@ module branch_unit #(
|
|||
input fu_data_t fu_data_i,
|
||||
// Instruction PC - ISSUE_STAGE
|
||||
input logic [CVA6Cfg.VLEN-1:0] pc_i,
|
||||
// Is zcmt instruction - ISSUE_STAGE
|
||||
input logic is_zcmt_i,
|
||||
// Instruction is compressed - ISSUE_STAGE
|
||||
input logic is_compressed_instr_i,
|
||||
// any functional unit is valid, check that there is no accidental mis-predict - TO_BE_COMPLETED
|
||||
input logic fu_valid_i,
|
||||
// Branch unit instruction is valid - ISSUE_STAGE
|
||||
input logic branch_valid_i,
|
||||
// ALU branch compare result - ALU
|
||||
|
@ -60,7 +60,6 @@ module branch_unit #(
|
|||
// TODO(zarubaf): The ALU can be used to calculate the branch target
|
||||
jump_base = (fu_data_i.operation == ariane_pkg::JALR) ? fu_data_i.operand_a[CVA6Cfg.VLEN-1:0] : pc_i;
|
||||
|
||||
target_address = {CVA6Cfg.VLEN{1'b0}};
|
||||
resolve_branch_o = 1'b0;
|
||||
resolved_branch_o.target_address = {CVA6Cfg.VLEN{1'b0}};
|
||||
resolved_branch_o.is_taken = 1'b0;
|
||||
|
@ -77,13 +76,21 @@ module branch_unit #(
|
|||
// we need to put the branch target address into rd, this is the result of this unit
|
||||
branch_result_o = next_pc;
|
||||
resolved_branch_o.pc = pc_i;
|
||||
// There are only two sources of mispredicts:
|
||||
// There are only three sources of mispredicts:
|
||||
// 1. Branches
|
||||
// 2. Jumps to register addresses
|
||||
// 3. Zcmt instructions
|
||||
if (branch_valid_i) begin
|
||||
// write target address which goes to PC Gen
|
||||
// write target address which goes to PC Gen or select target address if zcmt
|
||||
resolved_branch_o.target_address = (branch_comp_res_i) ? target_address : next_pc;
|
||||
resolved_branch_o.is_taken = branch_comp_res_i;
|
||||
if (CVA6Cfg.RVZCMT) begin
|
||||
if (is_zcmt_i) begin
|
||||
// Unconditional jump handling
|
||||
resolved_branch_o.is_mispredict = 1'b1; // miss prediction for ZCMT
|
||||
resolved_branch_o.cf_type = ariane_pkg::JumpR;
|
||||
end
|
||||
end
|
||||
// check the outcome of the branch speculation
|
||||
if (ariane_pkg::op_is_branch(fu_data_i.operation)) begin
|
||||
// Set the `cf_type` of the output as `branch`, this will update the BHT.
|
||||
|
@ -110,8 +117,6 @@ module branch_unit #(
|
|||
always_comb begin : exception_handling
|
||||
|
||||
// Do a jump if it is either unconditional jump (JAL | JALR) or `taken` conditional jump
|
||||
jump_taken = !(ariane_pkg::op_is_branch(fu_data_i.operation)) ||
|
||||
((ariane_pkg::op_is_branch(fu_data_i.operation)) && branch_comp_res_i);
|
||||
branch_exception_o.cause = riscv::INSTR_ADDR_MISALIGNED;
|
||||
branch_exception_o.valid = 1'b0;
|
||||
if (CVA6Cfg.TvalEn)
|
||||
|
@ -122,8 +127,12 @@ module branch_unit #(
|
|||
branch_exception_o.gva = CVA6Cfg.RVH ? v_i : 1'b0;
|
||||
// Only throw instruction address misaligned exception if this is indeed a `taken` conditional branch or
|
||||
// an unconditional jump
|
||||
if (branch_valid_i && (target_address[0] || (!CVA6Cfg.RVC && target_address[1])) && jump_taken) begin
|
||||
branch_exception_o.valid = 1'b1;
|
||||
if (!CVA6Cfg.RVC) begin
|
||||
jump_taken = !(ariane_pkg::op_is_branch(fu_data_i.operation)) ||
|
||||
((ariane_pkg::op_is_branch(fu_data_i.operation)) && branch_comp_res_i);
|
||||
if (branch_valid_i && (target_address[0] || target_address[1]) && jump_taken) begin
|
||||
branch_exception_o.valid = 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
|
|
@ -201,7 +201,7 @@ module axi_adapter #(
|
|||
end else begin
|
||||
// bursts of AMOs unsupported
|
||||
assert (amo_i == ariane_pkg::AMO_NONE)
|
||||
else $fatal("Bursts of atomic operations are not supported");
|
||||
else $fatal(1, "Bursts of atomic operations are not supported");
|
||||
|
||||
axi_req_o.aw.len = BURST_SIZE[7:0]; // number of bursts to do
|
||||
axi_req_o.w.data = wdata_i[0];
|
||||
|
@ -232,7 +232,7 @@ module axi_adapter #(
|
|||
gnt_o = axi_resp_i.ar_ready;
|
||||
if (type_i != ariane_pkg::SINGLE_REQ) begin
|
||||
assert (amo_i == ariane_pkg::AMO_NONE)
|
||||
else $fatal("Bursts of atomic operations are not supported");
|
||||
else $fatal(1, "Bursts of atomic operations are not supported");
|
||||
|
||||
axi_req_o.ar.len = BURST_SIZE[7:0];
|
||||
cnt_d = BURST_SIZE[ADDR_INDEX-1:0];
|
||||
|
|
|
@ -117,7 +117,8 @@ module cache_ctrl
|
|||
// cache-line offset -> multiple of XLEN
|
||||
cl_offset = mem_req_q.index[CVA6Cfg.DCACHE_OFFSET_WIDTH-1:$clog2(CVA6Cfg.XLEN/8)] <<
|
||||
$clog2(CVA6Cfg.XLEN); // shift by log2(XLEN) to the left
|
||||
axi_offset = '0;
|
||||
// XLEN offset within AXI request
|
||||
axi_offset = (mem_req_q.index >> $clog2(CVA6Cfg.XLEN / 8)) << $clog2(CVA6Cfg.XLEN);
|
||||
// default assignments
|
||||
state_d = state_q;
|
||||
mem_req_d = mem_req_q;
|
||||
|
@ -138,11 +139,6 @@ module cache_ctrl
|
|||
|
||||
mem_req_d.killed |= req_port_i.kill_req;
|
||||
|
||||
if (CVA6Cfg.XLEN == 32) begin
|
||||
axi_offset = mem_req_q.index[$clog2(CVA6Cfg.AxiDataWidth/8)-1:$clog2(CVA6Cfg.XLEN/8)] <<
|
||||
$clog2(CVA6Cfg.XLEN);
|
||||
end
|
||||
|
||||
case (state_q)
|
||||
|
||||
IDLE: begin
|
||||
|
@ -311,9 +307,9 @@ module cache_ctrl
|
|||
// two memory look-ups on a single-ported SRAM and therefore is non-atomic
|
||||
if (!mshr_index_matches_i) begin
|
||||
// store data, write dirty bit
|
||||
req_o = hit_way_q;
|
||||
addr_o = mem_req_q.index;
|
||||
we_o = 1'b1;
|
||||
req_o = hit_way_q;
|
||||
addr_o = mem_req_q.index;
|
||||
we_o = 1'b1;
|
||||
|
||||
be_o.vldrty = hit_way_q;
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ module cva6_hpdcache_if_adapter
|
|||
// {{{
|
||||
#(
|
||||
parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty,
|
||||
parameter hpdcache_pkg::hpdcache_cfg_t hpdcacheCfg = '0,
|
||||
parameter hpdcache_pkg::hpdcache_cfg_t HPDcacheCfg = '0,
|
||||
parameter type hpdcache_tag_t = logic,
|
||||
parameter type hpdcache_req_offset_t = logic,
|
||||
parameter type hpdcache_req_sid_t = logic,
|
||||
|
@ -22,7 +22,8 @@ module cva6_hpdcache_if_adapter
|
|||
parameter type hpdcache_rsp_t = logic,
|
||||
parameter type dcache_req_i_t = logic,
|
||||
parameter type dcache_req_o_t = logic,
|
||||
parameter bit is_load_port = 1'b1
|
||||
parameter bit InvalidateOnFlush = 1'b0,
|
||||
parameter bit IsLoadPort = 1'b1
|
||||
)
|
||||
// }}}
|
||||
|
||||
|
@ -42,6 +43,10 @@ module cva6_hpdcache_if_adapter
|
|||
input ariane_pkg::amo_req_t cva6_amo_req_i,
|
||||
output ariane_pkg::amo_resp_t cva6_amo_resp_o,
|
||||
|
||||
// Dcache flush signal
|
||||
input logic cva6_dcache_flush_i,
|
||||
output logic cva6_dcache_flush_ack_o,
|
||||
|
||||
// Request port to the L1 Dcache
|
||||
output logic hpdcache_req_valid_o,
|
||||
input logic hpdcache_req_ready_i,
|
||||
|
@ -58,8 +63,13 @@ module cva6_hpdcache_if_adapter
|
|||
|
||||
// Internal nets and registers
|
||||
// {{{
|
||||
logic forward_store, forward_amo;
|
||||
typedef enum {
|
||||
FLUSH_IDLE,
|
||||
FLUSH_PEND
|
||||
} flush_fsm_t;
|
||||
|
||||
logic hpdcache_req_is_uncacheable;
|
||||
hpdcache_req_t hpdcache_req;
|
||||
// }}}
|
||||
|
||||
// Request forwarding
|
||||
|
@ -67,7 +77,7 @@ module cva6_hpdcache_if_adapter
|
|||
generate
|
||||
// LOAD request
|
||||
// {{{
|
||||
if (is_load_port == 1'b1) begin : load_port_gen
|
||||
if (IsLoadPort == 1'b1) begin : load_port_gen
|
||||
assign hpdcache_req_is_uncacheable = !config_pkg::is_inside_cacheable_regions(
|
||||
CVA6Cfg,
|
||||
{
|
||||
|
@ -78,29 +88,41 @@ module cva6_hpdcache_if_adapter
|
|||
);
|
||||
|
||||
// Request forwarding
|
||||
assign hpdcache_req_valid_o = cva6_req_i.data_req,
|
||||
hpdcache_req_o.addr_offset = cva6_req_i.address_index,
|
||||
hpdcache_req_o.wdata = '0,
|
||||
hpdcache_req_o.op = hpdcache_pkg::HPDCACHE_REQ_LOAD,
|
||||
hpdcache_req_o.be = cva6_req_i.data_be,
|
||||
hpdcache_req_o.size = cva6_req_i.data_size,
|
||||
hpdcache_req_o.sid = hpdcache_req_sid_i,
|
||||
hpdcache_req_o.tid = cva6_req_i.data_id,
|
||||
hpdcache_req_o.need_rsp = 1'b1,
|
||||
hpdcache_req_o.phys_indexed = 1'b0,
|
||||
hpdcache_req_o.addr_tag = '0, // unused on virtually indexed request
|
||||
hpdcache_req_o.pma = '0; // unused on virtually indexed request
|
||||
assign hpdcache_req_valid_o = cva6_req_i.data_req;
|
||||
assign hpdcache_req.addr_offset = cva6_req_i.address_index;
|
||||
assign hpdcache_req.wdata = '0;
|
||||
assign hpdcache_req.op = hpdcache_pkg::HPDCACHE_REQ_LOAD;
|
||||
assign hpdcache_req.be = cva6_req_i.data_be;
|
||||
assign hpdcache_req.size = cva6_req_i.data_size;
|
||||
assign hpdcache_req.sid = hpdcache_req_sid_i;
|
||||
assign hpdcache_req.tid = cva6_req_i.data_id;
|
||||
assign hpdcache_req.need_rsp = 1'b1;
|
||||
assign hpdcache_req.phys_indexed = 1'b0;
|
||||
assign hpdcache_req.addr_tag = '0; // unused on virtually indexed request
|
||||
assign hpdcache_req.pma.uncacheable = 1'b0;
|
||||
assign hpdcache_req.pma.io = 1'b0;
|
||||
assign hpdcache_req.pma.wr_policy_hint = hpdcache_pkg::HPDCACHE_WR_POLICY_AUTO;
|
||||
|
||||
assign hpdcache_req_abort_o = cva6_req_i.kill_req,
|
||||
hpdcache_req_tag_o = cva6_req_i.address_tag,
|
||||
hpdcache_req_pma_o.uncacheable = hpdcache_req_is_uncacheable,
|
||||
hpdcache_req_pma_o.io = 1'b0;
|
||||
assign hpdcache_req_abort_o = cva6_req_i.kill_req;
|
||||
assign hpdcache_req_tag_o = cva6_req_i.address_tag;
|
||||
assign hpdcache_req_pma_o.uncacheable = hpdcache_req_is_uncacheable;
|
||||
assign hpdcache_req_pma_o.io = 1'b0;
|
||||
assign hpdcache_req_pma_o.wr_policy_hint = hpdcache_pkg::HPDCACHE_WR_POLICY_AUTO;
|
||||
|
||||
// Response forwarding
|
||||
assign cva6_req_o.data_rvalid = hpdcache_rsp_valid_i,
|
||||
cva6_req_o.data_rdata = hpdcache_rsp_i.rdata,
|
||||
cva6_req_o.data_rid = hpdcache_rsp_i.tid,
|
||||
cva6_req_o.data_gnt = hpdcache_req_ready_i;
|
||||
assign cva6_req_o.data_rvalid = hpdcache_rsp_valid_i;
|
||||
assign cva6_req_o.data_rdata = hpdcache_rsp_i.rdata;
|
||||
assign cva6_req_o.data_rid = hpdcache_rsp_i.tid;
|
||||
assign cva6_req_o.data_gnt = hpdcache_req_ready_i;
|
||||
|
||||
// Assertions
|
||||
// {{{
|
||||
// pragma translate_off
|
||||
flush_on_load_port_assert :
|
||||
assert property (@(posedge clk_i) disable iff (rst_ni !== 1'b1) (cva6_dcache_flush_i == 1'b0))
|
||||
else $error("Flush unsupported on load adapters");
|
||||
// pragma translate_on
|
||||
// }}}
|
||||
end // }}}
|
||||
|
||||
// {{{
|
||||
|
@ -116,12 +138,59 @@ module cva6_hpdcache_if_adapter
|
|||
logic [31:0] amo_resp_word;
|
||||
logic amo_pending_q;
|
||||
|
||||
hpdcache_req_t hpdcache_req_amo;
|
||||
hpdcache_req_t hpdcache_req_store;
|
||||
hpdcache_req_t hpdcache_req_flush;
|
||||
|
||||
flush_fsm_t flush_fsm_q, flush_fsm_d;
|
||||
|
||||
logic forward_store, forward_amo, forward_flush;
|
||||
|
||||
// DCACHE flush request
|
||||
// {{{
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin : flush_ff
|
||||
if (!rst_ni) begin
|
||||
flush_fsm_q <= FLUSH_IDLE;
|
||||
end else begin
|
||||
flush_fsm_q <= flush_fsm_d;
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin : flush_comb
|
||||
forward_flush = 1'b0;
|
||||
cva6_dcache_flush_ack_o = 1'b0;
|
||||
|
||||
flush_fsm_d = flush_fsm_q;
|
||||
|
||||
case (flush_fsm_q)
|
||||
FLUSH_IDLE: begin
|
||||
if (cva6_dcache_flush_i) begin
|
||||
forward_flush = 1'b1;
|
||||
if (hpdcache_req_ready_i) begin
|
||||
flush_fsm_d = FLUSH_PEND;
|
||||
end
|
||||
end
|
||||
end
|
||||
FLUSH_PEND: begin
|
||||
if (hpdcache_rsp_valid_i) begin
|
||||
if (hpdcache_rsp_i.tid == '0) begin
|
||||
cva6_dcache_flush_ack_o = 1'b1;
|
||||
flush_fsm_d = FLUSH_IDLE;
|
||||
end
|
||||
end
|
||||
end
|
||||
default: begin
|
||||
end
|
||||
endcase
|
||||
end
|
||||
// }}}
|
||||
|
||||
// AMO logic
|
||||
// {{{
|
||||
always_comb begin : amo_op_comb
|
||||
amo_addr = cva6_amo_req_i.operand_a;
|
||||
amo_addr_offset = amo_addr[0+:hpdcacheCfg.reqOffsetWidth];
|
||||
amo_tag = amo_addr[hpdcacheCfg.reqOffsetWidth+:hpdcacheCfg.tagWidth];
|
||||
amo_addr_offset = amo_addr[0+:HPDcacheCfg.reqOffsetWidth];
|
||||
amo_tag = amo_addr[HPDcacheCfg.reqOffsetWidth+:HPDcacheCfg.tagWidth];
|
||||
unique case (cva6_amo_req_i.amo_op)
|
||||
ariane_pkg::AMO_LR: amo_op = hpdcache_pkg::HPDCACHE_REQ_AMO_LR;
|
||||
ariane_pkg::AMO_SC: amo_op = hpdcache_pkg::HPDCACHE_REQ_AMO_SC;
|
||||
|
@ -145,7 +214,7 @@ module cva6_hpdcache_if_adapter
|
|||
CVA6Cfg,
|
||||
{
|
||||
{64 - CVA6Cfg.DCACHE_TAG_WIDTH{1'b0}}
|
||||
, hpdcache_req_o.addr_tag,
|
||||
, hpdcache_req.addr_tag,
|
||||
{CVA6Cfg.DCACHE_INDEX_WIDTH{1'b0}}
|
||||
}
|
||||
);
|
||||
|
@ -160,25 +229,78 @@ module cva6_hpdcache_if_adapter
|
|||
assign amo_data_be = 8'h0f;
|
||||
end
|
||||
|
||||
assign hpdcache_req_amo = '{
|
||||
addr_offset: amo_addr_offset,
|
||||
wdata: amo_data,
|
||||
op: amo_op,
|
||||
be: amo_data_be,
|
||||
size: cva6_amo_req_i.size,
|
||||
sid: hpdcache_req_sid_i,
|
||||
tid: '1,
|
||||
need_rsp: 1'b1,
|
||||
phys_indexed: 1'b1,
|
||||
addr_tag: amo_tag,
|
||||
pma: '{
|
||||
uncacheable: hpdcache_req_is_uncacheable,
|
||||
io: 1'b0,
|
||||
wr_policy_hint: hpdcache_pkg::HPDCACHE_WR_POLICY_AUTO
|
||||
}
|
||||
};
|
||||
|
||||
assign hpdcache_req_store = '{
|
||||
addr_offset: cva6_req_i.address_index,
|
||||
wdata: cva6_req_i.data_wdata,
|
||||
op: hpdcache_pkg::HPDCACHE_REQ_STORE,
|
||||
be: cva6_req_i.data_be,
|
||||
size: cva6_req_i.data_size,
|
||||
sid: hpdcache_req_sid_i,
|
||||
tid: '0,
|
||||
need_rsp: 1'b0,
|
||||
phys_indexed: 1'b1,
|
||||
addr_tag: cva6_req_i.address_tag,
|
||||
pma: '{
|
||||
uncacheable: hpdcache_req_is_uncacheable,
|
||||
io: 1'b0,
|
||||
wr_policy_hint: hpdcache_pkg::HPDCACHE_WR_POLICY_AUTO
|
||||
}
|
||||
};
|
||||
|
||||
assign hpdcache_req_flush = '{
|
||||
addr_offset: '0,
|
||||
addr_tag: '0,
|
||||
wdata: '0,
|
||||
op:
|
||||
InvalidateOnFlush
|
||||
?
|
||||
hpdcache_pkg::HPDCACHE_REQ_CMO_FLUSH_INVAL_ALL
|
||||
:
|
||||
hpdcache_pkg::HPDCACHE_REQ_CMO_FLUSH_ALL,
|
||||
be: '0,
|
||||
size: '0,
|
||||
sid: hpdcache_req_sid_i,
|
||||
tid: '0,
|
||||
need_rsp: 1'b1,
|
||||
phys_indexed: 1'b0,
|
||||
pma: '{
|
||||
uncacheable: 1'b0,
|
||||
io: 1'b0,
|
||||
wr_policy_hint: hpdcache_pkg::HPDCACHE_WR_POLICY_AUTO
|
||||
}
|
||||
};
|
||||
|
||||
assign forward_store = cva6_req_i.data_req;
|
||||
assign forward_amo = cva6_amo_req_i.req;
|
||||
|
||||
assign hpdcache_req_valid_o = forward_store | (forward_amo & ~amo_pending_q);
|
||||
assign hpdcache_req_o.addr_offset = forward_amo ? amo_addr_offset : cva6_req_i.address_index;
|
||||
assign hpdcache_req_o.wdata = forward_amo ? amo_data : cva6_req_i.data_wdata;
|
||||
assign hpdcache_req_o.op = forward_amo ? amo_op : hpdcache_pkg::HPDCACHE_REQ_STORE;
|
||||
assign hpdcache_req_o.be = forward_amo ? amo_data_be : cva6_req_i.data_be;
|
||||
assign hpdcache_req_o.size = forward_amo ? cva6_amo_req_i.size : cva6_req_i.data_size;
|
||||
assign hpdcache_req_o.sid = hpdcache_req_sid_i;
|
||||
assign hpdcache_req_o.tid = forward_amo ? '1 : '0;
|
||||
assign hpdcache_req_o.need_rsp = forward_amo;
|
||||
assign hpdcache_req_o.phys_indexed = 1'b1;
|
||||
assign hpdcache_req_o.addr_tag = forward_amo ? amo_tag : cva6_req_i.address_tag;
|
||||
assign hpdcache_req_o.pma.uncacheable = hpdcache_req_is_uncacheable;
|
||||
assign hpdcache_req_o.pma.io = 1'b0;
|
||||
assign hpdcache_req_valid_o = (forward_amo & ~amo_pending_q) | forward_store | forward_flush;
|
||||
|
||||
assign hpdcache_req = forward_amo ? hpdcache_req_amo :
|
||||
forward_store ? hpdcache_req_store : hpdcache_req_flush;
|
||||
|
||||
assign hpdcache_req_abort_o = 1'b0; // unused on physically indexed requests
|
||||
assign hpdcache_req_tag_o = '0; // unused on physically indexed requests
|
||||
assign hpdcache_req_pma_o = '0; // unused on physically indexed requests
|
||||
assign hpdcache_req_pma_o.uncacheable = 1'b0;
|
||||
assign hpdcache_req_pma_o.io = 1'b0;
|
||||
assign hpdcache_req_pma_o.wr_policy_hint = hpdcache_pkg::HPDCACHE_WR_POLICY_AUTO;
|
||||
// }}}
|
||||
|
||||
// Response forwarding
|
||||
|
@ -210,17 +332,21 @@ module cva6_hpdcache_if_adapter
|
|||
(~cva6_amo_resp_o.ack & amo_pending_q);
|
||||
end
|
||||
end
|
||||
|
||||
// Assertions
|
||||
// {{{
|
||||
// pragma translate_off
|
||||
forward_one_request_assert :
|
||||
assert property (@(posedge clk_i) disable iff (rst_ni !== 1'b1) ($onehot0(
|
||||
{forward_store, forward_amo, forward_flush}
|
||||
)))
|
||||
else $error("Only one request shall be forwarded");
|
||||
// pragma translate_on
|
||||
// }}}
|
||||
end
|
||||
// }}}
|
||||
endgenerate
|
||||
// }}}
|
||||
|
||||
// Assertions
|
||||
// {{{
|
||||
// pragma translate_off
|
||||
forward_one_request_assert :
|
||||
assert property (@(posedge clk_i) ($onehot0({forward_store, forward_amo})))
|
||||
else $error("Only one request shall be forwarded");
|
||||
// pragma translate_on
|
||||
assign hpdcache_req_o = hpdcache_req;
|
||||
// }}}
|
||||
endmodule
|
||||
|
|
|
@ -189,46 +189,58 @@ module cva6_hpdcache_subsystem
|
|||
// NumPorts + 1: Hardware Memory Prefetcher (hwpf)
|
||||
localparam int HPDCACHE_NREQUESTERS = NumPorts + 2;
|
||||
|
||||
localparam hpdcache_pkg::hpdcache_user_cfg_t hpdcacheUserCfg = '{
|
||||
nRequesters: HPDCACHE_NREQUESTERS,
|
||||
paWidth: CVA6Cfg.PLEN,
|
||||
wordWidth: CVA6Cfg.XLEN,
|
||||
sets: CVA6Cfg.DCACHE_NUM_WORDS,
|
||||
ways: CVA6Cfg.DCACHE_SET_ASSOC,
|
||||
clWords: CVA6Cfg.DCACHE_LINE_WIDTH / CVA6Cfg.XLEN,
|
||||
reqWords: 1,
|
||||
reqTransIdWidth: CVA6Cfg.DcacheIdWidth,
|
||||
reqSrcIdWidth: 3, // Up to 8 requesters
|
||||
victimSel: hpdcache_pkg::HPDCACHE_VICTIM_RANDOM,
|
||||
dataWaysPerRamWord: __minu(CVA6Cfg.DCACHE_SET_ASSOC, 128 / CVA6Cfg.XLEN),
|
||||
dataSetsPerRam: CVA6Cfg.DCACHE_NUM_WORDS,
|
||||
dataRamByteEnable: 1'b1,
|
||||
accessWords: __maxu(CVA6Cfg.DCACHE_LINE_WIDTH / (2 * CVA6Cfg.XLEN), 1),
|
||||
mshrSets: CVA6Cfg.NrLoadBufEntries < 16 ? 1 : CVA6Cfg.NrLoadBufEntries / 2,
|
||||
mshrWays: CVA6Cfg.NrLoadBufEntries < 16 ? CVA6Cfg.NrLoadBufEntries : 2,
|
||||
mshrWaysPerRamWord: CVA6Cfg.NrLoadBufEntries < 16 ? CVA6Cfg.NrLoadBufEntries : 2,
|
||||
mshrSetsPerRam: CVA6Cfg.NrLoadBufEntries < 16 ? 1 : CVA6Cfg.NrLoadBufEntries / 2,
|
||||
mshrRamByteEnable: 1'b1,
|
||||
mshrUseRegbank: (CVA6Cfg.NrLoadBufEntries < 16),
|
||||
refillCoreRspFeedthrough: 1'b1,
|
||||
refillFifoDepth: 2,
|
||||
wbufDirEntries: CVA6Cfg.WtDcacheWbufDepth,
|
||||
wbufDataEntries: CVA6Cfg.WtDcacheWbufDepth,
|
||||
wbufWords: 1,
|
||||
wbufTimecntWidth: 3,
|
||||
wbufSendFeedThrough: 1'b0,
|
||||
rtabEntries: 4,
|
||||
memAddrWidth: CVA6Cfg.AxiAddrWidth,
|
||||
memIdWidth: CVA6Cfg.MEM_TID_WIDTH,
|
||||
memDataWidth: CVA6Cfg.AxiDataWidth
|
||||
};
|
||||
function automatic hpdcache_pkg::hpdcache_user_cfg_t hpdcacheSetConfig();
|
||||
hpdcache_pkg::hpdcache_user_cfg_t userCfg;
|
||||
userCfg.nRequesters = HPDCACHE_NREQUESTERS;
|
||||
userCfg.paWidth = CVA6Cfg.PLEN;
|
||||
userCfg.wordWidth = CVA6Cfg.XLEN;
|
||||
userCfg.sets = CVA6Cfg.DCACHE_NUM_WORDS;
|
||||
userCfg.ways = CVA6Cfg.DCACHE_SET_ASSOC;
|
||||
userCfg.clWords = CVA6Cfg.DCACHE_LINE_WIDTH / CVA6Cfg.XLEN;
|
||||
userCfg.reqWords = 1;
|
||||
userCfg.reqTransIdWidth = CVA6Cfg.DcacheIdWidth;
|
||||
userCfg.reqSrcIdWidth = 3; // Up to 8 requesters
|
||||
userCfg.victimSel = hpdcache_pkg::HPDCACHE_VICTIM_RANDOM;
|
||||
userCfg.dataWaysPerRamWord = __minu(CVA6Cfg.DCACHE_SET_ASSOC, 128 / CVA6Cfg.XLEN);
|
||||
userCfg.dataSetsPerRam = CVA6Cfg.DCACHE_NUM_WORDS;
|
||||
userCfg.dataRamByteEnable = 1'b1;
|
||||
userCfg.accessWords = __maxu(CVA6Cfg.AxiDataWidth / CVA6Cfg.XLEN, 1 /*reqWords*/);
|
||||
userCfg.mshrSets = CVA6Cfg.NrLoadBufEntries < 16 ? 1 : CVA6Cfg.NrLoadBufEntries / 2;
|
||||
userCfg.mshrWays = CVA6Cfg.NrLoadBufEntries < 16 ? CVA6Cfg.NrLoadBufEntries : 2;
|
||||
userCfg.mshrWaysPerRamWord = CVA6Cfg.NrLoadBufEntries < 16 ? CVA6Cfg.NrLoadBufEntries : 2;
|
||||
userCfg.mshrSetsPerRam = CVA6Cfg.NrLoadBufEntries < 16 ? 1 : CVA6Cfg.NrLoadBufEntries / 2;
|
||||
userCfg.mshrRamByteEnable = 1'b1;
|
||||
userCfg.mshrUseRegbank = (CVA6Cfg.NrLoadBufEntries < 16);
|
||||
userCfg.refillCoreRspFeedthrough = 1'b1;
|
||||
userCfg.refillFifoDepth = 2;
|
||||
userCfg.wbufDirEntries = CVA6Cfg.WtDcacheWbufDepth;
|
||||
userCfg.wbufDataEntries = CVA6Cfg.WtDcacheWbufDepth;
|
||||
userCfg.wbufWords = 1;
|
||||
userCfg.wbufTimecntWidth = 3;
|
||||
userCfg.rtabEntries = 4;
|
||||
/*FIXME we should add additional CVA6 config parameters (flushEntries)*/
|
||||
userCfg.flushEntries = CVA6Cfg.WtDcacheWbufDepth;
|
||||
/*FIXME we should add additional CVA6 config parameters (flushFifoDepth)*/
|
||||
userCfg.flushFifoDepth = CVA6Cfg.WtDcacheWbufDepth;
|
||||
userCfg.memAddrWidth = CVA6Cfg.AxiAddrWidth;
|
||||
userCfg.memIdWidth = CVA6Cfg.MEM_TID_WIDTH;
|
||||
userCfg.memDataWidth = CVA6Cfg.AxiDataWidth;
|
||||
userCfg.wtEn =
|
||||
(CVA6Cfg.DCacheType == config_pkg::HPDCACHE_WT) ||
|
||||
(CVA6Cfg.DCacheType == config_pkg::HPDCACHE_WT_WB);
|
||||
userCfg.wbEn =
|
||||
(CVA6Cfg.DCacheType == config_pkg::HPDCACHE_WB) ||
|
||||
(CVA6Cfg.DCacheType == config_pkg::HPDCACHE_WT_WB);
|
||||
return userCfg;
|
||||
endfunction
|
||||
|
||||
localparam hpdcache_pkg::hpdcache_cfg_t hpdcacheCfg = hpdcache_pkg::hpdcacheBuildConfig(
|
||||
hpdcacheUserCfg
|
||||
localparam hpdcache_pkg::hpdcache_user_cfg_t HPDcacheUserCfg = hpdcacheSetConfig();
|
||||
localparam hpdcache_pkg::hpdcache_cfg_t HPDcacheCfg = hpdcache_pkg::hpdcacheBuildConfig(
|
||||
HPDcacheUserCfg
|
||||
);
|
||||
|
||||
`HPDCACHE_TYPEDEF_MEM_ATTR_T(hpdcache_mem_addr_t, hpdcache_mem_id_t, hpdcache_mem_data_t,
|
||||
hpdcache_mem_be_t, hpdcacheCfg);
|
||||
hpdcache_mem_be_t, HPDcacheCfg);
|
||||
`HPDCACHE_TYPEDEF_MEM_REQ_T(hpdcache_mem_req_t, hpdcache_mem_addr_t, hpdcache_mem_id_t);
|
||||
`HPDCACHE_TYPEDEF_MEM_RESP_R_T(hpdcache_mem_resp_r_t, hpdcache_mem_id_t, hpdcache_mem_data_t);
|
||||
`HPDCACHE_TYPEDEF_MEM_REQ_W_T(hpdcache_mem_req_w_t, hpdcache_mem_data_t, hpdcache_mem_be_t);
|
||||
|
@ -236,379 +248,110 @@ module cva6_hpdcache_subsystem
|
|||
|
||||
`HPDCACHE_TYPEDEF_REQ_ATTR_T(hpdcache_req_offset_t, hpdcache_data_word_t, hpdcache_data_be_t,
|
||||
hpdcache_req_data_t, hpdcache_req_be_t, hpdcache_req_sid_t,
|
||||
hpdcache_req_tid_t, hpdcache_tag_t, hpdcacheCfg);
|
||||
hpdcache_req_tid_t, hpdcache_tag_t, HPDcacheCfg);
|
||||
`HPDCACHE_TYPEDEF_REQ_T(hpdcache_req_t, hpdcache_req_offset_t, hpdcache_req_data_t,
|
||||
hpdcache_req_be_t, hpdcache_req_sid_t, hpdcache_req_tid_t,
|
||||
hpdcache_tag_t);
|
||||
`HPDCACHE_TYPEDEF_RSP_T(hpdcache_rsp_t, hpdcache_req_data_t, hpdcache_req_sid_t,
|
||||
hpdcache_req_tid_t);
|
||||
|
||||
typedef logic [hpdcacheCfg.u.wbufTimecntWidth-1:0] hpdcache_wbuf_timecnt_t;
|
||||
typedef logic [HPDcacheCfg.u.wbufTimecntWidth-1:0] hpdcache_wbuf_timecnt_t;
|
||||
|
||||
typedef logic [63:0] hwpf_stride_param_t;
|
||||
logic dcache_read_ready;
|
||||
logic dcache_read_valid;
|
||||
hpdcache_mem_req_t dcache_read;
|
||||
|
||||
logic dcache_req_valid[HPDCACHE_NREQUESTERS-1:0];
|
||||
logic dcache_req_ready[HPDCACHE_NREQUESTERS-1:0];
|
||||
hpdcache_req_t dcache_req [HPDCACHE_NREQUESTERS-1:0];
|
||||
logic dcache_req_abort[HPDCACHE_NREQUESTERS-1:0];
|
||||
hpdcache_tag_t dcache_req_tag [HPDCACHE_NREQUESTERS-1:0];
|
||||
hpdcache_pkg::hpdcache_pma_t dcache_req_pma [HPDCACHE_NREQUESTERS-1:0];
|
||||
logic dcache_rsp_valid[HPDCACHE_NREQUESTERS-1:0];
|
||||
hpdcache_rsp_t dcache_rsp [HPDCACHE_NREQUESTERS-1:0];
|
||||
logic dcache_read_miss, dcache_write_miss;
|
||||
logic dcache_read_resp_ready;
|
||||
logic dcache_read_resp_valid;
|
||||
hpdcache_mem_resp_r_t dcache_read_resp;
|
||||
|
||||
logic [ 2:0] snoop_valid;
|
||||
logic [ 2:0] snoop_abort;
|
||||
hpdcache_req_offset_t [ 2:0] snoop_addr_offset;
|
||||
hpdcache_tag_t [ 2:0] snoop_addr_tag;
|
||||
logic [ 2:0] snoop_phys_indexed;
|
||||
logic dcache_write_ready;
|
||||
logic dcache_write_valid;
|
||||
hpdcache_mem_req_t dcache_write;
|
||||
|
||||
logic dcache_cmo_req_is_prefetch;
|
||||
logic dcache_write_data_ready;
|
||||
logic dcache_write_data_valid;
|
||||
hpdcache_mem_req_w_t dcache_write_data;
|
||||
|
||||
logic dcache_miss_ready;
|
||||
logic dcache_miss_valid;
|
||||
hpdcache_mem_req_t dcache_miss;
|
||||
logic dcache_write_resp_ready;
|
||||
logic dcache_write_resp_valid;
|
||||
hpdcache_mem_resp_w_t dcache_write_resp;
|
||||
|
||||
logic dcache_miss_resp_ready;
|
||||
logic dcache_miss_resp_valid;
|
||||
hpdcache_mem_resp_r_t dcache_miss_resp;
|
||||
|
||||
logic dcache_wbuf_ready;
|
||||
logic dcache_wbuf_valid;
|
||||
hpdcache_mem_req_t dcache_wbuf;
|
||||
|
||||
logic dcache_wbuf_data_ready;
|
||||
logic dcache_wbuf_data_valid;
|
||||
hpdcache_mem_req_w_t dcache_wbuf_data;
|
||||
|
||||
logic dcache_wbuf_resp_ready;
|
||||
logic dcache_wbuf_resp_valid;
|
||||
hpdcache_mem_resp_w_t dcache_wbuf_resp;
|
||||
|
||||
logic dcache_uc_read_ready;
|
||||
logic dcache_uc_read_valid;
|
||||
hpdcache_mem_req_t dcache_uc_read;
|
||||
|
||||
logic dcache_uc_read_resp_ready;
|
||||
logic dcache_uc_read_resp_valid;
|
||||
hpdcache_mem_resp_r_t dcache_uc_read_resp;
|
||||
|
||||
logic dcache_uc_write_ready;
|
||||
logic dcache_uc_write_valid;
|
||||
hpdcache_mem_req_t dcache_uc_write;
|
||||
|
||||
logic dcache_uc_write_data_ready;
|
||||
logic dcache_uc_write_data_valid;
|
||||
hpdcache_mem_req_w_t dcache_uc_write_data;
|
||||
|
||||
logic dcache_uc_write_resp_ready;
|
||||
logic dcache_uc_write_resp_valid;
|
||||
hpdcache_mem_resp_w_t dcache_uc_write_resp;
|
||||
|
||||
hwpf_stride_pkg::hwpf_stride_throttle_t [NrHwPrefetchers-1:0] hwpf_throttle_in;
|
||||
hwpf_stride_pkg::hwpf_stride_throttle_t [NrHwPrefetchers-1:0] hwpf_throttle_out;
|
||||
|
||||
generate
|
||||
dcache_req_i_t dcache_req_ports[HPDCACHE_NREQUESTERS-1:0];
|
||||
|
||||
for (genvar r = 0; r < (NumPorts - 1); r++) begin : gen_cva6_hpdcache_load_if_adapter
|
||||
assign dcache_req_ports[r] = dcache_req_ports_i[r];
|
||||
|
||||
cva6_hpdcache_if_adapter #(
|
||||
.CVA6Cfg (CVA6Cfg),
|
||||
.hpdcacheCfg (hpdcacheCfg),
|
||||
.hpdcache_tag_t (hpdcache_tag_t),
|
||||
.hpdcache_req_offset_t(hpdcache_req_offset_t),
|
||||
.hpdcache_req_sid_t (hpdcache_req_sid_t),
|
||||
.hpdcache_req_t (hpdcache_req_t),
|
||||
.hpdcache_rsp_t (hpdcache_rsp_t),
|
||||
.dcache_req_i_t (dcache_req_i_t),
|
||||
.dcache_req_o_t (dcache_req_o_t),
|
||||
.is_load_port (1'b1)
|
||||
) i_cva6_hpdcache_load_if_adapter (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
|
||||
.hpdcache_req_sid_i(hpdcache_req_sid_t'(r)),
|
||||
|
||||
.cva6_req_i (dcache_req_ports[r]),
|
||||
.cva6_req_o (dcache_req_ports_o[r]),
|
||||
.cva6_amo_req_i ('0),
|
||||
.cva6_amo_resp_o( /* unused */),
|
||||
|
||||
.hpdcache_req_valid_o(dcache_req_valid[r]),
|
||||
.hpdcache_req_ready_i(dcache_req_ready[r]),
|
||||
.hpdcache_req_o (dcache_req[r]),
|
||||
.hpdcache_req_abort_o(dcache_req_abort[r]),
|
||||
.hpdcache_req_tag_o (dcache_req_tag[r]),
|
||||
.hpdcache_req_pma_o (dcache_req_pma[r]),
|
||||
|
||||
.hpdcache_rsp_valid_i(dcache_rsp_valid[r]),
|
||||
.hpdcache_rsp_i (dcache_rsp[r])
|
||||
);
|
||||
end
|
||||
|
||||
cva6_hpdcache_if_adapter #(
|
||||
.CVA6Cfg (CVA6Cfg),
|
||||
.hpdcacheCfg (hpdcacheCfg),
|
||||
.hpdcache_tag_t (hpdcache_tag_t),
|
||||
.hpdcache_req_offset_t(hpdcache_req_offset_t),
|
||||
.hpdcache_req_sid_t (hpdcache_req_sid_t),
|
||||
.hpdcache_req_t (hpdcache_req_t),
|
||||
.hpdcache_rsp_t (hpdcache_rsp_t),
|
||||
.dcache_req_i_t (dcache_req_i_t),
|
||||
.dcache_req_o_t (dcache_req_o_t),
|
||||
.is_load_port (1'b0)
|
||||
) i_cva6_hpdcache_store_if_adapter (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
|
||||
.hpdcache_req_sid_i(hpdcache_req_sid_t'(NumPorts - 1)),
|
||||
|
||||
.cva6_req_i (dcache_req_ports_i[NumPorts-1]),
|
||||
.cva6_req_o (dcache_req_ports_o[NumPorts-1]),
|
||||
.cva6_amo_req_i (dcache_amo_req_i),
|
||||
.cva6_amo_resp_o(dcache_amo_resp_o),
|
||||
|
||||
.hpdcache_req_valid_o(dcache_req_valid[NumPorts-1]),
|
||||
.hpdcache_req_ready_i(dcache_req_ready[NumPorts-1]),
|
||||
.hpdcache_req_o (dcache_req[NumPorts-1]),
|
||||
.hpdcache_req_abort_o(dcache_req_abort[NumPorts-1]),
|
||||
.hpdcache_req_tag_o (dcache_req_tag[NumPorts-1]),
|
||||
.hpdcache_req_pma_o (dcache_req_pma[NumPorts-1]),
|
||||
|
||||
.hpdcache_rsp_valid_i(dcache_rsp_valid[NumPorts-1]),
|
||||
.hpdcache_rsp_i (dcache_rsp[NumPorts-1])
|
||||
);
|
||||
|
||||
`ifdef HPDCACHE_ENABLE_CMO
|
||||
cva6_hpdcache_cmo_if_adapter #(
|
||||
.cmo_req_t(cmo_req_t),
|
||||
.cmo_rsp_t(cmo_rsp_t)
|
||||
) i_cva6_hpdcache_cmo_if_adapter (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
|
||||
.dcache_req_sid_i(hpdcache_req_sid_t'(NumPorts)),
|
||||
|
||||
.cva6_cmo_req_i (dcache_cmo_req_i),
|
||||
.cva6_cmo_resp_o(dcache_cmo_resp_o),
|
||||
|
||||
.dcache_req_valid_o(dcache_req_valid[NumPorts]),
|
||||
.dcache_req_ready_i(dcache_req_ready[NumPorts]),
|
||||
.dcache_req_o (dcache_req[NumPorts]),
|
||||
.dcache_req_abort_o(dcache_req_abort[NumPorts]),
|
||||
.dcache_req_tag_o (dcache_req_tag[NumPorts]),
|
||||
.dcache_req_pma_o (dcache_req_pma[NumPorts]),
|
||||
|
||||
.dcache_rsp_valid_i(dcache_rsp_valid[NumPorts]),
|
||||
.dcache_rsp_i (dcache_rsp[NumPorts])
|
||||
);
|
||||
`else
|
||||
assign dcache_req_valid[NumPorts] = 1'b0,
|
||||
dcache_req[NumPorts] = '0,
|
||||
dcache_req_abort[NumPorts] = 1'b0,
|
||||
dcache_req_tag[NumPorts] = '0,
|
||||
dcache_req_pma[NumPorts] = '0;
|
||||
`endif
|
||||
endgenerate
|
||||
|
||||
// Snoop load port
|
||||
assign snoop_valid[0] = dcache_req_valid[1] & dcache_req_ready[1],
|
||||
snoop_abort[0] = dcache_req_abort[1],
|
||||
snoop_addr_offset[0] = dcache_req[1].addr_offset,
|
||||
snoop_addr_tag[0] = dcache_req_tag[1],
|
||||
snoop_phys_indexed[0] = dcache_req[1].phys_indexed;
|
||||
|
||||
// Snoop Store/AMO port
|
||||
assign snoop_valid[1] = dcache_req_valid[NumPorts-1] & dcache_req_ready[NumPorts-1],
|
||||
snoop_abort[1] = dcache_req_abort[NumPorts-1],
|
||||
snoop_addr_offset[1] = dcache_req[NumPorts-1].addr_offset,
|
||||
snoop_addr_tag[1] = dcache_req_tag[NumPorts-1],
|
||||
snoop_phys_indexed[1] = dcache_req[NumPorts-1].phys_indexed;
|
||||
|
||||
`ifdef HPDCACHE_ENABLE_CMO
|
||||
// Snoop CMO port (in case of read prefetch accesses)
|
||||
assign dcache_cmo_req_is_prefetch = hpdcache_pkg::is_cmo_prefetch(
|
||||
dcache_req[NumPorts].op, dcache_req[NumPorts].size
|
||||
);
|
||||
assign snoop_valid[2] = dcache_req_valid[NumPorts]
|
||||
& dcache_req_ready[NumPorts]
|
||||
& dcache_cmo_req_is_prefetch,
|
||||
snoop_abort[2] = dcache_req_abort[NumPorts],
|
||||
snoop_addr_offset[2] = dcache_req[NumPorts].addr_offset,
|
||||
snoop_addr_tag[2] = dcache_req_tag[NumPorts],
|
||||
snoop_phys_indexed[2] = dcache_req[NumPorts].phys_indexed;
|
||||
`else
|
||||
assign snoop_valid[2] = 1'b0,
|
||||
snoop_abort[2] = 1'b0,
|
||||
snoop_addr_offset[2] = '0,
|
||||
snoop_addr_tag[2] = '0,
|
||||
snoop_phys_indexed[2] = 1'b0;
|
||||
`endif
|
||||
|
||||
generate
|
||||
for (genvar h = 0; h < NrHwPrefetchers; h++) begin : gen_hwpf_throttle
|
||||
assign hwpf_throttle_in[h] = hwpf_stride_pkg::hwpf_stride_throttle_t'(hwpf_throttle_i[h]),
|
||||
hwpf_throttle_o[h] = hwpf_stride_pkg::hwpf_stride_param_t'(hwpf_throttle_out[h]);
|
||||
end
|
||||
endgenerate
|
||||
|
||||
hwpf_stride_wrapper #(
|
||||
.hpdcacheCfg (hpdcacheCfg),
|
||||
.NUM_HW_PREFETCH (NrHwPrefetchers),
|
||||
.NUM_SNOOP_PORTS (3),
|
||||
.hpdcache_tag_t (hpdcache_tag_t),
|
||||
.hpdcache_req_offset_t(hpdcache_req_offset_t),
|
||||
.hpdcache_req_data_t (hpdcache_req_data_t),
|
||||
.hpdcache_req_be_t (hpdcache_req_be_t),
|
||||
.hpdcache_req_sid_t (hpdcache_req_sid_t),
|
||||
.hpdcache_req_tid_t (hpdcache_req_tid_t),
|
||||
.hpdcache_req_t (hpdcache_req_t),
|
||||
.hpdcache_rsp_t (hpdcache_rsp_t)
|
||||
) i_hwpf_stride_wrapper (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
|
||||
.hwpf_stride_base_set_i (hwpf_base_set_i),
|
||||
.hwpf_stride_base_i (hwpf_base_i),
|
||||
.hwpf_stride_base_o (hwpf_base_o),
|
||||
.hwpf_stride_param_set_i (hwpf_param_set_i),
|
||||
.hwpf_stride_param_i (hwpf_param_i),
|
||||
.hwpf_stride_param_o (hwpf_param_o),
|
||||
.hwpf_stride_throttle_set_i(hwpf_throttle_set_i),
|
||||
.hwpf_stride_throttle_i (hwpf_throttle_in),
|
||||
.hwpf_stride_throttle_o (hwpf_throttle_out),
|
||||
.hwpf_stride_status_o (hwpf_status_o),
|
||||
|
||||
.snoop_valid_i (snoop_valid),
|
||||
.snoop_abort_i (snoop_abort),
|
||||
.snoop_addr_offset_i (snoop_addr_offset),
|
||||
.snoop_addr_tag_i (snoop_addr_tag),
|
||||
.snoop_phys_indexed_i(snoop_phys_indexed),
|
||||
|
||||
.hpdcache_req_sid_i(hpdcache_req_sid_t'(NumPorts + 1)),
|
||||
|
||||
.hpdcache_req_valid_o(dcache_req_valid[NumPorts+1]),
|
||||
.hpdcache_req_ready_i(dcache_req_ready[NumPorts+1]),
|
||||
.hpdcache_req_o (dcache_req[NumPorts+1]),
|
||||
.hpdcache_req_abort_o(dcache_req_abort[NumPorts+1]),
|
||||
.hpdcache_req_tag_o (dcache_req_tag[NumPorts+1]),
|
||||
.hpdcache_req_pma_o (dcache_req_pma[NumPorts+1]),
|
||||
.hpdcache_rsp_valid_i(dcache_rsp_valid[NumPorts+1]),
|
||||
.hpdcache_rsp_i (dcache_rsp[NumPorts+1])
|
||||
);
|
||||
|
||||
hpdcache #(
|
||||
.hpdcacheCfg (hpdcacheCfg),
|
||||
.wbuf_timecnt_t (hpdcache_wbuf_timecnt_t),
|
||||
.hpdcache_tag_t (hpdcache_tag_t),
|
||||
.hpdcache_data_word_t (hpdcache_data_word_t),
|
||||
.hpdcache_data_be_t (hpdcache_data_be_t),
|
||||
.hpdcache_req_offset_t(hpdcache_req_offset_t),
|
||||
.hpdcache_req_data_t (hpdcache_req_data_t),
|
||||
.hpdcache_req_be_t (hpdcache_req_be_t),
|
||||
.hpdcache_req_sid_t (hpdcache_req_sid_t),
|
||||
.hpdcache_req_tid_t (hpdcache_req_tid_t),
|
||||
.hpdcache_req_t (hpdcache_req_t),
|
||||
.hpdcache_rsp_t (hpdcache_rsp_t),
|
||||
.hpdcache_mem_addr_t (hpdcache_mem_addr_t),
|
||||
.hpdcache_mem_id_t (hpdcache_mem_id_t),
|
||||
.hpdcache_mem_data_t (hpdcache_mem_data_t),
|
||||
.hpdcache_mem_be_t (hpdcache_mem_be_t),
|
||||
.hpdcache_mem_req_t (hpdcache_mem_req_t),
|
||||
.hpdcache_mem_req_w_t (hpdcache_mem_req_w_t),
|
||||
cva6_hpdcache_wrapper #(
|
||||
.CVA6Cfg(CVA6Cfg),
|
||||
.HPDcacheCfg(HPDcacheCfg),
|
||||
.dcache_req_i_t(dcache_req_i_t),
|
||||
.dcache_req_o_t(dcache_req_o_t),
|
||||
.NumPorts(NumPorts),
|
||||
.NrHwPrefetchers(NrHwPrefetchers),
|
||||
.cmo_req_t(cmo_req_t),
|
||||
.cmo_rsp_t(cmo_rsp_t),
|
||||
.hpdcache_mem_addr_t(hpdcache_mem_addr_t),
|
||||
.hpdcache_mem_id_t(hpdcache_mem_id_t),
|
||||
.hpdcache_mem_data_t(hpdcache_mem_data_t),
|
||||
.hpdcache_mem_be_t(hpdcache_mem_be_t),
|
||||
.hpdcache_mem_req_t(hpdcache_mem_req_t),
|
||||
.hpdcache_mem_req_w_t(hpdcache_mem_req_w_t),
|
||||
.hpdcache_mem_resp_r_t(hpdcache_mem_resp_r_t),
|
||||
.hpdcache_mem_resp_w_t(hpdcache_mem_resp_w_t)
|
||||
) i_hpdcache (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
.hpdcache_mem_resp_w_t(hpdcache_mem_resp_w_t),
|
||||
.hpdcache_req_offset_t(hpdcache_req_offset_t),
|
||||
.hpdcache_data_word_t(hpdcache_data_word_t),
|
||||
.hpdcache_req_data_t(hpdcache_req_data_t),
|
||||
.hpdcache_req_be_t(hpdcache_req_be_t),
|
||||
.hpdcache_req_sid_t(hpdcache_req_sid_t),
|
||||
.hpdcache_req_tid_t(hpdcache_req_tid_t),
|
||||
.hpdcache_tag_t(hpdcache_tag_t),
|
||||
.hpdcache_req_t(hpdcache_req_t),
|
||||
.hpdcache_rsp_t(hpdcache_rsp_t),
|
||||
.hpdcache_wbuf_timecnt_t(hpdcache_wbuf_timecnt_t),
|
||||
.hpdcache_data_be_t(hpdcache_data_be_t)
|
||||
) i_dcache (
|
||||
.clk_i(clk_i),
|
||||
.rst_ni(rst_ni),
|
||||
.dcache_enable_i(dcache_enable_i),
|
||||
.dcache_flush_i(dcache_flush_i),
|
||||
.dcache_flush_ack_o(dcache_flush_ack_o),
|
||||
.dcache_miss_o(dcache_miss_o),
|
||||
.dcache_amo_req_i(dcache_amo_req_i),
|
||||
.dcache_amo_resp_o(dcache_amo_resp_o),
|
||||
.dcache_cmo_req_i(dcache_cmo_req_i),
|
||||
.dcache_cmo_resp_o(dcache_cmo_resp_o),
|
||||
.dcache_req_ports_i(dcache_req_ports_i),
|
||||
.dcache_req_ports_o(dcache_req_ports_o),
|
||||
.wbuffer_empty_o(wbuffer_empty_o),
|
||||
.wbuffer_not_ni_o(wbuffer_not_ni_o),
|
||||
.hwpf_base_set_i(hwpf_base_set_i),
|
||||
.hwpf_base_i(hwpf_base_i),
|
||||
.hwpf_base_o(hwpf_base_o),
|
||||
.hwpf_param_set_i(hwpf_param_set_i),
|
||||
.hwpf_param_i(hwpf_param_i),
|
||||
.hwpf_param_o(hwpf_param_o),
|
||||
.hwpf_throttle_set_i(hwpf_throttle_set_i),
|
||||
.hwpf_throttle_i(hwpf_throttle_i),
|
||||
.hwpf_throttle_o(hwpf_throttle_o),
|
||||
.hwpf_status_o(hwpf_status_o),
|
||||
|
||||
.wbuf_flush_i(dcache_flush_i),
|
||||
.dcache_mem_req_read_ready_i(dcache_read_ready),
|
||||
.dcache_mem_req_read_valid_o(dcache_read_valid),
|
||||
.dcache_mem_req_read_o(dcache_read),
|
||||
|
||||
.core_req_valid_i(dcache_req_valid),
|
||||
.core_req_ready_o(dcache_req_ready),
|
||||
.core_req_i (dcache_req),
|
||||
.core_req_abort_i(dcache_req_abort),
|
||||
.core_req_tag_i (dcache_req_tag),
|
||||
.core_req_pma_i (dcache_req_pma),
|
||||
.dcache_mem_resp_read_ready_o(dcache_read_resp_ready),
|
||||
.dcache_mem_resp_read_valid_i(dcache_read_resp_valid),
|
||||
.dcache_mem_resp_read_i(dcache_read_resp),
|
||||
|
||||
.core_rsp_valid_o(dcache_rsp_valid),
|
||||
.core_rsp_o (dcache_rsp),
|
||||
.dcache_mem_req_write_ready_i(dcache_write_ready),
|
||||
.dcache_mem_req_write_valid_o(dcache_write_valid),
|
||||
.dcache_mem_req_write_o(dcache_write),
|
||||
|
||||
.mem_req_miss_read_ready_i(dcache_miss_ready),
|
||||
.mem_req_miss_read_valid_o(dcache_miss_valid),
|
||||
.mem_req_miss_read_o (dcache_miss),
|
||||
.dcache_mem_req_write_data_ready_i(dcache_write_data_ready),
|
||||
.dcache_mem_req_write_data_valid_o(dcache_write_data_valid),
|
||||
.dcache_mem_req_write_data_o(dcache_write_data),
|
||||
|
||||
.mem_resp_miss_read_ready_o(dcache_miss_resp_ready),
|
||||
.mem_resp_miss_read_valid_i(dcache_miss_resp_valid),
|
||||
.mem_resp_miss_read_i (dcache_miss_resp),
|
||||
|
||||
.mem_req_wbuf_write_ready_i(dcache_wbuf_ready),
|
||||
.mem_req_wbuf_write_valid_o(dcache_wbuf_valid),
|
||||
.mem_req_wbuf_write_o (dcache_wbuf),
|
||||
|
||||
.mem_req_wbuf_write_data_ready_i(dcache_wbuf_data_ready),
|
||||
.mem_req_wbuf_write_data_valid_o(dcache_wbuf_data_valid),
|
||||
.mem_req_wbuf_write_data_o (dcache_wbuf_data),
|
||||
|
||||
.mem_resp_wbuf_write_ready_o(dcache_wbuf_resp_ready),
|
||||
.mem_resp_wbuf_write_valid_i(dcache_wbuf_resp_valid),
|
||||
.mem_resp_wbuf_write_i (dcache_wbuf_resp),
|
||||
|
||||
.mem_req_uc_read_ready_i(dcache_uc_read_ready),
|
||||
.mem_req_uc_read_valid_o(dcache_uc_read_valid),
|
||||
.mem_req_uc_read_o (dcache_uc_read),
|
||||
|
||||
.mem_resp_uc_read_ready_o(dcache_uc_read_resp_ready),
|
||||
.mem_resp_uc_read_valid_i(dcache_uc_read_resp_valid),
|
||||
.mem_resp_uc_read_i (dcache_uc_read_resp),
|
||||
|
||||
.mem_req_uc_write_ready_i(dcache_uc_write_ready),
|
||||
.mem_req_uc_write_valid_o(dcache_uc_write_valid),
|
||||
.mem_req_uc_write_o (dcache_uc_write),
|
||||
|
||||
.mem_req_uc_write_data_ready_i(dcache_uc_write_data_ready),
|
||||
.mem_req_uc_write_data_valid_o(dcache_uc_write_data_valid),
|
||||
.mem_req_uc_write_data_o (dcache_uc_write_data),
|
||||
|
||||
.mem_resp_uc_write_ready_o(dcache_uc_write_resp_ready),
|
||||
.mem_resp_uc_write_valid_i(dcache_uc_write_resp_valid),
|
||||
.mem_resp_uc_write_i (dcache_uc_write_resp),
|
||||
|
||||
.evt_cache_write_miss_o(dcache_write_miss),
|
||||
.evt_cache_read_miss_o (dcache_read_miss),
|
||||
.evt_uncached_req_o ( /* unused */),
|
||||
.evt_cmo_req_o ( /* unused */),
|
||||
.evt_write_req_o ( /* unused */),
|
||||
.evt_read_req_o ( /* unused */),
|
||||
.evt_prefetch_req_o ( /* unused */),
|
||||
.evt_req_on_hold_o ( /* unused */),
|
||||
.evt_rtab_rollback_o ( /* unused */),
|
||||
.evt_stall_refill_o ( /* unused */),
|
||||
.evt_stall_o ( /* unused */),
|
||||
|
||||
.wbuf_empty_o(wbuffer_empty_o),
|
||||
|
||||
.cfg_enable_i (dcache_enable_i),
|
||||
.cfg_wbuf_threshold_i (3'd2),
|
||||
.cfg_wbuf_reset_timecnt_on_write_i (1'b1),
|
||||
.cfg_wbuf_sequential_waw_i (1'b0),
|
||||
.cfg_wbuf_inhibit_write_coalescing_i(1'b0),
|
||||
.cfg_prefetch_updt_plru_i (1'b1),
|
||||
.cfg_error_on_cacheable_amo_i (1'b0),
|
||||
.cfg_rtab_single_entry_i (1'b0)
|
||||
.dcache_mem_resp_write_ready_o(dcache_write_resp_ready),
|
||||
.dcache_mem_resp_write_valid_i(dcache_write_resp_valid),
|
||||
.dcache_mem_resp_write_i(dcache_write_resp)
|
||||
);
|
||||
|
||||
assign dcache_miss_o = dcache_read_miss, wbuffer_not_ni_o = wbuffer_empty_o;
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin : dcache_flush_ff
|
||||
if (!rst_ni) dcache_flush_ack_o <= 1'b0;
|
||||
else dcache_flush_ack_o <= ~dcache_flush_ack_o & dcache_flush_i;
|
||||
end
|
||||
|
||||
// }}}
|
||||
|
||||
// AXI arbiter instantiation
|
||||
// {{{
|
||||
cva6_hpdcache_subsystem_axi_arbiter #(
|
||||
|
@ -644,47 +387,25 @@ module cva6_hpdcache_subsystem
|
|||
.icache_miss_resp_valid_o(icache_miss_resp_valid),
|
||||
.icache_miss_resp_o (icache_miss_resp),
|
||||
|
||||
.dcache_miss_ready_o(dcache_miss_ready),
|
||||
.dcache_miss_valid_i(dcache_miss_valid),
|
||||
.dcache_miss_i (dcache_miss),
|
||||
.dcache_read_ready_o(dcache_read_ready),
|
||||
.dcache_read_valid_i(dcache_read_valid),
|
||||
.dcache_read_i (dcache_read),
|
||||
|
||||
.dcache_miss_resp_ready_i(dcache_miss_resp_ready),
|
||||
.dcache_miss_resp_valid_o(dcache_miss_resp_valid),
|
||||
.dcache_miss_resp_o (dcache_miss_resp),
|
||||
.dcache_read_resp_ready_i(dcache_read_resp_ready),
|
||||
.dcache_read_resp_valid_o(dcache_read_resp_valid),
|
||||
.dcache_read_resp_o (dcache_read_resp),
|
||||
|
||||
.dcache_wbuf_ready_o(dcache_wbuf_ready),
|
||||
.dcache_wbuf_valid_i(dcache_wbuf_valid),
|
||||
.dcache_wbuf_i (dcache_wbuf),
|
||||
.dcache_write_ready_o(dcache_write_ready),
|
||||
.dcache_write_valid_i(dcache_write_valid),
|
||||
.dcache_write_i (dcache_write),
|
||||
|
||||
.dcache_wbuf_data_ready_o(dcache_wbuf_data_ready),
|
||||
.dcache_wbuf_data_valid_i(dcache_wbuf_data_valid),
|
||||
.dcache_wbuf_data_i (dcache_wbuf_data),
|
||||
.dcache_write_data_ready_o(dcache_write_data_ready),
|
||||
.dcache_write_data_valid_i(dcache_write_data_valid),
|
||||
.dcache_write_data_i (dcache_write_data),
|
||||
|
||||
.dcache_wbuf_resp_ready_i(dcache_wbuf_resp_ready),
|
||||
.dcache_wbuf_resp_valid_o(dcache_wbuf_resp_valid),
|
||||
.dcache_wbuf_resp_o (dcache_wbuf_resp),
|
||||
|
||||
.dcache_uc_read_ready_o(dcache_uc_read_ready),
|
||||
.dcache_uc_read_valid_i(dcache_uc_read_valid),
|
||||
.dcache_uc_read_i (dcache_uc_read),
|
||||
.dcache_uc_read_id_i ('1),
|
||||
|
||||
.dcache_uc_read_resp_ready_i(dcache_uc_read_resp_ready),
|
||||
.dcache_uc_read_resp_valid_o(dcache_uc_read_resp_valid),
|
||||
.dcache_uc_read_resp_o (dcache_uc_read_resp),
|
||||
|
||||
.dcache_uc_write_ready_o(dcache_uc_write_ready),
|
||||
.dcache_uc_write_valid_i(dcache_uc_write_valid),
|
||||
.dcache_uc_write_i (dcache_uc_write),
|
||||
.dcache_uc_write_id_i ('1),
|
||||
|
||||
.dcache_uc_write_data_ready_o(dcache_uc_write_data_ready),
|
||||
.dcache_uc_write_data_valid_i(dcache_uc_write_data_valid),
|
||||
.dcache_uc_write_data_i (dcache_uc_write_data),
|
||||
|
||||
.dcache_uc_write_resp_ready_i(dcache_uc_write_resp_ready),
|
||||
.dcache_uc_write_resp_valid_o(dcache_uc_write_resp_valid),
|
||||
.dcache_uc_write_resp_o (dcache_uc_write_resp),
|
||||
.dcache_write_resp_ready_i(dcache_write_resp_ready),
|
||||
.dcache_write_resp_valid_o(dcache_write_resp_valid),
|
||||
.dcache_write_resp_o (dcache_write_resp),
|
||||
|
||||
.axi_req_o (noc_req_o),
|
||||
.axi_resp_i(noc_resp_i)
|
||||
|
@ -695,13 +416,13 @@ module cva6_hpdcache_subsystem
|
|||
// {{{
|
||||
// pragma translate_off
|
||||
initial begin : initial_assertions
|
||||
assert (hpdcacheCfg.u.reqSrcIdWidth >= $clog2(HPDCACHE_NREQUESTERS))
|
||||
assert (HPDcacheCfg.u.reqSrcIdWidth >= $clog2(HPDcacheCfg.u.nRequesters))
|
||||
else $fatal(1, "HPDCACHE_REQ_SRC_ID_WIDTH is not wide enough");
|
||||
assert (CVA6Cfg.MEM_TID_WIDTH <= CVA6Cfg.AxiIdWidth)
|
||||
else $fatal(1, "MEM_TID_WIDTH shall be less or equal to the AxiIdWidth");
|
||||
assert (CVA6Cfg.MEM_TID_WIDTH >= ($clog2(hpdcacheCfg.u.mshrSets * hpdcacheCfg.u.mshrWays) + 1))
|
||||
assert (CVA6Cfg.MEM_TID_WIDTH >= ($clog2(HPDcacheCfg.u.mshrSets * HPDcacheCfg.u.mshrWays) + 1))
|
||||
else $fatal(1, "MEM_TID_WIDTH shall allow to uniquely identify all D$ and I$ miss requests ");
|
||||
assert (CVA6Cfg.MEM_TID_WIDTH >= ($clog2(hpdcacheCfg.u.wbufDirEntries) + 1))
|
||||
assert (CVA6Cfg.MEM_TID_WIDTH >= ($clog2(HPDcacheCfg.u.wbufDirEntries) + 1))
|
||||
else $fatal(1, "MEM_TID_WIDTH shall allow to uniquely identify all D$ write requests ");
|
||||
end
|
||||
|
||||
|
|
|
@ -58,50 +58,27 @@ module cva6_hpdcache_subsystem_axi_arbiter
|
|||
|
||||
// Interfaces from/to D$
|
||||
// {{{
|
||||
output logic dcache_miss_ready_o,
|
||||
input logic dcache_miss_valid_i,
|
||||
input hpdcache_mem_req_t dcache_miss_i,
|
||||
// Read interface
|
||||
output logic dcache_read_ready_o,
|
||||
input logic dcache_read_valid_i,
|
||||
input hpdcache_mem_req_t dcache_read_i,
|
||||
|
||||
input logic dcache_miss_resp_ready_i,
|
||||
output logic dcache_miss_resp_valid_o,
|
||||
output hpdcache_mem_resp_r_t dcache_miss_resp_o,
|
||||
input logic dcache_read_resp_ready_i,
|
||||
output logic dcache_read_resp_valid_o,
|
||||
output hpdcache_mem_resp_r_t dcache_read_resp_o,
|
||||
|
||||
// Write-buffer write interface
|
||||
output logic dcache_wbuf_ready_o,
|
||||
input logic dcache_wbuf_valid_i,
|
||||
input hpdcache_mem_req_t dcache_wbuf_i,
|
||||
// Write interface
|
||||
output logic dcache_write_ready_o,
|
||||
input logic dcache_write_valid_i,
|
||||
input hpdcache_mem_req_t dcache_write_i,
|
||||
|
||||
output logic dcache_wbuf_data_ready_o,
|
||||
input logic dcache_wbuf_data_valid_i,
|
||||
input hpdcache_mem_req_w_t dcache_wbuf_data_i,
|
||||
output logic dcache_write_data_ready_o,
|
||||
input logic dcache_write_data_valid_i,
|
||||
input hpdcache_mem_req_w_t dcache_write_data_i,
|
||||
|
||||
input logic dcache_wbuf_resp_ready_i,
|
||||
output logic dcache_wbuf_resp_valid_o,
|
||||
output hpdcache_mem_resp_w_t dcache_wbuf_resp_o,
|
||||
|
||||
// Uncached read interface
|
||||
output logic dcache_uc_read_ready_o,
|
||||
input logic dcache_uc_read_valid_i,
|
||||
input hpdcache_mem_req_t dcache_uc_read_i,
|
||||
input hpdcache_mem_id_t dcache_uc_read_id_i,
|
||||
|
||||
input logic dcache_uc_read_resp_ready_i,
|
||||
output logic dcache_uc_read_resp_valid_o,
|
||||
output hpdcache_mem_resp_r_t dcache_uc_read_resp_o,
|
||||
|
||||
// Uncached write interface
|
||||
output logic dcache_uc_write_ready_o,
|
||||
input logic dcache_uc_write_valid_i,
|
||||
input hpdcache_mem_req_t dcache_uc_write_i,
|
||||
input hpdcache_mem_id_t dcache_uc_write_id_i,
|
||||
|
||||
output logic dcache_uc_write_data_ready_o,
|
||||
input logic dcache_uc_write_data_valid_i,
|
||||
input hpdcache_mem_req_w_t dcache_uc_write_data_i,
|
||||
|
||||
input logic dcache_uc_write_resp_ready_i,
|
||||
output logic dcache_uc_write_resp_valid_o,
|
||||
output hpdcache_mem_resp_w_t dcache_uc_write_resp_o,
|
||||
input logic dcache_write_resp_ready_i,
|
||||
output logic dcache_write_resp_valid_o,
|
||||
output hpdcache_mem_resp_w_t dcache_write_resp_o,
|
||||
// }}}
|
||||
|
||||
// AXI port to upstream memory/peripherals
|
||||
|
@ -166,13 +143,13 @@ module cva6_hpdcache_subsystem_axi_arbiter
|
|||
|
||||
assign icache_miss_req_w = icache_miss_valid_i, icache_miss_ready_o = icache_miss_req_wok;
|
||||
|
||||
assign icache_miss_req_wdata.mem_req_addr = icache_miss_i.paddr,
|
||||
icache_miss_req_wdata.mem_req_len = icache_miss_i.nc ? 0 : ICACHE_MEM_REQ_CL_LEN - 1,
|
||||
icache_miss_req_wdata.mem_req_size = icache_miss_i.nc ? ICACHE_WORD_SIZE : ICACHE_MEM_REQ_CL_SIZE,
|
||||
icache_miss_req_wdata.mem_req_id = icache_miss_i.tid,
|
||||
icache_miss_req_wdata.mem_req_command = hpdcache_pkg::HPDCACHE_MEM_READ,
|
||||
icache_miss_req_wdata.mem_req_atomic = hpdcache_pkg::hpdcache_mem_atomic_e'(0),
|
||||
icache_miss_req_wdata.mem_req_cacheable = ~icache_miss_i.nc;
|
||||
assign icache_miss_req_wdata.mem_req_addr = icache_miss_i.paddr;
|
||||
assign icache_miss_req_wdata.mem_req_len = icache_miss_i.nc ? 0 : ICACHE_MEM_REQ_CL_LEN - 1;
|
||||
assign icache_miss_req_wdata.mem_req_size = icache_miss_i.nc ? ICACHE_WORD_SIZE : ICACHE_MEM_REQ_CL_SIZE;
|
||||
assign icache_miss_req_wdata.mem_req_id = icache_miss_i.tid;
|
||||
assign icache_miss_req_wdata.mem_req_command = hpdcache_pkg::HPDCACHE_MEM_READ;
|
||||
assign icache_miss_req_wdata.mem_req_atomic = hpdcache_pkg::hpdcache_mem_atomic_e'(0);
|
||||
assign icache_miss_req_wdata.mem_req_cacheable = ~icache_miss_i.nc;
|
||||
|
||||
|
||||
// I$ response
|
||||
|
@ -258,12 +235,12 @@ module cva6_hpdcache_subsystem_axi_arbiter
|
|||
end
|
||||
endgenerate
|
||||
|
||||
assign icache_miss_resp_valid_o = icache_miss_resp_meta_rok,
|
||||
icache_miss_resp_o.rtype = wt_cache_pkg::ICACHE_IFILL_ACK,
|
||||
icache_miss_resp_o.user = '0,
|
||||
icache_miss_resp_o.inv = '0,
|
||||
icache_miss_resp_o.tid = icache_miss_resp_meta_id,
|
||||
icache_miss_resp_o.data = icache_miss_rdata;
|
||||
assign icache_miss_resp_valid_o = icache_miss_resp_meta_rok;
|
||||
assign icache_miss_resp_o.rtype = wt_cache_pkg::ICACHE_IFILL_ACK;
|
||||
assign icache_miss_resp_o.user = '0;
|
||||
assign icache_miss_resp_o.inv = '0;
|
||||
assign icache_miss_resp_o.tid = icache_miss_resp_meta_id;
|
||||
assign icache_miss_resp_o.data = icache_miss_rdata;
|
||||
|
||||
// consume the Icache miss on the arrival of the response. The request
|
||||
// metadata is decoded to forward the correct word in case of uncacheable
|
||||
|
@ -273,27 +250,23 @@ module cva6_hpdcache_subsystem_axi_arbiter
|
|||
|
||||
// Read request arbiter
|
||||
// {{{
|
||||
logic mem_req_read_ready [2:0];
|
||||
logic mem_req_read_valid [2:0];
|
||||
hpdcache_mem_req_t mem_req_read [2:0];
|
||||
logic [1:0] mem_req_read_ready;
|
||||
logic [1:0] mem_req_read_valid;
|
||||
hpdcache_mem_req_t [1:0] mem_req_read;
|
||||
|
||||
logic mem_req_read_ready_arb;
|
||||
logic mem_req_read_valid_arb;
|
||||
hpdcache_mem_req_t mem_req_read_arb;
|
||||
logic mem_req_read_ready_arb;
|
||||
logic mem_req_read_valid_arb;
|
||||
hpdcache_mem_req_t mem_req_read_arb;
|
||||
|
||||
assign mem_req_read_valid[0] = icache_miss_req_rok & ~icache_miss_pending_q,
|
||||
mem_req_read[0] = icache_miss_req_rdata;
|
||||
assign mem_req_read_valid[0] = icache_miss_req_rok & ~icache_miss_pending_q;
|
||||
assign mem_req_read[0] = icache_miss_req_rdata;
|
||||
|
||||
assign dcache_miss_ready_o = mem_req_read_ready[1],
|
||||
mem_req_read_valid[1] = dcache_miss_valid_i,
|
||||
mem_req_read[1] = dcache_miss_i;
|
||||
|
||||
assign dcache_uc_read_ready_o = mem_req_read_ready[2],
|
||||
mem_req_read_valid[2] = dcache_uc_read_valid_i,
|
||||
mem_req_read[2] = dcache_uc_read_i;
|
||||
assign dcache_read_ready_o = mem_req_read_ready[1];
|
||||
assign mem_req_read_valid[1] = dcache_read_valid_i;
|
||||
assign mem_req_read[1] = dcache_read_i;
|
||||
|
||||
hpdcache_mem_req_read_arbiter #(
|
||||
.N (3),
|
||||
.N (2),
|
||||
.hpdcache_mem_req_t(hpdcache_mem_req_t)
|
||||
) i_mem_req_read_arbiter (
|
||||
.clk_i,
|
||||
|
@ -315,21 +288,20 @@ module cva6_hpdcache_subsystem_axi_arbiter
|
|||
logic mem_resp_read_valid;
|
||||
hpdcache_mem_resp_r_t mem_resp_read;
|
||||
|
||||
logic mem_resp_read_ready_arb[2:0];
|
||||
logic mem_resp_read_valid_arb[2:0];
|
||||
hpdcache_mem_resp_r_t mem_resp_read_arb [2:0];
|
||||
logic mem_resp_read_ready_arb[1:0];
|
||||
logic mem_resp_read_valid_arb[1:0];
|
||||
hpdcache_mem_resp_r_t mem_resp_read_arb [1:0];
|
||||
|
||||
mem_resp_rt_t mem_resp_read_rt;
|
||||
|
||||
always_comb begin
|
||||
for (int i = 0; i < MEM_RESP_RT_DEPTH; i++) begin
|
||||
mem_resp_read_rt[i] = (i == int'( icache_miss_id_i)) ? 0 :
|
||||
(i == int'(dcache_uc_read_id_i)) ? 2 : 1;
|
||||
mem_resp_read_rt[i] = (i == int'(icache_miss_id_i)) ? 0 : 1;
|
||||
end
|
||||
end
|
||||
|
||||
hpdcache_mem_resp_demux #(
|
||||
.N (3),
|
||||
.N (2),
|
||||
.resp_t (hpdcache_mem_resp_r_t),
|
||||
.resp_id_t(hpdcache_mem_id_t)
|
||||
) i_mem_resp_read_demux (
|
||||
|
@ -348,124 +320,13 @@ module cva6_hpdcache_subsystem_axi_arbiter
|
|||
.mem_resp_rt_i(mem_resp_read_rt)
|
||||
);
|
||||
|
||||
assign icache_miss_resp_w = mem_resp_read_valid_arb[0],
|
||||
icache_miss_resp_wdata = mem_resp_read_arb[0],
|
||||
mem_resp_read_ready_arb[0] = icache_miss_resp_wok;
|
||||
assign icache_miss_resp_w = mem_resp_read_valid_arb[0];
|
||||
assign icache_miss_resp_wdata = mem_resp_read_arb[0];
|
||||
assign mem_resp_read_ready_arb[0] = icache_miss_resp_wok;
|
||||
|
||||
assign dcache_miss_resp_valid_o = mem_resp_read_valid_arb[1],
|
||||
dcache_miss_resp_o = mem_resp_read_arb[1],
|
||||
mem_resp_read_ready_arb[1] = dcache_miss_resp_ready_i;
|
||||
|
||||
assign dcache_uc_read_resp_valid_o = mem_resp_read_valid_arb[2],
|
||||
dcache_uc_read_resp_o = mem_resp_read_arb[2],
|
||||
mem_resp_read_ready_arb[2] = dcache_uc_read_resp_ready_i;
|
||||
// }}}
|
||||
|
||||
// Write request arbiter
|
||||
// {{{
|
||||
logic mem_req_write_ready [1:0];
|
||||
logic mem_req_write_valid [1:0];
|
||||
hpdcache_mem_req_t mem_req_write [1:0];
|
||||
|
||||
logic mem_req_write_data_ready [1:0];
|
||||
logic mem_req_write_data_valid [1:0];
|
||||
hpdcache_mem_req_w_t mem_req_write_data [1:0];
|
||||
|
||||
logic mem_req_write_ready_arb;
|
||||
logic mem_req_write_valid_arb;
|
||||
hpdcache_mem_req_t mem_req_write_arb;
|
||||
|
||||
logic mem_req_write_data_ready_arb;
|
||||
logic mem_req_write_data_valid_arb;
|
||||
hpdcache_mem_req_w_t mem_req_write_data_arb;
|
||||
|
||||
assign dcache_wbuf_ready_o = mem_req_write_ready[0],
|
||||
mem_req_write_valid[0] = dcache_wbuf_valid_i,
|
||||
mem_req_write[0] = dcache_wbuf_i;
|
||||
|
||||
assign dcache_wbuf_data_ready_o = mem_req_write_data_ready[0],
|
||||
mem_req_write_data_valid[0] = dcache_wbuf_data_valid_i,
|
||||
mem_req_write_data[0] = dcache_wbuf_data_i;
|
||||
|
||||
assign dcache_uc_write_ready_o = mem_req_write_ready[1],
|
||||
mem_req_write_valid[1] = dcache_uc_write_valid_i,
|
||||
mem_req_write[1] = dcache_uc_write_i;
|
||||
|
||||
assign dcache_uc_write_data_ready_o = mem_req_write_data_ready[1],
|
||||
mem_req_write_data_valid[1] = dcache_uc_write_data_valid_i,
|
||||
mem_req_write_data[1] = dcache_uc_write_data_i;
|
||||
|
||||
hpdcache_mem_req_write_arbiter #(
|
||||
.N (2),
|
||||
.hpdcache_mem_req_t (hpdcache_mem_req_t),
|
||||
.hpdcache_mem_req_w_t(hpdcache_mem_req_w_t)
|
||||
) i_mem_req_write_arbiter (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
|
||||
.mem_req_write_ready_o(mem_req_write_ready),
|
||||
.mem_req_write_valid_i(mem_req_write_valid),
|
||||
.mem_req_write_i (mem_req_write),
|
||||
|
||||
.mem_req_write_data_ready_o(mem_req_write_data_ready),
|
||||
.mem_req_write_data_valid_i(mem_req_write_data_valid),
|
||||
.mem_req_write_data_i (mem_req_write_data),
|
||||
|
||||
.mem_req_write_ready_i(mem_req_write_ready_arb),
|
||||
.mem_req_write_valid_o(mem_req_write_valid_arb),
|
||||
.mem_req_write_o (mem_req_write_arb),
|
||||
|
||||
.mem_req_write_data_ready_i(mem_req_write_data_ready_arb),
|
||||
.mem_req_write_data_valid_o(mem_req_write_data_valid_arb),
|
||||
.mem_req_write_data_o (mem_req_write_data_arb)
|
||||
);
|
||||
// }}}
|
||||
|
||||
// Write response demultiplexor
|
||||
// {{{
|
||||
logic mem_resp_write_ready;
|
||||
logic mem_resp_write_valid;
|
||||
hpdcache_mem_resp_w_t mem_resp_write;
|
||||
|
||||
logic mem_resp_write_ready_arb[1:0];
|
||||
logic mem_resp_write_valid_arb[1:0];
|
||||
hpdcache_mem_resp_w_t mem_resp_write_arb [1:0];
|
||||
|
||||
mem_resp_rt_t mem_resp_write_rt;
|
||||
|
||||
always_comb begin
|
||||
for (int i = 0; i < MEM_RESP_RT_DEPTH; i++) begin
|
||||
mem_resp_write_rt[i] = (i == int'(dcache_uc_write_id_i)) ? 1 : 0;
|
||||
end
|
||||
end
|
||||
|
||||
hpdcache_mem_resp_demux #(
|
||||
.N (2),
|
||||
.resp_t (hpdcache_mem_resp_w_t),
|
||||
.resp_id_t(hpdcache_mem_id_t)
|
||||
) i_hpdcache_mem_resp_write_demux (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
|
||||
.mem_resp_ready_o(mem_resp_write_ready),
|
||||
.mem_resp_valid_i(mem_resp_write_valid),
|
||||
.mem_resp_id_i (mem_resp_write.mem_resp_w_id),
|
||||
.mem_resp_i (mem_resp_write),
|
||||
|
||||
.mem_resp_ready_i(mem_resp_write_ready_arb),
|
||||
.mem_resp_valid_o(mem_resp_write_valid_arb),
|
||||
.mem_resp_o (mem_resp_write_arb),
|
||||
|
||||
.mem_resp_rt_i(mem_resp_write_rt)
|
||||
);
|
||||
|
||||
assign dcache_wbuf_resp_valid_o = mem_resp_write_valid_arb[0],
|
||||
dcache_wbuf_resp_o = mem_resp_write_arb[0],
|
||||
mem_resp_write_ready_arb[0] = dcache_wbuf_resp_ready_i;
|
||||
|
||||
assign dcache_uc_write_resp_valid_o = mem_resp_write_valid_arb[1],
|
||||
dcache_uc_write_resp_o = mem_resp_write_arb[1],
|
||||
mem_resp_write_ready_arb[1] = dcache_uc_write_resp_ready_i;
|
||||
assign dcache_read_resp_valid_o = mem_resp_read_valid_arb[1];
|
||||
assign dcache_read_resp_o = mem_resp_read_arb[1];
|
||||
assign mem_resp_read_ready_arb[1] = dcache_read_resp_ready_i;
|
||||
// }}}
|
||||
|
||||
// I$ miss pending
|
||||
|
@ -491,17 +352,17 @@ module cva6_hpdcache_subsystem_axi_arbiter
|
|||
.w_chan_t (axi_w_chan_t),
|
||||
.b_chan_t (axi_b_chan_t)
|
||||
) i_hpdcache_mem_to_axi_write (
|
||||
.req_ready_o(mem_req_write_ready_arb),
|
||||
.req_valid_i(mem_req_write_valid_arb),
|
||||
.req_i (mem_req_write_arb),
|
||||
.req_ready_o(dcache_write_ready_o),
|
||||
.req_valid_i(dcache_write_valid_i),
|
||||
.req_i (dcache_write_i),
|
||||
|
||||
.req_data_ready_o(mem_req_write_data_ready_arb),
|
||||
.req_data_valid_i(mem_req_write_data_valid_arb),
|
||||
.req_data_i (mem_req_write_data_arb),
|
||||
.req_data_ready_o(dcache_write_data_ready_o),
|
||||
.req_data_valid_i(dcache_write_data_valid_i),
|
||||
.req_data_i (dcache_write_data_i),
|
||||
|
||||
.resp_ready_i(mem_resp_write_ready),
|
||||
.resp_valid_o(mem_resp_write_valid),
|
||||
.resp_o (mem_resp_write),
|
||||
.resp_ready_i(dcache_write_resp_ready_i),
|
||||
.resp_valid_o(dcache_write_resp_valid_o),
|
||||
.resp_o (dcache_write_resp_o),
|
||||
|
||||
.axi_aw_valid_o(axi_req_o.aw_valid),
|
||||
.axi_aw_o (axi_req_o.aw),
|
||||
|
@ -546,13 +407,13 @@ module cva6_hpdcache_subsystem_axi_arbiter
|
|||
// pragma translate_off
|
||||
initial
|
||||
assert (CVA6Cfg.MEM_TID_WIDTH <= AxiIdWidth)
|
||||
else $fatal("MEM_TID_WIDTH shall be less or equal to AxiIdWidth");
|
||||
else $fatal(1, "MEM_TID_WIDTH shall be less or equal to AxiIdWidth");
|
||||
initial
|
||||
assert (CVA6Cfg.AxiDataWidth <= CVA6Cfg.ICACHE_LINE_WIDTH)
|
||||
else $fatal("AxiDataWidth shall be less or equal to the width of a Icache line");
|
||||
else $fatal(1, "AxiDataWidth shall be less or equal to the width of a Icache line");
|
||||
initial
|
||||
assert (CVA6Cfg.AxiDataWidth <= CVA6Cfg.DCACHE_LINE_WIDTH)
|
||||
else $fatal("AxiDataWidth shall be less or equal to the width of a Dcache line");
|
||||
else $fatal(1, "AxiDataWidth shall be less or equal to the width of a Dcache line");
|
||||
// pragma translate_on
|
||||
// }}}
|
||||
|
||||
|
|
426
core/cache_subsystem/cva6_hpdcache_wrapper.sv
Normal file
426
core/cache_subsystem/cva6_hpdcache_wrapper.sv
Normal file
|
@ -0,0 +1,426 @@
|
|||
// Copyright 2023 Commissariat a l'Energie Atomique et aux Energies
|
||||
// Alternatives (CEA)
|
||||
//
|
||||
// Licensed under the Solderpad Hardware License, Version 2.1 (the “License”);
|
||||
// you may not use this file except in compliance with the License.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
||||
// You may obtain a copy of the License at https://solderpad.org/licenses/
|
||||
//
|
||||
// Authors: Cesar Fuguet
|
||||
// Date: February, 2023
|
||||
// Description: Wrapper for the Core-V High-Performance L1 data cache (CV-HPDcache)
|
||||
|
||||
`include "hpdcache_typedef.svh"
|
||||
|
||||
module cva6_hpdcache_wrapper
|
||||
// Parameters
|
||||
// {{{
|
||||
#(
|
||||
parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty,
|
||||
parameter hpdcache_pkg::hpdcache_cfg_t HPDcacheCfg = '0,
|
||||
parameter type dcache_req_i_t = logic,
|
||||
parameter type dcache_req_o_t = logic,
|
||||
parameter int NumPorts = 4,
|
||||
parameter int NrHwPrefetchers = 4,
|
||||
|
||||
parameter type cmo_req_t = logic,
|
||||
parameter type cmo_rsp_t = logic,
|
||||
parameter type hpdcache_mem_addr_t = logic,
|
||||
parameter type hpdcache_mem_id_t = logic,
|
||||
parameter type hpdcache_mem_data_t = logic,
|
||||
parameter type hpdcache_mem_be_t = logic,
|
||||
parameter type hpdcache_mem_req_t = logic,
|
||||
parameter type hpdcache_mem_req_w_t = logic,
|
||||
parameter type hpdcache_mem_resp_r_t = logic,
|
||||
parameter type hpdcache_mem_resp_w_t = logic,
|
||||
parameter type hpdcache_req_offset_t = logic,
|
||||
parameter type hpdcache_data_word_t = logic,
|
||||
parameter type hpdcache_req_data_t = logic,
|
||||
parameter type hpdcache_req_be_t = logic,
|
||||
parameter type hpdcache_req_sid_t = logic,
|
||||
parameter type hpdcache_req_tid_t = logic,
|
||||
parameter type hpdcache_tag_t = logic,
|
||||
parameter type hpdcache_req_t = logic,
|
||||
parameter type hpdcache_rsp_t = logic,
|
||||
parameter type hpdcache_wbuf_timecnt_t = logic,
|
||||
parameter type hpdcache_data_be_t = logic
|
||||
)
|
||||
// }}}
|
||||
|
||||
// Ports
|
||||
// {{{
|
||||
(
|
||||
|
||||
// Subsystem Clock - SUBSYSTEM
|
||||
input logic clk_i,
|
||||
// Asynchronous reset active low - SUBSYSTEM
|
||||
input logic rst_ni,
|
||||
|
||||
// D$
|
||||
// {{{
|
||||
// Cache management
|
||||
// Data cache enable - CSR_REGFILE
|
||||
input logic dcache_enable_i,
|
||||
// Data cache flush - CONTROLLER
|
||||
input logic dcache_flush_i,
|
||||
// Flush acknowledge - CONTROLLER
|
||||
output logic dcache_flush_ack_o,
|
||||
// Load or store miss - PERF_COUNTERS
|
||||
output logic dcache_miss_o,
|
||||
|
||||
// AMO request/response - EX_STAGE
|
||||
input ariane_pkg::amo_req_t dcache_amo_req_i,
|
||||
output ariane_pkg::amo_resp_t dcache_amo_resp_o,
|
||||
// CMO interface request/response
|
||||
input cmo_req_t dcache_cmo_req_i,
|
||||
output cmo_rsp_t dcache_cmo_resp_o,
|
||||
// Data cache input request/response ports - EX_STAGE
|
||||
input dcache_req_i_t [NumPorts-1:0] dcache_req_ports_i,
|
||||
output dcache_req_o_t [NumPorts-1:0] dcache_req_ports_o,
|
||||
// Write buffer status - EX_STAGE
|
||||
output logic wbuffer_empty_o,
|
||||
output logic wbuffer_not_ni_o,
|
||||
|
||||
// Hardware memory prefetcher configuration
|
||||
input logic [NrHwPrefetchers-1:0] hwpf_base_set_i,
|
||||
input logic [NrHwPrefetchers-1:0][63:0] hwpf_base_i,
|
||||
output logic [NrHwPrefetchers-1:0][63:0] hwpf_base_o,
|
||||
input logic [NrHwPrefetchers-1:0] hwpf_param_set_i,
|
||||
input logic [NrHwPrefetchers-1:0][63:0] hwpf_param_i,
|
||||
output logic [NrHwPrefetchers-1:0][63:0] hwpf_param_o,
|
||||
input logic [NrHwPrefetchers-1:0] hwpf_throttle_set_i,
|
||||
input logic [NrHwPrefetchers-1:0][63:0] hwpf_throttle_i,
|
||||
output logic [NrHwPrefetchers-1:0][63:0] hwpf_throttle_o,
|
||||
output logic [ 63:0] hwpf_status_o,
|
||||
|
||||
input logic dcache_mem_req_read_ready_i,
|
||||
output logic dcache_mem_req_read_valid_o,
|
||||
output hpdcache_mem_req_t dcache_mem_req_read_o,
|
||||
|
||||
output logic dcache_mem_resp_read_ready_o,
|
||||
input logic dcache_mem_resp_read_valid_i,
|
||||
input hpdcache_mem_resp_r_t dcache_mem_resp_read_i,
|
||||
|
||||
input logic dcache_mem_req_write_ready_i,
|
||||
output logic dcache_mem_req_write_valid_o,
|
||||
output hpdcache_mem_req_t dcache_mem_req_write_o,
|
||||
|
||||
input logic dcache_mem_req_write_data_ready_i,
|
||||
output logic dcache_mem_req_write_data_valid_o,
|
||||
output hpdcache_mem_req_w_t dcache_mem_req_write_data_o,
|
||||
|
||||
output logic dcache_mem_resp_write_ready_o,
|
||||
input logic dcache_mem_resp_write_valid_i,
|
||||
input hpdcache_mem_resp_w_t dcache_mem_resp_write_i
|
||||
);
|
||||
|
||||
localparam int HPDCACHE_NREQUESTERS = NumPorts + 2;
|
||||
|
||||
typedef logic [63:0] hwpf_stride_param_t;
|
||||
|
||||
logic dcache_req_valid[HPDCACHE_NREQUESTERS];
|
||||
logic dcache_req_ready[HPDCACHE_NREQUESTERS];
|
||||
hpdcache_req_t dcache_req [HPDCACHE_NREQUESTERS];
|
||||
logic dcache_req_abort[HPDCACHE_NREQUESTERS];
|
||||
hpdcache_tag_t dcache_req_tag [HPDCACHE_NREQUESTERS];
|
||||
hpdcache_pkg::hpdcache_pma_t dcache_req_pma [HPDCACHE_NREQUESTERS];
|
||||
logic dcache_rsp_valid[HPDCACHE_NREQUESTERS];
|
||||
hpdcache_rsp_t dcache_rsp [HPDCACHE_NREQUESTERS];
|
||||
logic dcache_read_miss, dcache_write_miss;
|
||||
|
||||
logic [ 2:0] snoop_valid;
|
||||
logic [ 2:0] snoop_abort;
|
||||
hpdcache_req_offset_t [ 2:0] snoop_addr_offset;
|
||||
hpdcache_tag_t [ 2:0] snoop_addr_tag;
|
||||
logic [ 2:0] snoop_phys_indexed;
|
||||
|
||||
logic dcache_cmo_req_is_prefetch;
|
||||
|
||||
hwpf_stride_pkg::hwpf_stride_throttle_t [NrHwPrefetchers-1:0] hwpf_throttle_in;
|
||||
hwpf_stride_pkg::hwpf_stride_throttle_t [NrHwPrefetchers-1:0] hwpf_throttle_out;
|
||||
|
||||
generate
|
||||
dcache_req_i_t dcache_req_ports[NumPorts - 1];
|
||||
|
||||
for (genvar r = 0; r < (NumPorts - 1); r++) begin : gen_cva6_hpdcache_load_if_adapter
|
||||
assign dcache_req_ports[r] = dcache_req_ports_i[r];
|
||||
|
||||
cva6_hpdcache_if_adapter #(
|
||||
.CVA6Cfg (CVA6Cfg),
|
||||
.HPDcacheCfg (HPDcacheCfg),
|
||||
.hpdcache_tag_t (hpdcache_tag_t),
|
||||
.hpdcache_req_offset_t(hpdcache_req_offset_t),
|
||||
.hpdcache_req_sid_t (hpdcache_req_sid_t),
|
||||
.hpdcache_req_t (hpdcache_req_t),
|
||||
.hpdcache_rsp_t (hpdcache_rsp_t),
|
||||
.dcache_req_i_t (dcache_req_i_t),
|
||||
.dcache_req_o_t (dcache_req_o_t),
|
||||
.InvalidateOnFlush (1'b0),
|
||||
.IsLoadPort (1'b1)
|
||||
) i_cva6_hpdcache_load_if_adapter (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
|
||||
.hpdcache_req_sid_i(hpdcache_req_sid_t'(r)),
|
||||
|
||||
.cva6_req_i (dcache_req_ports[r]),
|
||||
.cva6_req_o (dcache_req_ports_o[r]),
|
||||
.cva6_amo_req_i ('0),
|
||||
.cva6_amo_resp_o( /* unused */),
|
||||
|
||||
.cva6_dcache_flush_i (1'b0),
|
||||
.cva6_dcache_flush_ack_o( /* unused */),
|
||||
|
||||
.hpdcache_req_valid_o(dcache_req_valid[r]),
|
||||
.hpdcache_req_ready_i(dcache_req_ready[r]),
|
||||
.hpdcache_req_o (dcache_req[r]),
|
||||
.hpdcache_req_abort_o(dcache_req_abort[r]),
|
||||
.hpdcache_req_tag_o (dcache_req_tag[r]),
|
||||
.hpdcache_req_pma_o (dcache_req_pma[r]),
|
||||
|
||||
.hpdcache_rsp_valid_i(dcache_rsp_valid[r]),
|
||||
.hpdcache_rsp_i (dcache_rsp[r])
|
||||
);
|
||||
end
|
||||
|
||||
cva6_hpdcache_if_adapter #(
|
||||
.CVA6Cfg (CVA6Cfg),
|
||||
.HPDcacheCfg (HPDcacheCfg),
|
||||
.hpdcache_tag_t (hpdcache_tag_t),
|
||||
.hpdcache_req_offset_t(hpdcache_req_offset_t),
|
||||
.hpdcache_req_sid_t (hpdcache_req_sid_t),
|
||||
.hpdcache_req_t (hpdcache_req_t),
|
||||
.hpdcache_rsp_t (hpdcache_rsp_t),
|
||||
.dcache_req_i_t (dcache_req_i_t),
|
||||
.dcache_req_o_t (dcache_req_o_t),
|
||||
.InvalidateOnFlush (CVA6Cfg.DcacheInvalidateOnFlush),
|
||||
.IsLoadPort (1'b0)
|
||||
) i_cva6_hpdcache_store_if_adapter (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
|
||||
.hpdcache_req_sid_i(hpdcache_req_sid_t'(NumPorts - 1)),
|
||||
|
||||
.cva6_req_i (dcache_req_ports_i[NumPorts-1]),
|
||||
.cva6_req_o (dcache_req_ports_o[NumPorts-1]),
|
||||
.cva6_amo_req_i (dcache_amo_req_i),
|
||||
.cva6_amo_resp_o(dcache_amo_resp_o),
|
||||
|
||||
.cva6_dcache_flush_i (dcache_flush_i),
|
||||
.cva6_dcache_flush_ack_o(dcache_flush_ack_o),
|
||||
|
||||
.hpdcache_req_valid_o(dcache_req_valid[NumPorts-1]),
|
||||
.hpdcache_req_ready_i(dcache_req_ready[NumPorts-1]),
|
||||
.hpdcache_req_o (dcache_req[NumPorts-1]),
|
||||
.hpdcache_req_abort_o(dcache_req_abort[NumPorts-1]),
|
||||
.hpdcache_req_tag_o (dcache_req_tag[NumPorts-1]),
|
||||
.hpdcache_req_pma_o (dcache_req_pma[NumPorts-1]),
|
||||
|
||||
.hpdcache_rsp_valid_i(dcache_rsp_valid[NumPorts-1]),
|
||||
.hpdcache_rsp_i (dcache_rsp[NumPorts-1])
|
||||
);
|
||||
|
||||
`ifdef HPDCACHE_ENABLE_CMO
|
||||
cva6_hpdcache_cmo_if_adapter #(
|
||||
.cmo_req_t(cmo_req_t),
|
||||
.cmo_rsp_t(cmo_rsp_t)
|
||||
) i_cva6_hpdcache_cmo_if_adapter (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
|
||||
.dcache_req_sid_i(hpdcache_req_sid_t'(NumPorts)),
|
||||
|
||||
.cva6_cmo_req_i (dcache_cmo_req_i),
|
||||
.cva6_cmo_resp_o(dcache_cmo_resp_o),
|
||||
|
||||
.dcache_req_valid_o(dcache_req_valid[NumPorts]),
|
||||
.dcache_req_ready_i(dcache_req_ready[NumPorts]),
|
||||
.dcache_req_o (dcache_req[NumPorts]),
|
||||
.dcache_req_abort_o(dcache_req_abort[NumPorts]),
|
||||
.dcache_req_tag_o (dcache_req_tag[NumPorts]),
|
||||
.dcache_req_pma_o (dcache_req_pma[NumPorts]),
|
||||
|
||||
.dcache_rsp_valid_i(dcache_rsp_valid[NumPorts]),
|
||||
.dcache_rsp_i (dcache_rsp[NumPorts])
|
||||
);
|
||||
`else
|
||||
assign dcache_req_valid[NumPorts] = 1'b0,
|
||||
dcache_req[NumPorts] = '0,
|
||||
dcache_req_abort[NumPorts] = 1'b0,
|
||||
dcache_req_tag[NumPorts] = '0,
|
||||
dcache_req_pma[NumPorts] = '0;
|
||||
`endif
|
||||
endgenerate
|
||||
|
||||
// Snoop load port
|
||||
assign snoop_valid[0] = dcache_req_valid[1] & dcache_req_ready[1],
|
||||
snoop_abort[0] = dcache_req_abort[1],
|
||||
snoop_addr_offset[0] = dcache_req[1].addr_offset,
|
||||
snoop_addr_tag[0] = dcache_req_tag[1],
|
||||
snoop_phys_indexed[0] = dcache_req[1].phys_indexed;
|
||||
|
||||
// Snoop Store/AMO port
|
||||
assign snoop_valid[1] = dcache_req_valid[NumPorts-1] & dcache_req_ready[NumPorts-1],
|
||||
snoop_abort[1] = dcache_req_abort[NumPorts-1],
|
||||
snoop_addr_offset[1] = dcache_req[NumPorts-1].addr_offset,
|
||||
snoop_addr_tag[1] = dcache_req_tag[NumPorts-1],
|
||||
snoop_phys_indexed[1] = dcache_req[NumPorts-1].phys_indexed;
|
||||
|
||||
`ifdef HPDCACHE_ENABLE_CMO
|
||||
// Snoop CMO port (in case of read prefetch accesses)
|
||||
assign dcache_cmo_req_is_prefetch = hpdcache_pkg::is_cmo_prefetch(
|
||||
dcache_req[NumPorts].op, dcache_req[NumPorts].size
|
||||
);
|
||||
assign snoop_valid[2] = dcache_req_valid[NumPorts]
|
||||
& dcache_req_ready[NumPorts]
|
||||
& dcache_cmo_req_is_prefetch,
|
||||
snoop_abort[2] = dcache_req_abort[NumPorts],
|
||||
snoop_addr_offset[2] = dcache_req[NumPorts].addr_offset,
|
||||
snoop_addr_tag[2] = dcache_req_tag[NumPorts],
|
||||
snoop_phys_indexed[2] = dcache_req[NumPorts].phys_indexed;
|
||||
`else
|
||||
assign snoop_valid[2] = 1'b0,
|
||||
snoop_abort[2] = 1'b0,
|
||||
snoop_addr_offset[2] = '0,
|
||||
snoop_addr_tag[2] = '0,
|
||||
snoop_phys_indexed[2] = 1'b0;
|
||||
`endif
|
||||
|
||||
generate
|
||||
for (genvar h = 0; h < NrHwPrefetchers; h++) begin : gen_hwpf_throttle
|
||||
assign hwpf_throttle_in[h] = hwpf_stride_pkg::hwpf_stride_throttle_t'(hwpf_throttle_i[h]);
|
||||
assign hwpf_throttle_o[h] = hwpf_stride_pkg::hwpf_stride_param_t'(hwpf_throttle_out[h]);
|
||||
end
|
||||
endgenerate
|
||||
|
||||
hwpf_stride_wrapper #(
|
||||
.HPDcacheCfg (HPDcacheCfg),
|
||||
.NUM_HW_PREFETCH (NrHwPrefetchers),
|
||||
.NUM_SNOOP_PORTS (3),
|
||||
.hpdcache_tag_t (hpdcache_tag_t),
|
||||
.hpdcache_req_offset_t(hpdcache_req_offset_t),
|
||||
.hpdcache_req_data_t (hpdcache_req_data_t),
|
||||
.hpdcache_req_be_t (hpdcache_req_be_t),
|
||||
.hpdcache_req_sid_t (hpdcache_req_sid_t),
|
||||
.hpdcache_req_tid_t (hpdcache_req_tid_t),
|
||||
.hpdcache_req_t (hpdcache_req_t),
|
||||
.hpdcache_rsp_t (hpdcache_rsp_t)
|
||||
) i_hwpf_stride_wrapper (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
|
||||
.hwpf_stride_base_set_i (hwpf_base_set_i),
|
||||
.hwpf_stride_base_i (hwpf_base_i),
|
||||
.hwpf_stride_base_o (hwpf_base_o),
|
||||
.hwpf_stride_param_set_i (hwpf_param_set_i),
|
||||
.hwpf_stride_param_i (hwpf_param_i),
|
||||
.hwpf_stride_param_o (hwpf_param_o),
|
||||
.hwpf_stride_throttle_set_i(hwpf_throttle_set_i),
|
||||
.hwpf_stride_throttle_i (hwpf_throttle_in),
|
||||
.hwpf_stride_throttle_o (hwpf_throttle_out),
|
||||
.hwpf_stride_status_o (hwpf_status_o),
|
||||
|
||||
.snoop_valid_i (snoop_valid),
|
||||
.snoop_abort_i (snoop_abort),
|
||||
.snoop_addr_offset_i (snoop_addr_offset),
|
||||
.snoop_addr_tag_i (snoop_addr_tag),
|
||||
.snoop_phys_indexed_i(snoop_phys_indexed),
|
||||
|
||||
.hpdcache_req_sid_i(hpdcache_req_sid_t'(NumPorts + 1)),
|
||||
|
||||
.hpdcache_req_valid_o(dcache_req_valid[NumPorts+1]),
|
||||
.hpdcache_req_ready_i(dcache_req_ready[NumPorts+1]),
|
||||
.hpdcache_req_o (dcache_req[NumPorts+1]),
|
||||
.hpdcache_req_abort_o(dcache_req_abort[NumPorts+1]),
|
||||
.hpdcache_req_tag_o (dcache_req_tag[NumPorts+1]),
|
||||
.hpdcache_req_pma_o (dcache_req_pma[NumPorts+1]),
|
||||
.hpdcache_rsp_valid_i(dcache_rsp_valid[NumPorts+1]),
|
||||
.hpdcache_rsp_i (dcache_rsp[NumPorts+1])
|
||||
);
|
||||
|
||||
hpdcache #(
|
||||
.HPDcacheCfg (HPDcacheCfg),
|
||||
.wbuf_timecnt_t (hpdcache_wbuf_timecnt_t),
|
||||
.hpdcache_tag_t (hpdcache_tag_t),
|
||||
.hpdcache_data_word_t (hpdcache_data_word_t),
|
||||
.hpdcache_data_be_t (hpdcache_data_be_t),
|
||||
.hpdcache_req_offset_t(hpdcache_req_offset_t),
|
||||
.hpdcache_req_data_t (hpdcache_req_data_t),
|
||||
.hpdcache_req_be_t (hpdcache_req_be_t),
|
||||
.hpdcache_req_sid_t (hpdcache_req_sid_t),
|
||||
.hpdcache_req_tid_t (hpdcache_req_tid_t),
|
||||
.hpdcache_req_t (hpdcache_req_t),
|
||||
.hpdcache_rsp_t (hpdcache_rsp_t),
|
||||
.hpdcache_mem_addr_t (hpdcache_mem_addr_t),
|
||||
.hpdcache_mem_id_t (hpdcache_mem_id_t),
|
||||
.hpdcache_mem_data_t (hpdcache_mem_data_t),
|
||||
.hpdcache_mem_be_t (hpdcache_mem_be_t),
|
||||
.hpdcache_mem_req_t (hpdcache_mem_req_t),
|
||||
.hpdcache_mem_req_w_t (hpdcache_mem_req_w_t),
|
||||
.hpdcache_mem_resp_r_t(hpdcache_mem_resp_r_t),
|
||||
.hpdcache_mem_resp_w_t(hpdcache_mem_resp_w_t)
|
||||
) i_hpdcache (
|
||||
.clk_i,
|
||||
.rst_ni,
|
||||
|
||||
.wbuf_flush_i(dcache_flush_i),
|
||||
|
||||
.core_req_valid_i(dcache_req_valid),
|
||||
.core_req_ready_o(dcache_req_ready),
|
||||
.core_req_i (dcache_req),
|
||||
.core_req_abort_i(dcache_req_abort),
|
||||
.core_req_tag_i (dcache_req_tag),
|
||||
.core_req_pma_i (dcache_req_pma),
|
||||
|
||||
.core_rsp_valid_o(dcache_rsp_valid),
|
||||
.core_rsp_o (dcache_rsp),
|
||||
|
||||
.mem_req_read_ready_i(dcache_mem_req_read_ready_i),
|
||||
.mem_req_read_valid_o(dcache_mem_req_read_valid_o),
|
||||
.mem_req_read_o (dcache_mem_req_read_o),
|
||||
|
||||
.mem_resp_read_ready_o(dcache_mem_resp_read_ready_o),
|
||||
.mem_resp_read_valid_i(dcache_mem_resp_read_valid_i),
|
||||
.mem_resp_read_i (dcache_mem_resp_read_i),
|
||||
|
||||
.mem_req_write_ready_i(dcache_mem_req_write_ready_i),
|
||||
.mem_req_write_valid_o(dcache_mem_req_write_valid_o),
|
||||
.mem_req_write_o (dcache_mem_req_write_o),
|
||||
|
||||
.mem_req_write_data_ready_i(dcache_mem_req_write_data_ready_i),
|
||||
.mem_req_write_data_valid_o(dcache_mem_req_write_data_valid_o),
|
||||
.mem_req_write_data_o (dcache_mem_req_write_data_o),
|
||||
|
||||
.mem_resp_write_ready_o(dcache_mem_resp_write_ready_o),
|
||||
.mem_resp_write_valid_i(dcache_mem_resp_write_valid_i),
|
||||
.mem_resp_write_i (dcache_mem_resp_write_i),
|
||||
|
||||
.evt_cache_write_miss_o(dcache_write_miss),
|
||||
.evt_cache_read_miss_o (dcache_read_miss),
|
||||
.evt_uncached_req_o ( /* unused */),
|
||||
.evt_cmo_req_o ( /* unused */),
|
||||
.evt_write_req_o ( /* unused */),
|
||||
.evt_read_req_o ( /* unused */),
|
||||
.evt_prefetch_req_o ( /* unused */),
|
||||
.evt_req_on_hold_o ( /* unused */),
|
||||
.evt_rtab_rollback_o ( /* unused */),
|
||||
.evt_stall_refill_o ( /* unused */),
|
||||
.evt_stall_o ( /* unused */),
|
||||
|
||||
.wbuf_empty_o(wbuffer_empty_o),
|
||||
|
||||
.cfg_enable_i (dcache_enable_i),
|
||||
.cfg_wbuf_threshold_i (3'd2),
|
||||
.cfg_wbuf_reset_timecnt_on_write_i (1'b1),
|
||||
.cfg_wbuf_sequential_waw_i (1'b0),
|
||||
.cfg_wbuf_inhibit_write_coalescing_i(1'b0),
|
||||
.cfg_prefetch_updt_plru_i (1'b1),
|
||||
.cfg_error_on_cacheable_amo_i (1'b0),
|
||||
.cfg_rtab_single_entry_i (1'b0),
|
||||
.cfg_default_wb_i (1'b0)
|
||||
);
|
||||
|
||||
assign dcache_miss_o = dcache_read_miss, wbuffer_not_ni_o = wbuffer_empty_o;
|
||||
// }}}
|
||||
|
||||
endmodule : cva6_hpdcache_wrapper
|
|
@ -424,9 +424,9 @@ module cva6_icache
|
|||
logic [CVA6Cfg.ICACHE_SET_ASSOC_WIDTH-1:0] hit_idx;
|
||||
|
||||
for (genvar i = 0; i < CVA6Cfg.ICACHE_SET_ASSOC; i++) begin : gen_tag_cmpsel
|
||||
assign cl_hit[i] = (cl_tag_rdata[i] == cl_tag_d) & vld_rdata[i];
|
||||
assign cl_sel[i] = cl_rdata[i][{cl_offset_q, 3'b0}+:CVA6Cfg.FETCH_WIDTH];
|
||||
assign cl_user[i] = cl_ruser[i][{cl_offset_q, 3'b0}+:CVA6Cfg.FETCH_USER_WIDTH];
|
||||
assign cl_hit[i] = (cl_tag_rdata[i] == cl_tag_d) & vld_rdata[i];
|
||||
assign cl_sel[i] = cl_rdata[i][{cl_offset_q, 3'b0}+:CVA6Cfg.FETCH_WIDTH];
|
||||
assign cl_user[i] = CVA6Cfg.FETCH_USER_EN ? cl_ruser[i][{cl_offset_q, 3'b0}+:CVA6Cfg.FETCH_USER_WIDTH] : '0;
|
||||
end
|
||||
|
||||
|
||||
|
@ -441,10 +441,10 @@ module cva6_icache
|
|||
always_comb begin
|
||||
if (cmp_en_q) begin
|
||||
dreq_o.data = cl_sel[hit_idx];
|
||||
dreq_o.user = cl_user[hit_idx];
|
||||
dreq_o.user = CVA6Cfg.FETCH_USER_EN ? cl_user[hit_idx] : '0;
|
||||
end else begin
|
||||
dreq_o.data = mem_rtrn_i.data[{cl_offset_q, 3'b0}+:CVA6Cfg.FETCH_WIDTH];
|
||||
dreq_o.user = mem_rtrn_i.user[{cl_offset_q, 3'b0}+:CVA6Cfg.FETCH_USER_WIDTH];
|
||||
dreq_o.user = CVA6Cfg.FETCH_USER_EN ? mem_rtrn_i.user[{cl_offset_q, 3'b0}+:CVA6Cfg.FETCH_USER_WIDTH] : '0;
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 32407cb8f69b71824083abd72b2d4e8bcd0c2f01
|
||||
Subproject commit 04de80896981527c34fbbd35d7b1ef787a082d7c
|
|
@ -135,6 +135,8 @@ module std_cache_subsystem
|
|||
logic [1:0] w_select, w_select_fifo, w_select_arbiter;
|
||||
logic [1:0] w_fifo_usage;
|
||||
logic w_fifo_empty, w_fifo_full;
|
||||
logic w_fifo_push, w_fifo_pop;
|
||||
logic aw_lock_q, aw_lock_d;
|
||||
|
||||
|
||||
// AR Channel
|
||||
|
@ -191,17 +193,26 @@ module std_cache_subsystem
|
|||
.flush_i (1'b0),
|
||||
.testmode_i(1'b0),
|
||||
.full_o (w_fifo_full),
|
||||
.empty_o (), // leave open
|
||||
.empty_o (), // leave open
|
||||
.usage_o (w_fifo_usage),
|
||||
.data_i (w_select),
|
||||
// a new transaction was requested and granted
|
||||
.push_i (axi_req_o.aw_valid & axi_resp_i.aw_ready),
|
||||
.push_i (w_fifo_push),
|
||||
// write ID to select the output MUX
|
||||
.data_o (w_select_fifo),
|
||||
// transaction has finished
|
||||
.pop_i (axi_req_o.w_valid & axi_resp_i.w_ready & axi_req_o.w.last)
|
||||
.pop_i (w_fifo_pop)
|
||||
);
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin : aw_lock_reg
|
||||
if (~rst_ni) aw_lock_q <= 1'b0;
|
||||
else aw_lock_q <= aw_lock_d;
|
||||
end
|
||||
|
||||
assign w_fifo_push = ~aw_lock_q & axi_req_o.aw_valid;
|
||||
assign w_fifo_pop = axi_req_o.w_valid & axi_resp_i.w_ready & axi_req_o.w.last;
|
||||
assign aw_lock_d = ~axi_resp_i.aw_ready & (axi_req_o.aw_valid | aw_lock_q);
|
||||
|
||||
// In fall-through mode, the empty_o will be low when push_i is high (on zero usage).
|
||||
// We do not want this here. Also, usage_o is missing the MSB, so on full fifo, usage_o is zero.
|
||||
assign w_fifo_empty = w_fifo_usage == 0 && !w_fifo_full;
|
||||
|
|
|
@ -81,18 +81,19 @@ module tag_cmp #(
|
|||
if (req_i[i]) break;
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
`ifndef SYNTHESIS
|
||||
`ifndef VERILATOR
|
||||
// assert that cache only hits on one way
|
||||
// this only needs to be checked one cycle after all ways have been requested
|
||||
onehot :
|
||||
assert property (@(posedge clk_i) disable iff (!rst_ni) &req_i |=> $onehot0(hit_way_o))
|
||||
else begin
|
||||
$fatal(1, "Hit should be one-hot encoded");
|
||||
end
|
||||
`endif
|
||||
`endif
|
||||
// assert that cache only hits on one way
|
||||
// this only needs to be checked one cycle after all ways have been requested
|
||||
onehot :
|
||||
assert property (@(posedge clk_i) disable iff (!rst_ni) &req_i |=> $onehot0(hit_way_o))
|
||||
else begin
|
||||
$fatal(1, "Hit should be one-hot encoded");
|
||||
end
|
||||
`endif
|
||||
`endif
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (~rst_ni) begin
|
||||
|
|
|
@ -64,6 +64,7 @@ module wt_axi_adapter
|
|||
localparam MaxNumWords = $clog2(CVA6Cfg.AxiDataWidth / 8);
|
||||
localparam AxiRdBlenIcache = CVA6Cfg.ICACHE_LINE_WIDTH / CVA6Cfg.AxiDataWidth - 1;
|
||||
localparam AxiRdBlenDcache = CVA6Cfg.DCACHE_LINE_WIDTH / CVA6Cfg.AxiDataWidth - 1;
|
||||
localparam AxiBlenWidth = AxiNumWords > 1 ? $clog2(AxiNumWords) : AxiNumWords;
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// request path
|
||||
|
@ -82,7 +83,7 @@ module wt_axi_adapter
|
|||
logic axi_wr_valid, axi_rd_valid, axi_rd_rdy, axi_wr_rdy;
|
||||
logic axi_rd_lock, axi_wr_lock, axi_rd_exokay, axi_wr_exokay, wr_exokay;
|
||||
logic [CVA6Cfg.AxiAddrWidth-1:0] axi_rd_addr, axi_wr_addr;
|
||||
logic [$clog2(AxiNumWords)-1:0] axi_rd_blen, axi_wr_blen;
|
||||
logic [AxiBlenWidth-1:0] axi_rd_blen, axi_wr_blen;
|
||||
logic [2:0] axi_rd_size, axi_wr_size;
|
||||
logic [CVA6Cfg.AxiIdWidth-1:0]
|
||||
axi_rd_id_in, axi_wr_id_in, axi_rd_id_out, axi_wr_id_out, wr_id_out;
|
||||
|
@ -141,7 +142,7 @@ module wt_axi_adapter
|
|||
axi_wr_data[0] = {(CVA6Cfg.AxiDataWidth/CVA6Cfg.XLEN){dcache_data.data}};
|
||||
axi_wr_user[0] = dcache_data.user;
|
||||
// Cast to AXI address width
|
||||
axi_wr_addr = {{CVA6Cfg.AxiAddrWidth-CVA6Cfg.PLEN{1'b0}}, dcache_data.paddr};
|
||||
axi_wr_addr = CVA6Cfg.AxiAddrWidth'(dcache_data.paddr);
|
||||
axi_wr_size = dcache_data.size;
|
||||
axi_wr_req = 1'b0;
|
||||
axi_wr_blen = '0;// single word writes
|
||||
|
@ -166,18 +167,18 @@ module wt_axi_adapter
|
|||
// arbiter mux
|
||||
if (arb_idx) begin
|
||||
// Cast to AXI address width
|
||||
axi_rd_addr = {{CVA6Cfg.AxiAddrWidth - CVA6Cfg.PLEN{1'b0}}, dcache_data.paddr};
|
||||
axi_rd_addr = CVA6Cfg.AxiAddrWidth'(dcache_data.paddr);
|
||||
// If dcache_data.size MSB is set, we want to read as much as possible
|
||||
axi_rd_size = dcache_data.size[2] ? MaxNumWords[2:0] : dcache_data.size;
|
||||
if (dcache_data.size[2]) begin
|
||||
axi_rd_blen = AxiRdBlenDcache[$clog2(AxiNumWords)-1:0];
|
||||
axi_rd_blen = AxiRdBlenDcache[AxiBlenWidth-1:0];
|
||||
end
|
||||
end else begin
|
||||
// Cast to AXI address width
|
||||
axi_rd_addr = {{CVA6Cfg.AxiAddrWidth - CVA6Cfg.PLEN{1'b0}}, icache_data.paddr};
|
||||
axi_rd_addr = CVA6Cfg.AxiAddrWidth'(icache_data.paddr);
|
||||
axi_rd_size = MaxNumWords[2:0]; // always request max number of words in case of ifill
|
||||
if (!icache_data.nc) begin
|
||||
axi_rd_blen = AxiRdBlenIcache[$clog2(AxiNumWords)-1:0];
|
||||
axi_rd_blen = AxiRdBlenIcache[AxiBlenWidth-1:0];
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -311,8 +312,9 @@ module wt_axi_adapter
|
|||
end
|
||||
|
||||
cva6_fifo_v3 #(
|
||||
.dtype (icache_req_t),
|
||||
.DEPTH (ReqFifoDepth),
|
||||
.FPGA_ALTERA(CVA6Cfg.FpgaAlteraEn),
|
||||
.dtype(icache_req_t),
|
||||
.DEPTH(ReqFifoDepth),
|
||||
.FPGA_EN(CVA6Cfg.FpgaEn)
|
||||
) i_icache_data_fifo (
|
||||
.clk_i (clk_i),
|
||||
|
@ -329,8 +331,9 @@ module wt_axi_adapter
|
|||
);
|
||||
|
||||
cva6_fifo_v3 #(
|
||||
.dtype (dcache_req_t),
|
||||
.DEPTH (ReqFifoDepth),
|
||||
.FPGA_ALTERA(CVA6Cfg.FpgaAlteraEn),
|
||||
.dtype(dcache_req_t),
|
||||
.DEPTH(ReqFifoDepth),
|
||||
.FPGA_EN(CVA6Cfg.FpgaEn)
|
||||
) i_dcache_data_fifo (
|
||||
.clk_i (clk_i),
|
||||
|
|
|
@ -188,10 +188,10 @@ module wt_dcache
|
|||
// read controllers (LD unit and PTW/MMU)
|
||||
///////////////////////////////////////////////////////
|
||||
|
||||
// 0 is used by MMU, 1 by READ access requests
|
||||
// 0 is used by MMU or implicit read by zcmt, 1 by READ access requests
|
||||
for (genvar k = 0; k < NumPorts - 1; k++) begin : gen_rd_ports
|
||||
// set these to high prio ports
|
||||
if ((k == 0 && CVA6Cfg.MmuPresent) || (k == 1) || (k == 2 && CVA6Cfg.EnableAccelerator)) begin
|
||||
if ((k == 0 && (CVA6Cfg.MmuPresent || CVA6Cfg.RVZCMT )) || (k == 1) || (k == 2 && CVA6Cfg.EnableAccelerator)) begin
|
||||
assign rd_prio[k] = 1'b1;
|
||||
wt_dcache_ctrl #(
|
||||
.CVA6Cfg(CVA6Cfg),
|
||||
|
|
|
@ -199,7 +199,7 @@ module wt_dcache_missunit
|
|||
// generate random cacheline index
|
||||
lfsr #(
|
||||
.LfsrWidth(8),
|
||||
.OutWidth ($clog2(CVA6Cfg.DCACHE_SET_ASSOC))
|
||||
.OutWidth (CVA6Cfg.DCACHE_SET_ASSOC_WIDTH)
|
||||
) i_lfsr_inv (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni(rst_ni),
|
||||
|
|
|
@ -594,8 +594,6 @@ module wt_dcache_wbuffer
|
|||
wbuffer_d[wr_ptr].data[k*8+:8] = req_port_i.data_wdata[k*8+:8];
|
||||
if (CVA6Cfg.DATA_USER_EN) begin
|
||||
wbuffer_d[wr_ptr].user[k*8+:8] = req_port_i.data_wuser[k*8+:8];
|
||||
end else begin
|
||||
wbuffer_d[wr_ptr].user[k*8+:8] = '0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -303,8 +303,12 @@ module wt_l15_adapter
|
|||
always_comb begin : p_rtrn_logic
|
||||
icache_rtrn_o.rtype = ICACHE_IFILL_ACK;
|
||||
dcache_rtrn_o.rtype = DCACHE_LOAD_ACK;
|
||||
icache_rtrn_vld_o = 1'b0;
|
||||
dcache_rtrn_vld_o = 1'b0;
|
||||
icache_rtrn_vld_o = 1'b0;
|
||||
dcache_rtrn_vld_o = 1'b0;
|
||||
icache_rtrn_o.inv.vld = rtrn_fifo_data.l15_inval_icache_inval;
|
||||
icache_rtrn_o.inv.all = rtrn_fifo_data.l15_inval_icache_all_way;
|
||||
dcache_rtrn_o.inv.vld = rtrn_fifo_data.l15_inval_dcache_inval;
|
||||
dcache_rtrn_o.inv.all = rtrn_fifo_data.l15_inval_dcache_all_way;
|
||||
if (!rtrn_fifo_empty) begin
|
||||
unique case (rtrn_fifo_data.l15_returntype)
|
||||
L15_LOAD_RET: begin
|
||||
|
@ -370,13 +374,9 @@ module wt_l15_adapter
|
|||
// invalidation signal mapping
|
||||
assign icache_rtrn_o.inv.idx = {rtrn_fifo_data.l15_inval_address_15_4, 4'b0000};
|
||||
assign icache_rtrn_o.inv.way = rtrn_fifo_data.l15_inval_way;
|
||||
assign icache_rtrn_o.inv.vld = rtrn_fifo_data.l15_inval_icache_inval;
|
||||
assign icache_rtrn_o.inv.all = rtrn_fifo_data.l15_inval_icache_all_way;
|
||||
|
||||
assign dcache_rtrn_o.inv.idx = {rtrn_fifo_data.l15_inval_address_15_4, 4'b0000};
|
||||
assign dcache_rtrn_o.inv.way = rtrn_fifo_data.l15_inval_way;
|
||||
assign dcache_rtrn_o.inv.vld = rtrn_fifo_data.l15_inval_dcache_inval;
|
||||
assign dcache_rtrn_o.inv.all = rtrn_fifo_data.l15_inval_dcache_all_way;
|
||||
|
||||
fifo_v2 #(
|
||||
.dtype(l15_rtrn_t),
|
||||
|
|
|
@ -36,6 +36,8 @@ module commit_stage
|
|||
input logic single_step_i,
|
||||
// The instruction we want to commit - ISSUE_STAGE
|
||||
input scoreboard_entry_t [CVA6Cfg.NrCommitPorts-1:0] commit_instr_i,
|
||||
// The instruction is cancelled - ISSUE_STAGE
|
||||
input logic [CVA6Cfg.NrCommitPorts-1:0] commit_drop_i,
|
||||
// Acknowledge that we are indeed committing - ISSUE_STAGE
|
||||
output logic [CVA6Cfg.NrCommitPorts-1:0] commit_ack_o,
|
||||
// Acknowledge that we are indeed committing - CSR_REGFILE
|
||||
|
@ -58,10 +60,10 @@ module commit_stage
|
|||
output logic [CVA6Cfg.XLEN-1:0] csr_wdata_o,
|
||||
// Data to read from CSR - CSR_REGFILE
|
||||
input logic [CVA6Cfg.XLEN-1:0] csr_rdata_i,
|
||||
// Exception or interrupt occurred in CSR stage (the same as commit) - CSR_REGFILE
|
||||
input exception_t csr_exception_i,
|
||||
// Write the fflags CSR - CSR_REGFILE
|
||||
output logic csr_write_fflags_o,
|
||||
// Exception or interrupt occurred in CSR stage (the same as commit) - CSR_REGFILE
|
||||
input exception_t csr_exception_i,
|
||||
// Commit the pending store - EX_STAGE
|
||||
output logic commit_lsu_o,
|
||||
// Commit buffer of LSU is ready - EX_STAGE
|
||||
|
@ -82,7 +84,9 @@ module commit_stage
|
|||
output logic flush_commit_o,
|
||||
// Flush TLBs and pipeline - CONTROLLER
|
||||
output logic sfence_vma_o,
|
||||
// TO_BE_COMPLETED - CONTROLLER
|
||||
output logic hfence_vvma_o,
|
||||
// TO_BE_COMPLETED - CONTROLLER
|
||||
output logic hfence_gvma_o
|
||||
);
|
||||
|
||||
|
@ -101,7 +105,7 @@ module commit_stage
|
|||
// );
|
||||
|
||||
for (genvar i = 0; i < CVA6Cfg.NrCommitPorts; i++) begin : gen_waddr
|
||||
assign waddr_o[i] = commit_instr_i[i].rd[4:0];
|
||||
assign waddr_o[i] = commit_instr_i[i].rd;
|
||||
end
|
||||
|
||||
assign pc_o = commit_instr_i[0].pc;
|
||||
|
@ -111,9 +115,8 @@ module commit_stage
|
|||
for (int i = 0; i < CVA6Cfg.NrCommitPorts; i++) begin
|
||||
dirty_fp_state_o |= commit_ack_o[i] & (commit_instr_i[i].fu inside {FPU, FPU_VEC} || (CVA6Cfg.FpPresent && ariane_pkg::is_rd_fpr(
|
||||
commit_instr_i[i].op
|
||||
)));
|
||||
// Check if we issued a vector floating-point instruction to the accellerator
|
||||
dirty_fp_state_o |= commit_instr_i[i].fu == ACCEL && commit_instr_i[i].vfp;
|
||||
// Check if we issued a vector floating-point instruction to the accellerator
|
||||
))) | commit_instr_i[i].fu == ACCEL && commit_instr_i[i].vfp;
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -149,136 +152,159 @@ module commit_stage
|
|||
csr_write_fflags_o = 1'b0;
|
||||
flush_commit_o = 1'b0;
|
||||
|
||||
// we will not commit the instruction if we took an exception
|
||||
// and we do not commit the instruction if we requested a halt
|
||||
if (commit_instr_i[0].valid && !commit_instr_i[0].ex.valid && !halt_i) begin
|
||||
if (CVA6Cfg.RVZCMP && commit_instr_i[0].is_macro_instr && commit_instr_i[0].is_last_macro_instr)
|
||||
commit_macro_ack[0] = 1'b1;
|
||||
else commit_macro_ack[0] = 1'b0;
|
||||
// we can definitely write the register file
|
||||
// if the instruction is not committing anything the destination
|
||||
commit_ack_o[0] = 1'b1;
|
||||
if (CVA6Cfg.FpPresent && ariane_pkg::is_rd_fpr(commit_instr_i[0].op)) begin
|
||||
we_fpr_o[0] = 1'b1;
|
||||
// we do not commit the instruction yet if we requested a halt
|
||||
if (commit_instr_i[0].valid && !halt_i) begin
|
||||
// we will not commit the instruction if we took an exception
|
||||
if (commit_instr_i[0].ex.valid) begin
|
||||
// However we can drop it (with its exception)
|
||||
if (commit_drop_i[0]) begin
|
||||
commit_ack_o[0] = 1'b1;
|
||||
end
|
||||
end else begin
|
||||
we_gpr_o[0] = 1'b1;
|
||||
end
|
||||
// check whether the instruction we retire was a store
|
||||
if ((!CVA6Cfg.RVA && commit_instr_i[0].fu == STORE) || (CVA6Cfg.RVA && commit_instr_i[0].fu == STORE && !instr_0_is_amo)) begin
|
||||
// check if the LSU is ready to accept another commit entry (e.g.: a non-speculative store)
|
||||
if (commit_lsu_ready_i) begin
|
||||
commit_ack_o[0] = 1'b1;
|
||||
commit_lsu_o = 1'b1;
|
||||
// stall in case the store buffer is not able to accept anymore instructions
|
||||
end else begin
|
||||
commit_ack_o[0] = 1'b0;
|
||||
commit_ack_o[0] = 1'b1;
|
||||
|
||||
if (CVA6Cfg.RVZCMP && commit_instr_i[0].is_macro_instr && commit_instr_i[0].is_last_macro_instr)
|
||||
commit_macro_ack[0] = 1'b1;
|
||||
else commit_macro_ack[0] = 1'b0;
|
||||
|
||||
if (!commit_drop_i[0]) begin
|
||||
// we can definitely write the register file
|
||||
// if the instruction is not committing anything the destination
|
||||
if (CVA6Cfg.FpPresent && ariane_pkg::is_rd_fpr(commit_instr_i[0].op)) begin
|
||||
we_fpr_o[0] = 1'b1;
|
||||
end else begin
|
||||
we_gpr_o[0] = 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
// ---------
|
||||
// FPU Flags
|
||||
// ---------
|
||||
if (CVA6Cfg.FpPresent) begin
|
||||
if (commit_instr_i[0].fu inside {FPU, FPU_VEC}) begin
|
||||
// write the CSR with potential exception flags from retiring floating point instruction
|
||||
csr_wdata_o = {{CVA6Cfg.XLEN - 5{1'b0}}, commit_instr_i[0].ex.cause[4:0]};
|
||||
csr_write_fflags_o = 1'b1;
|
||||
commit_ack_o[0] = 1'b1;
|
||||
|
||||
// check whether the instruction we retire was a store
|
||||
if (commit_instr_i[0].fu == STORE && !(CVA6Cfg.RVA && instr_0_is_amo)) begin
|
||||
// check if the LSU is ready to accept another commit entry (e.g.: a non-speculative store)
|
||||
if (commit_lsu_ready_i) begin
|
||||
commit_lsu_o = 1'b1;
|
||||
// stall in case the store buffer is not able to accept anymore instructions
|
||||
end else begin
|
||||
commit_ack_o[0] = 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
// ---------
|
||||
// CSR Logic
|
||||
// ---------
|
||||
// check whether the instruction we retire was a CSR instruction and it did not
|
||||
// throw an exception
|
||||
if (commit_instr_i[0].fu == CSR) begin
|
||||
// write the CSR file
|
||||
csr_op_o = commit_instr_i[0].op;
|
||||
csr_wdata_o = commit_instr_i[0].result;
|
||||
if (!csr_exception_i.valid) begin
|
||||
commit_csr_o = 1'b1;
|
||||
wdata_o[0] = csr_rdata_i;
|
||||
commit_ack_o[0] = 1'b1;
|
||||
end else begin
|
||||
commit_ack_o[0] = 1'b0;
|
||||
we_gpr_o[0] = 1'b0;
|
||||
// ---------
|
||||
// FPU Flags
|
||||
// ---------
|
||||
if (CVA6Cfg.FpPresent) begin
|
||||
if (commit_instr_i[0].fu inside {FPU, FPU_VEC}) begin
|
||||
if (!commit_drop_i[0]) begin
|
||||
// write the CSR with potential exception flags from retiring floating point instruction
|
||||
csr_wdata_o = {{CVA6Cfg.XLEN - 5{1'b0}}, commit_instr_i[0].ex.cause[4:0]};
|
||||
csr_write_fflags_o = 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
// ---------
|
||||
// CSR Logic
|
||||
// ---------
|
||||
// check whether the instruction we retire was a CSR instruction and it did not
|
||||
// throw an exception
|
||||
if (commit_instr_i[0].fu == CSR) begin
|
||||
// write the CSR file
|
||||
csr_op_o = commit_instr_i[0].op;
|
||||
csr_wdata_o = commit_instr_i[0].result;
|
||||
if (!commit_drop_i[0]) begin
|
||||
if (!csr_exception_i.valid) begin
|
||||
commit_csr_o = 1'b1;
|
||||
wdata_o[0] = csr_rdata_i;
|
||||
end else begin
|
||||
commit_ack_o[0] = 1'b0;
|
||||
we_gpr_o[0] = 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
// ------------------
|
||||
// SFENCE.VMA Logic
|
||||
// ------------------
|
||||
// sfence.vma is idempotent so we can safely re-execute it after returning
|
||||
// from interrupt service routine
|
||||
// check if this instruction was a SFENCE_VMA
|
||||
if (CVA6Cfg.RVS && commit_instr_i[0].op == SFENCE_VMA) begin
|
||||
if (!commit_drop_i[0]) begin
|
||||
// no store pending so we can flush the TLBs and pipeline
|
||||
sfence_vma_o = no_st_pending_i;
|
||||
// wait for the store buffer to drain until flushing the pipeline
|
||||
commit_ack_o[0] = no_st_pending_i;
|
||||
end
|
||||
end
|
||||
// ------------------
|
||||
// HFENCE.VVMA Logic
|
||||
// ------------------
|
||||
// hfence.vvma is idempotent so we can safely re-execute it after returning
|
||||
// from interrupt service routine
|
||||
// check if this instruction was a HFENCE_VVMA
|
||||
if (CVA6Cfg.RVH && commit_instr_i[0].op == HFENCE_VVMA) begin
|
||||
if (!commit_drop_i[0]) begin
|
||||
// no store pending so we can flush the TLBs and pipeline
|
||||
hfence_vvma_o = no_st_pending_i;
|
||||
// wait for the store buffer to drain until flushing the pipeline
|
||||
commit_ack_o[0] = no_st_pending_i;
|
||||
end
|
||||
end
|
||||
// ------------------
|
||||
// HFENCE.GVMA Logic
|
||||
// ------------------
|
||||
// hfence.gvma is idempotent so we can safely re-execute it after returning
|
||||
// from interrupt service routine
|
||||
// check if this instruction was a HFENCE_GVMA
|
||||
if (CVA6Cfg.RVH && commit_instr_i[0].op == HFENCE_GVMA) begin
|
||||
if (!commit_drop_i[0]) begin
|
||||
// no store pending so we can flush the TLBs and pipeline
|
||||
hfence_gvma_o = no_st_pending_i;
|
||||
// wait for the store buffer to drain until flushing the pipeline
|
||||
commit_ack_o[0] = no_st_pending_i;
|
||||
end
|
||||
end
|
||||
// ------------------
|
||||
// FENCE.I Logic
|
||||
// ------------------
|
||||
// fence.i is idempotent so we can safely re-execute it after returning
|
||||
// from interrupt service routine
|
||||
// Fence synchronizes data and instruction streams. That means that we need to flush the private icache
|
||||
// and the private dcache. This is the most expensive instruction.
|
||||
if (commit_instr_i[0].op == FENCE_I || (flush_dcache_i && CVA6Cfg.DCacheType == config_pkg::WB && commit_instr_i[0].fu != STORE)) begin
|
||||
if (!commit_drop_i[0]) begin
|
||||
commit_ack_o[0] = no_st_pending_i;
|
||||
// tell the controller to flush the I$
|
||||
fence_i_o = no_st_pending_i;
|
||||
end
|
||||
end
|
||||
// ------------------
|
||||
// FENCE Logic
|
||||
// ------------------
|
||||
// fence is idempotent so we can safely re-execute it after returning
|
||||
// from interrupt service routine
|
||||
if (commit_instr_i[0].op == FENCE) begin
|
||||
if (!commit_drop_i[0]) begin
|
||||
commit_ack_o[0] = no_st_pending_i;
|
||||
// tell the controller to flush the D$
|
||||
fence_o = no_st_pending_i;
|
||||
end
|
||||
end
|
||||
// ------------------
|
||||
// AMO
|
||||
// ------------------
|
||||
if (CVA6Cfg.RVA && instr_0_is_amo) begin
|
||||
// AMO finished
|
||||
commit_ack_o[0] = amo_resp_i.ack;
|
||||
// flush the pipeline
|
||||
flush_commit_o = amo_resp_i.ack;
|
||||
amo_valid_commit_o = 1'b1;
|
||||
we_gpr_o[0] = amo_resp_i.ack;
|
||||
end
|
||||
end
|
||||
// ------------------
|
||||
// SFENCE.VMA Logic
|
||||
// ------------------
|
||||
// sfence.vma is idempotent so we can safely re-execute it after returning
|
||||
// from interrupt service routine
|
||||
// check if this instruction was a SFENCE_VMA
|
||||
if (CVA6Cfg.RVS && commit_instr_i[0].op == SFENCE_VMA) begin
|
||||
// no store pending so we can flush the TLBs and pipeline
|
||||
sfence_vma_o = no_st_pending_i;
|
||||
// wait for the store buffer to drain until flushing the pipeline
|
||||
commit_ack_o[0] = no_st_pending_i;
|
||||
end
|
||||
// ------------------
|
||||
// HFENCE.VVMA Logic
|
||||
// ------------------
|
||||
// hfence.vvma is idempotent so we can safely re-execute it after returning
|
||||
// from interrupt service routine
|
||||
// check if this instruction was a HFENCE_VVMA
|
||||
if (CVA6Cfg.RVH && commit_instr_i[0].op == HFENCE_VVMA) begin
|
||||
// no store pending so we can flush the TLBs and pipeline
|
||||
hfence_vvma_o = no_st_pending_i;
|
||||
// wait for the store buffer to drain until flushing the pipeline
|
||||
commit_ack_o[0] = no_st_pending_i;
|
||||
end
|
||||
// ------------------
|
||||
// HFENCE.GVMA Logic
|
||||
// ------------------
|
||||
// hfence.gvma is idempotent so we can safely re-execute it after returning
|
||||
// from interrupt service routine
|
||||
// check if this instruction was a HFENCE_GVMA
|
||||
if (CVA6Cfg.RVH && commit_instr_i[0].op == HFENCE_GVMA) begin
|
||||
// no store pending so we can flush the TLBs and pipeline
|
||||
hfence_gvma_o = no_st_pending_i;
|
||||
// wait for the store buffer to drain until flushing the pipeline
|
||||
commit_ack_o[0] = no_st_pending_i;
|
||||
end
|
||||
// ------------------
|
||||
// FENCE.I Logic
|
||||
// ------------------
|
||||
// fence.i is idempotent so we can safely re-execute it after returning
|
||||
// from interrupt service routine
|
||||
// Fence synchronizes data and instruction streams. That means that we need to flush the private icache
|
||||
// and the private dcache. This is the most expensive instruction.
|
||||
if (commit_instr_i[0].op == FENCE_I || (flush_dcache_i && CVA6Cfg.DCacheType == config_pkg::WB && commit_instr_i[0].fu != STORE)) begin
|
||||
commit_ack_o[0] = no_st_pending_i;
|
||||
// tell the controller to flush the I$
|
||||
fence_i_o = no_st_pending_i;
|
||||
end
|
||||
// ------------------
|
||||
// FENCE Logic
|
||||
// ------------------
|
||||
// fence is idempotent so we can safely re-execute it after returning
|
||||
// from interrupt service routine
|
||||
if (commit_instr_i[0].op == FENCE) begin
|
||||
commit_ack_o[0] = no_st_pending_i;
|
||||
// tell the controller to flush the D$
|
||||
fence_o = no_st_pending_i;
|
||||
end
|
||||
// ------------------
|
||||
// AMO
|
||||
// ------------------
|
||||
if (CVA6Cfg.RVA && instr_0_is_amo) begin
|
||||
// AMO finished
|
||||
commit_ack_o[0] = amo_resp_i.ack;
|
||||
// flush the pipeline
|
||||
flush_commit_o = amo_resp_i.ack;
|
||||
amo_valid_commit_o = 1'b1;
|
||||
we_gpr_o[0] = amo_resp_i.ack;
|
||||
end
|
||||
end
|
||||
|
||||
if (CVA6Cfg.NrCommitPorts > 1) begin
|
||||
|
||||
commit_ack_o[1] = 1'b0;
|
||||
we_gpr_o[1] = 1'b0;
|
||||
wdata_o[1] = commit_instr_i[1].result;
|
||||
commit_macro_ack[1] = 1'b0;
|
||||
commit_ack_o[1] = 1'b0;
|
||||
we_gpr_o[1] = 1'b0;
|
||||
wdata_o[1] = commit_instr_i[1].result;
|
||||
|
||||
// -----------------
|
||||
// Commit Port 2
|
||||
|
@ -289,42 +315,44 @@ module commit_stage
|
|||
&& !halt_i
|
||||
&& !(commit_instr_i[0].fu inside {CSR})
|
||||
&& !flush_dcache_i
|
||||
&& !instr_0_is_amo
|
||||
&& !(CVA6Cfg.RVA && instr_0_is_amo)
|
||||
&& !single_step_i) begin
|
||||
// only if the first instruction didn't throw an exception and this instruction won't throw an exception
|
||||
// and the functional unit is of type ALU, LOAD, CTRL_FLOW, MULT, FPU or FPU_VEC
|
||||
if (!exception_o.valid && !commit_instr_i[1].ex.valid
|
||||
&& (commit_instr_i[1].fu inside {ALU, LOAD, CTRL_FLOW, MULT, FPU, FPU_VEC})) begin
|
||||
if (!commit_instr_i[1].ex.valid && (commit_instr_i[1].fu inside {ALU, LOAD, CTRL_FLOW, MULT, FPU, FPU_VEC})) begin
|
||||
|
||||
if (CVA6Cfg.FpPresent && ariane_pkg::is_rd_fpr(commit_instr_i[1].op)) we_fpr_o[1] = 1'b1;
|
||||
else we_gpr_o[1] = 1'b1;
|
||||
|
||||
if (commit_instr_i[1].is_macro_instr && commit_instr_i[1].is_last_macro_instr)
|
||||
if (CVA6Cfg.RVZCMP && commit_instr_i[1].is_macro_instr && commit_instr_i[1].is_last_macro_instr)
|
||||
commit_macro_ack[1] = 1'b1;
|
||||
else commit_macro_ack[1] = 1'b0;
|
||||
|
||||
commit_ack_o[1] = 1'b1;
|
||||
|
||||
// additionally check if we are retiring an FPU instruction because we need to make sure that we write all
|
||||
// exception flags
|
||||
if (CVA6Cfg.FpPresent && commit_instr_i[1].fu inside {FPU, FPU_VEC}) begin
|
||||
if (csr_write_fflags_o)
|
||||
csr_wdata_o = {
|
||||
{CVA6Cfg.XLEN - 5{1'b0}},
|
||||
(commit_instr_i[0].ex.cause[4:0] | commit_instr_i[1].ex.cause[4:0])
|
||||
};
|
||||
else csr_wdata_o = {{CVA6Cfg.XLEN - 5{1'b0}}, commit_instr_i[1].ex.cause[4:0]};
|
||||
if (!commit_drop_i[1]) begin
|
||||
if (CVA6Cfg.FpPresent && ariane_pkg::is_rd_fpr(commit_instr_i[1].op))
|
||||
we_fpr_o[1] = 1'b1;
|
||||
else we_gpr_o[1] = 1'b1;
|
||||
|
||||
csr_write_fflags_o = 1'b1;
|
||||
// additionally check if we are retiring an FPU instruction because we need to make sure that we write all
|
||||
// exception flags
|
||||
if (CVA6Cfg.FpPresent) begin
|
||||
if (commit_instr_i[1].fu inside {FPU, FPU_VEC}) begin
|
||||
if (csr_write_fflags_o)
|
||||
csr_wdata_o = {
|
||||
{CVA6Cfg.XLEN - 5{1'b0}},
|
||||
(commit_instr_i[0].ex.cause[4:0] | commit_instr_i[1].ex.cause[4:0])
|
||||
};
|
||||
else csr_wdata_o = {{CVA6Cfg.XLEN - 5{1'b0}}, commit_instr_i[1].ex.cause[4:0]};
|
||||
csr_write_fflags_o = 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if (CVA6Cfg.RVZCMP) begin
|
||||
if (CVA6Cfg.NrCommitPorts > 1)
|
||||
commit_macro_ack_o = (commit_instr_i[0].is_macro_instr || commit_instr_i[1].is_macro_instr) ? commit_macro_ack : commit_ack_o;
|
||||
else
|
||||
commit_macro_ack_o = (commit_instr_i[0].is_macro_instr) ? commit_macro_ack : commit_ack_o;
|
||||
for (int i = 0; i < CVA6Cfg.NrCommitPorts; i++) begin
|
||||
commit_macro_ack_o[i] = commit_instr_i[i].is_macro_instr ? commit_macro_ack[i] : commit_ack_o[i];
|
||||
end
|
||||
end else commit_macro_ack_o = commit_ack_o;
|
||||
end
|
||||
|
||||
|
@ -344,7 +372,7 @@ module commit_stage
|
|||
exception_o.gva = 1'b0;
|
||||
|
||||
// we need a valid instruction in the commit stage
|
||||
if (commit_instr_i[0].valid) begin
|
||||
if (commit_instr_i[0].valid && !commit_drop_i[0]) begin
|
||||
// ------------------------
|
||||
// check for CSR exception
|
||||
// ------------------------
|
||||
|
|
|
@ -31,7 +31,9 @@ module compressed_decoder #(
|
|||
// Output instruction is macro - decoder
|
||||
output logic is_macro_instr_o,
|
||||
// Output instruction is compressed - decoder
|
||||
output logic is_compressed_o
|
||||
output logic is_compressed_o,
|
||||
// Output instruction is macro - decoder
|
||||
output logic is_zcmt_instr_o
|
||||
);
|
||||
|
||||
// -------------------
|
||||
|
@ -39,10 +41,10 @@ module compressed_decoder #(
|
|||
// -------------------
|
||||
always_comb begin
|
||||
illegal_instr_o = 1'b0;
|
||||
instr_o = '0;
|
||||
is_compressed_o = 1'b1;
|
||||
instr_o = instr_i;
|
||||
is_macro_instr_o = 0;
|
||||
is_zcmt_instr_o = 1'b0;
|
||||
|
||||
// I: | imm[11:0] | rs1 | funct3 | rd | opcode |
|
||||
// S: | imm[11:5] | rs2 | rs1 | funct3 | imm[4:0] | opcode |
|
||||
|
@ -868,18 +870,13 @@ module compressed_decoder #(
|
|||
3'b000,
|
||||
riscv::OpcodeStoreFp
|
||||
};
|
||||
end else if (CVA6Cfg.RVZCMP) begin
|
||||
if (instr_i[12:10] == 3'b110 || instr_i[12:10] == 3'b111 || instr_i[12:10] == 3'b011) begin //is a push/pop instruction
|
||||
is_macro_instr_o = 1;
|
||||
instr_o = instr_i;
|
||||
end else begin
|
||||
illegal_instr_o = 1'b1;
|
||||
end
|
||||
end else begin
|
||||
illegal_instr_o = 1'b1;
|
||||
end
|
||||
end else if (CVA6Cfg.RVZCMP && (instr_i[12:10] == 3'b110 || instr_i[12:10] == 3'b111 || instr_i[12:10] == 3'b011)) begin
|
||||
is_macro_instr_o = 1;
|
||||
instr_o = instr_i;
|
||||
end else if (CVA6Cfg.RVZCMT && (instr_i[12:10] == 3'b000)) //jt/jalt instruction
|
||||
is_zcmt_instr_o = 1'b1;
|
||||
else illegal_instr_o = 1'b1;
|
||||
end
|
||||
|
||||
riscv::OpcodeC2Swsp: begin
|
||||
// c.swsp -> sw rs2, imm(x2)
|
||||
instr_o = {
|
||||
|
|
|
@ -45,7 +45,9 @@ module controller
|
|||
input logic flush_dcache_ack_i,
|
||||
// Flush TLBs - EX_STAGE
|
||||
output logic flush_tlb_o,
|
||||
// TO_BE_COMPLETED - TO_BE_COMPLETED
|
||||
output logic flush_tlb_vvma_o,
|
||||
// TO_BE_COMPLETED - TO_BE_COMPLETED
|
||||
output logic flush_tlb_gvma_o,
|
||||
// Halt request from CSR (WFI instruction) - CSR_REGFILE
|
||||
input logic halt_csr_i,
|
||||
|
@ -69,7 +71,9 @@ module controller
|
|||
input logic fence_i,
|
||||
// We got an instruction to flush the TLBs and pipeline - COMMIT_STAGE
|
||||
input logic sfence_vma_i,
|
||||
// TO_BE_COMPLETED - TO_BE_COMPLETED
|
||||
input logic hfence_vvma_i,
|
||||
// TO_BE_COMPLETED - TO_BE_COMPLETED
|
||||
input logic hfence_gvma_i,
|
||||
// Flush request from commit stage - COMMIT_STAGE
|
||||
input logic flush_commit_i,
|
||||
|
@ -120,7 +124,7 @@ module controller
|
|||
flush_ex_o = 1'b1;
|
||||
// this is not needed in the case since we
|
||||
// have a write-through cache in this case
|
||||
if (CVA6Cfg.DCacheType == config_pkg::WB) begin
|
||||
if (CVA6Cfg.DcacheFlushOnFence) begin
|
||||
flush_dcache = 1'b1;
|
||||
fence_active_d = 1'b1;
|
||||
end
|
||||
|
@ -138,7 +142,7 @@ module controller
|
|||
flush_icache_o = 1'b1;
|
||||
// this is not needed in the case since we
|
||||
// have a write-through cache in this case
|
||||
if (CVA6Cfg.DCacheType == config_pkg::WB) begin
|
||||
if (CVA6Cfg.DcacheFlushOnFence) begin
|
||||
flush_dcache = 1'b1;
|
||||
fence_active_d = 1'b1;
|
||||
end
|
||||
|
@ -146,7 +150,7 @@ module controller
|
|||
|
||||
// this is not needed in the case since we
|
||||
// have a write-through cache in this case
|
||||
if (CVA6Cfg.DCacheType == config_pkg::WB) begin
|
||||
if (CVA6Cfg.DcacheFlushOnFence) begin
|
||||
// wait for the acknowledge here
|
||||
if (flush_dcache_ack_i && fence_active_q) begin
|
||||
fence_active_d = 1'b0;
|
||||
|
@ -238,7 +242,7 @@ module controller
|
|||
// ----------------------
|
||||
always_comb begin
|
||||
// halt the core if the fence is active
|
||||
halt_o = halt_csr_i || halt_acc_i || (CVA6Cfg.DCacheType == config_pkg::WB && fence_active_q);
|
||||
halt_o = halt_csr_i || halt_acc_i || (CVA6Cfg.DcacheFlushOnFence && fence_active_q);
|
||||
end
|
||||
|
||||
// ----------------------
|
||||
|
|
File diff suppressed because it is too large
Load diff
611
core/cva6.sv
611
core/cva6.sv
File diff suppressed because it is too large
Load diff
|
@ -1,4 +1,5 @@
|
|||
// Copyright 2018 ETH Zurich and University of Bologna.
|
||||
// Copyright 2024 - PlanV Technologies for additionnal contribution.
|
||||
// Copyright and related rights are licensed under the Solderpad Hardware
|
||||
// License, Version 0.51 (the "License"); you may not use this file except in
|
||||
// compliance with the License. You may obtain a copy of the License at
|
||||
|
@ -9,9 +10,12 @@
|
|||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
// Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
|
||||
// Additional contributions by:
|
||||
// Angela Gonzalez - PlanV Technologies
|
||||
|
||||
module cva6_fifo_v3 #(
|
||||
parameter bit FALL_THROUGH = 1'b0, // fifo is in fall-through mode
|
||||
parameter bit FPGA_ALTERA = 1'b0, // FPGA Altera optimizations enabled
|
||||
parameter int unsigned DATA_WIDTH = 32, // default data width if the fifo is of type logic
|
||||
parameter int unsigned DEPTH = 8, // depth can be arbitrary from 0 to 2**32
|
||||
parameter type dtype = logic [DATA_WIDTH-1:0],
|
||||
|
@ -46,6 +50,8 @@ module cva6_fifo_v3 #(
|
|||
logic [ADDR_DEPTH:0] status_cnt_n, status_cnt_q;
|
||||
// actual memory
|
||||
dtype [FifoDepth - 1:0] mem_n, mem_q;
|
||||
dtype data_ft_n, data_ft_q;
|
||||
logic first_word_n, first_word_q;
|
||||
|
||||
// fifo ram signals for fpga target
|
||||
logic fifo_ram_we;
|
||||
|
@ -71,12 +77,18 @@ module cva6_fifo_v3 #(
|
|||
read_pointer_n = read_pointer_q;
|
||||
write_pointer_n = write_pointer_q;
|
||||
status_cnt_n = status_cnt_q;
|
||||
if (FPGA_EN && FPGA_ALTERA) data_ft_n = data_ft_q;
|
||||
if (FPGA_EN && FPGA_ALTERA) first_word_n = first_word_q;
|
||||
if (FPGA_EN) begin
|
||||
fifo_ram_we = '0;
|
||||
fifo_ram_read_address = read_pointer_q;
|
||||
fifo_ram_write_address = '0;
|
||||
fifo_ram_wdata = '0;
|
||||
data_o = (DEPTH == 0) ? data_i : fifo_ram_rdata;
|
||||
if (DEPTH == 0) begin
|
||||
data_o = data_i;
|
||||
end else begin
|
||||
if (FPGA_ALTERA) data_o = first_word_q ? data_ft_q : fifo_ram_rdata;
|
||||
else data_o = fifo_ram_rdata;
|
||||
end
|
||||
end else begin
|
||||
data_o = (DEPTH == 0) ? data_i : mem_q[read_pointer_q];
|
||||
mem_n = mem_q;
|
||||
|
@ -89,6 +101,7 @@ module cva6_fifo_v3 #(
|
|||
fifo_ram_we = 1'b1;
|
||||
fifo_ram_write_address = write_pointer_q;
|
||||
fifo_ram_wdata = data_i;
|
||||
if (FPGA_ALTERA) first_word_n = first_word_q && pop_i;
|
||||
end else begin
|
||||
// push the data onto the queue
|
||||
mem_n[write_pointer_q] = data_i;
|
||||
|
@ -104,6 +117,8 @@ module cva6_fifo_v3 #(
|
|||
end
|
||||
|
||||
if (pop_i && ~empty_o) begin
|
||||
data_ft_n = data_i;
|
||||
if (FPGA_EN && FPGA_ALTERA) first_word_n = first_word_q && push_i;
|
||||
// read from the queue is a default assignment
|
||||
// but increment the read pointer...
|
||||
if (read_pointer_n == FifoDepth[ADDR_DEPTH-1:0] - 1) read_pointer_n = '0;
|
||||
|
@ -116,14 +131,23 @@ module cva6_fifo_v3 #(
|
|||
if (push_i && pop_i && ~full_o && ~empty_o) status_cnt_n = status_cnt_q;
|
||||
|
||||
// FIFO is in pass through mode -> do not change the pointers
|
||||
if (FALL_THROUGH && (status_cnt_q == 0) && push_i) begin
|
||||
data_o = data_i;
|
||||
if ((FALL_THROUGH || (FPGA_EN && FPGA_ALTERA)) && (status_cnt_q == 0) && push_i) begin
|
||||
if (FALL_THROUGH) data_o = data_i;
|
||||
if (FPGA_EN && FPGA_ALTERA) begin
|
||||
data_ft_n = data_i;
|
||||
first_word_n = '1;
|
||||
end
|
||||
if (pop_i) begin
|
||||
first_word_n = '0;
|
||||
status_cnt_n = status_cnt_q;
|
||||
read_pointer_n = read_pointer_q;
|
||||
write_pointer_n = write_pointer_q;
|
||||
end
|
||||
end
|
||||
|
||||
if (FPGA_EN) fifo_ram_read_address = (FPGA_ALTERA == 1) ? read_pointer_n : read_pointer_q;
|
||||
else fifo_ram_read_address = '0;
|
||||
|
||||
end
|
||||
|
||||
// sequential process
|
||||
|
@ -132,32 +156,53 @@ module cva6_fifo_v3 #(
|
|||
read_pointer_q <= '0;
|
||||
write_pointer_q <= '0;
|
||||
status_cnt_q <= '0;
|
||||
if (FPGA_ALTERA) first_word_q <= '0;
|
||||
if (FPGA_ALTERA) data_ft_q <= '0;
|
||||
end else begin
|
||||
if (flush_i) begin
|
||||
read_pointer_q <= '0;
|
||||
write_pointer_q <= '0;
|
||||
status_cnt_q <= '0;
|
||||
if (FPGA_ALTERA) first_word_q <= '0;
|
||||
if (FPGA_ALTERA) data_ft_q <= '0;
|
||||
end else begin
|
||||
read_pointer_q <= read_pointer_n;
|
||||
write_pointer_q <= write_pointer_n;
|
||||
status_cnt_q <= status_cnt_n;
|
||||
if (FPGA_ALTERA) data_ft_q <= data_ft_n;
|
||||
if (FPGA_ALTERA) first_word_q <= first_word_n;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (FPGA_EN) begin : gen_fpga_queue
|
||||
AsyncDpRam #(
|
||||
.ADDR_WIDTH(ADDR_DEPTH),
|
||||
.DATA_DEPTH(DEPTH),
|
||||
.DATA_WIDTH($bits(dtype))
|
||||
) fifo_ram (
|
||||
.Clk_CI (clk_i),
|
||||
.WrEn_SI (fifo_ram_we),
|
||||
.RdAddr_DI(fifo_ram_read_address),
|
||||
.WrAddr_DI(fifo_ram_write_address),
|
||||
.WrData_DI(fifo_ram_wdata),
|
||||
.RdData_DO(fifo_ram_rdata)
|
||||
);
|
||||
if (FPGA_ALTERA) begin
|
||||
SyncDpRam_ind_r_w #(
|
||||
.ADDR_WIDTH(ADDR_DEPTH),
|
||||
.DATA_DEPTH(DEPTH),
|
||||
.DATA_WIDTH($bits(dtype))
|
||||
) fifo_ram (
|
||||
.Clk_CI (clk_i),
|
||||
.WrEn_SI (fifo_ram_we),
|
||||
.RdAddr_DI(fifo_ram_read_address),
|
||||
.WrAddr_DI(fifo_ram_write_address),
|
||||
.WrData_DI(fifo_ram_wdata),
|
||||
.RdData_DO(fifo_ram_rdata)
|
||||
);
|
||||
end else begin
|
||||
AsyncDpRam #(
|
||||
.ADDR_WIDTH(ADDR_DEPTH),
|
||||
.DATA_DEPTH(DEPTH),
|
||||
.DATA_WIDTH($bits(dtype))
|
||||
) fifo_ram (
|
||||
.Clk_CI (clk_i),
|
||||
.WrEn_SI (fifo_ram_we),
|
||||
.RdAddr_DI(fifo_ram_read_address),
|
||||
.WrAddr_DI(fifo_ram_write_address),
|
||||
.WrData_DI(fifo_ram_wdata),
|
||||
.RdData_DO(fifo_ram_rdata)
|
||||
);
|
||||
end
|
||||
end else begin : gen_asic_queue
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (~rst_ni) begin
|
||||
|
@ -169,7 +214,6 @@ module cva6_fifo_v3 #(
|
|||
end
|
||||
|
||||
// pragma translate_off
|
||||
`ifndef VERILATOR
|
||||
initial begin
|
||||
assert (DEPTH > 0)
|
||||
else $error("DEPTH must be greater than 0.");
|
||||
|
@ -182,7 +226,6 @@ module cva6_fifo_v3 #(
|
|||
empty_read :
|
||||
assert property (@(posedge clk_i) disable iff (~rst_ni) (empty_o |-> ~pop_i))
|
||||
else $fatal(1, "Trying to pop data although the FIFO is empty.");
|
||||
`endif
|
||||
// pragma translate_on
|
||||
|
||||
endmodule // fifo_v3
|
||||
|
|
|
@ -92,14 +92,16 @@ module cva6_mmu
|
|||
input logic flush_tlb_gvma_i,
|
||||
|
||||
// Performance counters
|
||||
output logic itlb_miss_o,
|
||||
output logic dtlb_miss_o,
|
||||
output logic itlb_miss_o,
|
||||
output logic dtlb_miss_o,
|
||||
// PTW memory interface
|
||||
input dcache_req_o_t req_port_i,
|
||||
output dcache_req_i_t req_port_o,
|
||||
input dcache_req_o_t req_port_i,
|
||||
output dcache_req_i_t req_port_o,
|
||||
|
||||
// PMP
|
||||
input riscv::pmpcfg_t [15:0] pmpcfg_i,
|
||||
input logic [15:0][CVA6Cfg.PLEN-3:0] pmpaddr_i
|
||||
|
||||
input riscv::pmpcfg_t [avoid_neg(CVA6Cfg.NrPMPEntries-1):0] pmpcfg_i,
|
||||
input logic [avoid_neg(CVA6Cfg.NrPMPEntries-1):0][CVA6Cfg.PLEN-3:0] pmpaddr_i
|
||||
);
|
||||
|
||||
// memory management, pte for cva6
|
||||
|
@ -131,6 +133,7 @@ module cva6_mmu
|
|||
logic iaccess_err; // insufficient privilege to access this instruction page
|
||||
logic i_g_st_access_err; // insufficient privilege at g stage to access this instruction page
|
||||
logic daccess_err; // insufficient privilege to access this data page
|
||||
logic canonical_addr_check; // canonical check on the virtual address for SV39
|
||||
logic d_g_st_access_err; // insufficient privilege to access this data page
|
||||
logic ptw_active; // PTW is currently walking a page table
|
||||
logic walking_instr; // PTW is walking because of an ITLB miss
|
||||
|
@ -192,12 +195,15 @@ module cva6_mmu
|
|||
.lu_asid_i (itlb_lu_asid),
|
||||
.lu_vmid_i (vmid_i),
|
||||
.lu_vaddr_i (icache_areq_i.fetch_vaddr),
|
||||
.lu_gpaddr_o (itlb_gpaddr),
|
||||
.lu_content_o (itlb_content),
|
||||
.lu_g_content_o(itlb_g_content),
|
||||
.lu_gpaddr_o (itlb_gpaddr),
|
||||
.asid_to_be_flushed_i,
|
||||
.vmid_to_be_flushed_i,
|
||||
.vaddr_to_be_flushed_i,
|
||||
.gpaddr_to_be_flushed_i,
|
||||
.lu_is_page_o (itlb_is_page),
|
||||
.lu_hit_o (itlb_lu_hit),
|
||||
.*
|
||||
.lu_hit_o (itlb_lu_hit)
|
||||
);
|
||||
|
||||
cva6_tlb #(
|
||||
|
@ -217,15 +223,18 @@ module cva6_mmu
|
|||
.v_i (ld_st_v_i),
|
||||
.update_i (update_dtlb),
|
||||
.lu_access_i (dtlb_lu_access),
|
||||
.lu_asid_i (itlb_lu_asid),
|
||||
.lu_asid_i (dtlb_lu_asid),
|
||||
.lu_vmid_i (vmid_i),
|
||||
.lu_vaddr_i (lsu_vaddr_i),
|
||||
.lu_gpaddr_o (dtlb_gpaddr),
|
||||
.lu_content_o (dtlb_content),
|
||||
.lu_g_content_o(dtlb_g_content),
|
||||
.lu_gpaddr_o (dtlb_gpaddr),
|
||||
.asid_to_be_flushed_i,
|
||||
.vmid_to_be_flushed_i,
|
||||
.vaddr_to_be_flushed_i,
|
||||
.gpaddr_to_be_flushed_i,
|
||||
.lu_is_page_o (dtlb_is_page),
|
||||
.lu_hit_o (dtlb_lu_hit),
|
||||
.*
|
||||
.lu_hit_o (dtlb_lu_hit)
|
||||
);
|
||||
|
||||
|
||||
|
@ -289,6 +298,7 @@ module cva6_mmu
|
|||
) i_ptw (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni(rst_ni),
|
||||
.flush_i,
|
||||
|
||||
.ptw_active_o (ptw_active),
|
||||
.walking_instr_o (walking_instr),
|
||||
|
@ -296,17 +306,27 @@ module cva6_mmu
|
|||
.ptw_error_at_g_st_o (ptw_error_at_g_st),
|
||||
.ptw_err_at_g_int_st_o (ptw_err_at_g_int_st),
|
||||
.ptw_access_exception_o(ptw_access_exception),
|
||||
.enable_translation_i,
|
||||
.enable_g_translation_i,
|
||||
.en_ld_st_translation_i,
|
||||
.en_ld_st_g_translation_i,
|
||||
.v_i,
|
||||
.ld_st_v_i,
|
||||
.hlvx_inst_i (hlvx_inst_i),
|
||||
|
||||
.lsu_is_store_i(lsu_is_store_i),
|
||||
// PTW memory interface
|
||||
.req_port_i (req_port_i),
|
||||
.req_port_o (req_port_o),
|
||||
|
||||
.update_vaddr_o(update_vaddr),
|
||||
|
||||
// to Shared TLB, update logic
|
||||
.shared_tlb_update_o(update_shared_tlb),
|
||||
|
||||
.update_vaddr_o(update_vaddr),
|
||||
|
||||
.asid_i,
|
||||
.vs_asid_i,
|
||||
.vmid_i,
|
||||
|
||||
// from shared TLB
|
||||
// did we miss?
|
||||
|
@ -316,7 +336,11 @@ module cva6_mmu
|
|||
|
||||
.itlb_req_i(itlb_req),
|
||||
|
||||
.hlvx_inst_i(hlvx_inst_i),
|
||||
.satp_ppn_i,
|
||||
.vsatp_ppn_i,
|
||||
.hgatp_ppn_i,
|
||||
.mxr_i,
|
||||
.vmxr_i,
|
||||
|
||||
// Performance counters
|
||||
.shared_tlb_miss_o(shared_tlb_miss), //open for now
|
||||
|
@ -325,16 +349,12 @@ module cva6_mmu
|
|||
.pmpcfg_i (pmpcfg_i),
|
||||
.pmpaddr_i (pmpaddr_i),
|
||||
.bad_paddr_o(ptw_bad_paddr),
|
||||
.bad_gpaddr_o(ptw_bad_gpaddr),
|
||||
.*
|
||||
|
||||
.bad_gpaddr_o(ptw_bad_gpaddr)
|
||||
);
|
||||
|
||||
//-----------------------
|
||||
// Instruction Interface
|
||||
//-----------------------
|
||||
logic match_any_execute_region;
|
||||
logic pmp_instr_allow;
|
||||
localparam int PPNWMin = (CVA6Cfg.PPNW - 1 > 29) ? 29 : CVA6Cfg.PPNW - 1;
|
||||
|
||||
// The instruction interface is a simple request response interface
|
||||
|
@ -361,7 +381,7 @@ module cva6_mmu
|
|||
// we work with SV39 or SV32, so if VM is enabled, check that all bits [CVA6Cfg.VLEN-1:CVA6Cfg.SV-1] are equal
|
||||
if (icache_areq_i.fetch_req && !((&icache_areq_i.fetch_vaddr[CVA6Cfg.VLEN-1:CVA6Cfg.SV-1]) == 1'b1 || (|icache_areq_i.fetch_vaddr[CVA6Cfg.VLEN-1:CVA6Cfg.SV-1]) == 1'b0)) begin
|
||||
|
||||
icache_areq_o.fetch_exception.cause = riscv::INSTR_ACCESS_FAULT;
|
||||
icache_areq_o.fetch_exception.cause = riscv::INSTR_PAGE_FAULT;
|
||||
icache_areq_o.fetch_exception.valid = 1'b1;
|
||||
if (CVA6Cfg.TvalEn)
|
||||
icache_areq_o.fetch_exception.tval = CVA6Cfg.XLEN'(icache_areq_i.fetch_vaddr);
|
||||
|
@ -419,16 +439,6 @@ module cva6_mmu
|
|||
icache_areq_o.fetch_exception.tinst = '0;
|
||||
icache_areq_o.fetch_exception.gva = v_i;
|
||||
end
|
||||
end else if (!pmp_instr_allow) begin
|
||||
icache_areq_o.fetch_exception.cause = riscv::INSTR_ACCESS_FAULT;
|
||||
icache_areq_o.fetch_exception.valid = 1'b1;
|
||||
if (CVA6Cfg.TvalEn)
|
||||
icache_areq_o.fetch_exception.tval = CVA6Cfg.XLEN'(icache_areq_i.fetch_vaddr);
|
||||
if (CVA6Cfg.RVH) begin
|
||||
icache_areq_o.fetch_exception.tval2 = '0;
|
||||
icache_areq_o.fetch_exception.tinst = '0;
|
||||
icache_areq_o.fetch_exception.gva = v_i;
|
||||
end
|
||||
end
|
||||
end else if (ptw_active && walking_instr) begin
|
||||
// ---------//
|
||||
|
@ -459,7 +469,7 @@ module cva6_mmu
|
|||
end else begin
|
||||
icache_areq_o.fetch_exception.cause = riscv::INSTR_ACCESS_FAULT;
|
||||
icache_areq_o.fetch_exception.valid = 1'b1;
|
||||
if (CVA6Cfg.TvalEn) //To confirm this is the right TVAL
|
||||
if (CVA6Cfg.TvalEn) //To confirm this is the right TVAL
|
||||
icache_areq_o.fetch_exception.tval = CVA6Cfg.XLEN'(update_vaddr);
|
||||
if (CVA6Cfg.RVH) begin
|
||||
icache_areq_o.fetch_exception.tval2 = '0;
|
||||
|
@ -469,48 +479,8 @@ module cva6_mmu
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
// if it didn't match any execute region throw an `Instruction Access Fault`
|
||||
// or: if we are not translating, check PMPs immediately on the paddr
|
||||
if ((!match_any_execute_region && !ptw_error) || (!(enable_translation_i || enable_g_translation_i) && !pmp_instr_allow)) begin
|
||||
icache_areq_o.fetch_exception.cause = riscv::INSTR_ACCESS_FAULT;
|
||||
icache_areq_o.fetch_exception.valid = 1'b1;
|
||||
if (CVA6Cfg.TvalEn) begin //To confirm this is the right TVAL
|
||||
if (enable_translation_i || enable_g_translation_i)
|
||||
icache_areq_o.fetch_exception.tval = CVA6Cfg.XLEN'(update_vaddr);
|
||||
else
|
||||
icache_areq_o.fetch_exception.tval=CVA6Cfg.XLEN'(icache_areq_o.fetch_paddr[CVA6Cfg.PLEN-1:(CVA6Cfg.PLEN > CVA6Cfg.VLEN) ? (CVA6Cfg.PLEN - CVA6Cfg.VLEN) : 0]);
|
||||
end
|
||||
if (CVA6Cfg.RVH) begin
|
||||
icache_areq_o.fetch_exception.tval2 = '0;
|
||||
icache_areq_o.fetch_exception.tinst = '0;
|
||||
icache_areq_o.fetch_exception.gva = v_i;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// check for execute flag on memory
|
||||
assign match_any_execute_region = config_pkg::is_inside_execute_regions(
|
||||
CVA6Cfg, {{64 - CVA6Cfg.PLEN{1'b0}}, icache_areq_o.fetch_paddr}
|
||||
);
|
||||
|
||||
// Instruction fetch
|
||||
pmp #(
|
||||
.CVA6Cfg (CVA6Cfg), //comment for hypervisor extension
|
||||
.PLEN (CVA6Cfg.PLEN),
|
||||
.PMP_LEN (CVA6Cfg.PLEN - 2),
|
||||
.NR_ENTRIES(CVA6Cfg.NrPMPEntries)
|
||||
// .NR_ENTRIES ( ArianeCfg.NrPMPEntries ) // configuration used in hypervisor extension
|
||||
) i_pmp_if (
|
||||
.addr_i (icache_areq_o.fetch_paddr),
|
||||
.priv_lvl_i,
|
||||
// we will always execute on the instruction fetch port
|
||||
.access_type_i(riscv::ACCESS_EXEC),
|
||||
// Configuration
|
||||
.conf_addr_i (pmpaddr_i),
|
||||
.conf_i (pmpcfg_i),
|
||||
.allow_o (pmp_instr_allow)
|
||||
);
|
||||
|
||||
//-----------------------
|
||||
// Data Interface
|
||||
|
@ -521,38 +491,37 @@ module cva6_mmu
|
|||
logic hs_ld_st_inst_n, hs_ld_st_inst_q;
|
||||
pte_cva6_t dtlb_pte_n, dtlb_pte_q;
|
||||
pte_cva6_t dtlb_gpte_n, dtlb_gpte_q;
|
||||
exception_t misaligned_ex_n, misaligned_ex_q;
|
||||
logic lsu_req_n, lsu_req_q;
|
||||
logic lsu_is_store_n, lsu_is_store_q;
|
||||
logic dtlb_hit_n, dtlb_hit_q;
|
||||
logic [CVA6Cfg.PtLevels-2:0] dtlb_is_page_n, dtlb_is_page_q;
|
||||
exception_t misaligned_ex_n, misaligned_ex_q;
|
||||
|
||||
// check if we need to do translation or if we are always ready (e.g.: we are not translating anything)
|
||||
assign lsu_dtlb_hit_o = (en_ld_st_translation_i || en_ld_st_g_translation_i) ? dtlb_lu_hit : 1'b1;
|
||||
|
||||
// Wires to PMP checks
|
||||
riscv::pmp_access_t pmp_access_type;
|
||||
logic pmp_data_allow;
|
||||
|
||||
|
||||
// The data interface is simpler and only consists of a request/response interface
|
||||
always_comb begin : data_interface
|
||||
// save request and DTLB response
|
||||
lsu_vaddr_n = lsu_vaddr_i;
|
||||
lsu_req_n = lsu_req_i;
|
||||
misaligned_ex_n = misaligned_ex_i;
|
||||
dtlb_pte_n = dtlb_content;
|
||||
dtlb_hit_n = dtlb_lu_hit;
|
||||
lsu_is_store_n = lsu_is_store_i;
|
||||
dtlb_is_page_n = dtlb_is_page;
|
||||
misaligned_ex_n = misaligned_ex_i;
|
||||
|
||||
lsu_valid_o = lsu_req_q;
|
||||
lsu_exception_o = misaligned_ex_q;
|
||||
pmp_access_type = lsu_is_store_q ? riscv::ACCESS_WRITE : riscv::ACCESS_READ;
|
||||
|
||||
// mute misaligned exceptions if there is no request otherwise they will throw accidental exceptions
|
||||
misaligned_ex_n.valid = misaligned_ex_i.valid & lsu_req_i;
|
||||
|
||||
// we work with SV39 or SV32, so if VM is enabled, check that all bits [CVA6Cfg.VLEN-1:CVA6Cfg.SV-1] are equal to bit [CVA6Cfg.SV]
|
||||
canonical_addr_check = (lsu_req_i && en_ld_st_translation_i &&
|
||||
!((&lsu_vaddr_i[CVA6Cfg.VLEN-1:CVA6Cfg.SV-1]) == 1'b1 || (|lsu_vaddr_i[CVA6Cfg.VLEN-1:CVA6Cfg.SV-1]) == 1'b0));
|
||||
|
||||
// Check if the User flag is set, then we may only access it in supervisor mode
|
||||
// if SUM is enabled
|
||||
daccess_err = en_ld_st_translation_i &&
|
||||
|
@ -619,7 +588,7 @@ module cva6_mmu
|
|||
lsu_exception_o.tinst = '0;
|
||||
lsu_exception_o.gva = ld_st_v_i;
|
||||
end
|
||||
end else if ((en_ld_st_translation_i || !CVA6Cfg.RVH) && (!dtlb_pte_q.w || daccess_err || !dtlb_pte_q.d)) begin
|
||||
end else if ((en_ld_st_translation_i || !CVA6Cfg.RVH) && (!dtlb_pte_q.w || daccess_err || canonical_addr_check || !dtlb_pte_q.d)) begin
|
||||
lsu_exception_o.cause = riscv::STORE_PAGE_FAULT;
|
||||
lsu_exception_o.valid = 1'b1;
|
||||
if (CVA6Cfg.TvalEn)
|
||||
|
@ -631,19 +600,6 @@ module cva6_mmu
|
|||
lsu_exception_o.tinst = lsu_tinst_q;
|
||||
lsu_exception_o.gva = ld_st_v_i;
|
||||
end
|
||||
// Check if any PMPs are violated
|
||||
end else if (!pmp_data_allow) begin
|
||||
lsu_exception_o.cause = riscv::ST_ACCESS_FAULT;
|
||||
lsu_exception_o.valid = 1'b1;
|
||||
if (CVA6Cfg.TvalEn)
|
||||
lsu_exception_o.tval = {
|
||||
{CVA6Cfg.XLEN - CVA6Cfg.VLEN{lsu_vaddr_q[CVA6Cfg.VLEN-1]}}, lsu_vaddr_q
|
||||
};
|
||||
if (CVA6Cfg.RVH) begin
|
||||
lsu_exception_o.tval2 = '0;
|
||||
lsu_exception_o.tinst = lsu_tinst_q;
|
||||
lsu_exception_o.gva = ld_st_v_i;
|
||||
end
|
||||
end
|
||||
// this is a load
|
||||
end else begin
|
||||
|
@ -660,7 +616,7 @@ module cva6_mmu
|
|||
lsu_exception_o.gva = ld_st_v_i;
|
||||
end
|
||||
// check for sufficient access privileges - throw a page fault if necessary
|
||||
end else if (daccess_err) begin
|
||||
end else if (daccess_err || canonical_addr_check) begin
|
||||
lsu_exception_o.cause = riscv::LOAD_PAGE_FAULT;
|
||||
lsu_exception_o.valid = 1'b1;
|
||||
if (CVA6Cfg.TvalEn)
|
||||
|
@ -672,19 +628,6 @@ module cva6_mmu
|
|||
lsu_exception_o.tinst = lsu_tinst_q;
|
||||
lsu_exception_o.gva = ld_st_v_i;
|
||||
end
|
||||
// Check if any PMPs are violated
|
||||
end else if (!pmp_data_allow) begin
|
||||
lsu_exception_o.cause = riscv::LD_ACCESS_FAULT;
|
||||
lsu_exception_o.valid = 1'b1;
|
||||
if (CVA6Cfg.TvalEn)
|
||||
lsu_exception_o.tval = {
|
||||
{CVA6Cfg.XLEN - CVA6Cfg.VLEN{lsu_vaddr_q[CVA6Cfg.VLEN-1]}}, lsu_vaddr_q
|
||||
};
|
||||
if (CVA6Cfg.RVH) begin
|
||||
lsu_exception_o.tval2 = '0;
|
||||
lsu_exception_o.tinst = lsu_tinst_q;
|
||||
lsu_exception_o.gva = ld_st_v_i;
|
||||
end
|
||||
end
|
||||
end
|
||||
end else
|
||||
|
@ -780,50 +723,9 @@ module cva6_mmu
|
|||
end
|
||||
end
|
||||
end
|
||||
// If translation is not enabled, check the paddr immediately against PMPs
|
||||
end else if (lsu_req_q && !misaligned_ex_q.valid && !pmp_data_allow) begin
|
||||
if (lsu_is_store_q) begin
|
||||
lsu_exception_o.cause = riscv::ST_ACCESS_FAULT;
|
||||
lsu_exception_o.valid = 1'b1;
|
||||
if (CVA6Cfg.TvalEn)
|
||||
lsu_exception_o.tval = CVA6Cfg.XLEN'(lsu_paddr_o[CVA6Cfg.PLEN-1:(CVA6Cfg.PLEN>CVA6Cfg.VLEN)?(CVA6Cfg.PLEN-CVA6Cfg.VLEN) : 0]);
|
||||
|
||||
if (CVA6Cfg.RVH) begin
|
||||
lsu_exception_o.tval2 = '0;
|
||||
lsu_exception_o.tinst = lsu_tinst_q;
|
||||
lsu_exception_o.gva = ld_st_v_i;
|
||||
end
|
||||
end else begin
|
||||
lsu_exception_o.cause = riscv::LD_ACCESS_FAULT;
|
||||
lsu_exception_o.valid = 1'b1;
|
||||
if (CVA6Cfg.TvalEn)
|
||||
lsu_exception_o.tval = CVA6Cfg.XLEN'(lsu_paddr_o[CVA6Cfg.PLEN-1:(CVA6Cfg.PLEN>CVA6Cfg.VLEN)?(CVA6Cfg.PLEN-CVA6Cfg.VLEN) : 0]);
|
||||
|
||||
if (CVA6Cfg.RVH) begin
|
||||
lsu_exception_o.tval2 = '0;
|
||||
lsu_exception_o.tinst = lsu_tinst_q;
|
||||
lsu_exception_o.gva = ld_st_v_i;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// Load/store PMP check
|
||||
pmp #(
|
||||
.CVA6Cfg (CVA6Cfg),
|
||||
.PLEN (CVA6Cfg.PLEN),
|
||||
.PMP_LEN (CVA6Cfg.PLEN - 2),
|
||||
.NR_ENTRIES(CVA6Cfg.NrPMPEntries)
|
||||
) i_pmp_data (
|
||||
.addr_i (lsu_paddr_o),
|
||||
.priv_lvl_i (ld_st_priv_lvl_i),
|
||||
.access_type_i(pmp_access_type),
|
||||
// Configuration
|
||||
.conf_addr_i (pmpaddr_i),
|
||||
.conf_i (pmpcfg_i),
|
||||
.allow_o (pmp_data_allow)
|
||||
);
|
||||
|
||||
// ----------
|
||||
// Registers
|
||||
// ----------
|
||||
|
@ -832,7 +734,6 @@ module cva6_mmu
|
|||
lsu_vaddr_q <= '0;
|
||||
lsu_gpaddr_q <= '0;
|
||||
lsu_req_q <= '0;
|
||||
misaligned_ex_q <= '0;
|
||||
dtlb_pte_q <= '0;
|
||||
dtlb_gpte_q <= '0;
|
||||
dtlb_hit_q <= '0;
|
||||
|
@ -840,20 +741,21 @@ module cva6_mmu
|
|||
dtlb_is_page_q <= '0;
|
||||
lsu_tinst_q <= '0;
|
||||
hs_ld_st_inst_q <= '0;
|
||||
misaligned_ex_q <= '0;
|
||||
end else begin
|
||||
lsu_vaddr_q <= lsu_vaddr_n;
|
||||
lsu_req_q <= lsu_req_n;
|
||||
misaligned_ex_q <= misaligned_ex_n;
|
||||
dtlb_pte_q <= dtlb_pte_n;
|
||||
dtlb_hit_q <= dtlb_hit_n;
|
||||
lsu_is_store_q <= lsu_is_store_n;
|
||||
dtlb_is_page_q <= dtlb_is_page_n;
|
||||
lsu_vaddr_q <= lsu_vaddr_n;
|
||||
lsu_req_q <= lsu_req_n;
|
||||
dtlb_pte_q <= dtlb_pte_n;
|
||||
dtlb_hit_q <= dtlb_hit_n;
|
||||
lsu_is_store_q <= lsu_is_store_n;
|
||||
dtlb_is_page_q <= dtlb_is_page_n;
|
||||
|
||||
if (CVA6Cfg.RVH) begin
|
||||
lsu_tinst_q <= lsu_tinst_n;
|
||||
hs_ld_st_inst_q <= hs_ld_st_inst_n;
|
||||
dtlb_gpte_q <= dtlb_gpte_n;
|
||||
lsu_gpaddr_q <= lsu_gpaddr_n;
|
||||
misaligned_ex_q <= misaligned_ex_n;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
// Date: 26/02/2024
|
||||
// Description: Hardware-PTW (Page-Table-Walker) for CVA6 supporting sv32, sv39 and sv39x4.
|
||||
// This module is an merge of the PTW Sv39 developed by Florian Zaruba,
|
||||
// the PTW Sv32 developed by Sebastien Jacq and the PTW Sv39x4 by Bruno Sá.
|
||||
// the PTW Sv32 developed by Sebastien Jacq and the PTW Sv39x4 by Bruno Sá.
|
||||
|
||||
/* verilator lint_off WIDTH */
|
||||
|
||||
|
@ -83,12 +83,10 @@ module cva6_ptw
|
|||
output logic shared_tlb_miss_o,
|
||||
|
||||
// PMP
|
||||
|
||||
input riscv::pmpcfg_t [15:0] pmpcfg_i,
|
||||
input logic [15:0][CVA6Cfg.PLEN-3:0] pmpaddr_i,
|
||||
input riscv::pmpcfg_t [avoid_neg(CVA6Cfg.NrPMPEntries-1):0] pmpcfg_i,
|
||||
input logic [avoid_neg(CVA6Cfg.NrPMPEntries-1):0][CVA6Cfg.PLEN-3:0] pmpaddr_i,
|
||||
output logic [CVA6Cfg.PLEN-1:0] bad_paddr_o,
|
||||
output logic [CVA6Cfg.GPLEN-1:0] bad_gpaddr_o
|
||||
|
||||
);
|
||||
|
||||
// input registers
|
||||
|
@ -218,7 +216,7 @@ module cva6_ptw
|
|||
|
||||
// output the correct ASIDs
|
||||
shared_tlb_update_o.asid = tlb_update_asid_q;
|
||||
shared_tlb_update_o.vmid = tlb_update_vmid_q;
|
||||
shared_tlb_update_o.vmid = CVA6Cfg.RVH ? tlb_update_vmid_q : '0;
|
||||
|
||||
bad_paddr_o = ptw_access_exception_o ? ptw_pptr_q : 'b0;
|
||||
if (CVA6Cfg.RVH)
|
||||
|
@ -232,10 +230,7 @@ module cva6_ptw
|
|||
|
||||
|
||||
pmp #(
|
||||
.CVA6Cfg (CVA6Cfg),
|
||||
.PLEN (CVA6Cfg.PLEN),
|
||||
.PMP_LEN (CVA6Cfg.PLEN - 2),
|
||||
.NR_ENTRIES(CVA6Cfg.NrPMPEntries)
|
||||
.CVA6Cfg(CVA6Cfg)
|
||||
) i_pmp_ptw (
|
||||
.addr_i (ptw_pptr_q),
|
||||
// PTW access are always checked as if in S-Mode...
|
||||
|
@ -263,8 +258,8 @@ module cva6_ptw
|
|||
// PAGESIZE=2^12 and LEVELS=3.)
|
||||
// 2. Let pte be the value of the PTE at address a+va.vpn[i]×PTESIZE. (For
|
||||
// Sv32, PTESIZE=4.)
|
||||
// 3. If pte.v = 0, or if pte.r = 0 and pte.w = 1, or if any bits or encodings
|
||||
// that are reserved for future standard use are set within pte, stop and raise
|
||||
// 3. If pte.v = 0, or if pte.r = 0 and pte.w = 1, or if any bits or encodings
|
||||
// that are reserved for future standard use are set within pte, stop and raise
|
||||
// a page-fault exception corresponding to the original access type.
|
||||
// 4. Otherwise, the PTE is valid. If pte.r = 1 or pte.x = 1, go to step 5.
|
||||
// Otherwise, this PTE is a pointer to the next level of the page table.
|
||||
|
@ -301,7 +296,6 @@ module cva6_ptw
|
|||
global_mapping_n = global_mapping_q;
|
||||
// input registers
|
||||
tlb_update_asid_n = tlb_update_asid_q;
|
||||
tlb_update_vmid_n = tlb_update_vmid_q;
|
||||
vaddr_n = vaddr_q;
|
||||
pptr = ptw_pptr_q;
|
||||
|
||||
|
@ -309,6 +303,7 @@ module cva6_ptw
|
|||
gpaddr_n = gpaddr_q;
|
||||
gptw_pptr_n = gptw_pptr_q;
|
||||
gpte_d = gpte_q;
|
||||
tlb_update_vmid_n = tlb_update_vmid_q;
|
||||
end
|
||||
|
||||
shared_tlb_miss_o = 1'b0;
|
||||
|
@ -621,17 +616,17 @@ module cva6_ptw
|
|||
ptw_lvl_q <= '0;
|
||||
tag_valid_q <= 1'b0;
|
||||
tlb_update_asid_q <= '0;
|
||||
tlb_update_vmid_q <= '0;
|
||||
vaddr_q <= '0;
|
||||
ptw_pptr_q <= '0;
|
||||
global_mapping_q <= 1'b0;
|
||||
data_rdata_q <= '0;
|
||||
data_rvalid_q <= 1'b0;
|
||||
if (CVA6Cfg.RVH) begin
|
||||
gpaddr_q <= '0;
|
||||
gptw_pptr_q <= '0;
|
||||
ptw_stage_q <= S_STAGE;
|
||||
gpte_q <= '0;
|
||||
gpaddr_q <= '0;
|
||||
gptw_pptr_q <= '0;
|
||||
ptw_stage_q <= S_STAGE;
|
||||
gpte_q <= '0;
|
||||
tlb_update_vmid_q <= '0;
|
||||
end
|
||||
end else begin
|
||||
state_q <= state_d;
|
||||
|
|
|
@ -400,7 +400,6 @@ for (
|
|||
//--------------
|
||||
|
||||
//pragma translate_off
|
||||
`ifndef VERILATOR
|
||||
|
||||
initial begin : p_assertions
|
||||
assert ((TLB_ENTRIES % 2 == 0) && (TLB_ENTRIES > 1))
|
||||
|
@ -435,7 +434,6 @@ for (
|
|||
$stop();
|
||||
end
|
||||
|
||||
`endif
|
||||
//pragma translate_on
|
||||
|
||||
endmodule
|
||||
|
|
|
@ -51,21 +51,23 @@ module cva6_rvfi
|
|||
localparam logic [63:0] SMODE_STATUS_READ_MASK = ariane_pkg::smode_status_read_mask(CVA6Cfg);
|
||||
|
||||
logic flush;
|
||||
logic issue_instr_ack;
|
||||
logic [ariane_pkg::SUPERSCALAR:0] fetch_entry_valid;
|
||||
logic [ariane_pkg::SUPERSCALAR:0][31:0] instruction;
|
||||
logic [ariane_pkg::SUPERSCALAR:0] is_compressed;
|
||||
logic [ariane_pkg::SUPERSCALAR:0][31:0] truncated;
|
||||
logic [CVA6Cfg.NrIssuePorts-1:0] issue_instr_ack;
|
||||
logic [CVA6Cfg.NrIssuePorts-1:0] fetch_entry_valid;
|
||||
logic [CVA6Cfg.NrIssuePorts-1:0][31:0] instruction;
|
||||
logic [CVA6Cfg.NrIssuePorts-1:0] is_compressed;
|
||||
logic [CVA6Cfg.NrIssuePorts-1:0][31:0] truncated;
|
||||
|
||||
logic [CVA6Cfg.TRANS_ID_BITS-1:0] issue_pointer;
|
||||
logic [CVA6Cfg.NrIssuePorts-1:0][CVA6Cfg.TRANS_ID_BITS-1:0] issue_pointer;
|
||||
logic [CVA6Cfg.NrCommitPorts-1:0][CVA6Cfg.TRANS_ID_BITS-1:0] commit_pointer;
|
||||
|
||||
logic flush_unissued_instr;
|
||||
logic decoded_instr_valid;
|
||||
logic decoded_instr_ack;
|
||||
logic [CVA6Cfg.NrIssuePorts-1:0] decoded_instr_valid;
|
||||
logic [CVA6Cfg.NrIssuePorts-1:0] decoded_instr_ack;
|
||||
|
||||
logic [CVA6Cfg.XLEN-1:0] rs1_forwarding;
|
||||
logic [CVA6Cfg.XLEN-1:0] rs2_forwarding;
|
||||
logic [CVA6Cfg.NrIssuePorts-1:0][CVA6Cfg.XLEN-1:0] rs1;
|
||||
logic [CVA6Cfg.NrIssuePorts-1:0][CVA6Cfg.XLEN-1:0] rs2;
|
||||
|
||||
logic [CVA6Cfg.NrCommitPorts-1:0][CVA6Cfg.XLEN-1:0] rvfi_intr;
|
||||
|
||||
logic [CVA6Cfg.NrCommitPorts-1:0][CVA6Cfg.VLEN-1:0] commit_instr_pc;
|
||||
fu_op [CVA6Cfg.NrCommitPorts-1:0] commit_instr_op;
|
||||
|
@ -73,7 +75,8 @@ module cva6_rvfi
|
|||
logic [CVA6Cfg.NrCommitPorts-1:0][REG_ADDR_SIZE-1:0] commit_instr_rs2;
|
||||
logic [CVA6Cfg.NrCommitPorts-1:0][REG_ADDR_SIZE-1:0] commit_instr_rd;
|
||||
logic [CVA6Cfg.NrCommitPorts-1:0][CVA6Cfg.XLEN-1:0] commit_instr_result;
|
||||
logic [CVA6Cfg.NrCommitPorts-1:0][CVA6Cfg.VLEN-1:0] commit_instr_valid;
|
||||
logic [CVA6Cfg.NrCommitPorts-1:0] commit_instr_valid;
|
||||
logic [CVA6Cfg.NrCommitPorts-1:0] commit_drop;
|
||||
|
||||
logic [CVA6Cfg.XLEN-1:0] ex_commit_cause;
|
||||
logic ex_commit_valid;
|
||||
|
@ -129,8 +132,8 @@ module cva6_rvfi
|
|||
assign decoded_instr_valid = instr.decoded_instr_valid;
|
||||
assign decoded_instr_ack = instr.decoded_instr_ack;
|
||||
|
||||
assign rs1_forwarding = instr.rs1_forwarding;
|
||||
assign rs2_forwarding = instr.rs2_forwarding;
|
||||
assign rs1 = instr.rs1;
|
||||
assign rs2 = instr.rs2;
|
||||
|
||||
assign commit_instr_pc = instr.commit_instr_pc;
|
||||
assign commit_instr_op = instr.commit_instr_op;
|
||||
|
@ -139,6 +142,7 @@ module cva6_rvfi
|
|||
assign commit_instr_rd = instr.commit_instr_rd;
|
||||
assign commit_instr_result = instr.commit_instr_result;
|
||||
assign commit_instr_valid = instr.commit_instr_valid;
|
||||
assign commit_drop = instr.commit_drop;
|
||||
|
||||
assign ex_commit_cause = instr.ex_commit_cause;
|
||||
assign ex_commit_valid = instr.ex_commit_valid;
|
||||
|
@ -159,7 +163,7 @@ module cva6_rvfi
|
|||
|
||||
//ID STAGE
|
||||
|
||||
for (genvar i = 0; i <= ariane_pkg::SUPERSCALAR; i++) begin
|
||||
for (genvar i = 0; i < CVA6Cfg.NrIssuePorts; i++) begin
|
||||
assign truncated[i] = (is_compressed[i]) ? {16'b0, instruction[i][15:0]} : instruction[i];
|
||||
end
|
||||
|
||||
|
@ -167,38 +171,42 @@ module cva6_rvfi
|
|||
logic valid;
|
||||
logic [31:0] instr;
|
||||
} issue_struct_t;
|
||||
issue_struct_t [ariane_pkg::SUPERSCALAR:0] issue_n, issue_q;
|
||||
issue_struct_t [CVA6Cfg.NrIssuePorts-1:0] issue_n, issue_q;
|
||||
logic took0;
|
||||
|
||||
always_comb begin
|
||||
issue_n = issue_q;
|
||||
took0 = 1'b0;
|
||||
|
||||
if (issue_instr_ack) issue_n[0].valid = 1'b0;
|
||||
for (int unsigned i = 0; i < CVA6Cfg.NrIssuePorts; i++) begin
|
||||
if (issue_instr_ack[i]) begin
|
||||
issue_n[i].valid = 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
if (!issue_n[ariane_pkg::SUPERSCALAR].valid) begin
|
||||
issue_n[ariane_pkg::SUPERSCALAR].valid = fetch_entry_valid[0];
|
||||
issue_n[ariane_pkg::SUPERSCALAR].instr = truncated[0];
|
||||
if (!issue_n[CVA6Cfg.NrIssuePorts-1].valid) begin
|
||||
issue_n[CVA6Cfg.NrIssuePorts-1].valid = fetch_entry_valid[0];
|
||||
issue_n[CVA6Cfg.NrIssuePorts-1].instr = truncated[0];
|
||||
took0 = 1'b1;
|
||||
end
|
||||
|
||||
if (!issue_n[0].valid) begin
|
||||
issue_n[0] = issue_n[ariane_pkg::SUPERSCALAR];
|
||||
issue_n[ariane_pkg::SUPERSCALAR].valid = 1'b0;
|
||||
issue_n[0] = issue_n[CVA6Cfg.NrIssuePorts-1];
|
||||
issue_n[CVA6Cfg.NrIssuePorts-1].valid = 1'b0;
|
||||
end
|
||||
|
||||
if (!issue_n[ariane_pkg::SUPERSCALAR].valid) begin
|
||||
if (!issue_n[CVA6Cfg.NrIssuePorts-1].valid) begin
|
||||
if (took0) begin
|
||||
issue_n[ariane_pkg::SUPERSCALAR].valid = fetch_entry_valid[ariane_pkg::SUPERSCALAR];
|
||||
issue_n[ariane_pkg::SUPERSCALAR].instr = truncated[ariane_pkg::SUPERSCALAR];
|
||||
issue_n[CVA6Cfg.NrIssuePorts-1].valid = fetch_entry_valid[CVA6Cfg.NrIssuePorts-1];
|
||||
issue_n[CVA6Cfg.NrIssuePorts-1].instr = truncated[CVA6Cfg.NrIssuePorts-1];
|
||||
end else begin
|
||||
issue_n[ariane_pkg::SUPERSCALAR].valid = fetch_entry_valid[0];
|
||||
issue_n[ariane_pkg::SUPERSCALAR].instr = truncated[0];
|
||||
issue_n[CVA6Cfg.NrIssuePorts-1].valid = fetch_entry_valid[0];
|
||||
issue_n[CVA6Cfg.NrIssuePorts-1].instr = truncated[0];
|
||||
end
|
||||
end
|
||||
|
||||
if (flush) begin
|
||||
for (int unsigned i = 0; i <= ariane_pkg::SUPERSCALAR; i++) begin
|
||||
for (int unsigned i = 0; i < CVA6Cfg.NrIssuePorts; i++) begin
|
||||
issue_n[i].valid = 1'b0;
|
||||
end
|
||||
end
|
||||
|
@ -229,16 +237,18 @@ module cva6_rvfi
|
|||
always_comb begin : issue_fifo
|
||||
mem_n = mem_q;
|
||||
|
||||
if (decoded_instr_valid && decoded_instr_ack && !flush_unissued_instr) begin
|
||||
mem_n[issue_pointer] = '{
|
||||
rs1_rdata: rs1_forwarding,
|
||||
rs2_rdata: rs2_forwarding,
|
||||
lsu_addr: '0,
|
||||
lsu_rmask: '0,
|
||||
lsu_wmask: '0,
|
||||
lsu_wdata: '0,
|
||||
instr: issue_q[0].instr
|
||||
};
|
||||
for (int unsigned i = 0; i < CVA6Cfg.NrIssuePorts; i++) begin
|
||||
if (decoded_instr_valid[i] && decoded_instr_ack[i] && !flush_unissued_instr) begin
|
||||
mem_n[issue_pointer[i]] = '{
|
||||
rs1_rdata: rs1[i],
|
||||
rs2_rdata: rs2[i],
|
||||
lsu_addr: '0,
|
||||
lsu_rmask: '0,
|
||||
lsu_wmask: '0,
|
||||
lsu_wdata: '0,
|
||||
instr: issue_q[i].instr
|
||||
};
|
||||
end
|
||||
end
|
||||
|
||||
if (lsu_rmask != 0) begin
|
||||
|
@ -247,7 +257,7 @@ module cva6_rvfi
|
|||
end else if (lsu_wmask != 0) begin
|
||||
mem_n[lsu_addr_trans_id].lsu_addr = lsu_addr;
|
||||
mem_n[lsu_addr_trans_id].lsu_wmask = lsu_wmask;
|
||||
mem_n[lsu_addr_trans_id].lsu_wdata = wbdata[1];
|
||||
mem_n[lsu_addr_trans_id].lsu_wdata = wbdata[STORE_WB];
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -266,20 +276,34 @@ module cva6_rvfi
|
|||
always_ff @(posedge clk_i) begin
|
||||
for (int i = 0; i < CVA6Cfg.NrCommitPorts; i++) begin
|
||||
logic exception;
|
||||
exception = commit_instr_valid[i][0] && ex_commit_valid;
|
||||
rvfi_instr_o[i].valid <= (commit_ack[i] && !ex_commit_valid) ||
|
||||
logic valid;
|
||||
exception = (i == 0) && commit_instr_valid[i] && ex_commit_valid && !commit_drop[i];
|
||||
valid = (commit_ack[i] && !ex_commit_valid && !commit_drop[i]) ||
|
||||
(exception && (ex_commit_cause == riscv::ENV_CALL_MMODE ||
|
||||
ex_commit_cause == riscv::ENV_CALL_SMODE ||
|
||||
ex_commit_cause == riscv::ENV_CALL_UMODE));
|
||||
rvfi_instr_o[i].insn <= mem_q[commit_pointer[i]].instr;
|
||||
// when trap, the instruction is not executed
|
||||
rvfi_instr_o[i].trap <= exception;
|
||||
rvfi_instr_o[i].valid <= valid;
|
||||
rvfi_instr_o[i].insn <= mem_q[commit_pointer[i]].instr;
|
||||
// when synchronous trap, the instruction is not executed
|
||||
rvfi_instr_o[i].trap <= exception && !ex_commit_cause[31];
|
||||
|
||||
if (exception && ex_commit_cause[31]) begin
|
||||
rvfi_intr[i] <= 'b101;
|
||||
end else if (exception) begin
|
||||
rvfi_intr[i] <= 'b11;
|
||||
end
|
||||
if (valid) begin
|
||||
rvfi_intr[i] <= 0;
|
||||
end
|
||||
|
||||
rvfi_instr_o[i].intr <= rvfi_intr[i];
|
||||
|
||||
rvfi_instr_o[i].cause <= ex_commit_cause;
|
||||
rvfi_instr_o[i].mode <= (CVA6Cfg.DebugEn && debug_mode) ? 2'b10 : priv_lvl;
|
||||
rvfi_instr_o[i].ixl <= CVA6Cfg.XLEN == 64 ? 2 : 1;
|
||||
rvfi_instr_o[i].rs1_addr <= commit_instr_rs1[i][4:0];
|
||||
rvfi_instr_o[i].rs2_addr <= commit_instr_rs2[i][4:0];
|
||||
rvfi_instr_o[i].rd_addr <= commit_instr_rd[i][4:0];
|
||||
rvfi_instr_o[i].rs1_addr <= commit_instr_rs1[i];
|
||||
rvfi_instr_o[i].rs2_addr <= commit_instr_rs2[i];
|
||||
rvfi_instr_o[i].rd_addr <= commit_instr_rd[i];
|
||||
rvfi_instr_o[i].rd_wdata <= (CVA6Cfg.FpPresent && is_rd_fpr(
|
||||
commit_instr_op[i]
|
||||
)) ? commit_instr_result[i] : wdata[i];
|
||||
|
@ -312,14 +336,12 @@ module cva6_rvfi
|
|||
assign rvfi_csr_o.``CSR_NAME``.rmask = CSR_ENABLE_COND ? 1 : 0; \
|
||||
assign rvfi_csr_o.``CSR_NAME``.wmask = (rvfi_csr_o.``CSR_NAME``.rdata != {{CVA6Cfg.XLEN - $bits(CSR_SOURCE_NAME)}, CSR_SOURCE_NAME}) && CSR_ENABLE_COND;
|
||||
|
||||
`define COMMA ,
|
||||
|
||||
`define CONNECT_RVFI_SAME(CSR_ENABLE_COND, CSR_NAME) \
|
||||
`CONNECT_RVFI_FULL(CSR_ENABLE_COND, CSR_NAME, csr.``CSR_NAME``_q)
|
||||
|
||||
`CONNECT_RVFI_FULL(CVA6Cfg.FpPresent, fflags, csr.fcsr_q.fflags)
|
||||
`CONNECT_RVFI_FULL(CVA6Cfg.FpPresent, frm, csr.fcsr_q.frm)
|
||||
`CONNECT_RVFI_FULL(CVA6Cfg.FpPresent, fcsr, { csr.fcsr_q.frm `COMMA csr.fcsr_q.fflags})
|
||||
`CONNECT_RVFI_FULL(CVA6Cfg.FpPresent, fcsr, {csr.fcsr_q.frm, csr.fcsr_q.fflags})
|
||||
|
||||
`CONNECT_RVFI_FULL(CVA6Cfg.FpPresent, ftran, csr.fcsr_q.fprec)
|
||||
`CONNECT_RVFI_SAME(CVA6Cfg.FpPresent, dcsr)
|
||||
|
@ -350,7 +372,7 @@ module cva6_rvfi
|
|||
`CONNECT_RVFI_FULL(1'b1, mstatus, csr.mstatus_extended)
|
||||
|
||||
bit [31:0] mstatush_q;
|
||||
`CONNECT_RVFI_FULL(1'b1, mstatush, mstatush_q)
|
||||
`CONNECT_RVFI_FULL(1'b1, mstatush, mstatush_q)
|
||||
|
||||
`CONNECT_RVFI_FULL(1'b1, misa, IsaCode)
|
||||
|
||||
|
@ -394,7 +416,7 @@ module cva6_rvfi
|
|||
`CONNECT_RVFI_SAME(1'b1, icache)
|
||||
|
||||
`CONNECT_RVFI_SAME(CVA6Cfg.EnableAccelerator, acc_cons)
|
||||
|
||||
`CONNECT_RVFI_SAME(CVA6Cfg.RVZCMT, jvt)
|
||||
`CONNECT_RVFI_FULL(1'b1, pmpcfg0, csr.pmpcfg_q[CVA6Cfg.XLEN/8-1:0])
|
||||
`CONNECT_RVFI_FULL(CVA6Cfg.XLEN == 32, pmpcfg1, csr.pmpcfg_q[7:4])
|
||||
|
||||
|
@ -405,7 +427,8 @@ module cva6_rvfi
|
|||
genvar i;
|
||||
generate
|
||||
for (i = 0; i < 16; i++) begin
|
||||
`CONNECT_RVFI_FULL(1'b1, pmpaddr[i], csr.pmpaddr_q[i][CVA6Cfg.PLEN-3:0])
|
||||
`CONNECT_RVFI_FULL(1'b1, pmpaddr[i], {
|
||||
csr.pmpaddr_q[i][CVA6Cfg.PLEN-3:1], pmpcfg_q[i].addr_mode[1]})
|
||||
end
|
||||
endgenerate
|
||||
;
|
||||
|
|
|
@ -22,23 +22,24 @@ module cva6_rvfi_probes
|
|||
|
||||
) (
|
||||
|
||||
input logic flush_i,
|
||||
input logic [SUPERSCALAR:0] issue_instr_ack_i,
|
||||
input logic [SUPERSCALAR:0] fetch_entry_valid_i,
|
||||
input logic [SUPERSCALAR:0][31:0] instruction_i,
|
||||
input logic [SUPERSCALAR:0] is_compressed_i,
|
||||
input logic flush_i,
|
||||
input logic [CVA6Cfg.NrIssuePorts-1:0] issue_instr_ack_i,
|
||||
input logic [CVA6Cfg.NrIssuePorts-1:0] fetch_entry_valid_i,
|
||||
input logic [CVA6Cfg.NrIssuePorts-1:0][31:0] instruction_i,
|
||||
input logic [CVA6Cfg.NrIssuePorts-1:0] is_compressed_i,
|
||||
|
||||
input logic [CVA6Cfg.TRANS_ID_BITS-1:0] issue_pointer_i,
|
||||
input logic [CVA6Cfg.NrCommitPorts-1:0][CVA6Cfg.TRANS_ID_BITS-1:0] commit_pointer_i,
|
||||
input logic [CVA6Cfg.NrIssuePorts-1 : 0][CVA6Cfg.TRANS_ID_BITS-1:0] issue_pointer_i,
|
||||
input logic [ CVA6Cfg.NrCommitPorts-1:0][CVA6Cfg.TRANS_ID_BITS-1:0] commit_pointer_i,
|
||||
|
||||
input logic flush_unissued_instr_i,
|
||||
input logic decoded_instr_valid_i,
|
||||
input logic decoded_instr_ack_i,
|
||||
input logic [CVA6Cfg.NrIssuePorts-1:0] decoded_instr_valid_i,
|
||||
input logic [CVA6Cfg.NrIssuePorts-1:0] decoded_instr_ack_i,
|
||||
|
||||
input logic [CVA6Cfg.XLEN-1:0] rs1_forwarding_i,
|
||||
input logic [CVA6Cfg.XLEN-1:0] rs2_forwarding_i,
|
||||
input logic [CVA6Cfg.NrIssuePorts-1:0][CVA6Cfg.XLEN-1:0] rs1_i,
|
||||
input logic [CVA6Cfg.NrIssuePorts-1:0][CVA6Cfg.XLEN-1:0] rs2_i,
|
||||
|
||||
input scoreboard_entry_t [CVA6Cfg.NrCommitPorts-1:0] commit_instr_i,
|
||||
input logic [CVA6Cfg.NrCommitPorts-1:0] commit_drop_i,
|
||||
input exception_t ex_commit_i,
|
||||
input riscv::priv_lvl_t priv_lvl_i,
|
||||
|
||||
|
@ -50,6 +51,7 @@ module cva6_rvfi_probes
|
|||
input logic [CVA6Cfg.NrCommitPorts-1:0][CVA6Cfg.XLEN-1:0] wdata_i,
|
||||
|
||||
input rvfi_probes_csr_t csr_i,
|
||||
input logic [1:0] irq_i,
|
||||
|
||||
output rvfi_probes_t rvfi_probes_o
|
||||
);
|
||||
|
@ -63,7 +65,7 @@ module cva6_rvfi_probes
|
|||
instr = '0;
|
||||
|
||||
instr.flush = flush_i;
|
||||
instr.issue_instr_ack = issue_instr_ack_i[0];
|
||||
instr.issue_instr_ack = issue_instr_ack_i;
|
||||
instr.fetch_entry_valid = fetch_entry_valid_i;
|
||||
instr.instruction = instruction_i;
|
||||
instr.is_compressed = is_compressed_i;
|
||||
|
@ -74,8 +76,8 @@ module cva6_rvfi_probes
|
|||
instr.decoded_instr_valid = decoded_instr_valid_i;
|
||||
instr.decoded_instr_ack = decoded_instr_ack_i;
|
||||
|
||||
instr.rs1_forwarding = rs1_forwarding_i;
|
||||
instr.rs2_forwarding = rs2_forwarding_i;
|
||||
instr.rs1 = rs1_i;
|
||||
instr.rs2 = rs2_i;
|
||||
|
||||
instr.ex_commit_cause = ex_commit_i.cause;
|
||||
instr.ex_commit_valid = ex_commit_i.valid;
|
||||
|
@ -103,10 +105,12 @@ module cva6_rvfi_probes
|
|||
instr.commit_instr_valid[i] = commit_instr_i[i].valid;
|
||||
end
|
||||
|
||||
instr.commit_drop = commit_drop_i;
|
||||
instr.commit_ack = commit_ack_i;
|
||||
instr.wdata = wdata_i;
|
||||
|
||||
csr = csr_i;
|
||||
csr.mip_q = csr_i.mip_q | ({{CVA6Cfg.XLEN - 1{1'b0}}, CVA6Cfg.RVS && irq_i[1]} << riscv::IRQ_S_EXT);
|
||||
|
||||
end
|
||||
|
||||
|
|
66
core/cvxif_compressed_if_driver.sv
Normal file
66
core/cvxif_compressed_if_driver.sv
Normal file
|
@ -0,0 +1,66 @@
|
|||
// Copyright 2024 Thales DIS France SAS
|
||||
//
|
||||
// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0
|
||||
// You may obtain a copy of the License at https://solderpad.org/licenses/
|
||||
//
|
||||
// Original Author: Guillaume Chauvon
|
||||
|
||||
module cvxif_compressed_if_driver #(
|
||||
parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty,
|
||||
parameter type x_compressed_req_t = logic,
|
||||
parameter type x_compressed_resp_t = logic
|
||||
) (
|
||||
// Subsystem Clock - SUBSYSTEM
|
||||
input logic clk_i,
|
||||
// Asynchronous reset active low - SUBSYSTEM
|
||||
input logic rst_ni,
|
||||
input logic flush_i,
|
||||
// CVA6 Hart id
|
||||
input logic [CVA6Cfg.XLEN-1:0] hart_id_i,
|
||||
|
||||
input logic is_compressed_i,
|
||||
input logic is_illegal_i,
|
||||
input logic [31:0] instruction_i,
|
||||
|
||||
output logic is_compressed_o,
|
||||
output logic is_illegal_o,
|
||||
output logic [31:0] instruction_o,
|
||||
input logic stall_i,
|
||||
output logic stall_o,
|
||||
// CVXIF Compressed interface
|
||||
input logic compressed_ready_i,
|
||||
input x_compressed_resp_t compressed_resp_i,
|
||||
output logic compressed_valid_o,
|
||||
output x_compressed_req_t compressed_req_o
|
||||
);
|
||||
|
||||
|
||||
always_comb begin
|
||||
is_illegal_o = is_illegal_i;
|
||||
instruction_o = instruction_i;
|
||||
is_compressed_o = is_compressed_i;
|
||||
compressed_valid_o = 1'b0;
|
||||
compressed_req_o.instr = '0;
|
||||
compressed_req_o.hartid = hart_id_i;
|
||||
stall_o = stall_i;
|
||||
if (is_illegal_i) begin
|
||||
compressed_valid_o = is_illegal_i;
|
||||
compressed_req_o.instr = instruction_i[15:0];
|
||||
is_illegal_o = ~compressed_resp_i.accept;
|
||||
instruction_o = compressed_resp_i.accept ? compressed_resp_i.instr : instruction_i;
|
||||
is_compressed_o = compressed_resp_i.accept ? 1'b0 : is_compressed_i;
|
||||
if (~stall_i) begin
|
||||
// Propagate stall from macro decoder or wait for compressed ready if compressed transaction is happening.
|
||||
stall_o = (compressed_valid_o && ~compressed_ready_i);
|
||||
end
|
||||
end
|
||||
if (flush_i) begin
|
||||
compressed_valid_o = 1'b0;
|
||||
compressed_req_o.instr = '0;
|
||||
compressed_req_o.hartid = hart_id_i;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
49
core/cvxif_example/compressed_instr_decoder.sv
Normal file
49
core/cvxif_example/compressed_instr_decoder.sv
Normal file
|
@ -0,0 +1,49 @@
|
|||
// Copyright 2024 Thales DIS France SAS
|
||||
//
|
||||
// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0
|
||||
// You may obtain a copy of the License at https://solderpad.org/licenses/
|
||||
//
|
||||
// Original Author: Guillaume Chauvon
|
||||
|
||||
module compressed_instr_decoder #(
|
||||
parameter type copro_compressed_resp_t = logic,
|
||||
parameter int NbInstr = 1,
|
||||
parameter copro_compressed_resp_t CoproInstr [NbInstr] = {0},
|
||||
parameter type x_compressed_req_t = logic,
|
||||
parameter type x_compressed_resp_t = logic
|
||||
) (
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
input logic compressed_valid_i,
|
||||
input x_compressed_req_t compressed_req_i,
|
||||
output logic compressed_ready_o,
|
||||
output x_compressed_resp_t compressed_resp_o
|
||||
);
|
||||
|
||||
logic [NbInstr-1:0] sel;
|
||||
|
||||
for (genvar i = 0; i < NbInstr; i++) begin : gen_predecoder_selector
|
||||
assign sel[i] = ((CoproInstr[i].mask & compressed_req_i.instr) == CoproInstr[i].instr);
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
compressed_ready_o = '1;
|
||||
compressed_resp_o.accept = '0;
|
||||
compressed_resp_o.instr = '0;
|
||||
for (int unsigned i = 0; i < NbInstr; i++) begin
|
||||
if (sel[i] && compressed_valid_i) begin
|
||||
compressed_resp_o.accept = CoproInstr[i].resp.accept;
|
||||
compressed_resp_o.instr = CoproInstr[i].resp.instr;
|
||||
// Remap rs1 and rs2
|
||||
compressed_resp_o.instr[19:15] = compressed_req_i.instr[11:7];
|
||||
compressed_resp_o.instr[24:20] = compressed_req_i.instr[6:2];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assert property (@(posedge clk_i) $onehot0(sel))
|
||||
else $warning("This offloaded instruction is valid for multiple coprocessor instructions !");
|
||||
|
||||
endmodule
|
160
core/cvxif_example/copro_alu.sv
Normal file
160
core/cvxif_example/copro_alu.sv
Normal file
|
@ -0,0 +1,160 @@
|
|||
// Copyright 2024 Thales DIS France SAS
|
||||
//
|
||||
// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0
|
||||
// You may obtain a copy of the License at https://solderpad.org/licenses/
|
||||
//
|
||||
// Original Author: Guillaume Chauvon
|
||||
|
||||
module copro_alu
|
||||
import cvxif_instr_pkg::*;
|
||||
#(
|
||||
parameter int unsigned NrRgprPorts = 2,
|
||||
parameter int unsigned XLEN = 32,
|
||||
parameter type hartid_t = logic,
|
||||
parameter type id_t = logic,
|
||||
parameter type registers_t = logic
|
||||
|
||||
) (
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
input registers_t registers_i,
|
||||
input opcode_t opcode_i,
|
||||
input hartid_t hartid_i,
|
||||
input id_t id_i,
|
||||
input logic [ 4:0] rd_i,
|
||||
output logic [XLEN-1:0] result_o,
|
||||
output hartid_t hartid_o,
|
||||
output id_t id_o,
|
||||
output logic [ 4:0] rd_o,
|
||||
output logic valid_o,
|
||||
output logic we_o
|
||||
);
|
||||
|
||||
logic [XLEN-1:0] result_n, result_q;
|
||||
hartid_t hartid_n, hartid_q;
|
||||
id_t id_n, id_q;
|
||||
logic valid_n, valid_q;
|
||||
logic [4:0] rd_n, rd_q;
|
||||
logic we_n, we_q;
|
||||
|
||||
assign result_o = result_q;
|
||||
assign hartid_o = hartid_q;
|
||||
assign id_o = id_q;
|
||||
assign valid_o = valid_q;
|
||||
assign rd_o = rd_q;
|
||||
assign we_o = we_q;
|
||||
|
||||
always_comb begin
|
||||
case (opcode_i)
|
||||
cvxif_instr_pkg::NOP: begin
|
||||
result_n = '0;
|
||||
hartid_n = hartid_i;
|
||||
id_n = id_i;
|
||||
valid_n = 1'b1;
|
||||
rd_n = '0;
|
||||
we_n = '0;
|
||||
end
|
||||
cvxif_instr_pkg::ADD: begin
|
||||
result_n = registers_i[1] + registers_i[0];
|
||||
hartid_n = hartid_i;
|
||||
id_n = id_i;
|
||||
valid_n = 1'b1;
|
||||
rd_n = rd_i;
|
||||
we_n = 1'b1;
|
||||
end
|
||||
cvxif_instr_pkg::DOUBLE_RS1: begin
|
||||
result_n = registers_i[0] + registers_i[0];
|
||||
hartid_n = hartid_i;
|
||||
id_n = id_i;
|
||||
valid_n = 1'b1;
|
||||
rd_n = rd_i;
|
||||
we_n = 1'b1;
|
||||
end
|
||||
cvxif_instr_pkg::DOUBLE_RS2: begin
|
||||
result_n = registers_i[1] + registers_i[1];
|
||||
hartid_n = hartid_i;
|
||||
id_n = id_i;
|
||||
valid_n = 1'b1;
|
||||
rd_n = rd_i;
|
||||
we_n = 1'b1;
|
||||
end
|
||||
cvxif_instr_pkg::ADD_MULTI: begin
|
||||
result_n = registers_i[1] + registers_i[0];
|
||||
hartid_n = hartid_i;
|
||||
id_n = id_i;
|
||||
valid_n = 1'b1;
|
||||
rd_n = rd_i;
|
||||
we_n = 1'b1;
|
||||
end
|
||||
cvxif_instr_pkg::MADD_RS3_R4: begin
|
||||
result_n = NrRgprPorts == 3 ? (registers_i[0] + registers_i[1] + registers_i[2]) : (registers_i[0] + registers_i[1]);
|
||||
hartid_n = hartid_i;
|
||||
id_n = id_i;
|
||||
valid_n = 1'b1;
|
||||
rd_n = rd_i;
|
||||
we_n = 1'b1;
|
||||
end
|
||||
cvxif_instr_pkg::MSUB_RS3_R4: begin
|
||||
result_n = NrRgprPorts == 3 ? (registers_i[0] - registers_i[1] - registers_i[2]) : (registers_i[0] - registers_i[1]);
|
||||
hartid_n = hartid_i;
|
||||
id_n = id_i;
|
||||
valid_n = 1'b1;
|
||||
rd_n = rd_i;
|
||||
we_n = 1'b1;
|
||||
end
|
||||
cvxif_instr_pkg::NMADD_RS3_R4: begin
|
||||
result_n = NrRgprPorts == 3 ? ~(registers_i[0] + registers_i[1] + registers_i[2]) : ~(registers_i[0] + registers_i[1]);
|
||||
hartid_n = hartid_i;
|
||||
id_n = id_i;
|
||||
valid_n = 1'b1;
|
||||
rd_n = rd_i;
|
||||
we_n = 1'b1;
|
||||
end
|
||||
cvxif_instr_pkg::NMSUB_RS3_R4: begin
|
||||
result_n = NrRgprPorts == 3 ? ~(registers_i[0] - registers_i[1] - registers_i[2]) : ~(registers_i[0] - registers_i[1]);
|
||||
hartid_n = hartid_i;
|
||||
id_n = id_i;
|
||||
valid_n = 1'b1;
|
||||
rd_n = rd_i;
|
||||
we_n = 1'b1;
|
||||
end
|
||||
cvxif_instr_pkg::ADD_RS3_R: begin
|
||||
result_n = NrRgprPorts == 3 ? registers_i[2] + registers_i[1] + registers_i[0] : registers_i[1] + registers_i[0];
|
||||
hartid_n = hartid_i;
|
||||
id_n = id_i;
|
||||
valid_n = 1'b1;
|
||||
rd_n = 5'b01010;
|
||||
we_n = 1'b1;
|
||||
end
|
||||
default: begin
|
||||
result_n = '0;
|
||||
hartid_n = '0;
|
||||
id_n = '0;
|
||||
valid_n = '0;
|
||||
rd_n = '0;
|
||||
we_n = '0;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_i, negedge rst_ni) begin
|
||||
if (~rst_ni) begin
|
||||
result_q <= '0;
|
||||
hartid_q <= '0;
|
||||
id_q <= '0;
|
||||
valid_q <= '0;
|
||||
rd_q <= '0;
|
||||
we_q <= '0;
|
||||
end else begin
|
||||
result_q <= result_n;
|
||||
hartid_q <= hartid_n;
|
||||
id_q <= id_n;
|
||||
valid_q <= valid_n;
|
||||
rd_q <= rd_n;
|
||||
we_q <= we_n;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
|
@ -1,19 +1,32 @@
|
|||
// Copyright 2021 Thales DIS design services SAS
|
||||
// Copyright 2024 Thales DIS France SAS
|
||||
//
|
||||
// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0
|
||||
// You may obtain a copy of the License at https://solderpad.org/licenses/
|
||||
//
|
||||
// Original Author: Guillaume Chauvon (guillaume.chauvon@thalesgroup.com)
|
||||
// Example coprocessor adds rs1,rs2(,rs3) together and gives back the result to the CPU via the CoreV-X-Interface.
|
||||
// Coprocessor delays the sending of the result depending on result least significant bits.
|
||||
// Original Author: Guillaume Chauvon
|
||||
|
||||
module cvxif_example_coprocessor
|
||||
import cvxif_pkg::*;
|
||||
import cvxif_instr_pkg::*;
|
||||
#(
|
||||
parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty
|
||||
// CVXIF Types
|
||||
parameter int unsigned NrRgprPorts = 2,
|
||||
parameter int unsigned XLEN = 32,
|
||||
parameter type readregflags_t = logic,
|
||||
parameter type writeregflags_t = logic,
|
||||
parameter type id_t = logic,
|
||||
parameter type hartid_t = logic,
|
||||
parameter type x_compressed_req_t = logic,
|
||||
parameter type x_compressed_resp_t = logic,
|
||||
parameter type x_issue_req_t = logic,
|
||||
parameter type x_issue_resp_t = logic,
|
||||
parameter type x_register_t = logic,
|
||||
parameter type x_commit_t = logic,
|
||||
parameter type x_result_t = logic,
|
||||
parameter type cvxif_req_t = logic,
|
||||
parameter type cvxif_resp_t = logic,
|
||||
localparam type registers_t = logic [NrRgprPorts-1:0][XLEN-1:0]
|
||||
) (
|
||||
input logic clk_i, // Clock
|
||||
input logic rst_ni, // Asynchronous reset active low
|
||||
|
@ -21,138 +34,119 @@ module cvxif_example_coprocessor
|
|||
output cvxif_resp_t cvxif_resp_o
|
||||
);
|
||||
|
||||
//Compressed interface
|
||||
logic x_compressed_valid_i;
|
||||
logic x_compressed_ready_o;
|
||||
x_compressed_req_t x_compressed_req_i;
|
||||
x_compressed_resp_t x_compressed_resp_o;
|
||||
//Issue interface
|
||||
logic x_issue_valid_i;
|
||||
logic x_issue_ready_o;
|
||||
x_issue_req_t x_issue_req_i;
|
||||
x_issue_resp_t x_issue_resp_o;
|
||||
//Commit interface
|
||||
logic x_commit_valid_i;
|
||||
x_commit_t x_commit_i;
|
||||
//Memory interface
|
||||
logic x_mem_valid_o;
|
||||
logic x_mem_ready_i;
|
||||
x_mem_req_t x_mem_req_o;
|
||||
x_mem_resp_t x_mem_resp_i;
|
||||
//Memory result interface
|
||||
logic x_mem_result_valid_i;
|
||||
x_mem_result_t x_mem_result_i;
|
||||
//Result interface
|
||||
logic x_result_valid_o;
|
||||
logic x_result_ready_i;
|
||||
x_result_t x_result_o;
|
||||
// Compressed interface signals
|
||||
x_compressed_req_t compressed_req;
|
||||
x_compressed_resp_t compressed_resp;
|
||||
logic compressed_valid, compressed_ready;
|
||||
// Issue interface signals
|
||||
x_issue_req_t issue_req;
|
||||
x_issue_resp_t issue_resp;
|
||||
logic issue_valid, issue_ready;
|
||||
|
||||
assign x_compressed_valid_i = cvxif_req_i.x_compressed_valid;
|
||||
assign x_compressed_req_i = cvxif_req_i.x_compressed_req;
|
||||
assign x_issue_valid_i = cvxif_req_i.x_issue_valid;
|
||||
assign x_issue_req_i = cvxif_req_i.x_issue_req;
|
||||
assign x_commit_valid_i = cvxif_req_i.x_commit_valid;
|
||||
assign x_commit_i = cvxif_req_i.x_commit;
|
||||
assign x_mem_ready_i = cvxif_req_i.x_mem_ready;
|
||||
assign x_mem_resp_i = cvxif_req_i.x_mem_resp;
|
||||
assign x_mem_result_valid_i = cvxif_req_i.x_mem_result_valid;
|
||||
assign x_mem_result_i = cvxif_req_i.x_mem_result;
|
||||
assign x_result_ready_i = cvxif_req_i.x_result_ready;
|
||||
// Register interface signals
|
||||
x_register_t register;
|
||||
logic register_valid;
|
||||
|
||||
assign cvxif_resp_o.x_compressed_ready = x_compressed_ready_o;
|
||||
assign cvxif_resp_o.x_compressed_resp = x_compressed_resp_o;
|
||||
assign cvxif_resp_o.x_issue_ready = x_issue_ready_o;
|
||||
assign cvxif_resp_o.x_issue_resp = x_issue_resp_o;
|
||||
assign cvxif_resp_o.x_mem_valid = x_mem_valid_o;
|
||||
assign cvxif_resp_o.x_mem_req = x_mem_req_o;
|
||||
assign cvxif_resp_o.x_result_valid = x_result_valid_o;
|
||||
assign cvxif_resp_o.x_result = x_result_o;
|
||||
// Decoder and alu signals
|
||||
registers_t registers;
|
||||
opcode_t opcode;
|
||||
hartid_t issue_hartid, hartid;
|
||||
id_t issue_id, id;
|
||||
logic [4:0] issue_rd, rd;
|
||||
logic [XLEN-1:0] result;
|
||||
logic we;
|
||||
|
||||
//Compressed interface
|
||||
assign x_compressed_ready_o = '0;
|
||||
assign x_compressed_resp_o.instr = '0;
|
||||
assign x_compressed_resp_o.accept = '0;
|
||||
// Issue and Register interface
|
||||
// Mandatory when X_ISSUE_REGISTER_SPLIT = 0
|
||||
assign cvxif_resp_o.compressed_ready = compressed_ready;
|
||||
assign cvxif_resp_o.compressed_resp = compressed_resp;
|
||||
assign cvxif_resp_o.issue_ready = issue_ready;
|
||||
assign cvxif_resp_o.issue_resp = issue_resp;
|
||||
assign cvxif_resp_o.register_ready = cvxif_resp_o.issue_ready;
|
||||
|
||||
assign compressed_req = cvxif_req_i.compressed_req;
|
||||
assign compressed_valid = cvxif_req_i.compressed_valid;
|
||||
assign issue_req = cvxif_req_i.issue_req;
|
||||
assign issue_valid = cvxif_req_i.issue_valid;
|
||||
assign register = cvxif_req_i.register;
|
||||
assign register_valid = cvxif_req_i.register_valid;
|
||||
|
||||
compressed_instr_decoder #(
|
||||
.copro_compressed_resp_t(cvxif_instr_pkg::copro_compressed_resp_t),
|
||||
.NbInstr(cvxif_instr_pkg::NbCompInstr),
|
||||
.CoproInstr(cvxif_instr_pkg::CoproCompInstr),
|
||||
.x_compressed_req_t(x_compressed_req_t),
|
||||
.x_compressed_resp_t(x_compressed_resp_t)
|
||||
) compressed_instr_decoder_i (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
.compressed_valid_i(compressed_valid),
|
||||
.compressed_req_i (compressed_req),
|
||||
.compressed_ready_o(compressed_ready),
|
||||
.compressed_resp_o (compressed_resp)
|
||||
);
|
||||
|
||||
instr_decoder #(
|
||||
.copro_issue_resp_t (cvxif_instr_pkg::copro_issue_resp_t),
|
||||
.opcode_t (cvxif_instr_pkg::opcode_t),
|
||||
.NbInstr (cvxif_instr_pkg::NbInstr),
|
||||
.CoproInstr(cvxif_instr_pkg::CoproInstr)
|
||||
.CoproInstr(cvxif_instr_pkg::CoproInstr),
|
||||
.NrRgprPorts(NrRgprPorts),
|
||||
.hartid_t (hartid_t),
|
||||
.id_t (id_t),
|
||||
.x_issue_req_t (x_issue_req_t),
|
||||
.x_issue_resp_t (x_issue_resp_t),
|
||||
.x_register_t (x_register_t),
|
||||
.registers_t (registers_t)
|
||||
) instr_decoder_i (
|
||||
.clk_i (clk_i),
|
||||
.x_issue_req_i (x_issue_req_i),
|
||||
.x_issue_resp_o(x_issue_resp_o)
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
.issue_valid_i (issue_valid),
|
||||
.issue_req_i (issue_req),
|
||||
.issue_ready_o (issue_ready),
|
||||
.issue_resp_o (issue_resp),
|
||||
.register_valid_i(register_valid),
|
||||
.register_i (register),
|
||||
.registers_o (registers),
|
||||
.opcode_o (opcode),
|
||||
.hartid_o (issue_hartid),
|
||||
.id_o (issue_id),
|
||||
.rd_o (issue_rd)
|
||||
);
|
||||
|
||||
typedef struct packed {
|
||||
x_issue_req_t req;
|
||||
x_issue_resp_t resp;
|
||||
} x_issue_t;
|
||||
|
||||
logic fifo_full, fifo_empty;
|
||||
logic x_issue_ready_q;
|
||||
logic instr_push, instr_pop;
|
||||
x_issue_t req_i;
|
||||
x_issue_t req_o;
|
||||
|
||||
|
||||
|
||||
assign instr_push = x_issue_resp_o.accept ? 1 : 0;
|
||||
assign instr_pop = (x_commit_i.x_commit_kill && x_commit_valid_i) || x_result_valid_o;
|
||||
assign x_issue_ready_q = ~fifo_full; // if something is in the fifo, the instruction is being processed
|
||||
// so we can't receive anything else
|
||||
assign req_i.req = x_issue_req_i;
|
||||
assign req_i.resp = x_issue_resp_o;
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin : regs
|
||||
if (!rst_ni) begin
|
||||
x_issue_ready_o <= 1;
|
||||
end else begin
|
||||
x_issue_ready_o <= x_issue_ready_q;
|
||||
end
|
||||
end
|
||||
|
||||
cva6_fifo_v3 #(
|
||||
.FALL_THROUGH(1), //data_o ready and pop in the same cycle
|
||||
.DATA_WIDTH (64),
|
||||
.DEPTH (8),
|
||||
.dtype (x_issue_t),
|
||||
.FPGA_EN (CVA6Cfg.FpgaEn)
|
||||
) fifo_commit_i (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
.flush_i (1'b0),
|
||||
.testmode_i(1'b0),
|
||||
.full_o (fifo_full),
|
||||
.empty_o (fifo_empty),
|
||||
.usage_o (),
|
||||
.data_i (req_i),
|
||||
.push_i (instr_push),
|
||||
.data_o (req_o),
|
||||
.pop_i (instr_pop)
|
||||
);
|
||||
|
||||
logic [3:0] c;
|
||||
counter #(
|
||||
.WIDTH(4)
|
||||
) counter_i (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
.clear_i (~x_commit_i.x_commit_kill && x_commit_valid_i),
|
||||
.en_i (1'b1),
|
||||
.load_i (),
|
||||
.down_i (),
|
||||
.d_i (),
|
||||
.q_o (c),
|
||||
.overflow_o()
|
||||
logic alu_valid;
|
||||
// Result interface
|
||||
copro_alu #(
|
||||
.NrRgprPorts(NrRgprPorts),
|
||||
.XLEN(XLEN),
|
||||
.hartid_t(hartid_t),
|
||||
.id_t(id_t),
|
||||
.registers_t(registers_t)
|
||||
) i_copro_alu (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
.registers_i(registers),
|
||||
.opcode_i (opcode),
|
||||
.hartid_i (issue_hartid),
|
||||
.id_i (issue_id),
|
||||
.rd_i (issue_rd),
|
||||
.hartid_o (hartid),
|
||||
.id_o (id),
|
||||
.result_o (result),
|
||||
.valid_o (alu_valid),
|
||||
.rd_o (rd),
|
||||
.we_o (we)
|
||||
);
|
||||
|
||||
always_comb begin
|
||||
x_result_o.data = req_o.req.rs[0] + req_o.req.rs[1] + (X_NUM_RS == 3 ? req_o.req.rs[2] : 0);
|
||||
x_result_valid_o = (c == x_result_o.data[3:0]) && ~fifo_empty ? 1 : 0;
|
||||
x_result_o.id = req_o.req.id;
|
||||
x_result_o.rd = req_o.req.instr[11:7];
|
||||
x_result_o.we = req_o.resp.writeback & x_result_valid_o;
|
||||
x_result_o.exc = 0;
|
||||
x_result_o.exccode = 0;
|
||||
cvxif_resp_o.result_valid = alu_valid; //TODO Should wait for ready from CPU
|
||||
cvxif_resp_o.result.hartid = hartid;
|
||||
cvxif_resp_o.result.id = id;
|
||||
cvxif_resp_o.result.data = result;
|
||||
cvxif_resp_o.result.rd = rd;
|
||||
cvxif_resp_o.result.we = we;
|
||||
end
|
||||
|
||||
|
||||
|
||||
endmodule
|
||||
|
|
|
@ -7,40 +7,147 @@
|
|||
//
|
||||
// Original Author: Guillaume Chauvon (guillaume.chauvon@thalesgroup.com)
|
||||
|
||||
|
||||
|
||||
package cvxif_instr_pkg;
|
||||
|
||||
typedef enum logic [3:0] {
|
||||
ILLEGAL = 4'b0000,
|
||||
NOP = 4'b0001,
|
||||
ADD = 4'b0010,
|
||||
DOUBLE_RS1 = 4'b0011,
|
||||
DOUBLE_RS2 = 4'b0100,
|
||||
ADD_MULTI = 4'b0101,
|
||||
MADD_RS3_R4 = 4'b0110,
|
||||
MSUB_RS3_R4 = 4'b0111,
|
||||
NMADD_RS3_R4 = 4'b1000,
|
||||
NMSUB_RS3_R4 = 4'b1001,
|
||||
ADD_RS3_R = 4'b1111
|
||||
} opcode_t;
|
||||
|
||||
|
||||
typedef struct packed {
|
||||
logic [31:0] instr;
|
||||
logic [31:0] mask;
|
||||
cvxif_pkg::x_issue_resp_t resp;
|
||||
logic accept;
|
||||
logic writeback; // TODO depends on dualwrite
|
||||
logic [2:0] register_read; // TODO Nr read ports
|
||||
} issue_resp_t;
|
||||
|
||||
typedef struct packed {
|
||||
logic accept;
|
||||
logic [31:0] instr;
|
||||
} compressed_resp_t;
|
||||
|
||||
typedef struct packed {
|
||||
logic [31:0] instr;
|
||||
logic [31:0] mask;
|
||||
issue_resp_t resp;
|
||||
opcode_t opcode;
|
||||
} copro_issue_resp_t;
|
||||
|
||||
// 2 Possible RISCV instructions for Coprocessor
|
||||
parameter int unsigned NbInstr = 2;
|
||||
|
||||
typedef struct packed {
|
||||
logic [15:0] instr;
|
||||
logic [15:0] mask;
|
||||
compressed_resp_t resp;
|
||||
} copro_compressed_resp_t;
|
||||
|
||||
// 4 Possible RISCV instructions for Coprocessor
|
||||
parameter int unsigned NbInstr = 10;
|
||||
parameter copro_issue_resp_t CoproInstr[NbInstr] = '{
|
||||
'{
|
||||
instr: 32'b00000_00_00000_00000_0_00_00000_0101011, // custom1 opcode
|
||||
mask: 32'b00000_00_00000_00000_0_00_00000_1111111,
|
||||
resp : '{
|
||||
accept : 1'b1,
|
||||
writeback : 1'b0,
|
||||
dualwrite : 1'b0,
|
||||
dualread : 1'b0,
|
||||
loadstore : 1'b0,
|
||||
exc : 1'b0
|
||||
}
|
||||
// Custom Nop
|
||||
instr:
|
||||
32'b00000_00_00000_00000_0_00_00000_1111011, // custom3 opcode
|
||||
mask: 32'b11111_11_00000_00000_1_11_00000_1111111,
|
||||
resp : '{accept : 1'b1, writeback : 1'b0, register_read : {1'b0, 1'b0, 1'b0}},
|
||||
opcode : NOP
|
||||
},
|
||||
'{
|
||||
instr: 32'b00000_00_00000_00000_0_00_00000_1011011, // custom2 opcode
|
||||
mask: 32'b00000_00_00000_00000_0_00_00000_1111111,
|
||||
resp : '{
|
||||
accept : 1'b1,
|
||||
writeback : 1'b1,
|
||||
dualwrite : 1'b0,
|
||||
dualread : 1'b0,
|
||||
loadstore : 1'b0,
|
||||
exc : 1'b0
|
||||
}
|
||||
// Custom Add : cus_add rd, rs1, rs2
|
||||
instr:
|
||||
32'b00000_00_00000_00000_0_01_00000_1111011, // custom3 opcode
|
||||
mask: 32'b11111_11_00000_00000_1_11_00000_1111111,
|
||||
resp : '{accept : 1'b1, writeback : 1'b1, register_read : {1'b0, 1'b1, 1'b1}},
|
||||
opcode : ADD
|
||||
},
|
||||
'{
|
||||
// Custom Add rs1 : cus_add rd, rs1, rs1
|
||||
instr:
|
||||
32'b00000_01_00000_00000_0_01_00000_1111011, // custom3 opcode
|
||||
mask: 32'b11111_11_00000_00000_1_11_00000_1111111,
|
||||
resp : '{accept : 1'b1, writeback : 1'b1, register_read : {1'b0, 1'b0, 1'b1}},
|
||||
opcode : DOUBLE_RS1
|
||||
},
|
||||
'{
|
||||
// Custom Add rs2 : cus_add rd, rs2, rs2
|
||||
instr:
|
||||
32'b00000_10_00000_00000_0_01_00000_1111011, // custom3 opcode
|
||||
mask: 32'b11111_11_00000_00000_1_11_00000_1111111,
|
||||
resp : '{accept : 1'b1, writeback : 1'b1, register_read : {1'b0, 1'b1, 1'b0}},
|
||||
opcode : DOUBLE_RS2
|
||||
},
|
||||
'{
|
||||
// Custom Add Multi rs1 : cus_add rd, rs1, rs1
|
||||
instr:
|
||||
32'b00000_11_00000_00000_0_01_00000_1111011, // custom3 opcode
|
||||
mask: 32'b11111_11_00000_00000_1_11_00000_1111111,
|
||||
resp : '{accept : 1'b1, writeback : 1'b1, register_read : {1'b0, 1'b1, 1'b1}},
|
||||
opcode : ADD_MULTI
|
||||
},
|
||||
'{
|
||||
// Custom Add Multi rs1 : cus_add rd, rs1, rs1
|
||||
instr:
|
||||
32'b00001_00_00000_00000_0_01_00000_1111011, // custom3 opcode
|
||||
mask: 32'b11111_11_00000_00000_1_11_00000_1111111,
|
||||
resp : '{accept : 1'b1, writeback : 1'b1, register_read : {1'b1, 1'b1, 1'b1}},
|
||||
opcode : ADD_RS3_R
|
||||
},
|
||||
'{
|
||||
// Custom Add Multi rs1 : cus_add rd, rs1, rs1
|
||||
instr:
|
||||
32'b00000_00_00000_00000_0_00_00000_1000011, // MADD opcode
|
||||
mask: 32'b00000_11_00000_00000_1_11_00000_1111111,
|
||||
resp : '{accept : 1'b1, writeback : 1'b1, register_read : {1'b1, 1'b1, 1'b1}},
|
||||
opcode : MADD_RS3_R4
|
||||
},
|
||||
'{
|
||||
// Custom Add Multi rs1 : cus_add rd, rs1, rs1
|
||||
instr:
|
||||
32'b00000_00_00000_00000_0_00_00000_1000111, // MSUB opcode
|
||||
mask: 32'b00000_11_00000_00000_1_11_00000_1111111,
|
||||
resp : '{accept : 1'b1, writeback : 1'b1, register_read : {1'b1, 1'b1, 1'b1}},
|
||||
opcode : MSUB_RS3_R4
|
||||
},
|
||||
'{
|
||||
// Custom Add Multi rs1 : cus_add rd, rs1, rs1
|
||||
instr:
|
||||
32'b00000_00_00000_00000_0_00_00000_1001011, // NMSUB opcode
|
||||
mask: 32'b00000_11_00000_00000_1_11_00000_1111111,
|
||||
resp : '{accept : 1'b1, writeback : 1'b1, register_read : {1'b1, 1'b1, 1'b1}},
|
||||
opcode : NMSUB_RS3_R4
|
||||
},
|
||||
'{
|
||||
// Custom Add Multi rs1 : cus_add rd, rs1, rs1
|
||||
instr:
|
||||
32'b00000_00_00000_00000_0_00_00000_1001111, // NMADD opcode
|
||||
mask: 32'b00000_11_00000_00000_1_11_00000_1111111,
|
||||
resp : '{accept : 1'b1, writeback : 1'b1, register_read : {1'b1, 1'b1, 1'b1}},
|
||||
opcode : NMADD_RS3_R4
|
||||
}
|
||||
};
|
||||
|
||||
parameter int unsigned NbCompInstr = 2;
|
||||
parameter copro_compressed_resp_t CoproCompInstr[NbCompInstr] = '{
|
||||
// C_NOP
|
||||
'{
|
||||
instr : 16'b111_0_00000_00000_00,
|
||||
mask : 16'b111_1_00000_00000_11,
|
||||
resp : '{accept : 1'b1, instr : 32'b00000_00_00000_00000_0_00_00000_1111011}
|
||||
},
|
||||
'{
|
||||
instr : 16'b111_1_00000_00000_00,
|
||||
mask : 16'b111_1_00000_00000_11,
|
||||
resp : '{accept : 1'b1, instr : 32'b00000_00_00000_00000_0_01_01010_1111011}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,46 +1,86 @@
|
|||
// Copyright 2021 Thales DIS design services SAS
|
||||
// Copyright 2024 Thales DIS France SAS
|
||||
//
|
||||
// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0
|
||||
// You may obtain a copy of the License at https://solderpad.org/licenses/
|
||||
//
|
||||
// Original Author: Guillaume Chauvon (guillaume.chauvon@thalesgroup.com)
|
||||
// Original Author: Guillaume Chauvon
|
||||
|
||||
module instr_decoder
|
||||
import cvxif_pkg::*;
|
||||
#(
|
||||
parameter int NbInstr = 1,
|
||||
parameter cvxif_instr_pkg::copro_issue_resp_t CoproInstr[NbInstr] = {0}
|
||||
module instr_decoder #(
|
||||
parameter type copro_issue_resp_t = logic,
|
||||
parameter type opcode_t = logic,
|
||||
parameter int NbInstr = 1,
|
||||
parameter copro_issue_resp_t CoproInstr [NbInstr] = {0},
|
||||
parameter int unsigned NrRgprPorts = 2,
|
||||
parameter type hartid_t = logic,
|
||||
parameter type id_t = logic,
|
||||
parameter type x_issue_req_t = logic,
|
||||
parameter type x_issue_resp_t = logic,
|
||||
parameter type x_register_t = logic,
|
||||
parameter type registers_t = logic
|
||||
) (
|
||||
input logic clk_i,
|
||||
input x_issue_req_t x_issue_req_i,
|
||||
output x_issue_resp_t x_issue_resp_o
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
input logic issue_valid_i,
|
||||
input x_issue_req_t issue_req_i,
|
||||
output logic issue_ready_o,
|
||||
output x_issue_resp_t issue_resp_o,
|
||||
input logic register_valid_i,
|
||||
input x_register_t register_i,
|
||||
output registers_t registers_o,
|
||||
output opcode_t opcode_o,
|
||||
output hartid_t hartid_o,
|
||||
output id_t id_o,
|
||||
output logic [4:0] rd_o
|
||||
);
|
||||
|
||||
logic [NbInstr-1:0] sel;
|
||||
logic rs1_ready;
|
||||
logic rs2_ready;
|
||||
logic rs3_ready;
|
||||
|
||||
for (genvar i = 0; i < NbInstr; i++) begin : gen_predecoder_selector
|
||||
assign sel[i] = ((CoproInstr[i].mask & x_issue_req_i.instr) == CoproInstr[i].instr);
|
||||
assign sel[i] = ((CoproInstr[i].mask & issue_req_i.instr) == CoproInstr[i].instr);
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
x_issue_resp_o.accept = '0;
|
||||
x_issue_resp_o.writeback = '0;
|
||||
x_issue_resp_o.dualwrite = '0;
|
||||
x_issue_resp_o.dualread = '0;
|
||||
x_issue_resp_o.loadstore = '0;
|
||||
x_issue_resp_o.exc = '0;
|
||||
rs1_ready = '0;
|
||||
rs2_ready = '0;
|
||||
rs3_ready = '0;
|
||||
issue_ready_o = '0;
|
||||
issue_resp_o.accept = '0;
|
||||
issue_resp_o.writeback = '0;
|
||||
issue_resp_o.register_read = '0;
|
||||
registers_o = '0;
|
||||
opcode_o = opcode_t'(0); // == ILLEGAL see cvxif_instr_pkg.sv
|
||||
hartid_o = '0;
|
||||
id_o = '0;
|
||||
rd_o = '0;
|
||||
for (int unsigned i = 0; i < NbInstr; i++) begin
|
||||
if (sel[i]) begin
|
||||
x_issue_resp_o.accept = CoproInstr[i].resp.accept;
|
||||
x_issue_resp_o.writeback = CoproInstr[i].resp.writeback;
|
||||
x_issue_resp_o.dualwrite = CoproInstr[i].resp.dualwrite;
|
||||
x_issue_resp_o.dualread = CoproInstr[i].resp.dualread;
|
||||
x_issue_resp_o.loadstore = CoproInstr[i].resp.loadstore;
|
||||
x_issue_resp_o.exc = CoproInstr[i].resp.exc;
|
||||
if (sel[i] && issue_valid_i) begin
|
||||
issue_resp_o.accept = CoproInstr[i].resp.accept;
|
||||
issue_resp_o.writeback = CoproInstr[i].resp.writeback;
|
||||
issue_resp_o.register_read = CoproInstr[i].resp.register_read; // Warning : potential 3 bits vector into 2 bits one
|
||||
if (issue_resp_o.accept) begin
|
||||
rs1_ready = (~CoproInstr[i].resp.register_read[0] || register_i.rs_valid[0]);
|
||||
rs2_ready = (~CoproInstr[i].resp.register_read[1] || register_i.rs_valid[1]);
|
||||
rs3_ready = NrRgprPorts == 3 ? (~CoproInstr[i].resp.register_read[2] || register_i.rs_valid[2]) : 1'b1;
|
||||
issue_ready_o = rs1_ready && rs2_ready && rs3_ready;
|
||||
end
|
||||
opcode_o = CoproInstr[i].opcode;
|
||||
id_o = issue_req_i.id;
|
||||
hartid_o = issue_req_i.hartid;
|
||||
rd_o = issue_req_i.instr[11:7];
|
||||
for (int unsigned j = 0; j < NrRgprPorts; j++) begin
|
||||
registers_o[j] = issue_resp_o.register_read[j] ? register_i.rs[j] : '0;
|
||||
end
|
||||
end
|
||||
end
|
||||
// Coprocessor could not decode offloaded instruction -> instruction is not accepted
|
||||
if (issue_valid_i && ~(|sel)) begin
|
||||
issue_ready_o = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
assert property (@(posedge clk_i) $onehot0(sel))
|
||||
|
|
146
core/cvxif_fu.sv
146
core/cvxif_fu.sv
|
@ -1,13 +1,14 @@
|
|||
// Copyright 2021 Thales DIS design services SAS
|
||||
// Copyright 2024 Thales DIS France SAS
|
||||
//
|
||||
// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0
|
||||
// You may obtain a copy of the License at https://solderpad.org/licenses/
|
||||
//
|
||||
// Original Author: Guillaume CHAUVON (guillaume.chauvon@thalesgroup.com)
|
||||
// Original Author: Guillaume Chauvon
|
||||
|
||||
// Functional Unit for the logic of the CoreV-X-Interface
|
||||
// Functional Unit for the CoreV-X-Interface
|
||||
// Handles Result interface and exception forwarding to next stages.
|
||||
|
||||
|
||||
module cvxif_fu
|
||||
|
@ -15,117 +16,64 @@ module cvxif_fu
|
|||
#(
|
||||
parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty,
|
||||
parameter type exception_t = logic,
|
||||
parameter type fu_data_t = logic
|
||||
parameter type x_result_t = logic
|
||||
) (
|
||||
// Subsystem Clock - SUBSYSTEM
|
||||
input logic clk_i,
|
||||
input logic clk_i,
|
||||
// Asynchronous reset active low - SUBSYSTEM
|
||||
input logic rst_ni,
|
||||
// FU data needed to execute instruction - ISSUE_STAGE
|
||||
input fu_data_t fu_data_i,
|
||||
// Current privilege mode - CSR_REGFILE
|
||||
input riscv::priv_lvl_t priv_lvl_i,
|
||||
input logic rst_ni,
|
||||
// Virtualization mode state - CSR_REGFILE
|
||||
input logic v_i,
|
||||
// CVXIF instruction is valid - ISSUE_STAGE
|
||||
input logic x_valid_i,
|
||||
// CVXIF is ready - ISSUE_STAGE
|
||||
output logic x_ready_o,
|
||||
input logic x_valid_i,
|
||||
// Transaction ID - ISSUE_STAGE
|
||||
input logic [CVA6Cfg.TRANS_ID_BITS-1:0] x_trans_id_i,
|
||||
// Instruction is illegal, determined during CVXIF issue transaction - ISSUE_STAGE
|
||||
input logic x_illegal_i,
|
||||
// Offloaded instruction - ISSUE_STAGE
|
||||
input logic [ 31:0] x_off_instr_i,
|
||||
// CVXIF transaction ID - ISSUE_STAGE
|
||||
output logic [CVA6Cfg.TRANS_ID_BITS-1:0] x_trans_id_o,
|
||||
input logic [ 31:0] x_off_instr_i,
|
||||
// CVXIF is ready - ISSUE_STAGE
|
||||
output logic x_ready_o,
|
||||
// CVXIF result transaction ID - ISSUE_STAGE
|
||||
output logic [CVA6Cfg.TRANS_ID_BITS-1:0] x_trans_id_o,
|
||||
// CVXIF exception - ISSUE_STAGE
|
||||
output exception_t x_exception_o,
|
||||
output exception_t x_exception_o,
|
||||
// CVXIF FU result - ISSUE_STAGE
|
||||
output logic [ CVA6Cfg.XLEN-1:0] x_result_o,
|
||||
output logic [ CVA6Cfg.XLEN-1:0] x_result_o,
|
||||
// CVXIF result valid - ISSUE_STAGE
|
||||
output logic x_valid_o,
|
||||
output logic x_valid_o,
|
||||
// CVXIF write enable - ISSUE_STAGE
|
||||
output logic x_we_o,
|
||||
// CVXIF request - SUBSYSTEM
|
||||
output cvxif_pkg::cvxif_req_t cvxif_req_o,
|
||||
// CVXIF response - SUBSYSTEM
|
||||
input cvxif_pkg::cvxif_resp_t cvxif_resp_i
|
||||
output logic x_we_o,
|
||||
// CVXIF destination register - ISSUE_STAGE
|
||||
output logic [ 4:0] x_rd_o,
|
||||
// CVXIF result interface
|
||||
input logic result_valid_i,
|
||||
input x_result_t result_i,
|
||||
output logic result_ready_o
|
||||
);
|
||||
localparam X_NUM_RS = ariane_pkg::NR_RGPR_PORTS;
|
||||
|
||||
logic illegal_n, illegal_q;
|
||||
logic [CVA6Cfg.TRANS_ID_BITS-1:0] illegal_id_n, illegal_id_q;
|
||||
logic [31:0] illegal_instr_n, illegal_instr_q;
|
||||
logic [X_NUM_RS-1:0] rs_valid;
|
||||
|
||||
if (cvxif_pkg::X_NUM_RS == 3) begin : gen_third_operand
|
||||
assign rs_valid = 3'b111;
|
||||
end else begin : gen_no_third_operand
|
||||
assign rs_valid = 2'b11;
|
||||
end
|
||||
|
||||
assign result_ready_o = 1'b1;
|
||||
|
||||
assign x_ready_o = 1'b1; // Readyness of cvxif_fu is determined in issue stage by CVXIF issue interface
|
||||
// Result signals
|
||||
assign x_valid_o = x_illegal_i || result_valid_i;
|
||||
assign x_result_o = result_i.data;
|
||||
assign x_trans_id_o = x_illegal_i ? x_trans_id_i : result_i.id;
|
||||
assign x_we_o = result_i.we;
|
||||
assign x_rd_o = result_i.rd;
|
||||
|
||||
// Handling of illegal instruction exception
|
||||
always_comb begin
|
||||
cvxif_req_o = '0;
|
||||
cvxif_req_o.x_result_ready = 1'b1;
|
||||
x_ready_o = cvxif_resp_i.x_issue_ready;
|
||||
if (x_valid_i) begin
|
||||
cvxif_req_o.x_issue_valid = x_valid_i;
|
||||
cvxif_req_o.x_issue_req.instr = x_off_instr_i;
|
||||
cvxif_req_o.x_issue_req.mode = priv_lvl_i;
|
||||
cvxif_req_o.x_issue_req.id = fu_data_i.trans_id;
|
||||
cvxif_req_o.x_issue_req.rs[0] = fu_data_i.operand_a;
|
||||
cvxif_req_o.x_issue_req.rs[1] = fu_data_i.operand_b;
|
||||
if (cvxif_pkg::X_NUM_RS == 3) begin
|
||||
cvxif_req_o.x_issue_req.rs[2] = fu_data_i.imm;
|
||||
end
|
||||
cvxif_req_o.x_issue_req.rs_valid = rs_valid;
|
||||
cvxif_req_o.x_commit_valid = x_valid_i;
|
||||
cvxif_req_o.x_commit.id = fu_data_i.trans_id;
|
||||
cvxif_req_o.x_commit.x_commit_kill = 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
illegal_n = illegal_q;
|
||||
illegal_id_n = illegal_id_q;
|
||||
illegal_instr_n = illegal_instr_q;
|
||||
if (~cvxif_resp_i.x_issue_resp.accept && cvxif_req_o.x_issue_valid && cvxif_resp_i.x_issue_ready && ~illegal_n) begin
|
||||
illegal_n = 1'b1;
|
||||
illegal_id_n = cvxif_req_o.x_issue_req.id;
|
||||
illegal_instr_n = cvxif_req_o.x_issue_req.instr;
|
||||
end
|
||||
x_valid_o = cvxif_resp_i.x_result_valid; //Read result only when CVXIF is enabled
|
||||
x_trans_id_o = x_valid_o ? cvxif_resp_i.x_result.id : '0;
|
||||
x_result_o = x_valid_o ? cvxif_resp_i.x_result.data : '0;
|
||||
x_exception_o.cause = x_valid_o ? {{(CVA6Cfg.XLEN-6){1'b0}}, cvxif_resp_i.x_result.exccode} : '0;
|
||||
x_exception_o.valid = x_valid_o ? cvxif_resp_i.x_result.exc : '0;
|
||||
x_exception_o.tval = '0;
|
||||
x_exception_o.valid = x_illegal_i;
|
||||
x_exception_o.cause = x_illegal_i ? riscv::ILLEGAL_INSTR : '0;
|
||||
if (CVA6Cfg.TvalEn)
|
||||
x_exception_o.tval = x_off_instr_i; // TODO Optimization : Set exception in IRO.
|
||||
// Hypervisor exception fields
|
||||
x_exception_o.tval2 = {CVA6Cfg.GPLEN{1'b0}};
|
||||
x_exception_o.tinst = '0;
|
||||
x_exception_o.tval2 = '0;
|
||||
x_exception_o.gva = '0;
|
||||
x_we_o = x_valid_o ? cvxif_resp_i.x_result.we : '0;
|
||||
if (illegal_n) begin
|
||||
if (~x_valid_o) begin
|
||||
x_trans_id_o = illegal_id_n;
|
||||
x_result_o = '0;
|
||||
x_valid_o = 1'b1;
|
||||
x_exception_o.cause = riscv::ILLEGAL_INSTR;
|
||||
x_exception_o.valid = 1'b1;
|
||||
if (CVA6Cfg.TvalEn) x_exception_o.tval = illegal_instr_n;
|
||||
x_exception_o.tinst = '0;
|
||||
x_exception_o.tval2 = '0;
|
||||
x_exception_o.gva = '0;
|
||||
x_we_o = '0;
|
||||
illegal_n = '0; // Reset flag for illegal instr. illegal_id and illegal instr values are a don't care, no need to reset it.
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_i, negedge rst_ni) begin
|
||||
if (~rst_ni) begin
|
||||
illegal_q <= 1'b0;
|
||||
illegal_id_q <= '0;
|
||||
illegal_instr_q <= '0;
|
||||
end else begin
|
||||
illegal_q <= illegal_n;
|
||||
illegal_id_q <= illegal_id_n;
|
||||
illegal_instr_q <= illegal_instr_n;
|
||||
end
|
||||
x_exception_o.gva = CVA6Cfg.RVH ? v_i : 1'b0;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
66
core/cvxif_issue_register_commit_if_driver.sv
Normal file
66
core/cvxif_issue_register_commit_if_driver.sv
Normal file
|
@ -0,0 +1,66 @@
|
|||
// Copyright 2024 Thales DIS France SAS
|
||||
//
|
||||
// Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0
|
||||
// You may obtain a copy of the License at https://solderpad.org/licenses/
|
||||
//
|
||||
// Original Author: Guillaume Chauvon
|
||||
|
||||
module cvxif_issue_register_commit_if_driver #(
|
||||
parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty,
|
||||
parameter type x_issue_req_t = logic,
|
||||
parameter type x_issue_resp_t = logic,
|
||||
parameter type x_register_t = logic,
|
||||
parameter type x_commit_t = logic
|
||||
) (
|
||||
// CVA6 inputs
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
input logic flush_i,
|
||||
input logic [CVA6Cfg.XLEN-1:0] hart_id_i,
|
||||
// CVXIF Issue interface
|
||||
input logic issue_ready_i,
|
||||
input x_issue_resp_t issue_resp_i,
|
||||
output logic issue_valid_o,
|
||||
output x_issue_req_t issue_req_o,
|
||||
// CVXIF Register interface
|
||||
input logic register_ready_i,
|
||||
output logic register_valid_o,
|
||||
output x_register_t register_o,
|
||||
// CVXIF Commit interface
|
||||
output logic commit_valid_o,
|
||||
output x_commit_t commit_o,
|
||||
// IRO in/out
|
||||
input logic valid_i,
|
||||
input logic [31:0] x_off_instr_i,
|
||||
input logic [CVA6Cfg.TRANS_ID_BITS-1:0] x_trans_id_i,
|
||||
input [(CVA6Cfg.NrRgprPorts/CVA6Cfg.NrIssuePorts)-1:0][CVA6Cfg.XLEN-1:0] register_i,
|
||||
input logic [(CVA6Cfg.NrRgprPorts/CVA6Cfg.NrIssuePorts)-1:0] rs_valid_i
|
||||
);
|
||||
// X_ISSUE_REGISTER_SPLIT = 0 : Issue and register transactions are synchrone
|
||||
// Mandatory assignement
|
||||
assign register_valid_o = issue_valid_o;
|
||||
assign register_o.hartid = issue_req_o.hartid;
|
||||
assign register_o.id = issue_req_o.id;
|
||||
|
||||
always_comb begin
|
||||
issue_valid_o = valid_i && ~flush_i;
|
||||
issue_req_o.instr = x_off_instr_i;
|
||||
issue_req_o.hartid = hart_id_i;
|
||||
issue_req_o.id = x_trans_id_i;
|
||||
register_o.rs = register_i;
|
||||
register_o.rs_valid = rs_valid_i;
|
||||
end
|
||||
|
||||
/* WARNING */
|
||||
// Always commit since speculation in execute in not possible : TODO to be verified
|
||||
|
||||
// Always do commit transaction with issue
|
||||
// If instruction goes to execute then it is not speculative
|
||||
assign commit_valid_o = issue_valid_o && issue_ready_i;
|
||||
assign commit_o.hartid = issue_req_o.hartid;
|
||||
assign commit_o.id = issue_req_o.id;
|
||||
assign commit_o.commit_kill = 1'b0;
|
||||
|
||||
endmodule
|
335
core/decoder.sv
335
core/decoder.sv
|
@ -48,6 +48,10 @@ module decoder
|
|||
input logic is_last_macro_instr_i,
|
||||
// Is mvsa01/mva01s macro instruction - macro_decoder
|
||||
input logic is_double_rd_macro_instr_i,
|
||||
// Zcmt instruction - FRONTEND
|
||||
input logic is_zcmt_i,
|
||||
// Jump address - zcmt_decoder
|
||||
input logic [CVA6Cfg.XLEN-1:0] jump_address_i,
|
||||
// Is a branch predict instruction - FRONTEND
|
||||
input branchpredict_sbe_t branch_predict_i,
|
||||
// If an exception occured in fetch stage - FRONTEND
|
||||
|
@ -112,7 +116,8 @@ module decoder
|
|||
SBIMM,
|
||||
UIMM,
|
||||
JIMM,
|
||||
RS3
|
||||
RS3,
|
||||
MUX_RD_RS3
|
||||
} imm_select;
|
||||
|
||||
logic [CVA6Cfg.XLEN-1:0] imm_i_type;
|
||||
|
@ -120,7 +125,6 @@ module decoder
|
|||
logic [CVA6Cfg.XLEN-1:0] imm_sb_type;
|
||||
logic [CVA6Cfg.XLEN-1:0] imm_u_type;
|
||||
logic [CVA6Cfg.XLEN-1:0] imm_uj_type;
|
||||
logic [CVA6Cfg.XLEN-1:0] imm_bi_type;
|
||||
|
||||
// ---------------------------------------
|
||||
// Accelerator instructions' first-pass decoder
|
||||
|
@ -178,18 +182,19 @@ module decoder
|
|||
instruction_o.use_zimm = 1'b0;
|
||||
instruction_o.bp = branch_predict_i;
|
||||
instruction_o.vfp = 1'b0;
|
||||
tinst = '0;
|
||||
instruction_o.is_zcmt = is_zcmt_i;
|
||||
ecall = 1'b0;
|
||||
ebreak = 1'b0;
|
||||
check_fprm = 1'b0;
|
||||
tinst = 32'h0;
|
||||
|
||||
if (~ex_i.valid) begin
|
||||
case (instr.rtype.opcode)
|
||||
riscv::OpcodeSystem: begin
|
||||
instruction_o.fu = CSR;
|
||||
instruction_o.rs1[4:0] = instr.itype.rs1;
|
||||
instruction_o.rs2[4:0] = instr.rtype.rs2; //TODO: needs to be checked if better way is available
|
||||
instruction_o.rd[4:0] = instr.itype.rd;
|
||||
instruction_o.rs1 = instr.itype.rs1;
|
||||
instruction_o.rs2 = instr.rtype.rs2; //TODO: needs to be checked if better way is available
|
||||
instruction_o.rd = instr.itype.rd;
|
||||
|
||||
unique case (instr.itype.funct3)
|
||||
3'b000: begin
|
||||
|
@ -328,13 +333,13 @@ module decoder
|
|||
if (instr.instr[25] != 1'b0) begin
|
||||
instruction_o.fu = STORE;
|
||||
imm_select = NOIMM;
|
||||
instruction_o.rs1[4:0] = instr.stype.rs1;
|
||||
instruction_o.rs2[4:0] = instr.stype.rs2;
|
||||
instruction_o.rs1 = instr.stype.rs1;
|
||||
instruction_o.rs2 = instr.stype.rs2;
|
||||
end else begin
|
||||
instruction_o.fu = LOAD;
|
||||
imm_select = NOIMM;
|
||||
instruction_o.rs1[4:0] = instr.itype.rs1;
|
||||
instruction_o.rd[4:0] = instr.itype.rd;
|
||||
instruction_o.rs1 = instr.itype.rs1;
|
||||
instruction_o.rd = instr.itype.rd;
|
||||
end
|
||||
|
||||
// Hypervisor load/store instructions when V=1 cause virtual instruction
|
||||
|
@ -401,25 +406,25 @@ module decoder
|
|||
3'b010: begin // CSRRS
|
||||
imm_select = IIMM;
|
||||
// this is just a read
|
||||
if (instr.itype.rs1 == 5'b0) instruction_o.op = ariane_pkg::CSR_READ;
|
||||
if (instr.itype.rs1 == '0) instruction_o.op = ariane_pkg::CSR_READ;
|
||||
else instruction_o.op = ariane_pkg::CSR_SET;
|
||||
end
|
||||
// atomically clear values in the CSR and write back to rd
|
||||
3'b011: begin // CSRRC
|
||||
imm_select = IIMM;
|
||||
// this is just a read
|
||||
if (instr.itype.rs1 == 5'b0) instruction_o.op = ariane_pkg::CSR_READ;
|
||||
if (instr.itype.rs1 == '0) instruction_o.op = ariane_pkg::CSR_READ;
|
||||
else instruction_o.op = ariane_pkg::CSR_CLEAR;
|
||||
end
|
||||
// use zimm and iimm
|
||||
3'b101: begin // CSRRWI
|
||||
instruction_o.rs1[4:0] = instr.itype.rs1;
|
||||
instruction_o.rs1 = instr.itype.rs1;
|
||||
imm_select = IIMM;
|
||||
instruction_o.use_zimm = 1'b1;
|
||||
instruction_o.op = ariane_pkg::CSR_WRITE;
|
||||
end
|
||||
3'b110: begin // CSRRSI
|
||||
instruction_o.rs1[4:0] = instr.itype.rs1;
|
||||
instruction_o.rs1 = instr.itype.rs1;
|
||||
imm_select = IIMM;
|
||||
instruction_o.use_zimm = 1'b1;
|
||||
// this is just a read
|
||||
|
@ -427,11 +432,11 @@ module decoder
|
|||
else instruction_o.op = ariane_pkg::CSR_SET;
|
||||
end
|
||||
3'b111: begin // CSRRCI
|
||||
instruction_o.rs1[4:0] = instr.itype.rs1;
|
||||
instruction_o.rs1 = instr.itype.rs1;
|
||||
imm_select = IIMM;
|
||||
instruction_o.use_zimm = 1'b1;
|
||||
// this is just a read
|
||||
if (instr.itype.rs1 == 5'b0) instruction_o.op = ariane_pkg::CSR_READ;
|
||||
if (instr.itype.rs1 == '0) instruction_o.op = ariane_pkg::CSR_READ;
|
||||
else instruction_o.op = ariane_pkg::CSR_CLEAR;
|
||||
end
|
||||
default: illegal_instr = 1'b1;
|
||||
|
@ -467,24 +472,24 @@ module decoder
|
|||
if (CVA6Cfg.FpPresent && CVA6Cfg.XFVec && fs_i != riscv::Off && ((CVA6Cfg.RVH && (!v_i || vfs_i != riscv::Off)) || !CVA6Cfg.RVH)) begin
|
||||
automatic logic allow_replication; // control honoring of replication flag
|
||||
|
||||
instruction_o.fu = FPU_VEC; // Same unit, but sets 'vectorial' signal
|
||||
instruction_o.rs1[4:0] = instr.rvftype.rs1;
|
||||
instruction_o.rs2[4:0] = instr.rvftype.rs2;
|
||||
instruction_o.rd[4:0] = instr.rvftype.rd;
|
||||
check_fprm = 1'b1;
|
||||
allow_replication = 1'b1;
|
||||
instruction_o.fu = FPU_VEC; // Same unit, but sets 'vectorial' signal
|
||||
instruction_o.rs1 = instr.rvftype.rs1;
|
||||
instruction_o.rs2 = instr.rvftype.rs2;
|
||||
instruction_o.rd = instr.rvftype.rd;
|
||||
check_fprm = 1'b1;
|
||||
allow_replication = 1'b1;
|
||||
// decode vectorial FP instruction
|
||||
unique case (instr.rvftype.vecfltop)
|
||||
5'b00001: begin
|
||||
instruction_o.op = ariane_pkg::FADD; // vfadd.vfmt - Vectorial FP Addition
|
||||
instruction_o.rs1 = '0; // Operand A is set to 0
|
||||
instruction_o.rs2[4:0] = instr.rvftype.rs1; // Operand B is set to rs1
|
||||
imm_select = IIMM; // Operand C is set to rs2
|
||||
instruction_o.op = ariane_pkg::FADD; // vfadd.vfmt - Vectorial FP Addition
|
||||
instruction_o.rs1 = '0; // Operand A is set to 0
|
||||
instruction_o.rs2 = instr.rvftype.rs1; // Operand B is set to rs1
|
||||
imm_select = IIMM; // Operand C is set to rs2
|
||||
end
|
||||
5'b00010: begin
|
||||
instruction_o.op = ariane_pkg::FSUB; // vfsub.vfmt - Vectorial FP Subtraction
|
||||
instruction_o.rs1 = '0; // Operand A is set to 0
|
||||
instruction_o.rs2[4:0] = instr.rvftype.rs1; // Operand B is set to rs1
|
||||
instruction_o.rs2 = instr.rvftype.rs1; // Operand B is set to rs1
|
||||
imm_select = IIMM; // Operand C is set to rs2
|
||||
end
|
||||
5'b00011:
|
||||
|
@ -515,7 +520,7 @@ module decoder
|
|||
5'b01100: begin
|
||||
unique case (instr.rvftype.rs2) inside // operation encoded in rs2, `inside` for matching ?
|
||||
5'b00000: begin
|
||||
instruction_o.rs2[4:0] = instr.rvftype.rs1; // set rs2 = rs1 so we can map FMV to SGNJ in the unit
|
||||
instruction_o.rs2 = instr.rvftype.rs1; // set rs2 = rs1 so we can map FMV to SGNJ in the unit
|
||||
if (instr.rvftype.repl)
|
||||
instruction_o.op = ariane_pkg::FMV_X2F; // vfmv.vfmt.x - GPR to FPR Move
|
||||
else instruction_o.op = ariane_pkg::FMV_F2X; // vfmv.x.vfmt - FPR to GPR Move
|
||||
|
@ -532,7 +537,7 @@ module decoder
|
|||
instruction_o.op = ariane_pkg::FCVT_I2F; // vfcvt.vfmt.x - Vectorial Int to FP Conversion
|
||||
5'b001??: begin
|
||||
instruction_o.op = ariane_pkg::FCVT_F2F; // vfcvt.vfmt.vfmt - Vectorial FP to FP Conversion
|
||||
instruction_o.rs2[4:0] = instr.rvftype.rd; // set rs2 = rd as target vector for conversion
|
||||
instruction_o.rs2 = instr.rvftype.rd; // set rs2 = rd as target vector for conversion
|
||||
imm_select = IIMM; // rs2 holds part of the intruction
|
||||
// TODO CHECK R bit for valid fmt combinations
|
||||
// determine source format
|
||||
|
@ -715,9 +720,9 @@ module decoder
|
|||
end else begin
|
||||
instruction_o.fu = (instr.rtype.funct7 == 7'b000_0001) ? MULT : ALU;
|
||||
end
|
||||
instruction_o.rs1[4:0] = instr.rtype.rs1;
|
||||
instruction_o.rs2[4:0] = instr.rtype.rs2;
|
||||
instruction_o.rd[4:0] = instr.rtype.rd;
|
||||
instruction_o.rs1 = instr.rtype.rs1;
|
||||
instruction_o.rs2 = instr.rtype.rs2;
|
||||
instruction_o.rd = instr.rtype.rd;
|
||||
|
||||
unique case ({
|
||||
instr.rtype.funct7, instr.rtype.funct3
|
||||
|
@ -777,12 +782,19 @@ module decoder
|
|||
// Bitwise Shifting
|
||||
{7'b011_0000, 3'b001} : instruction_o.op = ariane_pkg::ROL; // rol
|
||||
{7'b011_0000, 3'b101} : instruction_o.op = ariane_pkg::ROR; // ror
|
||||
{
|
||||
7'b000_0100, 3'b111
|
||||
} : begin
|
||||
if (CVA6Cfg.ZKN) instruction_o.op = ariane_pkg::PACK_H; //packh
|
||||
else illegal_instr_bm = 1'b1;
|
||||
end
|
||||
// Zero Extend Op RV32 encoding
|
||||
{
|
||||
7'b000_0100, 3'b100
|
||||
} : begin
|
||||
if (!CVA6Cfg.IS_XLEN64 && instr.instr[24:20] == 5'b00000)
|
||||
instruction_o.op = ariane_pkg::ZEXTH;
|
||||
instruction_o.op = ariane_pkg::ZEXTH; // Zero Extend Op RV32 encoding
|
||||
else if (CVA6Cfg.ZKN) instruction_o.op = ariane_pkg::PACK; // pack
|
||||
else illegal_instr_bm = 1'b1;
|
||||
end
|
||||
default: begin
|
||||
|
@ -806,10 +818,11 @@ module decoder
|
|||
unique case ({
|
||||
CVA6Cfg.RVB, CVA6Cfg.RVZiCond
|
||||
})
|
||||
2'b00: illegal_instr = illegal_instr_non_bm;
|
||||
2'b01: illegal_instr = illegal_instr_non_bm & illegal_instr_zic;
|
||||
2'b10: illegal_instr = illegal_instr_non_bm & illegal_instr_bm;
|
||||
2'b11: illegal_instr = illegal_instr_non_bm & illegal_instr_bm & illegal_instr_zic;
|
||||
2'b00: illegal_instr = illegal_instr_non_bm;
|
||||
2'b01: illegal_instr = illegal_instr_non_bm & illegal_instr_zic;
|
||||
2'b10: illegal_instr = illegal_instr_non_bm & illegal_instr_bm;
|
||||
2'b11: illegal_instr = illegal_instr_non_bm & illegal_instr_bm & illegal_instr_zic;
|
||||
default: ; // TODO: Check that default case is not synthesized.
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
@ -818,10 +831,10 @@ module decoder
|
|||
// 32bit Reg-Reg Operations
|
||||
// --------------------------
|
||||
riscv::OpcodeOp32: begin
|
||||
instruction_o.fu = (instr.rtype.funct7 == 7'b000_0001) ? MULT : ALU;
|
||||
instruction_o.rs1[4:0] = instr.rtype.rs1;
|
||||
instruction_o.rs2[4:0] = instr.rtype.rs2;
|
||||
instruction_o.rd[4:0] = instr.rtype.rd;
|
||||
instruction_o.fu = (instr.rtype.funct7 == 7'b000_0001) ? MULT : ALU;
|
||||
instruction_o.rs1 = instr.rtype.rs1;
|
||||
instruction_o.rs2 = instr.rtype.rs2;
|
||||
instruction_o.rd = instr.rtype.rd;
|
||||
if (CVA6Cfg.IS_XLEN64) begin
|
||||
unique case ({
|
||||
instr.rtype.funct7, instr.rtype.funct3
|
||||
|
@ -844,21 +857,21 @@ module decoder
|
|||
instr.rtype.funct7, instr.rtype.funct3
|
||||
})
|
||||
// Shift with Add (Unsigned Word)
|
||||
{7'b001_0000, 3'b010}: instruction_o.op = ariane_pkg::SH1ADDUW; // sh1add.uw
|
||||
{7'b001_0000, 3'b100}: instruction_o.op = ariane_pkg::SH2ADDUW; // sh2add.uw
|
||||
{7'b001_0000, 3'b110}: instruction_o.op = ariane_pkg::SH3ADDUW; // sh3add.uw
|
||||
{7'b001_0000, 3'b010} : instruction_o.op = ariane_pkg::SH1ADDUW; // sh1add.uw
|
||||
{7'b001_0000, 3'b100} : instruction_o.op = ariane_pkg::SH2ADDUW; // sh2add.uw
|
||||
{7'b001_0000, 3'b110} : instruction_o.op = ariane_pkg::SH3ADDUW; // sh3add.uw
|
||||
// Unsigned word Op's
|
||||
{7'b000_0100, 3'b000}: instruction_o.op = ariane_pkg::ADDUW; // add.uw
|
||||
{7'b000_0100, 3'b000} : instruction_o.op = ariane_pkg::ADDUW; // add.uw
|
||||
// Bitwise Shifting
|
||||
{7'b011_0000, 3'b001}: instruction_o.op = ariane_pkg::ROLW; // rolw
|
||||
{7'b011_0000, 3'b101}: instruction_o.op = ariane_pkg::RORW; // rorw
|
||||
// Zero Extend Op RV64 encoding
|
||||
{7'b000_0100, 3'b100}:
|
||||
begin
|
||||
{7'b011_0000, 3'b001} : instruction_o.op = ariane_pkg::ROLW; // rolw
|
||||
{7'b011_0000, 3'b101} : instruction_o.op = ariane_pkg::RORW; // rorw
|
||||
{
|
||||
7'b000_0100, 3'b100
|
||||
} : begin
|
||||
if (instr.instr[24:20] == 5'b00000)
|
||||
instruction_o.op = ariane_pkg::ZEXTH;
|
||||
else
|
||||
illegal_instr_bm = 1'b1;
|
||||
instruction_o.op = ariane_pkg::ZEXTH; // Zero Extend Op RV64 encoding
|
||||
else if (CVA6Cfg.ZKN) instruction_o.op = ariane_pkg::PACK_W; // packw
|
||||
else illegal_instr_bm = 1'b1;
|
||||
end
|
||||
default: illegal_instr_bm = 1'b1;
|
||||
endcase
|
||||
|
@ -874,8 +887,8 @@ module decoder
|
|||
riscv::OpcodeOpImm: begin
|
||||
instruction_o.fu = ALU;
|
||||
imm_select = IIMM;
|
||||
instruction_o.rs1[4:0] = instr.itype.rs1;
|
||||
instruction_o.rd[4:0] = instr.itype.rd;
|
||||
instruction_o.rs1 = instr.itype.rs1;
|
||||
instruction_o.rd = instr.itype.rd;
|
||||
unique case (instr.itype.funct3)
|
||||
3'b000: instruction_o.op = ariane_pkg::ADD; // Add Immediate
|
||||
3'b010: instruction_o.op = ariane_pkg::SLTS; // Set to one if Lower Than Immediate
|
||||
|
@ -904,14 +917,26 @@ module decoder
|
|||
unique case (instr.itype.funct3)
|
||||
3'b001: begin
|
||||
if (instr.instr[31:25] == 7'b0110000) begin
|
||||
if (instr.instr[22:20] == 3'b100) instruction_o.op = ariane_pkg::SEXTB;
|
||||
else if (instr.instr[22:20] == 3'b101) instruction_o.op = ariane_pkg::SEXTH;
|
||||
else if (instr.instr[22:20] == 3'b010) instruction_o.op = ariane_pkg::CPOP;
|
||||
else if (instr.instr[22:20] == 3'b000) instruction_o.op = ariane_pkg::CLZ;
|
||||
else if (instr.instr[22:20] == 3'b001) instruction_o.op = ariane_pkg::CTZ;
|
||||
end else if (instr.instr[31:26] == 6'b010010) instruction_o.op = ariane_pkg::BCLRI;
|
||||
else if (instr.instr[31:26] == 6'b011010) instruction_o.op = ariane_pkg::BINVI;
|
||||
else if (instr.instr[31:26] == 6'b001010) instruction_o.op = ariane_pkg::BSETI;
|
||||
if (instr.instr[24:20] == 5'b00100) instruction_o.op = ariane_pkg::SEXTB;
|
||||
else if (instr.instr[24:20] == 5'b00101) instruction_o.op = ariane_pkg::SEXTH;
|
||||
else if (instr.instr[24:20] == 5'b00010) instruction_o.op = ariane_pkg::CPOP;
|
||||
else if (instr.instr[24:20] == 5'b00000) instruction_o.op = ariane_pkg::CLZ;
|
||||
else if (instr.instr[24:20] == 5'b00001) instruction_o.op = ariane_pkg::CTZ;
|
||||
else illegal_instr_bm = 1'b1;
|
||||
end else if (CVA6Cfg.IS_XLEN64 && instr.instr[31:26] == 6'b010010)
|
||||
instruction_o.op = ariane_pkg::BCLRI;
|
||||
else if (CVA6Cfg.IS_XLEN32 && instr.instr[31:25] == 7'b0100100)
|
||||
instruction_o.op = ariane_pkg::BCLRI;
|
||||
else if (CVA6Cfg.IS_XLEN64 && instr.instr[31:26] == 6'b011010)
|
||||
instruction_o.op = ariane_pkg::BINVI;
|
||||
else if (CVA6Cfg.IS_XLEN32 && instr.instr[31:25] == 7'b0110100)
|
||||
instruction_o.op = ariane_pkg::BINVI;
|
||||
else if (CVA6Cfg.IS_XLEN64 && instr.instr[31:26] == 6'b001010)
|
||||
instruction_o.op = ariane_pkg::BSETI;
|
||||
else if (CVA6Cfg.IS_XLEN32 && instr.instr[31:25] == 7'b0010100)
|
||||
instruction_o.op = ariane_pkg::BSETI;
|
||||
else if (CVA6Cfg.ZKN && instr.instr[31:20] == 12'b000010001111)
|
||||
instruction_o.op = ariane_pkg::ZIP;
|
||||
else illegal_instr_bm = 1'b1;
|
||||
end
|
||||
3'b101: begin
|
||||
|
@ -920,8 +945,18 @@ module decoder
|
|||
instruction_o.op = ariane_pkg::REV8;
|
||||
else if (instr.instr[31:20] == 12'b011010011000)
|
||||
instruction_o.op = ariane_pkg::REV8;
|
||||
else if (instr.instr[31:26] == 6'b010_010) instruction_o.op = ariane_pkg::BEXTI;
|
||||
else if (instr.instr[31:26] == 6'b011_000) instruction_o.op = ariane_pkg::RORI;
|
||||
else if (CVA6Cfg.IS_XLEN64 && instr.instr[31:26] == 6'b010_010)
|
||||
instruction_o.op = ariane_pkg::BEXTI;
|
||||
else if (CVA6Cfg.IS_XLEN32 && instr.instr[31:25] == 7'b010_0100)
|
||||
instruction_o.op = ariane_pkg::BEXTI;
|
||||
else if (CVA6Cfg.IS_XLEN64 && instr.instr[31:26] == 6'b011_000)
|
||||
instruction_o.op = ariane_pkg::RORI;
|
||||
else if (CVA6Cfg.IS_XLEN32 && instr.instr[31:25] == 7'b011_0000)
|
||||
instruction_o.op = ariane_pkg::RORI;
|
||||
else if (CVA6Cfg.ZKN && instr.instr[31:20] == 12'b011010000111)
|
||||
instruction_o.op = ariane_pkg::BREV8;
|
||||
else if (CVA6Cfg.ZKN && instr.instr[31:20] == 12'b000010001111)
|
||||
instruction_o.op = ariane_pkg::UNZIP;
|
||||
else illegal_instr_bm = 1'b1;
|
||||
end
|
||||
default: illegal_instr_bm = 1'b1;
|
||||
|
@ -938,8 +973,8 @@ module decoder
|
|||
riscv::OpcodeOpImm32: begin
|
||||
instruction_o.fu = ALU;
|
||||
imm_select = IIMM;
|
||||
instruction_o.rs1[4:0] = instr.itype.rs1;
|
||||
instruction_o.rd[4:0] = instr.itype.rd;
|
||||
instruction_o.rs1 = instr.itype.rs1;
|
||||
instruction_o.rd = instr.itype.rd;
|
||||
if (CVA6Cfg.IS_XLEN64) begin
|
||||
unique case (instr.itype.funct3)
|
||||
3'b000: instruction_o.op = ariane_pkg::ADDW; // Add Immediate
|
||||
|
@ -987,8 +1022,8 @@ module decoder
|
|||
riscv::OpcodeStore: begin
|
||||
instruction_o.fu = STORE;
|
||||
imm_select = SIMM;
|
||||
instruction_o.rs1[4:0] = instr.stype.rs1;
|
||||
instruction_o.rs2[4:0] = instr.stype.rs2;
|
||||
instruction_o.rs1 = instr.stype.rs1;
|
||||
instruction_o.rs2 = instr.stype.rs2;
|
||||
// determine store size
|
||||
unique case (instr.stype.funct3)
|
||||
3'b000: instruction_o.op = ariane_pkg::SB;
|
||||
|
@ -1008,8 +1043,8 @@ module decoder
|
|||
riscv::OpcodeLoad: begin
|
||||
instruction_o.fu = LOAD;
|
||||
imm_select = IIMM;
|
||||
instruction_o.rs1[4:0] = instr.itype.rs1;
|
||||
instruction_o.rd[4:0] = instr.itype.rd;
|
||||
instruction_o.rs1 = instr.itype.rs1;
|
||||
instruction_o.rd = instr.itype.rd;
|
||||
// determine load size and signed type
|
||||
unique case (instr.itype.funct3)
|
||||
3'b000: instruction_o.op = ariane_pkg::LB;
|
||||
|
@ -1038,8 +1073,8 @@ module decoder
|
|||
if (CVA6Cfg.FpPresent && fs_i != riscv::Off && ((CVA6Cfg.RVH && (!v_i || vfs_i != riscv::Off)) || !CVA6Cfg.RVH)) begin // only generate decoder if FP extensions are enabled (static)
|
||||
instruction_o.fu = STORE;
|
||||
imm_select = SIMM;
|
||||
instruction_o.rs1[4:0] = instr.stype.rs1;
|
||||
instruction_o.rs2[4:0] = instr.stype.rs2;
|
||||
instruction_o.rs1 = instr.stype.rs1;
|
||||
instruction_o.rs2 = instr.stype.rs2;
|
||||
// determine store size
|
||||
unique case (instr.stype.funct3)
|
||||
// Only process instruction if corresponding extension is active (static)
|
||||
|
@ -1068,8 +1103,8 @@ module decoder
|
|||
if (CVA6Cfg.FpPresent && fs_i != riscv::Off && ((CVA6Cfg.RVH && (!v_i || vfs_i != riscv::Off)) || !CVA6Cfg.RVH)) begin // only generate decoder if FP extensions are enabled (static)
|
||||
instruction_o.fu = LOAD;
|
||||
imm_select = IIMM;
|
||||
instruction_o.rs1[4:0] = instr.itype.rs1;
|
||||
instruction_o.rd[4:0] = instr.itype.rd;
|
||||
instruction_o.rs1 = instr.itype.rs1;
|
||||
instruction_o.rd = instr.itype.rd;
|
||||
// determine load size
|
||||
unique case (instr.itype.funct3)
|
||||
// Only process instruction if corresponding extension is active (static)
|
||||
|
@ -1099,12 +1134,12 @@ module decoder
|
|||
// ----------------------------------
|
||||
riscv::OpcodeMadd, riscv::OpcodeMsub, riscv::OpcodeNmsub, riscv::OpcodeNmadd: begin
|
||||
if (CVA6Cfg.FpPresent && fs_i != riscv::Off && ((CVA6Cfg.RVH && (!v_i || vfs_i != riscv::Off)) || !CVA6Cfg.RVH)) begin // only generate decoder if FP extensions are enabled (static)
|
||||
instruction_o.fu = FPU;
|
||||
instruction_o.rs1[4:0] = instr.r4type.rs1;
|
||||
instruction_o.rs2[4:0] = instr.r4type.rs2;
|
||||
instruction_o.rd[4:0] = instr.r4type.rd;
|
||||
imm_select = RS3; // rs3 into result field
|
||||
check_fprm = 1'b1;
|
||||
instruction_o.fu = FPU;
|
||||
instruction_o.rs1 = instr.r4type.rs1;
|
||||
instruction_o.rs2 = instr.r4type.rs2;
|
||||
instruction_o.rd = instr.r4type.rd;
|
||||
imm_select = RS3; // rs3 into result field
|
||||
check_fprm = 1'b1;
|
||||
// select the correct fused operation
|
||||
unique case (instr.r4type.opcode)
|
||||
default: instruction_o.op = ariane_pkg::FMADD; // fmadd.fmt - FP Fused multiply-add
|
||||
|
@ -1154,24 +1189,24 @@ module decoder
|
|||
|
||||
riscv::OpcodeOpFp: begin
|
||||
if (CVA6Cfg.FpPresent && fs_i != riscv::Off && ((CVA6Cfg.RVH && (!v_i || vfs_i != riscv::Off)) || !CVA6Cfg.RVH)) begin // only generate decoder if FP extensions are enabled (static)
|
||||
instruction_o.fu = FPU;
|
||||
instruction_o.rs1[4:0] = instr.rftype.rs1;
|
||||
instruction_o.rs2[4:0] = instr.rftype.rs2;
|
||||
instruction_o.rd[4:0] = instr.rftype.rd;
|
||||
check_fprm = 1'b1;
|
||||
instruction_o.fu = FPU;
|
||||
instruction_o.rs1 = instr.rftype.rs1;
|
||||
instruction_o.rs2 = instr.rftype.rs2;
|
||||
instruction_o.rd = instr.rftype.rd;
|
||||
check_fprm = 1'b1;
|
||||
// decode FP instruction
|
||||
unique case (instr.rftype.funct5)
|
||||
5'b00000: begin
|
||||
instruction_o.op = ariane_pkg::FADD; // fadd.fmt - FP Addition
|
||||
instruction_o.rs1 = '0; // Operand A is set to 0
|
||||
instruction_o.rs2[4:0] = instr.rftype.rs1; // Operand B is set to rs1
|
||||
imm_select = IIMM; // Operand C is set to rs2
|
||||
instruction_o.op = ariane_pkg::FADD; // fadd.fmt - FP Addition
|
||||
instruction_o.rs1 = '0; // Operand A is set to 0
|
||||
instruction_o.rs2 = instr.rftype.rs1; // Operand B is set to rs1
|
||||
imm_select = IIMM; // Operand C is set to rs2
|
||||
end
|
||||
5'b00001: begin
|
||||
instruction_o.op = ariane_pkg::FSUB; // fsub.fmt - FP Subtraction
|
||||
instruction_o.rs1 = '0; // Operand A is set to 0
|
||||
instruction_o.rs2[4:0] = instr.rftype.rs1; // Operand B is set to rs1
|
||||
imm_select = IIMM; // Operand C is set to rs2
|
||||
instruction_o.op = ariane_pkg::FSUB; // fsub.fmt - FP Subtraction
|
||||
instruction_o.rs1 = '0; // Operand A is set to 0
|
||||
instruction_o.rs2 = instr.rftype.rs1; // Operand B is set to rs1
|
||||
imm_select = IIMM; // Operand C is set to rs2
|
||||
end
|
||||
5'b00010: instruction_o.op = ariane_pkg::FMUL; // fmul.fmt - FP Multiplication
|
||||
5'b00011: instruction_o.op = ariane_pkg::FDIV; // fdiv.fmt - FP Division
|
||||
|
@ -1202,7 +1237,7 @@ module decoder
|
|||
end
|
||||
5'b01000: begin
|
||||
instruction_o.op = ariane_pkg::FCVT_F2F; // fcvt.fmt.fmt - FP to FP Conversion
|
||||
instruction_o.rs2[4:0] = instr.rvftype.rs1; // tie rs2 to rs1 to be safe (vectors use rs2)
|
||||
instruction_o.rs2 = instr.rvftype.rs1; // tie rs2 to rs1 to be safe (vectors use rs2)
|
||||
imm_select = IIMM; // rs2 holds part of the intruction
|
||||
if (|instr.rftype.rs2[24:23])
|
||||
illegal_instr = 1'b1; // bits [22:20] used, other bits must be 0
|
||||
|
@ -1240,7 +1275,7 @@ module decoder
|
|||
illegal_instr = 1'b1; // bits [21:20] used, other bits must be 0
|
||||
end
|
||||
5'b11100: begin
|
||||
instruction_o.rs2[4:0] = instr.rftype.rs1; // set rs2 = rs1 so we can map FMV to SGNJ in the unit
|
||||
instruction_o.rs2 = instr.rftype.rs1; // set rs2 = rs1 so we can map FMV to SGNJ in the unit
|
||||
check_fprm = 1'b0; // instruction encoded in rm, do the check here
|
||||
if (instr.rftype.rm == 3'b000 || (CVA6Cfg.XF16ALT && instr.rftype.rm == 3'b100)) // FP16ALT has separate encoding
|
||||
instruction_o.op = ariane_pkg::FMV_F2X; // fmv.ifmt.fmt - FPR to GPR Move
|
||||
|
@ -1252,7 +1287,7 @@ module decoder
|
|||
end
|
||||
5'b11110: begin
|
||||
instruction_o.op = ariane_pkg::FMV_X2F; // fmv.fmt.ifmt - GPR to FPR Move
|
||||
instruction_o.rs2[4:0] = instr.rftype.rs1; // set rs2 = rs1 so we can map FMV to SGNJ in the unit
|
||||
instruction_o.rs2 = instr.rftype.rs1; // set rs2 = rs1 so we can map FMV to SGNJ in the unit
|
||||
check_fprm = 1'b0; // instruction encoded in rm, do the check here
|
||||
if (!(instr.rftype.rm == 3'b000 || (CVA6Cfg.XF16ALT && instr.rftype.rm == 3'b100)))
|
||||
illegal_instr = 1'b1;
|
||||
|
@ -1303,10 +1338,10 @@ module decoder
|
|||
// ----------------------------------
|
||||
riscv::OpcodeAmo: begin
|
||||
// we are going to use the load unit for AMOs
|
||||
instruction_o.fu = STORE;
|
||||
instruction_o.rs1[4:0] = instr.atype.rs1;
|
||||
instruction_o.rs2[4:0] = instr.atype.rs2;
|
||||
instruction_o.rd[4:0] = instr.atype.rd;
|
||||
instruction_o.fu = STORE;
|
||||
instruction_o.rs1 = instr.atype.rs1;
|
||||
instruction_o.rs2 = instr.atype.rs2;
|
||||
instruction_o.rd = instr.atype.rd;
|
||||
// TODO(zarubaf): Ordering
|
||||
// words
|
||||
if (CVA6Cfg.RVA && instr.stype.funct3 == 3'h2) begin
|
||||
|
@ -1349,16 +1384,18 @@ module decoder
|
|||
end else begin
|
||||
illegal_instr = 1'b1;
|
||||
end
|
||||
tinst = {
|
||||
instr.atype.funct5,
|
||||
instr.atype.aq,
|
||||
instr.atype.rl,
|
||||
instr.atype.rs2,
|
||||
5'b0,
|
||||
instr.atype.funct3,
|
||||
instr.atype.rd,
|
||||
instr.atype.opcode
|
||||
};
|
||||
if (CVA6Cfg.RVH) begin
|
||||
tinst = {
|
||||
instr.atype.funct5,
|
||||
instr.atype.aq,
|
||||
instr.atype.rl,
|
||||
instr.atype.rs2,
|
||||
5'b0,
|
||||
instr.atype.funct3,
|
||||
instr.atype.rd,
|
||||
instr.atype.opcode
|
||||
};
|
||||
end
|
||||
end
|
||||
|
||||
// --------------------------------
|
||||
|
@ -1367,8 +1404,8 @@ module decoder
|
|||
riscv::OpcodeBranch: begin
|
||||
imm_select = SBIMM;
|
||||
instruction_o.fu = CTRL_FLOW;
|
||||
instruction_o.rs1[4:0] = instr.stype.rs1;
|
||||
instruction_o.rs2[4:0] = instr.stype.rs2;
|
||||
instruction_o.rs1 = instr.stype.rs1;
|
||||
instruction_o.rs2 = instr.stype.rs2;
|
||||
|
||||
is_control_flow_instr_o = 1'b1;
|
||||
|
||||
|
@ -1389,9 +1426,9 @@ module decoder
|
|||
riscv::OpcodeJalr: begin
|
||||
instruction_o.fu = CTRL_FLOW;
|
||||
instruction_o.op = ariane_pkg::JALR;
|
||||
instruction_o.rs1[4:0] = instr.itype.rs1;
|
||||
instruction_o.rs1 = instr.itype.rs1;
|
||||
imm_select = IIMM;
|
||||
instruction_o.rd[4:0] = instr.itype.rd;
|
||||
instruction_o.rd = instr.itype.rd;
|
||||
is_control_flow_instr_o = 1'b1;
|
||||
// invalid jump and link register -> reserved for vector encoding
|
||||
if (instr.itype.funct3 != 3'b0) illegal_instr = 1'b1;
|
||||
|
@ -1400,34 +1437,37 @@ module decoder
|
|||
riscv::OpcodeJal: begin
|
||||
instruction_o.fu = CTRL_FLOW;
|
||||
imm_select = JIMM;
|
||||
instruction_o.rd[4:0] = instr.utype.rd;
|
||||
instruction_o.rd = instr.utype.rd;
|
||||
is_control_flow_instr_o = 1'b1;
|
||||
end
|
||||
|
||||
riscv::OpcodeAuipc: begin
|
||||
instruction_o.fu = ALU;
|
||||
imm_select = UIMM;
|
||||
instruction_o.use_pc = 1'b1;
|
||||
instruction_o.rd[4:0] = instr.utype.rd;
|
||||
instruction_o.fu = ALU;
|
||||
imm_select = UIMM;
|
||||
instruction_o.use_pc = 1'b1;
|
||||
instruction_o.rd = instr.utype.rd;
|
||||
end
|
||||
|
||||
riscv::OpcodeLui: begin
|
||||
imm_select = UIMM;
|
||||
instruction_o.fu = ALU;
|
||||
instruction_o.rd[4:0] = instr.utype.rd;
|
||||
imm_select = UIMM;
|
||||
instruction_o.fu = ALU;
|
||||
instruction_o.rd = instr.utype.rd;
|
||||
end
|
||||
|
||||
default: illegal_instr = 1'b1;
|
||||
endcase
|
||||
end
|
||||
if (CVA6Cfg.CvxifEn) begin
|
||||
if (is_illegal_i || illegal_instr) begin
|
||||
instruction_o.fu = CVXIF;
|
||||
instruction_o.rs1[4:0] = instr.r4type.rs1;
|
||||
instruction_o.rs2[4:0] = instr.r4type.rs2;
|
||||
instruction_o.rd[4:0] = instr.r4type.rd;
|
||||
instruction_o.op = ariane_pkg::OFFLOAD;
|
||||
imm_select = RS3;
|
||||
if (~ex_i.valid && (is_illegal_i || illegal_instr)) begin
|
||||
instruction_o.fu = CVXIF;
|
||||
instruction_o.rs1 = instr.r4type.rs1;
|
||||
instruction_o.rs2 = instr.r4type.rs2;
|
||||
instruction_o.rd = instr.r4type.rd;
|
||||
instruction_o.op = ariane_pkg::OFFLOAD;
|
||||
imm_select = instr.rtype.opcode == riscv::OpcodeMadd ||
|
||||
instr.rtype.opcode == riscv::OpcodeMsub ||
|
||||
instr.rtype.opcode == riscv::OpcodeNmadd ||
|
||||
instr.rtype.opcode == riscv::OpcodeNmsub ? RS3 : MUX_RD_RS3;
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1466,16 +1506,20 @@ module decoder
|
|||
imm_u_type = {
|
||||
{CVA6Cfg.XLEN - 32{instruction_i[31]}}, instruction_i[31:12], 12'b0
|
||||
}; // JAL, AUIPC, sign extended to 64 bit
|
||||
imm_uj_type = {
|
||||
{CVA6Cfg.XLEN - 20{instruction_i[31]}},
|
||||
instruction_i[19:12],
|
||||
instruction_i[20],
|
||||
instruction_i[30:21],
|
||||
1'b0
|
||||
};
|
||||
imm_bi_type = {{CVA6Cfg.XLEN - 5{instruction_i[24]}}, instruction_i[24:20]};
|
||||
// if zcmt then xlen jump address assign to immidiate
|
||||
if (CVA6Cfg.RVZCMT && is_zcmt_i) begin
|
||||
imm_uj_type = {{CVA6Cfg.XLEN - 32{jump_address_i[31]}}, jump_address_i[31:0]};
|
||||
end else begin
|
||||
imm_uj_type = {
|
||||
{CVA6Cfg.XLEN - 20{instruction_i[31]}},
|
||||
instruction_i[19:12],
|
||||
instruction_i[20],
|
||||
instruction_i[30:21],
|
||||
1'b0
|
||||
};
|
||||
end
|
||||
|
||||
// NOIMM, IIMM, SIMM, BIMM, UIMM, JIMM, RS3
|
||||
// NOIMM, IIMM, SIMM, SBIMM, UIMM, JIMM, RS3
|
||||
// select immediate
|
||||
case (imm_select)
|
||||
IIMM: begin
|
||||
|
@ -1503,6 +1547,11 @@ module decoder
|
|||
instruction_o.result = {{CVA6Cfg.XLEN - 5{1'b0}}, instr.r4type.rs3};
|
||||
instruction_o.use_imm = 1'b0;
|
||||
end
|
||||
MUX_RD_RS3: begin
|
||||
// result holds address of operand rs3 which is in rd field
|
||||
instruction_o.result = {{CVA6Cfg.XLEN - 5{1'b0}}, instr.rtype.rd};
|
||||
instruction_o.use_imm = 1'b0;
|
||||
end
|
||||
default: begin
|
||||
instruction_o.result = {CVA6Cfg.XLEN{1'b0}};
|
||||
instruction_o.use_imm = 1'b0;
|
||||
|
@ -1619,9 +1668,11 @@ module decoder
|
|||
if (irq_ctrl_i.mip[riscv::IRQ_M_TIMER] && irq_ctrl_i.mie[riscv::IRQ_M_TIMER]) begin
|
||||
interrupt_cause = INTERRUPTS.M_TIMER;
|
||||
end
|
||||
// Machine Mode Software Interrupt
|
||||
if (irq_ctrl_i.mip[riscv::IRQ_M_SOFT] && irq_ctrl_i.mie[riscv::IRQ_M_SOFT]) begin
|
||||
interrupt_cause = INTERRUPTS.M_SW;
|
||||
if (CVA6Cfg.SoftwareInterruptEn) begin
|
||||
// Machine Mode Software Interrupt
|
||||
if (irq_ctrl_i.mip[riscv::IRQ_M_SOFT] && irq_ctrl_i.mie[riscv::IRQ_M_SOFT]) begin
|
||||
interrupt_cause = INTERRUPTS.M_SW;
|
||||
end
|
||||
end
|
||||
// Machine Mode External Interrupt
|
||||
if (irq_ctrl_i.mip[riscv::IRQ_M_EXT] && irq_ctrl_i.mie[riscv::IRQ_M_EXT]) begin
|
||||
|
|
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