forked from libre-chip/cpu
Compare commits
66 commits
master
...
create-fet
| Author | SHA1 | Date | |
|---|---|---|---|
| 759c5de5b4 | |||
| c62d33048c | |||
| 596440755c | |||
| 68a4373bbd | |||
| f88346ea37 | |||
| a42b76b468 | |||
| 130c1b2892 | |||
| 167bc4b6a6 | |||
| faa8dde774 | |||
| 1db65ae753 | |||
| 59874b9b29 | |||
| 2ad469e331 | |||
| 0824b63d31 | |||
| 706d54ae0d | |||
| d361a2b578 | |||
| aa07e24c78 | |||
| 29757a568c | |||
| 33529a2296 | |||
| 5e9d0957f6 | |||
| fc8a6cd959 | |||
| 87112c681a | |||
| e6f876f9af | |||
| 9b8d99e9af | |||
| ffc3d4283c | |||
| 0433e4f8f1 | |||
| a93dca25ac | |||
| 85ada6e55a | |||
| 2e05329c36 | |||
| 1fc56e02f9 | |||
| aa85ecab01 | |||
| 62a330ed4d | |||
| c9a3de19b7 | |||
| 7ebcd5de1e | |||
| 3a35a698e2 | |||
| a4b052f5f3 | |||
| 62512960c3 | |||
| b7b6a02777 | |||
| 6d40eaadb3 | |||
| 305d7b0ae6 | |||
| 781dbc6bcb | |||
| 5faf0899a8 | |||
| 8c02483b65 | |||
| e4a7d9f59c | |||
| 3b5104c8fa | |||
| 2de4a67360 | |||
| d5a7d9dd9e | |||
| 59da0aec06 | |||
| 5e1238b5c7 | |||
| bc9a3a5ce7 | |||
| d42f010cda | |||
| 84e4fde512 | |||
| 8ab63f3c6a | |||
| f39f40ce1f | |||
| cbd52c60a8 | |||
| c87a1b8e1e | |||
| cfd04469ce | |||
| 231f5e72ec | |||
| 033d5d4f34 | |||
| 7a77c02cda | |||
| 61d52bd028 | |||
| 554238c544 | |||
| 24d6537ffe | |||
| c30bd0737f | |||
| 291ad59b02 | |||
| 5e8bc3e580 | |||
| 0e7a518bd0 |
48 changed files with 526149 additions and 36571 deletions
|
|
@ -1,77 +0,0 @@
|
||||||
# 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,57 +3,18 @@
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
deps:
|
|
||||||
runs-on: debian-12
|
|
||||||
uses: ./.forgejo/workflows/deps.yml
|
|
||||||
test:
|
test:
|
||||||
runs-on: debian-12
|
runs-on: debian-12
|
||||||
needs: deps
|
container:
|
||||||
|
image: git.libre-chip.org/libre-chip/fayalite-deps:latest
|
||||||
steps:
|
steps:
|
||||||
- uses: https://git.libre-chip.org/mirrors/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- run: |
|
- run: |
|
||||||
scripts/check-copyright.sh
|
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
|
- uses: https://git.libre-chip.org/mirrors/rust-cache@v2
|
||||||
with:
|
with:
|
||||||
save-if: ${{ github.ref == 'refs/heads/master' }}
|
save-if: ${{ github.ref == 'refs/heads/master' }}
|
||||||
|
- run: rustup override set 1.93.0
|
||||||
- run: cargo test
|
- run: cargo test
|
||||||
|
|
|
||||||
3
.gitattributes
vendored
Normal file
3
.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
# See Notices.txt for copyright information
|
||||||
|
*.vcd linguist-generated=true
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,3 +1,4 @@
|
||||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
# See Notices.txt for copyright information
|
# See Notices.txt for copyright information
|
||||||
/target
|
/target
|
||||||
|
OPF_PowerISA_v3.1C.pdf
|
||||||
|
|
|
||||||
616
Cargo.lock
generated
616
Cargo.lock
generated
|
|
@ -1,17 +1,20 @@
|
||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 4
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ahash"
|
name = "adler2"
|
||||||
version = "0.8.11"
|
version = "2.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "1.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"memchr",
|
||||||
"once_cell",
|
|
||||||
"version_check",
|
|
||||||
"zerocopy",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -93,6 +96,36 @@ version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
|
checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base16ct"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fd307490d624467aa6f74b0eabb77633d1f758a7b25f12bceb0b22e08d9726f6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.22.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bindgen"
|
||||||
|
version = "0.71.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"cexpr",
|
||||||
|
"clang-sys",
|
||||||
|
"itertools",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"regex",
|
||||||
|
"rustc-hash",
|
||||||
|
"shlex",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.6.0"
|
version = "2.6.0"
|
||||||
|
|
@ -136,20 +169,47 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "bytes"
|
||||||
version = "1.1.28"
|
version = "1.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2e80e3b6a3ab07840e1cae9b0666a63970dc28e8ed5ffbcdacbfc760c281bfc1"
|
checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.2.51"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"find-msvc-tools",
|
||||||
"shlex",
|
"shlex",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cexpr"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
|
||||||
|
dependencies = [
|
||||||
|
"nom",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clang-sys"
|
||||||
|
version = "1.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
|
||||||
|
dependencies = [
|
||||||
|
"glob",
|
||||||
|
"libc",
|
||||||
|
"libloading",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.20"
|
version = "4.5.20"
|
||||||
|
|
@ -172,6 +232,15 @@ dependencies = [
|
||||||
"strsim",
|
"strsim",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_complete"
|
||||||
|
version = "4.5.59"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2348487adcd4631696ced64ccdb40d38ac4d31cae7f2eec8817fcea1b9d1c43c"
|
||||||
|
dependencies = [
|
||||||
|
"clap",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_derive"
|
name = "clap_derive"
|
||||||
version = "4.5.18"
|
version = "4.5.18"
|
||||||
|
|
@ -206,7 +275,17 @@ checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6"
|
||||||
name = "cpu"
|
name = "cpu"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"base16ct 1.0.0",
|
||||||
"fayalite",
|
"fayalite",
|
||||||
|
"hex-literal",
|
||||||
|
"parse_powerisa_pdf",
|
||||||
|
"regex",
|
||||||
|
"roxmltree",
|
||||||
|
"serde",
|
||||||
|
"sha2",
|
||||||
|
"simple-mermaid",
|
||||||
|
"ureq",
|
||||||
|
"which",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -218,6 +297,15 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crc32fast"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crypto-common"
|
name = "crypto-common"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
|
|
@ -273,12 +361,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "errno"
|
name = "errno"
|
||||||
version = "0.3.9"
|
version = "0.3.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
|
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -300,20 +388,23 @@ checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fayalite"
|
name = "fayalite"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#bd75fdfefd642f6dd2210cfb003fa63f9dce114e"
|
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#c632e5d570d4763e8e18d764e95b7a9e515ebf99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"base64",
|
||||||
"bitvec",
|
"bitvec",
|
||||||
"blake3",
|
"blake3",
|
||||||
"clap",
|
"clap",
|
||||||
|
"clap_complete",
|
||||||
"ctor",
|
"ctor",
|
||||||
"eyre",
|
"eyre",
|
||||||
"fayalite-proc-macros",
|
"fayalite-proc-macros",
|
||||||
"fayalite-visit-gen",
|
"fayalite-visit-gen",
|
||||||
"hashbrown",
|
"hashbrown 0.15.5",
|
||||||
"jobslot",
|
"jobslot",
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"os_pipe",
|
"once_cell",
|
||||||
|
"ordered-float",
|
||||||
"petgraph",
|
"petgraph",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
|
@ -325,7 +416,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fayalite-proc-macros"
|
name = "fayalite-proc-macros"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#bd75fdfefd642f6dd2210cfb003fa63f9dce114e"
|
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#c632e5d570d4763e8e18d764e95b7a9e515ebf99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fayalite-proc-macros-impl",
|
"fayalite-proc-macros-impl",
|
||||||
]
|
]
|
||||||
|
|
@ -333,9 +424,9 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fayalite-proc-macros-impl"
|
name = "fayalite-proc-macros-impl"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#bd75fdfefd642f6dd2210cfb003fa63f9dce114e"
|
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#c632e5d570d4763e8e18d764e95b7a9e515ebf99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base16ct",
|
"base16ct 0.2.0",
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"prettyplease",
|
"prettyplease",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
|
@ -348,7 +439,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fayalite-visit-gen"
|
name = "fayalite-visit-gen"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#bd75fdfefd642f6dd2210cfb003fa63f9dce114e"
|
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#c632e5d570d4763e8e18d764e95b7a9e515ebf99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"prettyplease",
|
"prettyplease",
|
||||||
|
|
@ -360,12 +451,34 @@ dependencies = [
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "find-msvc-tools"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fixedbitset"
|
name = "fixedbitset"
|
||||||
version = "0.5.7"
|
version = "0.5.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
|
checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "flate2"
|
||||||
|
version = "1.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb"
|
||||||
|
dependencies = [
|
||||||
|
"crc32fast",
|
||||||
|
"miniz_oxide",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foldhash"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "funty"
|
name = "funty"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
|
|
@ -384,9 +497,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.15"
|
version = "0.2.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
|
|
@ -394,21 +507,52 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "getrandom"
|
||||||
version = "0.14.5"
|
version = "0.3.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"cfg-if",
|
||||||
"allocator-api2",
|
"libc",
|
||||||
|
"r-efi",
|
||||||
|
"wasip2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "glob"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.15.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
||||||
|
dependencies = [
|
||||||
|
"allocator-api2",
|
||||||
|
"equivalent",
|
||||||
|
"foldhash",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.16.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex-literal"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e712f64ec3850b98572bffac52e2c6f282b29fe6c5fa6d42334b30be438d95c1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "home"
|
name = "home"
|
||||||
version = "0.5.9"
|
version = "0.5.9"
|
||||||
|
|
@ -418,6 +562,22 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "http"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"itoa",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httparse"
|
||||||
|
version = "1.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indenter"
|
name = "indenter"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
|
|
@ -426,13 +586,14 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.5.0"
|
version = "2.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
|
checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown",
|
"hashbrown 0.16.1",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -441,6 +602,15 @@ version = "1.70.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.11"
|
version = "1.0.11"
|
||||||
|
|
@ -449,23 +619,39 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jobslot"
|
name = "jobslot"
|
||||||
version = "0.2.19"
|
version = "0.2.23"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fe10868679d7a24c2c67d862d0e64a342ce9aef7cdde9ce8019bd35d353d458d"
|
checksum = "58715c67c327da7f1558708348d68c207fd54900c4ae0529e29305d04d795b8c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"derive_destructure2",
|
"derive_destructure2",
|
||||||
"getrandom",
|
"getrandom 0.3.4",
|
||||||
"libc",
|
"libc",
|
||||||
"scopeguard",
|
"scopeguard",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.159"
|
version = "0.2.180"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
|
checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libloading"
|
||||||
|
version = "0.8.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"windows-link",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libm"
|
||||||
|
version = "0.2.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
|
|
@ -473,12 +659,57 @@ version = "0.4.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.29"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.7.4"
|
version = "2.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "minimal-lexical"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "miniz_oxide"
|
||||||
|
version = "0.8.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
|
||||||
|
dependencies = [
|
||||||
|
"adler2",
|
||||||
|
"simd-adler32",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mupdf-sys"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "13e9a0d4e844ab50315d43312f3d62f72c77205b07c8ee21cbd4b52bdc2a9910"
|
||||||
|
dependencies = [
|
||||||
|
"bindgen",
|
||||||
|
"cc",
|
||||||
|
"pkg-config",
|
||||||
|
"regex",
|
||||||
|
"zerocopy",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nom"
|
||||||
|
version = "7.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
"minimal-lexical",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-bigint"
|
name = "num-bigint"
|
||||||
version = "0.4.6"
|
version = "0.4.6"
|
||||||
|
|
@ -509,29 +740,56 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.20.2"
|
version = "1.21.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "os_pipe"
|
name = "ordered-float"
|
||||||
version = "1.2.1"
|
version = "5.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982"
|
checksum = "7f4779c6901a562440c3786d08192c6fbda7c1c2060edd10006b05ee35d10f2d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"num-traits",
|
||||||
"windows-sys 0.59.0",
|
"rand",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parse_powerisa_pdf"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "git+https://git.libre-chip.org/libre-chip/parse_powerisa_pdf.git?branch=master#38a1fb328bd44f26389c28fbf66716154f4113dc"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap",
|
||||||
|
"libm",
|
||||||
|
"mupdf-sys",
|
||||||
|
"quick-xml",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "percent-encoding"
|
||||||
|
version = "2.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "petgraph"
|
name = "petgraph"
|
||||||
version = "0.6.5"
|
version = "0.8.3"
|
||||||
source = "git+https://github.com/programmerjake/petgraph.git?rev=258ea8071209a924b73fe96f9f87a3b7b45cbc9f#258ea8071209a924b73fe96f9f87a3b7b45cbc9f"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fixedbitset",
|
"fixedbitset",
|
||||||
|
"hashbrown 0.15.5",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pkg-config"
|
||||||
|
version = "0.3.32"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "prettyplease"
|
name = "prettyplease"
|
||||||
version = "0.2.22"
|
version = "0.2.22"
|
||||||
|
|
@ -551,6 +809,15 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quick-xml"
|
||||||
|
version = "0.38.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.37"
|
version = "1.0.37"
|
||||||
|
|
@ -560,12 +827,95 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "r-efi"
|
||||||
|
version = "5.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "radium"
|
name = "radium"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
|
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 = "regex"
|
||||||
|
version = "1.12.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-automata",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.4.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.8.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ring"
|
||||||
|
version = "0.17.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"cfg-if",
|
||||||
|
"getrandom 0.2.16",
|
||||||
|
"libc",
|
||||||
|
"untrusted",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "roxmltree"
|
||||||
|
version = "0.21.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f1964b10c76125c36f8afe190065a4bf9a87bf324842c05701330bba9f1cacbb"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-hash"
|
||||||
|
version = "2.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.37"
|
version = "0.38.37"
|
||||||
|
|
@ -579,6 +929,41 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls"
|
||||||
|
version = "0.23.36"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"once_cell",
|
||||||
|
"ring",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"rustls-webpki",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-pki-types"
|
||||||
|
version = "1.13.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282"
|
||||||
|
dependencies = [
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-webpki"
|
||||||
|
version = "0.103.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52"
|
||||||
|
dependencies = [
|
||||||
|
"ring",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"untrusted",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.18"
|
version = "1.0.18"
|
||||||
|
|
@ -593,18 +978,28 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.210"
|
version = "1.0.228"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
|
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||||
|
dependencies = [
|
||||||
|
"serde_core",
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_core"
|
||||||
|
version = "1.0.228"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.210"
|
version = "1.0.228"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
|
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
@ -626,9 +1021,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha2"
|
name = "sha2"
|
||||||
version = "0.10.8"
|
version = "0.10.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"cpufeatures",
|
"cpufeatures",
|
||||||
|
|
@ -641,12 +1036,30 @@ version = "1.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simd-adler32"
|
||||||
|
version = "0.3.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simple-mermaid"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "589144a964b4b30fe3a83b4bb1a09e2475aac194ec832a046a23e75bddf9eb29"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "subtle"
|
||||||
|
version = "2.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.96"
|
version = "2.0.96"
|
||||||
|
|
@ -709,6 +1122,47 @@ version = "1.0.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
|
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "untrusted"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ureq"
|
||||||
|
version = "3.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d39cb1dbab692d82a977c0392ffac19e188bd9186a9f32806f0aaa859d75585a"
|
||||||
|
dependencies = [
|
||||||
|
"base64",
|
||||||
|
"flate2",
|
||||||
|
"log",
|
||||||
|
"percent-encoding",
|
||||||
|
"rustls",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"ureq-proto",
|
||||||
|
"utf-8",
|
||||||
|
"webpki-roots",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ureq-proto"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d81f9efa9df032be5934a46a068815a10a042b494b6a58cb0a1a97bb5467ed6f"
|
||||||
|
dependencies = [
|
||||||
|
"base64",
|
||||||
|
"http",
|
||||||
|
"httparse",
|
||||||
|
"log",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf-8"
|
||||||
|
version = "0.7.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "utf8parse"
|
name = "utf8parse"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
|
|
@ -729,9 +1183,27 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
version = "0.11.1+wasi-snapshot-preview1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasip2"
|
||||||
|
version = "1.0.1+wasi-0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7"
|
||||||
|
dependencies = [
|
||||||
|
"wit-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "webpki-roots"
|
||||||
|
version = "1.0.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c"
|
||||||
|
dependencies = [
|
||||||
|
"rustls-pki-types",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "which"
|
name = "which"
|
||||||
|
|
@ -741,10 +1213,17 @@ checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"either",
|
"either",
|
||||||
"home",
|
"home",
|
||||||
|
"regex",
|
||||||
"rustix",
|
"rustix",
|
||||||
"winsafe",
|
"winsafe",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-link"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.52.0"
|
version = "0.52.0"
|
||||||
|
|
@ -763,6 +1242,15 @@ dependencies = [
|
||||||
"windows-targets",
|
"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]]
|
[[package]]
|
||||||
name = "windows-targets"
|
name = "windows-targets"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
|
|
@ -833,6 +1321,12 @@ version = "0.0.19"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
|
checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wit-bindgen"
|
||||||
|
version = "0.46.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wyz"
|
name = "wyz"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
|
|
@ -844,20 +1338,26 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.7.35"
|
version = "0.8.27"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zerocopy-derive",
|
"zerocopy-derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy-derive"
|
name = "zerocopy-derive"
|
||||||
version = "0.7.35"
|
version = "0.8.27"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zeroize"
|
||||||
|
version = "1.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
|
||||||
|
|
|
||||||
11
Cargo.toml
11
Cargo.toml
|
|
@ -11,10 +11,19 @@ edition = "2024"
|
||||||
repository = ""
|
repository = ""
|
||||||
keywords = []
|
keywords = []
|
||||||
categories = []
|
categories = []
|
||||||
rust-version = "1.89.0"
|
rust-version = "1.93.0"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
|
base16ct = "1.0.0"
|
||||||
fayalite = { git = "https://git.libre-chip.org/libre-chip/fayalite.git", version = "0.3.0", branch = "master" }
|
fayalite = { git = "https://git.libre-chip.org/libre-chip/fayalite.git", version = "0.3.0", branch = "master" }
|
||||||
|
hex-literal = "1.1.0"
|
||||||
|
parse_powerisa_pdf = { git = "https://git.libre-chip.org/libre-chip/parse_powerisa_pdf.git", version = "0.1.0", branch = "master" }
|
||||||
|
roxmltree = "0.21.1"
|
||||||
|
serde = { version = "1.0.202", features = ["derive"] }
|
||||||
|
sha2 = "0.10.9"
|
||||||
|
simple-mermaid = "0.2.0"
|
||||||
|
ureq = "3.1.4"
|
||||||
|
which = { version = "6.0.3", features = ["regex"] }
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
opt-level = 1
|
opt-level = 1
|
||||||
|
|
|
||||||
15
README.md
Normal file
15
README.md
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
<!--
|
||||||
|
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,3 +16,20 @@ version.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
fayalite.workspace = true
|
fayalite.workspace = true
|
||||||
|
roxmltree.workspace = true
|
||||||
|
serde.workspace = true
|
||||||
|
simple-mermaid.workspace = true
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
base16ct.workspace = true
|
||||||
|
hex-literal.workspace = true
|
||||||
|
parse_powerisa_pdf.workspace = true
|
||||||
|
sha2.workspace = true
|
||||||
|
ureq.workspace = true
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
base16ct.workspace = true
|
||||||
|
hex-literal.workspace = true
|
||||||
|
regex = "1.12.2"
|
||||||
|
sha2.workspace = true
|
||||||
|
which.workspace = true
|
||||||
|
|
|
||||||
1
crates/cpu/README.md
Symbolic link
1
crates/cpu/README.md
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
../../README.md
|
||||||
96
crates/cpu/build.rs
Normal file
96
crates/cpu/build.rs
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use parse_powerisa_pdf::parse_powerisa_pdf_and_generate_xml;
|
||||||
|
use sha2::{Digest, Sha256};
|
||||||
|
use std::{
|
||||||
|
error::Error,
|
||||||
|
io::{ErrorKind, Read},
|
||||||
|
path::Path,
|
||||||
|
};
|
||||||
|
|
||||||
|
const EXPECTED_FILE_SIZE: u64 = 6425593;
|
||||||
|
const EXPECTED_FILE_HASH: &[u8; 32] =
|
||||||
|
&hex_literal::hex!("56372d23ece7e9e2c1b381a639443982a3e16e38109df1c141d655b779b61fdb");
|
||||||
|
|
||||||
|
fn verify_powerisa_file(file: impl std::io::Read) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||||
|
let mut buf = Vec::with_capacity(usize::try_from(EXPECTED_FILE_SIZE)? + 1);
|
||||||
|
file.take(EXPECTED_FILE_SIZE + 1).read_to_end(&mut buf)?;
|
||||||
|
if buf.len() > EXPECTED_FILE_SIZE as usize {
|
||||||
|
Err(format!("file is bigger than the expected length {EXPECTED_FILE_SIZE}").into())
|
||||||
|
} else if buf.len() < EXPECTED_FILE_SIZE as usize {
|
||||||
|
Err(format!(
|
||||||
|
"file is smaller than the expected length {EXPECTED_FILE_SIZE}: actual length {}",
|
||||||
|
buf.len()
|
||||||
|
)
|
||||||
|
.into())
|
||||||
|
} else {
|
||||||
|
let hash = Sha256::digest(&buf);
|
||||||
|
let hash = &*hash;
|
||||||
|
if hash != EXPECTED_FILE_HASH {
|
||||||
|
Err(format!(
|
||||||
|
"file's SHA256 hash doesn't match the expected hash: expected: {:x} got: {:x}",
|
||||||
|
base16ct::HexDisplay(EXPECTED_FILE_HASH),
|
||||||
|
base16ct::HexDisplay(hash)
|
||||||
|
)
|
||||||
|
.into())
|
||||||
|
} else {
|
||||||
|
Ok(buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_powerisa_pdf(path: impl AsRef<Path>) -> Result<bool, Box<dyn Error>> {
|
||||||
|
let path = path.as_ref();
|
||||||
|
let metadata = match std::fs::metadata(path) {
|
||||||
|
Err(e) if e.kind() == ErrorKind::NotFound => return Ok(false),
|
||||||
|
v => v?,
|
||||||
|
};
|
||||||
|
if !metadata.is_file() {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
let file = std::fs::File::open(path)?;
|
||||||
|
verify_powerisa_file(file)?;
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn out_dir() -> String {
|
||||||
|
std::env::var("OUT_DIR").expect("OUT_DIR env var is not set or invalid")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_powerisa_pdf_name_and_dir<'a>(
|
||||||
|
out_dir: &'a str,
|
||||||
|
) -> Result<(&'static str, &'a Path), Box<dyn Error>> {
|
||||||
|
const FILE_NAME: &str = "OPF_PowerISA_v3.1C.pdf";
|
||||||
|
let out_dir = Path::new(out_dir);
|
||||||
|
if is_powerisa_pdf(FILE_NAME)? {
|
||||||
|
println!("cargo::rerun-if-changed={FILE_NAME}");
|
||||||
|
return Ok((FILE_NAME, Path::new(".")));
|
||||||
|
}
|
||||||
|
let full_path = out_dir.join(FILE_NAME);
|
||||||
|
let full_path = full_path
|
||||||
|
.into_os_string()
|
||||||
|
.into_string()
|
||||||
|
.expect("should be valid UTF-8");
|
||||||
|
if is_powerisa_pdf(&full_path)? {
|
||||||
|
println!("cargo::rerun-if-changed={full_path}");
|
||||||
|
return Ok((FILE_NAME, out_dir));
|
||||||
|
}
|
||||||
|
const URL: &str = "https://libre-chip.org/OPF_PowerISA_v3.1C.pdf";
|
||||||
|
println!("cargo::warning={FILE_NAME} not found locally, downloading from {URL}");
|
||||||
|
let buf = verify_powerisa_file(ureq::get(URL).call()?.into_body().into_reader())?;
|
||||||
|
std::fs::write(&full_path, buf)?;
|
||||||
|
println!("cargo::rerun-if-changed={full_path}");
|
||||||
|
Ok((FILE_NAME, out_dir))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
let out_dir = out_dir();
|
||||||
|
let (pdf_name, pdf_dir) = get_powerisa_pdf_name_and_dir(&out_dir)?;
|
||||||
|
let old_dir = std::env::current_dir()?;
|
||||||
|
std::env::set_current_dir(pdf_dir)?;
|
||||||
|
let xml = parse_powerisa_pdf_and_generate_xml(pdf_name, None, false)?;
|
||||||
|
std::env::set_current_dir(old_dir)?;
|
||||||
|
std::fs::write(Path::new(&out_dir).join("powerisa-instructions.xml"), xml)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
@ -8,9 +8,10 @@ use crate::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use fayalite::prelude::*;
|
use fayalite::prelude::*;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
#[derive(Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct UnitConfig {
|
pub struct UnitConfig {
|
||||||
pub kind: UnitKind,
|
pub kind: UnitKind,
|
||||||
|
|
@ -27,12 +28,17 @@ impl UnitConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
#[derive(Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct CpuConfig {
|
pub struct CpuConfig {
|
||||||
pub units: Vec<UnitConfig>,
|
pub units: Vec<UnitConfig>,
|
||||||
pub out_reg_num_width: usize,
|
pub out_reg_num_width: usize,
|
||||||
pub fetch_width: NonZeroUsize,
|
pub fetch_width: NonZeroUsize,
|
||||||
|
pub max_branches_per_fetch: NonZeroUsize,
|
||||||
|
pub max_fetches_in_flight: NonZeroUsize,
|
||||||
|
pub log2_fetch_width_in_bytes: u8,
|
||||||
|
pub log2_cache_line_size_in_bytes: u8,
|
||||||
|
pub l1_i_cache_line_count: NonZeroUsize,
|
||||||
/// default value for [`UnitConfig::max_in_flight`]
|
/// default value for [`UnitConfig::max_in_flight`]
|
||||||
pub default_unit_max_in_flight: NonZeroUsize,
|
pub default_unit_max_in_flight: NonZeroUsize,
|
||||||
pub rob_size: NonZeroUsize,
|
pub rob_size: NonZeroUsize,
|
||||||
|
|
@ -46,6 +52,26 @@ impl CpuConfig {
|
||||||
};
|
};
|
||||||
v
|
v
|
||||||
};
|
};
|
||||||
|
pub const DEFAULT_MAX_BRANCHES_PER_FETCH: NonZeroUsize = {
|
||||||
|
let Some(v) = NonZeroUsize::new(1) else {
|
||||||
|
unreachable!();
|
||||||
|
};
|
||||||
|
v
|
||||||
|
};
|
||||||
|
pub const DEFAULT_MAX_FETCHES_IN_FLIGHT: NonZeroUsize = {
|
||||||
|
let Some(v) = NonZeroUsize::new(16) else {
|
||||||
|
unreachable!();
|
||||||
|
};
|
||||||
|
v
|
||||||
|
};
|
||||||
|
pub const DEFAULT_LOG2_FETCH_WIDTH_IN_BYTES: u8 = 3;
|
||||||
|
pub const DEFAULT_LOG2_CACHE_LINE_SIZE_IN_BYTES: u8 = 6;
|
||||||
|
pub const DEFAULT_L1_I_CACHE_LINE_COUNT: NonZeroUsize = {
|
||||||
|
let Some(v) = NonZeroUsize::new(256) else {
|
||||||
|
unreachable!();
|
||||||
|
};
|
||||||
|
v
|
||||||
|
};
|
||||||
pub const DEFAULT_UNIT_MAX_IN_FLIGHT: NonZeroUsize = {
|
pub const DEFAULT_UNIT_MAX_IN_FLIGHT: NonZeroUsize = {
|
||||||
let Some(v) = NonZeroUsize::new(8) else {
|
let Some(v) = NonZeroUsize::new(8) else {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
|
|
@ -57,6 +83,11 @@ impl CpuConfig {
|
||||||
units,
|
units,
|
||||||
out_reg_num_width: Self::DEFAULT_OUT_REG_NUM_WIDTH,
|
out_reg_num_width: Self::DEFAULT_OUT_REG_NUM_WIDTH,
|
||||||
fetch_width: Self::DEFAULT_FETCH_WIDTH,
|
fetch_width: Self::DEFAULT_FETCH_WIDTH,
|
||||||
|
max_branches_per_fetch: Self::DEFAULT_MAX_BRANCHES_PER_FETCH,
|
||||||
|
max_fetches_in_flight: Self::DEFAULT_MAX_FETCHES_IN_FLIGHT,
|
||||||
|
log2_fetch_width_in_bytes: Self::DEFAULT_LOG2_FETCH_WIDTH_IN_BYTES,
|
||||||
|
log2_cache_line_size_in_bytes: Self::DEFAULT_LOG2_CACHE_LINE_SIZE_IN_BYTES,
|
||||||
|
l1_i_cache_line_count: Self::DEFAULT_L1_I_CACHE_LINE_COUNT,
|
||||||
default_unit_max_in_flight: Self::DEFAULT_UNIT_MAX_IN_FLIGHT,
|
default_unit_max_in_flight: Self::DEFAULT_UNIT_MAX_IN_FLIGHT,
|
||||||
rob_size,
|
rob_size,
|
||||||
}
|
}
|
||||||
|
|
@ -116,4 +147,65 @@ impl CpuConfig {
|
||||||
UnitToRegAlloc[mop_ty][extra_out_ty][self.unit_num_width()][self.out_reg_num_width]
|
UnitToRegAlloc[mop_ty][extra_out_ty][self.unit_num_width()][self.out_reg_num_width]
|
||||||
[self.non_const_unit_nums().len()]
|
[self.non_const_unit_nums().len()]
|
||||||
}
|
}
|
||||||
|
pub fn fetch_width_in_bytes(&self) -> usize {
|
||||||
|
1usize
|
||||||
|
.checked_shl(self.log2_fetch_width_in_bytes.into())
|
||||||
|
.expect("log2_fetch_width_in_bytes is too big")
|
||||||
}
|
}
|
||||||
|
pub fn cache_line_size_in_bytes(&self) -> usize {
|
||||||
|
1usize
|
||||||
|
.checked_shl(self.log2_cache_line_size_in_bytes.into())
|
||||||
|
.expect("log2_cache_line_size_in_bytes is too big")
|
||||||
|
}
|
||||||
|
pub fn l1_i_cache_size_in_bytes(&self) -> usize {
|
||||||
|
self.l1_i_cache_line_count
|
||||||
|
.get()
|
||||||
|
.checked_mul(self.cache_line_size_in_bytes())
|
||||||
|
.expect("L1 I-Cache is too big")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl(get(|c| c.fetch_width.get()))]
|
||||||
|
pub type CpuConfigFetchWidth<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||||
|
|
||||||
|
#[hdl(get(|c| c.fetch_width.get() * 2))]
|
||||||
|
pub type TwiceCpuConfigFetchWidth<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||||
|
|
||||||
|
#[hdl(get(|c| c.max_branches_per_fetch.get()))]
|
||||||
|
pub type CpuConfigMaxBranchesPerFetch<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||||
|
|
||||||
|
#[hdl(get(|c| c.max_fetches_in_flight.get()))]
|
||||||
|
pub type CpuConfigMaxFetchesInFlight<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||||
|
|
||||||
|
#[hdl(get(|c| c.log2_fetch_width_in_bytes.into()))]
|
||||||
|
pub type CpuConfigLog2FetchWidthInBytes<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||||
|
|
||||||
|
#[hdl(get(|c| c.fetch_width_in_bytes()))]
|
||||||
|
pub type CpuConfigFetchWidthInBytes<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||||
|
|
||||||
|
#[hdl(get(|c| c.log2_cache_line_size_in_bytes.into()))]
|
||||||
|
pub type CpuConfigLog2CacheLineSizeInBytes<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||||
|
|
||||||
|
#[hdl(get(|c| c.cache_line_size_in_bytes()))]
|
||||||
|
pub type CpuConfigCacheLineSizeInBytes<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||||
|
|
||||||
|
#[hdl(get(|c| c.l1_i_cache_line_count.get()))]
|
||||||
|
pub type CpuConfigL1ICacheLineCount<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||||
|
|
||||||
|
#[hdl(get(|c| c.l1_i_cache_size_in_bytes()))]
|
||||||
|
pub type CpuConfigL1ICacheSizeInBytes<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||||
|
|
||||||
|
#[hdl(get(|c| c.rob_size.get()))]
|
||||||
|
pub type CpuConfigRobSize<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||||
|
|
||||||
|
pub trait PhantomConstCpuConfig:
|
||||||
|
PhantomConstGet<CpuConfig>
|
||||||
|
+ Into<PhantomConst<CpuConfig>>
|
||||||
|
+ From<PhantomConst<CpuConfig>>
|
||||||
|
+ Type
|
||||||
|
+ ToSimValue<Type = Self>
|
||||||
|
+ ToExpr<Type = Self>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PhantomConstCpuConfig for PhantomConst<CpuConfig> {}
|
||||||
|
|
|
||||||
4
crates/cpu/src/decoder.rs
Normal file
4
crates/cpu/src/decoder.rs
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
pub mod simple_power_isa;
|
||||||
2847
crates/cpu/src/decoder/simple_power_isa.rs
Normal file
2847
crates/cpu/src/decoder/simple_power_isa.rs
Normal file
File diff suppressed because it is too large
Load diff
266
crates/cpu/src/fetch.rs
Normal file
266
crates/cpu/src/fetch.rs
Normal file
|
|
@ -0,0 +1,266 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
config::{
|
||||||
|
CpuConfig, CpuConfigCacheLineSizeInBytes, CpuConfigFetchWidthInBytes,
|
||||||
|
CpuConfigL1ICacheLineCount, PhantomConstCpuConfig,
|
||||||
|
},
|
||||||
|
next_pc::{NextPcToFetchInterface, ResetStatus, ResetSteps, SimValueDefault},
|
||||||
|
};
|
||||||
|
use fayalite::{
|
||||||
|
memory::{ReadWriteStruct, memory_addr_width, splat_mask},
|
||||||
|
prelude::*,
|
||||||
|
util::ready_valid::ReadyValid,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
pub enum MemoryOperationKind {
|
||||||
|
Read,
|
||||||
|
Write,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl(no_static)]
|
||||||
|
pub struct MemoryOperationStart<C: PhantomConstGet<CpuConfig> + PhantomConstCpuConfig> {
|
||||||
|
pub kind: MemoryOperationKind,
|
||||||
|
pub addr: UInt<64>,
|
||||||
|
pub write_data: ArrayType<UInt<8>, CpuConfigFetchWidthInBytes<C>>,
|
||||||
|
pub config: C,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
pub enum MemoryOperationErrorKind {
|
||||||
|
Generic,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
pub enum MemoryOperationFinishKind {
|
||||||
|
Success(MemoryOperationKind),
|
||||||
|
Error(MemoryOperationErrorKind),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl(no_static)]
|
||||||
|
pub struct MemoryOperationFinish<C: PhantomConstGet<CpuConfig> + PhantomConstCpuConfig> {
|
||||||
|
pub kind: MemoryOperationFinishKind,
|
||||||
|
pub read_data: ArrayType<UInt<8>, CpuConfigFetchWidthInBytes<C>>,
|
||||||
|
pub config: C,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl(no_static)]
|
||||||
|
pub struct MemoryInterface<C: PhantomConstGet<CpuConfig> + PhantomConstCpuConfig> {
|
||||||
|
pub start: ReadyValid<MemoryOperationStart<C>>,
|
||||||
|
#[hdl(flip)]
|
||||||
|
pub finish: ReadyValid<MemoryOperationFinish<C>>,
|
||||||
|
pub config: C,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl(no_static)]
|
||||||
|
struct CacheLine<C: PhantomConstGet<CpuConfig> + PhantomConstCpuConfig> {
|
||||||
|
data: ArrayType<UInt<8>, CpuConfigCacheLineSizeInBytes<C>>,
|
||||||
|
addr: HdlOption<UInt<64>>,
|
||||||
|
config: C,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl(no_static)]
|
||||||
|
struct L1ICacheState<C: PhantomConstGet<CpuConfig> + PhantomConstCpuConfig> {
|
||||||
|
config: C,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: PhantomConstCpuConfig> SimValueDefault for L1ICacheState<C> {
|
||||||
|
#[hdl]
|
||||||
|
fn sim_value_default(self) -> SimValue<Self> {
|
||||||
|
let Self { config } = self;
|
||||||
|
#[hdl(sim)]
|
||||||
|
Self { config }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: PhantomConstCpuConfig> ResetSteps for L1ICacheState<C> {
|
||||||
|
#[hdl]
|
||||||
|
fn reset_step(this: &mut SimValue<Self>, step: usize) -> ResetStatus {
|
||||||
|
#[hdl(sim)]
|
||||||
|
let Self { config: _ } = this;
|
||||||
|
ResetStatus::Done
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl_module(extern)]
|
||||||
|
fn l1_i_cache_impl(config: PhantomConst<CpuConfig>) {
|
||||||
|
#[hdl]
|
||||||
|
let cd: ClockDomain = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let memory_interface: MemoryInterface<PhantomConst<CpuConfig>> =
|
||||||
|
m.output(MemoryInterface[config]);
|
||||||
|
#[hdl]
|
||||||
|
let from_next_pc: NextPcToFetchInterface<PhantomConst<CpuConfig>> =
|
||||||
|
m.input(NextPcToFetchInterface[config]);
|
||||||
|
// i_cache_port.clk is externally overridden with cd.clk
|
||||||
|
#[hdl]
|
||||||
|
let i_cache_port: ReadWriteStruct<CacheLine<PhantomConst<CpuConfig>>, DynSize> = m.output(
|
||||||
|
ReadWriteStruct[CacheLine[config]][memory_addr_width(CpuConfigL1ICacheLineCount[config])],
|
||||||
|
);
|
||||||
|
#[hdl]
|
||||||
|
let state_for_debug: L1ICacheState<PhantomConst<CpuConfig>> = m.output(L1ICacheState[config]);
|
||||||
|
m.register_clock_for_past(cd.clk);
|
||||||
|
#[hdl]
|
||||||
|
async fn run(
|
||||||
|
mut sim: ExternModuleSimulationState,
|
||||||
|
cd: Expr<ClockDomain>,
|
||||||
|
memory_interface: Expr<MemoryInterface<PhantomConst<CpuConfig>>>,
|
||||||
|
from_next_pc: Expr<NextPcToFetchInterface<PhantomConst<CpuConfig>>>,
|
||||||
|
i_cache_port: Expr<ReadWriteStruct<CacheLine<PhantomConst<CpuConfig>>, DynSize>>,
|
||||||
|
state_expr: Expr<L1ICacheState<PhantomConst<CpuConfig>>>,
|
||||||
|
) {
|
||||||
|
let mut state = sim.read(state_expr).await;
|
||||||
|
let config = state.config.ty();
|
||||||
|
let l1_i_cache_line_count = CpuConfigL1ICacheLineCount[config];
|
||||||
|
let cache_line_ty = CacheLine[config];
|
||||||
|
for step in 0usize.. {
|
||||||
|
sim.write(state_expr, state).await;
|
||||||
|
sim.wait_for_clock_edge(cd.clk).await;
|
||||||
|
state = sim.read_past(state_expr, cd.clk).await;
|
||||||
|
sim.write(i_cache_port.en, false).await;
|
||||||
|
let mut reset_status = ResetSteps::reset_step(&mut state, step);
|
||||||
|
if step < l1_i_cache_line_count {
|
||||||
|
reset_status = ResetStatus::Working;
|
||||||
|
#[hdl]
|
||||||
|
let ReadWriteStruct::<_, _> {
|
||||||
|
addr,
|
||||||
|
en,
|
||||||
|
clk: _, // externally overridden with cd.clk
|
||||||
|
rdata: _,
|
||||||
|
wmode,
|
||||||
|
wdata,
|
||||||
|
wmask,
|
||||||
|
} = i_cache_port;
|
||||||
|
sim.write(addr, step.cast_to(addr.ty())).await;
|
||||||
|
sim.write(en, true).await;
|
||||||
|
sim.write(wmode, true).await;
|
||||||
|
sim.write(
|
||||||
|
wdata,
|
||||||
|
#[hdl(sim)]
|
||||||
|
CacheLine::<_> {
|
||||||
|
data: repeat(0u8, cache_line_ty.data.len()),
|
||||||
|
addr: #[hdl(sim)]
|
||||||
|
HdlNone(),
|
||||||
|
config,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
sim.write(wmask, splat_mask(cache_line_ty, true.to_expr()))
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
match reset_status {
|
||||||
|
ResetStatus::Done => break,
|
||||||
|
ResetStatus::Working => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
m.extern_module_simulation_fn(
|
||||||
|
(
|
||||||
|
cd,
|
||||||
|
memory_interface,
|
||||||
|
from_next_pc,
|
||||||
|
i_cache_port,
|
||||||
|
state_for_debug,
|
||||||
|
),
|
||||||
|
|(cd, memory_interface, from_next_pc, i_cache_port, state_for_debug), mut sim| async move {
|
||||||
|
let config = memory_interface.ty().config;
|
||||||
|
let cache_line_size_in_bytes = CpuConfigCacheLineSizeInBytes[config];
|
||||||
|
let cache_line_ty = CacheLine[config];
|
||||||
|
sim.write(i_cache_port.clk, false).await; // externally overridden with cd.clk, so just write a constant here
|
||||||
|
sim.resettable(
|
||||||
|
cd,
|
||||||
|
|mut sim: ExternModuleSimulationState| async move {
|
||||||
|
sim.write(memory_interface.start.ready, false).await;
|
||||||
|
sim.write(memory_interface.finish.ready, false).await;
|
||||||
|
sim.write(
|
||||||
|
from_next_pc.next_fetch_block_ids,
|
||||||
|
from_next_pc.ty().next_fetch_block_ids.HdlNone(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
sim.write(from_next_pc.fetch.ready, false).await;
|
||||||
|
sim.write(from_next_pc.cancel.ready, false).await;
|
||||||
|
sim.write(i_cache_port.addr, 0u8.cast_to(i_cache_port.addr.ty()))
|
||||||
|
.await;
|
||||||
|
sim.write(i_cache_port.en, false).await;
|
||||||
|
sim.write(i_cache_port.wmode, false).await;
|
||||||
|
sim.write(
|
||||||
|
i_cache_port.wdata,
|
||||||
|
#[hdl(sim)]
|
||||||
|
CacheLine::<_> {
|
||||||
|
data: repeat(0u8, cache_line_size_in_bytes),
|
||||||
|
addr: HdlNone(),
|
||||||
|
config,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
sim.write(
|
||||||
|
i_cache_port.wmask,
|
||||||
|
splat_mask(cache_line_ty, false.to_expr()),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
sim.write(
|
||||||
|
state_for_debug,
|
||||||
|
#[hdl(sim)]
|
||||||
|
L1ICacheState::<_> { config },
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
},
|
||||||
|
|sim, ()| {
|
||||||
|
run(
|
||||||
|
sim,
|
||||||
|
cd,
|
||||||
|
memory_interface,
|
||||||
|
from_next_pc,
|
||||||
|
i_cache_port,
|
||||||
|
state_for_debug,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl_module]
|
||||||
|
pub fn l1_i_cache(config: PhantomConst<CpuConfig>) {
|
||||||
|
#[hdl]
|
||||||
|
let cd: ClockDomain = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let memory_interface: MemoryInterface<PhantomConst<CpuConfig>> =
|
||||||
|
m.output(MemoryInterface[config]);
|
||||||
|
#[hdl]
|
||||||
|
let from_next_pc: NextPcToFetchInterface<PhantomConst<CpuConfig>> =
|
||||||
|
m.input(NextPcToFetchInterface[config]);
|
||||||
|
let cache_line_ty = CacheLine[config];
|
||||||
|
let cache_line_count = CpuConfigL1ICacheLineCount[config];
|
||||||
|
#[hdl]
|
||||||
|
let mut i_cache = memory_array(ArrayType[cache_line_ty][cache_line_count]);
|
||||||
|
let i_cache_port = i_cache.new_rw_port();
|
||||||
|
#[hdl]
|
||||||
|
let l1_i_cache_impl = instance(l1_i_cache_impl(config));
|
||||||
|
connect(l1_i_cache_impl.cd, cd);
|
||||||
|
connect(memory_interface, l1_i_cache_impl.memory_interface);
|
||||||
|
connect(l1_i_cache_impl.from_next_pc, from_next_pc);
|
||||||
|
connect(i_cache_port, l1_i_cache_impl.i_cache_port);
|
||||||
|
connect(i_cache_port.clk, cd.clk);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl_module]
|
||||||
|
pub fn fetch(config: PhantomConst<CpuConfig>) {
|
||||||
|
#[hdl]
|
||||||
|
let cd: ClockDomain = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let memory_interface: MemoryInterface<PhantomConst<CpuConfig>> =
|
||||||
|
m.output(MemoryInterface[config]);
|
||||||
|
#[hdl]
|
||||||
|
let from_next_pc: NextPcToFetchInterface<PhantomConst<CpuConfig>> =
|
||||||
|
m.input(NextPcToFetchInterface[config]);
|
||||||
|
#[hdl]
|
||||||
|
let l1_i_cache = instance(l1_i_cache(config));
|
||||||
|
connect(l1_i_cache.cd, cd);
|
||||||
|
connect(memory_interface, l1_i_cache.memory_interface);
|
||||||
|
connect(l1_i_cache.from_next_pc, from_next_pc);
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -27,26 +27,432 @@ pub struct PowerIsaCrBitNum {
|
||||||
|
|
||||||
impl MOpRegNum {
|
impl MOpRegNum {
|
||||||
pub const POWER_ISA_LR_REG_NUM: u32 = 1;
|
pub const POWER_ISA_LR_REG_NUM: u32 = 1;
|
||||||
|
#[hdl]
|
||||||
|
pub fn power_isa_lr_reg() -> Expr<Self> {
|
||||||
|
#[hdl]
|
||||||
|
Self {
|
||||||
|
value: Self::POWER_ISA_LR_REG_NUM.cast_to_static::<UInt<_>>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
pub const POWER_ISA_CTR_REG_NUM: u32 = 2;
|
pub const POWER_ISA_CTR_REG_NUM: u32 = 2;
|
||||||
|
#[hdl]
|
||||||
|
pub fn power_isa_ctr_reg() -> Expr<Self> {
|
||||||
|
#[hdl]
|
||||||
|
Self {
|
||||||
|
value: Self::POWER_ISA_CTR_REG_NUM.cast_to_static::<UInt<_>>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
pub const POWER_ISA_TAR_REG_NUM: u32 = 3;
|
pub const POWER_ISA_TAR_REG_NUM: u32 = 3;
|
||||||
/// XER bits are stored in [`PRegValue.flags`], bits that don't exist in [`PRegValue.flags`] are stored in [`PRegValue.int_fp`]
|
#[hdl]
|
||||||
|
pub fn power_isa_tar_reg() -> Expr<Self> {
|
||||||
|
#[hdl]
|
||||||
|
Self {
|
||||||
|
value: Self::POWER_ISA_TAR_REG_NUM.cast_to_static::<UInt<_>>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// SO, OV, and OV32 XER bits -- in [`PRegValue.flags`]
|
||||||
///
|
///
|
||||||
/// [`PRegValue.flags`]: struct@crate::register::PRegValue
|
/// [`PRegValue.flags`]: struct@crate::register::PRegValue
|
||||||
/// [`PRegValue.int_fp`]: struct@crate::register::PRegValue
|
pub const POWER_ISA_XER_SO_OV_OV32_REG_NUM: u32 =
|
||||||
pub const POWER_ISA_XER_REG_NUM: u32 = 4;
|
range_u32_nth_or_panic(&Self::FLAG_REG_NUMS, 0);
|
||||||
|
/// CA and CA32 XER bits -- in [`PRegValue.flags`]
|
||||||
|
///
|
||||||
|
/// [`PRegValue.flags`]: struct@crate::register::PRegValue
|
||||||
|
pub const POWER_ISA_XER_CA_CA32_REG_NUM: u32 = 4;
|
||||||
|
/// only the XER bits that don't exist in [`PRegValue.flags`]
|
||||||
|
///
|
||||||
|
/// [`PRegValue.flags`]: struct@crate::register::PRegValue
|
||||||
|
pub const POWER_ISA_XER_OTHER_REG_NUM: u32 = 5;
|
||||||
|
|
||||||
pub const POWER_ISA_CR_REG_NUMS: Range<u32> = 8..16;
|
/// used as a temporary for things like computing the effective address before loading/storing memory
|
||||||
|
pub const POWER_ISA_TEMP_REG_NUM: u32 = 8;
|
||||||
|
#[hdl]
|
||||||
|
pub fn power_isa_temp_reg() -> Expr<Self> {
|
||||||
|
#[hdl]
|
||||||
|
Self {
|
||||||
|
value: Self::POWER_ISA_TEMP_REG_NUM.cast_to_static::<UInt<_>>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// SO, OV, and OV32 XER bits -- in [`PRegValue.flags`]
|
||||||
|
///
|
||||||
|
/// [`PRegValue.flags`]: struct@crate::register::PRegValue
|
||||||
|
#[hdl]
|
||||||
|
pub fn power_isa_xer_so_ov_ov32_reg() -> Expr<Self> {
|
||||||
|
#[hdl]
|
||||||
|
Self {
|
||||||
|
value: Self::POWER_ISA_XER_SO_OV_OV32_REG_NUM.cast_to_static::<UInt<_>>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// CA and CA32 XER bits -- in [`PRegValue.flags`]
|
||||||
|
///
|
||||||
|
/// [`PRegValue.flags`]: struct@crate::register::PRegValue
|
||||||
|
#[hdl]
|
||||||
|
pub fn power_isa_xer_ca_ca32_reg() -> Expr<Self> {
|
||||||
|
#[hdl]
|
||||||
|
Self {
|
||||||
|
value: Self::POWER_ISA_XER_CA_CA32_REG_NUM.cast_to_static::<UInt<_>>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// only the XER bits that don't exist in [`PRegValue.flags`]
|
||||||
|
///
|
||||||
|
/// [`PRegValue.flags`]: struct@crate::register::PRegValue
|
||||||
|
#[hdl]
|
||||||
|
pub fn power_isa_xer_other_reg() -> Expr<Self> {
|
||||||
|
#[hdl]
|
||||||
|
Self {
|
||||||
|
value: Self::POWER_ISA_XER_OTHER_REG_NUM.cast_to_static::<UInt<_>>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const POWER_ISA_CR_0_REG_NUM: u32 = range_u32_nth_or_panic(&Self::FLAG_REG_NUMS, 1);
|
||||||
|
pub const POWER_ISA_CR_1_THRU_7_REG_NUMS: Range<u32> = 9..16;
|
||||||
pub const fn power_isa_cr_reg_num(index: usize) -> u32 {
|
pub const fn power_isa_cr_reg_num(index: usize) -> u32 {
|
||||||
range_u32_nth_or_panic(&Self::POWER_ISA_CR_REG_NUMS, index)
|
if index == 0 {
|
||||||
|
Self::POWER_ISA_CR_0_REG_NUM
|
||||||
|
} else {
|
||||||
|
range_u32_nth_or_panic(&Self::POWER_ISA_CR_1_THRU_7_REG_NUMS, index - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
pub fn power_isa_cr_reg(field_num: Expr<UInt<3>>) -> Expr<Self> {
|
||||||
|
#[hdl]
|
||||||
|
let power_isa_cr_reg: Self = wire();
|
||||||
|
#[hdl]
|
||||||
|
if field_num.cmp_eq(0u8) {
|
||||||
|
connect_any(power_isa_cr_reg.value, Self::POWER_ISA_CR_0_REG_NUM);
|
||||||
|
} else {
|
||||||
|
connect_any(
|
||||||
|
power_isa_cr_reg.value,
|
||||||
|
Self::POWER_ISA_CR_1_THRU_7_REG_NUMS.start - 1 + field_num,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
power_isa_cr_reg
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
pub fn power_isa_cr_reg_imm(index: usize) -> Expr<Self> {
|
||||||
|
#[hdl]
|
||||||
|
Self {
|
||||||
|
value: Self::power_isa_cr_reg_num(index).cast_to_static::<UInt<_>>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
pub fn power_isa_cr_reg_sim(field_num: &SimValue<UInt<3>>) -> SimValue<Self> {
|
||||||
|
#[hdl(sim)]
|
||||||
|
Self {
|
||||||
|
value: Self::power_isa_cr_reg_num(
|
||||||
|
field_num.cast_to_static::<UInt<8>>().as_int() as usize
|
||||||
|
)
|
||||||
|
.cast_to_static::<UInt<_>>(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const POWER_ISA_GPR_REG_NUMS: Range<u32> = 32..64;
|
pub const POWER_ISA_GPR_REG_NUMS: Range<u32> = 32..64;
|
||||||
pub const fn power_isa_gpr_reg_num(index: usize) -> u32 {
|
pub const fn power_isa_gpr_reg_num(index: usize) -> u32 {
|
||||||
range_u32_nth_or_panic(&Self::POWER_ISA_GPR_REG_NUMS, index)
|
range_u32_nth_or_panic(&Self::POWER_ISA_GPR_REG_NUMS, index)
|
||||||
}
|
}
|
||||||
|
#[hdl]
|
||||||
|
pub fn power_isa_gpr_reg(reg_num: Expr<UInt<5>>) -> Expr<Self> {
|
||||||
|
#[hdl]
|
||||||
|
Self {
|
||||||
|
value: (Self::POWER_ISA_GPR_REG_NUMS.start + reg_num).cast_to_static::<UInt<_>>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
pub fn power_isa_gpr_reg_imm(index: usize) -> Expr<Self> {
|
||||||
|
#[hdl]
|
||||||
|
Self {
|
||||||
|
value: Self::power_isa_gpr_reg_num(index).cast_to_static::<UInt<_>>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
pub fn power_isa_gpr_reg_sim(reg_num: &SimValue<UInt<5>>) -> SimValue<Self> {
|
||||||
|
#[hdl(sim)]
|
||||||
|
Self {
|
||||||
|
value: (Self::POWER_ISA_GPR_REG_NUMS.start + reg_num).cast_to_static::<UInt<_>>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub const fn power_isa_gpr_or_zero_reg_num(index: usize) -> u32 {
|
||||||
|
if index == 0 {
|
||||||
|
Self::CONST_ZERO_REG_NUM
|
||||||
|
} else {
|
||||||
|
Self::power_isa_gpr_reg_num(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
pub fn power_isa_gpr_or_zero_reg(reg_num: Expr<UInt<5>>) -> Expr<Self> {
|
||||||
|
#[hdl]
|
||||||
|
let power_isa_gpr_or_zero_reg: Self = wire();
|
||||||
|
connect(power_isa_gpr_or_zero_reg, Self::power_isa_gpr_reg(reg_num));
|
||||||
|
#[hdl]
|
||||||
|
if reg_num.cmp_eq(0u8) {
|
||||||
|
connect(power_isa_gpr_or_zero_reg, Self::const_zero());
|
||||||
|
}
|
||||||
|
power_isa_gpr_or_zero_reg
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
pub fn power_isa_gpr_or_zero_reg_sim(reg_num: &SimValue<UInt<5>>) -> SimValue<Self> {
|
||||||
|
#[hdl(sim)]
|
||||||
|
Self {
|
||||||
|
value: Self::power_isa_gpr_or_zero_reg_num(
|
||||||
|
reg_num.cast_to_static::<UInt<8>>().as_int() as usize,
|
||||||
|
)
|
||||||
|
.cast_to_static::<UInt<_>>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub const POWER_ISA_FPR_REG_NUMS: Range<u32> = 64..96;
|
pub const POWER_ISA_FPR_REG_NUMS: Range<u32> = 64..96;
|
||||||
pub const fn power_isa_fpr_reg_num(index: usize) -> u32 {
|
pub const fn power_isa_fpr_reg_num(index: usize) -> u32 {
|
||||||
range_u32_nth_or_panic(&Self::POWER_ISA_FPR_REG_NUMS, index)
|
range_u32_nth_or_panic(&Self::POWER_ISA_FPR_REG_NUMS, index)
|
||||||
}
|
}
|
||||||
|
#[hdl]
|
||||||
|
pub fn power_isa_fpr_reg(reg_num: Expr<UInt<5>>) -> Expr<Self> {
|
||||||
|
#[hdl]
|
||||||
|
Self {
|
||||||
|
value: (Self::POWER_ISA_FPR_REG_NUMS.start + reg_num).cast_to_static::<UInt<_>>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
pub fn power_isa_fpr_reg_sim(reg_num: &SimValue<UInt<5>>) -> SimValue<Self> {
|
||||||
|
#[hdl(sim)]
|
||||||
|
Self {
|
||||||
|
value: (Self::POWER_ISA_FPR_REG_NUMS.start + reg_num).cast_to_static::<UInt<_>>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl(cmp_eq)]
|
||||||
|
pub struct PowerIsaSpr {
|
||||||
|
pub num: UInt<10>,
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! make_spr_enum {
|
||||||
|
(
|
||||||
|
$(#[$enum_meta:meta])*
|
||||||
|
$enum_vis:vis enum $PowerIsaSprEnum:ident {
|
||||||
|
$($enum_body:tt)*
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
$(#[$enum_meta])*
|
||||||
|
$enum_vis enum $PowerIsaSprEnum {
|
||||||
|
$($enum_body)*
|
||||||
|
Unknown(u16),
|
||||||
|
}
|
||||||
|
|
||||||
|
make_spr_enum! {
|
||||||
|
@impl
|
||||||
|
$enum_vis enum $PowerIsaSprEnum {
|
||||||
|
$($enum_body)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(
|
||||||
|
@impl
|
||||||
|
$enum_vis:vis enum $PowerIsaSprEnum:ident {
|
||||||
|
$(
|
||||||
|
$(#[$variant_meta:meta])*
|
||||||
|
$Variant:ident = $value:literal,
|
||||||
|
)+
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
impl $PowerIsaSprEnum {
|
||||||
|
pub const VARIANTS: &[Self; 1 << 10] = &{
|
||||||
|
let mut retval = [Self::Unknown(0); 1 << 10];
|
||||||
|
let mut i = 0;
|
||||||
|
while i < retval.len() {
|
||||||
|
retval[i] = Self::Unknown(i as u16);
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
let mut last_value = None;
|
||||||
|
#[track_caller]
|
||||||
|
const fn add_variant(
|
||||||
|
values: &mut [$PowerIsaSprEnum; 1 << 10],
|
||||||
|
last_value: &mut Option<u16>,
|
||||||
|
variant: $PowerIsaSprEnum,
|
||||||
|
value: u16,
|
||||||
|
) {
|
||||||
|
assert!(value < 1 << 10, "variant value out of range");
|
||||||
|
if let Some(last_value) = *last_value {
|
||||||
|
assert!(last_value < value, "variants must be in ascending order with no duplicates");
|
||||||
|
}
|
||||||
|
*last_value = Some(value);
|
||||||
|
values[value as usize] = variant;
|
||||||
|
}
|
||||||
|
$(add_variant(&mut retval, &mut last_value, Self::$Variant, $value);)+
|
||||||
|
retval
|
||||||
|
};
|
||||||
|
pub const fn value(self) -> u16 {
|
||||||
|
match self {
|
||||||
|
$(Self::$Variant => $value,)+
|
||||||
|
Self::Unknown(v) => v,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
make_spr_enum! {
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||||
|
#[repr(u16)]
|
||||||
|
pub enum PowerIsaSprEnum {
|
||||||
|
Xer = 1,
|
||||||
|
UserDscr = 3,
|
||||||
|
Lr = 8,
|
||||||
|
Ctr = 9,
|
||||||
|
UserAmr = 13,
|
||||||
|
Dscr = 17,
|
||||||
|
Dsisr = 18,
|
||||||
|
Dar = 19,
|
||||||
|
Dec = 22,
|
||||||
|
Srr0 = 26,
|
||||||
|
Srr1 = 27,
|
||||||
|
Cfar = 28,
|
||||||
|
Amr = 29,
|
||||||
|
Pidr = 48,
|
||||||
|
Iamr = 61,
|
||||||
|
ReadCtrl = 136,
|
||||||
|
WriteCtrl = 152,
|
||||||
|
Fscr = 153,
|
||||||
|
Uamor = 157,
|
||||||
|
Pspb = 159,
|
||||||
|
Dpdes = 176,
|
||||||
|
Dawr0 = 180,
|
||||||
|
Dawr1 = 181,
|
||||||
|
Rpr = 186,
|
||||||
|
Ciabr = 187,
|
||||||
|
Dawrx0 = 188,
|
||||||
|
Dawrx1 = 189,
|
||||||
|
Hfscr = 190,
|
||||||
|
Vrsave = 256,
|
||||||
|
UserSprg3 = 259,
|
||||||
|
Tb = 268,
|
||||||
|
Tbu = 269,
|
||||||
|
Sprg0 = 272,
|
||||||
|
Sprg1 = 273,
|
||||||
|
Sprg2 = 274,
|
||||||
|
Sprg3 = 275,
|
||||||
|
Tbl = 284,
|
||||||
|
WriteTbu = 285,
|
||||||
|
Tbu40 = 286,
|
||||||
|
Pvr = 287,
|
||||||
|
Hsprg0 = 304,
|
||||||
|
Hsprg1 = 305,
|
||||||
|
Hdsisr = 306,
|
||||||
|
Hdar = 307,
|
||||||
|
Spurr = 308,
|
||||||
|
Purr = 309,
|
||||||
|
Hdec = 310,
|
||||||
|
Hrmor = 313,
|
||||||
|
Hsrr0 = 314,
|
||||||
|
Hsrr1 = 315,
|
||||||
|
Lpcr = 318,
|
||||||
|
Lpidr = 319,
|
||||||
|
Hmer = 336,
|
||||||
|
Hmeer = 337,
|
||||||
|
Pcr = 338,
|
||||||
|
Heir = 339,
|
||||||
|
Amor = 349,
|
||||||
|
Tir = 446,
|
||||||
|
UserHdexcr = 455,
|
||||||
|
Ptcr = 464,
|
||||||
|
Hashkeyr = 468,
|
||||||
|
Hashpkeyr = 469,
|
||||||
|
Hdexcr = 471,
|
||||||
|
Usprg0 = 496,
|
||||||
|
Usprg1 = 497,
|
||||||
|
Urmor = 505,
|
||||||
|
Usrr0 = 506,
|
||||||
|
Usrr1 = 507,
|
||||||
|
Smfctrl = 511,
|
||||||
|
UserSier2 = 736,
|
||||||
|
UserSier3 = 737,
|
||||||
|
UserMmcr3 = 738,
|
||||||
|
Sier2 = 752,
|
||||||
|
Sier3 = 753,
|
||||||
|
Mmcr3 = 754,
|
||||||
|
UserSier = 768,
|
||||||
|
Mmcr2 = 769,
|
||||||
|
Mmcra = 770,
|
||||||
|
Pmc1 = 771,
|
||||||
|
Pmc2 = 772,
|
||||||
|
Pmc3 = 773,
|
||||||
|
Pmc4 = 774,
|
||||||
|
Pmc5 = 775,
|
||||||
|
Pmc6 = 776,
|
||||||
|
Mmcr0 = 779,
|
||||||
|
Siar = 780,
|
||||||
|
Sdar = 781,
|
||||||
|
Mmcr1 = 782,
|
||||||
|
Sier = 784,
|
||||||
|
PrivMmcr2 = 785,
|
||||||
|
PrivMmcra = 786,
|
||||||
|
PrivPmc1 = 787,
|
||||||
|
PrivPmc2 = 788,
|
||||||
|
PrivPmc3 = 789,
|
||||||
|
PrivPmc4 = 790,
|
||||||
|
PrivPmc5 = 791,
|
||||||
|
PrivPmc6 = 792,
|
||||||
|
PrivMmcr0 = 795,
|
||||||
|
PrivSiar = 796,
|
||||||
|
PrivSdar = 797,
|
||||||
|
PrivMmcr1 = 798,
|
||||||
|
Bescrs15 = 800,
|
||||||
|
Bescrsu16 = 801,
|
||||||
|
Bescrr15 = 802,
|
||||||
|
Bescrru16 = 803,
|
||||||
|
Ebbhr = 804,
|
||||||
|
Ebbrr = 805,
|
||||||
|
Bescr = 806,
|
||||||
|
Reserved808 = 808,
|
||||||
|
Reserved809 = 809,
|
||||||
|
Reserved810 = 810,
|
||||||
|
Reserved811 = 811,
|
||||||
|
UserDexcr = 812,
|
||||||
|
Tar = 815,
|
||||||
|
Asdr = 816,
|
||||||
|
Psscr = 823,
|
||||||
|
Dexcr = 828,
|
||||||
|
Ic = 848,
|
||||||
|
Vtb = 849,
|
||||||
|
HyperPsscr = 855,
|
||||||
|
Ppr = 896,
|
||||||
|
Ppr32 = 898,
|
||||||
|
Pir = 1023,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ValueType for PowerIsaSprEnum {
|
||||||
|
type Type = PowerIsaSpr;
|
||||||
|
type ValueCategory = fayalite::expr::value_category::ValueCategoryValue;
|
||||||
|
|
||||||
|
fn ty(&self) -> Self::Type {
|
||||||
|
PowerIsaSpr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToExpr for PowerIsaSprEnum {
|
||||||
|
#[hdl]
|
||||||
|
fn to_expr(&self) -> Expr<Self::Type> {
|
||||||
|
#[hdl]
|
||||||
|
PowerIsaSpr {
|
||||||
|
num: self.value().cast_to_static::<UInt<_>>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToSimValueWithType<PowerIsaSpr> for PowerIsaSprEnum {
|
||||||
|
fn to_sim_value_with_type(&self, _ty: PowerIsaSpr) -> SimValue<PowerIsaSpr> {
|
||||||
|
self.to_sim_value()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToSimValue for PowerIsaSprEnum {
|
||||||
|
#[hdl]
|
||||||
|
fn to_sim_value(&self) -> SimValue<Self::Type> {
|
||||||
|
#[hdl(sim)]
|
||||||
|
PowerIsaSpr {
|
||||||
|
num: self.value().cast_to_static::<UInt<_>>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,11 @@
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
pub mod decoder;
|
||||||
|
pub mod fetch;
|
||||||
pub mod instruction;
|
pub mod instruction;
|
||||||
|
pub mod next_pc;
|
||||||
|
pub mod powerisa_instructions_xml;
|
||||||
pub mod reg_alloc;
|
pub mod reg_alloc;
|
||||||
pub mod register;
|
pub mod register;
|
||||||
pub mod unit;
|
pub mod unit;
|
||||||
|
|
|
||||||
4862
crates/cpu/src/next_pc.rs
Normal file
4862
crates/cpu/src/next_pc.rs
Normal file
File diff suppressed because it is too large
Load diff
24
crates/cpu/src/next_pc/next_pc.mermaid
Normal file
24
crates/cpu/src/next_pc/next_pc.mermaid
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
%% SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
%% See Notices.txt for copyright information
|
||||||
|
stateDiagram-v2
|
||||||
|
direction LR
|
||||||
|
|
||||||
|
state "Next PC" as next_pc
|
||||||
|
[*] --> next_pc
|
||||||
|
|
||||||
|
state "Fetch/Decode" as fetch_decode
|
||||||
|
next_pc --> fetch_decode
|
||||||
|
|
||||||
|
state "Branch Predictor" as br_pred
|
||||||
|
next_pc --> br_pred
|
||||||
|
br_pred --> next_pc: cancel following
|
||||||
|
|
||||||
|
state "Post-decode" as post_decode
|
||||||
|
fetch_decode --> post_decode
|
||||||
|
br_pred --> post_decode
|
||||||
|
post_decode --> next_pc: cancel following
|
||||||
|
|
||||||
|
state "Execute/Retire" as execute_retire
|
||||||
|
post_decode --> execute_retire
|
||||||
|
execute_retire --> [*]
|
||||||
|
execute_retire --> next_pc: cancel following
|
||||||
2719
crates/cpu/src/powerisa_instructions_xml.rs
Normal file
2719
crates/cpu/src/powerisa_instructions_xml.rs
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -241,7 +241,7 @@ pub fn reg_alloc(config: &CpuConfig) {
|
||||||
// TODO: finish
|
// TODO: finish
|
||||||
connect(
|
connect(
|
||||||
rob.renamed_insns_in[fetch_index].data,
|
rob.renamed_insns_in[fetch_index].data,
|
||||||
Expr::ty(rob).renamed_insns_in.element().data.HdlNone(),
|
rob.ty().renamed_insns_in.element().data.HdlNone(),
|
||||||
);
|
);
|
||||||
// TODO: finish
|
// TODO: finish
|
||||||
connect(
|
connect(
|
||||||
|
|
@ -263,7 +263,7 @@ pub fn reg_alloc(config: &CpuConfig) {
|
||||||
);
|
);
|
||||||
connect(
|
connect(
|
||||||
renamed_mops[fetch_index],
|
renamed_mops[fetch_index],
|
||||||
Expr::ty(renamed_mops).element().HdlNone(),
|
renamed_mops.ty().element().HdlNone(),
|
||||||
);
|
);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
struct RenameTableReadPort<T> {
|
struct RenameTableReadPort<T> {
|
||||||
|
|
@ -332,7 +332,7 @@ pub fn reg_alloc(config: &CpuConfig) {
|
||||||
let write_port = wire_with_loc(
|
let write_port = wire_with_loc(
|
||||||
&format!("{table_name}_{fetch_index}_{}", reg_kind.reg_name()),
|
&format!("{table_name}_{fetch_index}_{}", reg_kind.reg_name()),
|
||||||
SourceLocation::caller(),
|
SourceLocation::caller(),
|
||||||
Expr::ty(write_port_),
|
write_port_.ty(),
|
||||||
);
|
);
|
||||||
connect(write_port_, write_port);
|
connect(write_port_, write_port);
|
||||||
write_ports.push_back(write_port);
|
write_ports.push_back(write_port);
|
||||||
|
|
@ -343,7 +343,7 @@ pub fn reg_alloc(config: &CpuConfig) {
|
||||||
addr: 0_hdl_u0,
|
addr: 0_hdl_u0,
|
||||||
en: false,
|
en: false,
|
||||||
clk: cd.clk,
|
clk: cd.clk,
|
||||||
data: Expr::ty(write_port.data).uninit(),
|
data: write_port.data.ty().uninit(),
|
||||||
mask: splat_mask(config.p_reg_num(), true.to_expr()),
|
mask: splat_mask(config.p_reg_num(), true.to_expr()),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -375,7 +375,7 @@ pub fn reg_alloc(config: &CpuConfig) {
|
||||||
config.renamed_mop_in_unit().TransformedMove,
|
config.renamed_mop_in_unit().TransformedMove,
|
||||||
|renamed_mop, renamed_move_op: Expr<MoveRegMOp<_, _>>| {
|
|renamed_mop, renamed_move_op: Expr<MoveRegMOp<_, _>>| {
|
||||||
// TODO: finish handling MoveRegMOp
|
// TODO: finish handling MoveRegMOp
|
||||||
connect(renamed_mop, Expr::ty(renamed_mop).HdlNone());
|
connect(renamed_mop, renamed_mop.ty().HdlNone());
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
connect(
|
connect(
|
||||||
|
|
@ -429,7 +429,7 @@ pub fn reg_alloc(config: &CpuConfig) {
|
||||||
);
|
);
|
||||||
connect(
|
connect(
|
||||||
selected_unit_index_leaf,
|
selected_unit_index_leaf,
|
||||||
Expr::ty(selected_unit_index_leaf).HdlNone(),
|
selected_unit_index_leaf.ty().HdlNone(),
|
||||||
);
|
);
|
||||||
let unit_index_wire = wire_with_loc(
|
let unit_index_wire = wire_with_loc(
|
||||||
&format!("unit_index_{fetch_index}_{unit_index}"),
|
&format!("unit_index_{fetch_index}_{unit_index}"),
|
||||||
|
|
@ -447,7 +447,7 @@ pub fn reg_alloc(config: &CpuConfig) {
|
||||||
let selected_unit_index_node = wire_with_loc(
|
let selected_unit_index_node = wire_with_loc(
|
||||||
&format!("selected_unit_index_node_{fetch_index}_{state}"),
|
&format!("selected_unit_index_node_{fetch_index}_{state}"),
|
||||||
SourceLocation::caller(),
|
SourceLocation::caller(),
|
||||||
Expr::ty(l),
|
l.ty(),
|
||||||
);
|
);
|
||||||
*state += 1;
|
*state += 1;
|
||||||
connect(selected_unit_index_node, l);
|
connect(selected_unit_index_node, l);
|
||||||
|
|
@ -516,7 +516,7 @@ pub fn reg_alloc(config: &CpuConfig) {
|
||||||
connect(unit_free_regs_tracker.alloc_out[0].ready, false);
|
connect(unit_free_regs_tracker.alloc_out[0].ready, false);
|
||||||
connect(
|
connect(
|
||||||
unit_to_reg_alloc.input.data,
|
unit_to_reg_alloc.input.data,
|
||||||
Expr::ty(unit_to_reg_alloc.input).data.HdlNone(),
|
unit_to_reg_alloc.input.ty().data.HdlNone(),
|
||||||
);
|
);
|
||||||
for fetch_index in 0..config.fetch_width.get() {
|
for fetch_index in 0..config.fetch_width.get() {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -550,7 +550,7 @@ pub fn reg_alloc(config: &CpuConfig) {
|
||||||
} else {
|
} else {
|
||||||
connect(
|
connect(
|
||||||
unit_to_reg_alloc.input.data,
|
unit_to_reg_alloc.input.data,
|
||||||
HdlSome(Expr::ty(unit_to_reg_alloc.input).data.HdlSome.uninit()),
|
HdlSome(unit_to_reg_alloc.input.ty().data.HdlSome.uninit()),
|
||||||
);
|
);
|
||||||
// FIXME: add hdl_assert(cd.clk, false.to_expr(), "");
|
// FIXME: add hdl_assert(cd.clk, false.to_expr(), "");
|
||||||
}
|
}
|
||||||
|
|
@ -578,7 +578,8 @@ pub fn reg_alloc(config: &CpuConfig) {
|
||||||
connect(unit_to_reg_alloc.unit_forwarding_info, unit_forwarding_info);
|
connect(unit_to_reg_alloc.unit_forwarding_info, unit_forwarding_info);
|
||||||
connect(
|
connect(
|
||||||
unit_forwarding_info.unit_output_writes[unit_index],
|
unit_forwarding_info.unit_output_writes[unit_index],
|
||||||
Expr::ty(unit_forwarding_info)
|
unit_forwarding_info
|
||||||
|
.ty()
|
||||||
.unit_output_writes
|
.unit_output_writes
|
||||||
.element()
|
.element()
|
||||||
.HdlNone(),
|
.HdlNone(),
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ pub fn unit_free_regs_tracker(
|
||||||
let reduced_alloc_nums = wire_with_loc(
|
let reduced_alloc_nums = wire_with_loc(
|
||||||
&format!("reduced_alloc_nums_{}_{}", range.start, range.end),
|
&format!("reduced_alloc_nums_{}_{}", range.start, range.end),
|
||||||
SourceLocation::caller(),
|
SourceLocation::caller(),
|
||||||
Array[UInt[Expr::ty(l.alloc_nums).element().width() + 1]][alloc_at_once.get()],
|
Array[UInt[l.alloc_nums.ty().element().width() + 1]][alloc_at_once.get()],
|
||||||
);
|
);
|
||||||
for alloc_index in 0..alloc_at_once.get() {
|
for alloc_index in 0..alloc_at_once.get() {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -120,10 +120,7 @@ pub fn unit_free_regs_tracker(
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use fayalite::{
|
use fayalite::{firrtl::ExportOptions, module::transform::simplify_enums::SimplifyEnumsKind};
|
||||||
cli::FormalMode, firrtl::ExportOptions,
|
|
||||||
module::transform::simplify_enums::SimplifyEnumsKind, testing::assert_formal,
|
|
||||||
};
|
|
||||||
use std::num::NonZero;
|
use std::num::NonZero;
|
||||||
|
|
||||||
fn test_unit_free_regs_tracker(
|
fn test_unit_free_regs_tracker(
|
||||||
|
|
@ -198,7 +195,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let free_before_alloc_array = wire(Array[Expr::ty(free_reg)][alloc_at_once.get() + 1]);
|
let free_before_alloc_array = wire(Array[free_reg.ty()][alloc_at_once.get() + 1]);
|
||||||
connect(free_before_alloc_array[0], free_reg);
|
connect(free_before_alloc_array[0], free_reg);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let expected_alloc = wire(Array[HdlOption[reg_num_ty]][alloc_at_once.get()]);
|
let expected_alloc = wire(Array[HdlOption[reg_num_ty]][alloc_at_once.get()]);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,14 @@
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
use fayalite::prelude::*;
|
|
||||||
|
use crate::instruction::ConditionMode;
|
||||||
|
use fayalite::{
|
||||||
|
expr::CastToImpl,
|
||||||
|
int::{BoolOrIntType, UIntInRange},
|
||||||
|
prelude::*,
|
||||||
|
ty::StaticType,
|
||||||
|
};
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
pub enum FlagsMode {
|
pub enum FlagsMode {
|
||||||
|
|
@ -8,95 +16,645 @@ pub enum FlagsMode {
|
||||||
X86(PRegFlagsX86),
|
X86(PRegFlagsX86),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait PRegFlagsViewTraitSealed {
|
||||||
|
type UnusedInner<T>: AsRef<[T]>
|
||||||
|
+ AsMut<[T]>
|
||||||
|
+ IntoIterator<
|
||||||
|
Item = T,
|
||||||
|
IntoIter: DoubleEndedIterator<Item = T>
|
||||||
|
+ ExactSizeIterator
|
||||||
|
+ std::iter::FusedIterator
|
||||||
|
+ Default,
|
||||||
|
>;
|
||||||
|
const UNUSED_INNER_LEN: usize;
|
||||||
|
fn unused_inner_map<T, R>(
|
||||||
|
v: Self::UnusedInner<T>,
|
||||||
|
f: impl FnMut(T) -> R,
|
||||||
|
) -> Self::UnusedInner<R>;
|
||||||
|
fn unused_inner_from_fn<T>(f: impl FnMut(usize) -> T) -> Self::UnusedInner<T>;
|
||||||
|
fn unused_inner_each_ref<T>(v: &Self::UnusedInner<T>) -> Self::UnusedInner<&T>;
|
||||||
|
fn unused_inner_each_mut<T>(v: &mut Self::UnusedInner<T>) -> Self::UnusedInner<&mut T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[expect(private_bounds)]
|
||||||
|
pub trait PRegFlagsViewTrait: Type + PRegFlagsViewTraitSealed {
|
||||||
|
type View<T>;
|
||||||
|
fn view<T: Type>(flags: impl ToExpr<Type = PRegFlags<T>>) -> Self::View<Expr<T>>;
|
||||||
|
fn view_sim<T: Type>(flags: impl ToSimValue<Type = PRegFlags<T>>) -> Self::View<SimValue<T>>;
|
||||||
|
fn view_sim_ref<T: Type>(flags: &SimValue<PRegFlags<T>>) -> Self::View<&SimValue<T>>;
|
||||||
|
fn view_sim_mut<T: Type>(flags: &mut SimValue<PRegFlags<T>>) -> Self::View<&mut SimValue<T>>;
|
||||||
|
fn from_view<T: ToExpr>(view: Self::View<T>) -> Expr<PRegFlags<T::Type>>;
|
||||||
|
fn from_view_sim<T: ToSimValue>(view: Self::View<T>) -> SimValue<PRegFlags<T::Type>>;
|
||||||
|
fn view_unused_into_view<T>(unused: ViewUnused<T, PRegFlagsAllUnused>) -> Self::View<T>;
|
||||||
|
fn view_into_view_unused<T>(view: Self::View<T>) -> ViewUnused<T, PRegFlagsAllUnused>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ViewUnused<T, V: PRegFlagsViewTrait>(V::UnusedInner<T>);
|
||||||
|
|
||||||
|
pub struct ViewUnusedIntoIter<T, V: PRegFlagsViewTrait>(
|
||||||
|
<V::UnusedInner<T> as IntoIterator>::IntoIter,
|
||||||
|
);
|
||||||
|
|
||||||
|
impl<T, V: PRegFlagsViewTrait> Iterator for ViewUnusedIntoIter<T, V> {
|
||||||
|
type Item = T;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
self.0.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
self.0.size_hint()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold<B, F>(self, init: B, f: F) -> B
|
||||||
|
where
|
||||||
|
F: FnMut(B, Self::Item) -> B,
|
||||||
|
{
|
||||||
|
self.0.fold(init, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn count(self) -> usize {
|
||||||
|
self.0.count()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn last(self) -> Option<Self::Item> {
|
||||||
|
self.0.last()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, V: PRegFlagsViewTrait> DoubleEndedIterator for ViewUnusedIntoIter<T, V> {
|
||||||
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
|
self.0.next_back()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rfold<B, F>(self, init: B, f: F) -> B
|
||||||
|
where
|
||||||
|
F: FnMut(B, Self::Item) -> B,
|
||||||
|
{
|
||||||
|
self.0.rfold(init, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, V: PRegFlagsViewTrait> ExactSizeIterator for ViewUnusedIntoIter<T, V> {
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.0.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, V: PRegFlagsViewTrait> std::iter::FusedIterator for ViewUnusedIntoIter<T, V> {}
|
||||||
|
|
||||||
|
impl<T, V: PRegFlagsViewTrait> Default for ViewUnusedIntoIter<T, V> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(Default::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Clone, V: PRegFlagsViewTrait> Clone for ViewUnusedIntoIter<T, V>
|
||||||
|
where
|
||||||
|
<V::UnusedInner<T> as IntoIterator>::IntoIter: Clone,
|
||||||
|
{
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self(self.0.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, V: PRegFlagsViewTrait> IntoIterator for ViewUnused<T, V> {
|
||||||
|
type Item = T;
|
||||||
|
type IntoIter = ViewUnusedIntoIter<T, V>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
ViewUnusedIntoIter(self.0.into_iter())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Default, V: PRegFlagsViewTrait> Default for ViewUnused<T, V> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::from_fn(|_| T::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, V: PRegFlagsViewTrait> ViewUnused<T, V> {
|
||||||
|
pub fn iter(&self) -> std::slice::Iter<'_, T> {
|
||||||
|
self.into_iter()
|
||||||
|
}
|
||||||
|
pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
|
||||||
|
self.into_iter()
|
||||||
|
}
|
||||||
|
pub fn from_fn(f: impl FnMut(usize) -> T) -> Self {
|
||||||
|
ViewUnused(V::unused_inner_from_fn(f))
|
||||||
|
}
|
||||||
|
pub fn each_ref(&self) -> ViewUnused<&T, V> {
|
||||||
|
ViewUnused(V::unused_inner_each_ref(&self.0))
|
||||||
|
}
|
||||||
|
pub fn each_mut(&mut self) -> ViewUnused<&mut T, V> {
|
||||||
|
ViewUnused(V::unused_inner_each_mut(&mut self.0))
|
||||||
|
}
|
||||||
|
pub fn map<R>(self, f: impl FnMut(T) -> R) -> ViewUnused<R, V> {
|
||||||
|
ViewUnused(V::unused_inner_map(self.0, f))
|
||||||
|
}
|
||||||
|
pub fn zip<U>(self, other: ViewUnused<U, V>) -> ViewUnused<(T, U), V> {
|
||||||
|
let mut iter = self.into_iter().zip(other);
|
||||||
|
ViewUnused::from_fn(|_| iter.next().expect("known to be Some"))
|
||||||
|
}
|
||||||
|
pub fn splat(v: T) -> Self
|
||||||
|
where
|
||||||
|
T: Clone,
|
||||||
|
{
|
||||||
|
let mut v = Some(v);
|
||||||
|
Self::from_fn(|i| {
|
||||||
|
let v = if i == V::UNUSED_INNER_LEN - 1 {
|
||||||
|
v.take()
|
||||||
|
} else {
|
||||||
|
v.clone()
|
||||||
|
};
|
||||||
|
let Some(v) = v else {
|
||||||
|
unreachable!();
|
||||||
|
};
|
||||||
|
v
|
||||||
|
})
|
||||||
|
}
|
||||||
|
pub fn splat_copied(v: T) -> Self
|
||||||
|
where
|
||||||
|
T: Copy,
|
||||||
|
{
|
||||||
|
Self::from_fn(|_| v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: BoolOrIntType, V: PRegFlagsViewTrait> ViewUnused<SimValue<T>, V> {
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
for i in self.iter_mut() {
|
||||||
|
SimValue::bits_mut(i).bits_mut().fill(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: BoolOrIntType, V: PRegFlagsViewTrait> ViewUnused<&'_ mut SimValue<T>, V> {
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
for i in self.iter_mut() {
|
||||||
|
SimValue::bits_mut(i).bits_mut().fill(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: BoolOrIntType, V: PRegFlagsViewTrait> ViewUnused<Expr<T>, V>
|
||||||
|
where
|
||||||
|
UInt: CastToImpl<T, ValueOutput: ToExpr>,
|
||||||
|
{
|
||||||
|
pub fn clear(self) {
|
||||||
|
for i in self {
|
||||||
|
connect(i, UInt::new_dyn(i.ty().width()).zero().cast_to(i.ty()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T, V: PRegFlagsViewTrait> IntoIterator for &'a ViewUnused<T, V> {
|
||||||
|
type Item = &'a T;
|
||||||
|
type IntoIter = std::slice::Iter<'a, T>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.0.as_ref().iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T, V: PRegFlagsViewTrait> IntoIterator for &'a mut ViewUnused<T, V> {
|
||||||
|
type Item = &'a mut T;
|
||||||
|
type IntoIter = std::slice::IterMut<'a, T>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.0.as_mut().iter_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Clone, V: PRegFlagsViewTrait> Clone for ViewUnused<T, V>
|
||||||
|
where
|
||||||
|
V::UnusedInner<T>: Clone,
|
||||||
|
{
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self(self.0.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Copy, V: PRegFlagsViewTrait> Copy for ViewUnused<T, V> where V::UnusedInner<T>: Copy {}
|
||||||
|
|
||||||
|
impl<T: fmt::Debug, V: PRegFlagsViewTrait> fmt::Debug for ViewUnused<T, V>
|
||||||
|
where
|
||||||
|
V::UnusedInner<T>: fmt::Debug,
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_tuple("ViewUnused").field(&self.0).finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_view_trait {
|
||||||
|
(
|
||||||
|
$(#[$flags_mode_meta:meta])*
|
||||||
|
$flags_mode_vis:vis struct $FlagsMode:ident {}
|
||||||
|
|
||||||
|
$(#[$view_meta:meta])*
|
||||||
|
$view_vis:vis struct $View:ident {
|
||||||
|
$(#[$unused_field_meta:meta])*
|
||||||
|
$unused_vis:vis $unused:ident: ViewUnused([$($unused_field:ident),* $(,)?]),
|
||||||
|
$($(#[$view_field_meta:meta])*
|
||||||
|
$view_field_vis:vis $view_field:ident: $flags_field:ident,)*
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
$(#[$flags_mode_meta])*
|
||||||
|
$flags_mode_vis struct $FlagsMode {}
|
||||||
|
|
||||||
|
$(#[$view_meta])*
|
||||||
|
$view_vis struct $View<T> {
|
||||||
|
$(#[$unused_field_meta])*
|
||||||
|
$unused_vis $unused: ViewUnused<T, $FlagsMode>,
|
||||||
|
$($(#[$view_field_meta])*
|
||||||
|
$view_field_vis $view_field: T,)*
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> $View<&'_ mut T> {
|
||||||
|
$view_vis const fn reborrow<'a>(&'a mut self) -> $View<&'a mut T> {
|
||||||
|
let $View {
|
||||||
|
$unused: ViewUnused([$($unused_field,)*]),
|
||||||
|
$($view_field: $flags_field,)*
|
||||||
|
} = self;
|
||||||
|
$View {
|
||||||
|
$unused: ViewUnused([$(&mut **$unused_field,)*]),
|
||||||
|
$($view_field: &mut **$flags_field,)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> $View<T> {
|
||||||
|
$view_vis fn splat(v: T) -> Self
|
||||||
|
where
|
||||||
|
T: Clone,
|
||||||
|
{
|
||||||
|
$View {
|
||||||
|
$($view_field: v.clone(),)*
|
||||||
|
$unused: ViewUnused::splat(v),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$view_vis const fn splat_copied(v: T) -> Self
|
||||||
|
where
|
||||||
|
T: Copy,
|
||||||
|
{
|
||||||
|
$View {
|
||||||
|
$($view_field: v,)*
|
||||||
|
$unused: ViewUnused([v; _]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$view_vis fn map<R>(self, mut f: impl FnMut(T) -> R) -> $View<R> {
|
||||||
|
#![allow(unused_mut)]
|
||||||
|
let $View {
|
||||||
|
$unused,
|
||||||
|
$($view_field,)*
|
||||||
|
} = self;
|
||||||
|
$View {
|
||||||
|
$($view_field: f($view_field),)*
|
||||||
|
$unused: $unused.map(f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$view_vis fn zip<U>(self, other: $View<U>) -> $View<(T, U)> {
|
||||||
|
struct Fields<T> {
|
||||||
|
$($unused_field: T,)*
|
||||||
|
$($flags_field: T,)*
|
||||||
|
}
|
||||||
|
let $View {
|
||||||
|
$unused: ViewUnused([$($unused_field,)*]),
|
||||||
|
$($view_field: $flags_field,)*
|
||||||
|
} = self;
|
||||||
|
let this = Fields {
|
||||||
|
$($unused_field,)*
|
||||||
|
$($flags_field,)*
|
||||||
|
};
|
||||||
|
let $View {
|
||||||
|
$unused: ViewUnused([$($unused_field,)*]),
|
||||||
|
$($view_field: $flags_field,)*
|
||||||
|
} = other;
|
||||||
|
let other = Fields {
|
||||||
|
$($unused_field,)*
|
||||||
|
$($flags_field,)*
|
||||||
|
};
|
||||||
|
$View {
|
||||||
|
$unused: ViewUnused([$((this.$unused_field, other.$unused_field),)*]),
|
||||||
|
$($view_field: (this.$flags_field, other.$flags_field),)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PRegFlagsViewTraitSealed for $FlagsMode {
|
||||||
|
type UnusedInner<T> = [T; Self::UNUSED_INNER_LEN];
|
||||||
|
const UNUSED_INNER_LEN: usize = {
|
||||||
|
let v: &[&str] = &[$(stringify!($unused_field),)*];
|
||||||
|
v.len()
|
||||||
|
};
|
||||||
|
fn unused_inner_map<T, R>(
|
||||||
|
v: Self::UnusedInner<T>,
|
||||||
|
f: impl FnMut(T) -> R,
|
||||||
|
) -> Self::UnusedInner<R> {
|
||||||
|
v.map(f)
|
||||||
|
}
|
||||||
|
fn unused_inner_from_fn<T>(f: impl FnMut(usize) -> T) -> Self::UnusedInner<T> {
|
||||||
|
std::array::from_fn(f)
|
||||||
|
}
|
||||||
|
fn unused_inner_each_ref<T>(
|
||||||
|
v: &Self::UnusedInner<T>,
|
||||||
|
) -> Self::UnusedInner<&T> {
|
||||||
|
v.each_ref()
|
||||||
|
}
|
||||||
|
fn unused_inner_each_mut<T>(
|
||||||
|
v: &mut Self::UnusedInner<T>,
|
||||||
|
) -> Self::UnusedInner<&mut T> {
|
||||||
|
v.each_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PRegFlagsViewTrait for $FlagsMode {
|
||||||
|
type View<T> = $View<T>;
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
fn view<T: Type>(flags: impl ToExpr<Type = PRegFlags<T>>) -> Self::View<Expr<T>> {
|
||||||
|
#[hdl]
|
||||||
|
let PRegFlags::<T> {
|
||||||
|
$($unused_field,)*
|
||||||
|
$($flags_field,)*
|
||||||
|
} = flags.to_expr();
|
||||||
|
$View {
|
||||||
|
$unused: ViewUnused([$($unused_field,)*]),
|
||||||
|
$($view_field: $flags_field,)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
fn view_sim<T: Type>(flags: impl ToSimValue<Type = PRegFlags<T>>) -> Self::View<SimValue<T>> {
|
||||||
|
#[hdl(sim)]
|
||||||
|
let PRegFlags::<T> {
|
||||||
|
$($unused_field,)*
|
||||||
|
$($flags_field,)*
|
||||||
|
} = flags.into_sim_value();
|
||||||
|
$View {
|
||||||
|
$unused: ViewUnused([$($unused_field,)*]),
|
||||||
|
$($view_field: $flags_field,)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
fn view_sim_ref<T: Type>(flags: &SimValue<PRegFlags<T>>) -> Self::View<&SimValue<T>> {
|
||||||
|
#[hdl(sim)]
|
||||||
|
let PRegFlags::<T> {
|
||||||
|
$($unused_field,)*
|
||||||
|
$($flags_field,)*
|
||||||
|
} = flags;
|
||||||
|
$View {
|
||||||
|
$unused: ViewUnused([$($unused_field,)*]),
|
||||||
|
$($view_field: $flags_field,)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
fn view_sim_mut<T: Type>(flags: &mut SimValue<PRegFlags<T>>) -> Self::View<&mut SimValue<T>> {
|
||||||
|
#[hdl(sim)]
|
||||||
|
let PRegFlags::<T> {
|
||||||
|
$($unused_field,)*
|
||||||
|
$($flags_field,)*
|
||||||
|
} = flags;
|
||||||
|
$View {
|
||||||
|
$unused: ViewUnused([$($unused_field,)*]),
|
||||||
|
$($view_field: $flags_field,)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
fn from_view<T: ToExpr>(view: Self::View<T>) -> Expr<PRegFlags<T::Type>> {
|
||||||
|
let $View {
|
||||||
|
$unused: ViewUnused([$($unused_field,)*]),
|
||||||
|
$($view_field: $flags_field,)*
|
||||||
|
} = view;
|
||||||
|
#[hdl]
|
||||||
|
PRegFlags::<_> {
|
||||||
|
$($unused_field,)*
|
||||||
|
$($flags_field,)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
fn from_view_sim<T: ToSimValue>(view: Self::View<T>) -> SimValue<PRegFlags<T::Type>> {
|
||||||
|
let $View {
|
||||||
|
$unused: ViewUnused([$($unused_field,)*]),
|
||||||
|
$($view_field: $flags_field,)*
|
||||||
|
} = view;
|
||||||
|
#[hdl(sim)]
|
||||||
|
PRegFlags::<_> {
|
||||||
|
$($unused_field,)*
|
||||||
|
$($flags_field,)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn view_unused_into_view<T>(unused: ViewUnused<T, PRegFlagsAllUnused>) -> Self::View<T> {
|
||||||
|
let fields = Fields::from_view_unused(unused);
|
||||||
|
$View {
|
||||||
|
$unused: ViewUnused([$(fields.$unused_field,)*]),
|
||||||
|
$($view_field: fields.$flags_field,)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn view_into_view_unused<T>(view: Self::View<T>) -> ViewUnused<T, PRegFlagsAllUnused> {
|
||||||
|
let $View {
|
||||||
|
$unused: ViewUnused([$($unused_field,)*]),
|
||||||
|
$($view_field: $flags_field,)*
|
||||||
|
} = view;
|
||||||
|
let fields = Fields {
|
||||||
|
$($unused_field,)*
|
||||||
|
$($flags_field,)*
|
||||||
|
};
|
||||||
|
fields.into_view_unused()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_view_trait! {
|
||||||
#[hdl(cmp_eq)]
|
#[hdl(cmp_eq)]
|
||||||
pub struct PRegFlagsPowerISA {}
|
pub struct PRegFlagsPowerISA {}
|
||||||
|
|
||||||
impl PRegFlagsPowerISA {
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub fn xer_ca(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
#[non_exhaustive]
|
||||||
flags.to_expr().pwr_ca_x86_cf
|
pub struct PRegFlagsPowerISAView {
|
||||||
}
|
pub unused: ViewUnused([]),
|
||||||
pub fn xer_ca32(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
pub xer_ca: pwr_ca_x86_cf,
|
||||||
flags.to_expr().pwr_ca32_x86_af
|
pub xer_ca32: pwr_ca32_x86_af,
|
||||||
}
|
pub xer_ov: pwr_ov_x86_of,
|
||||||
pub fn xer_ov(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
pub xer_ov32: pwr_ov32_x86_df,
|
||||||
flags.to_expr().pwr_ov_x86_of
|
pub cr_lt: pwr_cr_lt_x86_sf,
|
||||||
}
|
pub cr_gt: pwr_cr_gt_x86_pf,
|
||||||
pub fn xer_ov32(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
pub cr_eq: pwr_cr_eq_x86_zf,
|
||||||
flags.to_expr().pwr_ov32_x86_df
|
|
||||||
}
|
|
||||||
/// both `CR<N>.SO` and `XER.SO` since instructions that write to both always write the same value
|
/// both `CR<N>.SO` and `XER.SO` since instructions that write to both always write the same value
|
||||||
pub fn so(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
pub so: pwr_so,
|
||||||
flags.to_expr().pwr_so
|
|
||||||
}
|
|
||||||
pub fn cr_lt(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
|
||||||
flags.to_expr().pwr_cr_lt_x86_sf
|
|
||||||
}
|
|
||||||
pub fn cr_gt(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
|
||||||
flags.to_expr().pwr_cr_gt_x86_pf
|
|
||||||
}
|
|
||||||
pub fn cr_eq(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
|
||||||
flags.to_expr().pwr_cr_eq_x86_zf
|
|
||||||
}
|
|
||||||
#[hdl]
|
|
||||||
pub fn clear_unused(flags: impl ToExpr<Type = PRegFlags>) {
|
|
||||||
// list all flags explicitly so we don't miss handling any new flags
|
|
||||||
#[hdl]
|
|
||||||
let PRegFlags {
|
|
||||||
pwr_ca_x86_cf: _,
|
|
||||||
pwr_ca32_x86_af: _,
|
|
||||||
pwr_ov_x86_of: _,
|
|
||||||
pwr_ov32_x86_df: _,
|
|
||||||
pwr_cr_lt_x86_sf: _,
|
|
||||||
pwr_cr_gt_x86_pf: _,
|
|
||||||
pwr_cr_eq_x86_zf: _,
|
|
||||||
pwr_so: _,
|
|
||||||
} = flags;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PRegFlagsPowerISAView<Option<usize>> {
|
||||||
|
pub const CR_BIT_LE_INDEXES: Self = {
|
||||||
|
let mut v = Self::splat_copied(None);
|
||||||
|
let bits = v.cr_bits_lsb0_mut();
|
||||||
|
let mut i = 0;
|
||||||
|
while i < bits.len() {
|
||||||
|
*bits[i] = Some(i);
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
v
|
||||||
|
};
|
||||||
|
pub const CR_BIT_BE_INDEXES: Self = {
|
||||||
|
let mut v = Self::splat_copied(None);
|
||||||
|
let bits = v.cr_bits_msb0_mut();
|
||||||
|
let mut i = 0;
|
||||||
|
while i < bits.len() {
|
||||||
|
*bits[i] = Some(i);
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
v
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PRegFlagsPowerISAView<Option<SimValue<ConditionMode>>> {
|
||||||
|
pub fn cr_condition_modes_sim() -> Self {
|
||||||
|
PRegFlagsPowerISAView::cr_condition_modes().map(|v| v.map(ToSimValue::into_sim_value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PRegFlagsPowerISAView<Option<Expr<ConditionMode>>> {
|
||||||
|
pub fn cr_condition_modes() -> Self {
|
||||||
|
Self {
|
||||||
|
unused: ViewUnused([]),
|
||||||
|
xer_ca: None,
|
||||||
|
xer_ca32: None,
|
||||||
|
xer_ov: None,
|
||||||
|
xer_ov32: None,
|
||||||
|
cr_lt: Some(ConditionMode.SLt()),
|
||||||
|
cr_gt: Some(ConditionMode.SGt()),
|
||||||
|
cr_eq: Some(ConditionMode.Eq()),
|
||||||
|
so: Some(ConditionMode.Overflow()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> PRegFlagsPowerISAView<T> {
|
||||||
|
pub fn into_cr_bits_msb0(self) -> [T; 4] {
|
||||||
|
[self.cr_lt, self.cr_gt, self.cr_eq, self.so]
|
||||||
|
}
|
||||||
|
pub const fn cr_bits_msb0_ref(&self) -> [&T; 4] {
|
||||||
|
[&self.cr_lt, &self.cr_gt, &self.cr_eq, &self.so]
|
||||||
|
}
|
||||||
|
pub const fn cr_bits_msb0_mut(&mut self) -> [&mut T; 4] {
|
||||||
|
[
|
||||||
|
&mut self.cr_lt,
|
||||||
|
&mut self.cr_gt,
|
||||||
|
&mut self.cr_eq,
|
||||||
|
&mut self.so,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
pub fn into_cr_bits_lsb0(self) -> [T; 4] {
|
||||||
|
let mut retval = self.into_cr_bits_msb0();
|
||||||
|
retval.reverse();
|
||||||
|
retval
|
||||||
|
}
|
||||||
|
pub const fn cr_bits_lsb0_ref(&self) -> [&T; 4] {
|
||||||
|
let [b0, b1, b2, b3] = self.cr_bits_msb0_ref();
|
||||||
|
[b3, b2, b1, b0]
|
||||||
|
}
|
||||||
|
pub const fn cr_bits_lsb0_mut(&mut self) -> [&mut T; 4] {
|
||||||
|
let [b0, b1, b2, b3] = self.cr_bits_msb0_mut();
|
||||||
|
[b3, b2, b1, b0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PRegFlagsPowerISA {
|
||||||
|
pub fn cr_condition_modes_msb0() -> [Expr<ConditionMode>; 4] {
|
||||||
|
PRegFlagsPowerISAView::cr_condition_modes()
|
||||||
|
.into_cr_bits_msb0()
|
||||||
|
.map(|v| v.expect("known to be Some"))
|
||||||
|
}
|
||||||
|
pub fn cr_condition_modes_lsb0() -> [Expr<ConditionMode>; 4] {
|
||||||
|
PRegFlagsPowerISAView::cr_condition_modes()
|
||||||
|
.into_cr_bits_lsb0()
|
||||||
|
.map(|v| v.expect("known to be Some"))
|
||||||
|
}
|
||||||
|
pub fn cr_condition_modes_msb0_sim() -> [SimValue<ConditionMode>; 4] {
|
||||||
|
PRegFlagsPowerISAView::cr_condition_modes_sim()
|
||||||
|
.into_cr_bits_msb0()
|
||||||
|
.map(|v| v.expect("known to be Some"))
|
||||||
|
}
|
||||||
|
pub fn cr_condition_modes_lsb0_sim() -> [SimValue<ConditionMode>; 4] {
|
||||||
|
PRegFlagsPowerISAView::cr_condition_modes_sim()
|
||||||
|
.into_cr_bits_lsb0()
|
||||||
|
.map(|v| v.expect("known to be Some"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_view_trait! {
|
||||||
#[hdl(cmp_eq)]
|
#[hdl(cmp_eq)]
|
||||||
pub struct PRegFlagsX86 {}
|
pub struct PRegFlagsX86 {}
|
||||||
|
|
||||||
impl PRegFlagsX86 {
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub fn cf(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
#[non_exhaustive]
|
||||||
flags.to_expr().pwr_ca_x86_cf
|
pub struct PRegFlagsX86View {
|
||||||
}
|
pub unused: ViewUnused([pwr_so]),
|
||||||
pub fn zf(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
pub cf: pwr_ca_x86_cf,
|
||||||
flags.to_expr().pwr_cr_eq_x86_zf
|
pub zf: pwr_cr_eq_x86_zf,
|
||||||
}
|
pub sf: pwr_cr_lt_x86_sf,
|
||||||
pub fn sf(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
pub of: pwr_ov_x86_of,
|
||||||
flags.to_expr().pwr_cr_lt_x86_sf
|
pub af: pwr_ca32_x86_af,
|
||||||
}
|
pub pf: pwr_cr_gt_x86_pf,
|
||||||
pub fn of(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
pub df: pwr_ov32_x86_df,
|
||||||
flags.to_expr().pwr_ov_x86_of
|
|
||||||
}
|
|
||||||
pub fn af(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
|
||||||
flags.to_expr().pwr_ca32_x86_af
|
|
||||||
}
|
|
||||||
pub fn pf(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
|
||||||
flags.to_expr().pwr_cr_gt_x86_pf
|
|
||||||
}
|
|
||||||
pub fn df(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
|
||||||
flags.to_expr().pwr_ov32_x86_df
|
|
||||||
}
|
|
||||||
#[hdl]
|
|
||||||
pub fn clear_unused(flags: impl ToExpr<Type = PRegFlags>) {
|
|
||||||
// list all flags explicitly so we don't miss handling any new flags
|
|
||||||
#[hdl]
|
|
||||||
let PRegFlags {
|
|
||||||
pwr_ca_x86_cf: _,
|
|
||||||
pwr_ca32_x86_af: _,
|
|
||||||
pwr_ov_x86_of: _,
|
|
||||||
pwr_ov32_x86_df: _,
|
|
||||||
pwr_cr_lt_x86_sf: _,
|
|
||||||
pwr_cr_gt_x86_pf: _,
|
|
||||||
pwr_cr_eq_x86_zf: _,
|
|
||||||
pwr_so: unused1,
|
|
||||||
} = flags;
|
|
||||||
connect(unused1, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_flags {
|
||||||
|
(
|
||||||
|
$(#[$struct_meta:meta])*
|
||||||
|
$struct_vis:vis struct $PRegFlags:ident<$T:ident: Type = Bool> {
|
||||||
|
$($field:ident: T,)*
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
$(#[$struct_meta])*
|
||||||
|
$struct_vis struct $PRegFlags<$T: Type = Bool> {
|
||||||
|
$($field: $T,)*
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Fields<$T> {
|
||||||
|
$($field: $T,)*
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<$T> Fields<$T> {
|
||||||
|
fn from_view_unused(unused: ViewUnused<$T, PRegFlagsAllUnused>) -> Self {
|
||||||
|
let ViewUnused([
|
||||||
|
$($field,)*
|
||||||
|
]) = unused;
|
||||||
|
Self {
|
||||||
|
$($field,)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn into_view_unused(self) -> ViewUnused<$T, PRegFlagsAllUnused> {
|
||||||
|
ViewUnused([
|
||||||
|
$(self.$field,)*
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_view_trait! {
|
||||||
|
#[hdl(cmp_eq)]
|
||||||
|
pub struct PRegFlagsAllUnused {}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub struct PRegFlagsAllUnusedView {
|
||||||
|
pub unused: ViewUnused([
|
||||||
|
$($field,)*
|
||||||
|
]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_flags! {
|
||||||
#[hdl(cmp_eq)]
|
#[hdl(cmp_eq)]
|
||||||
/// this is *not* the same as any particular ISA's flags register,
|
/// this is *not* the same as any particular ISA's flags register,
|
||||||
/// on PowerISA it is a combination of some bits from XER with a single 4-bit CR field.
|
/// on PowerISA it is a combination of some bits from XER with a single 4-bit CR field.
|
||||||
|
|
@ -105,34 +663,103 @@ impl PRegFlagsX86 {
|
||||||
///
|
///
|
||||||
/// * PowerISA: [`struct@PRegFlagsPowerISA`]
|
/// * PowerISA: [`struct@PRegFlagsPowerISA`]
|
||||||
/// * x86: [`struct@PRegFlagsX86`]
|
/// * x86: [`struct@PRegFlagsX86`]
|
||||||
pub struct PRegFlags {
|
pub struct PRegFlags<T: Type = Bool> {
|
||||||
pwr_ca_x86_cf: Bool,
|
pwr_ca32_x86_af: T,
|
||||||
pwr_ca32_x86_af: Bool,
|
pwr_ca_x86_cf: T,
|
||||||
pwr_ov_x86_of: Bool,
|
pwr_ov32_x86_df: T,
|
||||||
pwr_ov32_x86_df: Bool,
|
pwr_ov_x86_of: T,
|
||||||
pwr_cr_lt_x86_sf: Bool,
|
pwr_so: T,
|
||||||
pwr_cr_gt_x86_pf: Bool,
|
pwr_cr_eq_x86_zf: T,
|
||||||
pwr_cr_eq_x86_zf: Bool,
|
pwr_cr_gt_x86_pf: T,
|
||||||
pwr_so: Bool,
|
pwr_cr_lt_x86_sf: T,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Type> PRegFlags<T> {
|
||||||
|
pub const fn field_ty(self) -> T {
|
||||||
|
self.pwr_so
|
||||||
|
}
|
||||||
|
pub fn view<V: PRegFlagsViewTrait>(flags: impl ToExpr<Type = Self>) -> V::View<Expr<T>> {
|
||||||
|
V::view(flags)
|
||||||
|
}
|
||||||
|
pub fn view_sim<V: PRegFlagsViewTrait>(
|
||||||
|
flags: impl ToSimValue<Type = Self>,
|
||||||
|
) -> V::View<SimValue<T>> {
|
||||||
|
V::view_sim(flags)
|
||||||
|
}
|
||||||
|
pub fn view_sim_ref<V: PRegFlagsViewTrait>(flags: &SimValue<Self>) -> V::View<&SimValue<T>> {
|
||||||
|
V::view_sim_ref(flags)
|
||||||
|
}
|
||||||
|
pub fn view_sim_mut<V: PRegFlagsViewTrait>(
|
||||||
|
flags: &mut SimValue<Self>,
|
||||||
|
) -> V::View<&mut SimValue<T>> {
|
||||||
|
V::view_sim_mut(flags)
|
||||||
|
}
|
||||||
|
pub fn from_view<V: PRegFlagsViewTrait>(view: V::View<impl ToExpr<Type = T>>) -> Expr<Self> {
|
||||||
|
V::from_view(view)
|
||||||
|
}
|
||||||
|
pub fn from_view_sim<V: PRegFlagsViewTrait>(
|
||||||
|
view: V::View<impl ToSimValue<Type = T>>,
|
||||||
|
) -> SimValue<Self> {
|
||||||
|
V::from_view_sim(view)
|
||||||
|
}
|
||||||
|
pub fn fields(flags: impl ToExpr<Type = Self>) -> ViewUnused<Expr<T>, PRegFlagsAllUnused> {
|
||||||
|
Self::view::<PRegFlagsAllUnused>(flags).unused
|
||||||
|
}
|
||||||
|
pub fn fields_sim(
|
||||||
|
flags: impl ToSimValue<Type = Self>,
|
||||||
|
) -> ViewUnused<SimValue<T>, PRegFlagsAllUnused> {
|
||||||
|
Self::view_sim::<PRegFlagsAllUnused>(flags).unused
|
||||||
|
}
|
||||||
|
pub fn fields_sim_ref(flags: &SimValue<Self>) -> ViewUnused<&SimValue<T>, PRegFlagsAllUnused> {
|
||||||
|
Self::view_sim_ref::<PRegFlagsAllUnused>(flags).unused
|
||||||
|
}
|
||||||
|
pub fn fields_sim_mut(
|
||||||
|
flags: &mut SimValue<Self>,
|
||||||
|
) -> ViewUnused<&mut SimValue<T>, PRegFlagsAllUnused> {
|
||||||
|
Self::view_sim_mut::<PRegFlagsAllUnused>(flags).unused
|
||||||
|
}
|
||||||
|
pub fn from_fields(
|
||||||
|
fields: ViewUnused<impl ToExpr<Type = T>, PRegFlagsAllUnused>,
|
||||||
|
) -> Expr<Self> {
|
||||||
|
Self::from_view::<PRegFlagsAllUnused>(PRegFlagsAllUnusedView { unused: fields })
|
||||||
|
}
|
||||||
|
pub fn from_fields_sim(
|
||||||
|
fields: ViewUnused<impl ToSimValue<Type = T>, PRegFlagsAllUnused>,
|
||||||
|
) -> SimValue<Self> {
|
||||||
|
Self::from_view_sim::<PRegFlagsAllUnused>(PRegFlagsAllUnusedView { unused: fields })
|
||||||
|
}
|
||||||
|
/// if trying to set all fields individually, prefer using the individual accessor
|
||||||
|
/// functions and [`PRegFlagsPowerISA::clear_unused()`]/[`PRegFlagsX86::clear_unused()`]/etc.
|
||||||
|
pub fn splat(v: impl ToExpr<Type = T>) -> Expr<Self> {
|
||||||
|
Self::from_fields(ViewUnused::splat(v.to_expr()))
|
||||||
|
}
|
||||||
|
/// if trying to set all fields individually, prefer using the individual accessor
|
||||||
|
/// functions and [`PRegFlagsPowerISA::clear_unused()`]/[`PRegFlagsX86::clear_unused()`]/etc.
|
||||||
|
pub fn splat_sim(v: impl ToSimValue<Type = T>) -> SimValue<Self> {
|
||||||
|
Self::from_fields_sim(ViewUnused::splat(v.into_sim_value()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PRegFlags<UIntInRange<0, { PRegFlags::FLAG_COUNT }>> {
|
||||||
|
pub fn flag_indexes() -> SimValue<Self> {
|
||||||
|
let ty = <Self as StaticType>::TYPE.field_ty();
|
||||||
|
Self::from_fields_sim(ViewUnused::from_fn(|i| i.to_sim_value_with_type(ty)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PRegFlags {
|
impl PRegFlags {
|
||||||
/// if trying to set all fields individually, prefer using the individual accessor
|
/// if trying to set all fields individually, prefer using the individual accessor
|
||||||
/// functions and [`PRegFlagsPowerISA::clear_unused()`]/[`PRegFlagsX86::clear_unused()`]/etc.
|
/// functions and [`PRegFlagsPowerISA::clear_unused()`]/[`PRegFlagsX86::clear_unused()`]/etc.
|
||||||
#[hdl]
|
|
||||||
pub fn zeroed() -> Expr<PRegFlags> {
|
pub fn zeroed() -> Expr<PRegFlags> {
|
||||||
#[hdl]
|
Self::splat(false)
|
||||||
PRegFlags {
|
|
||||||
pwr_ca_x86_cf: false,
|
|
||||||
pwr_ca32_x86_af: false,
|
|
||||||
pwr_ov_x86_of: false,
|
|
||||||
pwr_ov32_x86_df: false,
|
|
||||||
pwr_cr_lt_x86_sf: false,
|
|
||||||
pwr_cr_gt_x86_pf: false,
|
|
||||||
pwr_cr_eq_x86_zf: false,
|
|
||||||
pwr_so: false,
|
|
||||||
}
|
}
|
||||||
|
/// if trying to set all fields individually, prefer using the individual accessor
|
||||||
|
/// functions and [`PRegFlagsPowerISA::clear_unused()`]/[`PRegFlagsX86::clear_unused()`]/etc.
|
||||||
|
pub fn zeroed_sim() -> SimValue<PRegFlags> {
|
||||||
|
Self::splat_sim(false)
|
||||||
}
|
}
|
||||||
|
pub const FLAG_COUNT: usize = PRegFlagsAllUnused::UNUSED_INNER_LEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl(cmp_eq)]
|
#[hdl(cmp_eq)]
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,9 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
config::CpuConfig,
|
config::CpuConfig,
|
||||||
instruction::{
|
instruction::{
|
||||||
AluBranchMOp, LoadStoreMOp, MOp, MOpDestReg, MOpInto, MOpRegNum, MOpTrait, RenamedMOp,
|
AluBranchMOp, LoadStoreMOp, MOp, MOpDestReg, MOpInto, MOpRegNum, MOpTrait,
|
||||||
UnitOutRegNum, mop_enum,
|
MOpVariantVisitOps, MOpVariantVisitor, MOpVisitVariants, RenamedMOp, UnitOutRegNum,
|
||||||
|
mop_enum,
|
||||||
},
|
},
|
||||||
register::{FlagsMode, PRegValue},
|
register::{FlagsMode, PRegValue},
|
||||||
unit::unit_base::UnitToRegAlloc,
|
unit::unit_base::UnitToRegAlloc,
|
||||||
|
|
@ -15,6 +16,8 @@ use fayalite::{
|
||||||
intern::{Intern, Interned},
|
intern::{Intern, Interned},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
pub mod alu_branch;
|
pub mod alu_branch;
|
||||||
pub mod unit_base;
|
pub mod unit_base;
|
||||||
|
|
@ -36,7 +39,7 @@ macro_rules! all_units {
|
||||||
}
|
}
|
||||||
) => {
|
) => {
|
||||||
$(#[$enum_meta])*
|
$(#[$enum_meta])*
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
|
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Serialize, Deserialize)]
|
||||||
$vis enum $UnitKind {
|
$vis enum $UnitKind {
|
||||||
$(
|
$(
|
||||||
$(#[$variant_meta])*
|
$(#[$variant_meta])*
|
||||||
|
|
@ -52,9 +55,16 @@ macro_rules! all_units {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToExpr for $UnitKind {
|
impl ValueType for $UnitKind {
|
||||||
type Type = $HdlUnitKind;
|
type Type = $HdlUnitKind;
|
||||||
|
type ValueCategory = fayalite::expr::value_category::ValueCategoryExpr;
|
||||||
|
|
||||||
|
fn ty(&self) -> Self::Type {
|
||||||
|
$HdlUnitKind
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToExpr for $UnitKind {
|
||||||
fn to_expr(&self) -> Expr<Self::Type> {
|
fn to_expr(&self) -> Expr<Self::Type> {
|
||||||
match self {
|
match self {
|
||||||
$($UnitKind::$Unit => $HdlUnitKind.$Unit(),)*
|
$($UnitKind::$Unit => $HdlUnitKind.$Unit(),)*
|
||||||
|
|
@ -75,7 +85,15 @@ macro_rules! all_units {
|
||||||
#[impl_mop_into = false]
|
#[impl_mop_into = false]
|
||||||
#[hdl]
|
#[hdl]
|
||||||
$(#[$enum_meta])*
|
$(#[$enum_meta])*
|
||||||
$vis enum $UnitMOpEnum<$DestReg: Type, $SrcRegWidth: Size, #[MOp(get_ty = $transformed_move_op_get_ty)] $TransformedMoveOp: Type> {
|
$vis enum $UnitMOpEnum<
|
||||||
|
$DestReg: Type,
|
||||||
|
$SrcRegWidth: Size,
|
||||||
|
#[MOp(get_ty = $transformed_move_op_get_ty)] $TransformedMoveOp: Type,
|
||||||
|
#[MOpVisitVariants] [
|
||||||
|
$TransformedMoveOp: MOpVisitVariants<DestReg = $DestReg, SrcRegWidth = $SrcRegWidth>,
|
||||||
|
$($Op: MOpVisitVariants<DestReg = $DestReg, SrcRegWidth = $SrcRegWidth>,)*
|
||||||
|
]
|
||||||
|
> {
|
||||||
$(
|
$(
|
||||||
$(#[$variant_meta])*
|
$(#[$variant_meta])*
|
||||||
$Unit($Op),
|
$Unit($Op),
|
||||||
|
|
@ -98,7 +116,7 @@ macro_rules! all_units {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
$vis fn $extract(expr: impl ToExpr<Type = Self>) -> Expr<HdlOption<$Op>> {
|
$vis fn $extract(expr: impl ToExpr<Type = Self>) -> Expr<HdlOption<$Op>> {
|
||||||
let expr = expr.to_expr();
|
let expr = expr.to_expr();
|
||||||
let ty = Expr::ty(expr);
|
let ty = expr.ty();
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let $extract = wire(HdlOption[ty.$Unit]);
|
let $extract = wire(HdlOption[ty.$Unit]);
|
||||||
connect($extract, HdlOption[ty.$Unit].HdlNone());
|
connect($extract, HdlOption[ty.$Unit].HdlNone());
|
||||||
|
|
@ -164,10 +182,10 @@ macro_rules! all_units {
|
||||||
$TransformedMoveOp: MOpTrait<DestReg = $DestReg, SrcRegWidth = $SrcRegWidth>,
|
$TransformedMoveOp: MOpTrait<DestReg = $DestReg, SrcRegWidth = $SrcRegWidth>,
|
||||||
{
|
{
|
||||||
let this = this.to_expr();
|
let this = this.to_expr();
|
||||||
let new_ty = Expr::ty(this).with_transformed_move_op_ty(new_transformed_move_op_ty);
|
let new_ty = this.ty().with_transformed_move_op_ty(new_transformed_move_op_ty);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let with_transformed_move_op = wire(HdlOption[new_ty]);
|
let with_transformed_move_op = wire(HdlOption[new_ty]);
|
||||||
connect(with_transformed_move_op, Expr::ty(with_transformed_move_op).HdlNone());
|
connect(with_transformed_move_op, with_transformed_move_op.ty().HdlNone());
|
||||||
// workaround #[hdl] match expanding to a loop, so you can't move variables in it
|
// workaround #[hdl] match expanding to a loop, so you can't move variables in it
|
||||||
let mut connect_transformed_move_op = Some(connect_transformed_move_op);
|
let mut connect_transformed_move_op = Some(connect_transformed_move_op);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -209,7 +227,7 @@ macro_rules! all_units {
|
||||||
RenamedMOp[MOpTrait::dest_reg_ty(self)][MOpTrait::src_reg_width(self)]
|
RenamedMOp[MOpTrait::dest_reg_ty(self)][MOpTrait::src_reg_width(self)]
|
||||||
}
|
}
|
||||||
fn mop_into(this: Expr<Self>) -> Expr<RenamedMOp<$DestReg, $SrcRegWidth>> {
|
fn mop_into(this: Expr<Self>) -> Expr<RenamedMOp<$DestReg, $SrcRegWidth>> {
|
||||||
MOpInto::<RenamedMOp<$DestReg, $SrcRegWidth>>::mop_into_ty(Expr::ty(this)).$BeforeUnit(this)
|
MOpInto::<RenamedMOp<$DestReg, $SrcRegWidth>>::mop_into_ty(this.ty()).$BeforeUnit(this)
|
||||||
}
|
}
|
||||||
})*
|
})*
|
||||||
|
|
||||||
|
|
@ -218,7 +236,7 @@ macro_rules! all_units {
|
||||||
RenamedMOp[MOpTrait::dest_reg_ty(self)][MOpTrait::src_reg_width(self)]
|
RenamedMOp[MOpTrait::dest_reg_ty(self)][MOpTrait::src_reg_width(self)]
|
||||||
}
|
}
|
||||||
fn mop_into(this: Expr<Self>) -> Expr<RenamedMOp<$DestReg, $SrcRegWidth>> {
|
fn mop_into(this: Expr<Self>) -> Expr<RenamedMOp<$DestReg, $SrcRegWidth>> {
|
||||||
MOpInto::<RenamedMOp<$DestReg, $SrcRegWidth>>::mop_into_ty(Expr::ty(this)).$AfterUnit(this)
|
MOpInto::<RenamedMOp<$DestReg, $SrcRegWidth>>::mop_into_ty(this.ty()).$AfterUnit(this)
|
||||||
}
|
}
|
||||||
})*
|
})*
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,14 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
config::CpuConfig,
|
config::CpuConfig,
|
||||||
instruction::{
|
instruction::{
|
||||||
AddSubMOp, AluBranchMOp, AluCommonMOp, COMMON_MOP_SRC_LEN, CommonMOp, LogicalMOp, MOpTrait,
|
AddSubMOp, AluBranchMOp, AluCommonMOp, BranchMOp, COMMON_MOP_SRC_LEN, CommonMOpDefaultImm,
|
||||||
OutputIntegerMode, RenamedMOp, UnitOutRegNum,
|
CompareMOp, LogicalFlagsMOp, LogicalMOp, MOpTrait, OutputIntegerMode, ReadSpecialMOp,
|
||||||
|
RenamedMOp, ShiftRotateMOp, UnitOutRegNum,
|
||||||
|
},
|
||||||
|
register::{
|
||||||
|
FlagsMode, PRegFlagsPowerISA, PRegFlagsPowerISAView, PRegFlagsViewTrait, PRegFlagsX86,
|
||||||
|
PRegFlagsX86View, PRegValue, ViewUnused,
|
||||||
},
|
},
|
||||||
register::{FlagsMode, PRegFlagsPowerISA, PRegFlagsX86, PRegValue},
|
|
||||||
unit::{
|
unit::{
|
||||||
DynUnit, DynUnitWrapper, GlobalState, UnitKind, UnitMOp, UnitOutput, UnitResult,
|
DynUnit, DynUnitWrapper, GlobalState, UnitKind, UnitMOp, UnitOutput, UnitResult,
|
||||||
UnitResultCompleted, UnitTrait,
|
UnitResultCompleted, UnitTrait,
|
||||||
|
|
@ -38,11 +42,11 @@ fn add_sub<SrcCount: KnownSize>(
|
||||||
add_pc,
|
add_pc,
|
||||||
} = mop;
|
} = mop;
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let AluCommonMOp::<_, _, _> {
|
let AluCommonMOp::<_, _, _, _> {
|
||||||
common,
|
common,
|
||||||
output_integer_mode,
|
output_integer_mode,
|
||||||
} = alu_common;
|
} = alu_common;
|
||||||
let imm: Expr<UInt<64>> = CommonMOp::imm(common).cast_to_static();
|
let imm = CommonMOpDefaultImm::as_sint_dyn(common.imm).cast_to_static::<UInt<64>>();
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let carry_in_before_inversion = wire();
|
let carry_in_before_inversion = wire();
|
||||||
connect(carry_in_before_inversion, false);
|
connect(carry_in_before_inversion, false);
|
||||||
|
|
@ -56,13 +60,13 @@ fn add_sub<SrcCount: KnownSize>(
|
||||||
FlagsMode::PowerISA(_) => {
|
FlagsMode::PowerISA(_) => {
|
||||||
connect(
|
connect(
|
||||||
carry_in_before_inversion,
|
carry_in_before_inversion,
|
||||||
PRegFlagsPowerISA::xer_ca(src_values[1].flags),
|
PRegFlagsPowerISA::view(src_values[1].flags).xer_ca,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
FlagsMode::X86(_) => {
|
FlagsMode::X86(_) => {
|
||||||
connect(
|
connect(
|
||||||
carry_in_before_inversion,
|
carry_in_before_inversion,
|
||||||
PRegFlagsX86::cf(src_values[1].flags),
|
PRegFlagsX86::view(src_values[1].flags).cf,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -199,27 +203,36 @@ fn add_sub<SrcCount: KnownSize>(
|
||||||
#[hdl]
|
#[hdl]
|
||||||
match flags_mode {
|
match flags_mode {
|
||||||
FlagsMode::PowerISA(_) => {
|
FlagsMode::PowerISA(_) => {
|
||||||
PRegFlagsPowerISA::clear_unused(flags);
|
connect(
|
||||||
connect(PRegFlagsPowerISA::xer_ca(flags), pwr_ca);
|
flags,
|
||||||
connect(PRegFlagsPowerISA::xer_ca32(flags), pwr_ca32);
|
PRegFlagsPowerISA::from_view(PRegFlagsPowerISAView {
|
||||||
connect(PRegFlagsPowerISA::xer_ov(flags), pwr_ov);
|
unused: ViewUnused::splat(false.to_expr()),
|
||||||
connect(PRegFlagsPowerISA::xer_ov32(flags), pwr_ov32);
|
xer_ca: pwr_ca,
|
||||||
connect(PRegFlagsPowerISA::cr_lt(flags), pwr_cr_lt);
|
xer_ca32: pwr_ca32,
|
||||||
connect(PRegFlagsPowerISA::cr_gt(flags), pwr_cr_gt);
|
xer_ov: pwr_ov,
|
||||||
connect(PRegFlagsPowerISA::cr_eq(flags), pwr_cr_eq);
|
xer_ov32: pwr_ov32,
|
||||||
connect(PRegFlagsPowerISA::so(flags), pwr_so);
|
so: pwr_so,
|
||||||
|
cr_lt: pwr_cr_lt,
|
||||||
|
cr_gt: pwr_cr_gt,
|
||||||
|
cr_eq: pwr_cr_eq,
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
FlagsMode::X86(_) => {
|
FlagsMode::X86(_) => {
|
||||||
PRegFlagsX86::clear_unused(flags);
|
connect(
|
||||||
connect(PRegFlagsX86::cf(flags), x86_cf);
|
flags,
|
||||||
connect(PRegFlagsX86::af(flags), x86_af);
|
PRegFlagsX86::from_view(PRegFlagsX86View {
|
||||||
connect(PRegFlagsX86::of(flags), x86_of);
|
unused: ViewUnused::splat(false.to_expr()),
|
||||||
connect(PRegFlagsX86::sf(flags), x86_sf);
|
cf: x86_cf,
|
||||||
connect(PRegFlagsX86::pf(flags), x86_pf);
|
zf: x86_zf,
|
||||||
connect(PRegFlagsX86::zf(flags), x86_zf);
|
sf: x86_sf,
|
||||||
|
of: x86_of,
|
||||||
|
af: x86_af,
|
||||||
|
pf: x86_pf,
|
||||||
// this insn doesn't write DF, so it's output isn't used for reading DF
|
// this insn doesn't write DF, so it's output isn't used for reading DF
|
||||||
connect(PRegFlagsX86::df(flags), false);
|
df: false.to_expr(),
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -230,9 +243,95 @@ fn add_sub<SrcCount: KnownSize>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
fn logical_flags(
|
||||||
|
mop: Expr<LogicalFlagsMOp<UnitOutRegNum<DynSize>, DynSize>>,
|
||||||
|
flags_mode: Expr<FlagsMode>,
|
||||||
|
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
||||||
|
) -> Expr<UnitResultCompleted<()>> {
|
||||||
|
// TODO: finish
|
||||||
|
#[hdl]
|
||||||
|
UnitResultCompleted::<_> {
|
||||||
|
value: PRegValue::zeroed(),
|
||||||
|
extra_out: (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
fn logical(
|
fn logical(
|
||||||
mop: Expr<LogicalMOp<UnitOutRegNum<DynSize>, DynSize>>,
|
mop: Expr<LogicalMOp<UnitOutRegNum<DynSize>, DynSize, ConstUsize<2>>>,
|
||||||
|
flags_mode: Expr<FlagsMode>,
|
||||||
|
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
||||||
|
) -> Expr<UnitResultCompleted<()>> {
|
||||||
|
// TODO: finish
|
||||||
|
#[hdl]
|
||||||
|
UnitResultCompleted::<_> {
|
||||||
|
value: PRegValue::zeroed(),
|
||||||
|
extra_out: (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
fn logical_i(
|
||||||
|
mop: Expr<LogicalMOp<UnitOutRegNum<DynSize>, DynSize, ConstUsize<1>>>,
|
||||||
|
flags_mode: Expr<FlagsMode>,
|
||||||
|
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
||||||
|
) -> Expr<UnitResultCompleted<()>> {
|
||||||
|
// TODO: finish
|
||||||
|
#[hdl]
|
||||||
|
UnitResultCompleted::<_> {
|
||||||
|
value: PRegValue::zeroed(),
|
||||||
|
extra_out: (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
fn shift_rotate(
|
||||||
|
mop: Expr<ShiftRotateMOp<UnitOutRegNum<DynSize>, DynSize>>,
|
||||||
|
flags_mode: Expr<FlagsMode>,
|
||||||
|
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
||||||
|
) -> Expr<UnitResultCompleted<()>> {
|
||||||
|
// TODO: finish
|
||||||
|
#[hdl]
|
||||||
|
UnitResultCompleted::<_> {
|
||||||
|
value: PRegValue::zeroed(),
|
||||||
|
extra_out: (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
fn compare<SrcCount: KnownSize>(
|
||||||
|
mop: Expr<CompareMOp<UnitOutRegNum<DynSize>, DynSize, SrcCount>>,
|
||||||
|
flags_mode: Expr<FlagsMode>,
|
||||||
|
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
||||||
|
) -> Expr<UnitResultCompleted<()>> {
|
||||||
|
// TODO: finish
|
||||||
|
#[hdl]
|
||||||
|
UnitResultCompleted::<_> {
|
||||||
|
value: PRegValue::zeroed(),
|
||||||
|
extra_out: (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
fn branch<SrcCount: KnownSize>(
|
||||||
|
mop: Expr<BranchMOp<UnitOutRegNum<DynSize>, DynSize, SrcCount>>,
|
||||||
|
pc: Expr<UInt<64>>,
|
||||||
|
flags_mode: Expr<FlagsMode>,
|
||||||
|
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
||||||
|
) -> Expr<UnitResultCompleted<()>> {
|
||||||
|
// TODO: finish
|
||||||
|
#[hdl]
|
||||||
|
UnitResultCompleted::<_> {
|
||||||
|
value: PRegValue::zeroed(),
|
||||||
|
extra_out: (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
fn read_special(
|
||||||
|
mop: Expr<ReadSpecialMOp<UnitOutRegNum<DynSize>, DynSize>>,
|
||||||
|
pc: Expr<UInt<64>>,
|
||||||
flags_mode: Expr<FlagsMode>,
|
flags_mode: Expr<FlagsMode>,
|
||||||
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
|
||||||
) -> Expr<UnitResultCompleted<()>> {
|
) -> Expr<UnitResultCompleted<()>> {
|
||||||
|
|
@ -266,16 +365,13 @@ pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
|
||||||
let unit_base = instance(unit_base(
|
let unit_base = instance(unit_base(
|
||||||
config,
|
config,
|
||||||
unit_index,
|
unit_index,
|
||||||
Expr::ty(unit_to_reg_alloc).input.data.HdlSome.mop,
|
unit_to_reg_alloc.ty().input.data.HdlSome.mop,
|
||||||
(),
|
(),
|
||||||
));
|
));
|
||||||
connect(unit_to_reg_alloc, unit_base.unit_to_reg_alloc);
|
connect(unit_to_reg_alloc, unit_base.unit_to_reg_alloc);
|
||||||
connect(unit_base.cd, cd);
|
connect(unit_base.cd, cd);
|
||||||
connect(unit_base.execute_start.ready, true);
|
connect(unit_base.execute_start.ready, true);
|
||||||
connect(
|
connect(unit_base.execute_end, unit_base.execute_end.ty().HdlNone());
|
||||||
unit_base.execute_end,
|
|
||||||
Expr::ty(unit_base.execute_end).HdlNone(),
|
|
||||||
);
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if let HdlSome(execute_start) = ReadyValid::firing_data(unit_base.execute_start) {
|
if let HdlSome(execute_start) = ReadyValid::firing_data(unit_base.execute_start) {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -322,6 +418,23 @@ pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
AluBranchMOp::<_, _>::LogicalFlags(mop) => connect(
|
||||||
|
unit_base.execute_end,
|
||||||
|
HdlSome(
|
||||||
|
#[hdl]
|
||||||
|
ExecuteEnd::<_, _> {
|
||||||
|
unit_output: #[hdl]
|
||||||
|
UnitOutput::<_, _> {
|
||||||
|
which: MOpTrait::dest_reg(mop),
|
||||||
|
result: UnitResult[()].Completed(logical_flags(
|
||||||
|
mop,
|
||||||
|
global_state.flags_mode,
|
||||||
|
src_values,
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
AluBranchMOp::<_, _>::Logical(mop) => connect(
|
AluBranchMOp::<_, _>::Logical(mop) => connect(
|
||||||
unit_base.execute_end,
|
unit_base.execute_end,
|
||||||
HdlSome(
|
HdlSome(
|
||||||
|
|
@ -339,6 +452,128 @@ pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
AluBranchMOp::<_, _>::LogicalI(mop) => connect(
|
||||||
|
unit_base.execute_end,
|
||||||
|
HdlSome(
|
||||||
|
#[hdl]
|
||||||
|
ExecuteEnd::<_, _> {
|
||||||
|
unit_output: #[hdl]
|
||||||
|
UnitOutput::<_, _> {
|
||||||
|
which: MOpTrait::dest_reg(mop),
|
||||||
|
result: UnitResult[()].Completed(logical_i(
|
||||||
|
mop,
|
||||||
|
global_state.flags_mode,
|
||||||
|
src_values,
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
AluBranchMOp::<_, _>::ShiftRotate(mop) => connect(
|
||||||
|
unit_base.execute_end,
|
||||||
|
HdlSome(
|
||||||
|
#[hdl]
|
||||||
|
ExecuteEnd::<_, _> {
|
||||||
|
unit_output: #[hdl]
|
||||||
|
UnitOutput::<_, _> {
|
||||||
|
which: MOpTrait::dest_reg(mop),
|
||||||
|
result: UnitResult[()].Completed(shift_rotate(
|
||||||
|
mop,
|
||||||
|
global_state.flags_mode,
|
||||||
|
src_values,
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
AluBranchMOp::<_, _>::Compare(mop) => connect(
|
||||||
|
unit_base.execute_end,
|
||||||
|
HdlSome(
|
||||||
|
#[hdl]
|
||||||
|
ExecuteEnd::<_, _> {
|
||||||
|
unit_output: #[hdl]
|
||||||
|
UnitOutput::<_, _> {
|
||||||
|
which: MOpTrait::dest_reg(mop),
|
||||||
|
result: UnitResult[()].Completed(compare(
|
||||||
|
mop,
|
||||||
|
global_state.flags_mode,
|
||||||
|
src_values,
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
AluBranchMOp::<_, _>::CompareI(mop) => connect(
|
||||||
|
unit_base.execute_end,
|
||||||
|
HdlSome(
|
||||||
|
#[hdl]
|
||||||
|
ExecuteEnd::<_, _> {
|
||||||
|
unit_output: #[hdl]
|
||||||
|
UnitOutput::<_, _> {
|
||||||
|
which: MOpTrait::dest_reg(mop),
|
||||||
|
result: UnitResult[()].Completed(compare(
|
||||||
|
mop,
|
||||||
|
global_state.flags_mode,
|
||||||
|
src_values,
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
AluBranchMOp::<_, _>::Branch(mop) => connect(
|
||||||
|
unit_base.execute_end,
|
||||||
|
HdlSome(
|
||||||
|
#[hdl]
|
||||||
|
ExecuteEnd::<_, _> {
|
||||||
|
unit_output: #[hdl]
|
||||||
|
UnitOutput::<_, _> {
|
||||||
|
which: MOpTrait::dest_reg(mop),
|
||||||
|
result: UnitResult[()].Completed(branch(
|
||||||
|
mop,
|
||||||
|
pc,
|
||||||
|
global_state.flags_mode,
|
||||||
|
src_values,
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
AluBranchMOp::<_, _>::BranchI(mop) => connect(
|
||||||
|
unit_base.execute_end,
|
||||||
|
HdlSome(
|
||||||
|
#[hdl]
|
||||||
|
ExecuteEnd::<_, _> {
|
||||||
|
unit_output: #[hdl]
|
||||||
|
UnitOutput::<_, _> {
|
||||||
|
which: MOpTrait::dest_reg(mop),
|
||||||
|
result: UnitResult[()].Completed(branch(
|
||||||
|
mop,
|
||||||
|
pc,
|
||||||
|
global_state.flags_mode,
|
||||||
|
src_values,
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
AluBranchMOp::<_, _>::ReadSpecial(mop) => connect(
|
||||||
|
unit_base.execute_end,
|
||||||
|
HdlSome(
|
||||||
|
#[hdl]
|
||||||
|
ExecuteEnd::<_, _> {
|
||||||
|
unit_output: #[hdl]
|
||||||
|
UnitOutput::<_, _> {
|
||||||
|
which: MOpTrait::dest_reg(mop),
|
||||||
|
result: UnitResult[()].Completed(read_special(
|
||||||
|
mop,
|
||||||
|
pc,
|
||||||
|
global_state.flags_mode,
|
||||||
|
src_values,
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -227,7 +227,7 @@ impl InFlightOpsSummary<DynSize> {
|
||||||
in_flight_ops: impl ToExpr<Type = ArrayType<HdlOption<InFlightOp<MOp>>, MaxInFlight>>,
|
in_flight_ops: impl ToExpr<Type = ArrayType<HdlOption<InFlightOp<MOp>>, MaxInFlight>>,
|
||||||
) -> Expr<Self> {
|
) -> Expr<Self> {
|
||||||
let in_flight_ops = in_flight_ops.to_expr();
|
let in_flight_ops = in_flight_ops.to_expr();
|
||||||
let max_in_flight = Expr::ty(in_flight_ops).len();
|
let max_in_flight = in_flight_ops.ty().len();
|
||||||
let index_range = 0..max_in_flight;
|
let index_range = 0..max_in_flight;
|
||||||
let index_ty = UInt::range(index_range.clone());
|
let index_ty = UInt::range(index_range.clone());
|
||||||
tree_reduce(
|
tree_reduce(
|
||||||
|
|
@ -259,7 +259,7 @@ pub fn unit_base<
|
||||||
let execute_end: HdlOption<ExecuteEnd<DynSize, ExtraOut>> =
|
let execute_end: HdlOption<ExecuteEnd<DynSize, ExtraOut>> =
|
||||||
m.input(HdlOption[ExecuteEnd[config.out_reg_num_width][extra_out_ty]]);
|
m.input(HdlOption[ExecuteEnd[config.out_reg_num_width][extra_out_ty]]);
|
||||||
|
|
||||||
connect(execute_start.data, Expr::ty(execute_start).data.HdlNone());
|
connect(execute_start.data, execute_start.ty().data.HdlNone());
|
||||||
|
|
||||||
let max_in_flight = config.unit_max_in_flight(unit_index).get();
|
let max_in_flight = config.unit_max_in_flight(unit_index).get();
|
||||||
let in_flight_op_ty = InFlightOp[mop_ty];
|
let in_flight_op_ty = InFlightOp[mop_ty];
|
||||||
|
|
@ -270,7 +270,7 @@ pub fn unit_base<
|
||||||
|
|
||||||
let in_flight_ops_summary_value = InFlightOpsSummary::summarize(in_flight_ops);
|
let in_flight_ops_summary_value = InFlightOpsSummary::summarize(in_flight_ops);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let in_flight_ops_summary = wire(Expr::ty(in_flight_ops_summary_value));
|
let in_flight_ops_summary = wire(in_flight_ops_summary_value.ty());
|
||||||
connect(in_flight_ops_summary, in_flight_ops_summary_value);
|
connect(in_flight_ops_summary, in_flight_ops_summary_value);
|
||||||
|
|
||||||
connect(
|
connect(
|
||||||
|
|
@ -302,7 +302,7 @@ pub fn unit_base<
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let input_src_regs_valid = wire();
|
let input_src_regs_valid = wire();
|
||||||
connect(input_src_regs_valid, [true; COMMON_MOP_SRC_LEN]);
|
connect(input_src_regs_valid, [true; COMMON_MOP_SRC_LEN]);
|
||||||
let mut unit_output_regs_valid: Vec<MemBuilder<Bool>> = (0..Expr::ty(unit_output_writes).len())
|
let mut unit_output_regs_valid: Vec<MemBuilder<Bool>> = (0..unit_output_writes.ty().len())
|
||||||
.map(|unit_index| {
|
.map(|unit_index| {
|
||||||
let mut mem = memory_with_loc(
|
let mut mem = memory_with_loc(
|
||||||
&format!("unit_{unit_index}_output_regs_valid"),
|
&format!("unit_{unit_index}_output_regs_valid"),
|
||||||
|
|
@ -313,7 +313,7 @@ pub fn unit_base<
|
||||||
mem
|
mem
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
for unit_index in 0..Expr::ty(unit_output_writes).len() {
|
for unit_index in 0..unit_output_writes.ty().len() {
|
||||||
let mut unit_output_regs = memory_with_loc(
|
let mut unit_output_regs = memory_with_loc(
|
||||||
&format!("unit_{unit_index}_output_regs"),
|
&format!("unit_{unit_index}_output_regs"),
|
||||||
PRegValue,
|
PRegValue,
|
||||||
|
|
@ -411,7 +411,7 @@ pub fn unit_base<
|
||||||
|
|
||||||
connect(
|
connect(
|
||||||
unit_to_reg_alloc.output,
|
unit_to_reg_alloc.output,
|
||||||
Expr::ty(unit_to_reg_alloc.output).HdlNone(),
|
unit_to_reg_alloc.output.ty().HdlNone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -503,7 +503,7 @@ pub fn unit_base<
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if in_flight_ops_summary.ready_op_index.cmp_eq(HdlSome(
|
if in_flight_ops_summary.ready_op_index.cmp_eq(HdlSome(
|
||||||
in_flight_op_index.cast_to(Expr::ty(in_flight_ops_summary).ready_op_index.HdlSome),
|
in_flight_op_index.cast_to(in_flight_ops_summary.ty().ready_op_index.HdlSome),
|
||||||
)) {
|
)) {
|
||||||
connect(read_src_regs, src_regs);
|
connect(read_src_regs, src_regs);
|
||||||
}
|
}
|
||||||
|
|
@ -512,7 +512,7 @@ pub fn unit_base<
|
||||||
in_flight_op_next_src_ready_flags[in_flight_op_index],
|
in_flight_op_next_src_ready_flags[in_flight_op_index],
|
||||||
src_ready_flags,
|
src_ready_flags,
|
||||||
);
|
);
|
||||||
for unit_index in 0..Expr::ty(unit_output_writes).len() {
|
for unit_index in 0..unit_output_writes.ty().len() {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if let HdlSome(unit_output_write) = unit_output_writes[unit_index] {
|
if let HdlSome(unit_output_write) = unit_output_writes[unit_index] {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use fayalite::{expr::ops::ArrayLiteral, module::wire_with_loc, prelude::*};
|
||||||
|
use std::num::NonZero;
|
||||||
|
|
||||||
pub mod array_vec;
|
pub mod array_vec;
|
||||||
pub mod tree_reduce;
|
pub mod tree_reduce;
|
||||||
|
|
||||||
|
|
@ -25,3 +28,255 @@ pub(crate) const fn range_u32_nth_or_panic(range: &std::ops::Range<u32>, index:
|
||||||
panic!("index out of range")
|
panic!("index out of range")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: move to fayalite
|
||||||
|
pub trait Rotate<Amount> {
|
||||||
|
type Output;
|
||||||
|
/// like [`usize::rotate_left`] or [`<[T]>::rotate_left`](slice::rotate_left) depending on `Self` -- note that in lsb0 those rotate in opposite directions
|
||||||
|
fn rotate_left(&self, amount: Amount) -> Self::Output;
|
||||||
|
/// like [`usize::rotate_right`] or [`<[T]>::rotate_right`](slice::rotate_right) depending on `Self` -- note that in lsb0 those rotate in opposite directions
|
||||||
|
fn rotate_right(&self, amount: Amount) -> Self::Output;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<VSz: Size> Rotate<usize> for Expr<UIntType<VSz>> {
|
||||||
|
type Output = Self;
|
||||||
|
/// like [`usize::rotate_left`]
|
||||||
|
fn rotate_left(&self, amount: usize) -> Self::Output {
|
||||||
|
if self.ty().width() == 0 {
|
||||||
|
return *self;
|
||||||
|
}
|
||||||
|
let amount = amount % self.ty().width();
|
||||||
|
let l = *self << amount;
|
||||||
|
let r = *self >> (self.ty().width() - amount);
|
||||||
|
(l | r).cast_to(self.ty())
|
||||||
|
}
|
||||||
|
/// like [`usize::rotate_right`]
|
||||||
|
fn rotate_right(&self, amount: usize) -> Self::Output {
|
||||||
|
if self.ty().width() == 0 {
|
||||||
|
return *self;
|
||||||
|
}
|
||||||
|
let amount = amount % self.ty().width();
|
||||||
|
let l = *self << (self.ty().width() - amount);
|
||||||
|
let r = *self >> amount;
|
||||||
|
(l | r).cast_to(self.ty())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<VSz: Size> Rotate<usize> for SimValue<UIntType<VSz>> {
|
||||||
|
type Output = Self;
|
||||||
|
/// like [`usize::rotate_left`]
|
||||||
|
fn rotate_left(&self, amount: usize) -> Self::Output {
|
||||||
|
if self.ty().width() == 0 {
|
||||||
|
return self.clone();
|
||||||
|
}
|
||||||
|
let amount = amount % self.ty().width();
|
||||||
|
let l = self << amount;
|
||||||
|
let r = self >> (self.ty().width() - amount);
|
||||||
|
(l | r).cast_to(self.ty())
|
||||||
|
}
|
||||||
|
/// like [`usize::rotate_right`]
|
||||||
|
fn rotate_right(&self, amount: usize) -> Self::Output {
|
||||||
|
if self.ty().width() == 0 {
|
||||||
|
return self.clone();
|
||||||
|
}
|
||||||
|
let amount = amount % self.ty().width();
|
||||||
|
let l = self << (self.ty().width() - amount);
|
||||||
|
let r = self >> amount;
|
||||||
|
(l | r).cast_to(self.ty())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<VSz: Size, ASz: Size> Rotate<Expr<UIntType<ASz>>> for Expr<UIntType<VSz>> {
|
||||||
|
type Output = Self;
|
||||||
|
/// like [`usize::rotate_left`]
|
||||||
|
fn rotate_left(&self, amount: Expr<UIntType<ASz>>) -> Self::Output {
|
||||||
|
if self.ty().width() == 0 {
|
||||||
|
return *self;
|
||||||
|
}
|
||||||
|
let amount = amount % self.ty().width();
|
||||||
|
let l = *self << amount;
|
||||||
|
let r = *self >> (self.ty().width() - amount);
|
||||||
|
(l | r).cast_to(self.ty())
|
||||||
|
}
|
||||||
|
/// like [`usize::rotate_right`]
|
||||||
|
fn rotate_right(&self, amount: Expr<UIntType<ASz>>) -> Self::Output {
|
||||||
|
if self.ty().width() == 0 {
|
||||||
|
return *self;
|
||||||
|
}
|
||||||
|
let amount = amount % self.ty().width();
|
||||||
|
let l = *self << (self.ty().width() - amount).cast_to(amount.ty());
|
||||||
|
let r = *self >> amount;
|
||||||
|
(l | r).cast_to(self.ty())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<VSz: Size, ASz: Size> Rotate<SimValue<UIntType<ASz>>> for SimValue<UIntType<VSz>> {
|
||||||
|
type Output = Self;
|
||||||
|
/// like [`usize::rotate_left`]
|
||||||
|
fn rotate_left(&self, amount: SimValue<UIntType<ASz>>) -> Self::Output {
|
||||||
|
if self.ty().width() == 0 {
|
||||||
|
return self.clone();
|
||||||
|
}
|
||||||
|
let amount = amount % self.ty().width();
|
||||||
|
let l = self << &amount;
|
||||||
|
let r = self >> (self.ty().width() - amount);
|
||||||
|
(l | r).cast_to(self.ty())
|
||||||
|
}
|
||||||
|
/// like [`usize::rotate_right`]
|
||||||
|
fn rotate_right(&self, amount: SimValue<UIntType<ASz>>) -> Self::Output {
|
||||||
|
if self.ty().width() == 0 {
|
||||||
|
return self.clone();
|
||||||
|
}
|
||||||
|
let amount = amount % self.ty().width();
|
||||||
|
let l = self << (self.ty().width() - &amount).cast_to(amount.ty());
|
||||||
|
let r = self >> amount;
|
||||||
|
(l | r).cast_to(self.ty())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn array_rotate_helper<T: Type, N: Size, AmountSize: Size>(
|
||||||
|
mut array: Expr<ArrayType<T, N>>,
|
||||||
|
amount: Expr<UIntType<AmountSize>>,
|
||||||
|
rotate_fn: impl Fn(&mut [Expr<T>], usize),
|
||||||
|
rotate_fn_name: &str,
|
||||||
|
) -> Expr<ArrayType<T, N>> {
|
||||||
|
let Some(mut prev_step_size) = NonZero::new(array.ty().len()) else {
|
||||||
|
return array;
|
||||||
|
};
|
||||||
|
fn named<T: Type>(v: Expr<T>, name: impl AsRef<str>) -> Expr<T> {
|
||||||
|
let w = wire_with_loc(name.as_ref(), SourceLocation::caller(), v.ty());
|
||||||
|
connect(w, v);
|
||||||
|
w
|
||||||
|
}
|
||||||
|
fn non_empty_array_to_expr<T: Type, Len: Size>(
|
||||||
|
v: impl AsRef<[Expr<T>]>,
|
||||||
|
) -> Expr<ArrayType<T, Len>> {
|
||||||
|
let v = v.as_ref();
|
||||||
|
ArrayLiteral::new(v[0].ty(), v.iter().map(|v| Expr::canonical(*v)).collect()).to_expr()
|
||||||
|
}
|
||||||
|
fn mux<T: Type>(b: Expr<Bool>, true_v: Expr<T>, false_v: Expr<T>) -> Expr<T> {
|
||||||
|
let a: Expr<Array<T, 2>> = non_empty_array_to_expr([false_v, true_v]);
|
||||||
|
a[b.cast_to_static::<UInt<1>>()]
|
||||||
|
}
|
||||||
|
let amount_ty = amount.ty();
|
||||||
|
let mut amount = (amount % prev_step_size).cast_to(amount_ty);
|
||||||
|
loop {
|
||||||
|
(prev_step_size, amount, array) =
|
||||||
|
if let Some(step_size) = NonZero::new(prev_step_size.get() / 2) {
|
||||||
|
let amount = named(amount, format!("{rotate_fn_name}_amount_{prev_step_size}"));
|
||||||
|
let do_rotate = amount.cmp_ge(step_size);
|
||||||
|
let mut rotated_array = (*array).clone();
|
||||||
|
rotate_fn(rotated_array.as_mut(), step_size.get());
|
||||||
|
let rotated_array = named(
|
||||||
|
non_empty_array_to_expr(rotated_array),
|
||||||
|
format!("{rotate_fn_name}_rotated_array_{step_size}"),
|
||||||
|
);
|
||||||
|
let array = mux(do_rotate, rotated_array, array);
|
||||||
|
let array = named(array, format!("{rotate_fn_name}_array_{step_size}"));
|
||||||
|
let amount = mux(do_rotate, (amount - step_size).cast_to(amount_ty), amount);
|
||||||
|
(step_size, amount, array)
|
||||||
|
} else {
|
||||||
|
return array;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Type, N: Size, AmountSize: Size> Rotate<Expr<UIntType<AmountSize>>>
|
||||||
|
for Expr<ArrayType<T, N>>
|
||||||
|
{
|
||||||
|
type Output = Self;
|
||||||
|
/// like [`<[T]>::rotate_left`](slice::rotate_left)
|
||||||
|
fn rotate_left(&self, amount: Expr<UIntType<AmountSize>>) -> Self::Output {
|
||||||
|
array_rotate_helper(*self, amount, <[Expr<T>]>::rotate_left, "rotate_left")
|
||||||
|
}
|
||||||
|
/// like [`<[T]>::rotate_right`](slice::rotate_right)
|
||||||
|
fn rotate_right(&self, amount: Expr<UIntType<AmountSize>>) -> Self::Output {
|
||||||
|
array_rotate_helper(*self, amount, <[Expr<T>]>::rotate_right, "rotate_right")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Type, N: Size, AmountSize: Size> Rotate<SimValue<UIntType<AmountSize>>>
|
||||||
|
for SimValue<ArrayType<T, N>>
|
||||||
|
{
|
||||||
|
type Output = Self;
|
||||||
|
/// like [`<[T]>::rotate_left`](slice::rotate_left)
|
||||||
|
fn rotate_left(&self, amount: SimValue<UIntType<AmountSize>>) -> Self::Output {
|
||||||
|
if self.ty().len() == 0 {
|
||||||
|
return self.clone();
|
||||||
|
}
|
||||||
|
let Ok(amount) = usize::try_from(amount.to_bigint() % self.ty().len()) else {
|
||||||
|
unreachable!();
|
||||||
|
};
|
||||||
|
let mut retval = self.clone();
|
||||||
|
AsMut::<[SimValue<T>]>::as_mut(&mut SimValue::value_mut(&mut retval)).rotate_left(amount);
|
||||||
|
retval
|
||||||
|
}
|
||||||
|
/// like [`<[T]>::rotate_right`](slice::rotate_right)
|
||||||
|
fn rotate_right(&self, amount: SimValue<UIntType<AmountSize>>) -> Self::Output {
|
||||||
|
if self.ty().len() == 0 {
|
||||||
|
return self.clone();
|
||||||
|
}
|
||||||
|
let Ok(amount) = usize::try_from(amount.to_bigint() % self.ty().len()) else {
|
||||||
|
unreachable!();
|
||||||
|
};
|
||||||
|
let mut retval = self.clone();
|
||||||
|
AsMut::<[SimValue<T>]>::as_mut(&mut SimValue::value_mut(&mut retval)).rotate_right(amount);
|
||||||
|
retval
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Type, N: Size> Rotate<usize> for Expr<ArrayType<T, N>> {
|
||||||
|
type Output = Self;
|
||||||
|
/// like [`<[T]>::rotate_left`](slice::rotate_left)
|
||||||
|
fn rotate_left(&self, amount: usize) -> Self::Output {
|
||||||
|
if self.ty().len() == 0 {
|
||||||
|
return self.clone();
|
||||||
|
}
|
||||||
|
let amount = amount % self.ty().len();
|
||||||
|
let mut retval = Vec::from_iter(*self);
|
||||||
|
retval.rotate_left(amount);
|
||||||
|
ArrayLiteral::new(
|
||||||
|
self.ty().element(),
|
||||||
|
retval.into_iter().map(Expr::canonical).collect(),
|
||||||
|
)
|
||||||
|
.to_expr()
|
||||||
|
}
|
||||||
|
/// like [`<[T]>::rotate_right`](slice::rotate_right)
|
||||||
|
fn rotate_right(&self, amount: usize) -> Self::Output {
|
||||||
|
if self.ty().len() == 0 {
|
||||||
|
return self.clone();
|
||||||
|
}
|
||||||
|
let amount = amount % self.ty().len();
|
||||||
|
let mut retval = Vec::from_iter(*self);
|
||||||
|
retval.rotate_right(amount);
|
||||||
|
ArrayLiteral::new(
|
||||||
|
self.ty().element(),
|
||||||
|
retval.into_iter().map(Expr::canonical).collect(),
|
||||||
|
)
|
||||||
|
.to_expr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Type, N: Size> Rotate<usize> for SimValue<ArrayType<T, N>> {
|
||||||
|
type Output = Self;
|
||||||
|
/// like [`<[T]>::rotate_left`](slice::rotate_left)
|
||||||
|
fn rotate_left(&self, amount: usize) -> Self::Output {
|
||||||
|
if self.ty().len() == 0 {
|
||||||
|
return self.clone();
|
||||||
|
}
|
||||||
|
let amount = amount % self.ty().len();
|
||||||
|
let mut retval = self.clone();
|
||||||
|
AsMut::<[SimValue<T>]>::as_mut(&mut SimValue::value_mut(&mut retval)).rotate_left(amount);
|
||||||
|
retval
|
||||||
|
}
|
||||||
|
/// like [`<[T]>::rotate_right`](slice::rotate_right)
|
||||||
|
fn rotate_right(&self, amount: usize) -> Self::Output {
|
||||||
|
if self.ty().len() == 0 {
|
||||||
|
return self.clone();
|
||||||
|
}
|
||||||
|
let amount = amount % self.ty().len();
|
||||||
|
let mut retval = self.clone();
|
||||||
|
AsMut::<[SimValue<T>]>::as_mut(&mut SimValue::value_mut(&mut retval)).rotate_right(amount);
|
||||||
|
retval
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,147 +1,10 @@
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
use fayalite::{
|
use fayalite::{expr::ops::ExprIndex, int::UIntInRangeInclusiveType, prelude::*};
|
||||||
expr::ops::{ExprCastTo, ExprIndex, ExprPartialEq, ExprPartialOrd},
|
|
||||||
int::SizeType,
|
|
||||||
intern::{Intern, Interned},
|
|
||||||
prelude::*,
|
|
||||||
ty::{MatchVariantWithoutScope, StaticType, TypeProperties},
|
|
||||||
};
|
|
||||||
use std::{marker::PhantomData, ops::Index};
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
#[hdl]
|
||||||
pub struct Length<Max: Size> {
|
pub type Length<Max: Size> = UIntInRangeInclusiveType<ConstUsize<0>, Max>;
|
||||||
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
|
/// like [`std::vec::Vec`], except with a [`Expr`] for [`len()`][`Self::len()`] and a fixed capacity
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -156,7 +19,31 @@ impl<T: Type, N: Size> ArrayVec<T, N> {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
ArrayVec {
|
ArrayVec {
|
||||||
elements: self.elements.uninit(),
|
elements: self.elements.uninit(),
|
||||||
len: self.len.zero(),
|
len: 0u8.cast_to(self.len),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
pub fn new_sim(self, uninit_element: impl ToSimValueWithType<T>) -> SimValue<Self> {
|
||||||
|
let uninit_element = uninit_element.into_sim_value_with_type(self.element());
|
||||||
|
#[hdl(sim)]
|
||||||
|
ArrayVec::<_, _> {
|
||||||
|
elements: SimValue::from_array_elements(
|
||||||
|
self.elements,
|
||||||
|
(0..self.elements.len()).map(|_| uninit_element.clone()),
|
||||||
|
),
|
||||||
|
len: 0u8.cast_to(self.len),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
pub fn new_full_sim(
|
||||||
|
self,
|
||||||
|
elements: impl ToSimValueWithType<ArrayType<T, N>>,
|
||||||
|
) -> SimValue<Self> {
|
||||||
|
let elements = elements.to_sim_value_with_type(self.elements);
|
||||||
|
#[hdl(sim)]
|
||||||
|
Self {
|
||||||
|
elements,
|
||||||
|
len: self.elements.len().to_sim_value_with_type(self.len),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn element(self) -> T {
|
pub fn element(self) -> T {
|
||||||
|
|
@ -176,8 +63,8 @@ impl<T: Type, N: Size> ArrayVec<T, N> {
|
||||||
let elements = elements.to_expr();
|
let elements = elements.to_expr();
|
||||||
let len = len.to_expr();
|
let len = len.to_expr();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Length::new(N::from_usize(Expr::ty(elements).len())),
|
Length[N::from_usize(elements.ty().len())],
|
||||||
Expr::ty(len),
|
len.ty(),
|
||||||
"len type mismatch",
|
"len type mismatch",
|
||||||
);
|
);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -189,9 +76,12 @@ impl<T: Type, N: Size> ArrayVec<T, N> {
|
||||||
pub fn len(this: impl ToExpr<Type = Self>) -> Expr<Length<N>> {
|
pub fn len(this: impl ToExpr<Type = Self>) -> Expr<Length<N>> {
|
||||||
this.to_expr().len
|
this.to_expr().len
|
||||||
}
|
}
|
||||||
|
pub fn len_sim(this: &SimValue<Self>) -> &SimValue<Length<N>> {
|
||||||
|
&this.len
|
||||||
|
}
|
||||||
pub fn is_empty(this: impl ToExpr<Type = Self>) -> Expr<Bool> {
|
pub fn is_empty(this: impl ToExpr<Type = Self>) -> Expr<Bool> {
|
||||||
let len = Self::len(this);
|
let len = Self::len(this);
|
||||||
len.cmp_eq(Expr::ty(len).zero())
|
len.cmp_eq(0u8)
|
||||||
}
|
}
|
||||||
pub fn capacity(self) -> usize {
|
pub fn capacity(self) -> usize {
|
||||||
self.elements.len()
|
self.elements.len()
|
||||||
|
|
@ -207,11 +97,77 @@ impl<T: Type, N: Size> ArrayVec<T, N> {
|
||||||
let this = this.to_expr();
|
let this = this.to_expr();
|
||||||
for (index, element) in this.elements.into_iter().enumerate() {
|
for (index, element) in this.elements.into_iter().enumerate() {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if index.cmp_lt(Length::as_uint(this.len)) {
|
if index.cmp_lt(this.len) {
|
||||||
f(index, element);
|
f(index, element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn elements_sim_ref(this: &SimValue<Self>) -> &[SimValue<T>] {
|
||||||
|
&this.elements[..*this.len]
|
||||||
|
}
|
||||||
|
pub fn elements_sim_mut(this: &mut SimValue<Self>) -> &mut [SimValue<T>] {
|
||||||
|
let len = *this.len;
|
||||||
|
&mut this.elements[..len]
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
pub async fn async_for_each_sim(
|
||||||
|
this: impl ToSimValue<Type = Self>,
|
||||||
|
mut f: impl AsyncFnMut(usize, SimValue<T>),
|
||||||
|
) {
|
||||||
|
#[hdl(sim)]
|
||||||
|
let ArrayVec::<_, _> { elements, len } = this.into_sim_value();
|
||||||
|
for (index, element) in elements.into_iter().enumerate() {
|
||||||
|
if index.cmp_lt(*len) {
|
||||||
|
f(index, element).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
pub async fn async_for_each_sim_ref<'a>(
|
||||||
|
this: &'a SimValue<Self>,
|
||||||
|
mut f: impl AsyncFnMut(usize, &'a SimValue<T>),
|
||||||
|
) {
|
||||||
|
#[hdl(sim)]
|
||||||
|
let ArrayVec::<_, _> { elements, len } = this;
|
||||||
|
for (index, element) in elements.iter().enumerate() {
|
||||||
|
if index.cmp_lt(**len) {
|
||||||
|
f(index, element).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
pub async fn async_for_each_sim_mut<'a>(
|
||||||
|
this: &'a mut SimValue<Self>,
|
||||||
|
mut f: impl AsyncFnMut(usize, &'a mut SimValue<T>),
|
||||||
|
) {
|
||||||
|
#[hdl(sim)]
|
||||||
|
let ArrayVec::<_, _> { elements, len } = this;
|
||||||
|
for (index, element) in elements.iter_mut().enumerate() {
|
||||||
|
if index.cmp_lt(**len) {
|
||||||
|
f(index, element).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
pub fn try_push_sim(
|
||||||
|
this: &mut SimValue<Self>,
|
||||||
|
value: impl ToSimValueWithType<T>,
|
||||||
|
) -> Result<(), SimValue<T>> {
|
||||||
|
let value = value.into_sim_value_with_type(this.ty().element());
|
||||||
|
let capacity = this.ty().capacity();
|
||||||
|
#[hdl(sim)]
|
||||||
|
let ArrayVec::<_, _> { elements, len } = this;
|
||||||
|
if **len < capacity {
|
||||||
|
elements[**len] = value;
|
||||||
|
**len += 1;
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn truncate_sim(this: &mut SimValue<Self>, len: usize) {
|
||||||
|
*this.len = len.min(*this.len);
|
||||||
|
}
|
||||||
pub fn mapped_ty<U: Type>(self, new_element_ty: U) -> ArrayVec<U, N> {
|
pub fn mapped_ty<U: Type>(self, new_element_ty: U) -> ArrayVec<U, N> {
|
||||||
ArrayVec {
|
ArrayVec {
|
||||||
elements: ArrayType[new_element_ty][N::from_usize(self.elements.len())],
|
elements: ArrayType[new_element_ty][N::from_usize(self.elements.len())],
|
||||||
|
|
@ -226,7 +182,7 @@ impl<T: Type, N: Size> ArrayVec<T, N> {
|
||||||
) -> Expr<ArrayVec<U, N>> {
|
) -> Expr<ArrayVec<U, N>> {
|
||||||
let this = this.to_expr();
|
let this = this.to_expr();
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let mapped_array_vec = wire(Expr::ty(this).mapped_ty(new_element_ty));
|
let mapped_array_vec = wire(this.ty().mapped_ty(new_element_ty));
|
||||||
connect(mapped_array_vec.len, this.len);
|
connect(mapped_array_vec.len, this.len);
|
||||||
Self::for_each(this, |index, element| {
|
Self::for_each(this, |index, element| {
|
||||||
connect(mapped_array_vec[index], f(index, element));
|
connect(mapped_array_vec[index], f(index, element));
|
||||||
|
|
@ -234,15 +190,42 @@ impl<T: Type, N: Size> ArrayVec<T, N> {
|
||||||
mapped_array_vec
|
mapped_array_vec
|
||||||
}
|
}
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
pub fn map_sim<U: Type>(
|
||||||
|
this: impl ToSimValue<Type = Self>,
|
||||||
|
uninit_element: impl ToSimValue<Type = U>,
|
||||||
|
mut f: impl FnMut(usize, SimValue<T>) -> SimValue<U>,
|
||||||
|
) -> SimValue<ArrayVec<U, N>> {
|
||||||
|
let this = this.into_sim_value();
|
||||||
|
let uninit_element = uninit_element.into_sim_value();
|
||||||
|
let ty = this.ty().mapped_ty(uninit_element.ty());
|
||||||
|
#[hdl(sim)]
|
||||||
|
let Self { elements, len } = this;
|
||||||
|
#[hdl(sim)]
|
||||||
|
ArrayVec::<_, _> {
|
||||||
|
elements: SimValue::from_array_elements(
|
||||||
|
ty.elements,
|
||||||
|
SimValue::into_value(elements)
|
||||||
|
.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(index, element)| {
|
||||||
|
if index < *len {
|
||||||
|
f(index, element)
|
||||||
|
} else {
|
||||||
|
uninit_element.clone()
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
len,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
pub fn as_array_of_options(this: impl ToExpr<Type = Self>) -> Expr<ArrayType<HdlOption<T>, N>> {
|
pub fn as_array_of_options(this: impl ToExpr<Type = Self>) -> Expr<ArrayType<HdlOption<T>, N>> {
|
||||||
let this = this.to_expr();
|
let this = this.to_expr();
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let array_vec_as_array_of_options = wire(
|
let array_vec_as_array_of_options =
|
||||||
ArrayType[HdlOption[Expr::ty(this).element()]]
|
wire(ArrayType[HdlOption[this.ty().element()]][N::from_usize(this.ty().capacity())]);
|
||||||
[N::from_usize(Expr::ty(this).capacity())],
|
|
||||||
);
|
|
||||||
for element in array_vec_as_array_of_options {
|
for element in array_vec_as_array_of_options {
|
||||||
connect(element, Expr::ty(element).HdlNone());
|
connect(element, element.ty().HdlNone());
|
||||||
}
|
}
|
||||||
Self::for_each(this, |index, element| {
|
Self::for_each(this, |index, element| {
|
||||||
connect(array_vec_as_array_of_options[index], HdlSome(element))
|
connect(array_vec_as_array_of_options[index], HdlSome(element))
|
||||||
|
|
@ -263,3 +246,34 @@ where
|
||||||
<ArrayType<T, N> as ExprIndex<Idx>>::expr_index(&this.elements, index)
|
<ArrayType<T, N> as ExprIndex<Idx>>::expr_index(&this.elements, index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Type> ArrayVec<T, ConstUsize<1>> {
|
||||||
|
#[hdl]
|
||||||
|
pub fn from_opt_sim(
|
||||||
|
opt: impl ToSimValue<Type = HdlOption<T>>,
|
||||||
|
uninit_element: impl ToSimValueWithType<T>,
|
||||||
|
) -> SimValue<Self> {
|
||||||
|
let opt = opt.into_sim_value();
|
||||||
|
let ty = ArrayVec[opt.ty().HdlSome][ConstUsize];
|
||||||
|
#[hdl(sim)]
|
||||||
|
match opt {
|
||||||
|
HdlSome(v) => ty.new_full_sim([v]),
|
||||||
|
HdlNone => ty.new_sim(uninit_element),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
pub fn into_opt_sim(this: impl ToSimValue<Type = Self>) -> SimValue<HdlOption<T>> {
|
||||||
|
let this = this.into_sim_value();
|
||||||
|
#[hdl(sim)]
|
||||||
|
let Self { elements, len } = this;
|
||||||
|
let [element] = SimValue::into_value(elements);
|
||||||
|
let ty = HdlOption[element.ty()];
|
||||||
|
if *len == 0 {
|
||||||
|
#[hdl(sim)]
|
||||||
|
ty.HdlNone()
|
||||||
|
} else {
|
||||||
|
#[hdl(sim)]
|
||||||
|
ty.HdlSome(element)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
0
crates/cpu/tests/expected/fetch.vcd
generated
Normal file
0
crates/cpu/tests/expected/fetch.vcd
generated
Normal file
300436
crates/cpu/tests/expected/next_pc.vcd
generated
Normal file
300436
crates/cpu/tests/expected/next_pc.vcd
generated
Normal file
File diff suppressed because it is too large
Load diff
108387
crates/cpu/tests/expected/reg_alloc.vcd
generated
108387
crates/cpu/tests/expected/reg_alloc.vcd
generated
File diff suppressed because it is too large
Load diff
185
crates/cpu/tests/fetch.rs
Normal file
185
crates/cpu/tests/fetch.rs
Normal file
|
|
@ -0,0 +1,185 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use cpu::{
|
||||||
|
config::{CpuConfig, UnitConfig},
|
||||||
|
fetch::{MemoryInterface, fetch},
|
||||||
|
next_pc::NextPcToFetchInterface,
|
||||||
|
unit::UnitKind,
|
||||||
|
util::array_vec::ArrayVec,
|
||||||
|
};
|
||||||
|
use fayalite::{
|
||||||
|
prelude::*,
|
||||||
|
sim::vcd::VcdWriterDecls,
|
||||||
|
util::{DebugAsDisplay, RcWriter},
|
||||||
|
};
|
||||||
|
use std::{cell::Cell, collections::VecDeque, num::NonZeroUsize};
|
||||||
|
|
||||||
|
const MEMORY_QUEUE_SIZE: usize = 32;
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
struct MemoryQueueEntry {
|
||||||
|
addr: UInt<64>,
|
||||||
|
cycles_left: UInt<8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MemoryQueueEntry {
|
||||||
|
#[hdl]
|
||||||
|
fn default_sim(self) -> SimValue<Self> {
|
||||||
|
#[hdl(sim)]
|
||||||
|
Self {
|
||||||
|
addr: 0u64,
|
||||||
|
cycles_left: 0u8,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl_module(extern)]
|
||||||
|
fn mock_memory(config: PhantomConst<CpuConfig>) {
|
||||||
|
#[hdl]
|
||||||
|
let cd: ClockDomain = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let memory_interface: MemoryInterface<PhantomConst<CpuConfig>> =
|
||||||
|
m.input(MemoryInterface[config]);
|
||||||
|
#[hdl]
|
||||||
|
let queue_debug: ArrayVec<MemoryQueueEntry, ConstUsize<{ MEMORY_QUEUE_SIZE }>> = m.output();
|
||||||
|
m.register_clock_for_past(cd.clk);
|
||||||
|
m.extern_module_simulation_fn(
|
||||||
|
(cd, memory_interface, queue_debug),
|
||||||
|
|(cd, memory_interface, queue_debug), mut sim| async move {
|
||||||
|
// intentionally have a different sequence each time we're reset
|
||||||
|
let delay_sequence_index = Cell::new(0);
|
||||||
|
sim.resettable(
|
||||||
|
cd,
|
||||||
|
async |mut sim| {
|
||||||
|
sim.write(memory_interface.start.ready, false).await;
|
||||||
|
sim.write(memory_interface.finish.ready, false).await;
|
||||||
|
sim.write(
|
||||||
|
queue_debug,
|
||||||
|
queue_debug.ty().new_sim(MemoryQueueEntry.default_sim()),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
},
|
||||||
|
|sim, ()| {
|
||||||
|
run_fn(
|
||||||
|
cd,
|
||||||
|
memory_interface,
|
||||||
|
queue_debug,
|
||||||
|
&delay_sequence_index,
|
||||||
|
sim,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
#[hdl]
|
||||||
|
async fn run_fn(
|
||||||
|
cd: Expr<ClockDomain>,
|
||||||
|
memory_interface: Expr<MemoryInterface<PhantomConst<CpuConfig>>>,
|
||||||
|
queue_debug: Expr<ArrayVec<MemoryQueueEntry, ConstUsize<{ MEMORY_QUEUE_SIZE }>>>,
|
||||||
|
delay_sequence_index: &Cell<u64>,
|
||||||
|
mut sim: ExternModuleSimulationState,
|
||||||
|
) {
|
||||||
|
let config = memory_interface.config.ty();
|
||||||
|
let mut queue: VecDeque<SimValue<MemoryQueueEntry>> = VecDeque::new();
|
||||||
|
loop {
|
||||||
|
let mut sim_queue = queue_debug.ty().new_sim(MemoryQueueEntry.default_sim());
|
||||||
|
for entry in &queue {
|
||||||
|
ArrayVec::try_push_sim(&mut sim_queue, entry)
|
||||||
|
.ok()
|
||||||
|
.expect("queue is known to be small enough");
|
||||||
|
}
|
||||||
|
sim.write(queue_debug, sim_queue).await;
|
||||||
|
todo!();
|
||||||
|
sim.wait_for_clock_edge(cd.clk).await;
|
||||||
|
println!(
|
||||||
|
"Dump mock memory queue: {:#?}",
|
||||||
|
Vec::from_iter(
|
||||||
|
queue
|
||||||
|
.iter()
|
||||||
|
.map(|v| { DebugAsDisplay(format!("addr={:#x}", v.addr.as_int())) })
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl_module]
|
||||||
|
fn dut(config: PhantomConst<CpuConfig>) {
|
||||||
|
#[hdl]
|
||||||
|
let cd: ClockDomain = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let from_next_pc: NextPcToFetchInterface<PhantomConst<CpuConfig>> =
|
||||||
|
m.input(NextPcToFetchInterface[config]);
|
||||||
|
#[hdl]
|
||||||
|
let fetch = instance(fetch(config));
|
||||||
|
#[hdl]
|
||||||
|
let fetch {
|
||||||
|
cd: fetch_cd,
|
||||||
|
memory_interface: fetch_memory_interface,
|
||||||
|
from_next_pc: fetch_from_next_pc,
|
||||||
|
} = fetch;
|
||||||
|
connect(fetch_cd, cd);
|
||||||
|
connect(fetch_from_next_pc, from_next_pc);
|
||||||
|
#[hdl]
|
||||||
|
let mock_memory = instance(mock_memory(config));
|
||||||
|
#[hdl]
|
||||||
|
let mock_memory {
|
||||||
|
cd: mock_memory_cd,
|
||||||
|
memory_interface: mock_memory_interface,
|
||||||
|
queue_debug: _,
|
||||||
|
} = mock_memory;
|
||||||
|
connect(mock_memory_cd, cd);
|
||||||
|
connect(mock_memory_interface, fetch_memory_interface);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
#[test]
|
||||||
|
fn test_fetch() {
|
||||||
|
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();
|
||||||
|
config.log2_fetch_width_in_bytes = 4;
|
||||||
|
let m = dut(PhantomConst::new_sized(config));
|
||||||
|
let mut sim = Simulation::new(m);
|
||||||
|
let writer = RcWriter::default();
|
||||||
|
sim.add_trace_writer(VcdWriterDecls::new(writer.clone()));
|
||||||
|
struct DumpVcdOnDrop {
|
||||||
|
writer: Option<RcWriter>,
|
||||||
|
}
|
||||||
|
impl Drop for DumpVcdOnDrop {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if let Some(mut writer) = self.writer.take() {
|
||||||
|
let vcd = String::from_utf8(writer.take()).unwrap();
|
||||||
|
println!("####### VCD:\n{vcd}\n#######");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut writer = DumpVcdOnDrop {
|
||||||
|
writer: Some(writer),
|
||||||
|
};
|
||||||
|
sim.write_clock(sim.io().cd.clk, false);
|
||||||
|
sim.write_reset(sim.io().cd.rst, true);
|
||||||
|
for cycle in 0..2000 {
|
||||||
|
todo!("drive m.from_next_pc");
|
||||||
|
sim.advance_time(SimDuration::from_nanos(500));
|
||||||
|
println!("clock tick: {cycle}");
|
||||||
|
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 fetch does now, which isn't known to be correct
|
||||||
|
let vcd = String::from_utf8(writer.writer.take().unwrap().take()).unwrap();
|
||||||
|
println!("####### VCD:\n{vcd}\n#######");
|
||||||
|
if vcd != include_str!("expected/fetch.vcd") {
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
}
|
||||||
1558
crates/cpu/tests/next_pc.rs
Normal file
1558
crates/cpu/tests/next_pc.rs
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -3,14 +3,12 @@
|
||||||
|
|
||||||
use cpu::{
|
use cpu::{
|
||||||
config::{CpuConfig, UnitConfig},
|
config::{CpuConfig, UnitConfig},
|
||||||
instruction::{AddSubMOp, LogicalMOp, MOp, MOpDestReg, MOpRegNum, OutputIntegerMode},
|
instruction::{AddSubMOp, LogicalMOp, Lut4, MOp, MOpDestReg, MOpRegNum, OutputIntegerMode},
|
||||||
reg_alloc::{FetchedDecodedMOp, reg_alloc},
|
reg_alloc::{FetchedDecodedMOp, reg_alloc},
|
||||||
register::{FlagsMode, PRegFlagsPowerISA},
|
register::{FlagsMode, PRegFlagsPowerISA},
|
||||||
unit::{GlobalState, UnitKind},
|
unit::{GlobalState, UnitKind},
|
||||||
};
|
};
|
||||||
use fayalite::{
|
use fayalite::{
|
||||||
assert_export_firrtl,
|
|
||||||
firrtl::ExportOptions,
|
|
||||||
prelude::*,
|
prelude::*,
|
||||||
sim::{Simulation, time::SimDuration, vcd::VcdWriterDecls},
|
sim::{Simulation, time::SimDuration, vcd::VcdWriterDecls},
|
||||||
util::RcWriter,
|
util::RcWriter,
|
||||||
|
|
@ -61,7 +59,7 @@ fn test_reg_alloc() {
|
||||||
[HdlSome(()), HdlNone()],
|
[HdlSome(()), HdlNone()],
|
||||||
},
|
},
|
||||||
[0u8; 2],
|
[0u8; 2],
|
||||||
0x12345678u32.cast_to_static(),
|
0x12345678u32.cast_to_static::<SInt<_>>(),
|
||||||
OutputIntegerMode.DupLow32(),
|
OutputIntegerMode.DupLow32(),
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
|
@ -83,7 +81,7 @@ fn test_reg_alloc() {
|
||||||
[HdlSome(()), HdlNone()],
|
[HdlSome(()), HdlNone()],
|
||||||
},
|
},
|
||||||
[1u8, 0, 0],
|
[1u8, 0, 0],
|
||||||
1.cast_to_static(),
|
1.cast_to_static::<SInt<_>>(),
|
||||||
OutputIntegerMode.Full64(),
|
OutputIntegerMode.Full64(),
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
|
@ -101,9 +99,9 @@ fn test_reg_alloc() {
|
||||||
flag_regs: [HdlNone(), HdlSome(())],
|
flag_regs: [HdlNone(), HdlSome(())],
|
||||||
},
|
},
|
||||||
[2u8, 4u8],
|
[2u8, 4u8],
|
||||||
0.cast_to_static(),
|
0.cast_to_static::<SInt<_>>(),
|
||||||
OutputIntegerMode.Full64(),
|
OutputIntegerMode.Full64(),
|
||||||
0b0110_hdl_u4,
|
Lut4::from_fn(|a, b| a ^ b),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
let insns = insns_init.into_iter().chain(insns_loop.into_iter().cycle());
|
let insns = insns_init.into_iter().chain(insns_loop.into_iter().cycle());
|
||||||
|
|
|
||||||
131637
crates/cpu/tests/simple_power_isa_decoder/expected/decode_one_insn.vcd
generated
Normal file
131637
crates/cpu/tests/simple_power_isa_decoder/expected/decode_one_insn.vcd
generated
Normal file
File diff suppressed because it is too large
Load diff
208
crates/cpu/tests/simple_power_isa_decoder/main.rs
Normal file
208
crates/cpu/tests/simple_power_isa_decoder/main.rs
Normal file
|
|
@ -0,0 +1,208 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use crate::test_cases::TestCase;
|
||||||
|
use cpu::{
|
||||||
|
decoder::simple_power_isa::decode_one_insn, instruction::MOp, util::array_vec::ArrayVec,
|
||||||
|
};
|
||||||
|
use fayalite::{prelude::*, sim::vcd::VcdWriterDecls, util::RcWriter};
|
||||||
|
use std::{fmt::Write as _, io::Write, process::Command};
|
||||||
|
|
||||||
|
mod test_cases;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_test_cases_assembly() -> std::io::Result<()> {
|
||||||
|
let llvm_mc_regex = regex::Regex::new(r"llvm-mc(-\d+)?$").expect("known to be a valid regex");
|
||||||
|
let llvm_mc = which::which_re(llvm_mc_regex)
|
||||||
|
.expect("can't find llvm-mc or llvm-mc-<num> in path")
|
||||||
|
.next()
|
||||||
|
.expect("can't find llvm-mc or llvm-mc-<num> in path");
|
||||||
|
let test_cases = test_cases::test_cases();
|
||||||
|
let mut assembly = String::new();
|
||||||
|
for TestCase {
|
||||||
|
mnemonic,
|
||||||
|
first_input: _,
|
||||||
|
second_input: _,
|
||||||
|
output: _,
|
||||||
|
loc: _,
|
||||||
|
} in &test_cases
|
||||||
|
{
|
||||||
|
writeln!(assembly, "{mnemonic}").unwrap();
|
||||||
|
}
|
||||||
|
let (reader, mut writer) = std::io::pipe()?;
|
||||||
|
let thread = std::thread::spawn(move || writer.write_all(assembly.as_bytes()));
|
||||||
|
let std::process::Output {
|
||||||
|
status,
|
||||||
|
stdout,
|
||||||
|
stderr,
|
||||||
|
} = Command::new(&llvm_mc)
|
||||||
|
.arg("--triple=powerpc64le-linux-gnu")
|
||||||
|
.arg("--assemble")
|
||||||
|
.arg("--filetype=asm")
|
||||||
|
.arg("--show-encoding")
|
||||||
|
.arg("-")
|
||||||
|
.stdin(reader)
|
||||||
|
.output()?;
|
||||||
|
let _ = thread.join();
|
||||||
|
let stderr = String::from_utf8_lossy(&stderr);
|
||||||
|
eprint!("{stderr}");
|
||||||
|
if !status.success() {
|
||||||
|
panic!("{} failed: {status}", llvm_mc.display());
|
||||||
|
}
|
||||||
|
let stdout = String::from_utf8_lossy(&stdout);
|
||||||
|
print!("{stdout}");
|
||||||
|
let mut lines = stdout.lines();
|
||||||
|
let text_line = lines.next();
|
||||||
|
assert_eq!(text_line, Some("\t.text"));
|
||||||
|
let mut any_error = false;
|
||||||
|
macro_rules! assert_eq_cont {
|
||||||
|
($l:expr, $r:expr, $($msg:tt)+) => {
|
||||||
|
match (&$l, &$r) {
|
||||||
|
(l, r) => if l != r {
|
||||||
|
eprintln!("assertion failed: {}\nl={l:#?}\nr={r:#?}", format_args!($($msg)+));
|
||||||
|
any_error = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
for test_case @ TestCase {
|
||||||
|
mnemonic: _,
|
||||||
|
first_input,
|
||||||
|
second_input,
|
||||||
|
output: _,
|
||||||
|
loc: _,
|
||||||
|
} in test_cases
|
||||||
|
{
|
||||||
|
let Some(line) = lines.next() else {
|
||||||
|
panic!("output missing line for: {test_case:?}");
|
||||||
|
};
|
||||||
|
if line.starts_with("\t.long") {
|
||||||
|
assert_eq!(
|
||||||
|
line,
|
||||||
|
format!("\t.long\t{first_input}"),
|
||||||
|
"test_case={test_case:?}\nline:\n{line}"
|
||||||
|
);
|
||||||
|
if let Some(second_input) = second_input {
|
||||||
|
let Some(line) = lines.next() else {
|
||||||
|
panic!("output missing line for: {test_case:?}");
|
||||||
|
};
|
||||||
|
assert_eq!(
|
||||||
|
line,
|
||||||
|
format!("\t.long\t{second_input}"),
|
||||||
|
"test_case={test_case:?}\nline:\n{line}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let Some((_, comment)) = line.split_once('#') else {
|
||||||
|
panic!("output line missing comment. test_case={test_case:?}\nline:\n{line}");
|
||||||
|
};
|
||||||
|
let [b0, b1, b2, b3] = first_input.to_le_bytes();
|
||||||
|
let expected_comment = if let Some(second_input) = second_input {
|
||||||
|
let [b4, b5, b6, b7] = second_input.to_le_bytes();
|
||||||
|
format!(
|
||||||
|
" encoding: [0x{b0:02x},0x{b1:02x},0x{b2:02x},0x{b3:02x},0x{b4:02x},0x{b5:02x},0x{b6:02x},0x{b7:02x}]"
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
format!(" encoding: [0x{b0:02x},0x{b1:02x},0x{b2:02x},0x{b3:02x}]")
|
||||||
|
};
|
||||||
|
assert_eq_cont!(
|
||||||
|
comment,
|
||||||
|
expected_comment,
|
||||||
|
"test_case={test_case:?}\nline:\n{line}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
for line in lines {
|
||||||
|
assert!(line.trim().is_empty(), "bad trailing output line: {line:?}");
|
||||||
|
}
|
||||||
|
if any_error {
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
#[test]
|
||||||
|
fn test_decode_insn() {
|
||||||
|
let _n = SourceLocation::normalize_files_for_tests();
|
||||||
|
let m = decode_one_insn();
|
||||||
|
let mut sim = Simulation::new(m);
|
||||||
|
let writer = RcWriter::default();
|
||||||
|
sim.add_trace_writer(VcdWriterDecls::new(writer.clone()));
|
||||||
|
struct DumpVcdOnDrop {
|
||||||
|
writer: Option<RcWriter>,
|
||||||
|
}
|
||||||
|
impl Drop for DumpVcdOnDrop {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if let Some(mut writer) = self.writer.take() {
|
||||||
|
let vcd = String::from_utf8(writer.take()).unwrap();
|
||||||
|
println!("####### VCD:\n{vcd}\n#######");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut writer = DumpVcdOnDrop {
|
||||||
|
writer: Some(writer),
|
||||||
|
};
|
||||||
|
for test_case @ TestCase {
|
||||||
|
mnemonic: _,
|
||||||
|
first_input,
|
||||||
|
second_input,
|
||||||
|
output: _,
|
||||||
|
loc: _,
|
||||||
|
} in test_cases::test_cases()
|
||||||
|
{
|
||||||
|
sim.write(sim.io().first_input, first_input);
|
||||||
|
sim.write(
|
||||||
|
sim.io().second_input,
|
||||||
|
if let Some(v) = second_input {
|
||||||
|
#[hdl(sim)]
|
||||||
|
HdlSome(v)
|
||||||
|
} else {
|
||||||
|
#[hdl(sim)]
|
||||||
|
HdlNone()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
sim.advance_time(SimDuration::from_micros(1));
|
||||||
|
let second_input_used = sim.read_bool(sim.io().second_input_used);
|
||||||
|
let is_illegal = sim.read_bool(sim.io().is_illegal);
|
||||||
|
let output = sim.read(sim.io().output);
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[expect(dead_code, reason = "used only for Debug formatting")]
|
||||||
|
struct FormattedOutput<'a> {
|
||||||
|
insns: &'a [SimValue<MOp>],
|
||||||
|
second_input_used: bool,
|
||||||
|
is_illegal: bool,
|
||||||
|
}
|
||||||
|
let expected = format!(
|
||||||
|
"{:#?}",
|
||||||
|
FormattedOutput {
|
||||||
|
insns: ArrayVec::elements_sim_ref(&test_case.output),
|
||||||
|
second_input_used: second_input.is_some(),
|
||||||
|
is_illegal: false,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let output = format!(
|
||||||
|
"{:#?}",
|
||||||
|
FormattedOutput {
|
||||||
|
insns: ArrayVec::elements_sim_ref(&output),
|
||||||
|
second_input_used,
|
||||||
|
is_illegal,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
expected == output,
|
||||||
|
"test_case={test_case:#?}\noutput={output}\nexpected={expected}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let vcd = String::from_utf8(writer.writer.take().unwrap().take()).unwrap();
|
||||||
|
println!("####### VCD:\n{vcd}\n#######");
|
||||||
|
if vcd != include_str!("expected/decode_one_insn.vcd") {
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
#[test]
|
||||||
|
fn test_simple_power_isa_decoder() {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
158
crates/cpu/tests/simple_power_isa_decoder/test_cases.rs
Normal file
158
crates/cpu/tests/simple_power_isa_decoder/test_cases.rs
Normal file
|
|
@ -0,0 +1,158 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use cpu::{instruction::MOp, util::array_vec::ArrayVec};
|
||||||
|
use fayalite::prelude::*;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
mod branch;
|
||||||
|
mod condition_register;
|
||||||
|
mod fixed_point_arithmetic;
|
||||||
|
mod fixed_point_compare;
|
||||||
|
mod fixed_point_load;
|
||||||
|
mod fixed_point_logical;
|
||||||
|
mod fixed_point_rotate_and_shift;
|
||||||
|
mod fixed_point_store;
|
||||||
|
mod move_to_from_system_register;
|
||||||
|
mod prefixed_no_operation;
|
||||||
|
|
||||||
|
pub struct TestCase {
|
||||||
|
pub mnemonic: &'static str,
|
||||||
|
pub first_input: u32,
|
||||||
|
pub second_input: Option<u32>,
|
||||||
|
pub output: SimValue<ArrayVec<MOp, ConstUsize<3>>>,
|
||||||
|
pub loc: &'static std::panic::Location<'static>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for TestCase {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let Self {
|
||||||
|
mnemonic,
|
||||||
|
first_input,
|
||||||
|
second_input,
|
||||||
|
output,
|
||||||
|
loc,
|
||||||
|
} = self;
|
||||||
|
let mut debug_struct = f.debug_struct("TestCase");
|
||||||
|
debug_struct
|
||||||
|
.field("mnemonic", mnemonic)
|
||||||
|
.field("first_input", &format_args!("0x{first_input:08x}"));
|
||||||
|
if let Some(second_input) = second_input {
|
||||||
|
debug_struct.field("second_input", &format_args!("0x{second_input:08x}"));
|
||||||
|
} else {
|
||||||
|
debug_struct.field("second_input", &format_args!("None"));
|
||||||
|
}
|
||||||
|
debug_struct
|
||||||
|
.field("output", &ArrayVec::elements_sim_ref(output))
|
||||||
|
.field("loc", &format_args!("{loc}"))
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn insn_empty(mnemonic: &'static str, first_input: u32, second_input: Option<u32>) -> TestCase {
|
||||||
|
let zero_mop = UInt::new_dyn(MOp.canonical().bit_width())
|
||||||
|
.zero()
|
||||||
|
.cast_bits_to(MOp);
|
||||||
|
TestCase {
|
||||||
|
mnemonic,
|
||||||
|
first_input,
|
||||||
|
second_input,
|
||||||
|
output: ArrayVec::new_sim(ArrayVec[MOp][ConstUsize], &zero_mop),
|
||||||
|
loc: std::panic::Location::caller(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn insn_single(
|
||||||
|
mnemonic: &'static str,
|
||||||
|
first_input: u32,
|
||||||
|
second_input: Option<u32>,
|
||||||
|
output: impl ToSimValue<Type = MOp>,
|
||||||
|
) -> TestCase {
|
||||||
|
let zero_mop = UInt::new_dyn(MOp.canonical().bit_width())
|
||||||
|
.zero()
|
||||||
|
.cast_bits_to(MOp);
|
||||||
|
let mut single_storage = ArrayVec::new_sim(ArrayVec[MOp][ConstUsize], &zero_mop);
|
||||||
|
ArrayVec::try_push_sim(&mut single_storage, zero_mop).expect("known to have space");
|
||||||
|
ArrayVec::elements_sim_mut(&mut single_storage)[0] = output.to_sim_value();
|
||||||
|
TestCase {
|
||||||
|
mnemonic,
|
||||||
|
first_input,
|
||||||
|
second_input,
|
||||||
|
output: single_storage,
|
||||||
|
loc: std::panic::Location::caller(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn insn_double(
|
||||||
|
mnemonic: &'static str,
|
||||||
|
first_input: u32,
|
||||||
|
second_input: Option<u32>,
|
||||||
|
insns: [impl ToSimValue<Type = MOp>; 2],
|
||||||
|
) -> TestCase {
|
||||||
|
let zero_mop = UInt::new_dyn(MOp.canonical().bit_width())
|
||||||
|
.zero()
|
||||||
|
.cast_bits_to(MOp);
|
||||||
|
let mut single_storage = ArrayVec::new_sim(ArrayVec[MOp][ConstUsize], &zero_mop);
|
||||||
|
ArrayVec::try_push_sim(&mut single_storage, &zero_mop).expect("known to have space");
|
||||||
|
ArrayVec::try_push_sim(&mut single_storage, zero_mop).expect("known to have space");
|
||||||
|
ArrayVec::elements_sim_mut(&mut single_storage)[0] = insns[0].to_sim_value();
|
||||||
|
ArrayVec::elements_sim_mut(&mut single_storage)[1] = insns[1].to_sim_value();
|
||||||
|
TestCase {
|
||||||
|
mnemonic,
|
||||||
|
first_input,
|
||||||
|
second_input,
|
||||||
|
output: single_storage,
|
||||||
|
loc: std::panic::Location::caller(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn insn_triple(
|
||||||
|
mnemonic: &'static str,
|
||||||
|
first_input: u32,
|
||||||
|
second_input: Option<u32>,
|
||||||
|
insns: [impl ToSimValue<Type = MOp>; 3],
|
||||||
|
) -> TestCase {
|
||||||
|
let zero_mop = UInt::new_dyn(MOp.canonical().bit_width())
|
||||||
|
.zero()
|
||||||
|
.cast_bits_to(MOp);
|
||||||
|
let mut single_storage = ArrayVec::new_sim(ArrayVec[MOp][ConstUsize], &zero_mop);
|
||||||
|
ArrayVec::try_push_sim(&mut single_storage, &zero_mop).expect("known to have space");
|
||||||
|
ArrayVec::try_push_sim(&mut single_storage, &zero_mop).expect("known to have space");
|
||||||
|
ArrayVec::try_push_sim(&mut single_storage, zero_mop).expect("known to have space");
|
||||||
|
ArrayVec::elements_sim_mut(&mut single_storage)[0] = insns[0].to_sim_value();
|
||||||
|
ArrayVec::elements_sim_mut(&mut single_storage)[1] = insns[1].to_sim_value();
|
||||||
|
ArrayVec::elements_sim_mut(&mut single_storage)[2] = insns[2].to_sim_value();
|
||||||
|
TestCase {
|
||||||
|
mnemonic,
|
||||||
|
first_input,
|
||||||
|
second_input,
|
||||||
|
output: single_storage,
|
||||||
|
loc: std::panic::Location::caller(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn test_cases() -> Vec<TestCase> {
|
||||||
|
let mut retval = Vec::new();
|
||||||
|
branch::test_cases_book_i_2_4_branch(&mut retval);
|
||||||
|
condition_register::test_cases_book_i_2_5_condition_register(&mut retval);
|
||||||
|
fixed_point_load::test_cases_book_i_3_3_2_fixed_point_load(&mut retval);
|
||||||
|
fixed_point_store::test_cases_book_i_3_3_3_fixed_point_store(&mut retval);
|
||||||
|
fixed_point_arithmetic::test_cases_book_i_3_3_9_fixed_point_arithmetic(&mut retval);
|
||||||
|
fixed_point_compare::test_cases_book_i_3_3_10_fixed_point_compare(&mut retval);
|
||||||
|
fixed_point_logical::test_cases_book_i_3_3_13_fixed_point_logical(&mut retval);
|
||||||
|
fixed_point_rotate_and_shift::test_cases_book_i_3_3_14_fixed_point_rotate_and_shift(
|
||||||
|
&mut retval,
|
||||||
|
);
|
||||||
|
move_to_from_system_register::test_cases_book_i_3_3_19_move_to_from_system_register(
|
||||||
|
&mut retval,
|
||||||
|
);
|
||||||
|
prefixed_no_operation::test_cases_book_i_3_3_20_prefixed_no_operation(&mut retval);
|
||||||
|
move_to_from_system_register::test_cases_book_iii_5_4_4_move_to_from_system_register(
|
||||||
|
&mut retval,
|
||||||
|
);
|
||||||
|
retval
|
||||||
|
}
|
||||||
446
crates/cpu/tests/simple_power_isa_decoder/test_cases/branch.rs
Normal file
446
crates/cpu/tests/simple_power_isa_decoder/test_cases/branch.rs
Normal file
|
|
@ -0,0 +1,446 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use crate::test_cases::{TestCase, insn_double, insn_single};
|
||||||
|
use cpu::instruction::{
|
||||||
|
AddSubMOp, BranchMOp, ConditionMode, MOp, MOpDestReg, MOpRegNum, OutputIntegerMode,
|
||||||
|
};
|
||||||
|
use fayalite::prelude::*;
|
||||||
|
|
||||||
|
/// covers instructions in PowerISA v3.1C Book I 2.4 Branch Instructions
|
||||||
|
pub fn test_cases_book_i_2_4_branch(retval: &mut Vec<TestCase>) {
|
||||||
|
retval.push(insn_single(
|
||||||
|
"b 0x345678",
|
||||||
|
0x48345678,
|
||||||
|
None,
|
||||||
|
BranchMOp::branch_i(
|
||||||
|
MOpDestReg::new_sim(&[], &[]),
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
0x345678.cast_to_static::<SInt<_>>(),
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"ba 0x345678",
|
||||||
|
0x4834567a,
|
||||||
|
None,
|
||||||
|
BranchMOp::branch_i(
|
||||||
|
MOpDestReg::new_sim(&[], &[]),
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
0x345678.cast_to_static::<SInt<_>>(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"bl 0x345678",
|
||||||
|
0x48345679,
|
||||||
|
None,
|
||||||
|
BranchMOp::branch_i(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_LR_REG_NUM], &[]),
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
0x345678.cast_to_static::<SInt<_>>(),
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"bla 0x345678",
|
||||||
|
0x4834567b,
|
||||||
|
None,
|
||||||
|
BranchMOp::branch_i(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_LR_REG_NUM], &[]),
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
0x345678.cast_to_static::<SInt<_>>(),
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
fn insn_dec_ctr_and(
|
||||||
|
mnemonic: &'static str,
|
||||||
|
first_input: u32,
|
||||||
|
second_input: Option<u32>,
|
||||||
|
second_insn: impl ToSimValue<Type = MOp>,
|
||||||
|
) -> TestCase {
|
||||||
|
insn_double(
|
||||||
|
mnemonic,
|
||||||
|
first_input,
|
||||||
|
second_input,
|
||||||
|
[
|
||||||
|
AddSubMOp::add_sub_i::<MOp>(
|
||||||
|
MOpDestReg::new([MOpRegNum::power_isa_ctr_reg()], []),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_ctr_reg().value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
],
|
||||||
|
(-1).cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.into_sim_value(),
|
||||||
|
second_insn.into_sim_value(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
macro_rules! insn_branch_conds {
|
||||||
|
(
|
||||||
|
mnemonic = $mnemonic:literal;
|
||||||
|
mnemonic_l = $mnemonic_l:literal;
|
||||||
|
asm_last_arg = $asm_last_arg:literal;
|
||||||
|
imm = $imm:literal;
|
||||||
|
encoding = $encoding:literal;
|
||||||
|
src1 = $src1:expr;
|
||||||
|
pc_relative = $pc_relative:expr;
|
||||||
|
is_ret = $is_ret:expr;
|
||||||
|
) => {
|
||||||
|
insn_branch_conds! {
|
||||||
|
mnemonic = $mnemonic;
|
||||||
|
asm_last_arg = $asm_last_arg;
|
||||||
|
imm = $imm;
|
||||||
|
encoding = $encoding;
|
||||||
|
dest = MOpDestReg::new_sim(&[], &[]);
|
||||||
|
src1 = $src1;
|
||||||
|
pc_relative = $pc_relative;
|
||||||
|
lk = false;
|
||||||
|
is_ret = $is_ret;
|
||||||
|
}
|
||||||
|
insn_branch_conds! {
|
||||||
|
mnemonic = $mnemonic_l;
|
||||||
|
asm_last_arg = $asm_last_arg;
|
||||||
|
imm = $imm;
|
||||||
|
encoding = $encoding | 1;
|
||||||
|
dest = MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_LR_REG_NUM], &[]);
|
||||||
|
src1 = $src1;
|
||||||
|
pc_relative = $pc_relative;
|
||||||
|
lk = true;
|
||||||
|
is_ret = $is_ret;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(
|
||||||
|
mnemonic = $mnemonic:literal;
|
||||||
|
asm_last_arg = $asm_last_arg:literal;
|
||||||
|
imm = $imm:literal;
|
||||||
|
encoding = $encoding:expr;
|
||||||
|
dest = $dest:expr;
|
||||||
|
src1 = $src1:expr;
|
||||||
|
pc_relative = $pc_relative:expr;
|
||||||
|
lk = $lk:expr;
|
||||||
|
is_ret = $is_ret:expr;
|
||||||
|
) => {
|
||||||
|
if !$mnemonic.starts_with("bcctr") {
|
||||||
|
retval.push(insn_dec_ctr_and(
|
||||||
|
concat!($mnemonic, " 0, 0, ", $asm_last_arg),
|
||||||
|
$encoding,
|
||||||
|
None,
|
||||||
|
BranchMOp::branch_cond_ctr(
|
||||||
|
$dest,
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_cr_reg_imm(0).value,
|
||||||
|
$src1,
|
||||||
|
MOpRegNum::power_isa_ctr_reg().value,
|
||||||
|
],
|
||||||
|
$imm.cast_to_static::<SInt<_>>(),
|
||||||
|
true,
|
||||||
|
ConditionMode.SLt(),
|
||||||
|
true,
|
||||||
|
$pc_relative,
|
||||||
|
$lk,
|
||||||
|
$is_ret,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_dec_ctr_and(
|
||||||
|
concat!($mnemonic, " 0, 1, ", $asm_last_arg),
|
||||||
|
$encoding | 0x010000,
|
||||||
|
None,
|
||||||
|
BranchMOp::branch_cond_ctr(
|
||||||
|
$dest,
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_cr_reg_imm(0).value,
|
||||||
|
$src1,
|
||||||
|
MOpRegNum::power_isa_ctr_reg().value,
|
||||||
|
],
|
||||||
|
$imm.cast_to_static::<SInt<_>>(),
|
||||||
|
true,
|
||||||
|
ConditionMode.SGt(),
|
||||||
|
true,
|
||||||
|
$pc_relative,
|
||||||
|
$lk,
|
||||||
|
$is_ret,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_dec_ctr_and(
|
||||||
|
concat!($mnemonic, " 0, 2, ", $asm_last_arg),
|
||||||
|
$encoding | 0x020000,
|
||||||
|
None,
|
||||||
|
BranchMOp::branch_cond_ctr(
|
||||||
|
$dest,
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_cr_reg_imm(0).value,
|
||||||
|
$src1,
|
||||||
|
MOpRegNum::power_isa_ctr_reg().value,
|
||||||
|
],
|
||||||
|
$imm.cast_to_static::<SInt<_>>(),
|
||||||
|
true,
|
||||||
|
ConditionMode.Eq(),
|
||||||
|
true,
|
||||||
|
$pc_relative,
|
||||||
|
$lk,
|
||||||
|
$is_ret,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_dec_ctr_and(
|
||||||
|
concat!($mnemonic, " 0, 3, ", $asm_last_arg),
|
||||||
|
$encoding | 0x030000,
|
||||||
|
None,
|
||||||
|
BranchMOp::branch_cond_ctr(
|
||||||
|
$dest,
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_cr_reg_imm(0).value,
|
||||||
|
$src1,
|
||||||
|
MOpRegNum::power_isa_ctr_reg().value,
|
||||||
|
],
|
||||||
|
$imm.cast_to_static::<SInt<_>>(),
|
||||||
|
true,
|
||||||
|
ConditionMode.Overflow(),
|
||||||
|
true,
|
||||||
|
$pc_relative,
|
||||||
|
$lk,
|
||||||
|
$is_ret,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_dec_ctr_and(
|
||||||
|
concat!($mnemonic, " 0, 9, ", $asm_last_arg),
|
||||||
|
$encoding | 0x090000,
|
||||||
|
None,
|
||||||
|
BranchMOp::branch_cond_ctr(
|
||||||
|
$dest,
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_cr_reg_imm(2).value,
|
||||||
|
$src1,
|
||||||
|
MOpRegNum::power_isa_ctr_reg().value,
|
||||||
|
],
|
||||||
|
$imm.cast_to_static::<SInt<_>>(),
|
||||||
|
true,
|
||||||
|
ConditionMode.SGt(),
|
||||||
|
true,
|
||||||
|
$pc_relative,
|
||||||
|
$lk,
|
||||||
|
$is_ret,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_dec_ctr_and(
|
||||||
|
concat!($mnemonic, " 2, 0, ", $asm_last_arg),
|
||||||
|
$encoding | (2 << 21),
|
||||||
|
None,
|
||||||
|
BranchMOp::branch_cond_ctr(
|
||||||
|
$dest,
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_cr_reg_imm(0).value,
|
||||||
|
$src1,
|
||||||
|
MOpRegNum::power_isa_ctr_reg().value,
|
||||||
|
],
|
||||||
|
$imm.cast_to_static::<SInt<_>>(),
|
||||||
|
true,
|
||||||
|
ConditionMode.SLt(),
|
||||||
|
false,
|
||||||
|
$pc_relative,
|
||||||
|
$lk,
|
||||||
|
$is_ret,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
retval.push(insn_single(
|
||||||
|
concat!($mnemonic, " 4, 0, ", $asm_last_arg),
|
||||||
|
$encoding | (4 << 21),
|
||||||
|
None,
|
||||||
|
BranchMOp::branch_cond_ctr(
|
||||||
|
$dest,
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_cr_reg_imm(0).value,
|
||||||
|
$src1,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
],
|
||||||
|
$imm.cast_to_static::<SInt<_>>(),
|
||||||
|
true,
|
||||||
|
ConditionMode.SLt(),
|
||||||
|
true,
|
||||||
|
$pc_relative,
|
||||||
|
$lk,
|
||||||
|
$is_ret,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
if !$mnemonic.starts_with("bcctr") {
|
||||||
|
retval.push(insn_dec_ctr_and(
|
||||||
|
concat!($mnemonic, " 8, 0, ", $asm_last_arg),
|
||||||
|
$encoding | (8 << 21),
|
||||||
|
None,
|
||||||
|
BranchMOp::branch_cond_ctr(
|
||||||
|
$dest,
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_cr_reg_imm(0).value,
|
||||||
|
$src1,
|
||||||
|
MOpRegNum::power_isa_ctr_reg().value,
|
||||||
|
],
|
||||||
|
$imm.cast_to_static::<SInt<_>>(),
|
||||||
|
false,
|
||||||
|
ConditionMode.SLt(),
|
||||||
|
true,
|
||||||
|
$pc_relative,
|
||||||
|
$lk,
|
||||||
|
$is_ret,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_dec_ctr_and(
|
||||||
|
concat!($mnemonic, " 10, 0, ", $asm_last_arg),
|
||||||
|
$encoding | (10 << 21),
|
||||||
|
None,
|
||||||
|
BranchMOp::branch_cond_ctr(
|
||||||
|
$dest,
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_cr_reg_imm(0).value,
|
||||||
|
$src1,
|
||||||
|
MOpRegNum::power_isa_ctr_reg().value,
|
||||||
|
],
|
||||||
|
$imm.cast_to_static::<SInt<_>>(),
|
||||||
|
false,
|
||||||
|
ConditionMode.SLt(),
|
||||||
|
false,
|
||||||
|
$pc_relative,
|
||||||
|
$lk,
|
||||||
|
$is_ret,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
retval.push(insn_single(
|
||||||
|
concat!($mnemonic, " 12, 0, ", $asm_last_arg),
|
||||||
|
$encoding | (12 << 21),
|
||||||
|
None,
|
||||||
|
BranchMOp::branch_cond_ctr(
|
||||||
|
$dest,
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_cr_reg_imm(0).value,
|
||||||
|
$src1,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
],
|
||||||
|
$imm.cast_to_static::<SInt<_>>(),
|
||||||
|
false,
|
||||||
|
ConditionMode.SLt(),
|
||||||
|
true,
|
||||||
|
$pc_relative,
|
||||||
|
$lk,
|
||||||
|
$is_ret,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
if !$mnemonic.starts_with("bcctr") {
|
||||||
|
retval.push(insn_dec_ctr_and(
|
||||||
|
concat!($mnemonic, " 16, 0, ", $asm_last_arg),
|
||||||
|
$encoding | (16 << 21),
|
||||||
|
None,
|
||||||
|
BranchMOp::branch_ctr(
|
||||||
|
$dest,
|
||||||
|
$src1,
|
||||||
|
MOpRegNum::power_isa_ctr_reg().value,
|
||||||
|
$imm.cast_to_static::<SInt<_>>(),
|
||||||
|
true,
|
||||||
|
$pc_relative,
|
||||||
|
$lk,
|
||||||
|
$is_ret,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_dec_ctr_and(
|
||||||
|
concat!($mnemonic, " 18, 0, ", $asm_last_arg),
|
||||||
|
$encoding | (18 << 21),
|
||||||
|
None,
|
||||||
|
BranchMOp::branch_ctr(
|
||||||
|
$dest,
|
||||||
|
$src1,
|
||||||
|
MOpRegNum::power_isa_ctr_reg().value,
|
||||||
|
$imm.cast_to_static::<SInt<_>>(),
|
||||||
|
false,
|
||||||
|
$pc_relative,
|
||||||
|
$lk,
|
||||||
|
$is_ret,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
retval.push(insn_single(
|
||||||
|
concat!($mnemonic, " 20, 0, ", $asm_last_arg),
|
||||||
|
$encoding | (20 << 21),
|
||||||
|
None,
|
||||||
|
BranchMOp::branch_i(
|
||||||
|
$dest,
|
||||||
|
$src1,
|
||||||
|
$imm.cast_to_static::<SInt<_>>(),
|
||||||
|
$pc_relative,
|
||||||
|
$lk,
|
||||||
|
$is_ret,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
insn_branch_conds! {
|
||||||
|
mnemonic = "bc";
|
||||||
|
mnemonic_l = "bcl";
|
||||||
|
asm_last_arg = "0x1234";
|
||||||
|
imm = 0x1234;
|
||||||
|
encoding = 0x40001234;
|
||||||
|
src1 = MOpRegNum::const_zero().value;
|
||||||
|
pc_relative = true;
|
||||||
|
is_ret = false;
|
||||||
|
}
|
||||||
|
insn_branch_conds! {
|
||||||
|
mnemonic = "bca";
|
||||||
|
mnemonic_l = "bcla";
|
||||||
|
asm_last_arg = "0x1234";
|
||||||
|
imm = 0x1234;
|
||||||
|
encoding = 0x40001236;
|
||||||
|
src1 = MOpRegNum::const_zero().value;
|
||||||
|
pc_relative = false;
|
||||||
|
is_ret = false;
|
||||||
|
}
|
||||||
|
insn_branch_conds! {
|
||||||
|
mnemonic = "bclr";
|
||||||
|
mnemonic_l = "bclrl";
|
||||||
|
asm_last_arg = "0";
|
||||||
|
imm = 0;
|
||||||
|
encoding = 0x4c000020;
|
||||||
|
src1 = MOpRegNum::power_isa_lr_reg().value;
|
||||||
|
pc_relative = false;
|
||||||
|
is_ret = true;
|
||||||
|
}
|
||||||
|
insn_branch_conds! {
|
||||||
|
mnemonic = "bcctr";
|
||||||
|
mnemonic_l = "bcctrl";
|
||||||
|
asm_last_arg = "0";
|
||||||
|
imm = 0;
|
||||||
|
encoding = 0x4c000420;
|
||||||
|
src1 = MOpRegNum::power_isa_ctr_reg().value;
|
||||||
|
pc_relative = false;
|
||||||
|
is_ret = false;
|
||||||
|
}
|
||||||
|
retval.push(insn_dec_ctr_and(
|
||||||
|
// LLVM doesn't support the bctar[l] instructions:
|
||||||
|
// https://github.com/llvm/llvm-project/issues/176864
|
||||||
|
".long 0x4e400461 # bctarl 18, 0, 0",
|
||||||
|
0x4e400461,
|
||||||
|
None,
|
||||||
|
BranchMOp::branch_ctr(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_LR_REG_NUM], &[]),
|
||||||
|
MOpRegNum::power_isa_tar_reg().value,
|
||||||
|
MOpRegNum::power_isa_ctr_reg().value,
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use crate::test_cases::{TestCase, insn_single};
|
||||||
|
use cpu::{
|
||||||
|
instruction::{LogicalFlagsMOp, LogicalFlagsMOpImm, Lut4, MOpDestReg, MOpRegNum, MoveRegMOp},
|
||||||
|
register::PRegFlagsPowerISA,
|
||||||
|
};
|
||||||
|
use fayalite::prelude::*;
|
||||||
|
|
||||||
|
/// covers instructions in PowerISA v3.1C Book I 2.5 Condition Register Instructions
|
||||||
|
pub fn test_cases_book_i_2_5_condition_register(retval: &mut Vec<TestCase>) {
|
||||||
|
macro_rules! cr_bit_logical_op {
|
||||||
|
(
|
||||||
|
$mnemonic:literal,
|
||||||
|
$encoding:literal,
|
||||||
|
$lut:expr
|
||||||
|
) => {{
|
||||||
|
retval.push(insn_single(
|
||||||
|
concat!($mnemonic, " 4*cr3+so, 4*cr1+gt, 4*cr5+lt"),
|
||||||
|
$encoding | 0x01e5a000,
|
||||||
|
None,
|
||||||
|
LogicalFlagsMOp::logical_flags(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_cr_reg_imm(1).value,
|
||||||
|
MOpRegNum::power_isa_cr_reg_imm(5).value,
|
||||||
|
MOpRegNum::power_isa_cr_reg_imm(3).value,
|
||||||
|
],
|
||||||
|
LogicalFlagsMOpImm::from_swizzle_fn::<PRegFlagsPowerISA>(|src0, src1, src2| {
|
||||||
|
let mut dest = src2.map(|v| Some(v.into()));
|
||||||
|
dest.so = Some((src0.cr_gt, src1.cr_lt).into());
|
||||||
|
dest
|
||||||
|
}),
|
||||||
|
$lut,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
concat!($mnemonic, " lt, gt, eq"),
|
||||||
|
$encoding | 0x00011000,
|
||||||
|
None,
|
||||||
|
LogicalFlagsMOp::logical_flags(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(0)], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_cr_reg_imm(0).value,
|
||||||
|
MOpRegNum::power_isa_cr_reg_imm(0).value,
|
||||||
|
MOpRegNum::power_isa_cr_reg_imm(0).value,
|
||||||
|
],
|
||||||
|
LogicalFlagsMOpImm::from_swizzle_fn::<PRegFlagsPowerISA>(|src0, src1, src2| {
|
||||||
|
let mut dest = src2.map(|v| Some(v.into()));
|
||||||
|
dest.cr_lt = Some((src0.cr_gt, src1.cr_eq).into());
|
||||||
|
dest
|
||||||
|
}),
|
||||||
|
$lut,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
concat!($mnemonic, " gt, gt, eq"),
|
||||||
|
$encoding | 0x00211000,
|
||||||
|
None,
|
||||||
|
LogicalFlagsMOp::logical_flags(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(0)], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_cr_reg_imm(0).value,
|
||||||
|
MOpRegNum::power_isa_cr_reg_imm(0).value,
|
||||||
|
MOpRegNum::power_isa_cr_reg_imm(0).value,
|
||||||
|
],
|
||||||
|
LogicalFlagsMOpImm::from_swizzle_fn::<PRegFlagsPowerISA>(|src0, src1, src2| {
|
||||||
|
let mut dest = src2.map(|v| Some(v.into()));
|
||||||
|
dest.cr_gt = Some((src0.cr_gt, src1.cr_eq).into());
|
||||||
|
dest
|
||||||
|
}),
|
||||||
|
$lut,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
cr_bit_logical_op!("crand", 0x4c000202, Lut4::from_fn(|a, b| a & b));
|
||||||
|
cr_bit_logical_op!("crnand", 0x4c0001c2, Lut4::from_fn(|a, b| !(a & b)));
|
||||||
|
cr_bit_logical_op!("cror", 0x4c000382, Lut4::from_fn(|a, b| a | b));
|
||||||
|
cr_bit_logical_op!("crxor", 0x4c000182, Lut4::from_fn(|a, b| a ^ b));
|
||||||
|
cr_bit_logical_op!("crnor", 0x4c000042, Lut4::from_fn(|a, b| !(a | b)));
|
||||||
|
cr_bit_logical_op!("creqv", 0x4c000242, Lut4::from_fn(|a, b| a == b));
|
||||||
|
cr_bit_logical_op!("crandc", 0x4c000102, Lut4::from_fn(|a, b| a & !b));
|
||||||
|
cr_bit_logical_op!("crorc", 0x4c000342, Lut4::from_fn(|a, b| a | !b));
|
||||||
|
macro_rules! mcrf {
|
||||||
|
($dest:literal, $src:literal; $encoding:literal) => {
|
||||||
|
retval.push(insn_single(
|
||||||
|
concat!("mcrf ", $dest, ", ", $src),
|
||||||
|
$encoding,
|
||||||
|
None,
|
||||||
|
MoveRegMOp::move_reg(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num($dest)], &[]),
|
||||||
|
[MOpRegNum::power_isa_cr_reg_imm($src).value],
|
||||||
|
0i8.cast_to_static::<SInt<_>>(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
mcrf!(0, 0; 0x4c000000);
|
||||||
|
mcrf!(5, 7; 0x4e9c0000);
|
||||||
|
mcrf!(5, 0; 0x4e800000);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,408 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use crate::test_cases::{TestCase, insn_single};
|
||||||
|
use cpu::instruction::{AddSubMOp, MOpDestReg, MOpRegNum, OutputIntegerMode};
|
||||||
|
use fayalite::prelude::*;
|
||||||
|
|
||||||
|
/// covers instructions in PowerISA v3.1C Book I 3.3.9 Fixed-Point Arithmetic Instructions
|
||||||
|
pub fn test_cases_book_i_3_3_9_fixed_point_arithmetic(retval: &mut Vec<TestCase>) {
|
||||||
|
retval.push(insn_single(
|
||||||
|
"addi 3, 4, 0x1234",
|
||||||
|
0x38641234,
|
||||||
|
None,
|
||||||
|
AddSubMOp::add_sub_i(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
],
|
||||||
|
0x1234.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"paddi 3, 4, 0x123456789, 0",
|
||||||
|
0x06012345,
|
||||||
|
Some(0x38646789),
|
||||||
|
AddSubMOp::add_sub_i(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
],
|
||||||
|
0x123456789i64.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"paddi 3, 0, 0x123456789, 1",
|
||||||
|
0x06112345,
|
||||||
|
Some(0x38606789),
|
||||||
|
AddSubMOp::add_sub_i(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||||
|
[MOpRegNum::const_zero().value, MOpRegNum::const_zero().value],
|
||||||
|
0x123456789i64.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"addis 3, 4, 0x1234",
|
||||||
|
0x3C641234,
|
||||||
|
None,
|
||||||
|
AddSubMOp::add_sub_i(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
],
|
||||||
|
0x12340000.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"addpcis 3, 0x1234",
|
||||||
|
0x4c7a1204,
|
||||||
|
None,
|
||||||
|
AddSubMOp::add_sub_i(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||||
|
[MOpRegNum::const_zero().value; _],
|
||||||
|
0x12340004.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"add. 3, 4, 5",
|
||||||
|
0x7c642a15,
|
||||||
|
None,
|
||||||
|
AddSubMOp::add_sub(
|
||||||
|
MOpDestReg::new_sim(
|
||||||
|
&[MOpRegNum::power_isa_gpr_reg_num(3)],
|
||||||
|
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
|
||||||
|
),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(5).value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"addic. 3, 4, 0x1234",
|
||||||
|
0x34641234,
|
||||||
|
None,
|
||||||
|
AddSubMOp::add_sub_i(
|
||||||
|
MOpDestReg::new_sim(
|
||||||
|
&[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_num(3),
|
||||||
|
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
|
||||||
|
],
|
||||||
|
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
|
||||||
|
),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
],
|
||||||
|
0x1234.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"subf. 3, 4, 5",
|
||||||
|
0x7c642851,
|
||||||
|
None,
|
||||||
|
AddSubMOp::add_sub(
|
||||||
|
MOpDestReg::new_sim(
|
||||||
|
&[MOpRegNum::power_isa_gpr_reg_num(3)],
|
||||||
|
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
|
||||||
|
),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(5).value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"subfic 3, 4, 0x1234",
|
||||||
|
0x20641234,
|
||||||
|
None,
|
||||||
|
AddSubMOp::add_sub_i(
|
||||||
|
MOpDestReg::new_sim(
|
||||||
|
&[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_num(3),
|
||||||
|
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
|
||||||
|
],
|
||||||
|
&[],
|
||||||
|
),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
],
|
||||||
|
0x1234.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"addc. 3, 4, 5",
|
||||||
|
0x7c642815,
|
||||||
|
None,
|
||||||
|
AddSubMOp::add_sub(
|
||||||
|
MOpDestReg::new_sim(
|
||||||
|
&[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_num(3),
|
||||||
|
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
|
||||||
|
],
|
||||||
|
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
|
||||||
|
),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(5).value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"subfc. 3, 4, 5",
|
||||||
|
0x7c642811,
|
||||||
|
None,
|
||||||
|
AddSubMOp::add_sub(
|
||||||
|
MOpDestReg::new_sim(
|
||||||
|
&[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_num(3),
|
||||||
|
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
|
||||||
|
],
|
||||||
|
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
|
||||||
|
),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(5).value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"adde. 3, 4, 5",
|
||||||
|
0x7c642915,
|
||||||
|
None,
|
||||||
|
AddSubMOp::add_sub(
|
||||||
|
MOpDestReg::new_sim(
|
||||||
|
&[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_num(3),
|
||||||
|
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
|
||||||
|
],
|
||||||
|
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
|
||||||
|
),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||||
|
MOpRegNum::power_isa_xer_ca_ca32_reg().value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(5).value,
|
||||||
|
],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"subfe. 3, 4, 5",
|
||||||
|
0x7c642911,
|
||||||
|
None,
|
||||||
|
AddSubMOp::add_sub(
|
||||||
|
MOpDestReg::new_sim(
|
||||||
|
&[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_num(3),
|
||||||
|
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
|
||||||
|
],
|
||||||
|
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
|
||||||
|
),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||||
|
MOpRegNum::power_isa_xer_ca_ca32_reg().value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(5).value,
|
||||||
|
],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"addme. 3, 4",
|
||||||
|
0x7c6401d5,
|
||||||
|
None,
|
||||||
|
AddSubMOp::add_sub(
|
||||||
|
MOpDestReg::new_sim(
|
||||||
|
&[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_num(3),
|
||||||
|
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
|
||||||
|
],
|
||||||
|
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
|
||||||
|
),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||||
|
MOpRegNum::power_isa_xer_ca_ca32_reg().value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
],
|
||||||
|
(-1i8).cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"subfme. 3, 4",
|
||||||
|
0x7c6401d1,
|
||||||
|
None,
|
||||||
|
AddSubMOp::add_sub(
|
||||||
|
MOpDestReg::new_sim(
|
||||||
|
&[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_num(3),
|
||||||
|
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
|
||||||
|
],
|
||||||
|
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
|
||||||
|
),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||||
|
MOpRegNum::power_isa_xer_ca_ca32_reg().value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
],
|
||||||
|
(-1i8).cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"addze. 3, 4",
|
||||||
|
0x7c640195,
|
||||||
|
None,
|
||||||
|
AddSubMOp::add_sub(
|
||||||
|
MOpDestReg::new_sim(
|
||||||
|
&[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_num(3),
|
||||||
|
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
|
||||||
|
],
|
||||||
|
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
|
||||||
|
),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||||
|
MOpRegNum::power_isa_xer_ca_ca32_reg().value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"subfze. 3, 4",
|
||||||
|
0x7c640191,
|
||||||
|
None,
|
||||||
|
AddSubMOp::add_sub(
|
||||||
|
MOpDestReg::new_sim(
|
||||||
|
&[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_num(3),
|
||||||
|
MOpRegNum::POWER_ISA_XER_CA_CA32_REG_NUM,
|
||||||
|
],
|
||||||
|
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
|
||||||
|
),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||||
|
MOpRegNum::power_isa_xer_ca_ca32_reg().value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"neg. 3, 4",
|
||||||
|
0x7c6400d1,
|
||||||
|
None,
|
||||||
|
AddSubMOp::add_sub(
|
||||||
|
MOpDestReg::new_sim(
|
||||||
|
&[MOpRegNum::power_isa_gpr_reg_num(3)],
|
||||||
|
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM],
|
||||||
|
),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,163 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use crate::test_cases::{TestCase, insn_single};
|
||||||
|
use cpu::instruction::{CompareMOp, CompareMode, MOpDestReg, MOpRegNum, OutputIntegerMode};
|
||||||
|
use fayalite::prelude::*;
|
||||||
|
|
||||||
|
/// covers instructions in PowerISA v3.1C Book I 3.3.10 Fixed-Point Compare Instructions
|
||||||
|
pub fn test_cases_book_i_3_3_10_fixed_point_compare(retval: &mut Vec<TestCase>) {
|
||||||
|
retval.push(insn_single(
|
||||||
|
"cmpi 3, 0, 4, 0x1234",
|
||||||
|
0x2d841234,
|
||||||
|
None,
|
||||||
|
CompareMOp::compare_i(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||||
|
[MOpRegNum::power_isa_gpr_reg_imm(4).value],
|
||||||
|
0x1234.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
CompareMode.S32(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"cmpi 3, 1, 4, -0x7655",
|
||||||
|
0x2da489ab,
|
||||||
|
None,
|
||||||
|
CompareMOp::compare_i(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||||
|
[MOpRegNum::power_isa_gpr_reg_imm(4).value],
|
||||||
|
(0x89abu16 as i16).cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
CompareMode.S64(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"cmp 3, 0, 4, 5",
|
||||||
|
0x7d842800,
|
||||||
|
None,
|
||||||
|
CompareMOp::compare(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(5).value,
|
||||||
|
],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
CompareMode.S32(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"cmp 3, 1, 4, 5",
|
||||||
|
0x7da42800,
|
||||||
|
None,
|
||||||
|
CompareMOp::compare(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(5).value,
|
||||||
|
],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
CompareMode.S64(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"cmpli 3, 0, 4, 0x1234",
|
||||||
|
0x29841234,
|
||||||
|
None,
|
||||||
|
CompareMOp::compare_i(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||||
|
[MOpRegNum::power_isa_gpr_reg_imm(4).value],
|
||||||
|
0x1234.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
CompareMode.U32(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"cmpli 3, 1, 4, 0x89ab",
|
||||||
|
0x29a489ab,
|
||||||
|
None,
|
||||||
|
CompareMOp::compare_i(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||||
|
[MOpRegNum::power_isa_gpr_reg_imm(4).value],
|
||||||
|
0x89ab.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
CompareMode.U64(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"cmpl 3, 0, 4, 5",
|
||||||
|
0x7d842840,
|
||||||
|
None,
|
||||||
|
CompareMOp::compare(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(5).value,
|
||||||
|
],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
CompareMode.U32(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"cmpl 3, 1, 4, 5",
|
||||||
|
0x7da42840,
|
||||||
|
None,
|
||||||
|
CompareMOp::compare(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(5).value,
|
||||||
|
],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
CompareMode.U64(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"cmprb 3, 0, 4, 5",
|
||||||
|
0x7d842980,
|
||||||
|
None,
|
||||||
|
CompareMOp::compare(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(5).value,
|
||||||
|
],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
CompareMode.CmpRBOne(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"cmprb 3, 1, 4, 5",
|
||||||
|
0x7da42980,
|
||||||
|
None,
|
||||||
|
CompareMOp::compare(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(5).value,
|
||||||
|
],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
CompareMode.CmpRBTwo(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"cmpeqb 3, 4, 5",
|
||||||
|
0x7d8429c0,
|
||||||
|
None,
|
||||||
|
CompareMOp::compare(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(4).value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm(5).value,
|
||||||
|
],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
CompareMode.CmpEqB(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,525 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use crate::test_cases::{TestCase, insn_double};
|
||||||
|
use cpu::instruction::{
|
||||||
|
AddSubMOp, LoadMOp, LoadStoreConversion, LoadStoreWidth, MOpDestReg, MOpRegNum,
|
||||||
|
OutputIntegerMode,
|
||||||
|
};
|
||||||
|
use fayalite::prelude::*;
|
||||||
|
|
||||||
|
/// covers instructions in PowerISA v3.1C Book I 3.3.2 Fixed-Point Load Instructions
|
||||||
|
pub fn test_cases_book_i_3_3_2_fixed_point_load(retval: &mut Vec<TestCase>) {
|
||||||
|
macro_rules! load_prefixed {
|
||||||
|
(
|
||||||
|
$mnemonic:literal $dest:literal, $disp:literal($ra:literal), $r:literal;
|
||||||
|
$prefix:literal, $suffix:literal;
|
||||||
|
$width:ident;
|
||||||
|
$conversion:ident;
|
||||||
|
) => {
|
||||||
|
retval.push(insn_double(
|
||||||
|
concat!($mnemonic, " ", $dest, ", ", $disp, "(", $ra, "), ", $r),
|
||||||
|
$prefix,
|
||||||
|
Some($suffix),
|
||||||
|
[
|
||||||
|
AddSubMOp::add_sub_i(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]),
|
||||||
|
[
|
||||||
|
if $r != 0 || $ra == 0 {
|
||||||
|
MOpRegNum::const_zero().value
|
||||||
|
} else {
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($ra).value
|
||||||
|
},
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
],
|
||||||
|
($disp as i64).cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
$r != 0,
|
||||||
|
),
|
||||||
|
LoadMOp::load(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
|
||||||
|
[MOpRegNum::power_isa_temp_reg().value],
|
||||||
|
LoadStoreWidth.$width(),
|
||||||
|
LoadStoreConversion.$conversion(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
macro_rules! load {
|
||||||
|
(
|
||||||
|
$mnemonic:literal $dest:literal, $disp:literal($ra:literal);
|
||||||
|
$encoding:literal;
|
||||||
|
$width:ident;
|
||||||
|
$conversion:ident;
|
||||||
|
) => {
|
||||||
|
retval.push(insn_double(
|
||||||
|
concat!($mnemonic, " ", $dest, ", ", $disp, "(", $ra, ")"),
|
||||||
|
$encoding,
|
||||||
|
None,
|
||||||
|
[
|
||||||
|
AddSubMOp::add_sub_i(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]),
|
||||||
|
[
|
||||||
|
if $ra == 0 {
|
||||||
|
MOpRegNum::const_zero().value
|
||||||
|
} else {
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($ra).value
|
||||||
|
},
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
],
|
||||||
|
($disp as i64).cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
LoadMOp::load(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
|
||||||
|
[MOpRegNum::power_isa_temp_reg().value],
|
||||||
|
LoadStoreWidth.$width(),
|
||||||
|
LoadStoreConversion.$conversion(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
macro_rules! load_update {
|
||||||
|
(
|
||||||
|
$mnemonic:literal $dest:literal, $disp:literal($ra:literal);
|
||||||
|
$encoding:literal;
|
||||||
|
$width:ident;
|
||||||
|
$conversion:ident;
|
||||||
|
) => {
|
||||||
|
retval.push(insn_double(
|
||||||
|
concat!($mnemonic, " ", $dest, ", ", $disp, "(", $ra, ")"),
|
||||||
|
$encoding,
|
||||||
|
None,
|
||||||
|
[
|
||||||
|
AddSubMOp::add_sub_i(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($ra)], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($ra).value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
],
|
||||||
|
($disp as i64).cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
LoadMOp::load(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
|
||||||
|
[MOpRegNum::power_isa_gpr_reg_imm($ra).value],
|
||||||
|
LoadStoreWidth.$width(),
|
||||||
|
LoadStoreConversion.$conversion(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
macro_rules! load_indexed {
|
||||||
|
(
|
||||||
|
$mnemonic:literal $dest:literal, $ra:literal, $rb:literal;
|
||||||
|
$encoding:literal;
|
||||||
|
$width:ident;
|
||||||
|
$conversion:ident;
|
||||||
|
) => {
|
||||||
|
retval.push(insn_double(
|
||||||
|
concat!($mnemonic, " ", $dest, ", ", $ra, ", ", $rb),
|
||||||
|
$encoding,
|
||||||
|
None,
|
||||||
|
[
|
||||||
|
AddSubMOp::add_sub_i(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]),
|
||||||
|
[
|
||||||
|
if $ra == 0 {
|
||||||
|
MOpRegNum::const_zero().value
|
||||||
|
} else {
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($ra).value
|
||||||
|
},
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($rb).value,
|
||||||
|
],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
LoadMOp::load(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
|
||||||
|
[MOpRegNum::power_isa_temp_reg().value],
|
||||||
|
LoadStoreWidth.$width(),
|
||||||
|
LoadStoreConversion.$conversion(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
macro_rules! load_update_indexed {
|
||||||
|
(
|
||||||
|
$mnemonic:literal $dest:literal, $ra:literal, $rb:literal;
|
||||||
|
$encoding:literal;
|
||||||
|
$width:ident;
|
||||||
|
$conversion:ident;
|
||||||
|
) => {
|
||||||
|
retval.push(insn_double(
|
||||||
|
concat!($mnemonic, " ", $dest, ", ", $ra, ", ", $rb),
|
||||||
|
$encoding,
|
||||||
|
None,
|
||||||
|
[
|
||||||
|
AddSubMOp::add_sub_i(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($ra)], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($ra).value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($rb).value,
|
||||||
|
],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
LoadMOp::load(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($dest)], &[]),
|
||||||
|
[MOpRegNum::power_isa_gpr_reg_imm($ra).value],
|
||||||
|
LoadStoreWidth.$width(),
|
||||||
|
LoadStoreConversion.$conversion(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
load! {
|
||||||
|
"lbz" 3, 0x1234(4);
|
||||||
|
0x88641234;
|
||||||
|
Width8Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load! {
|
||||||
|
"lbz" 3, 0x1234(0);
|
||||||
|
0x88601234;
|
||||||
|
Width8Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load_prefixed! {
|
||||||
|
"plbz" 3, 0x123456789(4), 0;
|
||||||
|
0x06012345, 0x88646789;
|
||||||
|
Width8Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load_prefixed! {
|
||||||
|
"plbz" 3, 0x123456789(0), 0;
|
||||||
|
0x06012345, 0x88606789;
|
||||||
|
Width8Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load_prefixed! {
|
||||||
|
"plbz" 3, 0x123456789(0), 1;
|
||||||
|
0x06112345, 0x88606789;
|
||||||
|
Width8Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load_indexed! {
|
||||||
|
"lbzx" 3, 4, 5;
|
||||||
|
0x7c6428ae;
|
||||||
|
Width8Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load_indexed! {
|
||||||
|
"lbzx" 3, 0, 5;
|
||||||
|
0x7c6028ae;
|
||||||
|
Width8Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load_update! {
|
||||||
|
"lbzu" 3, 0x1234(4);
|
||||||
|
0x8c641234;
|
||||||
|
Width8Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load_update_indexed! {
|
||||||
|
"lbzux" 3, 4, 5;
|
||||||
|
0x7c6428ee;
|
||||||
|
Width8Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
|
||||||
|
load! {
|
||||||
|
"lhz" 3, 0x1234(4);
|
||||||
|
0xa0641234;
|
||||||
|
Width16Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load! {
|
||||||
|
"lhz" 3, 0x1234(0);
|
||||||
|
0xa0601234;
|
||||||
|
Width16Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load_prefixed! {
|
||||||
|
"plhz" 3, 0x123456789(4), 0;
|
||||||
|
0x06012345, 0xa0646789;
|
||||||
|
Width16Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load_prefixed! {
|
||||||
|
"plhz" 3, 0x123456789(0), 0;
|
||||||
|
0x06012345, 0xa0606789;
|
||||||
|
Width16Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load_prefixed! {
|
||||||
|
"plhz" 3, 0x123456789(0), 1;
|
||||||
|
0x06112345, 0xa0606789;
|
||||||
|
Width16Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load_indexed! {
|
||||||
|
"lhzx" 3, 4, 5;
|
||||||
|
0x7c642a2e;
|
||||||
|
Width16Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load_indexed! {
|
||||||
|
"lhzx" 3, 0, 5;
|
||||||
|
0x7c602a2e;
|
||||||
|
Width16Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load_update! {
|
||||||
|
"lhzu" 3, 0x1234(4);
|
||||||
|
0xa4641234;
|
||||||
|
Width16Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load_update_indexed! {
|
||||||
|
"lhzux" 3, 4, 5;
|
||||||
|
0x7c642a6e;
|
||||||
|
Width16Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
|
||||||
|
load! {
|
||||||
|
"lha" 3, 0x1234(4);
|
||||||
|
0xa8641234;
|
||||||
|
Width16Bit;
|
||||||
|
SignExt;
|
||||||
|
}
|
||||||
|
load! {
|
||||||
|
"lha" 3, 0x1234(0);
|
||||||
|
0xa8601234;
|
||||||
|
Width16Bit;
|
||||||
|
SignExt;
|
||||||
|
}
|
||||||
|
load_prefixed! {
|
||||||
|
"plha" 3, 0x123456789(4), 0;
|
||||||
|
0x06012345, 0xa8646789;
|
||||||
|
Width16Bit;
|
||||||
|
SignExt;
|
||||||
|
}
|
||||||
|
load_prefixed! {
|
||||||
|
"plha" 3, 0x123456789(0), 0;
|
||||||
|
0x06012345, 0xa8606789;
|
||||||
|
Width16Bit;
|
||||||
|
SignExt;
|
||||||
|
}
|
||||||
|
load_prefixed! {
|
||||||
|
"plha" 3, 0x123456789(0), 1;
|
||||||
|
0x06112345, 0xa8606789;
|
||||||
|
Width16Bit;
|
||||||
|
SignExt;
|
||||||
|
}
|
||||||
|
load_indexed! {
|
||||||
|
"lhax" 3, 4, 5;
|
||||||
|
0x7c642aae;
|
||||||
|
Width16Bit;
|
||||||
|
SignExt;
|
||||||
|
}
|
||||||
|
load_indexed! {
|
||||||
|
"lhax" 3, 0, 5;
|
||||||
|
0x7c602aae;
|
||||||
|
Width16Bit;
|
||||||
|
SignExt;
|
||||||
|
}
|
||||||
|
load_update! {
|
||||||
|
"lhau" 3, 0x1234(4);
|
||||||
|
0xac641234;
|
||||||
|
Width16Bit;
|
||||||
|
SignExt;
|
||||||
|
}
|
||||||
|
load_update_indexed! {
|
||||||
|
"lhaux" 3, 4, 5;
|
||||||
|
0x7c642aee;
|
||||||
|
Width16Bit;
|
||||||
|
SignExt;
|
||||||
|
}
|
||||||
|
|
||||||
|
load! {
|
||||||
|
"lwz" 3, 0x1234(4);
|
||||||
|
0x80641234;
|
||||||
|
Width32Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load! {
|
||||||
|
"lwz" 3, 0x1234(0);
|
||||||
|
0x80601234;
|
||||||
|
Width32Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load_prefixed! {
|
||||||
|
"plwz" 3, 0x123456789(4), 0;
|
||||||
|
0x06012345, 0x80646789;
|
||||||
|
Width32Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load_prefixed! {
|
||||||
|
"plwz" 3, 0x123456789(0), 0;
|
||||||
|
0x06012345, 0x80606789;
|
||||||
|
Width32Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load_prefixed! {
|
||||||
|
"plwz" 3, 0x123456789(0), 1;
|
||||||
|
0x06112345, 0x80606789;
|
||||||
|
Width32Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load_indexed! {
|
||||||
|
"lwzx" 3, 4, 5;
|
||||||
|
0x7c64282e;
|
||||||
|
Width32Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load_indexed! {
|
||||||
|
"lwzx" 3, 0, 5;
|
||||||
|
0x7c60282e;
|
||||||
|
Width32Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load_update! {
|
||||||
|
"lwzu" 3, 0x1234(4);
|
||||||
|
0x84641234;
|
||||||
|
Width32Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load_update_indexed! {
|
||||||
|
"lwzux" 3, 4, 5;
|
||||||
|
0x7c64286e;
|
||||||
|
Width32Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
|
||||||
|
load! {
|
||||||
|
"lwa" 3, 0x1234(4);
|
||||||
|
0xe8641236;
|
||||||
|
Width32Bit;
|
||||||
|
SignExt;
|
||||||
|
}
|
||||||
|
load! {
|
||||||
|
"lwa" 3, 0x1234(0);
|
||||||
|
0xe8601236;
|
||||||
|
Width32Bit;
|
||||||
|
SignExt;
|
||||||
|
}
|
||||||
|
load_prefixed! {
|
||||||
|
"plwa" 3, 0x123456789(4), 0;
|
||||||
|
0x04012345, 0xa4646789;
|
||||||
|
Width32Bit;
|
||||||
|
SignExt;
|
||||||
|
}
|
||||||
|
load_prefixed! {
|
||||||
|
"plwa" 3, 0x123456789(0), 0;
|
||||||
|
0x04012345, 0xa4606789;
|
||||||
|
Width32Bit;
|
||||||
|
SignExt;
|
||||||
|
}
|
||||||
|
load_prefixed! {
|
||||||
|
"plwa" 3, 0x123456789(0), 1;
|
||||||
|
0x04112345, 0xa4606789;
|
||||||
|
Width32Bit;
|
||||||
|
SignExt;
|
||||||
|
}
|
||||||
|
load_indexed! {
|
||||||
|
"lwax" 3, 4, 5;
|
||||||
|
0x7c642aaa;
|
||||||
|
Width32Bit;
|
||||||
|
SignExt;
|
||||||
|
}
|
||||||
|
load_indexed! {
|
||||||
|
"lwax" 3, 0, 5;
|
||||||
|
0x7c602aaa;
|
||||||
|
Width32Bit;
|
||||||
|
SignExt;
|
||||||
|
}
|
||||||
|
// there is no `lwau`
|
||||||
|
load_update_indexed! {
|
||||||
|
"lwaux" 3, 4, 5;
|
||||||
|
0x7c642aea;
|
||||||
|
Width32Bit;
|
||||||
|
SignExt;
|
||||||
|
}
|
||||||
|
|
||||||
|
load! {
|
||||||
|
"ld" 3, 0x1234(4);
|
||||||
|
0xe8641234;
|
||||||
|
Width64Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load! {
|
||||||
|
"ld" 3, 0x1234(0);
|
||||||
|
0xe8601234;
|
||||||
|
Width64Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load_prefixed! {
|
||||||
|
"pld" 3, 0x123456789(4), 0;
|
||||||
|
0x04012345, 0xe4646789;
|
||||||
|
Width64Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load_prefixed! {
|
||||||
|
"pld" 3, 0x123456789(0), 0;
|
||||||
|
0x04012345, 0xe4606789;
|
||||||
|
Width64Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load_prefixed! {
|
||||||
|
"pld" 3, 0x123456789(0), 1;
|
||||||
|
0x04112345, 0xe4606789;
|
||||||
|
Width64Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load_indexed! {
|
||||||
|
"ldx" 3, 4, 5;
|
||||||
|
0x7c64282a;
|
||||||
|
Width64Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load_indexed! {
|
||||||
|
"ldx" 3, 0, 5;
|
||||||
|
0x7c60282a;
|
||||||
|
Width64Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load_update! {
|
||||||
|
"ldu" 3, 0x1234(4);
|
||||||
|
0xe8641235;
|
||||||
|
Width64Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
load_update_indexed! {
|
||||||
|
"ldux" 3, 4, 5;
|
||||||
|
0x7c64286a;
|
||||||
|
Width64Bit;
|
||||||
|
ZeroExt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,273 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use crate::test_cases::{TestCase, insn_empty, insn_single};
|
||||||
|
use cpu::instruction::{LogicalMOp, Lut4, MOpDestReg, MOpRegNum, MoveRegMOp, OutputIntegerMode};
|
||||||
|
use fayalite::prelude::*;
|
||||||
|
|
||||||
|
/// covers instructions in PowerISA v3.1C Book I 3.3.13 Fixed-Point Logical Instructions
|
||||||
|
pub fn test_cases_book_i_3_3_13_fixed_point_logical(retval: &mut Vec<TestCase>) {
|
||||||
|
macro_rules! insn_logic_i {
|
||||||
|
(
|
||||||
|
$mnemonic:literal $dest:literal, $src:literal, $imm:literal;
|
||||||
|
$encoding:literal;
|
||||||
|
|$a:ident, $b:ident| $lut_fn:expr;
|
||||||
|
) => {
|
||||||
|
retval.push(insn_single(
|
||||||
|
concat!(
|
||||||
|
$mnemonic,
|
||||||
|
" ",
|
||||||
|
stringify!($dest),
|
||||||
|
", ",
|
||||||
|
stringify!($src),
|
||||||
|
", ",
|
||||||
|
stringify!($imm)
|
||||||
|
),
|
||||||
|
$encoding,
|
||||||
|
None,
|
||||||
|
LogicalMOp::logical_i(
|
||||||
|
MOpDestReg::new_sim(
|
||||||
|
&[MOpRegNum::power_isa_gpr_reg_num($dest)],
|
||||||
|
if $mnemonic.contains('.') {
|
||||||
|
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM]
|
||||||
|
} else {
|
||||||
|
&[]
|
||||||
|
},
|
||||||
|
),
|
||||||
|
[MOpRegNum::power_isa_gpr_reg_imm($src).value],
|
||||||
|
(($imm as u32) << if $mnemonic.contains('s') { 16 } else { 0 })
|
||||||
|
.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
Lut4::from_fn(|$a, $b| $lut_fn),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
insn_logic_i! {
|
||||||
|
"andi." 3, 4, 0x89ab;
|
||||||
|
0x708389ab;
|
||||||
|
|a, b| a & b;
|
||||||
|
}
|
||||||
|
insn_logic_i! {
|
||||||
|
"andis." 3, 4, 0x89ab;
|
||||||
|
0x748389ab;
|
||||||
|
|a, b| a & b;
|
||||||
|
}
|
||||||
|
insn_logic_i! {
|
||||||
|
"ori" 3, 4, 0x89ab;
|
||||||
|
0x608389ab;
|
||||||
|
|a, b| a | b;
|
||||||
|
}
|
||||||
|
// ensure nop decodes to zero instructions
|
||||||
|
retval.push(insn_empty("ori 0, 0, 0", 0x60000000, None));
|
||||||
|
insn_logic_i! {
|
||||||
|
"oris" 3, 4, 0x89ab;
|
||||||
|
0x648389ab;
|
||||||
|
|a, b| a | b;
|
||||||
|
}
|
||||||
|
insn_logic_i! {
|
||||||
|
"xori" 3, 4, 0x89ab;
|
||||||
|
0x688389ab;
|
||||||
|
|a, b| a ^ b;
|
||||||
|
}
|
||||||
|
insn_logic_i! {
|
||||||
|
"xori" 0, 0, 0; // ensure xnop actually decodes to a normal ALU instruction
|
||||||
|
0x68000000;
|
||||||
|
|a, b| a ^ b;
|
||||||
|
}
|
||||||
|
insn_logic_i! {
|
||||||
|
"xoris" 3, 4, 0x89ab;
|
||||||
|
0x6c8389ab;
|
||||||
|
|a, b| a ^ b;
|
||||||
|
}
|
||||||
|
macro_rules! insn_logic {
|
||||||
|
(
|
||||||
|
$mnemonic:literal $dest:literal, $src0:literal, $src1:literal;
|
||||||
|
$encoding:literal;
|
||||||
|
|$a:ident, $b:ident| $lut_fn:expr;
|
||||||
|
) => {
|
||||||
|
retval.push(insn_single(
|
||||||
|
concat!(
|
||||||
|
$mnemonic,
|
||||||
|
" ",
|
||||||
|
stringify!($dest),
|
||||||
|
", ",
|
||||||
|
stringify!($src0),
|
||||||
|
", ",
|
||||||
|
stringify!($src1)
|
||||||
|
),
|
||||||
|
$encoding,
|
||||||
|
None,
|
||||||
|
LogicalMOp::logical(
|
||||||
|
MOpDestReg::new_sim(
|
||||||
|
&[MOpRegNum::power_isa_gpr_reg_num($dest)],
|
||||||
|
if $mnemonic.contains('.') {
|
||||||
|
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM]
|
||||||
|
} else {
|
||||||
|
&[]
|
||||||
|
},
|
||||||
|
),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($src0).value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($src1).value,
|
||||||
|
],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
Lut4::from_fn(|$a, $b| $lut_fn),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
insn_logic! {
|
||||||
|
"and" 3, 4, 5;
|
||||||
|
0x7c832838;
|
||||||
|
|a, b| a & b;
|
||||||
|
}
|
||||||
|
insn_logic! {
|
||||||
|
"and." 3, 4, 5;
|
||||||
|
0x7c832839;
|
||||||
|
|a, b| a & b;
|
||||||
|
}
|
||||||
|
insn_logic! {
|
||||||
|
"xor" 3, 4, 5;
|
||||||
|
0x7c832a78;
|
||||||
|
|a, b| a ^ b;
|
||||||
|
}
|
||||||
|
insn_logic! {
|
||||||
|
"xor." 3, 4, 5;
|
||||||
|
0x7c832a79;
|
||||||
|
|a, b| a ^ b;
|
||||||
|
}
|
||||||
|
insn_logic! {
|
||||||
|
"nand" 3, 4, 5;
|
||||||
|
0x7c832bb8;
|
||||||
|
|a, b| !(a & b);
|
||||||
|
}
|
||||||
|
insn_logic! {
|
||||||
|
"nand." 3, 4, 5;
|
||||||
|
0x7c832bb9;
|
||||||
|
|a, b| !(a & b);
|
||||||
|
}
|
||||||
|
insn_logic! {
|
||||||
|
"or" 3, 4, 5;
|
||||||
|
0x7c832b78;
|
||||||
|
|a, b| a | b;
|
||||||
|
}
|
||||||
|
retval.push(insn_single(
|
||||||
|
"or 3, 4, 4", // mr 3, 4
|
||||||
|
0x7c832378,
|
||||||
|
None,
|
||||||
|
MoveRegMOp::move_reg(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||||
|
[MOpRegNum::power_isa_gpr_reg_imm(4).value],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
insn_logic! {
|
||||||
|
"or." 3, 4, 5;
|
||||||
|
0x7c832b79;
|
||||||
|
|a, b| a | b;
|
||||||
|
}
|
||||||
|
insn_logic! {
|
||||||
|
"or." 3, 4, 4; // mr. 3, 4
|
||||||
|
0x7c832379;
|
||||||
|
|a, b| a | b;
|
||||||
|
}
|
||||||
|
insn_logic! {
|
||||||
|
"orc" 3, 4, 5;
|
||||||
|
0x7c832b38;
|
||||||
|
|a, b| a | !b;
|
||||||
|
}
|
||||||
|
insn_logic! {
|
||||||
|
"orc." 3, 4, 5;
|
||||||
|
0x7c832b39;
|
||||||
|
|a, b| a | !b;
|
||||||
|
}
|
||||||
|
insn_logic! {
|
||||||
|
"nor" 3, 4, 5;
|
||||||
|
0x7c8328f8;
|
||||||
|
|a, b| !(a | b);
|
||||||
|
}
|
||||||
|
insn_logic! {
|
||||||
|
"nor." 3, 4, 5;
|
||||||
|
0x7c8328f9;
|
||||||
|
|a, b| !(a | b);
|
||||||
|
}
|
||||||
|
insn_logic! {
|
||||||
|
"eqv" 3, 4, 5;
|
||||||
|
0x7c832a38;
|
||||||
|
|a, b| a == b;
|
||||||
|
}
|
||||||
|
insn_logic! {
|
||||||
|
"eqv." 3, 4, 5;
|
||||||
|
0x7c832a39;
|
||||||
|
|a, b| a == b;
|
||||||
|
}
|
||||||
|
insn_logic! {
|
||||||
|
"andc" 3, 4, 5;
|
||||||
|
0x7c832878;
|
||||||
|
|a, b| a & !b;
|
||||||
|
}
|
||||||
|
insn_logic! {
|
||||||
|
"andc." 3, 4, 5;
|
||||||
|
0x7c832879;
|
||||||
|
|a, b| a & !b;
|
||||||
|
}
|
||||||
|
macro_rules! insn_exts {
|
||||||
|
(
|
||||||
|
$mnemonic:literal $dest:literal, $src:literal;
|
||||||
|
$encoding:literal;
|
||||||
|
$OutputIntegerMode:ident;
|
||||||
|
) => {
|
||||||
|
retval.push(insn_single(
|
||||||
|
concat!($mnemonic, " ", stringify!($dest), ", ", stringify!($src)),
|
||||||
|
$encoding,
|
||||||
|
None,
|
||||||
|
LogicalMOp::logical_i(
|
||||||
|
MOpDestReg::new_sim(
|
||||||
|
&[MOpRegNum::power_isa_gpr_reg_num($dest)],
|
||||||
|
if $mnemonic.contains('.') {
|
||||||
|
&[MOpRegNum::POWER_ISA_CR_0_REG_NUM]
|
||||||
|
} else {
|
||||||
|
&[]
|
||||||
|
},
|
||||||
|
),
|
||||||
|
[MOpRegNum::power_isa_gpr_reg_imm($src).value],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.$OutputIntegerMode(),
|
||||||
|
Lut4::from_fn(|a, b| a | b),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
insn_exts! {
|
||||||
|
"extsb" 3, 4;
|
||||||
|
0x7c830774;
|
||||||
|
SignExt8;
|
||||||
|
}
|
||||||
|
insn_exts! {
|
||||||
|
"extsb." 3, 4;
|
||||||
|
0x7c830775;
|
||||||
|
SignExt8;
|
||||||
|
}
|
||||||
|
insn_exts! {
|
||||||
|
"extsh" 3, 4;
|
||||||
|
0x7c830734;
|
||||||
|
SignExt16;
|
||||||
|
}
|
||||||
|
insn_exts! {
|
||||||
|
"extsh." 3, 4;
|
||||||
|
0x7c830735;
|
||||||
|
SignExt16;
|
||||||
|
}
|
||||||
|
insn_exts! {
|
||||||
|
"extsw" 3, 4;
|
||||||
|
0x7c8307b4;
|
||||||
|
SignExt32;
|
||||||
|
}
|
||||||
|
insn_exts! {
|
||||||
|
"extsw." 3, 4;
|
||||||
|
0x7c8307b5;
|
||||||
|
SignExt32;
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,512 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use crate::test_cases::{TestCase, insn_double, insn_triple};
|
||||||
|
use cpu::instruction::{
|
||||||
|
AddSubMOp, LoadStoreConversion, LoadStoreWidth, MOpDestReg, MOpRegNum, MoveRegMOp,
|
||||||
|
OutputIntegerMode, StoreMOp,
|
||||||
|
};
|
||||||
|
use fayalite::prelude::*;
|
||||||
|
|
||||||
|
/// covers instructions in PowerISA v3.1C Book I 3.3.3 Fixed-Point Store Instructions
|
||||||
|
pub fn test_cases_book_i_3_3_3_fixed_point_store(retval: &mut Vec<TestCase>) {
|
||||||
|
macro_rules! store_prefixed {
|
||||||
|
(
|
||||||
|
$mnemonic:literal $rs:literal, $disp:literal($ra:literal), $r:literal;
|
||||||
|
$prefix:literal, $suffix:literal;
|
||||||
|
$width:ident;
|
||||||
|
) => {
|
||||||
|
retval.push(insn_double(
|
||||||
|
concat!($mnemonic, " ", $rs, ", ", $disp, "(", $ra, "), ", $r),
|
||||||
|
$prefix,
|
||||||
|
Some($suffix),
|
||||||
|
[
|
||||||
|
AddSubMOp::add_sub_i(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]),
|
||||||
|
[
|
||||||
|
if $r != 0 || $ra == 0 {
|
||||||
|
MOpRegNum::const_zero().value
|
||||||
|
} else {
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($ra).value
|
||||||
|
},
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
],
|
||||||
|
($disp as i64).cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
$r != 0,
|
||||||
|
),
|
||||||
|
StoreMOp::store(
|
||||||
|
MOpDestReg::new_sim(&[], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_temp_reg().value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($rs).value,
|
||||||
|
],
|
||||||
|
LoadStoreWidth.$width(),
|
||||||
|
LoadStoreConversion.ZeroExt(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
macro_rules! store {
|
||||||
|
(
|
||||||
|
$mnemonic:literal $rs:literal, $disp:literal($ra:literal);
|
||||||
|
$encoding:literal;
|
||||||
|
$width:ident;
|
||||||
|
) => {
|
||||||
|
retval.push(insn_double(
|
||||||
|
concat!($mnemonic, " ", $rs, ", ", $disp, "(", $ra, ")"),
|
||||||
|
$encoding,
|
||||||
|
None,
|
||||||
|
[
|
||||||
|
AddSubMOp::add_sub_i(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]),
|
||||||
|
[
|
||||||
|
if $ra == 0 {
|
||||||
|
MOpRegNum::const_zero().value
|
||||||
|
} else {
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($ra).value
|
||||||
|
},
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
],
|
||||||
|
($disp as i64).cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
StoreMOp::store(
|
||||||
|
MOpDestReg::new_sim(&[], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_temp_reg().value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($rs).value,
|
||||||
|
],
|
||||||
|
LoadStoreWidth.$width(),
|
||||||
|
LoadStoreConversion.ZeroExt(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
macro_rules! store_update {
|
||||||
|
(
|
||||||
|
$mnemonic:literal $rs:literal, $disp:literal($ra:literal);
|
||||||
|
$encoding:literal;
|
||||||
|
$width:ident;
|
||||||
|
) => {
|
||||||
|
if $ra == $rs {
|
||||||
|
retval.push(insn_triple(
|
||||||
|
concat!($mnemonic, " ", $rs, ", ", $disp, "(", $ra, ")"),
|
||||||
|
$encoding,
|
||||||
|
None,
|
||||||
|
[
|
||||||
|
AddSubMOp::add_sub_i(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($ra).value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
],
|
||||||
|
($disp as i64).cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
StoreMOp::store(
|
||||||
|
MOpDestReg::new_sim(&[], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_temp_reg().value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($rs).value,
|
||||||
|
],
|
||||||
|
LoadStoreWidth.$width(),
|
||||||
|
LoadStoreConversion.ZeroExt(),
|
||||||
|
),
|
||||||
|
MoveRegMOp::move_reg(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($ra)], &[]),
|
||||||
|
[MOpRegNum::power_isa_temp_reg().value],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
retval.push(insn_double(
|
||||||
|
concat!($mnemonic, " ", $rs, ", ", $disp, "(", $ra, ")"),
|
||||||
|
$encoding,
|
||||||
|
None,
|
||||||
|
[
|
||||||
|
AddSubMOp::add_sub_i(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($ra)], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($ra).value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
],
|
||||||
|
($disp as i64).cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
StoreMOp::store(
|
||||||
|
MOpDestReg::new_sim(&[], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($ra).value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($rs).value,
|
||||||
|
],
|
||||||
|
LoadStoreWidth.$width(),
|
||||||
|
LoadStoreConversion.ZeroExt(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
macro_rules! store_indexed {
|
||||||
|
(
|
||||||
|
$mnemonic:literal $rs:literal, $ra:literal, $rb:literal;
|
||||||
|
$encoding:literal;
|
||||||
|
$width:ident;
|
||||||
|
) => {
|
||||||
|
retval.push(insn_double(
|
||||||
|
concat!($mnemonic, " ", $rs, ", ", $ra, ", ", $rb),
|
||||||
|
$encoding,
|
||||||
|
None,
|
||||||
|
[
|
||||||
|
AddSubMOp::add_sub_i(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]),
|
||||||
|
[
|
||||||
|
if $ra == 0 {
|
||||||
|
MOpRegNum::const_zero().value
|
||||||
|
} else {
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($ra).value
|
||||||
|
},
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($rb).value,
|
||||||
|
],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
StoreMOp::store(
|
||||||
|
MOpDestReg::new_sim(&[], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_temp_reg().value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($rs).value,
|
||||||
|
],
|
||||||
|
LoadStoreWidth.$width(),
|
||||||
|
LoadStoreConversion.ZeroExt(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
macro_rules! store_update_indexed {
|
||||||
|
(
|
||||||
|
$mnemonic:literal $rs:literal, $ra:literal, $rb:literal;
|
||||||
|
$encoding:literal;
|
||||||
|
$width:ident;
|
||||||
|
) => {
|
||||||
|
if $ra == $rs {
|
||||||
|
retval.push(insn_triple(
|
||||||
|
concat!($mnemonic, " ", $rs, ", ", $ra, ", ", $rb),
|
||||||
|
$encoding,
|
||||||
|
None,
|
||||||
|
[
|
||||||
|
AddSubMOp::add_sub_i(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TEMP_REG_NUM], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($ra).value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($rb).value,
|
||||||
|
],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
StoreMOp::store(
|
||||||
|
MOpDestReg::new_sim(&[], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_temp_reg().value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($rs).value,
|
||||||
|
],
|
||||||
|
LoadStoreWidth.$width(),
|
||||||
|
LoadStoreConversion.ZeroExt(),
|
||||||
|
),
|
||||||
|
MoveRegMOp::move_reg(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($ra)], &[]),
|
||||||
|
[MOpRegNum::power_isa_temp_reg().value],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
retval.push(insn_double(
|
||||||
|
concat!($mnemonic, " ", $rs, ", ", $ra, ", ", $rb),
|
||||||
|
$encoding,
|
||||||
|
None,
|
||||||
|
[
|
||||||
|
AddSubMOp::add_sub_i(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num($ra)], &[]),
|
||||||
|
[
|
||||||
|
if $ra == 0 {
|
||||||
|
MOpRegNum::const_zero().value
|
||||||
|
} else {
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($ra).value
|
||||||
|
},
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($rb).value,
|
||||||
|
],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
OutputIntegerMode.Full64(),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
StoreMOp::store(
|
||||||
|
MOpDestReg::new_sim(&[], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($ra).value,
|
||||||
|
MOpRegNum::power_isa_gpr_reg_imm($rs).value,
|
||||||
|
],
|
||||||
|
LoadStoreWidth.$width(),
|
||||||
|
LoadStoreConversion.ZeroExt(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
store! {
|
||||||
|
"stb" 3, 0x1234(4);
|
||||||
|
0x98641234;
|
||||||
|
Width8Bit;
|
||||||
|
}
|
||||||
|
store! {
|
||||||
|
"stb" 3, 0x1234(0);
|
||||||
|
0x98601234;
|
||||||
|
Width8Bit;
|
||||||
|
}
|
||||||
|
store_prefixed! {
|
||||||
|
"pstb" 3, 0x123456789(4), 0;
|
||||||
|
0x06012345, 0x98646789;
|
||||||
|
Width8Bit;
|
||||||
|
}
|
||||||
|
store_prefixed! {
|
||||||
|
"pstb" 3, 0x123456789(0), 0;
|
||||||
|
0x06012345, 0x98606789;
|
||||||
|
Width8Bit;
|
||||||
|
}
|
||||||
|
store_prefixed! {
|
||||||
|
"pstb" 3, 0x123456789(0), 1;
|
||||||
|
0x06112345, 0x98606789;
|
||||||
|
Width8Bit;
|
||||||
|
}
|
||||||
|
store_indexed! {
|
||||||
|
"stbx" 3, 4, 5;
|
||||||
|
0x7c6429ae;
|
||||||
|
Width8Bit;
|
||||||
|
}
|
||||||
|
store_indexed! {
|
||||||
|
"stbx" 3, 0, 5;
|
||||||
|
0x7c6029ae;
|
||||||
|
Width8Bit;
|
||||||
|
}
|
||||||
|
store_update! {
|
||||||
|
"stbu" 3, 0x1234(4);
|
||||||
|
0x9c641234;
|
||||||
|
Width8Bit;
|
||||||
|
}
|
||||||
|
store_update! {
|
||||||
|
"stbu" 3, 0x1234(3);
|
||||||
|
0x9c631234;
|
||||||
|
Width8Bit;
|
||||||
|
}
|
||||||
|
store_update_indexed! {
|
||||||
|
"stbux" 3, 4, 5;
|
||||||
|
0x7c6429ee;
|
||||||
|
Width8Bit;
|
||||||
|
}
|
||||||
|
store_update_indexed! {
|
||||||
|
"stbux" 3, 3, 5;
|
||||||
|
0x7c6329ee;
|
||||||
|
Width8Bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
store! {
|
||||||
|
"sth" 3, 0x1234(4);
|
||||||
|
0xb0641234;
|
||||||
|
Width16Bit;
|
||||||
|
}
|
||||||
|
store! {
|
||||||
|
"sth" 3, 0x1234(0);
|
||||||
|
0xb0601234;
|
||||||
|
Width16Bit;
|
||||||
|
}
|
||||||
|
store_prefixed! {
|
||||||
|
"psth" 3, 0x123456789(4), 0;
|
||||||
|
0x06012345, 0xb0646789;
|
||||||
|
Width16Bit;
|
||||||
|
}
|
||||||
|
store_prefixed! {
|
||||||
|
"psth" 3, 0x123456789(0), 0;
|
||||||
|
0x06012345, 0xb0606789;
|
||||||
|
Width16Bit;
|
||||||
|
}
|
||||||
|
store_prefixed! {
|
||||||
|
"psth" 3, 0x123456789(0), 1;
|
||||||
|
0x06112345, 0xb0606789;
|
||||||
|
Width16Bit;
|
||||||
|
}
|
||||||
|
store_indexed! {
|
||||||
|
"sthx" 3, 4, 5;
|
||||||
|
0x7c642b2e;
|
||||||
|
Width16Bit;
|
||||||
|
}
|
||||||
|
store_indexed! {
|
||||||
|
"sthx" 3, 0, 5;
|
||||||
|
0x7c602b2e;
|
||||||
|
Width16Bit;
|
||||||
|
}
|
||||||
|
store_update! {
|
||||||
|
"sthu" 3, 0x1234(4);
|
||||||
|
0xb4641234;
|
||||||
|
Width16Bit;
|
||||||
|
}
|
||||||
|
store_update! {
|
||||||
|
"sthu" 3, 0x1234(3);
|
||||||
|
0xb4631234;
|
||||||
|
Width16Bit;
|
||||||
|
}
|
||||||
|
store_update_indexed! {
|
||||||
|
"sthux" 3, 4, 5;
|
||||||
|
0x7c642b6e;
|
||||||
|
Width16Bit;
|
||||||
|
}
|
||||||
|
store_update_indexed! {
|
||||||
|
"sthux" 3, 3, 5;
|
||||||
|
0x7c632b6e;
|
||||||
|
Width16Bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
store! {
|
||||||
|
"stw" 3, 0x1234(4);
|
||||||
|
0x90641234;
|
||||||
|
Width32Bit;
|
||||||
|
}
|
||||||
|
store! {
|
||||||
|
"stw" 3, 0x1234(0);
|
||||||
|
0x90601234;
|
||||||
|
Width32Bit;
|
||||||
|
}
|
||||||
|
store_prefixed! {
|
||||||
|
"pstw" 3, 0x123456789(4), 0;
|
||||||
|
0x06012345, 0x90646789;
|
||||||
|
Width32Bit;
|
||||||
|
}
|
||||||
|
store_prefixed! {
|
||||||
|
"pstw" 3, 0x123456789(0), 0;
|
||||||
|
0x06012345, 0x90606789;
|
||||||
|
Width32Bit;
|
||||||
|
}
|
||||||
|
store_prefixed! {
|
||||||
|
"pstw" 3, 0x123456789(0), 1;
|
||||||
|
0x06112345, 0x90606789;
|
||||||
|
Width32Bit;
|
||||||
|
}
|
||||||
|
store_indexed! {
|
||||||
|
"stwx" 3, 4, 5;
|
||||||
|
0x7c64292e;
|
||||||
|
Width32Bit;
|
||||||
|
}
|
||||||
|
store_indexed! {
|
||||||
|
"stwx" 3, 0, 5;
|
||||||
|
0x7c60292e;
|
||||||
|
Width32Bit;
|
||||||
|
}
|
||||||
|
store_update! {
|
||||||
|
"stwu" 3, 0x1234(4);
|
||||||
|
0x94641234;
|
||||||
|
Width32Bit;
|
||||||
|
}
|
||||||
|
store_update! {
|
||||||
|
"stwu" 3, 0x1234(3);
|
||||||
|
0x94631234;
|
||||||
|
Width32Bit;
|
||||||
|
}
|
||||||
|
store_update_indexed! {
|
||||||
|
"stwux" 3, 4, 5;
|
||||||
|
0x7c64296e;
|
||||||
|
Width32Bit;
|
||||||
|
}
|
||||||
|
store_update_indexed! {
|
||||||
|
"stwux" 3, 3, 5;
|
||||||
|
0x7c63296e;
|
||||||
|
Width32Bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
store! {
|
||||||
|
"std" 3, 0x1234(4);
|
||||||
|
0xf8641234;
|
||||||
|
Width64Bit;
|
||||||
|
}
|
||||||
|
store! {
|
||||||
|
"std" 3, 0x1234(0);
|
||||||
|
0xf8601234;
|
||||||
|
Width64Bit;
|
||||||
|
}
|
||||||
|
store_prefixed! {
|
||||||
|
"pstd" 3, 0x123456789(4), 0;
|
||||||
|
0x04012345, 0xf4646789;
|
||||||
|
Width64Bit;
|
||||||
|
}
|
||||||
|
store_prefixed! {
|
||||||
|
"pstd" 3, 0x123456789(0), 0;
|
||||||
|
0x04012345, 0xf4606789;
|
||||||
|
Width64Bit;
|
||||||
|
}
|
||||||
|
store_prefixed! {
|
||||||
|
"pstd" 3, 0x123456789(0), 1;
|
||||||
|
0x04112345, 0xf4606789;
|
||||||
|
Width64Bit;
|
||||||
|
}
|
||||||
|
store_indexed! {
|
||||||
|
"stdx" 3, 4, 5;
|
||||||
|
0x7c64292a;
|
||||||
|
Width64Bit;
|
||||||
|
}
|
||||||
|
store_indexed! {
|
||||||
|
"stdx" 3, 0, 5;
|
||||||
|
0x7c60292a;
|
||||||
|
Width64Bit;
|
||||||
|
}
|
||||||
|
store_update! {
|
||||||
|
"stdu" 3, 0x1234(4);
|
||||||
|
0xf8641235;
|
||||||
|
Width64Bit;
|
||||||
|
}
|
||||||
|
store_update! {
|
||||||
|
"stdu" 3, 0x1234(3);
|
||||||
|
0xf8631235;
|
||||||
|
Width64Bit;
|
||||||
|
}
|
||||||
|
store_update_indexed! {
|
||||||
|
"stdux" 3, 4, 5;
|
||||||
|
0x7c64296a;
|
||||||
|
Width64Bit;
|
||||||
|
}
|
||||||
|
store_update_indexed! {
|
||||||
|
"stdux" 3, 3, 5;
|
||||||
|
0x7c63296a;
|
||||||
|
Width64Bit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,149 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use crate::test_cases::{TestCase, insn_single};
|
||||||
|
use cpu::instruction::{
|
||||||
|
LogicalFlagsMOp, LogicalFlagsMOpImm, Lut4, MOpDestReg, MOpRegNum, MoveRegMOp, ReadSpecialMOp,
|
||||||
|
ReadSpecialMOpImm,
|
||||||
|
};
|
||||||
|
use fayalite::prelude::*;
|
||||||
|
|
||||||
|
/// covers instructions in PowerISA v3.1C Book I 3.3.19 Move To/From System Register Instructions
|
||||||
|
pub fn test_cases_book_i_3_3_19_move_to_from_system_register(retval: &mut Vec<TestCase>) {
|
||||||
|
// mfspr/mtspr are covered by test_cases_book_iii_5_4_4_move_to_from_system_register
|
||||||
|
#[hdl]
|
||||||
|
fn mcrxrx_imm() -> SimValue<LogicalFlagsMOpImm> {
|
||||||
|
#[hdl(sim)]
|
||||||
|
LogicalFlagsMOpImm {
|
||||||
|
// if the order of flags in PRegFlags changes, this will need to be updated
|
||||||
|
src0_start: 4usize.cast_to(LogicalFlagsMOpImm.src0_start),
|
||||||
|
src1_start: 4usize.cast_to(LogicalFlagsMOpImm.src1_start),
|
||||||
|
src2_start: 4usize.cast_to(LogicalFlagsMOpImm.src2_start),
|
||||||
|
dest_start: 0usize.cast_to(LogicalFlagsMOpImm.dest_start),
|
||||||
|
dest_count: 6usize.cast_to(LogicalFlagsMOpImm.dest_count),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
retval.push(insn_single(
|
||||||
|
"mcrxrx 3",
|
||||||
|
0x7d800480,
|
||||||
|
None,
|
||||||
|
LogicalFlagsMOp::logical_flags(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_cr_reg_num(3)], &[]),
|
||||||
|
[
|
||||||
|
MOpRegNum::power_isa_xer_ca_ca32_reg().value,
|
||||||
|
MOpRegNum::const_zero().value,
|
||||||
|
MOpRegNum::power_isa_xer_so_ov_ov32_reg().value,
|
||||||
|
],
|
||||||
|
mcrxrx_imm(),
|
||||||
|
Lut4::from_fn(|a, b| a | b),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// covers instructions in PowerISA v3.1C Book III 5.4.4 Move To/From System Register Instructions
|
||||||
|
pub fn test_cases_book_iii_5_4_4_move_to_from_system_register(retval: &mut Vec<TestCase>) {
|
||||||
|
retval.push(insn_single(
|
||||||
|
"mflr 3",
|
||||||
|
0x7c6802a6,
|
||||||
|
None,
|
||||||
|
MoveRegMOp::move_reg(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||||
|
[MOpRegNum::power_isa_lr_reg().value],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"mtlr 3",
|
||||||
|
0x7c6803a6,
|
||||||
|
None,
|
||||||
|
MoveRegMOp::move_reg(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_LR_REG_NUM], &[]),
|
||||||
|
[MOpRegNum::power_isa_gpr_reg_imm(3).value],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"mfctr 3",
|
||||||
|
0x7c6902a6,
|
||||||
|
None,
|
||||||
|
MoveRegMOp::move_reg(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||||
|
[MOpRegNum::power_isa_ctr_reg().value],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"mtctr 3",
|
||||||
|
0x7c6903a6,
|
||||||
|
None,
|
||||||
|
MoveRegMOp::move_reg(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_CTR_REG_NUM], &[]),
|
||||||
|
[MOpRegNum::power_isa_gpr_reg_imm(3).value],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"mfspr 3, 815 # mftar 3",
|
||||||
|
0x7c6fcaa6,
|
||||||
|
None,
|
||||||
|
MoveRegMOp::move_reg(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||||
|
[MOpRegNum::power_isa_tar_reg().value],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
retval.push(insn_single(
|
||||||
|
"mtspr 815, 3 # mttar 3",
|
||||||
|
0x7c6fcba6,
|
||||||
|
None,
|
||||||
|
MoveRegMOp::move_reg(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_TAR_REG_NUM], &[]),
|
||||||
|
[MOpRegNum::power_isa_gpr_reg_imm(3).value],
|
||||||
|
0.cast_to_static::<SInt<_>>(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
// make sure we generate mfspr and not the phased-out mftb
|
||||||
|
retval.push(insn_single(
|
||||||
|
"mfspr 3, 268 # mftb 3",
|
||||||
|
0x7c6c42a6,
|
||||||
|
None,
|
||||||
|
ReadSpecialMOp::read_special(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||||
|
[MOpRegNum::const_zero().value; 0],
|
||||||
|
ReadSpecialMOpImm.PowerIsaTimeBase(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
// make sure we generate mfspr and not the phased-out mftb
|
||||||
|
retval.push(insn_single(
|
||||||
|
"mfspr 3, 269 # mftbu 3",
|
||||||
|
0x7c6d42a6,
|
||||||
|
None,
|
||||||
|
ReadSpecialMOp::read_special(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||||
|
[MOpRegNum::const_zero().value; 0],
|
||||||
|
ReadSpecialMOpImm.PowerIsaTimeBaseU(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
// phased-out mftb -- not actually generated by the assembler so we have to use .long
|
||||||
|
retval.push(insn_single(
|
||||||
|
".long 0x7c6c42e6 # mftb 3, 268",
|
||||||
|
0x7c6c42e6,
|
||||||
|
None,
|
||||||
|
ReadSpecialMOp::read_special(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||||
|
[MOpRegNum::const_zero().value; 0],
|
||||||
|
ReadSpecialMOpImm.PowerIsaTimeBase(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
// phased-out mftb -- not actually generated by the assembler so we have to use .long
|
||||||
|
retval.push(insn_single(
|
||||||
|
".long 0x7c6d42e6 # mftb 3, 269",
|
||||||
|
0x7c6d42e6,
|
||||||
|
None,
|
||||||
|
ReadSpecialMOp::read_special(
|
||||||
|
MOpDestReg::new_sim(&[MOpRegNum::power_isa_gpr_reg_num(3)], &[]),
|
||||||
|
[MOpRegNum::const_zero().value; 0],
|
||||||
|
ReadSpecialMOpImm.PowerIsaTimeBaseU(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use crate::test_cases::{TestCase, insn_empty};
|
||||||
|
|
||||||
|
/// covers instructions in PowerISA v3.1C Book I 3.3.20 Prefixed No-Operation Instruction
|
||||||
|
pub fn test_cases_book_i_3_3_20_prefixed_no_operation(retval: &mut Vec<TestCase>) {
|
||||||
|
// ensure pnop decodes to zero instructions
|
||||||
|
retval.push(insn_empty(
|
||||||
|
// LLVM doesn't support the pnop instruction:
|
||||||
|
// https://github.com/llvm/llvm-project/issues/176831
|
||||||
|
".long 0x07000000, 0 # pnop",
|
||||||
|
0x07000000,
|
||||||
|
Some(0),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
@ -31,6 +31,7 @@ function check_file()
|
||||||
POUND_HEADER=('^"# SPDX-License-Identifier: LGPL-3.0-or-later"$' '^"# See Notices.txt for copyright information"$')
|
POUND_HEADER=('^"# SPDX-License-Identifier: LGPL-3.0-or-later"$' '^"# See Notices.txt for copyright information"$')
|
||||||
SLASH_HEADER=('^"// SPDX-License-Identifier: LGPL-3.0-or-later"$' '^"// See Notices.txt for copyright information"$')
|
SLASH_HEADER=('^"// SPDX-License-Identifier: LGPL-3.0-or-later"$' '^"// See Notices.txt for copyright information"$')
|
||||||
MD_HEADER=('^"<!--"$' '^"SPDX-License-Identifier: LGPL-3.0-or-later"$' '^"See Notices.txt for copyright information"$')
|
MD_HEADER=('^"<!--"$' '^"SPDX-License-Identifier: LGPL-3.0-or-later"$' '^"See Notices.txt for copyright information"$')
|
||||||
|
MERMAID_HEADER=('^"%% SPDX-License-Identifier: LGPL-3.0-or-later"$' '^"%% See Notices.txt for copyright information"$')
|
||||||
|
|
||||||
function main()
|
function main()
|
||||||
{
|
{
|
||||||
|
|
@ -45,12 +46,15 @@ function main()
|
||||||
*/LICENSE.md|*/Notices.txt)
|
*/LICENSE.md|*/Notices.txt)
|
||||||
# copyright file
|
# copyright file
|
||||||
;;
|
;;
|
||||||
/crates/cpu/tests/expected/*.vcd|/crates/cpu/tests/expected/*.txt)
|
/crates/cpu/tests*/expected/*.vcd|/crates/cpu/tests*/expected/*.txt)
|
||||||
# file that can't contain copyright header
|
# file that can't contain copyright header
|
||||||
;;
|
;;
|
||||||
/.forgejo/workflows/*.yml|*/.gitignore|*.toml)
|
/.forgejo/workflows/*.yml|*/.gitignore|*/.gitattributes|*.toml)
|
||||||
check_file "$file" "${POUND_HEADER[@]}"
|
check_file "$file" "${POUND_HEADER[@]}"
|
||||||
;;
|
;;
|
||||||
|
*.mermaid)
|
||||||
|
check_file "$file" "${MERMAID_HEADER[@]}"
|
||||||
|
;;
|
||||||
*.md)
|
*.md)
|
||||||
check_file "$file" "${MD_HEADER[@]}"
|
check_file "$file" "${MD_HEADER[@]}"
|
||||||
;;
|
;;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue