forked from libre-chip/cpu
Compare commits
No commits in common. "next-pc" and "master" have entirely different histories.
18 changed files with 670 additions and 1123 deletions
77
.forgejo/workflows/deps.yml
Normal file
77
.forgejo/workflows/deps.yml
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
# See Notices.txt for copyright information
|
||||
on:
|
||||
workflow_call:
|
||||
outputs:
|
||||
cache-primary-key:
|
||||
value: ${{ jobs.deps.outputs.cache-primary-key }}
|
||||
|
||||
jobs:
|
||||
deps:
|
||||
runs-on: debian-12
|
||||
outputs:
|
||||
cache-primary-key: ${{ steps.restore-deps.outputs.cache-primary-key }}
|
||||
steps:
|
||||
- uses: https://git.libre-chip.org/mirrors/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: https://git.libre-chip.org/mirrors/cache/restore@v3
|
||||
id: restore-deps
|
||||
with:
|
||||
path: deps
|
||||
key: ${{ github.repository }}-deps-${{ runner.os }}-${{ hashFiles('.forgejo/workflows/deps.yml') }}
|
||||
lookup-only: true
|
||||
- name: Install Apt packages
|
||||
if: steps.restore-deps.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
apt-get update -qq
|
||||
apt-get install -qq \
|
||||
bison \
|
||||
build-essential \
|
||||
ccache \
|
||||
clang \
|
||||
cvc5 \
|
||||
flex \
|
||||
gawk \
|
||||
g++ \
|
||||
git \
|
||||
libboost-filesystem-dev \
|
||||
libboost-python-dev \
|
||||
libboost-system-dev \
|
||||
libffi-dev \
|
||||
libreadline-dev \
|
||||
lld \
|
||||
pkg-config \
|
||||
python3 \
|
||||
python3-click \
|
||||
tcl-dev \
|
||||
zlib1g-dev
|
||||
- name: Install Firtool
|
||||
if: steps.restore-deps.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
mkdir -p deps
|
||||
wget -O deps/firrtl.tar.gz https://github.com/llvm/circt/releases/download/firtool-1.86.0/firrtl-bin-linux-x64.tar.gz
|
||||
sha256sum -c - <<<'bf6f4ab18ae76f135c944efbd81e25391c31c1bd0617c58ab0592640abefee14 deps/firrtl.tar.gz'
|
||||
tar -C deps -xvaf deps/firrtl.tar.gz
|
||||
rm -rf deps/firtool
|
||||
mv deps/firtool-1.86.0 deps/firtool
|
||||
- name: Get SymbiYosys
|
||||
if: steps.restore-deps.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
git clone --depth=1 --branch=yosys-0.45 https://git.libre-chip.org/mirrors/sby deps/sby
|
||||
- name: Build Z3
|
||||
if: steps.restore-deps.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
git clone --depth=1 --recursive --branch=z3-4.13.3 https://git.libre-chip.org/mirrors/z3 deps/z3
|
||||
(cd deps/z3; PYTHON=python3 ./configure --prefix=/usr/local)
|
||||
make -C deps/z3/build -j"$(nproc)"
|
||||
- name: Build Yosys
|
||||
if: steps.restore-deps.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
git clone --depth=1 --recursive --branch=0.45 https://git.libre-chip.org/mirrors/yosys deps/yosys
|
||||
make -C deps/yosys -j"$(nproc)"
|
||||
- uses: https://git.libre-chip.org/mirrors/cache/save@v3
|
||||
if: steps.restore-deps.outputs.cache-hit != 'true'
|
||||
with:
|
||||
path: deps
|
||||
key: ${{ steps.restore-deps.outputs.cache-primary-key }}
|
||||
|
|
@ -3,16 +3,56 @@
|
|||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
deps:
|
||||
runs-on: debian-12
|
||||
uses: ./.forgejo/workflows/deps.yml
|
||||
test:
|
||||
runs-on: debian-12
|
||||
container:
|
||||
image: git.libre-chip.org/libre-chip/fayalite-deps:latest
|
||||
needs: deps
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: https://git.libre-chip.org/mirrors/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- run: |
|
||||
scripts/check-copyright.sh
|
||||
- run: |
|
||||
apt-get update -qq
|
||||
apt-get install -qq \
|
||||
bison \
|
||||
build-essential \
|
||||
ccache \
|
||||
clang \
|
||||
cvc5 \
|
||||
flex \
|
||||
gawk \
|
||||
git \
|
||||
libboost-filesystem-dev \
|
||||
libboost-python-dev \
|
||||
libboost-system-dev \
|
||||
libffi-dev \
|
||||
libreadline-dev \
|
||||
lld \
|
||||
pkg-config \
|
||||
python3 \
|
||||
python3-click \
|
||||
tcl-dev \
|
||||
z3 \
|
||||
zlib1g-dev
|
||||
- run: |
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.89.0
|
||||
source "$HOME/.cargo/env"
|
||||
echo "$PATH" >> "$GITHUB_PATH"
|
||||
- uses: https://git.libre-chip.org/mirrors/cache/restore@v3
|
||||
with:
|
||||
path: deps
|
||||
key: ${{ needs.deps.outputs.cache-primary-key }}
|
||||
fail-on-cache-miss: true
|
||||
- run: |
|
||||
make -C deps/z3/build install
|
||||
make -C deps/sby install
|
||||
make -C deps/yosys install
|
||||
export PATH="$(realpath deps/firtool/bin):$PATH"
|
||||
echo "$PATH" >> "$GITHUB_PATH"
|
||||
- uses: https://git.libre-chip.org/mirrors/rust-cache@v2
|
||||
with:
|
||||
save-if: ${{ github.ref == 'refs/heads/master' }}
|
||||
|
|
|
|||
167
Cargo.lock
generated
167
Cargo.lock
generated
|
|
@ -1,6 +1,18 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
|
|
@ -81,12 +93,6 @@ version = "0.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.6.0"
|
||||
|
|
@ -166,15 +172,6 @@ dependencies = [
|
|||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_complete"
|
||||
version = "4.5.59"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2348487adcd4631696ced64ccdb40d38ac4d31cae7f2eec8817fcea1b9d1c43c"
|
||||
dependencies = [
|
||||
"clap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.18"
|
||||
|
|
@ -210,7 +207,6 @@ name = "cpu"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"fayalite",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -304,22 +300,20 @@ checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
|
|||
[[package]]
|
||||
name = "fayalite"
|
||||
version = "0.3.0"
|
||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#0b77d1bea0af932a40fd221daf65d5a9b7d62bc5"
|
||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#bd75fdfefd642f6dd2210cfb003fa63f9dce114e"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bitvec",
|
||||
"blake3",
|
||||
"clap",
|
||||
"clap_complete",
|
||||
"ctor",
|
||||
"eyre",
|
||||
"fayalite-proc-macros",
|
||||
"fayalite-visit-gen",
|
||||
"hashbrown 0.15.5",
|
||||
"hashbrown",
|
||||
"jobslot",
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
"ordered-float",
|
||||
"os_pipe",
|
||||
"petgraph",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
@ -331,7 +325,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "fayalite-proc-macros"
|
||||
version = "0.3.0"
|
||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#0b77d1bea0af932a40fd221daf65d5a9b7d62bc5"
|
||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#bd75fdfefd642f6dd2210cfb003fa63f9dce114e"
|
||||
dependencies = [
|
||||
"fayalite-proc-macros-impl",
|
||||
]
|
||||
|
|
@ -339,7 +333,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "fayalite-proc-macros-impl"
|
||||
version = "0.3.0"
|
||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#0b77d1bea0af932a40fd221daf65d5a9b7d62bc5"
|
||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#bd75fdfefd642f6dd2210cfb003fa63f9dce114e"
|
||||
dependencies = [
|
||||
"base16ct",
|
||||
"num-bigint",
|
||||
|
|
@ -354,7 +348,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "fayalite-visit-gen"
|
||||
version = "0.3.0"
|
||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#0b77d1bea0af932a40fd221daf65d5a9b7d62bc5"
|
||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#bd75fdfefd642f6dd2210cfb003fa63f9dce114e"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"prettyplease",
|
||||
|
|
@ -372,12 +366,6 @@ version = "0.5.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||
|
||||
[[package]]
|
||||
name = "funty"
|
||||
version = "2.0.0"
|
||||
|
|
@ -396,14 +384,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.3.4"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
|
||||
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"r-efi",
|
||||
"wasip2",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -411,16 +398,9 @@ name = "hashbrown"
|
|||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"allocator-api2",
|
||||
"equivalent",
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -451,7 +431,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.14.5",
|
||||
"hashbrown",
|
||||
"serde",
|
||||
]
|
||||
|
||||
|
|
@ -469,16 +449,16 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
|||
|
||||
[[package]]
|
||||
name = "jobslot"
|
||||
version = "0.2.23"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58715c67c327da7f1558708348d68c207fd54900c4ae0529e29305d04d795b8c"
|
||||
checksum = "fe10868679d7a24c2c67d862d0e64a342ce9aef7cdde9ce8019bd35d353d458d"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"derive_destructure2",
|
||||
"getrandom",
|
||||
"libc",
|
||||
"scopeguard",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -534,26 +514,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||
|
||||
[[package]]
|
||||
name = "ordered-float"
|
||||
version = "5.1.0"
|
||||
name = "os_pipe"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f4779c6901a562440c3786d08192c6fbda7c1c2060edd10006b05ee35d10f2d"
|
||||
checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"rand",
|
||||
"serde",
|
||||
"libc",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "petgraph"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455"
|
||||
version = "0.6.5"
|
||||
source = "git+https://github.com/programmerjake/petgraph.git?rev=258ea8071209a924b73fe96f9f87a3b7b45cbc9f#258ea8071209a924b73fe96f9f87a3b7b45cbc9f"
|
||||
dependencies = [
|
||||
"fixedbitset",
|
||||
"hashbrown 0.15.5",
|
||||
"indexmap",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -584,37 +560,12 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "r-efi"
|
||||
version = "5.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||
|
||||
[[package]]
|
||||
name = "radium"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.37"
|
||||
|
|
@ -777,13 +728,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "wasip2"
|
||||
version = "1.0.1+wasi-0.2.4"
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7"
|
||||
dependencies = [
|
||||
"wit-bindgen",
|
||||
]
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
|
|
@ -797,12 +745,6 @@ dependencies = [
|
|||
"winsafe",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
|
|
@ -821,15 +763,6 @@ dependencies = [
|
|||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
|
|
@ -900,12 +833,6 @@ version = "0.0.19"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.46.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
|
||||
|
||||
[[package]]
|
||||
name = "wyz"
|
||||
version = "0.5.1"
|
||||
|
|
@ -914,3 +841,23 @@ checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
|
|||
dependencies = [
|
||||
"tap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ rust-version = "1.89.0"
|
|||
|
||||
[workspace.dependencies]
|
||||
fayalite = { git = "https://git.libre-chip.org/libre-chip/fayalite.git", version = "0.3.0", branch = "master" }
|
||||
serde = { version = "1.0.202", features = ["derive"] }
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 1
|
||||
|
|
|
|||
15
README.md
15
README.md
|
|
@ -1,15 +0,0 @@
|
|||
<!--
|
||||
SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
See Notices.txt for copyright information
|
||||
-->
|
||||
# Libre-Chip's CPU
|
||||
|
||||
<https://libre-chip.org/first_arch/index.html>
|
||||
|
||||
# Funding
|
||||
|
||||
## NLnet Grants
|
||||
|
||||
* [Libre-Chip CPU with proof of No Spectre bugs](https://nlnet.nl/project/Libre-Chip-proof/) 2024-12-324 [(progress)](https://git.libre-chip.org/libre-chip/grant-tracking/src/branch/master/nlnet-2024-12-324/progress.md)
|
||||
|
||||
This project was funded through the [NGI0 Commons Fund](https://nlnet.nl/commonsfund), a fund established by [NLnet](https://nlnet.nl/) with financial support from the European Commission's [Next Generation Internet](https://ngi.eu) programme, under the aegis of [DG Communications Networks, Content and Technology](https://commission.europa.eu/about-european-commission/departments-and-executive-agencies/communications-networks-content-and-technology_en) under grant agreement № [101135429](https://cordis.europa.eu/project/id/101135429). Additional funding is made available by the [Swiss State Secretariat for Education, Research and Innovation](https://www.sbfi.admin.ch/sbfi/en/home.html) (SERI).
|
||||
|
|
@ -16,4 +16,3 @@ version.workspace = true
|
|||
|
||||
[dependencies]
|
||||
fayalite.workspace = true
|
||||
serde.workspace = true
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
../../README.md
|
||||
|
|
@ -8,10 +8,9 @@ use crate::{
|
|||
},
|
||||
};
|
||||
use fayalite::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::num::NonZeroUsize;
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
||||
#[non_exhaustive]
|
||||
pub struct UnitConfig {
|
||||
pub kind: UnitKind,
|
||||
|
|
@ -28,14 +27,12 @@ impl UnitConfig {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
||||
#[non_exhaustive]
|
||||
pub struct CpuConfig {
|
||||
pub units: Vec<UnitConfig>,
|
||||
pub out_reg_num_width: usize,
|
||||
pub fetch_width: NonZeroUsize,
|
||||
pub max_branches_per_fetch: NonZeroUsize,
|
||||
pub fetch_width_in_bytes: NonZeroUsize,
|
||||
/// default value for [`UnitConfig::max_in_flight`]
|
||||
pub default_unit_max_in_flight: NonZeroUsize,
|
||||
pub rob_size: NonZeroUsize,
|
||||
|
|
@ -49,18 +46,6 @@ impl CpuConfig {
|
|||
};
|
||||
v
|
||||
};
|
||||
pub const DEFAULT_MAX_BRANCHES_PER_FETCH: NonZeroUsize = {
|
||||
let Some(v) = NonZeroUsize::new(1) else {
|
||||
unreachable!();
|
||||
};
|
||||
v
|
||||
};
|
||||
pub const DEFAULT_FETCH_WIDTH_IN_BYTES: NonZeroUsize = {
|
||||
let Some(v) = NonZeroUsize::new(4) else {
|
||||
unreachable!();
|
||||
};
|
||||
v
|
||||
};
|
||||
pub const DEFAULT_UNIT_MAX_IN_FLIGHT: NonZeroUsize = {
|
||||
let Some(v) = NonZeroUsize::new(8) else {
|
||||
unreachable!();
|
||||
|
|
@ -72,8 +57,6 @@ impl CpuConfig {
|
|||
units,
|
||||
out_reg_num_width: Self::DEFAULT_OUT_REG_NUM_WIDTH,
|
||||
fetch_width: Self::DEFAULT_FETCH_WIDTH,
|
||||
max_branches_per_fetch: Self::DEFAULT_MAX_BRANCHES_PER_FETCH,
|
||||
fetch_width_in_bytes: Self::DEFAULT_FETCH_WIDTH_IN_BYTES,
|
||||
default_unit_max_in_flight: Self::DEFAULT_UNIT_MAX_IN_FLIGHT,
|
||||
rob_size,
|
||||
}
|
||||
|
|
@ -134,12 +117,3 @@ impl CpuConfig {
|
|||
[self.non_const_unit_nums().len()]
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl(get(|c| c.fetch_width.get()))]
|
||||
pub type CpuConfigFetchWidth<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||
|
||||
#[hdl(get(|c| c.max_branches_per_fetch.get()))]
|
||||
pub type CpuConfigMaxBranchesPerFetch<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||
|
||||
#[hdl(get(|c| c.fetch_width_in_bytes.get()))]
|
||||
pub type CpuConfigFetchWidthInBytes<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ use fayalite::{
|
|||
expr::ops::{ArrayLiteral, ExprPartialEq},
|
||||
intern::Interned,
|
||||
prelude::*,
|
||||
sim::value::SimValuePartialEq,
|
||||
};
|
||||
use std::{fmt, marker::PhantomData, ops::Range};
|
||||
|
||||
|
|
@ -182,12 +181,6 @@ impl ExprPartialEq<Self> for OutputIntegerMode {
|
|||
}
|
||||
}
|
||||
|
||||
impl SimValuePartialEq<Self> for OutputIntegerMode {
|
||||
fn sim_value_eq(this: &SimValue<Self>, other: &SimValue<Self>) -> bool {
|
||||
SimValue::opaque(this) == SimValue::opaque(other)
|
||||
}
|
||||
}
|
||||
|
||||
pub const MOP_IMM_WIDTH: usize = 34;
|
||||
pub const MOP_MIN_REG_WIDTH: usize = 8;
|
||||
pub const COMMON_MOP_SRC_LEN: usize = 3;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
// See Notices.txt for copyright information
|
||||
pub mod config;
|
||||
pub mod instruction;
|
||||
pub mod next_pc;
|
||||
pub mod reg_alloc;
|
||||
pub mod register;
|
||||
pub mod unit;
|
||||
|
|
|
|||
|
|
@ -1,561 +0,0 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
|
||||
//! [Next-Instruction Logic](https://git.libre-chip.org/libre-chip/grant-tracking/issues/10)
|
||||
//!
|
||||
//! The basic idea here is that there's a `next_pc` stage that sends predicted fetch PCs to the `fetch` stage,
|
||||
//! the `fetch` stage's outputs eventually end up in the `decode` stage,
|
||||
//! after the `decode` stage there's a `post_decode` stage (that may run in the same clock cycle as `decode`)
|
||||
//! that checks that the fetched instructions' kinds match the predicted instruction kinds and that feeds
|
||||
//! information back to the `fetch` stage to cancel fetches that need to be predicted differently.
|
||||
|
||||
use crate::{config::CpuConfig, util::array_vec::ArrayVec};
|
||||
use fayalite::{
|
||||
int::{UIntInRange, UIntInRangeInclusive},
|
||||
prelude::*,
|
||||
sim::value::SimOnlyValueTrait,
|
||||
util::ready_valid::ReadyValid,
|
||||
};
|
||||
|
||||
#[hdl]
|
||||
pub enum PredictedCond {
|
||||
Taken,
|
||||
Fallthrough,
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
pub struct PredictedFallthrough {}
|
||||
|
||||
#[hdl]
|
||||
pub enum BranchPredictionKind<CondKind> {
|
||||
Branch(HdlOption<CondKind>),
|
||||
IndirectBranch(HdlOption<CondKind>),
|
||||
Call(HdlOption<CondKind>),
|
||||
IndirectCall(HdlOption<CondKind>),
|
||||
Ret(HdlOption<CondKind>),
|
||||
}
|
||||
|
||||
#[hdl(get(|c| c.max_branches_per_fetch.get() - 1))]
|
||||
pub type NextPcPredictionMaxBranchesBeforeLast<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||
|
||||
#[hdl(no_static)]
|
||||
pub struct NextPcPrediction<C: PhantomConstGet<CpuConfig>> {
|
||||
pub fetch_pc: UInt<64>,
|
||||
pub async_interrupt: Bool,
|
||||
pub branches_before_last: ArrayVec<
|
||||
BranchPredictionKind<PredictedFallthrough>,
|
||||
NextPcPredictionMaxBranchesBeforeLast<C>,
|
||||
>,
|
||||
pub last_branch: HdlOption<BranchPredictionKind<PredictedCond>>,
|
||||
pub last_branch_target_pc: UInt<64>,
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
pub struct NextPcToFetchInterfaceInner {
|
||||
pub next_fetch_pc: UInt<64>,
|
||||
pub fetch_block_id: UInt<8>,
|
||||
pub in_progress_fetches_to_cancel: UInt<8>,
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
pub struct NextPcToFetchInterface<C: PhantomConstGet<CpuConfig>> {
|
||||
pub inner: ReadyValid<NextPcToFetchInterfaceInner>,
|
||||
pub config: C,
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
/// WIP version of decoded instruction just good enough to represent stuff needed for [`next_pc()`] since the actual instruction definition isn't finalized yet. This will be replaced at a later point.
|
||||
pub enum WipDecodedInsnKind {
|
||||
NonBranch,
|
||||
Branch(UInt<64>),
|
||||
BranchCond(UInt<64>),
|
||||
IndirectBranch,
|
||||
IndirectBranchCond,
|
||||
Call(UInt<64>),
|
||||
CallCond(UInt<64>),
|
||||
IndirectCall,
|
||||
IndirectCallCond,
|
||||
Ret,
|
||||
RetCond,
|
||||
/// not actually an instruction read from memory, covers stuff like external interrupts, page faults, memory errors, and so on.
|
||||
Interrupt(UInt<64>),
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
/// WIP version of decoded instruction just good enough to represent stuff needed for [`next_pc()`] since the actual instruction definition isn't finalized yet. This will be replaced at a later point.
|
||||
pub struct WipDecodedInsn {
|
||||
pub fetch_block_id: UInt<8>,
|
||||
pub id: UInt<12>,
|
||||
pub pc: UInt<64>,
|
||||
pub kind: WipDecodedInsnKind,
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
/// handles updating speculative branch predictor state (e.g. branch histories) when instructions retire,
|
||||
/// as well as updating state when a branch instruction is mis-speculated.
|
||||
pub struct NextPcToRetireInterface<C: PhantomConstGet<CpuConfig>> {
|
||||
// TODO: add needed fields
|
||||
pub config: C,
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
pub struct DecodeToPostDecodeInterface<C: PhantomConstGet<CpuConfig>> {
|
||||
// TODO: add needed fields
|
||||
pub config: C,
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
pub struct PostDecodeOutputInterface<C: PhantomConstGet<CpuConfig>> {
|
||||
// TODO: add needed fields
|
||||
pub config: C,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Copy, Clone, PartialEq, Eq, Debug, Hash, Default, serde::Serialize, serde::Deserialize,
|
||||
)]
|
||||
enum BranchPredictionState {
|
||||
StronglyNotTaken,
|
||||
#[default]
|
||||
WeaklyNotTaken,
|
||||
WeaklyTaken,
|
||||
StronglyTaken,
|
||||
}
|
||||
|
||||
impl BranchPredictionState {
|
||||
#[must_use]
|
||||
fn is_taken(self) -> bool {
|
||||
match self {
|
||||
Self::StronglyNotTaken => false,
|
||||
Self::WeaklyNotTaken => false,
|
||||
Self::WeaklyTaken => true,
|
||||
Self::StronglyTaken => true,
|
||||
}
|
||||
}
|
||||
#[must_use]
|
||||
fn towards_taken(self) -> Self {
|
||||
match self {
|
||||
Self::StronglyNotTaken => Self::WeaklyNotTaken,
|
||||
Self::WeaklyNotTaken => Self::WeaklyTaken,
|
||||
Self::WeaklyTaken => Self::StronglyTaken,
|
||||
Self::StronglyTaken => Self::StronglyTaken,
|
||||
}
|
||||
}
|
||||
#[must_use]
|
||||
fn towards_not_taken(self) -> Self {
|
||||
match self {
|
||||
Self::StronglyNotTaken => Self::StronglyNotTaken,
|
||||
Self::WeaklyNotTaken => Self::StronglyNotTaken,
|
||||
Self::WeaklyTaken => Self::WeaklyNotTaken,
|
||||
Self::StronglyTaken => Self::WeaklyTaken,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[must_use]
|
||||
enum ResetStatus {
|
||||
Done,
|
||||
Working,
|
||||
}
|
||||
|
||||
impl ResetStatus {
|
||||
fn and(self, other: Self) -> Self {
|
||||
match (self, other) {
|
||||
(ResetStatus::Done, ResetStatus::Done) => ResetStatus::Done,
|
||||
(ResetStatus::Done | ResetStatus::Working, ResetStatus::Working)
|
||||
| (ResetStatus::Working, ResetStatus::Done) => ResetStatus::Working,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait SimValueDefault: Type {
|
||||
fn sim_value_default(self) -> SimValue<Self>;
|
||||
}
|
||||
|
||||
impl<T: SimOnlyValueTrait> SimValueDefault for SimOnly<T> {
|
||||
fn sim_value_default(self) -> SimValue<Self> {
|
||||
SimOnlyValue::<T>::default().to_sim_value_with_type(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Type> SimValueDefault for HdlOption<T> {
|
||||
fn sim_value_default(self) -> SimValue<Self> {
|
||||
self.HdlNone().to_sim_value_with_type(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl SimValueDefault for Bool {
|
||||
fn sim_value_default(self) -> SimValue<Self> {
|
||||
false.to_sim_value()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Width: Size> SimValueDefault for UIntType<Width> {
|
||||
fn sim_value_default(self) -> SimValue<Self> {
|
||||
self.zero().to_sim_value()
|
||||
}
|
||||
}
|
||||
|
||||
trait ResetSteps: Type {
|
||||
async fn reset_step(
|
||||
this: Expr<Self>,
|
||||
sim: &mut ExternModuleSimulationState,
|
||||
step: usize,
|
||||
) -> ResetStatus;
|
||||
}
|
||||
|
||||
impl<T: SimValueDefault, Len: Size> ResetSteps for ArrayType<T, Len> {
|
||||
async fn reset_step(
|
||||
this: Expr<Self>,
|
||||
sim: &mut ExternModuleSimulationState,
|
||||
step: usize,
|
||||
) -> ResetStatus {
|
||||
let element = Expr::ty(this).element();
|
||||
let len = Expr::ty(this).len();
|
||||
if step < len {
|
||||
sim.write(this[step], element.sim_value_default()).await;
|
||||
}
|
||||
if step.saturating_add(1) >= len {
|
||||
ResetStatus::Done
|
||||
} else {
|
||||
ResetStatus::Working
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
struct CallStack {
|
||||
return_addresses: Array<UInt<64>, { CallStack::SIZE }>,
|
||||
len: UIntInRangeInclusive<0, { CallStack::SIZE }>,
|
||||
}
|
||||
|
||||
impl CallStack {
|
||||
const SIZE: usize = 16;
|
||||
}
|
||||
|
||||
impl SimValueDefault for CallStack {
|
||||
#[hdl]
|
||||
fn sim_value_default(self) -> SimValue<Self> {
|
||||
#[hdl(sim)]
|
||||
CallStack {
|
||||
// something other than zero so you can see the values getting reset
|
||||
return_addresses: [!0u64; Self::SIZE],
|
||||
len: 0usize.to_sim_value_with_type(self.len),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ResetSteps for CallStack {
|
||||
#[hdl]
|
||||
async fn reset_step(
|
||||
this: Expr<Self>,
|
||||
sim: &mut ExternModuleSimulationState,
|
||||
_step: usize,
|
||||
) -> ResetStatus {
|
||||
#[hdl]
|
||||
let CallStack {
|
||||
return_addresses,
|
||||
len,
|
||||
} = this;
|
||||
// return_addresses is implemented as a shift register, so it can be all reset at once
|
||||
for i in return_addresses {
|
||||
sim.write(i, 0u64).await;
|
||||
}
|
||||
sim.write(len, 0usize).await;
|
||||
ResetStatus::Done
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
struct BranchTargetBuffer {
|
||||
branch_pc_to_target_map: Array<HdlOption<(UInt<64>, UInt<64>)>, { BranchTargetBuffer::SIZE }>,
|
||||
}
|
||||
|
||||
impl BranchTargetBuffer {
|
||||
const SIZE: usize = 16;
|
||||
}
|
||||
|
||||
impl SimValueDefault for BranchTargetBuffer {
|
||||
#[hdl]
|
||||
fn sim_value_default(self) -> SimValue<Self> {
|
||||
#[hdl(sim)]
|
||||
BranchTargetBuffer {
|
||||
// something other than zero so you can see the values getting reset
|
||||
branch_pc_to_target_map: [HdlSome((0u64, 0u64)); Self::SIZE],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ResetSteps for BranchTargetBuffer {
|
||||
#[hdl]
|
||||
async fn reset_step(
|
||||
this: Expr<Self>,
|
||||
sim: &mut ExternModuleSimulationState,
|
||||
step: usize,
|
||||
) -> ResetStatus {
|
||||
#[hdl]
|
||||
let BranchTargetBuffer {
|
||||
branch_pc_to_target_map,
|
||||
} = this;
|
||||
ResetSteps::reset_step(branch_pc_to_target_map, sim, step).await
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
struct BranchHistory {
|
||||
history: Array<Bool, { BranchHistory::SIZE }>,
|
||||
/// exclusive
|
||||
tail: UIntInRange<0, { BranchHistory::SIZE }>,
|
||||
/// inclusive, always at or after tail, always at or before speculative_head
|
||||
non_speculative_head: UIntInRange<0, { BranchHistory::SIZE }>,
|
||||
/// inclusive, always at or after both tail and non_speculative_head
|
||||
speculative_head: UIntInRange<0, { BranchHistory::SIZE }>,
|
||||
}
|
||||
|
||||
impl ResetSteps for BranchHistory {
|
||||
#[hdl]
|
||||
async fn reset_step(
|
||||
this: Expr<Self>,
|
||||
sim: &mut ExternModuleSimulationState,
|
||||
step: usize,
|
||||
) -> ResetStatus {
|
||||
#[hdl]
|
||||
let Self {
|
||||
history,
|
||||
tail,
|
||||
non_speculative_head,
|
||||
speculative_head,
|
||||
} = this;
|
||||
sim.write(tail, 0usize).await;
|
||||
sim.write(non_speculative_head, 0usize).await;
|
||||
sim.write(speculative_head, 0usize).await;
|
||||
ResetSteps::reset_step(history, sim, step).await
|
||||
}
|
||||
}
|
||||
|
||||
impl SimValueDefault for BranchHistory {
|
||||
#[hdl]
|
||||
fn sim_value_default(self) -> SimValue<Self> {
|
||||
#[hdl(sim)]
|
||||
BranchHistory {
|
||||
// something other than zero so you can see the values getting reset
|
||||
history: [true; Self::SIZE],
|
||||
tail: 0usize.to_sim_value_with_type(self.tail),
|
||||
non_speculative_head: 0usize.to_sim_value_with_type(self.non_speculative_head),
|
||||
speculative_head: 0usize.to_sim_value_with_type(self.speculative_head),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum BranchHistoryTryPushSpeculativeError {
|
||||
NoSpace,
|
||||
}
|
||||
|
||||
enum BranchHistoryTryPushNonSpeculativeError {
|
||||
NoSpace,
|
||||
Misprediction { speculated: bool },
|
||||
}
|
||||
|
||||
impl BranchHistory {
|
||||
const LOG2_SIZE: usize = 8;
|
||||
const SIZE: usize = 1 << Self::LOG2_SIZE;
|
||||
fn next_pos(pos: usize) -> usize {
|
||||
(pos + 1) % Self::SIZE
|
||||
}
|
||||
fn prev_pos(pos: usize) -> usize {
|
||||
(pos + Self::SIZE - 1) % Self::SIZE
|
||||
}
|
||||
async fn history_from_head<const N: usize>(
|
||||
this: Expr<Self>,
|
||||
sim: &mut ExternModuleSimulationState,
|
||||
head: usize,
|
||||
) -> [bool; N] {
|
||||
let mut retval = [false; N];
|
||||
let mut pos = head;
|
||||
for entry in &mut retval {
|
||||
if pos == *sim.read(this.tail).await {
|
||||
break;
|
||||
}
|
||||
*entry = sim.read_bool(this.history[pos]).await;
|
||||
pos = Self::prev_pos(pos);
|
||||
}
|
||||
retval
|
||||
}
|
||||
async fn delete_speculative_history(this: Expr<Self>, sim: &mut ExternModuleSimulationState) {
|
||||
let non_speculative_head = sim.read(this.non_speculative_head).await;
|
||||
sim.write(this.speculative_head, non_speculative_head).await;
|
||||
}
|
||||
async fn recent_history_including_speculative<const N: usize>(
|
||||
this: Expr<Self>,
|
||||
sim: &mut ExternModuleSimulationState,
|
||||
) -> [bool; N] {
|
||||
let head = *sim.read(this.speculative_head).await;
|
||||
Self::history_from_head(this, sim, head).await
|
||||
}
|
||||
async fn speculative_full(this: Expr<Self>, sim: &mut ExternModuleSimulationState) -> bool {
|
||||
let speculative_head = *sim.read(this.speculative_head).await;
|
||||
Self::next_pos(speculative_head) == *sim.read(this.tail).await
|
||||
}
|
||||
async fn try_push_speculative(
|
||||
this: Expr<Self>,
|
||||
sim: &mut ExternModuleSimulationState,
|
||||
value: bool,
|
||||
) -> Result<(), BranchHistoryTryPushSpeculativeError> {
|
||||
if Self::speculative_full(this, sim).await {
|
||||
Err(BranchHistoryTryPushSpeculativeError::NoSpace)
|
||||
} else {
|
||||
let speculative_head = *sim.read(this.speculative_head).await;
|
||||
let speculative_head = Self::next_pos(speculative_head);
|
||||
sim.write(this.speculative_head, speculative_head).await;
|
||||
sim.write(this.history[speculative_head], value).await;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
async fn try_push_non_speculative(
|
||||
this: Expr<Self>,
|
||||
sim: &mut ExternModuleSimulationState,
|
||||
value: bool,
|
||||
) -> Result<(), BranchHistoryTryPushNonSpeculativeError> {
|
||||
let speculative_head = *sim.read(this.speculative_head).await;
|
||||
let non_speculative_head = *sim.read(this.non_speculative_head).await;
|
||||
if speculative_head == non_speculative_head {
|
||||
Err(BranchHistoryTryPushNonSpeculativeError::NoSpace)
|
||||
} else {
|
||||
let pos = Self::next_pos(non_speculative_head);
|
||||
let speculated = sim.read_bool(this.history[pos]).await;
|
||||
if speculated != value {
|
||||
Err(BranchHistoryTryPushNonSpeculativeError::Misprediction { speculated })
|
||||
} else {
|
||||
sim.write(this.non_speculative_head, pos).await;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
pub struct NextPcState {
|
||||
speculative_call_stack: CallStack,
|
||||
non_speculative_call_stack: CallStack,
|
||||
branch_target_buffer: BranchTargetBuffer,
|
||||
branch_history: BranchHistory,
|
||||
branch_predictor: Array<SimOnly<BranchPredictionState>, { NextPcState::BRANCH_PREDICTOR_SIZE }>,
|
||||
}
|
||||
|
||||
impl NextPcState {
|
||||
const BRANCH_PREDICTOR_LOG2_SIZE: usize = 8;
|
||||
const BRANCH_PREDICTOR_SIZE: usize = 1 << Self::BRANCH_PREDICTOR_LOG2_SIZE;
|
||||
async fn branch_predictor_index(
|
||||
this: Expr<Self>,
|
||||
sim: &mut ExternModuleSimulationState,
|
||||
pc: u64,
|
||||
) -> usize {
|
||||
let mut history = 0u64;
|
||||
let history_bits: [bool; Self::BRANCH_PREDICTOR_LOG2_SIZE] =
|
||||
BranchHistory::recent_history_including_speculative(this.branch_history, sim).await;
|
||||
for history_bit in history_bits {
|
||||
history <<= 1;
|
||||
if history_bit {
|
||||
history |= 1;
|
||||
}
|
||||
}
|
||||
let mut t = history;
|
||||
t ^= t.rotate_left(5) & !pc.rotate_right(3);
|
||||
t ^= pc;
|
||||
t ^= !t.rotate_left(2) & t.rotate_left(4);
|
||||
let mut retval = 0;
|
||||
for i in (0..Self::BRANCH_PREDICTOR_LOG2_SIZE).step_by(Self::BRANCH_PREDICTOR_LOG2_SIZE) {
|
||||
retval ^= t >> i;
|
||||
}
|
||||
retval as usize % Self::BRANCH_PREDICTOR_SIZE
|
||||
}
|
||||
}
|
||||
|
||||
impl SimValueDefault for NextPcState {
|
||||
#[hdl]
|
||||
fn sim_value_default(self) -> SimValue<Self> {
|
||||
let Self {
|
||||
speculative_call_stack,
|
||||
non_speculative_call_stack,
|
||||
branch_target_buffer,
|
||||
branch_history,
|
||||
branch_predictor,
|
||||
} = self;
|
||||
#[hdl(sim)]
|
||||
Self {
|
||||
speculative_call_stack: speculative_call_stack.sim_value_default(),
|
||||
non_speculative_call_stack: non_speculative_call_stack.sim_value_default(),
|
||||
branch_target_buffer: branch_target_buffer.sim_value_default(),
|
||||
branch_history: branch_history.sim_value_default(),
|
||||
// use something other than the default so you can see the reset progress
|
||||
branch_predictor: std::array::from_fn(|_| {
|
||||
SimOnlyValue::new(BranchPredictionState::default().towards_not_taken())
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ResetSteps for NextPcState {
|
||||
#[hdl]
|
||||
async fn reset_step(
|
||||
this: Expr<Self>,
|
||||
sim: &mut ExternModuleSimulationState,
|
||||
step: usize,
|
||||
) -> ResetStatus {
|
||||
#[hdl]
|
||||
let NextPcState {
|
||||
speculative_call_stack,
|
||||
non_speculative_call_stack,
|
||||
branch_target_buffer,
|
||||
branch_history,
|
||||
branch_predictor,
|
||||
} = this;
|
||||
let speculative_call_stack =
|
||||
ResetSteps::reset_step(speculative_call_stack, sim, step).await;
|
||||
let non_speculative_call_stack =
|
||||
ResetSteps::reset_step(non_speculative_call_stack, sim, step).await;
|
||||
let branch_target_buffer = ResetSteps::reset_step(branch_target_buffer, sim, step).await;
|
||||
let branch_history = ResetSteps::reset_step(branch_history, sim, step).await;
|
||||
let branch_predictor = ResetSteps::reset_step(branch_predictor, sim, step).await;
|
||||
speculative_call_stack
|
||||
.and(non_speculative_call_stack)
|
||||
.and(branch_target_buffer)
|
||||
.and(branch_history)
|
||||
.and(branch_predictor)
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl_module(extern)]
|
||||
pub fn next_pc(config: PhantomConst<CpuConfig>) {
|
||||
#[hdl]
|
||||
let cd: ClockDomain = m.input();
|
||||
#[hdl]
|
||||
let to_fetch: NextPcToFetchInterface<PhantomConst<CpuConfig>> =
|
||||
m.output(NextPcToFetchInterface[config]);
|
||||
#[hdl]
|
||||
let state_for_debug: NextPcState = m.output();
|
||||
m.extern_module_simulation_fn(
|
||||
(cd, to_fetch, state_for_debug),
|
||||
|(cd, to_fetch, state_for_debug), mut sim| async move {
|
||||
sim.write(state_for_debug, NextPcState.sim_value_default())
|
||||
.await;
|
||||
sim.resettable(
|
||||
cd,
|
||||
|mut sim: ExternModuleSimulationState| async move {
|
||||
sim.write(to_fetch.inner.data, HdlNone()).await;
|
||||
},
|
||||
|mut sim: ExternModuleSimulationState, ()| async move {
|
||||
for step in 0usize.. {
|
||||
sim.wait_for_clock_edge(cd.clk).await;
|
||||
match ResetSteps::reset_step(state_for_debug, &mut sim, step).await {
|
||||
ResetStatus::Done => break,
|
||||
ResetStatus::Working => {}
|
||||
}
|
||||
}
|
||||
// TODO: finish
|
||||
},
|
||||
)
|
||||
.await;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
@ -120,7 +120,10 @@ pub fn unit_free_regs_tracker(
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use fayalite::{firrtl::ExportOptions, module::transform::simplify_enums::SimplifyEnumsKind};
|
||||
use fayalite::{
|
||||
cli::FormalMode, firrtl::ExportOptions,
|
||||
module::transform::simplify_enums::SimplifyEnumsKind, testing::assert_formal,
|
||||
};
|
||||
use std::num::NonZero;
|
||||
|
||||
fn test_unit_free_regs_tracker(
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ use fayalite::{
|
|||
intern::{Intern, Interned},
|
||||
prelude::*,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub mod alu_branch;
|
||||
pub mod unit_base;
|
||||
|
|
@ -37,7 +36,7 @@ macro_rules! all_units {
|
|||
}
|
||||
) => {
|
||||
$(#[$enum_meta])*
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Serialize, Deserialize)]
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
|
||||
$vis enum $UnitKind {
|
||||
$(
|
||||
$(#[$variant_meta])*
|
||||
|
|
|
|||
|
|
@ -1,10 +1,147 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
|
||||
use fayalite::{expr::ops::ExprIndex, int::UIntInRangeInclusiveType, prelude::*};
|
||||
use fayalite::{
|
||||
expr::ops::{ExprCastTo, ExprIndex, ExprPartialEq, ExprPartialOrd},
|
||||
int::SizeType,
|
||||
intern::{Intern, Interned},
|
||||
prelude::*,
|
||||
ty::{MatchVariantWithoutScope, StaticType, TypeProperties},
|
||||
};
|
||||
use std::{marker::PhantomData, ops::Index};
|
||||
|
||||
#[hdl]
|
||||
pub type Length<Max: Size> = UIntInRangeInclusiveType<ConstUsize<0>, Max>;
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct Length<Max: Size> {
|
||||
ty: UInt,
|
||||
_phantom: PhantomData<Max>,
|
||||
}
|
||||
|
||||
impl<Max: Size> Length<Max> {
|
||||
pub fn new(max: Max::SizeType) -> Self {
|
||||
Self {
|
||||
ty: UInt::range_inclusive(0..=Max::as_usize(max)),
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
pub fn ty(self) -> UInt {
|
||||
self.ty
|
||||
}
|
||||
pub fn zero(self) -> Expr<Self> {
|
||||
Self::from_uint_unchecked(self.ty.zero())
|
||||
}
|
||||
pub fn from_uint_unchecked(v: impl ToExpr<Type = UInt>) -> Expr<Self> {
|
||||
Expr::from_canonical(Expr::canonical(v.to_expr()))
|
||||
}
|
||||
pub fn cast_from_uint_unchecked<SrcWidth: Size>(
|
||||
self,
|
||||
v: impl ToExpr<Type = UIntType<SrcWidth>>,
|
||||
) -> Expr<Self> {
|
||||
Self::from_uint_unchecked(v.to_expr().cast_to(self.ty))
|
||||
}
|
||||
pub fn as_uint(this: impl ToExpr<Type = Self>) -> Expr<UInt> {
|
||||
let this = this.to_expr();
|
||||
this.cast_to(Expr::ty(this).ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Max: Size, DestWidth: Size> ExprCastTo<UIntType<DestWidth>> for Length<Max> {
|
||||
fn cast_to(src: Expr<Self>, to_type: UIntType<DestWidth>) -> Expr<UIntType<DestWidth>> {
|
||||
Expr::<UInt>::from_canonical(Expr::canonical(src)).cast_to(to_type)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const Length: __LengthWithoutGenerics = __LengthWithoutGenerics {};
|
||||
|
||||
#[non_exhaustive]
|
||||
pub struct __LengthWithoutGenerics {}
|
||||
|
||||
impl<M: SizeType> Index<M> for __LengthWithoutGenerics {
|
||||
type Output = Length<M::Size>;
|
||||
|
||||
fn index(&self, max: M) -> &Self::Output {
|
||||
Interned::into_inner(Length::new(max).intern_sized())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Max: Size> Type for Length<Max> {
|
||||
type BaseType = UInt;
|
||||
type MaskType = Bool;
|
||||
type MatchVariant = Expr<Self>;
|
||||
type MatchActiveScope = ();
|
||||
type MatchVariantAndInactiveScope = MatchVariantWithoutScope<Self::MatchVariant>;
|
||||
type MatchVariantsIter = std::iter::Once<Self::MatchVariantAndInactiveScope>;
|
||||
fn match_variants(
|
||||
this: Expr<Self>,
|
||||
source_location: SourceLocation,
|
||||
) -> Self::MatchVariantsIter {
|
||||
let _ = source_location;
|
||||
std::iter::once(MatchVariantWithoutScope(this))
|
||||
}
|
||||
|
||||
fn mask_type(&self) -> Self::MaskType {
|
||||
Bool
|
||||
}
|
||||
|
||||
fn canonical(&self) -> CanonicalType {
|
||||
self.ty.canonical()
|
||||
}
|
||||
|
||||
fn from_canonical(canonical_type: CanonicalType) -> Self {
|
||||
let ty = <UInt>::from_canonical(canonical_type);
|
||||
if let Some(known_max) = Max::KNOWN_VALUE {
|
||||
assert_eq!(ty, UInt::range_inclusive(0..=known_max));
|
||||
}
|
||||
Self {
|
||||
ty,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn source_location() -> SourceLocation {
|
||||
SourceLocation::caller()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Max: KnownSize> StaticType for Length<Max> {
|
||||
const TYPE: Self = Self {
|
||||
ty: UInt {
|
||||
width: Max::VALUE.next_power_of_two().ilog2() as usize,
|
||||
},
|
||||
_phantom: PhantomData,
|
||||
};
|
||||
const MASK_TYPE: Self::MaskType = Bool;
|
||||
const TYPE_PROPERTIES: TypeProperties = {
|
||||
let mut p = <UInt<1>>::TYPE_PROPERTIES;
|
||||
p.bit_width = Self::TYPE.ty.width;
|
||||
p
|
||||
};
|
||||
const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES;
|
||||
}
|
||||
|
||||
impl<Max: Size> ExprPartialEq<Self> for Length<Max> {
|
||||
fn cmp_eq(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
Self::as_uint(lhs).cmp_eq(Self::as_uint(rhs))
|
||||
}
|
||||
fn cmp_ne(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
Self::as_uint(lhs).cmp_ne(Self::as_uint(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl<Max: Size> ExprPartialOrd<Self> for Length<Max> {
|
||||
fn cmp_lt(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
Self::as_uint(lhs).cmp_lt(Self::as_uint(rhs))
|
||||
}
|
||||
fn cmp_le(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
Self::as_uint(lhs).cmp_le(Self::as_uint(rhs))
|
||||
}
|
||||
fn cmp_gt(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
Self::as_uint(lhs).cmp_gt(Self::as_uint(rhs))
|
||||
}
|
||||
fn cmp_ge(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||
Self::as_uint(lhs).cmp_ge(Self::as_uint(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
/// like [`std::vec::Vec`], except with a [`Expr`] for [`len()`][`Self::len()`] and a fixed capacity
|
||||
#[hdl]
|
||||
|
|
@ -19,7 +156,7 @@ impl<T: Type, N: Size> ArrayVec<T, N> {
|
|||
#[hdl]
|
||||
ArrayVec {
|
||||
elements: self.elements.uninit(),
|
||||
len: 0u8.cast_to(self.len),
|
||||
len: self.len.zero(),
|
||||
}
|
||||
}
|
||||
pub fn element(self) -> T {
|
||||
|
|
@ -39,7 +176,7 @@ impl<T: Type, N: Size> ArrayVec<T, N> {
|
|||
let elements = elements.to_expr();
|
||||
let len = len.to_expr();
|
||||
assert_eq!(
|
||||
Length[N::from_usize(Expr::ty(elements).len())],
|
||||
Length::new(N::from_usize(Expr::ty(elements).len())),
|
||||
Expr::ty(len),
|
||||
"len type mismatch",
|
||||
);
|
||||
|
|
@ -54,7 +191,7 @@ impl<T: Type, N: Size> ArrayVec<T, N> {
|
|||
}
|
||||
pub fn is_empty(this: impl ToExpr<Type = Self>) -> Expr<Bool> {
|
||||
let len = Self::len(this);
|
||||
len.cmp_eq(0u8)
|
||||
len.cmp_eq(Expr::ty(len).zero())
|
||||
}
|
||||
pub fn capacity(self) -> usize {
|
||||
self.elements.len()
|
||||
|
|
@ -70,7 +207,7 @@ impl<T: Type, N: Size> ArrayVec<T, N> {
|
|||
let this = this.to_expr();
|
||||
for (index, element) in this.elements.into_iter().enumerate() {
|
||||
#[hdl]
|
||||
if index.cmp_lt(this.len) {
|
||||
if index.cmp_lt(Length::as_uint(this.len)) {
|
||||
f(index, element);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16832,6 +16832,38 @@ $upscope $end
|
|||
$upscope $end
|
||||
$enddefinitions $end
|
||||
$dumpvars
|
||||
0vg
|
||||
0wg
|
||||
0xg
|
||||
0yg
|
||||
0zg
|
||||
0{g
|
||||
0|g
|
||||
0}g
|
||||
0~g
|
||||
0!h
|
||||
0"h
|
||||
0#h
|
||||
0$h
|
||||
0%h
|
||||
0&h
|
||||
0'h
|
||||
0(h
|
||||
0)h
|
||||
0*h
|
||||
0+h
|
||||
0,h
|
||||
0-h
|
||||
0.h
|
||||
0/h
|
||||
00h
|
||||
01h
|
||||
02h
|
||||
03h
|
||||
04h
|
||||
05h
|
||||
06h
|
||||
07h
|
||||
b0 (_
|
||||
b0 ia
|
||||
b0 )_
|
||||
|
|
@ -17338,26 +17370,6 @@ b0 ga
|
|||
b0 Jd
|
||||
b0 ha
|
||||
b0 Kd
|
||||
b0 Ld
|
||||
b0 Nd
|
||||
b0 Md
|
||||
b0 Od
|
||||
0Pd
|
||||
0Qd
|
||||
0Rd
|
||||
0Sd
|
||||
0Td
|
||||
0Ud
|
||||
0Vd
|
||||
0Wd
|
||||
0Xd
|
||||
0Yd
|
||||
0Zd
|
||||
0[d
|
||||
0\d
|
||||
0]d
|
||||
0^d
|
||||
0_d
|
||||
0`d
|
||||
0ad
|
||||
0bd
|
||||
|
|
@ -17374,326 +17386,6 @@ b0 Od
|
|||
0md
|
||||
0nd
|
||||
0od
|
||||
b0 pd
|
||||
0"e
|
||||
02e
|
||||
0Be
|
||||
0Re
|
||||
0be
|
||||
0re
|
||||
0$f
|
||||
04f
|
||||
b0 qd
|
||||
0#e
|
||||
03e
|
||||
0Ce
|
||||
0Se
|
||||
0ce
|
||||
0se
|
||||
0%f
|
||||
05f
|
||||
b0 rd
|
||||
0$e
|
||||
04e
|
||||
0De
|
||||
0Te
|
||||
0de
|
||||
0te
|
||||
0&f
|
||||
06f
|
||||
b0 sd
|
||||
0%e
|
||||
05e
|
||||
0Ee
|
||||
0Ue
|
||||
0ee
|
||||
0ue
|
||||
0'f
|
||||
07f
|
||||
b0 td
|
||||
0&e
|
||||
06e
|
||||
0Fe
|
||||
0Ve
|
||||
0fe
|
||||
0ve
|
||||
0(f
|
||||
08f
|
||||
b0 ud
|
||||
0'e
|
||||
07e
|
||||
0Ge
|
||||
0We
|
||||
0ge
|
||||
0we
|
||||
0)f
|
||||
09f
|
||||
b0 vd
|
||||
0(e
|
||||
08e
|
||||
0He
|
||||
0Xe
|
||||
0he
|
||||
0xe
|
||||
0*f
|
||||
0:f
|
||||
b0 wd
|
||||
0)e
|
||||
09e
|
||||
0Ie
|
||||
0Ye
|
||||
0ie
|
||||
0ye
|
||||
0+f
|
||||
0;f
|
||||
b0 xd
|
||||
0*e
|
||||
0:e
|
||||
0Je
|
||||
0Ze
|
||||
0je
|
||||
0ze
|
||||
0,f
|
||||
0<f
|
||||
b0 yd
|
||||
0+e
|
||||
0;e
|
||||
0Ke
|
||||
0[e
|
||||
0ke
|
||||
0{e
|
||||
0-f
|
||||
0=f
|
||||
b0 zd
|
||||
0,e
|
||||
0<e
|
||||
0Le
|
||||
0\e
|
||||
0le
|
||||
0|e
|
||||
0.f
|
||||
0>f
|
||||
b0 {d
|
||||
0-e
|
||||
0=e
|
||||
0Me
|
||||
0]e
|
||||
0me
|
||||
0}e
|
||||
0/f
|
||||
0?f
|
||||
b0 |d
|
||||
0.e
|
||||
0>e
|
||||
0Ne
|
||||
0^e
|
||||
0ne
|
||||
0~e
|
||||
00f
|
||||
0@f
|
||||
b0 }d
|
||||
0/e
|
||||
0?e
|
||||
0Oe
|
||||
0_e
|
||||
0oe
|
||||
0!f
|
||||
01f
|
||||
0Af
|
||||
b0 ~d
|
||||
00e
|
||||
0@e
|
||||
0Pe
|
||||
0`e
|
||||
0pe
|
||||
0"f
|
||||
02f
|
||||
0Bf
|
||||
b0 !e
|
||||
01e
|
||||
0Ae
|
||||
0Qe
|
||||
0ae
|
||||
0qe
|
||||
0#f
|
||||
03f
|
||||
0Cf
|
||||
b0 Df
|
||||
0Tf
|
||||
0df
|
||||
0tf
|
||||
0&g
|
||||
06g
|
||||
0Fg
|
||||
0Vg
|
||||
0fg
|
||||
b0 Ef
|
||||
0Uf
|
||||
0ef
|
||||
0uf
|
||||
0'g
|
||||
07g
|
||||
0Gg
|
||||
0Wg
|
||||
0gg
|
||||
b0 Ff
|
||||
0Vf
|
||||
0ff
|
||||
0vf
|
||||
0(g
|
||||
08g
|
||||
0Hg
|
||||
0Xg
|
||||
0hg
|
||||
b0 Gf
|
||||
0Wf
|
||||
0gf
|
||||
0wf
|
||||
0)g
|
||||
09g
|
||||
0Ig
|
||||
0Yg
|
||||
0ig
|
||||
b0 Hf
|
||||
0Xf
|
||||
0hf
|
||||
0xf
|
||||
0*g
|
||||
0:g
|
||||
0Jg
|
||||
0Zg
|
||||
0jg
|
||||
b0 If
|
||||
0Yf
|
||||
0if
|
||||
0yf
|
||||
0+g
|
||||
0;g
|
||||
0Kg
|
||||
0[g
|
||||
0kg
|
||||
b0 Jf
|
||||
0Zf
|
||||
0jf
|
||||
0zf
|
||||
0,g
|
||||
0<g
|
||||
0Lg
|
||||
0\g
|
||||
0lg
|
||||
b0 Kf
|
||||
0[f
|
||||
0kf
|
||||
0{f
|
||||
0-g
|
||||
0=g
|
||||
0Mg
|
||||
0]g
|
||||
0mg
|
||||
b0 Lf
|
||||
0\f
|
||||
0lf
|
||||
0|f
|
||||
0.g
|
||||
0>g
|
||||
0Ng
|
||||
0^g
|
||||
0ng
|
||||
b0 Mf
|
||||
0]f
|
||||
0mf
|
||||
0}f
|
||||
0/g
|
||||
0?g
|
||||
0Og
|
||||
0_g
|
||||
0og
|
||||
b0 Nf
|
||||
0^f
|
||||
0nf
|
||||
0~f
|
||||
00g
|
||||
0@g
|
||||
0Pg
|
||||
0`g
|
||||
0pg
|
||||
b0 Of
|
||||
0_f
|
||||
0of
|
||||
0!g
|
||||
01g
|
||||
0Ag
|
||||
0Qg
|
||||
0ag
|
||||
0qg
|
||||
b0 Pf
|
||||
0`f
|
||||
0pf
|
||||
0"g
|
||||
02g
|
||||
0Bg
|
||||
0Rg
|
||||
0bg
|
||||
0rg
|
||||
b0 Qf
|
||||
0af
|
||||
0qf
|
||||
0#g
|
||||
03g
|
||||
0Cg
|
||||
0Sg
|
||||
0cg
|
||||
0sg
|
||||
b0 Rf
|
||||
0bf
|
||||
0rf
|
||||
0$g
|
||||
04g
|
||||
0Dg
|
||||
0Tg
|
||||
0dg
|
||||
0tg
|
||||
b0 Sf
|
||||
0cf
|
||||
0sf
|
||||
0%g
|
||||
05g
|
||||
0Eg
|
||||
0Ug
|
||||
0eg
|
||||
0ug
|
||||
0vg
|
||||
0wg
|
||||
0xg
|
||||
0yg
|
||||
0zg
|
||||
0{g
|
||||
0|g
|
||||
0}g
|
||||
0~g
|
||||
0!h
|
||||
0"h
|
||||
0#h
|
||||
0$h
|
||||
0%h
|
||||
0&h
|
||||
0'h
|
||||
0(h
|
||||
0)h
|
||||
0*h
|
||||
0+h
|
||||
0,h
|
||||
0-h
|
||||
0.h
|
||||
0/h
|
||||
00h
|
||||
01h
|
||||
02h
|
||||
03h
|
||||
04h
|
||||
05h
|
||||
06h
|
||||
07h
|
||||
b0 8h
|
||||
0Hh
|
||||
0Xh
|
||||
|
|
@ -17838,6 +17530,150 @@ b0 Gh
|
|||
0Ii
|
||||
0Yi
|
||||
0ii
|
||||
b0 Df
|
||||
0Tf
|
||||
0df
|
||||
0tf
|
||||
0&g
|
||||
06g
|
||||
0Fg
|
||||
0Vg
|
||||
0fg
|
||||
b0 Ef
|
||||
0Uf
|
||||
0ef
|
||||
0uf
|
||||
0'g
|
||||
07g
|
||||
0Gg
|
||||
0Wg
|
||||
0gg
|
||||
b0 Ff
|
||||
0Vf
|
||||
0ff
|
||||
0vf
|
||||
0(g
|
||||
08g
|
||||
0Hg
|
||||
0Xg
|
||||
0hg
|
||||
b0 Gf
|
||||
0Wf
|
||||
0gf
|
||||
0wf
|
||||
0)g
|
||||
09g
|
||||
0Ig
|
||||
0Yg
|
||||
0ig
|
||||
b0 Hf
|
||||
0Xf
|
||||
0hf
|
||||
0xf
|
||||
0*g
|
||||
0:g
|
||||
0Jg
|
||||
0Zg
|
||||
0jg
|
||||
b0 If
|
||||
0Yf
|
||||
0if
|
||||
0yf
|
||||
0+g
|
||||
0;g
|
||||
0Kg
|
||||
0[g
|
||||
0kg
|
||||
b0 Jf
|
||||
0Zf
|
||||
0jf
|
||||
0zf
|
||||
0,g
|
||||
0<g
|
||||
0Lg
|
||||
0\g
|
||||
0lg
|
||||
b0 Kf
|
||||
0[f
|
||||
0kf
|
||||
0{f
|
||||
0-g
|
||||
0=g
|
||||
0Mg
|
||||
0]g
|
||||
0mg
|
||||
b0 Lf
|
||||
0\f
|
||||
0lf
|
||||
0|f
|
||||
0.g
|
||||
0>g
|
||||
0Ng
|
||||
0^g
|
||||
0ng
|
||||
b0 Mf
|
||||
0]f
|
||||
0mf
|
||||
0}f
|
||||
0/g
|
||||
0?g
|
||||
0Og
|
||||
0_g
|
||||
0og
|
||||
b0 Nf
|
||||
0^f
|
||||
0nf
|
||||
0~f
|
||||
00g
|
||||
0@g
|
||||
0Pg
|
||||
0`g
|
||||
0pg
|
||||
b0 Of
|
||||
0_f
|
||||
0of
|
||||
0!g
|
||||
01g
|
||||
0Ag
|
||||
0Qg
|
||||
0ag
|
||||
0qg
|
||||
b0 Pf
|
||||
0`f
|
||||
0pf
|
||||
0"g
|
||||
02g
|
||||
0Bg
|
||||
0Rg
|
||||
0bg
|
||||
0rg
|
||||
b0 Qf
|
||||
0af
|
||||
0qf
|
||||
0#g
|
||||
03g
|
||||
0Cg
|
||||
0Sg
|
||||
0cg
|
||||
0sg
|
||||
b0 Rf
|
||||
0bf
|
||||
0rf
|
||||
0$g
|
||||
04g
|
||||
0Dg
|
||||
0Tg
|
||||
0dg
|
||||
0tg
|
||||
b0 Sf
|
||||
0cf
|
||||
0sf
|
||||
0%g
|
||||
05g
|
||||
0Eg
|
||||
0Ug
|
||||
0eg
|
||||
0ug
|
||||
b0 ji
|
||||
0zi
|
||||
0,j
|
||||
|
|
@ -17982,6 +17818,170 @@ b0 yi
|
|||
0{j
|
||||
0-k
|
||||
0=k
|
||||
b0 pd
|
||||
0"e
|
||||
02e
|
||||
0Be
|
||||
0Re
|
||||
0be
|
||||
0re
|
||||
0$f
|
||||
04f
|
||||
b0 qd
|
||||
0#e
|
||||
03e
|
||||
0Ce
|
||||
0Se
|
||||
0ce
|
||||
0se
|
||||
0%f
|
||||
05f
|
||||
b0 rd
|
||||
0$e
|
||||
04e
|
||||
0De
|
||||
0Te
|
||||
0de
|
||||
0te
|
||||
0&f
|
||||
06f
|
||||
b0 sd
|
||||
0%e
|
||||
05e
|
||||
0Ee
|
||||
0Ue
|
||||
0ee
|
||||
0ue
|
||||
0'f
|
||||
07f
|
||||
b0 td
|
||||
0&e
|
||||
06e
|
||||
0Fe
|
||||
0Ve
|
||||
0fe
|
||||
0ve
|
||||
0(f
|
||||
08f
|
||||
b0 ud
|
||||
0'e
|
||||
07e
|
||||
0Ge
|
||||
0We
|
||||
0ge
|
||||
0we
|
||||
0)f
|
||||
09f
|
||||
b0 vd
|
||||
0(e
|
||||
08e
|
||||
0He
|
||||
0Xe
|
||||
0he
|
||||
0xe
|
||||
0*f
|
||||
0:f
|
||||
b0 wd
|
||||
0)e
|
||||
09e
|
||||
0Ie
|
||||
0Ye
|
||||
0ie
|
||||
0ye
|
||||
0+f
|
||||
0;f
|
||||
b0 xd
|
||||
0*e
|
||||
0:e
|
||||
0Je
|
||||
0Ze
|
||||
0je
|
||||
0ze
|
||||
0,f
|
||||
0<f
|
||||
b0 yd
|
||||
0+e
|
||||
0;e
|
||||
0Ke
|
||||
0[e
|
||||
0ke
|
||||
0{e
|
||||
0-f
|
||||
0=f
|
||||
b0 zd
|
||||
0,e
|
||||
0<e
|
||||
0Le
|
||||
0\e
|
||||
0le
|
||||
0|e
|
||||
0.f
|
||||
0>f
|
||||
b0 {d
|
||||
0-e
|
||||
0=e
|
||||
0Me
|
||||
0]e
|
||||
0me
|
||||
0}e
|
||||
0/f
|
||||
0?f
|
||||
b0 |d
|
||||
0.e
|
||||
0>e
|
||||
0Ne
|
||||
0^e
|
||||
0ne
|
||||
0~e
|
||||
00f
|
||||
0@f
|
||||
b0 }d
|
||||
0/e
|
||||
0?e
|
||||
0Oe
|
||||
0_e
|
||||
0oe
|
||||
0!f
|
||||
01f
|
||||
0Af
|
||||
b0 ~d
|
||||
00e
|
||||
0@e
|
||||
0Pe
|
||||
0`e
|
||||
0pe
|
||||
0"f
|
||||
02f
|
||||
0Bf
|
||||
b0 !e
|
||||
01e
|
||||
0Ae
|
||||
0Qe
|
||||
0ae
|
||||
0qe
|
||||
0#f
|
||||
03f
|
||||
0Cf
|
||||
0Pd
|
||||
0Qd
|
||||
0Rd
|
||||
0Sd
|
||||
0Td
|
||||
0Ud
|
||||
0Vd
|
||||
0Wd
|
||||
0Xd
|
||||
0Yd
|
||||
0Zd
|
||||
0[d
|
||||
0\d
|
||||
0]d
|
||||
0^d
|
||||
0_d
|
||||
b0 Ld
|
||||
b0 Nd
|
||||
b0 Md
|
||||
b0 Od
|
||||
0!
|
||||
1"
|
||||
sHdlSome\x20(1) #
|
||||
|
|
|
|||
|
|
@ -1,45 +0,0 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
|
||||
use cpu::{
|
||||
config::{CpuConfig, UnitConfig},
|
||||
next_pc::next_pc,
|
||||
unit::UnitKind,
|
||||
};
|
||||
use fayalite::{prelude::*, sim::vcd::VcdWriterDecls, util::RcWriter};
|
||||
use std::num::NonZeroUsize;
|
||||
|
||||
#[hdl]
|
||||
#[test]
|
||||
fn test_next_pc() {
|
||||
let _n = SourceLocation::normalize_files_for_tests();
|
||||
let mut config = CpuConfig::new(
|
||||
vec![
|
||||
UnitConfig::new(UnitKind::AluBranch),
|
||||
UnitConfig::new(UnitKind::AluBranch),
|
||||
],
|
||||
NonZeroUsize::new(20).unwrap(),
|
||||
);
|
||||
config.fetch_width = NonZeroUsize::new(2).unwrap();
|
||||
let m = next_pc(PhantomConst::new_sized(config));
|
||||
let mut sim = Simulation::new(m);
|
||||
let mut writer = RcWriter::default();
|
||||
sim.add_trace_writer(VcdWriterDecls::new(writer.clone()));
|
||||
let to_fetch = sim.io().to_fetch;
|
||||
sim.write_clock(sim.io().cd.clk, false);
|
||||
sim.write_reset(sim.io().cd.rst, true);
|
||||
sim.write_bool(to_fetch.inner.ready, true);
|
||||
for _cycle in 0..300 {
|
||||
sim.advance_time(SimDuration::from_nanos(500));
|
||||
sim.write_clock(sim.io().cd.clk, true);
|
||||
sim.advance_time(SimDuration::from_nanos(500));
|
||||
sim.write_clock(sim.io().cd.clk, false);
|
||||
sim.write_reset(sim.io().cd.rst, false);
|
||||
}
|
||||
// FIXME: vcd is just whatever next_pc does now, which isn't known to be correct
|
||||
let vcd = String::from_utf8(writer.take()).unwrap();
|
||||
println!("####### VCD:\n{vcd}\n#######");
|
||||
if vcd != include_str!("expected/next_pc.vcd") {
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,8 @@ use cpu::{
|
|||
unit::{GlobalState, UnitKind},
|
||||
};
|
||||
use fayalite::{
|
||||
assert_export_firrtl,
|
||||
firrtl::ExportOptions,
|
||||
prelude::*,
|
||||
sim::{Simulation, time::SimDuration, vcd::VcdWriterDecls},
|
||||
util::RcWriter,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue