Compare commits
6 commits
master
...
main_memor
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8433f4f150 | ||
|
|
672a29e76d | ||
|
|
35ea85d074 | ||
|
|
1ead550d13 | ||
|
|
540a91878c | ||
|
|
9f68cbb953 |
50 changed files with 37132 additions and 551424 deletions
77
.forgejo/workflows/deps.yml
Normal file
77
.forgejo/workflows/deps.yml
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
# See Notices.txt for copyright information
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
outputs:
|
||||||
|
cache-primary-key:
|
||||||
|
value: ${{ jobs.deps.outputs.cache-primary-key }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deps:
|
||||||
|
runs-on: debian-12
|
||||||
|
outputs:
|
||||||
|
cache-primary-key: ${{ steps.restore-deps.outputs.cache-primary-key }}
|
||||||
|
steps:
|
||||||
|
- uses: https://git.libre-chip.org/mirrors/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- uses: https://git.libre-chip.org/mirrors/cache/restore@v3
|
||||||
|
id: restore-deps
|
||||||
|
with:
|
||||||
|
path: deps
|
||||||
|
key: ${{ github.repository }}-deps-${{ runner.os }}-${{ hashFiles('.forgejo/workflows/deps.yml') }}
|
||||||
|
lookup-only: true
|
||||||
|
- name: Install Apt packages
|
||||||
|
if: steps.restore-deps.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
apt-get update -qq
|
||||||
|
apt-get install -qq \
|
||||||
|
bison \
|
||||||
|
build-essential \
|
||||||
|
ccache \
|
||||||
|
clang \
|
||||||
|
cvc5 \
|
||||||
|
flex \
|
||||||
|
gawk \
|
||||||
|
g++ \
|
||||||
|
git \
|
||||||
|
libboost-filesystem-dev \
|
||||||
|
libboost-python-dev \
|
||||||
|
libboost-system-dev \
|
||||||
|
libffi-dev \
|
||||||
|
libreadline-dev \
|
||||||
|
lld \
|
||||||
|
pkg-config \
|
||||||
|
python3 \
|
||||||
|
python3-click \
|
||||||
|
tcl-dev \
|
||||||
|
zlib1g-dev
|
||||||
|
- name: Install Firtool
|
||||||
|
if: steps.restore-deps.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
mkdir -p deps
|
||||||
|
wget -O deps/firrtl.tar.gz https://github.com/llvm/circt/releases/download/firtool-1.86.0/firrtl-bin-linux-x64.tar.gz
|
||||||
|
sha256sum -c - <<<'bf6f4ab18ae76f135c944efbd81e25391c31c1bd0617c58ab0592640abefee14 deps/firrtl.tar.gz'
|
||||||
|
tar -C deps -xvaf deps/firrtl.tar.gz
|
||||||
|
rm -rf deps/firtool
|
||||||
|
mv deps/firtool-1.86.0 deps/firtool
|
||||||
|
- name: Get SymbiYosys
|
||||||
|
if: steps.restore-deps.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
git clone --depth=1 --branch=yosys-0.45 https://git.libre-chip.org/mirrors/sby deps/sby
|
||||||
|
- name: Build Z3
|
||||||
|
if: steps.restore-deps.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
git clone --depth=1 --recursive --branch=z3-4.13.3 https://git.libre-chip.org/mirrors/z3 deps/z3
|
||||||
|
(cd deps/z3; PYTHON=python3 ./configure --prefix=/usr/local)
|
||||||
|
make -C deps/z3/build -j"$(nproc)"
|
||||||
|
- name: Build Yosys
|
||||||
|
if: steps.restore-deps.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
git clone --depth=1 --recursive --branch=0.45 https://git.libre-chip.org/mirrors/yosys deps/yosys
|
||||||
|
make -C deps/yosys -j"$(nproc)"
|
||||||
|
- uses: https://git.libre-chip.org/mirrors/cache/save@v3
|
||||||
|
if: steps.restore-deps.outputs.cache-hit != 'true'
|
||||||
|
with:
|
||||||
|
path: deps
|
||||||
|
key: ${{ steps.restore-deps.outputs.cache-primary-key }}
|
||||||
|
|
@ -3,18 +3,57 @@
|
||||||
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
|
||||||
container:
|
needs: deps
|
||||||
image: git.libre-chip.org/libre-chip/fayalite-deps:latest
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: https://git.libre-chip.org/mirrors/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
3
.gitattributes
vendored
|
|
@ -1,3 +0,0 @@
|
||||||
# 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,4 +1,3 @@
|
||||||
# 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
|
|
||||||
|
|
|
||||||
610
Cargo.lock
generated
610
Cargo.lock
generated
|
|
@ -1,20 +1,17 @@
|
||||||
# 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 = 4
|
version = 3
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "adler2"
|
name = "ahash"
|
||||||
version = "2.0.1"
|
version = "0.8.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aho-corasick"
|
|
||||||
version = "1.1.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"cfg-if",
|
||||||
|
"once_cell",
|
||||||
|
"version_check",
|
||||||
|
"zerocopy",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -96,36 +93,6 @@ 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"
|
||||||
|
|
@ -168,48 +135,21 @@ dependencies = [
|
||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bytes"
|
|
||||||
version = "1.11.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.51"
|
version = "1.1.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203"
|
checksum = "2e80e3b6a3ab07840e1cae9b0666a63970dc28e8ed5ffbcdacbfc760c281bfc1"
|
||||||
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"
|
||||||
|
|
@ -232,15 +172,6 @@ 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"
|
||||||
|
|
@ -275,17 +206,7 @@ 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]]
|
||||||
|
|
@ -297,15 +218,6 @@ 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"
|
||||||
|
|
@ -361,12 +273,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "errno"
|
name = "errno"
|
||||||
version = "0.3.14"
|
version = "0.3.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -388,23 +300,20 @@ 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#c632e5d570d4763e8e18d764e95b7a9e515ebf99"
|
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#bd75fdfefd642f6dd2210cfb003fa63f9dce114e"
|
||||||
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 0.15.5",
|
"hashbrown",
|
||||||
"jobslot",
|
"jobslot",
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"once_cell",
|
"os_pipe",
|
||||||
"ordered-float",
|
|
||||||
"petgraph",
|
"petgraph",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
|
@ -416,7 +325,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#c632e5d570d4763e8e18d764e95b7a9e515ebf99"
|
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#bd75fdfefd642f6dd2210cfb003fa63f9dce114e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fayalite-proc-macros-impl",
|
"fayalite-proc-macros-impl",
|
||||||
]
|
]
|
||||||
|
|
@ -424,9 +333,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#c632e5d570d4763e8e18d764e95b7a9e515ebf99"
|
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#bd75fdfefd642f6dd2210cfb003fa63f9dce114e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base16ct 0.2.0",
|
"base16ct",
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"prettyplease",
|
"prettyplease",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
|
@ -439,7 +348,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#c632e5d570d4763e8e18d764e95b7a9e515ebf99"
|
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#bd75fdfefd642f6dd2210cfb003fa63f9dce114e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"prettyplease",
|
"prettyplease",
|
||||||
|
|
@ -451,34 +360,12 @@ 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"
|
||||||
|
|
@ -497,62 +384,31 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.16"
|
version = "0.2.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
|
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "getrandom"
|
|
||||||
version = "0.3.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"r-efi",
|
|
||||||
"wasip2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "glob"
|
|
||||||
version = "0.3.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.15.5"
|
version = "0.14.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"ahash",
|
||||||
"allocator-api2",
|
"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"
|
||||||
|
|
@ -562,22 +418,6 @@ 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"
|
||||||
|
|
@ -586,14 +426,13 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.13.0"
|
version = "2.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
|
checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown 0.16.1",
|
"hashbrown",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_core",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -602,15 +441,6 @@ 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"
|
||||||
|
|
@ -619,39 +449,23 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jobslot"
|
name = "jobslot"
|
||||||
version = "0.2.23"
|
version = "0.2.19"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "58715c67c327da7f1558708348d68c207fd54900c4ae0529e29305d04d795b8c"
|
checksum = "fe10868679d7a24c2c67d862d0e64a342ce9aef7cdde9ce8019bd35d353d458d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"derive_destructure2",
|
"derive_destructure2",
|
||||||
"getrandom 0.3.4",
|
"getrandom",
|
||||||
"libc",
|
"libc",
|
||||||
"scopeguard",
|
"scopeguard",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.180"
|
version = "0.2.159"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
|
checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
|
||||||
|
|
||||||
[[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"
|
||||||
|
|
@ -659,57 +473,12 @@ 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"
|
||||||
|
|
@ -740,56 +509,29 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.21.3"
|
version = "1.20.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ordered-float"
|
name = "os_pipe"
|
||||||
version = "5.1.0"
|
version = "1.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7f4779c6901a562440c3786d08192c6fbda7c1c2060edd10006b05ee35d10f2d"
|
checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-traits",
|
"libc",
|
||||||
"rand",
|
"windows-sys 0.59.0",
|
||||||
"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.8.3"
|
version = "0.6.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/programmerjake/petgraph.git?rev=258ea8071209a924b73fe96f9f87a3b7b45cbc9f#258ea8071209a924b73fe96f9f87a3b7b45cbc9f"
|
||||||
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"
|
||||||
|
|
@ -809,15 +551,6 @@ 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"
|
||||||
|
|
@ -827,95 +560,12 @@ 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"
|
||||||
|
|
@ -929,41 +579,6 @@ 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"
|
||||||
|
|
@ -978,28 +593,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.228"
|
version = "1.0.210"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
|
||||||
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.228"
|
version = "1.0.210"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
@ -1021,9 +626,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha2"
|
name = "sha2"
|
||||||
version = "0.10.9"
|
version = "0.10.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"cpufeatures",
|
"cpufeatures",
|
||||||
|
|
@ -1036,30 +641,12 @@ 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"
|
||||||
|
|
@ -1122,47 +709,6 @@ 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"
|
||||||
|
|
@ -1183,27 +729,9 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.11.1+wasi-snapshot-preview1"
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
[[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"
|
||||||
|
|
@ -1213,17 +741,10 @@ 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"
|
||||||
|
|
@ -1242,15 +763,6 @@ 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"
|
||||||
|
|
@ -1321,12 +833,6 @@ 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"
|
||||||
|
|
@ -1338,26 +844,20 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.8.27"
|
version = "0.7.35"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c"
|
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zerocopy-derive",
|
"zerocopy-derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy-derive"
|
name = "zerocopy-derive"
|
||||||
version = "0.8.27"
|
version = "0.7.35"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831"
|
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||||
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,19 +11,10 @@ edition = "2024"
|
||||||
repository = ""
|
repository = ""
|
||||||
keywords = []
|
keywords = []
|
||||||
categories = []
|
categories = []
|
||||||
rust-version = "1.93.0"
|
rust-version = "1.89.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
15
README.md
|
|
@ -1,15 +0,0 @@
|
||||||
<!--
|
|
||||||
SPDX-License-Identifier: LGPL-3.0-or-later
|
|
||||||
See Notices.txt for copyright information
|
|
||||||
-->
|
|
||||||
# Libre-Chip's CPU
|
|
||||||
|
|
||||||
<https://libre-chip.org/first_arch/index.html>
|
|
||||||
|
|
||||||
# Funding
|
|
||||||
|
|
||||||
## NLnet Grants
|
|
||||||
|
|
||||||
* [Libre-Chip CPU with proof of No Spectre bugs](https://nlnet.nl/project/Libre-Chip-proof/) 2024-12-324 [(progress)](https://git.libre-chip.org/libre-chip/grant-tracking/src/branch/master/nlnet-2024-12-324/progress.md)
|
|
||||||
|
|
||||||
This project was funded through the [NGI0 Commons Fund](https://nlnet.nl/commonsfund), a fund established by [NLnet](https://nlnet.nl/) with financial support from the European Commission's [Next Generation Internet](https://ngi.eu) programme, under the aegis of [DG Communications Networks, Content and Technology](https://commission.europa.eu/about-european-commission/departments-and-executive-agencies/communications-networks-content-and-technology_en) under grant agreement № [101135429](https://cordis.europa.eu/project/id/101135429). Additional funding is made available by the [Swiss State Secretariat for Education, Research and Innovation](https://www.sbfi.admin.ch/sbfi/en/home.html) (SERI).
|
|
||||||
|
|
@ -16,20 +16,3 @@ 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 +0,0 @@
|
||||||
../../README.md
|
|
||||||
|
|
@ -1,96 +0,0 @@
|
||||||
// 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,10 +8,9 @@ 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, Serialize, Deserialize)]
|
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct UnitConfig {
|
pub struct UnitConfig {
|
||||||
pub kind: UnitKind,
|
pub kind: UnitKind,
|
||||||
|
|
@ -28,18 +27,12 @@ impl UnitConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
||||||
#[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 log2_l1_i_cache_line_count: u8,
|
|
||||||
pub l1_i_cache_max_misses_in_flight: 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,
|
||||||
|
|
@ -53,27 +46,6 @@ 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_LOG2_L1_I_CACHE_LINE_COUNT: u8 = 8;
|
|
||||||
pub const DEFAULT_L1_I_CACHE_MAX_MISSES_IN_FLIGHT: NonZeroUsize = {
|
|
||||||
let Some(v) = NonZeroUsize::new(2) 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!();
|
||||||
|
|
@ -85,12 +57,6 @@ 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,
|
|
||||||
log2_l1_i_cache_line_count: Self::DEFAULT_LOG2_L1_I_CACHE_LINE_COUNT,
|
|
||||||
l1_i_cache_max_misses_in_flight: Self::DEFAULT_L1_I_CACHE_MAX_MISSES_IN_FLIGHT,
|
|
||||||
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,
|
||||||
}
|
}
|
||||||
|
|
@ -150,100 +116,4 @@ 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 log2_fetches_per_cache_line(&self) -> usize {
|
|
||||||
self.log2_cache_line_size_in_bytes
|
|
||||||
.checked_sub(self.log2_fetch_width_in_bytes)
|
|
||||||
.expect("cache line size in bytes must not be smaller than fetch width in bytes")
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
pub fn fetches_per_cache_line(&self) -> usize {
|
|
||||||
self.log2_fetches_per_cache_line()
|
|
||||||
.try_into()
|
|
||||||
.ok()
|
|
||||||
.and_then(|v| 1usize.checked_shl(v))
|
|
||||||
.expect("log2_fetches_per_cache_line is too big")
|
|
||||||
}
|
|
||||||
pub fn l1_i_cache_line_count(&self) -> usize {
|
|
||||||
1usize
|
|
||||||
.checked_shl(self.log2_l1_i_cache_line_count.into())
|
|
||||||
.expect("log2_l1_i_cache_line_count is too big")
|
|
||||||
}
|
|
||||||
pub fn log2_l1_i_cache_size_in_bytes(&self) -> usize {
|
|
||||||
self.log2_l1_i_cache_line_count as usize + self.log2_cache_line_size_in_bytes as usize
|
|
||||||
}
|
|
||||||
pub fn l1_i_cache_size_in_bytes(&self) -> usize {
|
|
||||||
1usize
|
|
||||||
.checked_shl(self.log2_l1_i_cache_size_in_bytes() as _)
|
|
||||||
.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_fetches_per_cache_line()))]
|
|
||||||
pub type CpuConfigLog2FetchesPerCacheLine<C: PhantomConstGet<CpuConfig>> = DynSize;
|
|
||||||
|
|
||||||
#[hdl(get(|c| c.fetches_per_cache_line()))]
|
|
||||||
pub type CpuConfigFetchesPerCacheLine<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.log2_l1_i_cache_line_count.into()))]
|
|
||||||
pub type CpuConfigLog2L1ICacheLineCount<C: PhantomConstGet<CpuConfig>> = DynSize;
|
|
||||||
|
|
||||||
#[hdl(get(|c| c.l1_i_cache_line_count()))]
|
|
||||||
pub type CpuConfigL1ICacheLineCount<C: PhantomConstGet<CpuConfig>> = DynSize;
|
|
||||||
|
|
||||||
#[hdl(get(|c| c.log2_l1_i_cache_size_in_bytes()))]
|
|
||||||
pub type CpuConfigLog2L1ICacheSizeInBytes<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.l1_i_cache_max_misses_in_flight.get()))]
|
|
||||||
pub type CpuConfigL1ICacheMaxMissesInFlight<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> {}
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
||||||
// See Notices.txt for copyright information
|
|
||||||
|
|
||||||
pub mod simple_power_isa;
|
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -27,432 +27,26 @@ 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;
|
||||||
#[hdl]
|
/// XER bits are stored in [`PRegValue.flags`], bits that don't exist in [`PRegValue.flags`] are stored in [`PRegValue.int_fp`]
|
||||||
pub fn power_isa_tar_reg() -> Expr<Self> {
|
///
|
||||||
#[hdl]
|
/// [`PRegValue.flags`]: struct@crate::register::PRegValue
|
||||||
Self {
|
/// [`PRegValue.int_fp`]: struct@crate::register::PRegValue
|
||||||
value: Self::POWER_ISA_TAR_REG_NUM.cast_to_static::<UInt<_>>(),
|
pub const POWER_ISA_XER_REG_NUM: u32 = 4;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// SO, OV, and OV32 XER bits -- in [`PRegValue.flags`]
|
pub const POWER_ISA_CR_REG_NUMS: Range<u32> = 8..16;
|
||||||
///
|
|
||||||
/// [`PRegValue.flags`]: struct@crate::register::PRegValue
|
|
||||||
pub const POWER_ISA_XER_SO_OV_OV32_REG_NUM: u32 =
|
|
||||||
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;
|
|
||||||
|
|
||||||
/// 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 {
|
||||||
if index == 0 {
|
range_u32_nth_or_panic(&Self::POWER_ISA_CR_REG_NUMS, index)
|
||||||
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,12 +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
|
||||||
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;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
//TODO read other modules
|
||||||
|
pub mod main_memory;
|
||||||
|
|
|
||||||
60
crates/cpu/src/main_memory.rs
Normal file
60
crates/cpu/src/main_memory.rs
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
// first copied code block -- changes needed
|
||||||
|
use crate::{
|
||||||
|
config::CpuConfig,
|
||||||
|
instruction::{
|
||||||
|
AluBranchMOp, LoadStoreMOp, MOp, MOpDestReg, MOpInto, MOpRegNum, MOpTrait, RenamedMOp,
|
||||||
|
UnitOutRegNum, mop_enum,
|
||||||
|
},
|
||||||
|
register::{FlagsMode, PRegValue},
|
||||||
|
unit::unit_base::UnitToRegAlloc,
|
||||||
|
};
|
||||||
|
use fayalite::{
|
||||||
|
bundle::{Bundle, BundleType},
|
||||||
|
intern::{Intern, Interned},
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
|
|
||||||
|
//input address <32> bit ?
|
||||||
|
//output data word <8> bit for first test (read only)
|
||||||
|
|
||||||
|
#[hdl_module]
|
||||||
|
/// add a comment here
|
||||||
|
pub fn main_memory(config: &CpuConfig) {
|
||||||
|
#[hdl]
|
||||||
|
let addr: UInt<64> = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let read_data: UInt<64> = m.output();
|
||||||
|
#[hdl]
|
||||||
|
let en: Bool = m.input();
|
||||||
|
|
||||||
|
//WIP: add write support
|
||||||
|
#[hdl]
|
||||||
|
let write_en: Bool = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let write_data: UInt<64> = m.input();
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
let cd: ClockDomain = m.input();
|
||||||
|
|
||||||
|
#[hdl] // FIXME: do not hardcode memory size and content --
|
||||||
|
//let mut my_memory = memory_with_init([0x12_hdl_u8, 0x34_hdl_u8, 0x56_hdl_u8, 0x78_hdl_u8]);
|
||||||
|
let mut my_memory = memory();
|
||||||
|
my_memory.depth(256); //TODO make configurable
|
||||||
|
|
||||||
|
let read_port = my_memory.new_read_port();
|
||||||
|
connect_any(read_port.addr, addr);
|
||||||
|
connect_any(read_port.en, addr.cmp_lt(256u64) & en); // and not write_en
|
||||||
|
connect(read_port.clk, cd.clk);
|
||||||
|
connect(read_data, read_port.data);
|
||||||
|
|
||||||
|
let write_port = my_memory.new_write_port();
|
||||||
|
connect_any(write_port.addr, addr);
|
||||||
|
connect_any(write_port.en, addr.cmp_lt(256u64) & en & write_en);
|
||||||
|
connect_any(write_port.data, write_data);
|
||||||
|
connect(write_port.clk, cd.clk);
|
||||||
|
|
||||||
|
connect_any(write_port.mask, true); //can only write 8 bits at a time
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,24 +0,0 @@
|
||||||
%% 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
|
|
||||||
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,
|
||||||
rob.ty().renamed_insns_in.element().data.HdlNone(),
|
Expr::ty(rob).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],
|
||||||
renamed_mops.ty().element().HdlNone(),
|
Expr::ty(renamed_mops).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(),
|
||||||
write_port_.ty(),
|
Expr::ty(write_port_),
|
||||||
);
|
);
|
||||||
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: write_port.data.ty().uninit(),
|
data: Expr::ty(write_port.data).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, renamed_mop.ty().HdlNone());
|
connect(renamed_mop, Expr::ty(renamed_mop).HdlNone());
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
connect(
|
connect(
|
||||||
|
|
@ -429,7 +429,7 @@ pub fn reg_alloc(config: &CpuConfig) {
|
||||||
);
|
);
|
||||||
connect(
|
connect(
|
||||||
selected_unit_index_leaf,
|
selected_unit_index_leaf,
|
||||||
selected_unit_index_leaf.ty().HdlNone(),
|
Expr::ty(selected_unit_index_leaf).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(),
|
||||||
l.ty(),
|
Expr::ty(l),
|
||||||
);
|
);
|
||||||
*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,
|
||||||
unit_to_reg_alloc.input.ty().data.HdlNone(),
|
Expr::ty(unit_to_reg_alloc.input).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(unit_to_reg_alloc.input.ty().data.HdlSome.uninit()),
|
HdlSome(Expr::ty(unit_to_reg_alloc.input).data.HdlSome.uninit()),
|
||||||
);
|
);
|
||||||
// FIXME: add hdl_assert(cd.clk, false.to_expr(), "");
|
// FIXME: add hdl_assert(cd.clk, false.to_expr(), "");
|
||||||
}
|
}
|
||||||
|
|
@ -578,8 +578,7 @@ 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],
|
||||||
unit_forwarding_info
|
Expr::ty(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[l.alloc_nums.ty().element().width() + 1]][alloc_at_once.get()],
|
Array[UInt[Expr::ty(l.alloc_nums).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,7 +120,10 @@ pub fn unit_free_regs_tracker(
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use fayalite::{firrtl::ExportOptions, module::transform::simplify_enums::SimplifyEnumsKind};
|
use fayalite::{
|
||||||
|
cli::FormalMode, firrtl::ExportOptions,
|
||||||
|
module::transform::simplify_enums::SimplifyEnumsKind, testing::assert_formal,
|
||||||
|
};
|
||||||
use std::num::NonZero;
|
use std::num::NonZero;
|
||||||
|
|
||||||
fn test_unit_free_regs_tracker(
|
fn test_unit_free_regs_tracker(
|
||||||
|
|
@ -195,7 +198,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let free_before_alloc_array = wire(Array[free_reg.ty()][alloc_at_once.get() + 1]);
|
let free_before_alloc_array = wire(Array[Expr::ty(free_reg)][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,14 +1,6 @@
|
||||||
// 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 {
|
||||||
|
|
@ -16,750 +8,131 @@ pub enum FlagsMode {
|
||||||
X86(PRegFlagsX86),
|
X86(PRegFlagsX86),
|
||||||
}
|
}
|
||||||
|
|
||||||
trait PRegFlagsViewTraitSealed {
|
#[hdl(cmp_eq)]
|
||||||
type UnusedInner<T>: AsRef<[T]>
|
pub struct PRegFlagsPowerISA {}
|
||||||
+ 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)]
|
|
||||||
pub struct PRegFlagsPowerISA {}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
#[non_exhaustive]
|
|
||||||
pub struct PRegFlagsPowerISAView {
|
|
||||||
pub unused: ViewUnused([]),
|
|
||||||
pub xer_ca: pwr_ca_x86_cf,
|
|
||||||
pub xer_ca32: pwr_ca32_x86_af,
|
|
||||||
pub xer_ov: pwr_ov_x86_of,
|
|
||||||
pub xer_ov32: pwr_ov32_x86_df,
|
|
||||||
pub cr_lt: pwr_cr_lt_x86_sf,
|
|
||||||
pub cr_gt: pwr_cr_gt_x86_pf,
|
|
||||||
pub cr_eq: pwr_cr_eq_x86_zf,
|
|
||||||
/// both `CR<N>.SO` and `XER.SO` since instructions that write to both always write the same value
|
|
||||||
pub so: pwr_so,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
impl PRegFlagsPowerISA {
|
||||||
pub fn cr_condition_modes_msb0() -> [Expr<ConditionMode>; 4] {
|
pub fn xer_ca(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
||||||
PRegFlagsPowerISAView::cr_condition_modes()
|
flags.to_expr().pwr_ca_x86_cf
|
||||||
.into_cr_bits_msb0()
|
|
||||||
.map(|v| v.expect("known to be Some"))
|
|
||||||
}
|
}
|
||||||
pub fn cr_condition_modes_lsb0() -> [Expr<ConditionMode>; 4] {
|
pub fn xer_ca32(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
||||||
PRegFlagsPowerISAView::cr_condition_modes()
|
flags.to_expr().pwr_ca32_x86_af
|
||||||
.into_cr_bits_lsb0()
|
|
||||||
.map(|v| v.expect("known to be Some"))
|
|
||||||
}
|
}
|
||||||
pub fn cr_condition_modes_msb0_sim() -> [SimValue<ConditionMode>; 4] {
|
pub fn xer_ov(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
||||||
PRegFlagsPowerISAView::cr_condition_modes_sim()
|
flags.to_expr().pwr_ov_x86_of
|
||||||
.into_cr_bits_msb0()
|
|
||||||
.map(|v| v.expect("known to be Some"))
|
|
||||||
}
|
}
|
||||||
pub fn cr_condition_modes_lsb0_sim() -> [SimValue<ConditionMode>; 4] {
|
pub fn xer_ov32(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
||||||
PRegFlagsPowerISAView::cr_condition_modes_sim()
|
flags.to_expr().pwr_ov32_x86_df
|
||||||
.into_cr_bits_lsb0()
|
}
|
||||||
.map(|v| v.expect("known to be Some"))
|
/// 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> {
|
||||||
|
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_view_trait! {
|
#[hdl(cmp_eq)]
|
||||||
#[hdl(cmp_eq)]
|
pub struct PRegFlagsX86 {}
|
||||||
pub struct PRegFlagsX86 {}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
impl PRegFlagsX86 {
|
||||||
#[non_exhaustive]
|
pub fn cf(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
||||||
pub struct PRegFlagsX86View {
|
flags.to_expr().pwr_ca_x86_cf
|
||||||
pub unused: ViewUnused([pwr_so]),
|
}
|
||||||
pub cf: pwr_ca_x86_cf,
|
pub fn zf(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
||||||
pub zf: pwr_cr_eq_x86_zf,
|
flags.to_expr().pwr_cr_eq_x86_zf
|
||||||
pub sf: pwr_cr_lt_x86_sf,
|
}
|
||||||
pub of: pwr_ov_x86_of,
|
pub fn sf(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
||||||
pub af: pwr_ca32_x86_af,
|
flags.to_expr().pwr_cr_lt_x86_sf
|
||||||
pub pf: pwr_cr_gt_x86_pf,
|
}
|
||||||
pub df: pwr_ov32_x86_df,
|
pub fn of(flags: impl ToExpr<Type = PRegFlags>) -> Expr<Bool> {
|
||||||
|
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 {
|
#[hdl(cmp_eq)]
|
||||||
(
|
/// this is *not* the same as any particular ISA's flags register,
|
||||||
$(#[$struct_meta:meta])*
|
/// on PowerISA it is a combination of some bits from XER with a single 4-bit CR field.
|
||||||
$struct_vis:vis struct $PRegFlags:ident<$T:ident: Type = Bool> {
|
///
|
||||||
$($field:ident: T,)*
|
/// Accessor functions depend on the ISA:
|
||||||
}
|
///
|
||||||
) => {
|
/// * PowerISA: [`struct@PRegFlagsPowerISA`]
|
||||||
$(#[$struct_meta])*
|
/// * x86: [`struct@PRegFlagsX86`]
|
||||||
$struct_vis struct $PRegFlags<$T: Type = Bool> {
|
pub struct PRegFlags {
|
||||||
$($field: $T,)*
|
pwr_ca_x86_cf: Bool,
|
||||||
}
|
pwr_ca32_x86_af: Bool,
|
||||||
|
pwr_ov_x86_of: Bool,
|
||||||
struct Fields<$T> {
|
pwr_ov32_x86_df: Bool,
|
||||||
$($field: $T,)*
|
pwr_cr_lt_x86_sf: Bool,
|
||||||
}
|
pwr_cr_gt_x86_pf: Bool,
|
||||||
|
pwr_cr_eq_x86_zf: Bool,
|
||||||
impl<$T> Fields<$T> {
|
pwr_so: Bool,
|
||||||
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)]
|
|
||||||
/// 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.
|
|
||||||
///
|
|
||||||
/// Accessor functions depend on the ISA:
|
|
||||||
///
|
|
||||||
/// * PowerISA: [`struct@PRegFlagsPowerISA`]
|
|
||||||
/// * x86: [`struct@PRegFlagsX86`]
|
|
||||||
pub struct PRegFlags<T: Type = Bool> {
|
|
||||||
pwr_ca32_x86_af: T,
|
|
||||||
pwr_ca_x86_cf: T,
|
|
||||||
pwr_ov32_x86_df: T,
|
|
||||||
pwr_ov_x86_of: T,
|
|
||||||
pwr_so: T,
|
|
||||||
pwr_cr_eq_x86_zf: T,
|
|
||||||
pwr_cr_gt_x86_pf: T,
|
|
||||||
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> {
|
||||||
Self::splat(false)
|
#[hdl]
|
||||||
|
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,9 +4,8 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
config::CpuConfig,
|
config::CpuConfig,
|
||||||
instruction::{
|
instruction::{
|
||||||
AluBranchMOp, LoadStoreMOp, MOp, MOpDestReg, MOpInto, MOpRegNum, MOpTrait,
|
AluBranchMOp, LoadStoreMOp, MOp, MOpDestReg, MOpInto, MOpRegNum, MOpTrait, RenamedMOp,
|
||||||
MOpVariantVisitOps, MOpVariantVisitor, MOpVisitVariants, RenamedMOp, UnitOutRegNum,
|
UnitOutRegNum, mop_enum,
|
||||||
mop_enum,
|
|
||||||
},
|
},
|
||||||
register::{FlagsMode, PRegValue},
|
register::{FlagsMode, PRegValue},
|
||||||
unit::unit_base::UnitToRegAlloc,
|
unit::unit_base::UnitToRegAlloc,
|
||||||
|
|
@ -16,8 +15,6 @@ 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;
|
||||||
|
|
@ -39,7 +36,7 @@ macro_rules! all_units {
|
||||||
}
|
}
|
||||||
) => {
|
) => {
|
||||||
$(#[$enum_meta])*
|
$(#[$enum_meta])*
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Serialize, Deserialize)]
|
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
|
||||||
$vis enum $UnitKind {
|
$vis enum $UnitKind {
|
||||||
$(
|
$(
|
||||||
$(#[$variant_meta])*
|
$(#[$variant_meta])*
|
||||||
|
|
@ -55,16 +52,9 @@ macro_rules! all_units {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ValueType for $UnitKind {
|
|
||||||
type Type = $HdlUnitKind;
|
|
||||||
type ValueCategory = fayalite::expr::value_category::ValueCategoryExpr;
|
|
||||||
|
|
||||||
fn ty(&self) -> Self::Type {
|
|
||||||
$HdlUnitKind
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToExpr for $UnitKind {
|
impl ToExpr for $UnitKind {
|
||||||
|
type Type = $HdlUnitKind;
|
||||||
|
|
||||||
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(),)*
|
||||||
|
|
@ -85,15 +75,7 @@ macro_rules! all_units {
|
||||||
#[impl_mop_into = false]
|
#[impl_mop_into = false]
|
||||||
#[hdl]
|
#[hdl]
|
||||||
$(#[$enum_meta])*
|
$(#[$enum_meta])*
|
||||||
$vis enum $UnitMOpEnum<
|
$vis enum $UnitMOpEnum<$DestReg: Type, $SrcRegWidth: Size, #[MOp(get_ty = $transformed_move_op_get_ty)] $TransformedMoveOp: Type> {
|
||||||
$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),
|
||||||
|
|
@ -116,7 +98,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();
|
let ty = Expr::ty(expr);
|
||||||
#[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());
|
||||||
|
|
@ -182,10 +164,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 = this.ty().with_transformed_move_op_ty(new_transformed_move_op_ty);
|
let new_ty = Expr::ty(this).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, with_transformed_move_op.ty().HdlNone());
|
connect(with_transformed_move_op, Expr::ty(with_transformed_move_op).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]
|
||||||
|
|
@ -227,7 +209,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(this.ty()).$BeforeUnit(this)
|
MOpInto::<RenamedMOp<$DestReg, $SrcRegWidth>>::mop_into_ty(Expr::ty(this)).$BeforeUnit(this)
|
||||||
}
|
}
|
||||||
})*
|
})*
|
||||||
|
|
||||||
|
|
@ -236,7 +218,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(this.ty()).$AfterUnit(this)
|
MOpInto::<RenamedMOp<$DestReg, $SrcRegWidth>>::mop_into_ty(Expr::ty(this)).$AfterUnit(this)
|
||||||
}
|
}
|
||||||
})*
|
})*
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,10 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
config::CpuConfig,
|
config::CpuConfig,
|
||||||
instruction::{
|
instruction::{
|
||||||
AddSubMOp, AluBranchMOp, AluCommonMOp, BranchMOp, COMMON_MOP_SRC_LEN, CommonMOpDefaultImm,
|
AddSubMOp, AluBranchMOp, AluCommonMOp, COMMON_MOP_SRC_LEN, CommonMOp, LogicalMOp, MOpTrait,
|
||||||
CompareMOp, LogicalFlagsMOp, LogicalMOp, MOpTrait, OutputIntegerMode, ReadSpecialMOp,
|
OutputIntegerMode, RenamedMOp, UnitOutRegNum,
|
||||||
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,
|
||||||
|
|
@ -42,11 +38,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 = CommonMOpDefaultImm::as_sint_dyn(common.imm).cast_to_static::<UInt<64>>();
|
let imm: Expr<UInt<64>> = CommonMOp::imm(common).cast_to_static();
|
||||||
#[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);
|
||||||
|
|
@ -60,13 +56,13 @@ fn add_sub<SrcCount: KnownSize>(
|
||||||
FlagsMode::PowerISA(_) => {
|
FlagsMode::PowerISA(_) => {
|
||||||
connect(
|
connect(
|
||||||
carry_in_before_inversion,
|
carry_in_before_inversion,
|
||||||
PRegFlagsPowerISA::view(src_values[1].flags).xer_ca,
|
PRegFlagsPowerISA::xer_ca(src_values[1].flags),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
FlagsMode::X86(_) => {
|
FlagsMode::X86(_) => {
|
||||||
connect(
|
connect(
|
||||||
carry_in_before_inversion,
|
carry_in_before_inversion,
|
||||||
PRegFlagsX86::view(src_values[1].flags).cf,
|
PRegFlagsX86::cf(src_values[1].flags),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -203,36 +199,27 @@ fn add_sub<SrcCount: KnownSize>(
|
||||||
#[hdl]
|
#[hdl]
|
||||||
match flags_mode {
|
match flags_mode {
|
||||||
FlagsMode::PowerISA(_) => {
|
FlagsMode::PowerISA(_) => {
|
||||||
connect(
|
PRegFlagsPowerISA::clear_unused(flags);
|
||||||
flags,
|
connect(PRegFlagsPowerISA::xer_ca(flags), pwr_ca);
|
||||||
PRegFlagsPowerISA::from_view(PRegFlagsPowerISAView {
|
connect(PRegFlagsPowerISA::xer_ca32(flags), pwr_ca32);
|
||||||
unused: ViewUnused::splat(false.to_expr()),
|
connect(PRegFlagsPowerISA::xer_ov(flags), pwr_ov);
|
||||||
xer_ca: pwr_ca,
|
connect(PRegFlagsPowerISA::xer_ov32(flags), pwr_ov32);
|
||||||
xer_ca32: pwr_ca32,
|
connect(PRegFlagsPowerISA::cr_lt(flags), pwr_cr_lt);
|
||||||
xer_ov: pwr_ov,
|
connect(PRegFlagsPowerISA::cr_gt(flags), pwr_cr_gt);
|
||||||
xer_ov32: pwr_ov32,
|
connect(PRegFlagsPowerISA::cr_eq(flags), pwr_cr_eq);
|
||||||
so: pwr_so,
|
connect(PRegFlagsPowerISA::so(flags), pwr_so);
|
||||||
cr_lt: pwr_cr_lt,
|
|
||||||
cr_gt: pwr_cr_gt,
|
|
||||||
cr_eq: pwr_cr_eq,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
FlagsMode::X86(_) => {
|
FlagsMode::X86(_) => {
|
||||||
connect(
|
PRegFlagsX86::clear_unused(flags);
|
||||||
flags,
|
connect(PRegFlagsX86::cf(flags), x86_cf);
|
||||||
PRegFlagsX86::from_view(PRegFlagsX86View {
|
connect(PRegFlagsX86::af(flags), x86_af);
|
||||||
unused: ViewUnused::splat(false.to_expr()),
|
connect(PRegFlagsX86::of(flags), x86_of);
|
||||||
cf: x86_cf,
|
connect(PRegFlagsX86::sf(flags), x86_sf);
|
||||||
zf: x86_zf,
|
connect(PRegFlagsX86::pf(flags), x86_pf);
|
||||||
sf: x86_sf,
|
connect(PRegFlagsX86::zf(flags), x86_zf);
|
||||||
of: x86_of,
|
|
||||||
af: x86_af,
|
// this insn doesn't write DF, so it's output isn't used for reading DF
|
||||||
pf: x86_pf,
|
connect(PRegFlagsX86::df(flags), false);
|
||||||
// this insn doesn't write DF, so it's output isn't used for reading DF
|
|
||||||
df: false.to_expr(),
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -243,95 +230,9 @@ 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, ConstUsize<2>>>,
|
mop: Expr<LogicalMOp<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 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<()>> {
|
||||||
|
|
@ -365,13 +266,16 @@ 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,
|
||||||
unit_to_reg_alloc.ty().input.data.HdlSome.mop,
|
Expr::ty(unit_to_reg_alloc).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(unit_base.execute_end, unit_base.execute_end.ty().HdlNone());
|
connect(
|
||||||
|
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]
|
||||||
|
|
@ -418,23 +322,6 @@ 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(
|
||||||
|
|
@ -452,128 +339,6 @@ 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 = in_flight_ops.ty().len();
|
let max_in_flight = Expr::ty(in_flight_ops).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, execute_start.ty().data.HdlNone());
|
connect(execute_start.data, Expr::ty(execute_start).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(in_flight_ops_summary_value.ty());
|
let in_flight_ops_summary = wire(Expr::ty(in_flight_ops_summary_value));
|
||||||
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..unit_output_writes.ty().len())
|
let mut unit_output_regs_valid: Vec<MemBuilder<Bool>> = (0..Expr::ty(unit_output_writes).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..unit_output_writes.ty().len() {
|
for unit_index in 0..Expr::ty(unit_output_writes).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,
|
||||||
unit_to_reg_alloc.output.ty().HdlNone(),
|
Expr::ty(unit_to_reg_alloc.output).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(in_flight_ops_summary.ty().ready_op_index.HdlSome),
|
in_flight_op_index.cast_to(Expr::ty(in_flight_ops_summary).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..unit_output_writes.ty().len() {
|
for unit_index in 0..Expr::ty(unit_output_writes).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,9 +1,6 @@
|
||||||
// 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;
|
||||||
|
|
||||||
|
|
@ -28,255 +25,3 @@ 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,28 +1,147 @@
|
||||||
// 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::ExprIndex, int::UIntInRangeInclusiveType, prelude::*};
|
use fayalite::{
|
||||||
use std::fmt;
|
expr::ops::{ExprCastTo, ExprIndex, ExprPartialEq, ExprPartialOrd},
|
||||||
|
int::SizeType,
|
||||||
|
intern::{Intern, Interned},
|
||||||
|
prelude::*,
|
||||||
|
ty::{MatchVariantWithoutScope, StaticType, TypeProperties},
|
||||||
|
};
|
||||||
|
use std::{marker::PhantomData, ops::Index};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||||
pub struct ArrayVecFullError<V, I: Iterator> {
|
pub struct Length<Max: Size> {
|
||||||
pub value: V,
|
ty: UInt,
|
||||||
pub rest: std::iter::Chain<std::iter::Once<I::Item>, I>,
|
_phantom: PhantomData<Max>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V, I: Iterator> fmt::Display for ArrayVecFullError<V, I> {
|
impl<Max: Size> Length<Max> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
pub fn new(max: Max::SizeType) -> Self {
|
||||||
write!(f, "ArrayVec is full")
|
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<V: fmt::Debug, I: Iterator<Item: fmt::Debug> + fmt::Debug> std::error::Error
|
impl<Max: Size, DestWidth: Size> ExprCastTo<UIntType<DestWidth>> for Length<Max> {
|
||||||
for ArrayVecFullError<V, I>
|
fn cast_to(src: Expr<Self>, to_type: UIntType<DestWidth>) -> Expr<UIntType<DestWidth>> {
|
||||||
{
|
Expr::<UInt>::from_canonical(Expr::canonical(src)).cast_to(to_type)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl]
|
#[allow(non_upper_case_globals)]
|
||||||
pub type Length<Max: Size> = UIntInRangeInclusiveType<ConstUsize<0>, Max>;
|
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]
|
||||||
|
|
@ -37,55 +156,7 @@ impl<T: Type, N: Size> ArrayVec<T, N> {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
ArrayVec {
|
ArrayVec {
|
||||||
elements: self.elements.uninit(),
|
elements: self.elements.uninit(),
|
||||||
len: 0u8.cast_to(self.len),
|
len: self.len.zero(),
|
||||||
}
|
|
||||||
}
|
|
||||||
#[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 from_iter_sim<I: IntoIterator<Item: ToSimValueWithType<T>>>(
|
|
||||||
self,
|
|
||||||
uninit_element: impl ToSimValueWithType<T>,
|
|
||||||
iter: I,
|
|
||||||
) -> Result<SimValue<Self>, ArrayVecFullError<SimValue<Self>, I::IntoIter>> {
|
|
||||||
let mut value = Self::new_sim(self, uninit_element);
|
|
||||||
let element = self.element();
|
|
||||||
let mut iter = iter.into_iter();
|
|
||||||
for i in 0..self.capacity() {
|
|
||||||
let Some(v) = iter.next() else {
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
value.elements[i] = v.into_sim_value_with_type(element);
|
|
||||||
*value.len = i + 1;
|
|
||||||
}
|
|
||||||
if let Some(extra) = iter.next() {
|
|
||||||
Err(ArrayVecFullError {
|
|
||||||
value,
|
|
||||||
rest: std::iter::once(extra).chain(iter),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Ok(value)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn element(self) -> T {
|
pub fn element(self) -> T {
|
||||||
|
|
@ -105,8 +176,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[N::from_usize(elements.ty().len())],
|
Length::new(N::from_usize(Expr::ty(elements).len())),
|
||||||
len.ty(),
|
Expr::ty(len),
|
||||||
"len type mismatch",
|
"len type mismatch",
|
||||||
);
|
);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -118,12 +189,9 @@ 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(0u8)
|
len.cmp_eq(Expr::ty(len).zero())
|
||||||
}
|
}
|
||||||
pub fn capacity(self) -> usize {
|
pub fn capacity(self) -> usize {
|
||||||
self.elements.len()
|
self.elements.len()
|
||||||
|
|
@ -139,77 +207,11 @@ 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(this.len) {
|
if index.cmp_lt(Length::as_uint(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())],
|
||||||
|
|
@ -224,7 +226,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(this.ty().mapped_ty(new_element_ty));
|
let mapped_array_vec = wire(Expr::ty(this).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));
|
||||||
|
|
@ -232,42 +234,15 @@ 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 =
|
let array_vec_as_array_of_options = wire(
|
||||||
wire(ArrayType[HdlOption[this.ty().element()]][N::from_usize(this.ty().capacity())]);
|
ArrayType[HdlOption[Expr::ty(this).element()]]
|
||||||
|
[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, element.ty().HdlNone());
|
connect(element, Expr::ty(element).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))
|
||||||
|
|
@ -288,34 +263,3 @@ 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,697 +0,0 @@
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
||||||
// See Notices.txt for copyright information
|
|
||||||
|
|
||||||
use cpu::{
|
|
||||||
config::{CpuConfig, UnitConfig},
|
|
||||||
fetch::{
|
|
||||||
FetchToDecodeInterface, FetchToDecodeInterfaceInner, MemoryInterface,
|
|
||||||
MemoryOperationErrorKind, MemoryOperationFinish, MemoryOperationFinishKind,
|
|
||||||
MemoryOperationKind, MemoryOperationStart, fetch,
|
|
||||||
},
|
|
||||||
next_pc::{FETCH_BLOCK_ID_WIDTH, NextPcToFetchInterface, NextPcToFetchInterfaceInner},
|
|
||||||
unit::UnitKind,
|
|
||||||
util::array_vec::ArrayVec,
|
|
||||||
};
|
|
||||||
use fayalite::{
|
|
||||||
prelude::*,
|
|
||||||
sim::vcd::VcdWriterDecls,
|
|
||||||
util::{DebugAsDisplay, RcWriter},
|
|
||||||
};
|
|
||||||
use std::{cell::RefCell, collections::VecDeque, fmt, num::NonZeroUsize};
|
|
||||||
|
|
||||||
struct Random {
|
|
||||||
index: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Random {
|
|
||||||
fn next(&mut self) -> u64 {
|
|
||||||
let index = self.index;
|
|
||||||
self.index = self.index.wrapping_add(1);
|
|
||||||
// make a pseudo-random number deterministically based on index
|
|
||||||
index
|
|
||||||
.wrapping_add(1)
|
|
||||||
.wrapping_mul(0x18C49126EABE7A0D) // random prime
|
|
||||||
.rotate_left(32)
|
|
||||||
.wrapping_mul(0x92B38C197608A6B) // random prime
|
|
||||||
.rotate_right(60)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const MEMORY_QUEUE_SIZE: usize = 16;
|
|
||||||
|
|
||||||
#[hdl]
|
|
||||||
struct MemoryQueueEntry {
|
|
||||||
addr: UInt<64>,
|
|
||||||
fetch_block_id: UInt<{ FETCH_BLOCK_ID_WIDTH }>,
|
|
||||||
cycles_left: UInt<8>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MemoryQueueEntry {
|
|
||||||
#[hdl]
|
|
||||||
fn default_sim(self) -> SimValue<Self> {
|
|
||||||
#[hdl(sim)]
|
|
||||||
Self {
|
|
||||||
addr: 0u64,
|
|
||||||
fetch_block_id: self.fetch_block_id.zero(),
|
|
||||||
cycles_left: 0u8,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn get_next_delay(random: &mut Random) -> u8 {
|
|
||||||
if random.next() % 32 == 0 { 30 } else { 5 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const MEMORY_DATA: &str = "Test data, testing...\nTest Test!\nSecond Cache Line\nTesting.....\n";
|
|
||||||
const MEMORY_START: u64 = 0x1000;
|
|
||||||
const MEMORY_RANGE2: std::ops::Range<u64> = 0x2000..0x3000;
|
|
||||||
const MEMORY_ERROR_RANGE: std::ops::Range<u64> = 0x10F00..0x20F00;
|
|
||||||
const MEMORY_ERROR_STEP: u64 = 0x1000;
|
|
||||||
|
|
||||||
fn read_memory(start: u64, len: usize) -> Option<&'static [u8]> {
|
|
||||||
if MEMORY_ERROR_RANGE.contains(&start) {
|
|
||||||
let start = start - MEMORY_ERROR_RANGE.start;
|
|
||||||
let fail_at = start / MEMORY_ERROR_STEP;
|
|
||||||
let offset = start % MEMORY_ERROR_STEP;
|
|
||||||
return if offset < fail_at {
|
|
||||||
[0xFFu8; MEMORY_DATA.len()].get(..len)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if MEMORY_RANGE2.contains(&start) {
|
|
||||||
return [0xF2u8; MEMORY_DATA.len()].get(..len);
|
|
||||||
}
|
|
||||||
MEMORY_DATA
|
|
||||||
.as_bytes()
|
|
||||||
.get(start.checked_sub(MEMORY_START)?.try_into().ok()?..)?
|
|
||||||
.get(..len)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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 random = RefCell::new(Random { index: 0 });
|
|
||||||
sim.resettable(
|
|
||||||
cd,
|
|
||||||
async |mut sim| {
|
|
||||||
#[hdl]
|
|
||||||
let MemoryInterface::<_> {
|
|
||||||
start,
|
|
||||||
finish,
|
|
||||||
next_fetch_block_ids,
|
|
||||||
config: _,
|
|
||||||
} = memory_interface;
|
|
||||||
sim.write(start.ready, false).await;
|
|
||||||
sim.write(finish.data, finish.ty().data.HdlNone()).await;
|
|
||||||
sim.write(next_fetch_block_ids, next_fetch_block_ids.ty().HdlNone())
|
|
||||||
.await;
|
|
||||||
sim.write(
|
|
||||||
queue_debug,
|
|
||||||
queue_debug.ty().new_sim(MemoryQueueEntry.default_sim()),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
},
|
|
||||||
|sim, ()| run_fn(cd, memory_interface, queue_debug, &random, 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 }>>>,
|
|
||||||
random: &RefCell<Random>,
|
|
||||||
mut sim: ExternModuleSimulationState,
|
|
||||||
) {
|
|
||||||
let mut random = random.borrow_mut();
|
|
||||||
let config = memory_interface.config.ty();
|
|
||||||
let finish_data_ty = memory_interface.finish.data.ty();
|
|
||||||
let next_fetch_block_ids_ty = memory_interface.next_fetch_block_ids.ty();
|
|
||||||
let mut queue: VecDeque<SimValue<MemoryQueueEntry>> = VecDeque::new();
|
|
||||||
loop {
|
|
||||||
for entry in &mut queue {
|
|
||||||
entry.cycles_left = entry.cycles_left.as_int().saturating_sub(1).to_sim_value();
|
|
||||||
}
|
|
||||||
let sim_queue = queue_debug
|
|
||||||
.ty()
|
|
||||||
.from_iter_sim(MemoryQueueEntry.default_sim(), &queue)
|
|
||||||
.ok()
|
|
||||||
.expect("queue is known to be small enough");
|
|
||||||
sim.write(queue_debug, sim_queue).await;
|
|
||||||
sim.write_bool(
|
|
||||||
memory_interface.start.ready,
|
|
||||||
queue.len() < MEMORY_QUEUE_SIZE && random.next() % 32 != 0,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
sim.write(
|
|
||||||
memory_interface.next_fetch_block_ids,
|
|
||||||
#[hdl(sim)]
|
|
||||||
next_fetch_block_ids_ty.HdlSome(
|
|
||||||
next_fetch_block_ids_ty
|
|
||||||
.HdlSome
|
|
||||||
.from_iter_sim(0u8, queue.iter().map(|entry| &entry.fetch_block_id))
|
|
||||||
.ok()
|
|
||||||
.expect("queue is known to be small enough"),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
let finish_data = if let Some(entry) = queue
|
|
||||||
.front()
|
|
||||||
.filter(|entry| entry.cycles_left.as_int() == 0)
|
|
||||||
{
|
|
||||||
#[hdl(sim)]
|
|
||||||
let MemoryQueueEntry {
|
|
||||||
addr,
|
|
||||||
fetch_block_id: _,
|
|
||||||
cycles_left: _,
|
|
||||||
} = entry;
|
|
||||||
let addr = addr.as_int();
|
|
||||||
let mut read_data =
|
|
||||||
repeat(0u8, finish_data_ty.HdlSome.read_data.len()).to_sim_value();
|
|
||||||
let kind = if let Some(data) = read_memory(addr, read_data.len()) {
|
|
||||||
for (l, r) in read_data.iter_mut().zip(data) {
|
|
||||||
*l = r.to_sim_value();
|
|
||||||
}
|
|
||||||
#[hdl(sim)]
|
|
||||||
MemoryOperationFinishKind.Success(
|
|
||||||
#[hdl(sim)]
|
|
||||||
MemoryOperationKind.Read(),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
#[hdl(sim)]
|
|
||||||
MemoryOperationFinishKind.Error(
|
|
||||||
#[hdl(sim)]
|
|
||||||
MemoryOperationErrorKind.Generic(),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
#[hdl(sim)]
|
|
||||||
finish_data_ty.HdlSome(
|
|
||||||
#[hdl(sim)]
|
|
||||||
MemoryOperationFinish::<_> {
|
|
||||||
kind,
|
|
||||||
read_data,
|
|
||||||
config,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
#[hdl(sim)]
|
|
||||||
finish_data_ty.HdlNone()
|
|
||||||
};
|
|
||||||
sim.write(memory_interface.finish.data, &finish_data).await;
|
|
||||||
sim.wait_for_clock_edge(cd.clk).await;
|
|
||||||
println!(
|
|
||||||
"Dump mock memory queue: {:#?}",
|
|
||||||
Vec::from_iter(queue.iter().map(|v| {
|
|
||||||
DebugAsDisplay(format!(
|
|
||||||
"fid={:#x} addr={:#x}",
|
|
||||||
v.fetch_block_id.as_int(),
|
|
||||||
v.addr.as_int(),
|
|
||||||
))
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
if sim
|
|
||||||
.read_past_bool(memory_interface.start.ready, cd.clk)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
#[hdl(sim)]
|
|
||||||
if let HdlSome(memory_operation_start) =
|
|
||||||
sim.read_past(memory_interface.start.data, cd.clk).await
|
|
||||||
{
|
|
||||||
#[hdl(sim)]
|
|
||||||
let MemoryOperationStart::<_> {
|
|
||||||
kind,
|
|
||||||
addr,
|
|
||||||
write_data: _,
|
|
||||||
fetch_block_id,
|
|
||||||
config: _,
|
|
||||||
} = memory_operation_start;
|
|
||||||
#[hdl(sim)]
|
|
||||||
match kind {
|
|
||||||
MemoryOperationKind::Read => {}
|
|
||||||
MemoryOperationKind::Write => unreachable!(),
|
|
||||||
}
|
|
||||||
let entry = #[hdl(sim)]
|
|
||||||
MemoryQueueEntry {
|
|
||||||
addr,
|
|
||||||
fetch_block_id,
|
|
||||||
cycles_left: MemoryQueueEntry::get_next_delay(&mut random),
|
|
||||||
};
|
|
||||||
println!("mock memory start: {entry:#?}");
|
|
||||||
queue.push_back(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if sim
|
|
||||||
.read_past_bool(memory_interface.finish.ready, cd.clk)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
#[hdl(sim)]
|
|
||||||
if let HdlSome(finish_data) = finish_data {
|
|
||||||
let Some(entry) = queue.pop_front() else {
|
|
||||||
unreachable!();
|
|
||||||
};
|
|
||||||
#[hdl(sim)]
|
|
||||||
let MemoryOperationFinish::<_> {
|
|
||||||
kind,
|
|
||||||
read_data,
|
|
||||||
config: _,
|
|
||||||
} = finish_data;
|
|
||||||
let kind = #[hdl(sim)]
|
|
||||||
match kind {
|
|
||||||
MemoryOperationFinishKind::Error(_) => Err(()),
|
|
||||||
MemoryOperationFinishKind::Success(_) => Ok(()),
|
|
||||||
};
|
|
||||||
println!(
|
|
||||||
"mock memory finish: kind={kind:?} read_data={read_data:?} {entry:#?}"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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 to_decode: FetchToDecodeInterface<PhantomConst<CpuConfig>> =
|
|
||||||
m.output(FetchToDecodeInterface[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,
|
|
||||||
to_decode: fetch_to_decode,
|
|
||||||
} = fetch;
|
|
||||||
connect(fetch_cd, cd);
|
|
||||||
connect(fetch_from_next_pc, from_next_pc);
|
|
||||||
connect(to_decode, fetch_to_decode);
|
|
||||||
#[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);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct FetchTestOperation {
|
|
||||||
start_pc: u64,
|
|
||||||
fetch_block_id: u8,
|
|
||||||
fetch_block_data: [u8; FETCH_WIDTH_IN_BYTES],
|
|
||||||
error: Option<SimValue<MemoryOperationErrorKind>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for FetchTestOperation {
|
|
||||||
#[hdl]
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
let Self {
|
|
||||||
start_pc,
|
|
||||||
fetch_block_id,
|
|
||||||
fetch_block_data,
|
|
||||||
ref error,
|
|
||||||
} = *self;
|
|
||||||
if let Some(error) = error {
|
|
||||||
#[hdl(sim)]
|
|
||||||
match error {
|
|
||||||
MemoryOperationErrorKind::Generic => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
start_pc == other.start_pc
|
|
||||||
&& fetch_block_id == other.fetch_block_id
|
|
||||||
&& fetch_block_data == other.fetch_block_data
|
|
||||||
&& error.is_some() == other.error.is_some()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for FetchTestOperation {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
let Self {
|
|
||||||
start_pc,
|
|
||||||
fetch_block_id,
|
|
||||||
fetch_block_data,
|
|
||||||
error,
|
|
||||||
} = self;
|
|
||||||
let mut debug_struct = f.debug_struct("FetchTestOperation");
|
|
||||||
debug_struct.field("start_pc", &format_args!("{start_pc:#x}"));
|
|
||||||
debug_struct.field("fetch_block_id", &format_args!("{fetch_block_id:#x}"));
|
|
||||||
if fetch_block_data.iter().all(|v| *v == fetch_block_data[0]) {
|
|
||||||
debug_struct.field(
|
|
||||||
"fetch_block_data",
|
|
||||||
&format_args!(
|
|
||||||
"[b'{}'; {FETCH_WIDTH_IN_BYTES}]",
|
|
||||||
fetch_block_data[0].escape_ascii(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
debug_struct.field(
|
|
||||||
"fetch_block_data",
|
|
||||||
&format_args!("b\"{}\"", fetch_block_data.escape_ascii()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
debug_struct.field("error", error).finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const LOG2_FETCH_WIDTH_IN_BYTES: u8 = 3;
|
|
||||||
const FETCH_WIDTH_IN_BYTES: usize = 1 << LOG2_FETCH_WIDTH_IN_BYTES;
|
|
||||||
const LOG2_CACHE_LINE_SIZE_IN_BYTES: u8 = 5;
|
|
||||||
const CACHE_LINE_SIZE_IN_BYTES: usize = 1 << LOG2_CACHE_LINE_SIZE_IN_BYTES;
|
|
||||||
|
|
||||||
// needs to be a multiple of the cache line size
|
|
||||||
const _: [(); CACHE_LINE_SIZE_IN_BYTES * 2] = [(); MEMORY_DATA.len()];
|
|
||||||
|
|
||||||
fn fetch_test_operations() -> Vec<FetchTestOperation> {
|
|
||||||
#[track_caller]
|
|
||||||
fn mem_data(r: std::ops::RangeFrom<usize>) -> [u8; FETCH_WIDTH_IN_BYTES] {
|
|
||||||
*MEMORY_DATA[r]
|
|
||||||
.as_bytes()
|
|
||||||
.first_chunk()
|
|
||||||
.expect("start should be in-range")
|
|
||||||
}
|
|
||||||
#[hdl]
|
|
||||||
fn generic_error() -> SimValue<MemoryOperationErrorKind> {
|
|
||||||
#[hdl(sim)]
|
|
||||||
MemoryOperationErrorKind.Generic()
|
|
||||||
}
|
|
||||||
let mut last_fetch_block_id = 0u8.wrapping_sub(1);
|
|
||||||
macro_rules! op {
|
|
||||||
{
|
|
||||||
$($field:ident: $value:expr,)*
|
|
||||||
} => {
|
|
||||||
FetchTestOperation {
|
|
||||||
fetch_block_id: {
|
|
||||||
last_fetch_block_id = last_fetch_block_id.wrapping_add(1);
|
|
||||||
last_fetch_block_id
|
|
||||||
},
|
|
||||||
$($field: $value,)*
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
vec![
|
|
||||||
op! {
|
|
||||||
start_pc: 0x1000,
|
|
||||||
fetch_block_data: mem_data(0..),
|
|
||||||
error: None,
|
|
||||||
},
|
|
||||||
op! {
|
|
||||||
start_pc: 0x1010,
|
|
||||||
fetch_block_data: mem_data(0x10..),
|
|
||||||
error: None,
|
|
||||||
},
|
|
||||||
op! {
|
|
||||||
start_pc: 0x1020,
|
|
||||||
fetch_block_data: mem_data(0x20..),
|
|
||||||
error: None,
|
|
||||||
},
|
|
||||||
op! {
|
|
||||||
start_pc: 0x100,
|
|
||||||
fetch_block_data: [0; _],
|
|
||||||
error: Some(generic_error()),
|
|
||||||
},
|
|
||||||
op! {
|
|
||||||
start_pc: MEMORY_ERROR_RANGE.start,
|
|
||||||
fetch_block_data: [0; _],
|
|
||||||
error: Some(generic_error()),
|
|
||||||
},
|
|
||||||
op! {
|
|
||||||
start_pc: MEMORY_ERROR_RANGE.start + MEMORY_ERROR_STEP,
|
|
||||||
fetch_block_data: [0; _],
|
|
||||||
error: Some(generic_error()),
|
|
||||||
},
|
|
||||||
op! {
|
|
||||||
start_pc: MEMORY_ERROR_RANGE.start + MEMORY_ERROR_STEP * 2,
|
|
||||||
fetch_block_data: [0; _],
|
|
||||||
error: Some(generic_error()),
|
|
||||||
},
|
|
||||||
op! {
|
|
||||||
start_pc: MEMORY_ERROR_RANGE.start + MEMORY_ERROR_STEP * 3,
|
|
||||||
fetch_block_data: [0; _],
|
|
||||||
error: Some(generic_error()),
|
|
||||||
},
|
|
||||||
op! {
|
|
||||||
start_pc: 0x1000,
|
|
||||||
fetch_block_data: mem_data(0..),
|
|
||||||
error: None,
|
|
||||||
},
|
|
||||||
op! {
|
|
||||||
start_pc: 0x1010,
|
|
||||||
fetch_block_data: mem_data(0x10..),
|
|
||||||
error: None,
|
|
||||||
},
|
|
||||||
op! {
|
|
||||||
start_pc: 0x1020,
|
|
||||||
fetch_block_data: mem_data(0x20..),
|
|
||||||
error: None,
|
|
||||||
},
|
|
||||||
op! {
|
|
||||||
start_pc: 0x1000,
|
|
||||||
fetch_block_data: mem_data(0..),
|
|
||||||
error: None,
|
|
||||||
},
|
|
||||||
op! {
|
|
||||||
start_pc: 0x1010,
|
|
||||||
fetch_block_data: mem_data(0x10..),
|
|
||||||
error: None,
|
|
||||||
},
|
|
||||||
op! {
|
|
||||||
start_pc: 0x1020,
|
|
||||||
fetch_block_data: mem_data(0x20..),
|
|
||||||
error: None,
|
|
||||||
},
|
|
||||||
op! {
|
|
||||||
start_pc: MEMORY_RANGE2.start,
|
|
||||||
fetch_block_data: [0xF2; _],
|
|
||||||
error: None,
|
|
||||||
},
|
|
||||||
op! {
|
|
||||||
start_pc: MEMORY_RANGE2.start,
|
|
||||||
fetch_block_data: [0xF2; _],
|
|
||||||
error: None,
|
|
||||||
},
|
|
||||||
op! {
|
|
||||||
start_pc: MEMORY_RANGE2.start,
|
|
||||||
fetch_block_data: [0xF2; _],
|
|
||||||
error: None,
|
|
||||||
},
|
|
||||||
op! {
|
|
||||||
start_pc: MEMORY_RANGE2.start,
|
|
||||||
fetch_block_data: [0xF2; _],
|
|
||||||
error: None,
|
|
||||||
},
|
|
||||||
op! {
|
|
||||||
start_pc: MEMORY_RANGE2.start,
|
|
||||||
fetch_block_data: [0xF2; _],
|
|
||||||
error: None,
|
|
||||||
},
|
|
||||||
op! {
|
|
||||||
start_pc: MEMORY_RANGE2.start,
|
|
||||||
fetch_block_data: [0xF2; _],
|
|
||||||
error: None,
|
|
||||||
},
|
|
||||||
op! {
|
|
||||||
start_pc: MEMORY_RANGE2.start,
|
|
||||||
fetch_block_data: [0xF2; _],
|
|
||||||
error: None,
|
|
||||||
},
|
|
||||||
op! {
|
|
||||||
start_pc: 0x1000,
|
|
||||||
fetch_block_data: mem_data(0..),
|
|
||||||
error: None,
|
|
||||||
},
|
|
||||||
op! {
|
|
||||||
start_pc: 0x1000,
|
|
||||||
fetch_block_data: mem_data(0..),
|
|
||||||
error: None,
|
|
||||||
},
|
|
||||||
op! {
|
|
||||||
start_pc: 0x1000,
|
|
||||||
fetch_block_data: mem_data(0..),
|
|
||||||
error: None,
|
|
||||||
},
|
|
||||||
op! {
|
|
||||||
start_pc: 0x1000,
|
|
||||||
fetch_block_data: mem_data(0..),
|
|
||||||
error: None,
|
|
||||||
},
|
|
||||||
op! {
|
|
||||||
start_pc: 0x1000,
|
|
||||||
fetch_block_data: mem_data(0..),
|
|
||||||
error: None,
|
|
||||||
},
|
|
||||||
op! {
|
|
||||||
start_pc: 0x1000,
|
|
||||||
fetch_block_data: mem_data(0..),
|
|
||||||
error: None,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[hdl]
|
|
||||||
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 = LOG2_FETCH_WIDTH_IN_BYTES;
|
|
||||||
config.log2_cache_line_size_in_bytes = LOG2_CACHE_LINE_SIZE_IN_BYTES;
|
|
||||||
config.log2_l1_i_cache_line_count = 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),
|
|
||||||
};
|
|
||||||
let from_next_pc_ty = sim.io().from_next_pc.ty();
|
|
||||||
sim.write_clock(sim.io().cd.clk, false);
|
|
||||||
sim.write_reset(sim.io().cd.rst, true);
|
|
||||||
sim.write(
|
|
||||||
sim.io().from_next_pc.cancel.data,
|
|
||||||
from_next_pc_ty.cancel.data.HdlNone(),
|
|
||||||
);
|
|
||||||
sim.write(
|
|
||||||
sim.io().from_next_pc.fetch.data,
|
|
||||||
from_next_pc_ty.fetch.data.HdlNone(),
|
|
||||||
);
|
|
||||||
sim.write(sim.io().to_decode.fetched.ready, true);
|
|
||||||
sim.write(
|
|
||||||
sim.io().to_decode.next_fetch_block_ids,
|
|
||||||
HdlSome(
|
|
||||||
sim.io()
|
|
||||||
.ty()
|
|
||||||
.to_decode
|
|
||||||
.next_fetch_block_ids
|
|
||||||
.HdlSome
|
|
||||||
.new_sim(0u8),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
let operations = fetch_test_operations();
|
|
||||||
let mut started_operations = 0;
|
|
||||||
let mut finished_operations = 0;
|
|
||||||
for cycle in 0..150 {
|
|
||||||
sim.write(
|
|
||||||
sim.io().from_next_pc.fetch.data,
|
|
||||||
if let Some(op) = operations.get(started_operations) {
|
|
||||||
#[hdl(sim)]
|
|
||||||
HdlSome(
|
|
||||||
#[hdl(sim)]
|
|
||||||
NextPcToFetchInterfaceInner {
|
|
||||||
start_pc: op.start_pc,
|
|
||||||
fetch_block_id: op.fetch_block_id,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
#[hdl(sim)]
|
|
||||||
HdlNone()
|
|
||||||
},
|
|
||||||
);
|
|
||||||
sim.advance_time(SimDuration::from_nanos(500));
|
|
||||||
#[hdl(sim)]
|
|
||||||
if let HdlSome(next_fetch_block_ids) = sim.read(sim.io().from_next_pc.next_fetch_block_ids)
|
|
||||||
{
|
|
||||||
let next_fetch_block_ids = ArrayVec::elements_sim_ref(&next_fetch_block_ids);
|
|
||||||
let expected_next_fetch_block_ids = Vec::from_iter(
|
|
||||||
operations
|
|
||||||
.get(finished_operations..started_operations)
|
|
||||||
.unwrap_or(&[])
|
|
||||||
.iter()
|
|
||||||
.map(|op| op.fetch_block_id.to_sim_value()),
|
|
||||||
);
|
|
||||||
println!("expected_next_fetch_block_ids={expected_next_fetch_block_ids:?}");
|
|
||||||
assert_eq!(next_fetch_block_ids, expected_next_fetch_block_ids);
|
|
||||||
}
|
|
||||||
if sim.read_bool(sim.io().from_next_pc.fetch.ready) {
|
|
||||||
#[hdl(sim)]
|
|
||||||
if let HdlSome(_) = sim.read(sim.io().from_next_pc.fetch.data) {
|
|
||||||
println!("started fetch: {:#?}", operations[started_operations]);
|
|
||||||
started_operations += 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println!("not ready to start fetch");
|
|
||||||
}
|
|
||||||
if sim.read_bool(sim.io().to_decode.fetched.ready) {
|
|
||||||
#[hdl(sim)]
|
|
||||||
if let HdlSome(fetched) = sim.read(sim.io().to_decode.fetched.data) {
|
|
||||||
#[hdl(sim)]
|
|
||||||
let FetchToDecodeInterfaceInner::<_> {
|
|
||||||
start_pc,
|
|
||||||
fetch_block_id,
|
|
||||||
fetch_block_data,
|
|
||||||
error,
|
|
||||||
config: _,
|
|
||||||
} = &fetched;
|
|
||||||
let Some(expected_op) = operations.get(finished_operations) else {
|
|
||||||
panic!("too many finished operations: {fetched:#?}");
|
|
||||||
};
|
|
||||||
let op = FetchTestOperation {
|
|
||||||
start_pc: start_pc.as_int(),
|
|
||||||
fetch_block_id: fetch_block_id.as_int(),
|
|
||||||
error: #[hdl(sim)]
|
|
||||||
match error {
|
|
||||||
HdlSome(e) => Some(e.clone()),
|
|
||||||
HdlNone => None,
|
|
||||||
},
|
|
||||||
fetch_block_data: std::array::from_fn(|i| fetch_block_data[i].as_int()),
|
|
||||||
};
|
|
||||||
println!("finished fetch: op={op:#?}");
|
|
||||||
assert_eq!(
|
|
||||||
op, *expected_op,
|
|
||||||
"cycle={cycle} finished_operations={finished_operations}",
|
|
||||||
);
|
|
||||||
finished_operations += 1;
|
|
||||||
} else {
|
|
||||||
println!("not ready to finish fetch");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
assert_eq!(finished_operations, operations.len());
|
|
||||||
let vcd = String::from_utf8(writer.writer.take().unwrap().take()).unwrap();
|
|
||||||
println!("####### VCD:\n{vcd}\n#######");
|
|
||||||
if vcd != include_str!("expected/fetch.vcd") {
|
|
||||||
panic!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
92
crates/cpu/tests/main_memory.rs
Normal file
92
crates/cpu/tests/main_memory.rs
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use cpu::{
|
||||||
|
config::{CpuConfig, UnitConfig},
|
||||||
|
instruction::{AddSubMOp, LogicalMOp, MOp, MOpDestReg, MOpRegNum, OutputIntegerMode},
|
||||||
|
main_memory::main_memory,
|
||||||
|
reg_alloc::{FetchedDecodedMOp, reg_alloc},
|
||||||
|
register::{FlagsMode, PRegFlagsPowerISA},
|
||||||
|
unit::{GlobalState, UnitKind},
|
||||||
|
};
|
||||||
|
use fayalite::{
|
||||||
|
assert_export_firrtl,
|
||||||
|
firrtl::ExportOptions,
|
||||||
|
prelude::*,
|
||||||
|
sim::{Simulation, time::SimDuration, vcd::VcdWriterDecls},
|
||||||
|
util::RcWriter,
|
||||||
|
};
|
||||||
|
use std::num::NonZeroUsize;
|
||||||
|
|
||||||
|
//new test - much simpler
|
||||||
|
#[test]
|
||||||
|
fn test_main_memory() {
|
||||||
|
let mut config = CpuConfig::new(
|
||||||
|
vec![
|
||||||
|
UnitConfig::new(UnitKind::AluBranch),
|
||||||
|
UnitConfig::new(UnitKind::AluBranch),
|
||||||
|
],
|
||||||
|
NonZeroUsize::new(20).unwrap(),
|
||||||
|
);
|
||||||
|
// create a simulation from main_memory()
|
||||||
|
let mut sim = Simulation::new(main_memory(&config));
|
||||||
|
// add a .vcd writer that writes to main_memory.vcd -- this is simple for demo purposes,
|
||||||
|
// but for our actual code we should do better than just writing
|
||||||
|
// to main_memory.vcd in the repository's root
|
||||||
|
//WRONG: sim.add_trace_writer(std::fs::File::create("main_memory.vcd").unwrap());
|
||||||
|
|
||||||
|
let out_file = std::fs::File::create("main_memory.vcd").unwrap();
|
||||||
|
sim.add_trace_writer(VcdWriterDecls::new(out_file));
|
||||||
|
|
||||||
|
sim.write(sim.io().en, true);
|
||||||
|
sim.write(sim.io().cd.rst, false);
|
||||||
|
sim.write(sim.io().cd.clk, false);
|
||||||
|
sim.write(sim.io().write_en, false);
|
||||||
|
sim.write(sim.io().write_data, 0xFF00FF00FF00FF00u64);
|
||||||
|
|
||||||
|
// TODO convert to for loop
|
||||||
|
// you need to write an initial value to all inputs before you can start running the simulation
|
||||||
|
sim.write(sim.io().addr, 0x12345u64);
|
||||||
|
// now wait 1us because why not
|
||||||
|
sim.advance_time(SimDuration::from_micros(1)); //panic here at simulation
|
||||||
|
|
||||||
|
dbg!(sim.read(sim.io().read_data)); // dbg! macro just displays the value you pass to it
|
||||||
|
|
||||||
|
for n in 0u64..4u64 {
|
||||||
|
sim.write(sim.io().addr, n);
|
||||||
|
// now wait 1us because why not
|
||||||
|
sim.advance_time(SimDuration::from_micros(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
sim.write(sim.io().write_en, true);
|
||||||
|
sim.write(sim.io().addr, 0u64);
|
||||||
|
sim.write(sim.io().write_data, 0xFFFFFFFFFFFFFFFFu64); //fill with ones
|
||||||
|
|
||||||
|
sim.write_clock(sim.io().cd.clk, true);
|
||||||
|
sim.advance_time(SimDuration::from_micros(1));
|
||||||
|
sim.write_clock(sim.io().cd.clk, false);
|
||||||
|
sim.advance_time(SimDuration::from_micros(1));
|
||||||
|
|
||||||
|
sim.write(sim.io().addr, 1u64);
|
||||||
|
|
||||||
|
sim.write_clock(sim.io().cd.clk, true);
|
||||||
|
sim.advance_time(SimDuration::from_micros(1));
|
||||||
|
sim.write_clock(sim.io().cd.clk, false);
|
||||||
|
sim.advance_time(SimDuration::from_micros(1));
|
||||||
|
|
||||||
|
sim.write(sim.io().addr, 2u64);
|
||||||
|
|
||||||
|
sim.write_clock(sim.io().cd.clk, true);
|
||||||
|
sim.advance_time(SimDuration::from_micros(1));
|
||||||
|
sim.write_clock(sim.io().cd.clk, false);
|
||||||
|
sim.advance_time(SimDuration::from_micros(1));
|
||||||
|
|
||||||
|
sim.write(sim.io().addr, 3u64);
|
||||||
|
|
||||||
|
sim.write_clock(sim.io().cd.clk, true);
|
||||||
|
sim.advance_time(SimDuration::from_micros(1));
|
||||||
|
sim.write_clock(sim.io().cd.clk, false);
|
||||||
|
sim.advance_time(SimDuration::from_micros(1));
|
||||||
|
|
||||||
|
sim.flush_traces().unwrap(); // make sure everything is written to the output file
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -3,12 +3,14 @@
|
||||||
|
|
||||||
use cpu::{
|
use cpu::{
|
||||||
config::{CpuConfig, UnitConfig},
|
config::{CpuConfig, UnitConfig},
|
||||||
instruction::{AddSubMOp, LogicalMOp, Lut4, MOp, MOpDestReg, MOpRegNum, OutputIntegerMode},
|
instruction::{AddSubMOp, LogicalMOp, 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,
|
||||||
|
|
@ -59,7 +61,7 @@ fn test_reg_alloc() {
|
||||||
[HdlSome(()), HdlNone()],
|
[HdlSome(()), HdlNone()],
|
||||||
},
|
},
|
||||||
[0u8; 2],
|
[0u8; 2],
|
||||||
0x12345678u32.cast_to_static::<SInt<_>>(),
|
0x12345678u32.cast_to_static(),
|
||||||
OutputIntegerMode.DupLow32(),
|
OutputIntegerMode.DupLow32(),
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
|
@ -81,7 +83,7 @@ fn test_reg_alloc() {
|
||||||
[HdlSome(()), HdlNone()],
|
[HdlSome(()), HdlNone()],
|
||||||
},
|
},
|
||||||
[1u8, 0, 0],
|
[1u8, 0, 0],
|
||||||
1.cast_to_static::<SInt<_>>(),
|
1.cast_to_static(),
|
||||||
OutputIntegerMode.Full64(),
|
OutputIntegerMode.Full64(),
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
|
@ -99,9 +101,9 @@ fn test_reg_alloc() {
|
||||||
flag_regs: [HdlNone(), HdlSome(())],
|
flag_regs: [HdlNone(), HdlSome(())],
|
||||||
},
|
},
|
||||||
[2u8, 4u8],
|
[2u8, 4u8],
|
||||||
0.cast_to_static::<SInt<_>>(),
|
0.cast_to_static(),
|
||||||
OutputIntegerMode.Full64(),
|
OutputIntegerMode.Full64(),
|
||||||
Lut4::from_fn(|a, b| a ^ b),
|
0b0110_hdl_u4,
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
let insns = insns_init.into_iter().chain(insns_loop.into_iter().cycle());
|
let insns = insns_init.into_iter().chain(insns_loop.into_iter().cycle());
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,208 +0,0 @@
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
@ -1,158 +0,0 @@
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
@ -1,446 +0,0 @@
|
||||||
// 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,
|
|
||||||
),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
@ -1,103 +0,0 @@
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
@ -1,408 +0,0 @@
|
||||||
// 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,
|
|
||||||
),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
@ -1,163 +0,0 @@
|
||||||
// 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(),
|
|
||||||
),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
@ -1,525 +0,0 @@
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,273 +0,0 @@
|
||||||
// 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
|
|
@ -1,512 +0,0 @@
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,149 +0,0 @@
|
||||||
// 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(),
|
|
||||||
),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
// 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,7 +31,6 @@ 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()
|
||||||
{
|
{
|
||||||
|
|
@ -46,15 +45,12 @@ 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|*/.gitattributes|*.toml)
|
/.forgejo/workflows/*.yml|*/.gitignore|*.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