Compare commits
4 commits
master
...
wip-splitt
| Author | SHA1 | Date | |
|---|---|---|---|
| 921cddbe06 | |||
| b9d68c0019 | |||
| 9fa959652e | |||
| 9199fdf35c |
27 changed files with 2208 additions and 1134 deletions
77
.forgejo/workflows/deps.yml
Normal file
77
.forgejo/workflows/deps.yml
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
# See Notices.txt for copyright information
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
outputs:
|
||||||
|
cache-primary-key:
|
||||||
|
value: ${{ jobs.deps.outputs.cache-primary-key }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deps:
|
||||||
|
runs-on: debian-12
|
||||||
|
outputs:
|
||||||
|
cache-primary-key: ${{ steps.restore-deps.outputs.cache-primary-key }}
|
||||||
|
steps:
|
||||||
|
- uses: https://git.libre-chip.org/mirrors/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- uses: https://git.libre-chip.org/mirrors/cache/restore@v3
|
||||||
|
id: restore-deps
|
||||||
|
with:
|
||||||
|
path: deps
|
||||||
|
key: ${{ github.repository }}-deps-${{ runner.os }}-${{ hashFiles('.forgejo/workflows/deps.yml') }}
|
||||||
|
lookup-only: true
|
||||||
|
- name: Install Apt packages
|
||||||
|
if: steps.restore-deps.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
apt-get update -qq
|
||||||
|
apt-get install -qq \
|
||||||
|
bison \
|
||||||
|
build-essential \
|
||||||
|
ccache \
|
||||||
|
clang \
|
||||||
|
cvc5 \
|
||||||
|
flex \
|
||||||
|
gawk \
|
||||||
|
g++ \
|
||||||
|
git \
|
||||||
|
libboost-filesystem-dev \
|
||||||
|
libboost-python-dev \
|
||||||
|
libboost-system-dev \
|
||||||
|
libffi-dev \
|
||||||
|
libreadline-dev \
|
||||||
|
lld \
|
||||||
|
pkg-config \
|
||||||
|
python3 \
|
||||||
|
python3-click \
|
||||||
|
tcl-dev \
|
||||||
|
zlib1g-dev
|
||||||
|
- name: Install Firtool
|
||||||
|
if: steps.restore-deps.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
mkdir -p deps
|
||||||
|
wget -O deps/firrtl.tar.gz https://github.com/llvm/circt/releases/download/firtool-1.86.0/firrtl-bin-linux-x64.tar.gz
|
||||||
|
sha256sum -c - <<<'bf6f4ab18ae76f135c944efbd81e25391c31c1bd0617c58ab0592640abefee14 deps/firrtl.tar.gz'
|
||||||
|
tar -C deps -xvaf deps/firrtl.tar.gz
|
||||||
|
rm -rf deps/firtool
|
||||||
|
mv deps/firtool-1.86.0 deps/firtool
|
||||||
|
- name: Get SymbiYosys
|
||||||
|
if: steps.restore-deps.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
git clone --depth=1 --branch=yosys-0.45 https://git.libre-chip.org/mirrors/sby deps/sby
|
||||||
|
- name: Build Z3
|
||||||
|
if: steps.restore-deps.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
git clone --depth=1 --recursive --branch=z3-4.13.3 https://git.libre-chip.org/mirrors/z3 deps/z3
|
||||||
|
(cd deps/z3; PYTHON=python3 ./configure --prefix=/usr/local)
|
||||||
|
make -C deps/z3/build -j"$(nproc)"
|
||||||
|
- name: Build Yosys
|
||||||
|
if: steps.restore-deps.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
git clone --depth=1 --recursive --branch=0.45 https://git.libre-chip.org/mirrors/yosys deps/yosys
|
||||||
|
make -C deps/yosys -j"$(nproc)"
|
||||||
|
- uses: https://git.libre-chip.org/mirrors/cache/save@v3
|
||||||
|
if: steps.restore-deps.outputs.cache-hit != 'true'
|
||||||
|
with:
|
||||||
|
path: deps
|
||||||
|
key: ${{ steps.restore-deps.outputs.cache-primary-key }}
|
||||||
|
|
@ -3,16 +3,55 @@
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
deps:
|
||||||
|
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.82.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' }}
|
||||||
|
|
|
||||||
176
Cargo.lock
generated
176
Cargo.lock
generated
|
|
@ -1,6 +1,18 @@
|
||||||
# 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]]
|
||||||
|
name = "ahash"
|
||||||
|
version = "0.8.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"once_cell",
|
||||||
|
"version_check",
|
||||||
|
"zerocopy",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "allocator-api2"
|
name = "allocator-api2"
|
||||||
|
|
@ -81,12 +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 = "base64"
|
|
||||||
version = "0.22.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.6.0"
|
version = "2.6.0"
|
||||||
|
|
@ -166,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"
|
||||||
|
|
@ -210,6 +207,8 @@ name = "cpu"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fayalite",
|
"fayalite",
|
||||||
|
"name_mangling_serde",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -303,22 +302,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#edcc5927a5f9ebca6df5720bb1f5931e50095a57"
|
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#d453755bb2cd0b6f2340f3e49058d29a2ee279e8"
|
||||||
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",
|
||||||
"ordered-float",
|
"os_pipe",
|
||||||
"petgraph",
|
"petgraph",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
|
@ -330,7 +327,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#edcc5927a5f9ebca6df5720bb1f5931e50095a57"
|
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#d453755bb2cd0b6f2340f3e49058d29a2ee279e8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fayalite-proc-macros-impl",
|
"fayalite-proc-macros-impl",
|
||||||
]
|
]
|
||||||
|
|
@ -338,7 +335,7 @@ 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#edcc5927a5f9ebca6df5720bb1f5931e50095a57"
|
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#d453755bb2cd0b6f2340f3e49058d29a2ee279e8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base16ct",
|
"base16ct",
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
|
|
@ -353,7 +350,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#edcc5927a5f9ebca6df5720bb1f5931e50095a57"
|
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#d453755bb2cd0b6f2340f3e49058d29a2ee279e8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"prettyplease",
|
"prettyplease",
|
||||||
|
|
@ -371,12 +368,6 @@ 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 = "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"
|
||||||
|
|
@ -395,14 +386,13 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.3.4"
|
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 = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
|
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"r-efi",
|
"wasi",
|
||||||
"wasip2",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -410,16 +400,9 @@ name = "hashbrown"
|
||||||
version = "0.14.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 = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hashbrown"
|
|
||||||
version = "0.15.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"ahash",
|
||||||
"allocator-api2",
|
"allocator-api2",
|
||||||
"equivalent",
|
|
||||||
"foldhash",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -450,7 +433,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
|
checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown 0.14.5",
|
"hashbrown",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -468,16 +451,16 @@ 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",
|
"getrandom",
|
||||||
"libc",
|
"libc",
|
||||||
"scopeguard",
|
"scopeguard",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -498,6 +481,14 @@ 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 = "name_mangling_serde"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-bigint"
|
name = "num-bigint"
|
||||||
version = "0.4.6"
|
version = "0.4.6"
|
||||||
|
|
@ -533,26 +524,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
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]]
|
[[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]]
|
[[package]]
|
||||||
|
|
@ -583,37 +570,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]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.37"
|
version = "0.38.37"
|
||||||
|
|
@ -776,13 +738,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasip2"
|
name = "wasi"
|
||||||
version = "1.0.1+wasi-0.2.4"
|
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 = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7"
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
dependencies = [
|
|
||||||
"wit-bindgen",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "which"
|
name = "which"
|
||||||
|
|
@ -796,12 +755,6 @@ dependencies = [
|
||||||
"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"
|
||||||
|
|
@ -820,15 +773,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"
|
||||||
|
|
@ -899,12 +843,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"
|
||||||
|
|
@ -913,3 +851,23 @@ checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"tap",
|
"tap",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy"
|
||||||
|
version = "0.7.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||||
|
dependencies = [
|
||||||
|
"zerocopy-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy-derive"
|
||||||
|
version = "0.7.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,17 @@ members = ["crates/*"]
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
license = "LGPL-3.0-or-later"
|
license = "LGPL-3.0-or-later"
|
||||||
edition = "2024"
|
edition = "2021"
|
||||||
repository = ""
|
repository = ""
|
||||||
keywords = []
|
keywords = []
|
||||||
categories = []
|
categories = []
|
||||||
rust-version = "1.89.0"
|
rust-version = "1.82.0"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
|
name_mangling_serde = { version = "=0.1.0", path = "crates/name_mangling_serde" }
|
||||||
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" }
|
||||||
|
serde = { version = "1.0.202", features = ["derive"] }
|
||||||
|
serde_json = { version = "1.0.117", features = ["preserve_order"] }
|
||||||
|
|
||||||
[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,3 +16,8 @@ version.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
fayalite.workspace = true
|
fayalite.workspace = true
|
||||||
|
serde.workspace = true
|
||||||
|
name_mangling_serde.workspace = true
|
||||||
|
|
||||||
|
[lints.rust]
|
||||||
|
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(todo)'] }
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
../../README.md
|
|
||||||
|
|
@ -1,16 +1,17 @@
|
||||||
// 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 crate::{
|
use crate::{
|
||||||
instruction::{CONST_ZERO_UNIT_NUM, MOpTrait, PRegNum, RenamedMOp, UnitNum, UnitOutRegNum},
|
instruction::{PRegNum, CONST_ZERO_UNIT_NUM},
|
||||||
unit::{
|
unit::UnitKind,
|
||||||
UnitCancelInput, UnitKind, UnitOutputWrite,
|
|
||||||
unit_base::{UnitForwardingInfo, UnitToRegAlloc},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use fayalite::prelude::*;
|
use fayalite::{
|
||||||
|
intern::{Intern, Interned},
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct UnitConfig {
|
pub struct UnitConfig {
|
||||||
pub kind: UnitKind,
|
pub kind: UnitKind,
|
||||||
|
|
@ -27,15 +28,14 @@ impl UnitConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct CpuConfig {
|
pub struct CpuConfig {
|
||||||
pub units: Vec<UnitConfig>,
|
pub units: Interned<[UnitConfig]>,
|
||||||
pub out_reg_num_width: usize,
|
pub out_reg_num_width: usize,
|
||||||
pub fetch_width: NonZeroUsize,
|
pub fetch_width: 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,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CpuConfig {
|
impl CpuConfig {
|
||||||
|
|
@ -52,13 +52,12 @@ impl CpuConfig {
|
||||||
};
|
};
|
||||||
v
|
v
|
||||||
};
|
};
|
||||||
pub fn new(units: Vec<UnitConfig>, rob_size: NonZeroUsize) -> Self {
|
pub fn new(units: Interned<[UnitConfig]>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
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,
|
||||||
default_unit_max_in_flight: Self::DEFAULT_UNIT_MAX_IN_FLIGHT,
|
default_unit_max_in_flight: Self::DEFAULT_UNIT_MAX_IN_FLIGHT,
|
||||||
rob_size,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn non_const_unit_nums(&self) -> std::ops::Range<usize> {
|
pub fn non_const_unit_nums(&self) -> std::ops::Range<usize> {
|
||||||
|
|
@ -67,53 +66,83 @@ impl CpuConfig {
|
||||||
pub fn unit_num_width(&self) -> usize {
|
pub fn unit_num_width(&self) -> usize {
|
||||||
UInt::range(CONST_ZERO_UNIT_NUM..self.non_const_unit_nums().end).width()
|
UInt::range(CONST_ZERO_UNIT_NUM..self.non_const_unit_nums().end).width()
|
||||||
}
|
}
|
||||||
pub fn unit_num(&self) -> UnitNum<DynSize> {
|
|
||||||
UnitNum[self.unit_num_width()]
|
|
||||||
}
|
|
||||||
pub fn unit_out_reg_num(&self) -> UnitOutRegNum<DynSize> {
|
|
||||||
UnitOutRegNum[self.out_reg_num_width]
|
|
||||||
}
|
|
||||||
pub fn p_reg_num(&self) -> PRegNum<DynSize, DynSize> {
|
|
||||||
PRegNum[self.unit_num_width()][self.out_reg_num_width]
|
|
||||||
}
|
|
||||||
pub fn p_reg_num_width(&self) -> usize {
|
|
||||||
self.unit_num_width() + self.out_reg_num_width
|
|
||||||
}
|
|
||||||
pub fn renamed_mop_in_unit(&self) -> RenamedMOp<UnitOutRegNum<DynSize>, DynSize> {
|
|
||||||
RenamedMOp[self.unit_out_reg_num()][self.p_reg_num_width()]
|
|
||||||
}
|
|
||||||
pub fn unit_output_write(&self) -> UnitOutputWrite<DynSize> {
|
|
||||||
UnitOutputWrite[self.out_reg_num_width]
|
|
||||||
}
|
|
||||||
pub fn unit_output_writes(&self) -> Array<HdlOption<UnitOutputWrite<DynSize>>> {
|
|
||||||
Array[HdlOption[self.unit_output_write()]][self.non_const_unit_nums().len()]
|
|
||||||
}
|
|
||||||
pub fn unit_cancel_input(&self) -> UnitCancelInput<DynSize> {
|
|
||||||
UnitCancelInput[self.out_reg_num_width]
|
|
||||||
}
|
|
||||||
pub fn unit_forwarding_info(&self) -> UnitForwardingInfo<DynSize, DynSize, DynSize> {
|
|
||||||
UnitForwardingInfo[self.unit_num_width()][self.out_reg_num_width]
|
|
||||||
[self.non_const_unit_nums().len()]
|
|
||||||
}
|
|
||||||
pub fn unit_max_in_flight(&self, unit_index: usize) -> NonZeroUsize {
|
pub fn unit_max_in_flight(&self, unit_index: usize) -> NonZeroUsize {
|
||||||
self.units[unit_index]
|
self.units[unit_index]
|
||||||
.max_in_flight
|
.max_in_flight
|
||||||
.unwrap_or(self.default_unit_max_in_flight)
|
.unwrap_or(self.default_unit_max_in_flight)
|
||||||
}
|
}
|
||||||
pub fn unit_to_reg_alloc<
|
pub fn retire_queue_index_width(&self) -> usize {
|
||||||
MOp: Type + MOpTrait<DestReg = UnitOutRegNum<DynSize>, SrcRegWidth = DynSize>,
|
let max_in_flight: usize = (0..self.units.len())
|
||||||
ExtraOut: Type,
|
.map(|unit_index| self.unit_max_in_flight(unit_index).get())
|
||||||
>(
|
.sum();
|
||||||
&self,
|
2 + max_in_flight.next_power_of_two().ilog2() as usize
|
||||||
mop_ty: MOp,
|
|
||||||
extra_out_ty: ExtraOut,
|
|
||||||
) -> UnitToRegAlloc<MOp, ExtraOut, DynSize, DynSize, DynSize> {
|
|
||||||
assert_eq!(
|
|
||||||
mop_ty.dest_reg_ty(),
|
|
||||||
self.unit_out_reg_num(),
|
|
||||||
"inconsistent types",
|
|
||||||
);
|
|
||||||
UnitToRegAlloc[mop_ty][extra_out_ty][self.unit_num_width()][self.out_reg_num_width]
|
|
||||||
[self.non_const_unit_nums().len()]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod sealed {
|
||||||
|
pub trait Sealed {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl sealed::Sealed for PhantomConst<CpuConfig> {}
|
||||||
|
|
||||||
|
pub trait CpuConfigType: Type + ToExpr<Type = Self> + sealed::Sealed {
|
||||||
|
fn get(self) -> Interned<CpuConfig>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CpuConfigType for PhantomConst<CpuConfig> {
|
||||||
|
fn get(self) -> Interned<CpuConfig> {
|
||||||
|
self.get()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Identity<Arg: ?Sized> {
|
||||||
|
type SelfType: ?Sized;
|
||||||
|
type ArgType: ?Sized;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized, Arg: ?Sized> Identity<Arg> for T {
|
||||||
|
type SelfType = T;
|
||||||
|
type ArgType = Arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_cpu_config_accessors {
|
||||||
|
(
|
||||||
|
$(
|
||||||
|
#[without_generics = $without_generics:ident]
|
||||||
|
$vis:vis type $ident:ident<$T:ident> = |$arg:ident| $expr:expr;
|
||||||
|
)*
|
||||||
|
) => {
|
||||||
|
$(
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
$vis struct $without_generics;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
$vis const $ident: $without_generics = $without_generics;
|
||||||
|
|
||||||
|
$vis type $ident<$T> = <DynSize as Identity<$T>>::SelfType;
|
||||||
|
|
||||||
|
impl<$T: CpuConfigType> std::ops::Index<$T> for $without_generics {
|
||||||
|
type Output = usize;
|
||||||
|
|
||||||
|
fn index(&self, $arg: $T) -> &Self::Output {
|
||||||
|
Interned::into_inner(Intern::intern_sized($expr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_cpu_config_accessors! {
|
||||||
|
#[without_generics = __UnitNumWidth_WithoutGenerics]
|
||||||
|
pub type UnitNumWidth<T> = |arg| arg.get().unit_num_width();
|
||||||
|
#[without_generics = __UnitOutRegNumWidth_WithoutGenerics]
|
||||||
|
pub type UnitOutRegNumWidth<T> = |arg| arg.get().out_reg_num_width;
|
||||||
|
#[without_generics = __PRegNumWidth_WithoutGenerics]
|
||||||
|
pub type PRegNumWidth<T> = |arg| PRegNum[arg].canonical().bit_width();
|
||||||
|
#[without_generics = __RetireQueueIndexWidth_WithoutGenerics]
|
||||||
|
pub type RetireQueueIndexWidth<T> = |arg| arg.get().retire_queue_index_width();
|
||||||
|
#[without_generics = __UnitCount_WithoutGenerics]
|
||||||
|
pub type UnitCount<T> = |arg| arg.get().non_const_unit_nums().len();
|
||||||
|
#[without_generics = __FetchWidth_WithoutGenerics]
|
||||||
|
pub type FetchWidth<T> = |arg| arg.get().fetch_width.get();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,14 @@
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
use crate::{unit::UnitMOp, util::range_u32_len};
|
use crate::{
|
||||||
|
config::{CpuConfigType, UnitNumWidth, UnitOutRegNumWidth},
|
||||||
|
unit::UnitMOp,
|
||||||
|
util::range_u32_len,
|
||||||
|
};
|
||||||
use fayalite::{
|
use fayalite::{
|
||||||
expr::ops::{ArrayLiteral, ExprPartialEq},
|
expr::ops::{ArrayLiteral, ExprPartialEq},
|
||||||
intern::Interned,
|
intern::Interned,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
sim::value::SimValuePartialEq,
|
|
||||||
};
|
};
|
||||||
use std::{fmt, marker::PhantomData, ops::Range};
|
use std::{fmt, marker::PhantomData, ops::Range};
|
||||||
|
|
||||||
|
|
@ -26,7 +29,10 @@ impl<T: MOpTrait> MOpInto<T> for T {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait MOpTrait: Type {
|
pub trait MOpTrait: Type {
|
||||||
type Mapped<NewDestReg: Type, NewSrcRegWidth: Size>: MOpTrait<DestReg = NewDestReg, SrcRegWidth = NewSrcRegWidth>;
|
type Mapped<NewDestReg: Type, NewSrcRegWidth: Size>: MOpTrait<
|
||||||
|
DestReg = NewDestReg,
|
||||||
|
SrcRegWidth = NewSrcRegWidth,
|
||||||
|
>;
|
||||||
type DestReg: Type;
|
type DestReg: Type;
|
||||||
type SrcRegWidth: Size;
|
type SrcRegWidth: Size;
|
||||||
fn dest_reg_ty(self) -> Self::DestReg;
|
fn dest_reg_ty(self) -> Self::DestReg;
|
||||||
|
|
@ -71,11 +77,11 @@ pub trait CommonMOpTrait: MOpTrait {
|
||||||
type PrefixPad: KnownSize;
|
type PrefixPad: KnownSize;
|
||||||
type SrcCount: KnownSize;
|
type SrcCount: KnownSize;
|
||||||
type CommonMOpTraitMapped<NewDestReg: Type, NewSrcRegWidth: Size>: CommonMOpTrait<
|
type CommonMOpTraitMapped<NewDestReg: Type, NewSrcRegWidth: Size>: CommonMOpTrait<
|
||||||
DestReg = NewDestReg,
|
DestReg = NewDestReg,
|
||||||
SrcRegWidth = NewSrcRegWidth,
|
SrcRegWidth = NewSrcRegWidth,
|
||||||
PrefixPad = Self::PrefixPad,
|
PrefixPad = Self::PrefixPad,
|
||||||
SrcCount = Self::SrcCount,
|
SrcCount = Self::SrcCount,
|
||||||
>;
|
>;
|
||||||
type CommonMOpTraitDestReg: Type;
|
type CommonMOpTraitDestReg: Type;
|
||||||
type CommonMOpTraitSrcRegWidth: Size;
|
type CommonMOpTraitSrcRegWidth: Size;
|
||||||
fn common_mop_ty(
|
fn common_mop_ty(
|
||||||
|
|
@ -182,12 +188,6 @@ impl ExprPartialEq<Self> for OutputIntegerMode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SimValuePartialEq<Self> for OutputIntegerMode {
|
|
||||||
fn sim_value_eq(this: &SimValue<Self>, other: &SimValue<Self>) -> bool {
|
|
||||||
SimValue::opaque(this) == SimValue::opaque(other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const MOP_IMM_WIDTH: usize = 34;
|
pub const MOP_IMM_WIDTH: usize = 34;
|
||||||
pub const MOP_MIN_REG_WIDTH: usize = 8;
|
pub const MOP_MIN_REG_WIDTH: usize = 8;
|
||||||
pub const COMMON_MOP_SRC_LEN: usize = 3;
|
pub const COMMON_MOP_SRC_LEN: usize = 3;
|
||||||
|
|
@ -809,19 +809,21 @@ common_mop_struct! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl(cmp_eq)]
|
#[hdl(cmp_eq, no_static)]
|
||||||
/// there may be more than one unit of a given kind, so UnitNum is not the same as UnitKind.
|
/// there may be more than one unit of a given kind, so UnitNum is not the same as UnitKind.
|
||||||
/// zero is used for built-in constants, such as the zero register
|
/// zero is used for built-in constants, such as the zero register
|
||||||
pub struct UnitNum<Width: Size> {
|
pub struct UnitNum<C: Type + CpuConfigType> {
|
||||||
pub adj_value: UIntType<Width>,
|
pub adj_value: UIntType<UnitNumWidth<C>>,
|
||||||
|
pub config: C,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Width: Size> UnitNum<Width> {
|
impl<C: Type + CpuConfigType> UnitNum<C> {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
pub fn const_zero(self) -> Expr<Self> {
|
pub fn const_zero(self) -> Expr<Self> {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
UnitNum {
|
UnitNum {
|
||||||
adj_value: CONST_ZERO_UNIT_NUM.cast_to(self.adj_value),
|
adj_value: CONST_ZERO_UNIT_NUM.cast_to(self.adj_value),
|
||||||
|
config: self.config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -829,6 +831,7 @@ impl<Width: Size> UnitNum<Width> {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
UnitNum {
|
UnitNum {
|
||||||
adj_value: (index + 1).cast_to(self.adj_value),
|
adj_value: (index + 1).cast_to(self.adj_value),
|
||||||
|
config: self.config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn is_index(expr: impl ToExpr<Type = Self>, index: usize) -> Expr<Bool> {
|
pub fn is_index(expr: impl ToExpr<Type = Self>, index: usize) -> Expr<Bool> {
|
||||||
|
|
@ -839,7 +842,7 @@ impl<Width: Size> UnitNum<Width> {
|
||||||
.cmp_eq(expr.adj_value)
|
.cmp_eq(expr.adj_value)
|
||||||
}
|
}
|
||||||
#[hdl]
|
#[hdl]
|
||||||
pub fn as_index(expr: impl ToExpr<Type = Self>) -> Expr<HdlOption<UIntType<Width>>> {
|
pub fn as_index(expr: impl ToExpr<Type = Self>) -> Expr<HdlOption<UIntType<DynSize>>> {
|
||||||
let expr = expr.to_expr();
|
let expr = expr.to_expr();
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let unit_index = wire(HdlOption[Expr::ty(expr).adj_value]);
|
let unit_index = wire(HdlOption[Expr::ty(expr).adj_value]);
|
||||||
|
|
@ -857,19 +860,20 @@ impl<Width: Size> UnitNum<Width> {
|
||||||
|
|
||||||
pub const CONST_ZERO_UNIT_NUM: usize = 0;
|
pub const CONST_ZERO_UNIT_NUM: usize = 0;
|
||||||
|
|
||||||
#[hdl(cmp_eq)]
|
#[hdl(cmp_eq, no_static)]
|
||||||
pub struct UnitOutRegNum<Width: Size> {
|
pub struct UnitOutRegNum<C: Type + CpuConfigType> {
|
||||||
pub value: UIntType<Width>,
|
pub value: UIntType<UnitOutRegNumWidth<C>>,
|
||||||
|
pub config: C,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl(cmp_eq)]
|
#[hdl(cmp_eq, no_static)]
|
||||||
/// Physical Register Number -- registers in the CPU's backend
|
/// Physical Register Number -- registers in the CPU's backend
|
||||||
pub struct PRegNum<UnitNumWidth: Size, OutRegNumWidth: Size> {
|
pub struct PRegNum<C: Type + CpuConfigType> {
|
||||||
pub unit_num: UnitNum<UnitNumWidth>,
|
pub unit_num: UnitNum<C>,
|
||||||
pub unit_out_reg: UnitOutRegNum<OutRegNumWidth>,
|
pub unit_out_reg: UnitOutRegNum<C>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<UnitNumWidth: Size, OutRegNumWidth: Size> PRegNum<UnitNumWidth, OutRegNumWidth> {
|
impl<C: Type + CpuConfigType> PRegNum<C> {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
pub fn const_zero(self) -> Expr<Self> {
|
pub fn const_zero(self) -> Expr<Self> {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -878,6 +882,7 @@ impl<UnitNumWidth: Size, OutRegNumWidth: Size> PRegNum<UnitNumWidth, OutRegNumWi
|
||||||
unit_out_reg: #[hdl]
|
unit_out_reg: #[hdl]
|
||||||
UnitOutRegNum {
|
UnitOutRegNum {
|
||||||
value: 0u8.cast_to(self.unit_out_reg.value),
|
value: 0u8.cast_to(self.unit_out_reg.value),
|
||||||
|
config: self.unit_out_reg.config,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -914,11 +919,9 @@ impl MOpRegNum {
|
||||||
//
|
//
|
||||||
// TODO: maybe add more registers later.
|
// TODO: maybe add more registers later.
|
||||||
pub const FLAG_REG_NUMS: Range<u32> = 0xFE..0x100;
|
pub const FLAG_REG_NUMS: Range<u32> = 0xFE..0x100;
|
||||||
/// registers handled by a special small rename table (for flags and stuff, since it has more read/write ports)
|
/// registers that aren't constants
|
||||||
pub const SPECIAL_REG_NUMS: Range<u32> = Self::FLAG_REG_NUMS;
|
pub const NON_CONST_REG_NUMS: Range<u32> =
|
||||||
/// registers handled by the large rename table for normal registers (has less read/write ports)
|
Self::CONST_ZERO_REG_NUM + 1..Self::FLAG_REG_NUMS.end;
|
||||||
pub const NORMAL_REG_NUMS: Range<u32> =
|
|
||||||
Self::CONST_ZERO_REG_NUM + 1..Self::SPECIAL_REG_NUMS.start;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl(cmp_eq)]
|
#[hdl(cmp_eq)]
|
||||||
|
|
@ -933,29 +936,6 @@ pub struct MOpDestReg {
|
||||||
pub flag_regs: Array<HdlOption<()>, { range_u32_len(&MOpRegNum::FLAG_REG_NUMS) }>,
|
pub flag_regs: Array<HdlOption<()>, { range_u32_len(&MOpRegNum::FLAG_REG_NUMS) }>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
|
|
||||||
pub enum RenameTableName {
|
|
||||||
/// the large rename table for normal registers (has less read/write ports)
|
|
||||||
Normal,
|
|
||||||
/// a special small rename table (for flags and stuff, since it has more read/write ports)
|
|
||||||
Special,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RenameTableName {
|
|
||||||
pub const fn reg_range(self) -> std::ops::Range<u32> {
|
|
||||||
match self {
|
|
||||||
Self::Normal => MOpRegNum::NORMAL_REG_NUMS,
|
|
||||||
Self::Special => MOpRegNum::SPECIAL_REG_NUMS,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub const fn as_str(self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
Self::Normal => "rename_table_normal",
|
|
||||||
Self::Special => "rename_table_special",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
|
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
|
||||||
pub enum MOpDestRegKind {
|
pub enum MOpDestRegKind {
|
||||||
NormalReg {
|
NormalReg {
|
||||||
|
|
@ -993,16 +973,13 @@ impl fmt::Display for MOpDestRegName {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MOpDestRegKind {
|
impl MOpDestRegKind {
|
||||||
pub const fn reg_range(self) -> std::ops::Range<u32> {
|
pub const fn reg_num_range(self) -> std::ops::Range<u32> {
|
||||||
match self {
|
match self {
|
||||||
Self::NormalReg { .. } => MOpRegNum::NORMAL_REG_NUMS,
|
Self::NormalReg { dest_reg_index: _ } => MOpRegNum::NON_CONST_REG_NUMS,
|
||||||
Self::FlagReg { .. } => MOpRegNum::FLAG_REG_NUMS,
|
Self::FlagReg {
|
||||||
}
|
reg_num,
|
||||||
}
|
flag_reg_index: _,
|
||||||
pub const fn rename_table_names(self) -> &'static [RenameTableName] {
|
} => reg_num..reg_num + 1,
|
||||||
match self {
|
|
||||||
Self::NormalReg { .. } => &[RenameTableName::Normal, RenameTableName::Special],
|
|
||||||
Self::FlagReg { .. } => &[RenameTableName::Special],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn fixed_reg_num(self) -> Option<u32> {
|
pub fn fixed_reg_num(self) -> Option<u32> {
|
||||||
|
|
@ -1095,5 +1072,5 @@ pub type MOp = UnitMOp<
|
||||||
>;
|
>;
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
pub type RenamedMOp<DestReg: Type, SrcRegWidth: Size> =
|
pub type RenamedMOp<SrcRegWidth: Size> =
|
||||||
UnitMOp<DestReg, SrcRegWidth, L2RegisterFileMOp<DestReg, SrcRegWidth>>;
|
UnitMOp<(), SrcRegWidth, L2RegisterFileMOp<(), SrcRegWidth>>;
|
||||||
|
|
|
||||||
261
crates/cpu/src/instruction_rename.rs
Normal file
261
crates/cpu/src/instruction_rename.rs
Normal file
|
|
@ -0,0 +1,261 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
config::{CpuConfig, CpuConfigType, FetchWidth, PRegNumWidth},
|
||||||
|
instruction::{MOp, MOpDestReg, MOpRegNum, MOpTrait, MoveRegMOp, PRegNum, RenamedMOp},
|
||||||
|
rename_table::{rename_table, RenameTablePortConfig},
|
||||||
|
unit::{RenamedInsnData, RetireQueueIndex, UnitMOp},
|
||||||
|
util::array_vec::{ArrayVec, Length, ReadyValidArray},
|
||||||
|
};
|
||||||
|
use fayalite::{
|
||||||
|
prelude::*,
|
||||||
|
util::{prefix_sum::PrefixSumAlgorithm, ready_valid::ReadyValid},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[hdl(no_static)]
|
||||||
|
pub struct InstructionRenameInputInsn<C: Type + CpuConfigType> {
|
||||||
|
pub mop: MOp,
|
||||||
|
pub pc: UInt<64>,
|
||||||
|
pub renamed_dest: PRegNum<C>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl(no_static)]
|
||||||
|
struct InsnsInPrefixSummary<C: Type + CpuConfigType> {
|
||||||
|
all_ready: Bool,
|
||||||
|
ready_count: Length<FetchWidth<C>>,
|
||||||
|
retire_queue_used: Length<FetchWidth<C>>,
|
||||||
|
config: C,
|
||||||
|
}
|
||||||
|
|
||||||
|
type C = PhantomConst<CpuConfig>;
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
pub type InstructionRenameInsnsOut<C: Type + CpuConfigType> = ArrayType<
|
||||||
|
ReadyValid<RenamedInsnData<C, RenamedMOp<PRegNumWidth<C>>, PRegNum<C>>>,
|
||||||
|
FetchWidth<C>,
|
||||||
|
>;
|
||||||
|
|
||||||
|
#[hdl_module]
|
||||||
|
pub fn instruction_rename(config: PhantomConst<CpuConfig>) {
|
||||||
|
#[hdl]
|
||||||
|
let cd: ClockDomain = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let insns_in: ReadyValidArray<InstructionRenameInputInsn<C>, FetchWidth<C>> =
|
||||||
|
m.input(ReadyValidArray[InstructionRenameInputInsn[config]][FetchWidth[config]]);
|
||||||
|
#[hdl]
|
||||||
|
let start_retire_queue_index: RetireQueueIndex<C> = m.input(RetireQueueIndex[config]);
|
||||||
|
#[hdl]
|
||||||
|
let end_retire_queue_index: RetireQueueIndex<C> = m.output(RetireQueueIndex[config]);
|
||||||
|
#[hdl]
|
||||||
|
let insns_out: InstructionRenameInsnsOut<C> = m.output(InstructionRenameInsnsOut[config]);
|
||||||
|
|
||||||
|
// TODO: handle resetting table after cancelling instructions
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
let insns_ready_or_move = wire(ArrayType[Bool][FetchWidth[config]]);
|
||||||
|
|
||||||
|
for (insn_ready_or_move, insn_out) in insns_ready_or_move.into_iter().zip(insns_out) {
|
||||||
|
connect(insn_ready_or_move, insn_out.ready);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayVec::for_each(insns_in.data, |fetch_index, input_insn| {
|
||||||
|
#[hdl]
|
||||||
|
match input_insn.mop {
|
||||||
|
UnitMOp::<_, _, _>::TransformedMove(_) => {
|
||||||
|
connect(insns_ready_or_move[fetch_index], true);
|
||||||
|
}
|
||||||
|
UnitMOp::<_, _, _>::AluBranch(_) | UnitMOp::<_, _, _>::LoadStore(_) => {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let insns_in_prefix_summary_ty = InsnsInPrefixSummary[config];
|
||||||
|
#[hdl]
|
||||||
|
let insns_in_prefix_summaries = wire(ArrayType[insns_in_prefix_summary_ty][FetchWidth[config]]);
|
||||||
|
let insns_in_prefix_summaries_vec = PrefixSumAlgorithm::WorkEfficient.run(
|
||||||
|
(0..FetchWidth[config]).map(|fetch_index| {
|
||||||
|
#[hdl]
|
||||||
|
let insns_in_prefix_summary_in = wire(insns_in_prefix_summary_ty);
|
||||||
|
#[hdl]
|
||||||
|
let InsnsInPrefixSummary::<_> {
|
||||||
|
all_ready,
|
||||||
|
ready_count,
|
||||||
|
retire_queue_used,
|
||||||
|
config: _,
|
||||||
|
} = insns_in_prefix_summary_in;
|
||||||
|
connect(all_ready, insns_out[fetch_index].ready);
|
||||||
|
connect(
|
||||||
|
ready_count,
|
||||||
|
Expr::ty(ready_count).cast_from_uint_unchecked(all_ready.cast_to(UInt[1])),
|
||||||
|
);
|
||||||
|
connect(retire_queue_used, Expr::ty(retire_queue_used).zero());
|
||||||
|
#[hdl]
|
||||||
|
if let HdlSome(input_insn) = ArrayVec::get(insns_in.data, fetch_index) {
|
||||||
|
connect(retire_queue_used, ready_count);
|
||||||
|
#[hdl]
|
||||||
|
match input_insn.mop {
|
||||||
|
UnitMOp::<_, _, _>::TransformedMove(_) => {
|
||||||
|
connect(all_ready, true);
|
||||||
|
}
|
||||||
|
UnitMOp::<_, _, _>::AluBranch(_) | UnitMOp::<_, _, _>::LoadStore(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
insns_in_prefix_summary_in
|
||||||
|
}),
|
||||||
|
|l, r| {
|
||||||
|
#[hdl]
|
||||||
|
let insns_in_prefix_summary_merge = wire(insns_in_prefix_summary_ty);
|
||||||
|
#[hdl]
|
||||||
|
let InsnsInPrefixSummary::<_> {
|
||||||
|
all_ready,
|
||||||
|
ready_count,
|
||||||
|
retire_queue_used,
|
||||||
|
config: _,
|
||||||
|
} = insns_in_prefix_summary_merge;
|
||||||
|
connect(all_ready, l.all_ready & r.all_ready);
|
||||||
|
#[hdl]
|
||||||
|
if l.all_ready {
|
||||||
|
connect(
|
||||||
|
ready_count,
|
||||||
|
Expr::ty(ready_count).cast_from_uint_unchecked(
|
||||||
|
Length::as_uint(l.ready_count) + Length::as_uint(r.ready_count),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
connect(
|
||||||
|
retire_queue_used,
|
||||||
|
Expr::ty(retire_queue_used).cast_from_uint_unchecked(
|
||||||
|
Length::as_uint(l.retire_queue_used) + Length::as_uint(r.retire_queue_used),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
connect(ready_count, l.ready_count);
|
||||||
|
connect(retire_queue_used, l.retire_queue_used);
|
||||||
|
}
|
||||||
|
insns_in_prefix_summary_merge
|
||||||
|
},
|
||||||
|
);
|
||||||
|
for (l, r) in insns_in_prefix_summaries
|
||||||
|
.into_iter()
|
||||||
|
.zip(insns_in_prefix_summaries_vec)
|
||||||
|
{
|
||||||
|
connect(l, r);
|
||||||
|
}
|
||||||
|
connect(
|
||||||
|
insns_in.ready,
|
||||||
|
insns_in_prefix_summaries[FetchWidth[config] - 1].ready_count,
|
||||||
|
);
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
let retire_queue_indexes = wire(Array[RetireQueueIndex[config]][FetchWidth[config] + 1]);
|
||||||
|
connect(retire_queue_indexes[0], start_retire_queue_index);
|
||||||
|
connect(
|
||||||
|
end_retire_queue_index,
|
||||||
|
retire_queue_indexes[FetchWidth[config]],
|
||||||
|
);
|
||||||
|
for (retire_queue_index, insns_in_prefix_summary) in retire_queue_indexes
|
||||||
|
.into_iter()
|
||||||
|
.skip(1)
|
||||||
|
.zip(insns_in_prefix_summaries)
|
||||||
|
{
|
||||||
|
connect_any(
|
||||||
|
retire_queue_index.index,
|
||||||
|
start_retire_queue_index.index
|
||||||
|
+ Length::as_uint(insns_in_prefix_summary.retire_queue_used),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut port_configs = Vec::new();
|
||||||
|
let mut src_reg_count = 0;
|
||||||
|
MOpTrait::for_each_src_reg(MOp.uninit(), &mut |_, src_index| {
|
||||||
|
src_reg_count = src_reg_count.max(src_index + 1);
|
||||||
|
});
|
||||||
|
for _ in 0..FetchWidth[config] {
|
||||||
|
for _ in 0..src_reg_count {
|
||||||
|
port_configs.push(RenameTablePortConfig::Read {
|
||||||
|
addr_range: MOpRegNum::NON_CONST_REG_NUMS,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for dest_reg_kind in MOpDestReg::REG_KINDS {
|
||||||
|
port_configs.push(RenameTablePortConfig::Write {
|
||||||
|
addr_range: dest_reg_kind.reg_num_range(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
let rename_table = instance(rename_table(config, &port_configs));
|
||||||
|
|
||||||
|
connect(rename_table.cd, cd);
|
||||||
|
|
||||||
|
for read_port in rename_table.read_ports {
|
||||||
|
connect_any(read_port.addr, 0_hdl_u0);
|
||||||
|
}
|
||||||
|
for write_port in rename_table.write_ports {
|
||||||
|
connect_any(write_port.addr, 0_hdl_u0);
|
||||||
|
connect_any(write_port.data, PRegNum[config].const_zero());
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayVec::for_each(
|
||||||
|
ReadyValidArray::firing_data(insns_in),
|
||||||
|
|fetch_index, input_insn| {
|
||||||
|
let read_port_index = fetch_index * src_reg_count;
|
||||||
|
let write_port_index = fetch_index * MOpDestReg::REG_COUNT;
|
||||||
|
#[hdl]
|
||||||
|
let InstructionRenameInputInsn::<_> {
|
||||||
|
mop,
|
||||||
|
pc,
|
||||||
|
renamed_dest,
|
||||||
|
} = input_insn;
|
||||||
|
let insn_out =
|
||||||
|
MOpTrait::map_regs(mop, (), PRegNumWidth[config], &mut |src_reg, src_index| {
|
||||||
|
connect(
|
||||||
|
rename_table.read_ports[read_port_index + src_index].addr,
|
||||||
|
src_reg.cast_bits_to(MOpRegNum),
|
||||||
|
);
|
||||||
|
rename_table.read_ports[read_port_index + src_index]
|
||||||
|
.data
|
||||||
|
.cast_to_bits()
|
||||||
|
});
|
||||||
|
for (i, dest_reg) in MOpDestReg::regs(MOpTrait::dest_reg(mop))
|
||||||
|
.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
{
|
||||||
|
connect(
|
||||||
|
rename_table.write_ports[write_port_index + i].addr,
|
||||||
|
dest_reg,
|
||||||
|
);
|
||||||
|
connect(
|
||||||
|
rename_table.write_ports[write_port_index + i].data,
|
||||||
|
renamed_dest,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let insn_out = UnitMOp::try_with_transformed_move_op(
|
||||||
|
insn_out,
|
||||||
|
RenamedMOp[PRegNumWidth[config]].TransformedMove,
|
||||||
|
|insn_out: Expr<HdlOption<_>>, move_reg: Expr<MoveRegMOp<_, _>>| {
|
||||||
|
for i in 0..MOpDestReg::REG_COUNT {
|
||||||
|
// execute move by using same PRegNum as src[0] for dest
|
||||||
|
connect(
|
||||||
|
rename_table.write_ports[write_port_index + i].data,
|
||||||
|
move_reg.common.src[0].cast_bits_to(PRegNum[config]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// move already executed, so remove it
|
||||||
|
connect(insn_out, Expr::ty(insn_out).HdlNone());
|
||||||
|
},
|
||||||
|
);
|
||||||
|
connect(
|
||||||
|
insns_out[fetch_index].data,
|
||||||
|
HdlOption::map(insn_out, |insn_out| {
|
||||||
|
#[hdl]
|
||||||
|
RenamedInsnData::<_, _, _> {
|
||||||
|
retire_queue_index: retire_queue_indexes[fetch_index],
|
||||||
|
pc,
|
||||||
|
dest: renamed_dest,
|
||||||
|
mop: insn_out,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,10 @@
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod instruction;
|
pub mod instruction;
|
||||||
|
pub mod instruction_rename;
|
||||||
pub mod reg_alloc;
|
pub mod reg_alloc;
|
||||||
pub mod register;
|
pub mod register;
|
||||||
|
pub mod rename_table;
|
||||||
|
pub mod retire_queue;
|
||||||
pub mod unit;
|
pub mod unit;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
|
|
||||||
|
|
@ -3,18 +3,18 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
config::CpuConfig,
|
config::CpuConfig,
|
||||||
instruction::{
|
instruction::{
|
||||||
COMMON_MOP_SRC_LEN, MOp, MOpDestReg, MOpRegNum, MOpTrait, MoveRegMOp, PRegNum,
|
MOp, MOpDestReg, MOpRegNum, MOpTrait, MoveRegMOp, PRegNum, UnitOutRegNum,
|
||||||
RenameTableName, UnitOutRegNum,
|
COMMON_MOP_SRC_LEN,
|
||||||
},
|
},
|
||||||
unit::{
|
unit::{
|
||||||
GlobalState, TrapData, UnitMOp, UnitOutput, UnitOutputWrite, UnitResult,
|
GlobalState, TrapData, UnitMOp, UnitOutput, UnitOutputWrite, UnitResult,
|
||||||
UnitResultCompleted, UnitTrait,
|
UnitResultCompleted, UnitTrait,
|
||||||
unit_base::{UnitForwardingInfo, UnitInput},
|
|
||||||
},
|
},
|
||||||
util::tree_reduce::tree_reduce_with_state,
|
util::array_vec::ReadyValidArray,
|
||||||
};
|
};
|
||||||
use fayalite::{
|
use fayalite::{
|
||||||
memory::{WriteStruct, splat_mask},
|
int::BoolOrIntType,
|
||||||
|
memory::{splat_mask, WriteStruct},
|
||||||
module::{instance_with_loc, memory_with_loc, wire_with_loc},
|
module::{instance_with_loc, memory_with_loc, wire_with_loc},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
util::ready_valid::ReadyValid,
|
util::ready_valid::ReadyValid,
|
||||||
|
|
@ -44,150 +44,12 @@ pub enum FetchDecodeSpecialOp {
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
pub struct FetchDecodeInterface<FetchWidth: Size> {
|
pub struct FetchDecodeInterface<FetchWidth: Size> {
|
||||||
pub decoded_insns: ArrayType<ReadyValid<FetchedDecodedMOp>, FetchWidth>,
|
pub decoded_insns: ReadyValidArray<FetchedDecodedMOp, FetchWidth>,
|
||||||
#[hdl(flip)]
|
#[hdl(flip)]
|
||||||
pub fetch_decode_special_op: ReadyValid<FetchDecodeSpecialOp>,
|
pub fetch_decode_special_op: ReadyValid<FetchDecodeSpecialOp>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl]
|
#[cfg(todo)]
|
||||||
struct ROBRenamedInsn<UnitNumWidth: Size, OutRegNumWidth: Size> {
|
|
||||||
mop_dest: MOpDestReg,
|
|
||||||
p_dest: PRegNum<UnitNumWidth, OutRegNumWidth>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[hdl]
|
|
||||||
struct ROBEntry<UnitNumWidth: Size, OutRegNumWidth: Size> {
|
|
||||||
renamed_insn: ROBRenamedInsn<UnitNumWidth, OutRegNumWidth>,
|
|
||||||
dest_written: Bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[hdl_module]
|
|
||||||
fn rob(config: &CpuConfig) {
|
|
||||||
#[hdl]
|
|
||||||
let cd: ClockDomain = m.input();
|
|
||||||
#[hdl]
|
|
||||||
let renamed_insns_in: Array<ReadyValid<ROBRenamedInsn<DynSize, DynSize>>> = m.input(
|
|
||||||
Array[ReadyValid[ROBRenamedInsn[config.unit_num_width()][config.out_reg_num_width]]]
|
|
||||||
[config.fetch_width.get()],
|
|
||||||
);
|
|
||||||
#[hdl]
|
|
||||||
let unit_forwarding_info: UnitForwardingInfo<DynSize, DynSize, DynSize> =
|
|
||||||
m.input(config.unit_forwarding_info());
|
|
||||||
|
|
||||||
let rob_entry_ty = ROBEntry[config.unit_num_width()][config.out_reg_num_width];
|
|
||||||
#[hdl]
|
|
||||||
let rob = reg_builder()
|
|
||||||
.clock_domain(cd)
|
|
||||||
.no_reset(Array[rob_entry_ty][config.rob_size.get()]);
|
|
||||||
#[hdl]
|
|
||||||
let rob_valid_start = reg_builder()
|
|
||||||
.clock_domain(cd)
|
|
||||||
.reset(UInt::range(0..config.rob_size.get()).zero());
|
|
||||||
#[hdl]
|
|
||||||
let rob_valid_end = reg_builder()
|
|
||||||
.clock_domain(cd)
|
|
||||||
.reset(UInt::range(0..config.rob_size.get()).zero());
|
|
||||||
#[hdl]
|
|
||||||
let free_space = wire(UInt::range_inclusive(0..=config.rob_size.get()));
|
|
||||||
#[hdl]
|
|
||||||
if rob_valid_end.cmp_lt(rob_valid_start) {
|
|
||||||
// rob_valid_end wrapped around but start didn't
|
|
||||||
connect_any(
|
|
||||||
free_space,
|
|
||||||
rob_valid_end + config.rob_size.get() - rob_valid_start,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
connect_any(free_space, rob_valid_end - rob_valid_start);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct IndexAndRange {
|
|
||||||
index: Expr<UInt>,
|
|
||||||
range: std::ops::Range<usize>,
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut next_write_index = IndexAndRange {
|
|
||||||
index: rob_valid_end,
|
|
||||||
range: 0..config.rob_size.get(),
|
|
||||||
};
|
|
||||||
for fetch_index in 0..config.fetch_width.get() {
|
|
||||||
let write_index = next_write_index;
|
|
||||||
let next_write_index_range = write_index.range.start..write_index.range.end + 1;
|
|
||||||
next_write_index = IndexAndRange {
|
|
||||||
index: wire_with_loc(
|
|
||||||
&format!("next_write_index_{fetch_index}"),
|
|
||||||
SourceLocation::caller(),
|
|
||||||
UInt::range(next_write_index_range.clone()),
|
|
||||||
),
|
|
||||||
range: next_write_index_range,
|
|
||||||
};
|
|
||||||
connect(
|
|
||||||
renamed_insns_in[fetch_index].ready,
|
|
||||||
fetch_index.cmp_lt(free_space),
|
|
||||||
);
|
|
||||||
#[hdl]
|
|
||||||
if let HdlSome(renamed_insn) = ReadyValid::firing_data(renamed_insns_in[fetch_index]) {
|
|
||||||
for i in write_index.range.clone() {
|
|
||||||
#[hdl]
|
|
||||||
if write_index.index.cmp_eq(i) {
|
|
||||||
connect(
|
|
||||||
rob[i % config.rob_size.get()],
|
|
||||||
#[hdl]
|
|
||||||
ROBEntry {
|
|
||||||
renamed_insn,
|
|
||||||
dest_written: false,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO: optimize write_index chain better
|
|
||||||
connect_any(
|
|
||||||
next_write_index.index,
|
|
||||||
write_index.index
|
|
||||||
+ ReadyValid::firing(renamed_insns_in[fetch_index]).cast_to_static::<UInt<1>>(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
assert!(
|
|
||||||
config.rob_size >= config.fetch_width,
|
|
||||||
"rob_size ({}) is too small for fetch_width = {} -- next_write_index would overflow",
|
|
||||||
config.rob_size,
|
|
||||||
config.fetch_width,
|
|
||||||
);
|
|
||||||
#[hdl]
|
|
||||||
if next_write_index.index.cmp_lt(config.rob_size.get()) {
|
|
||||||
connect_any(rob_valid_end, next_write_index.index);
|
|
||||||
} else {
|
|
||||||
connect_any(
|
|
||||||
rob_valid_end,
|
|
||||||
next_write_index.index - config.rob_size.get(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: optimize better, O(rob_size * unit_count) is too big here
|
|
||||||
for rob_index in 0..config.rob_size.get() {
|
|
||||||
for unit_index in 0..config.non_const_unit_nums().len() {
|
|
||||||
#[hdl]
|
|
||||||
if let HdlSome(unit_output_write) = unit_forwarding_info.unit_output_writes[unit_index]
|
|
||||||
{
|
|
||||||
#[hdl]
|
|
||||||
let UnitOutputWrite::<_> {
|
|
||||||
which: unit_out_reg,
|
|
||||||
value: _,
|
|
||||||
} = unit_output_write;
|
|
||||||
let p_reg_num = #[hdl]
|
|
||||||
PRegNum::<_, _> {
|
|
||||||
unit_num: config.unit_num().from_index(unit_index),
|
|
||||||
unit_out_reg,
|
|
||||||
};
|
|
||||||
#[hdl]
|
|
||||||
if rob[rob_index].renamed_insn.p_dest.cmp_eq(p_reg_num) {
|
|
||||||
connect(rob[rob_index].dest_written, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[hdl_module]
|
#[hdl_module]
|
||||||
/// combination register allocator, register renaming, unit selection, and retire handling
|
/// combination register allocator, register renaming, unit selection, and retire handling
|
||||||
pub fn reg_alloc(config: &CpuConfig) {
|
pub fn reg_alloc(config: &CpuConfig) {
|
||||||
|
|
@ -205,10 +67,6 @@ pub fn reg_alloc(config: &CpuConfig) {
|
||||||
);
|
);
|
||||||
// TODO: finish
|
// TODO: finish
|
||||||
|
|
||||||
#[hdl]
|
|
||||||
let rob = instance(rob(config));
|
|
||||||
connect(rob.cd, cd);
|
|
||||||
|
|
||||||
let mut rename_table_mems = BTreeMap::<RenameTableName, MemBuilder<_>>::new();
|
let mut rename_table_mems = BTreeMap::<RenameTableName, MemBuilder<_>>::new();
|
||||||
|
|
||||||
for reg_kind in MOpDestReg::REG_KINDS {
|
for reg_kind in MOpDestReg::REG_KINDS {
|
||||||
|
|
@ -238,11 +96,6 @@ pub fn reg_alloc(config: &CpuConfig) {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let renamed_mops_out_reg = wire(Array[HdlOption[config.p_reg_num()]][config.fetch_width.get()]);
|
let renamed_mops_out_reg = wire(Array[HdlOption[config.p_reg_num()]][config.fetch_width.get()]);
|
||||||
for fetch_index in 0..config.fetch_width.get() {
|
for fetch_index in 0..config.fetch_width.get() {
|
||||||
// TODO: finish
|
|
||||||
connect(
|
|
||||||
rob.renamed_insns_in[fetch_index].data,
|
|
||||||
Expr::ty(rob).renamed_insns_in.element().data.HdlNone(),
|
|
||||||
);
|
|
||||||
// TODO: finish
|
// TODO: finish
|
||||||
connect(
|
connect(
|
||||||
fetch_decode_interface.decoded_insns[fetch_index].ready,
|
fetch_decode_interface.decoded_insns[fetch_index].ready,
|
||||||
|
|
@ -483,7 +336,6 @@ pub fn reg_alloc(config: &CpuConfig) {
|
||||||
);
|
);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let unit_forwarding_info = wire(config.unit_forwarding_info());
|
let unit_forwarding_info = wire(config.unit_forwarding_info());
|
||||||
connect(rob.unit_forwarding_info, unit_forwarding_info);
|
|
||||||
for (unit_index, unit_config) in config.units.iter().enumerate() {
|
for (unit_index, unit_config) in config.units.iter().enumerate() {
|
||||||
let dyn_unit = unit_config.kind.unit(config, unit_index);
|
let dyn_unit = unit_config.kind.unit(config, unit_index);
|
||||||
let unit = instance_with_loc(
|
let unit = instance_with_loc(
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
use crate::util::tree_reduce::tree_reduce;
|
use fayalite::{
|
||||||
use fayalite::{module::wire_with_loc, prelude::*, util::ready_valid::ReadyValid};
|
module::wire_with_loc,
|
||||||
|
prelude::*,
|
||||||
|
util::{prefix_sum::reduce, ready_valid::ReadyValid},
|
||||||
|
};
|
||||||
use std::{num::NonZeroUsize, ops::Range};
|
use std::{num::NonZeroUsize, ops::Range};
|
||||||
|
|
||||||
#[hdl_module]
|
#[hdl_module]
|
||||||
|
|
@ -44,7 +47,7 @@ pub fn unit_free_regs_tracker(
|
||||||
count,
|
count,
|
||||||
count_overflowed,
|
count_overflowed,
|
||||||
alloc_nums,
|
alloc_nums,
|
||||||
}) = tree_reduce(
|
}) = reduce(
|
||||||
(0..reg_count).map(|index| Summary {
|
(0..reg_count).map(|index| Summary {
|
||||||
range: index..index + 1,
|
range: index..index + 1,
|
||||||
count: (!allocated_reg[index])
|
count: (!allocated_reg[index])
|
||||||
|
|
@ -120,7 +123,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(
|
||||||
|
|
|
||||||
187
crates/cpu/src/rename_table.rs
Normal file
187
crates/cpu/src/rename_table.rs
Normal file
|
|
@ -0,0 +1,187 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
config::{CpuConfig, CpuConfigType},
|
||||||
|
instruction::{MOpRegNum, PRegNum},
|
||||||
|
util::range_intersection,
|
||||||
|
};
|
||||||
|
use fayalite::{
|
||||||
|
memory::{splat_mask, ReadStruct, WriteStruct},
|
||||||
|
module::memory_with_loc,
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
|
use std::{mem, ops::Range};
|
||||||
|
|
||||||
|
#[hdl(no_static)]
|
||||||
|
pub struct RenameTableReadPort<C: Type + CpuConfigType> {
|
||||||
|
pub addr: MOpRegNum,
|
||||||
|
#[hdl(flip)]
|
||||||
|
pub data: PRegNum<C>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl(no_static)]
|
||||||
|
pub struct RenameTableWritePort<C: Type + CpuConfigType> {
|
||||||
|
pub addr: MOpRegNum,
|
||||||
|
pub data: PRegNum<C>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum RenameTablePortConfig {
|
||||||
|
Read { addr_range: Range<u32> },
|
||||||
|
Write { addr_range: Range<u32> },
|
||||||
|
}
|
||||||
|
|
||||||
|
type C = PhantomConst<CpuConfig>;
|
||||||
|
|
||||||
|
/// register rename table.
|
||||||
|
/// all read/write operations are done in the order of `port_configs`.
|
||||||
|
/// So if `port_configs[0]` is a write and `port_configs[1]` is a read,
|
||||||
|
/// then the read port will combinatorially return data written by the
|
||||||
|
/// write port in the *same* clock cycle. However, if `port_configs[0]`
|
||||||
|
/// is a read and `port_configs[1]` is a write, then the read port will
|
||||||
|
/// not see the data written by the write port until the *next* clock cycle.
|
||||||
|
#[hdl_module]
|
||||||
|
pub fn rename_table(config: PhantomConst<CpuConfig>, port_configs: &[RenameTablePortConfig]) {
|
||||||
|
let read_count = port_configs
|
||||||
|
.iter()
|
||||||
|
.filter(|v| matches!(v, RenameTablePortConfig::Read { .. }))
|
||||||
|
.count();
|
||||||
|
let write_count = port_configs
|
||||||
|
.iter()
|
||||||
|
.filter(|v| matches!(v, RenameTablePortConfig::Write { .. }))
|
||||||
|
.count();
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
let cd: ClockDomain = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let read_ports: Array<RenameTableReadPort<C>> =
|
||||||
|
m.input(Array[RenameTableReadPort[config]][read_count]);
|
||||||
|
#[hdl]
|
||||||
|
let write_ports: Array<RenameTableWritePort<C>> =
|
||||||
|
m.input(Array[RenameTableWritePort[config]][write_count]);
|
||||||
|
|
||||||
|
for read_port in read_ports {
|
||||||
|
connect(read_port.data, PRegNum[config].const_zero());
|
||||||
|
}
|
||||||
|
|
||||||
|
let port_configs_and_indexes = port_configs.iter().scan(
|
||||||
|
(0usize, 0),
|
||||||
|
|(read_port_index, write_port_index), port_config| {
|
||||||
|
Some((
|
||||||
|
port_config,
|
||||||
|
match port_config {
|
||||||
|
RenameTablePortConfig::Read { .. } => {
|
||||||
|
mem::replace(read_port_index, *read_port_index + 1)
|
||||||
|
}
|
||||||
|
RenameTablePortConfig::Write { .. } => {
|
||||||
|
mem::replace(write_port_index, *write_port_index + 1)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
))
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut range_transitions = Vec::with_capacity(port_configs.len() * 2);
|
||||||
|
for port_config in port_configs {
|
||||||
|
let (RenameTablePortConfig::Read { addr_range }
|
||||||
|
| RenameTablePortConfig::Write { addr_range }) = port_config;
|
||||||
|
range_transitions.push(addr_range.start);
|
||||||
|
range_transitions.push(addr_range.end);
|
||||||
|
}
|
||||||
|
range_transitions.sort_unstable();
|
||||||
|
range_transitions.dedup();
|
||||||
|
let mut last_range_transition = None;
|
||||||
|
for range_transition in range_transitions {
|
||||||
|
let Some(last_range_transition) = last_range_transition.replace(range_transition) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let cur_addr_range = last_range_transition..range_transition;
|
||||||
|
let mut mem = memory_with_loc(
|
||||||
|
&if cur_addr_range.len() == 1 {
|
||||||
|
format!("mem_{:#x}", cur_addr_range.start)
|
||||||
|
} else {
|
||||||
|
format!("mem_{:#x}_{:#x}", cur_addr_range.start, cur_addr_range.end)
|
||||||
|
},
|
||||||
|
PRegNum[config],
|
||||||
|
SourceLocation::caller(),
|
||||||
|
);
|
||||||
|
mem.depth(cur_addr_range.len());
|
||||||
|
let addr_in_range = |addr: Expr<MOpRegNum>| {
|
||||||
|
if cur_addr_range.len() == 1 {
|
||||||
|
addr.value.cmp_eq(cur_addr_range.start)
|
||||||
|
} else {
|
||||||
|
addr.value.cmp_ge(cur_addr_range.start) & addr.value.cmp_lt(cur_addr_range.end)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for (port_config, port_index) in port_configs_and_indexes.clone() {
|
||||||
|
match port_config {
|
||||||
|
RenameTablePortConfig::Read { addr_range } => {
|
||||||
|
if range_intersection(&addr_range, &cur_addr_range).is_none() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let port = read_ports[port_index];
|
||||||
|
#[hdl]
|
||||||
|
let ReadStruct::<_, _> {
|
||||||
|
addr,
|
||||||
|
en,
|
||||||
|
clk,
|
||||||
|
data,
|
||||||
|
} = mem.new_read_port();
|
||||||
|
connect_any(addr, port.addr.value - cur_addr_range.start);
|
||||||
|
connect(en, addr_in_range(port.addr));
|
||||||
|
connect(clk, cd.clk);
|
||||||
|
#[hdl]
|
||||||
|
if en {
|
||||||
|
connect(port.data, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RenameTablePortConfig::Write { addr_range } => {
|
||||||
|
if range_intersection(&addr_range, &cur_addr_range).is_none() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let port = write_ports[port_index];
|
||||||
|
#[hdl]
|
||||||
|
let WriteStruct::<_, _> {
|
||||||
|
addr,
|
||||||
|
en,
|
||||||
|
clk,
|
||||||
|
data,
|
||||||
|
mask,
|
||||||
|
} = mem.new_write_port();
|
||||||
|
connect_any(addr, port.addr.value - cur_addr_range.start);
|
||||||
|
connect(en, addr_in_range(port.addr));
|
||||||
|
connect(clk, cd.clk);
|
||||||
|
connect(data, port.data);
|
||||||
|
connect(mask, splat_mask(Expr::ty(port).data, true.to_expr()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (port_config_index, (port_config, port_index)) in
|
||||||
|
port_configs_and_indexes.clone().enumerate()
|
||||||
|
{
|
||||||
|
let RenameTablePortConfig::Read { addr_range } = port_config else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let port = read_ports[port_index];
|
||||||
|
for (prev_port_config, prev_port_index) in
|
||||||
|
port_configs_and_indexes.clone().take(port_config_index)
|
||||||
|
{
|
||||||
|
let RenameTablePortConfig::Write {
|
||||||
|
addr_range: prev_addr_range,
|
||||||
|
} = prev_port_config
|
||||||
|
else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if range_intersection(addr_range, prev_addr_range).is_none() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let prev_port = write_ports[prev_port_index];
|
||||||
|
#[hdl]
|
||||||
|
if prev_port.addr.cmp_eq(port.addr) {
|
||||||
|
connect(port.data, prev_port.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
33
crates/cpu/src/retire_queue.rs
Normal file
33
crates/cpu/src/retire_queue.rs
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
config::{CpuConfig, CpuConfigType},
|
||||||
|
instruction::{MOpDestReg, PRegNum},
|
||||||
|
unit::RetireQueueIndex,
|
||||||
|
};
|
||||||
|
use fayalite::prelude::*;
|
||||||
|
|
||||||
|
#[hdl(no_static)]
|
||||||
|
pub struct RenameRetireInterface<C: Type + CpuConfigType> {
|
||||||
|
pub start_retire_queue_index: RetireQueueIndex<C>,
|
||||||
|
#[hdl(flip)]
|
||||||
|
pub end_retire_queue_index: RetireQueueIndex<C>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl(no_static)]
|
||||||
|
pub struct RetireQueueEntry<C: Type + CpuConfigType> {
|
||||||
|
pub mop_dest: MOpDestReg,
|
||||||
|
pub renamed_dest: PRegNum<C>,
|
||||||
|
}
|
||||||
|
|
||||||
|
type C = PhantomConst<CpuConfig>;
|
||||||
|
|
||||||
|
#[hdl_module]
|
||||||
|
pub fn retire_queue(config: PhantomConst<CpuConfig>) {
|
||||||
|
#[hdl]
|
||||||
|
let cd: ClockDomain = m.input();
|
||||||
|
#[hdl]
|
||||||
|
let rename_retire_interface: RenameRetireInterface<C> = m.output(RenameRetireInterface[config]);
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
@ -2,19 +2,21 @@
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::CpuConfig,
|
config::{CpuConfig, CpuConfigType, RetireQueueIndexWidth, UnitCount},
|
||||||
instruction::{
|
instruction::{
|
||||||
AluBranchMOp, LoadStoreMOp, MOp, MOpDestReg, MOpInto, MOpRegNum, MOpTrait, RenamedMOp,
|
mop_enum, AluBranchMOp, LoadStoreMOp, MOp, MOpDestReg, MOpInto, MOpRegNum, MOpTrait,
|
||||||
UnitOutRegNum, mop_enum,
|
RenamedMOp, UnitOutRegNum,
|
||||||
},
|
},
|
||||||
register::{FlagsMode, PRegValue},
|
register::{FlagsMode, PRegValue},
|
||||||
unit::unit_base::UnitToRegAlloc,
|
|
||||||
};
|
};
|
||||||
use fayalite::{
|
use fayalite::{
|
||||||
bundle::{Bundle, BundleType},
|
bundle::{Bundle, BundleType},
|
||||||
|
int::BoolOrIntType,
|
||||||
intern::{Intern, Interned},
|
intern::{Intern, Interned},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
|
util::ready_valid::ReadyValid,
|
||||||
};
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub mod alu_branch;
|
pub mod alu_branch;
|
||||||
pub mod unit_base;
|
pub mod unit_base;
|
||||||
|
|
@ -36,7 +38,7 @@ macro_rules! all_units {
|
||||||
}
|
}
|
||||||
) => {
|
) => {
|
||||||
$(#[$enum_meta])*
|
$(#[$enum_meta])*
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
|
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Serialize, Deserialize)]
|
||||||
$vis enum $UnitKind {
|
$vis enum $UnitKind {
|
||||||
$(
|
$(
|
||||||
$(#[$variant_meta])*
|
$(#[$variant_meta])*
|
||||||
|
|
@ -45,7 +47,7 @@ macro_rules! all_units {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $UnitKind {
|
impl $UnitKind {
|
||||||
pub fn unit(self, config: &CpuConfig, unit_index: usize) -> DynUnit {
|
pub fn unit(self, config: PhantomConst<CpuConfig>, unit_index: usize) -> DynUnit {
|
||||||
match self {
|
match self {
|
||||||
$($UnitKind::$Unit => $create_dyn_unit_fn(config, unit_index),)*
|
$($UnitKind::$Unit => $create_dyn_unit_fn(config, unit_index),)*
|
||||||
}
|
}
|
||||||
|
|
@ -204,23 +206,28 @@ macro_rules! all_units {
|
||||||
})*
|
})*
|
||||||
};
|
};
|
||||||
|
|
||||||
$(impl<$DestReg: Type, $SrcRegWidth: Size> MOpInto<RenamedMOp<$DestReg, $SrcRegWidth>> for $BeforeOp {
|
const _: () = {
|
||||||
fn mop_into_ty(self) -> RenamedMOp<$DestReg, $SrcRegWidth> {
|
#[hdl]
|
||||||
RenamedMOp[MOpTrait::dest_reg_ty(self)][MOpTrait::src_reg_width(self)]
|
type $DestReg = ();
|
||||||
}
|
|
||||||
fn mop_into(this: Expr<Self>) -> Expr<RenamedMOp<$DestReg, $SrcRegWidth>> {
|
|
||||||
MOpInto::<RenamedMOp<$DestReg, $SrcRegWidth>>::mop_into_ty(Expr::ty(this)).$BeforeUnit(this)
|
|
||||||
}
|
|
||||||
})*
|
|
||||||
|
|
||||||
$(impl<$DestReg: Type, $SrcRegWidth: Size> MOpInto<RenamedMOp<$DestReg, $SrcRegWidth>> for $AfterOp {
|
$(impl<$SrcRegWidth: Size> MOpInto<RenamedMOp<$SrcRegWidth>> for $BeforeOp {
|
||||||
fn mop_into_ty(self) -> RenamedMOp<$DestReg, $SrcRegWidth> {
|
fn mop_into_ty(self) -> RenamedMOp<$SrcRegWidth> {
|
||||||
RenamedMOp[MOpTrait::dest_reg_ty(self)][MOpTrait::src_reg_width(self)]
|
RenamedMOp[MOpTrait::src_reg_width(self)]
|
||||||
}
|
}
|
||||||
fn mop_into(this: Expr<Self>) -> Expr<RenamedMOp<$DestReg, $SrcRegWidth>> {
|
fn mop_into(this: Expr<Self>) -> Expr<RenamedMOp<$SrcRegWidth>> {
|
||||||
MOpInto::<RenamedMOp<$DestReg, $SrcRegWidth>>::mop_into_ty(Expr::ty(this)).$AfterUnit(this)
|
MOpInto::<RenamedMOp<$SrcRegWidth>>::mop_into_ty(Expr::ty(this)).$BeforeUnit(this)
|
||||||
}
|
}
|
||||||
})*
|
})*
|
||||||
|
|
||||||
|
$(impl<$SrcRegWidth: Size> MOpInto<RenamedMOp<$SrcRegWidth>> for $AfterOp {
|
||||||
|
fn mop_into_ty(self) -> RenamedMOp<$SrcRegWidth> {
|
||||||
|
RenamedMOp[MOpTrait::src_reg_width(self)]
|
||||||
|
}
|
||||||
|
fn mop_into(this: Expr<Self>) -> Expr<RenamedMOp<$SrcRegWidth>> {
|
||||||
|
MOpInto::<RenamedMOp<$SrcRegWidth>>::mop_into_ty(Expr::ty(this)).$AfterUnit(this)
|
||||||
|
}
|
||||||
|
})*
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -253,18 +260,80 @@ pub struct GlobalState {
|
||||||
pub flags_mode: FlagsMode,
|
pub flags_mode: FlagsMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// index into the retire queue (the queue of instructions that haven't yet retired)
|
||||||
|
#[hdl(cmp_eq, no_static)]
|
||||||
|
pub struct RetireQueueIndex<C: Type + CpuConfigType> {
|
||||||
|
/// increases by one for each instruction added to the retire queue.
|
||||||
|
///
|
||||||
|
/// this wraps around, so you must not compare it using `cmp_lt`/`cmp_gt`
|
||||||
|
/// but instead must use [`Self::insns_until`] and compare the output with zero.
|
||||||
|
pub index: UIntType<RetireQueueIndexWidth<C>>,
|
||||||
|
pub config: C,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: Type + CpuConfigType> RetireQueueIndex<C> {
|
||||||
|
pub fn insns_until(
|
||||||
|
this: impl ToExpr<Type = Self>,
|
||||||
|
target: impl ToExpr<Type = Self>,
|
||||||
|
) -> Expr<SIntType<RetireQueueIndexWidth<C>>> {
|
||||||
|
let this = this.to_expr();
|
||||||
|
let target = target.to_expr();
|
||||||
|
assert_eq!(Expr::ty(this), Expr::ty(target));
|
||||||
|
(this.index - target.index).cast_to(Expr::ty(this).index.as_same_width_sint())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl(no_static)]
|
||||||
|
pub struct RenamedInsnData<C: Type + CpuConfigType, MOp, DestReg> {
|
||||||
|
pub retire_queue_index: RetireQueueIndex<C>,
|
||||||
|
pub pc: UInt<64>,
|
||||||
|
pub dest: DestReg,
|
||||||
|
pub mop: MOp,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl(no_static)]
|
||||||
|
pub struct UnitForwardingInfo<C: Type + CpuConfigType> {
|
||||||
|
pub unit_output_writes: ArrayType<HdlOption<UnitOutputWrite<C>>, UnitCount<C>>,
|
||||||
|
pub unit_reg_frees: ArrayType<HdlOption<UnitOutRegNum<C>>, UnitCount<C>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[hdl(no_static)]
|
||||||
|
pub struct UnitToRegAlloc<C: Type + CpuConfigType, MOp: Type, ExtraOut: Type> {
|
||||||
|
#[hdl(flip)]
|
||||||
|
pub unit_forwarding_info: UnitForwardingInfo<C>,
|
||||||
|
#[hdl(flip)]
|
||||||
|
pub input: ReadyValid<RenamedInsnData<C, MOp, UnitOutRegNum<C>>>,
|
||||||
|
#[hdl(flip)]
|
||||||
|
pub cancel_input: HdlOption<UnitCancelInput<C>>,
|
||||||
|
pub output: HdlOption<UnitOutput<C, ExtraOut>>,
|
||||||
|
pub ready_for_retire_queue_index: HdlOption<RetireQueueIndex<C>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: Type + CpuConfigType, MOp: Type, ExtraOut: Type> UnitToRegAlloc<C, MOp, ExtraOut> {
|
||||||
|
pub fn mop_ty(self) -> MOp {
|
||||||
|
self.input.data.HdlSome.mop
|
||||||
|
}
|
||||||
|
pub fn extra_out_ty(self) -> ExtraOut {
|
||||||
|
self.output.HdlSome.extra_out_ty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[hdl(cmp_eq)]
|
#[hdl(cmp_eq)]
|
||||||
pub struct UnitResultCompleted<ExtraOut> {
|
pub struct UnitResultCompleted<ExtraOut> {
|
||||||
pub value: PRegValue,
|
pub value: PRegValue,
|
||||||
pub extra_out: ExtraOut,
|
pub extra_out: ExtraOut,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl(cmp_eq)]
|
#[hdl(cmp_eq, no_static)]
|
||||||
pub struct UnitOutputWrite<OutRegNumWidth: Size> {
|
pub struct UnitOutputWrite<C: Type + CpuConfigType> {
|
||||||
pub which: UnitOutRegNum<OutRegNumWidth>,
|
pub dest: UnitOutRegNum<C>,
|
||||||
pub value: PRegValue,
|
pub value: PRegValue,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
pub type UnitOutputWrites<C: Type + CpuConfigType> =
|
||||||
|
ArrayType<HdlOption<UnitOutputWrite<C>>, UnitCount<C>>;
|
||||||
|
|
||||||
#[hdl(cmp_eq)]
|
#[hdl(cmp_eq)]
|
||||||
pub struct TrapData {
|
pub struct TrapData {
|
||||||
// TODO
|
// TODO
|
||||||
|
|
@ -282,21 +351,31 @@ impl<ExtraOut: Type> UnitResult<ExtraOut> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl]
|
#[hdl(no_static)]
|
||||||
pub struct UnitOutput<OutRegNumWidth: Size, ExtraOut> {
|
pub struct UnitOutput<C: Type + CpuConfigType, ExtraOut> {
|
||||||
pub which: UnitOutRegNum<OutRegNumWidth>,
|
pub dest: UnitOutRegNum<C>,
|
||||||
|
pub retire_queue_index: RetireQueueIndex<C>,
|
||||||
pub result: UnitResult<ExtraOut>,
|
pub result: UnitResult<ExtraOut>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<OutRegNumWidth: Size, ExtraOut: Type> UnitOutput<OutRegNumWidth, ExtraOut> {
|
impl<C: Type + CpuConfigType, ExtraOut: Type> UnitOutput<C, ExtraOut> {
|
||||||
pub fn extra_out_ty(self) -> ExtraOut {
|
pub fn extra_out_ty(self) -> ExtraOut {
|
||||||
self.result.extra_out_ty()
|
self.result.extra_out_ty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl(cmp_eq)]
|
#[hdl(cmp_eq, no_static)]
|
||||||
pub struct UnitCancelInput<OutRegNumWidth: Size> {
|
pub struct UnitCancelInput<C: Type + CpuConfigType> {
|
||||||
pub which: UnitOutRegNum<OutRegNumWidth>,
|
pub target: RetireQueueIndex<C>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: Type + CpuConfigType> UnitCancelInput<C> {
|
||||||
|
pub fn is_canceled(
|
||||||
|
this: impl ToExpr<Type = Self>,
|
||||||
|
insn_retire_queue_index: impl ToExpr<Type = RetireQueueIndex<C>>,
|
||||||
|
) -> Expr<Bool> {
|
||||||
|
RetireQueueIndex::insns_until(insn_retire_queue_index, this.to_expr().target).cmp_ge(0i8)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait UnitTrait:
|
pub trait UnitTrait:
|
||||||
|
|
@ -312,17 +391,14 @@ pub trait UnitTrait:
|
||||||
|
|
||||||
fn unit_kind(&self) -> UnitKind;
|
fn unit_kind(&self) -> UnitKind;
|
||||||
|
|
||||||
fn extract_mop(
|
fn extract_mop(&self, mop: Expr<RenamedMOp<DynSize>>) -> Expr<HdlOption<Self::MOp>>;
|
||||||
&self,
|
|
||||||
mop: Expr<RenamedMOp<UnitOutRegNum<DynSize>, DynSize>>,
|
|
||||||
) -> Expr<HdlOption<Self::MOp>>;
|
|
||||||
|
|
||||||
fn module(&self) -> Interned<Module<Self::Type>>;
|
fn module(&self) -> Interned<Module<Self::Type>>;
|
||||||
|
|
||||||
fn unit_to_reg_alloc(
|
fn unit_to_reg_alloc(
|
||||||
&self,
|
&self,
|
||||||
this: Expr<Self::Type>,
|
this: Expr<Self::Type>,
|
||||||
) -> Expr<UnitToRegAlloc<Self::MOp, Self::ExtraOut, DynSize, DynSize, DynSize>>;
|
) -> Expr<UnitToRegAlloc<PhantomConst<CpuConfig>, Self::MOp, Self::ExtraOut>>;
|
||||||
|
|
||||||
fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain>;
|
fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain>;
|
||||||
|
|
||||||
|
|
@ -370,10 +446,7 @@ impl UnitTrait for DynUnit {
|
||||||
self.unit_kind
|
self.unit_kind
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_mop(
|
fn extract_mop(&self, mop: Expr<RenamedMOp<DynSize>>) -> Expr<HdlOption<Self::MOp>> {
|
||||||
&self,
|
|
||||||
mop: Expr<RenamedMOp<UnitOutRegNum<DynSize>, DynSize>>,
|
|
||||||
) -> Expr<HdlOption<Self::MOp>> {
|
|
||||||
self.unit.extract_mop(mop)
|
self.unit.extract_mop(mop)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -384,7 +457,7 @@ impl UnitTrait for DynUnit {
|
||||||
fn unit_to_reg_alloc(
|
fn unit_to_reg_alloc(
|
||||||
&self,
|
&self,
|
||||||
this: Expr<Self::Type>,
|
this: Expr<Self::Type>,
|
||||||
) -> Expr<UnitToRegAlloc<Self::MOp, Self::ExtraOut, DynSize, DynSize, DynSize>> {
|
) -> Expr<UnitToRegAlloc<PhantomConst<CpuConfig>, Self::MOp, Self::ExtraOut>> {
|
||||||
self.unit.unit_to_reg_alloc(this)
|
self.unit.unit_to_reg_alloc(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -425,10 +498,7 @@ impl<T: UnitTrait + Clone + std::hash::Hash + Eq> UnitTrait for DynUnitWrapper<T
|
||||||
self.0.unit_kind()
|
self.0.unit_kind()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_mop(
|
fn extract_mop(&self, mop: Expr<RenamedMOp<DynSize>>) -> Expr<HdlOption<Self::MOp>> {
|
||||||
&self,
|
|
||||||
mop: Expr<RenamedMOp<UnitOutRegNum<DynSize>, DynSize>>,
|
|
||||||
) -> Expr<HdlOption<Self::MOp>> {
|
|
||||||
Expr::from_enum(Expr::as_enum(self.0.extract_mop(mop)))
|
Expr::from_enum(Expr::as_enum(self.0.extract_mop(mop)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -439,7 +509,7 @@ impl<T: UnitTrait + Clone + std::hash::Hash + Eq> UnitTrait for DynUnitWrapper<T
|
||||||
fn unit_to_reg_alloc(
|
fn unit_to_reg_alloc(
|
||||||
&self,
|
&self,
|
||||||
this: Expr<Self::Type>,
|
this: Expr<Self::Type>,
|
||||||
) -> Expr<UnitToRegAlloc<Self::MOp, Self::ExtraOut, DynSize, DynSize, DynSize>> {
|
) -> Expr<UnitToRegAlloc<PhantomConst<CpuConfig>, Self::MOp, Self::ExtraOut>> {
|
||||||
Expr::from_bundle(Expr::as_bundle(
|
Expr::from_bundle(Expr::as_bundle(
|
||||||
self.0.unit_to_reg_alloc(Expr::from_bundle(this)),
|
self.0.unit_to_reg_alloc(Expr::from_bundle(this)),
|
||||||
))
|
))
|
||||||
|
|
|
||||||
|
|
@ -2,29 +2,26 @@
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::CpuConfig,
|
config::{CpuConfig, PRegNumWidth},
|
||||||
instruction::{
|
instruction::{
|
||||||
AddSubMOp, AluBranchMOp, AluCommonMOp, COMMON_MOP_SRC_LEN, CommonMOp, LogicalMOp, MOpTrait,
|
AddSubMOp, AluBranchMOp, AluCommonMOp, CommonMOp, LogicalMOp, OutputIntegerMode,
|
||||||
OutputIntegerMode, RenamedMOp, UnitOutRegNum,
|
RenamedMOp, COMMON_MOP_SRC_LEN,
|
||||||
},
|
},
|
||||||
register::{FlagsMode, PRegFlagsPowerISA, PRegFlagsX86, PRegValue},
|
register::{FlagsMode, PRegFlagsPowerISA, PRegFlagsX86, PRegValue},
|
||||||
unit::{
|
unit::{
|
||||||
|
unit_base::{unit_base, ExecuteEnd, ExecuteStart},
|
||||||
DynUnit, DynUnitWrapper, GlobalState, UnitKind, UnitMOp, UnitOutput, UnitResult,
|
DynUnit, DynUnitWrapper, GlobalState, UnitKind, UnitMOp, UnitOutput, UnitResult,
|
||||||
UnitResultCompleted, UnitTrait,
|
UnitResultCompleted, UnitToRegAlloc, UnitTrait,
|
||||||
unit_base::{ExecuteEnd, ExecuteStart, UnitToRegAlloc, unit_base},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use fayalite::{
|
use fayalite::{
|
||||||
intern::{Intern, Interned},
|
intern::Interned, module::wire_with_loc, prelude::*, util::ready_valid::ReadyValid,
|
||||||
module::wire_with_loc,
|
|
||||||
prelude::*,
|
|
||||||
util::ready_valid::ReadyValid,
|
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, ops::RangeTo};
|
use std::{collections::HashMap, ops::RangeTo};
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
fn add_sub<SrcCount: KnownSize>(
|
fn add_sub<SrcCount: KnownSize>(
|
||||||
mop: Expr<AddSubMOp<UnitOutRegNum<DynSize>, DynSize, SrcCount>>,
|
mop: Expr<AddSubMOp<(), DynSize, SrcCount>>,
|
||||||
pc: Expr<UInt<64>>,
|
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 }>>,
|
||||||
|
|
@ -232,7 +229,7 @@ fn add_sub<SrcCount: KnownSize>(
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
fn logical(
|
fn logical(
|
||||||
mop: Expr<LogicalMOp<UnitOutRegNum<DynSize>, DynSize>>,
|
mop: Expr<LogicalMOp<(), DynSize>>,
|
||||||
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<()>> {
|
||||||
|
|
@ -245,20 +242,15 @@ fn logical(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl_module]
|
#[hdl_module]
|
||||||
pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
|
pub fn alu_branch(config: PhantomConst<CpuConfig>, unit_index: usize) {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let cd: ClockDomain = m.input();
|
let cd: ClockDomain = m.input();
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let unit_to_reg_alloc: UnitToRegAlloc<
|
let unit_to_reg_alloc: UnitToRegAlloc<
|
||||||
AluBranchMOp<UnitOutRegNum<DynSize>, DynSize>,
|
PhantomConst<CpuConfig>,
|
||||||
|
AluBranchMOp<(), DynSize>,
|
||||||
(),
|
(),
|
||||||
DynSize,
|
> = m.output(UnitToRegAlloc[config][AluBranchMOp[()][PRegNumWidth[config]]][()]);
|
||||||
DynSize,
|
|
||||||
DynSize,
|
|
||||||
> = m.output(config.unit_to_reg_alloc(
|
|
||||||
AluBranchMOp[config.unit_out_reg_num()][config.p_reg_num_width()],
|
|
||||||
(),
|
|
||||||
));
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let global_state: GlobalState = m.input();
|
let global_state: GlobalState = m.input();
|
||||||
|
|
||||||
|
|
@ -279,13 +271,9 @@ pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
|
||||||
#[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]
|
||||||
let ExecuteStart::<_> {
|
let ExecuteStart::<_, _> { insn, src_values } = execute_start;
|
||||||
mop,
|
|
||||||
pc,
|
|
||||||
src_values,
|
|
||||||
} = execute_start;
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
match mop {
|
match insn.mop {
|
||||||
AluBranchMOp::<_, _>::AddSub(mop) => connect(
|
AluBranchMOp::<_, _>::AddSub(mop) => connect(
|
||||||
unit_base.execute_end,
|
unit_base.execute_end,
|
||||||
HdlSome(
|
HdlSome(
|
||||||
|
|
@ -293,10 +281,11 @@ pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
|
||||||
ExecuteEnd::<_, _> {
|
ExecuteEnd::<_, _> {
|
||||||
unit_output: #[hdl]
|
unit_output: #[hdl]
|
||||||
UnitOutput::<_, _> {
|
UnitOutput::<_, _> {
|
||||||
which: MOpTrait::dest_reg(mop),
|
dest: insn.dest,
|
||||||
|
retire_queue_index: insn.retire_queue_index,
|
||||||
result: UnitResult[()].Completed(add_sub(
|
result: UnitResult[()].Completed(add_sub(
|
||||||
mop,
|
mop,
|
||||||
pc,
|
insn.pc,
|
||||||
global_state.flags_mode,
|
global_state.flags_mode,
|
||||||
src_values,
|
src_values,
|
||||||
)),
|
)),
|
||||||
|
|
@ -311,10 +300,11 @@ pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
|
||||||
ExecuteEnd::<_, _> {
|
ExecuteEnd::<_, _> {
|
||||||
unit_output: #[hdl]
|
unit_output: #[hdl]
|
||||||
UnitOutput::<_, _> {
|
UnitOutput::<_, _> {
|
||||||
which: MOpTrait::dest_reg(mop),
|
dest: insn.dest,
|
||||||
|
retire_queue_index: insn.retire_queue_index,
|
||||||
result: UnitResult[()].Completed(add_sub(
|
result: UnitResult[()].Completed(add_sub(
|
||||||
mop,
|
mop,
|
||||||
pc,
|
insn.pc,
|
||||||
global_state.flags_mode,
|
global_state.flags_mode,
|
||||||
src_values,
|
src_values,
|
||||||
)),
|
)),
|
||||||
|
|
@ -329,7 +319,8 @@ pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
|
||||||
ExecuteEnd::<_, _> {
|
ExecuteEnd::<_, _> {
|
||||||
unit_output: #[hdl]
|
unit_output: #[hdl]
|
||||||
UnitOutput::<_, _> {
|
UnitOutput::<_, _> {
|
||||||
which: MOpTrait::dest_reg(mop),
|
dest: insn.dest,
|
||||||
|
retire_queue_index: insn.retire_queue_index,
|
||||||
result: UnitResult[()].Completed(logical(
|
result: UnitResult[()].Completed(logical(
|
||||||
mop,
|
mop,
|
||||||
global_state.flags_mode,
|
global_state.flags_mode,
|
||||||
|
|
@ -345,14 +336,14 @@ pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct AluBranch {
|
pub struct AluBranch {
|
||||||
config: Interned<CpuConfig>,
|
config: PhantomConst<CpuConfig>,
|
||||||
module: Interned<Module<alu_branch>>,
|
module: Interned<Module<alu_branch>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AluBranch {
|
impl AluBranch {
|
||||||
pub fn new(config: &CpuConfig, unit_index: usize) -> Self {
|
pub fn new(config: PhantomConst<CpuConfig>, unit_index: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
config: config.intern(),
|
config,
|
||||||
module: alu_branch(config, unit_index),
|
module: alu_branch(config, unit_index),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -361,7 +352,7 @@ impl AluBranch {
|
||||||
impl UnitTrait for AluBranch {
|
impl UnitTrait for AluBranch {
|
||||||
type Type = alu_branch;
|
type Type = alu_branch;
|
||||||
type ExtraOut = ();
|
type ExtraOut = ();
|
||||||
type MOp = AluBranchMOp<UnitOutRegNum<DynSize>, DynSize>;
|
type MOp = AluBranchMOp<(), DynSize>;
|
||||||
|
|
||||||
fn ty(&self) -> Self::Type {
|
fn ty(&self) -> Self::Type {
|
||||||
self.module.io_ty()
|
self.module.io_ty()
|
||||||
|
|
@ -379,10 +370,7 @@ impl UnitTrait for AluBranch {
|
||||||
UnitKind::AluBranch
|
UnitKind::AluBranch
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_mop(
|
fn extract_mop(&self, mop: Expr<RenamedMOp<DynSize>>) -> Expr<HdlOption<Self::MOp>> {
|
||||||
&self,
|
|
||||||
mop: Expr<RenamedMOp<UnitOutRegNum<DynSize>, DynSize>>,
|
|
||||||
) -> Expr<HdlOption<Self::MOp>> {
|
|
||||||
UnitMOp::alu_branch_mop(mop)
|
UnitMOp::alu_branch_mop(mop)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -393,7 +381,7 @@ impl UnitTrait for AluBranch {
|
||||||
fn unit_to_reg_alloc(
|
fn unit_to_reg_alloc(
|
||||||
&self,
|
&self,
|
||||||
this: Expr<Self::Type>,
|
this: Expr<Self::Type>,
|
||||||
) -> Expr<UnitToRegAlloc<Self::MOp, Self::ExtraOut, DynSize, DynSize, DynSize>> {
|
) -> Expr<UnitToRegAlloc<PhantomConst<CpuConfig>, Self::MOp, Self::ExtraOut>> {
|
||||||
this.unit_to_reg_alloc
|
this.unit_to_reg_alloc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,72 +2,31 @@
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::CpuConfig,
|
config::{CpuConfig, CpuConfigType, UnitOutRegNumWidth},
|
||||||
instruction::{COMMON_MOP_SRC_LEN, MOpTrait, PRegNum, UnitNum, UnitOutRegNum},
|
instruction::{MOpTrait, PRegNum, UnitNum, UnitOutRegNum, COMMON_MOP_SRC_LEN},
|
||||||
register::PRegValue,
|
register::PRegValue,
|
||||||
unit::{UnitCancelInput, UnitOutput, UnitOutputWrite},
|
unit::{
|
||||||
util::tree_reduce::tree_reduce,
|
RenamedInsnData, RetireQueueIndex, UnitCancelInput, UnitForwardingInfo, UnitOutput,
|
||||||
|
UnitOutputWrite, UnitToRegAlloc,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use fayalite::{
|
use fayalite::{
|
||||||
memory::splat_mask,
|
memory::splat_mask,
|
||||||
module::{memory_with_loc, wire_with_loc},
|
module::{memory_with_loc, wire_with_loc},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
ty::StaticType,
|
ty::StaticType,
|
||||||
util::ready_valid::ReadyValid,
|
util::{prefix_sum::reduce, ready_valid::ReadyValid},
|
||||||
};
|
};
|
||||||
use std::marker::PhantomData;
|
|
||||||
|
|
||||||
#[hdl]
|
#[hdl(no_static)]
|
||||||
pub struct UnitForwardingInfo<UnitNumWidth: Size, OutRegNumWidth: Size, UnitCount: Size> {
|
pub struct ExecuteStart<C: Type + CpuConfigType, MOp: Type> {
|
||||||
pub unit_output_writes: ArrayType<HdlOption<UnitOutputWrite<OutRegNumWidth>>, UnitCount>,
|
pub insn: RenamedInsnData<C, MOp, UnitOutRegNum<C>>,
|
||||||
pub unit_reg_frees: ArrayType<HdlOption<UnitOutRegNum<OutRegNumWidth>>, UnitCount>,
|
|
||||||
pub _phantom: PhantomData<UnitNumWidth>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[hdl]
|
|
||||||
pub struct UnitInput<MOp: Type> {
|
|
||||||
pub mop: MOp,
|
|
||||||
pub pc: UInt<64>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[hdl]
|
|
||||||
pub struct UnitToRegAlloc<
|
|
||||||
MOp: Type,
|
|
||||||
ExtraOut: Type,
|
|
||||||
UnitNumWidth: Size,
|
|
||||||
OutRegNumWidth: Size,
|
|
||||||
UnitCount: Size,
|
|
||||||
> {
|
|
||||||
#[hdl(flip)]
|
|
||||||
pub unit_forwarding_info: UnitForwardingInfo<UnitNumWidth, OutRegNumWidth, UnitCount>,
|
|
||||||
#[hdl(flip)]
|
|
||||||
pub input: ReadyValid<UnitInput<MOp>>,
|
|
||||||
#[hdl(flip)]
|
|
||||||
pub cancel_input: HdlOption<UnitCancelInput<OutRegNumWidth>>,
|
|
||||||
pub output: HdlOption<UnitOutput<OutRegNumWidth, ExtraOut>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<MOp: Type, ExtraOut: Type, UnitNumWidth: Size, OutRegNumWidth: Size, UnitCount: Size>
|
|
||||||
UnitToRegAlloc<MOp, ExtraOut, UnitNumWidth, OutRegNumWidth, UnitCount>
|
|
||||||
{
|
|
||||||
pub fn mop_ty(self) -> MOp {
|
|
||||||
self.input.data.HdlSome.mop
|
|
||||||
}
|
|
||||||
pub fn extra_out_ty(self) -> ExtraOut {
|
|
||||||
self.output.HdlSome.extra_out_ty()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[hdl]
|
|
||||||
pub struct ExecuteStart<MOp: Type + MOpTrait<DestReg = UnitOutRegNum<DynSize>>> {
|
|
||||||
pub mop: MOp,
|
|
||||||
pub pc: UInt<64>,
|
|
||||||
pub src_values: Array<PRegValue, { COMMON_MOP_SRC_LEN }>,
|
pub src_values: Array<PRegValue, { COMMON_MOP_SRC_LEN }>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl]
|
#[hdl(no_static)]
|
||||||
pub struct ExecuteEnd<OutRegNumWidth: Size, ExtraOut> {
|
pub struct ExecuteEnd<C: Type + CpuConfigType, ExtraOut> {
|
||||||
pub unit_output: UnitOutput<OutRegNumWidth, ExtraOut>,
|
pub unit_output: UnitOutput<C, ExtraOut>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -147,27 +106,34 @@ impl InFlightOpState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl]
|
#[hdl(no_static)]
|
||||||
struct InFlightOp<MOp: Type> {
|
struct InFlightOp<C: Type + CpuConfigType, MOp: Type> {
|
||||||
state: InFlightOpState,
|
state: InFlightOpState,
|
||||||
mop: MOp,
|
insn: RenamedInsnData<C, MOp, UnitOutRegNum<C>>,
|
||||||
pc: UInt<64>,
|
|
||||||
src_ready_flags: Array<Bool, { COMMON_MOP_SRC_LEN }>,
|
src_ready_flags: Array<Bool, { COMMON_MOP_SRC_LEN }>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl]
|
impl<C: Type + CpuConfigType, MOp: Type> InFlightOp<C, MOp> {
|
||||||
struct InFlightOpsSummary<OpIndexWidth: Size> {
|
fn config(self) -> C {
|
||||||
empty_op_index: HdlOption<UIntType<OpIndexWidth>>,
|
self.insn.retire_queue_index.config
|
||||||
ready_op_index: HdlOption<UIntType<OpIndexWidth>>,
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<OpIndexWidth: Size> InFlightOpsSummary<OpIndexWidth> {
|
#[hdl(no_static)]
|
||||||
|
struct InFlightOpsSummary<C: Type + CpuConfigType, OpIndexWidth: Size> {
|
||||||
|
empty_op_index: HdlOption<UIntType<OpIndexWidth>>,
|
||||||
|
ready_op_index: HdlOption<UIntType<OpIndexWidth>>,
|
||||||
|
ready_for_retire_queue_index: HdlOption<RetireQueueIndex<C>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: Type + CpuConfigType, OpIndexWidth: Size> InFlightOpsSummary<C, OpIndexWidth> {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
fn new<MOp: Type>(
|
fn new<MOp: Type>(
|
||||||
op_index: usize,
|
op_index: usize,
|
||||||
op_index_ty: UIntType<OpIndexWidth>,
|
op_index_ty: UIntType<OpIndexWidth>,
|
||||||
in_flight_op: impl ToExpr<Type = HdlOption<InFlightOp<MOp>>>,
|
in_flight_op: impl ToExpr<Type = HdlOption<InFlightOp<C, MOp>>>,
|
||||||
) -> Expr<Self> {
|
) -> Expr<Self> {
|
||||||
|
let in_flight_op = in_flight_op.to_expr();
|
||||||
let empty_op_index = wire_with_loc(
|
let empty_op_index = wire_with_loc(
|
||||||
&format!("empty_op_index_{op_index}"),
|
&format!("empty_op_index_{op_index}"),
|
||||||
SourceLocation::caller(),
|
SourceLocation::caller(),
|
||||||
|
|
@ -180,34 +146,73 @@ impl<OpIndexWidth: Size> InFlightOpsSummary<OpIndexWidth> {
|
||||||
HdlOption[op_index_ty],
|
HdlOption[op_index_ty],
|
||||||
);
|
);
|
||||||
connect(ready_op_index, HdlOption[op_index_ty].HdlNone());
|
connect(ready_op_index, HdlOption[op_index_ty].HdlNone());
|
||||||
|
let ready_for_retire_queue_index = wire_with_loc(
|
||||||
|
&format!("ready_for_retire_queue_index_{op_index}"),
|
||||||
|
SourceLocation::caller(),
|
||||||
|
HdlOption[RetireQueueIndex[Expr::ty(in_flight_op).HdlSome.config()]],
|
||||||
|
);
|
||||||
|
connect(
|
||||||
|
ready_for_retire_queue_index,
|
||||||
|
Expr::ty(ready_for_retire_queue_index).HdlNone(),
|
||||||
|
);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if let HdlSome(in_flight_op) = in_flight_op {
|
if let HdlSome(in_flight_op) = in_flight_op {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let InFlightOp::<_> {
|
let InFlightOp::<_, _> {
|
||||||
state,
|
state,
|
||||||
mop: _,
|
insn,
|
||||||
pc: _,
|
|
||||||
src_ready_flags,
|
src_ready_flags,
|
||||||
} = in_flight_op;
|
} = in_flight_op;
|
||||||
connect(ready_op_index, HdlOption[op_index_ty].HdlNone());
|
connect(ready_op_index, HdlOption[op_index_ty].HdlNone());
|
||||||
|
let ready_for_retire_queue_index_value = wire_with_loc(
|
||||||
|
&format!("ready_for_retire_queue_index_value_{op_index}"),
|
||||||
|
SourceLocation::caller(),
|
||||||
|
RetireQueueIndex[Expr::ty(in_flight_op).config()],
|
||||||
|
);
|
||||||
|
connect(ready_for_retire_queue_index_value, insn.retire_queue_index);
|
||||||
|
// TODO: don't subtract one from `.index` when instruction is ready to
|
||||||
|
// do something at retire time (e.g. non-speculative stores)
|
||||||
|
// -- that will need a new InFlightOpState variant.
|
||||||
|
connect_any(
|
||||||
|
ready_for_retire_queue_index_value.index,
|
||||||
|
// subtract one -- this instruction isn't ready to retire,
|
||||||
|
// but the previous one could be
|
||||||
|
insn.retire_queue_index.index - 1u8,
|
||||||
|
);
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
match state {
|
match state {
|
||||||
InFlightOpState::Ready =>
|
InFlightOpState::Ready => {
|
||||||
{
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if src_ready_flags.cmp_eq([true; COMMON_MOP_SRC_LEN]) {
|
if src_ready_flags.cmp_eq([true; COMMON_MOP_SRC_LEN]) {
|
||||||
connect(ready_op_index, HdlSome(op_index.cast_to(op_index_ty)));
|
connect(ready_op_index, HdlSome(op_index.cast_to(op_index_ty)));
|
||||||
}
|
}
|
||||||
|
connect(
|
||||||
|
ready_for_retire_queue_index,
|
||||||
|
HdlSome(ready_for_retire_queue_index_value),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
InFlightOpState::CanceledAndRunning => {
|
||||||
|
// the instruction has been canceled, but is still
|
||||||
|
// executing so we treat it as if it doesn't exist
|
||||||
|
// other than making sure the in_flight_op slot
|
||||||
|
// isn't reused until execution is done.
|
||||||
|
}
|
||||||
|
InFlightOpState::Running => {
|
||||||
|
connect(
|
||||||
|
ready_for_retire_queue_index,
|
||||||
|
HdlSome(ready_for_retire_queue_index_value),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
InFlightOpState::CanceledAndRunning | InFlightOpState::Running => {}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
connect(empty_op_index, HdlSome(op_index.cast_to(op_index_ty)));
|
connect(empty_op_index, HdlSome(op_index.cast_to(op_index_ty)));
|
||||||
}
|
}
|
||||||
#[hdl]
|
#[hdl]
|
||||||
InFlightOpsSummary::<_> {
|
InFlightOpsSummary::<_, _> {
|
||||||
empty_op_index,
|
empty_op_index,
|
||||||
ready_op_index,
|
ready_op_index,
|
||||||
|
ready_for_retire_queue_index,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -215,22 +220,60 @@ impl<OpIndexWidth: Size> InFlightOpsSummary<OpIndexWidth> {
|
||||||
let l = l.to_expr();
|
let l = l.to_expr();
|
||||||
let r = r.to_expr();
|
let r = r.to_expr();
|
||||||
#[hdl]
|
#[hdl]
|
||||||
InFlightOpsSummary::<_> {
|
let combine_ready_for_retire_queue_index = wire(Expr::ty(l).ready_for_retire_queue_index);
|
||||||
|
#[hdl]
|
||||||
|
if let HdlSome(l_ready_for_retire_queue_index) = l.ready_for_retire_queue_index {
|
||||||
|
#[hdl]
|
||||||
|
if let HdlSome(r_ready_for_retire_queue_index) = r.ready_for_retire_queue_index {
|
||||||
|
#[hdl]
|
||||||
|
if RetireQueueIndex::insns_until(
|
||||||
|
l_ready_for_retire_queue_index,
|
||||||
|
r_ready_for_retire_queue_index,
|
||||||
|
)
|
||||||
|
.cmp_lt(0i8)
|
||||||
|
{
|
||||||
|
connect(
|
||||||
|
combine_ready_for_retire_queue_index,
|
||||||
|
l.ready_for_retire_queue_index,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
connect(
|
||||||
|
combine_ready_for_retire_queue_index,
|
||||||
|
r.ready_for_retire_queue_index,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
connect(
|
||||||
|
combine_ready_for_retire_queue_index,
|
||||||
|
l.ready_for_retire_queue_index,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
connect(
|
||||||
|
combine_ready_for_retire_queue_index,
|
||||||
|
r.ready_for_retire_queue_index,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
InFlightOpsSummary::<_, _> {
|
||||||
empty_op_index: HdlOption::or(l.empty_op_index, r.empty_op_index),
|
empty_op_index: HdlOption::or(l.empty_op_index, r.empty_op_index),
|
||||||
ready_op_index: HdlOption::or(l.ready_op_index, r.ready_op_index),
|
ready_op_index: HdlOption::or(l.ready_op_index, r.ready_op_index),
|
||||||
|
ready_for_retire_queue_index: combine_ready_for_retire_queue_index,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InFlightOpsSummary<DynSize> {
|
impl InFlightOpsSummary<PhantomConst<CpuConfig>, DynSize> {
|
||||||
fn summarize<MOp: Type, MaxInFlight: Size>(
|
fn summarize<MOp: Type, MaxInFlight: Size>(
|
||||||
in_flight_ops: impl ToExpr<Type = ArrayType<HdlOption<InFlightOp<MOp>>, MaxInFlight>>,
|
in_flight_ops: impl ToExpr<
|
||||||
|
Type = ArrayType<HdlOption<InFlightOp<PhantomConst<CpuConfig>, MOp>>, MaxInFlight>,
|
||||||
|
>,
|
||||||
) -> Expr<Self> {
|
) -> Expr<Self> {
|
||||||
let in_flight_ops = in_flight_ops.to_expr();
|
let in_flight_ops = in_flight_ops.to_expr();
|
||||||
let max_in_flight = Expr::ty(in_flight_ops).len();
|
let max_in_flight = 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(
|
reduce(
|
||||||
index_range.map(|i| Self::new(i, index_ty, in_flight_ops[i])),
|
index_range.map(|i| Self::new(i, index_ty, in_flight_ops[i])),
|
||||||
Self::combine,
|
Self::combine,
|
||||||
)
|
)
|
||||||
|
|
@ -239,11 +282,8 @@ impl InFlightOpsSummary<DynSize> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl_module]
|
#[hdl_module]
|
||||||
pub fn unit_base<
|
pub fn unit_base<MOp: Type + MOpTrait<DestReg = (), SrcRegWidth = DynSize>, ExtraOut: Type>(
|
||||||
MOp: Type + MOpTrait<DestReg = UnitOutRegNum<DynSize>, SrcRegWidth = DynSize>,
|
config: PhantomConst<CpuConfig>,
|
||||||
ExtraOut: Type,
|
|
||||||
>(
|
|
||||||
config: &CpuConfig,
|
|
||||||
unit_index: usize,
|
unit_index: usize,
|
||||||
mop_ty: MOp,
|
mop_ty: MOp,
|
||||||
extra_out_ty: ExtraOut,
|
extra_out_ty: ExtraOut,
|
||||||
|
|
@ -251,18 +291,19 @@ pub fn unit_base<
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let cd: ClockDomain = m.input();
|
let cd: ClockDomain = m.input();
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let unit_to_reg_alloc: UnitToRegAlloc<MOp, ExtraOut, DynSize, DynSize, DynSize> =
|
let unit_to_reg_alloc: UnitToRegAlloc<PhantomConst<CpuConfig>, MOp, ExtraOut> =
|
||||||
m.output(config.unit_to_reg_alloc(mop_ty, extra_out_ty));
|
m.output(UnitToRegAlloc[config][mop_ty][extra_out_ty]);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let execute_start: ReadyValid<ExecuteStart<MOp>> = m.output(ReadyValid[ExecuteStart[mop_ty]]);
|
let execute_start: ReadyValid<ExecuteStart<PhantomConst<CpuConfig>, MOp>> =
|
||||||
|
m.output(ReadyValid[ExecuteStart[config][mop_ty]]);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let execute_end: HdlOption<ExecuteEnd<DynSize, ExtraOut>> =
|
let execute_end: HdlOption<ExecuteEnd<PhantomConst<CpuConfig>, ExtraOut>> =
|
||||||
m.input(HdlOption[ExecuteEnd[config.out_reg_num_width][extra_out_ty]]);
|
m.input(HdlOption[ExecuteEnd[config][extra_out_ty]]);
|
||||||
|
|
||||||
connect(execute_start.data, Expr::ty(execute_start).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.get().unit_max_in_flight(unit_index).get();
|
||||||
let in_flight_op_ty = InFlightOp[mop_ty];
|
let in_flight_op_ty = InFlightOp[config][mop_ty];
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let in_flight_ops = reg_builder()
|
let in_flight_ops = reg_builder()
|
||||||
.clock_domain(cd)
|
.clock_domain(cd)
|
||||||
|
|
@ -278,17 +319,21 @@ pub fn unit_base<
|
||||||
HdlOption::is_some(in_flight_ops_summary.empty_op_index),
|
HdlOption::is_some(in_flight_ops_summary.empty_op_index),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
connect(
|
||||||
|
unit_to_reg_alloc.ready_for_retire_queue_index,
|
||||||
|
in_flight_ops_summary.ready_for_retire_queue_index,
|
||||||
|
);
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let UnitForwardingInfo::<_, _, _> {
|
let UnitForwardingInfo::<_> {
|
||||||
unit_output_writes,
|
unit_output_writes,
|
||||||
unit_reg_frees,
|
unit_reg_frees,
|
||||||
_phantom: _,
|
|
||||||
} = unit_to_reg_alloc.unit_forwarding_info;
|
} = unit_to_reg_alloc.unit_forwarding_info;
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let read_src_regs = wire(mop_ty.src_regs_ty());
|
let read_src_regs = wire(mop_ty.src_regs_ty());
|
||||||
connect(
|
connect(
|
||||||
read_src_regs,
|
read_src_regs,
|
||||||
repeat(config.p_reg_num().const_zero().cast_to_bits(), ConstUsize),
|
repeat(PRegNum[config].const_zero().cast_to_bits(), ConstUsize),
|
||||||
);
|
);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let read_src_values = wire();
|
let read_src_values = wire();
|
||||||
|
|
@ -297,7 +342,7 @@ pub fn unit_base<
|
||||||
let input_src_regs = wire(mop_ty.src_regs_ty());
|
let input_src_regs = wire(mop_ty.src_regs_ty());
|
||||||
connect(
|
connect(
|
||||||
input_src_regs,
|
input_src_regs,
|
||||||
repeat(config.p_reg_num().const_zero().cast_to_bits(), ConstUsize),
|
repeat(PRegNum[config].const_zero().cast_to_bits(), ConstUsize),
|
||||||
);
|
);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let input_src_regs_valid = wire();
|
let input_src_regs_valid = wire();
|
||||||
|
|
@ -309,7 +354,7 @@ pub fn unit_base<
|
||||||
Bool,
|
Bool,
|
||||||
SourceLocation::caller(),
|
SourceLocation::caller(),
|
||||||
);
|
);
|
||||||
mem.depth(1 << config.out_reg_num_width);
|
mem.depth(1 << UnitOutRegNumWidth[config]);
|
||||||
mem
|
mem
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
@ -319,11 +364,11 @@ pub fn unit_base<
|
||||||
PRegValue,
|
PRegValue,
|
||||||
SourceLocation::caller(),
|
SourceLocation::caller(),
|
||||||
);
|
);
|
||||||
unit_output_regs.depth(1 << config.out_reg_num_width);
|
unit_output_regs.depth(1 << UnitOutRegNumWidth[config]);
|
||||||
|
|
||||||
for src_index in 0..COMMON_MOP_SRC_LEN {
|
for src_index in 0..COMMON_MOP_SRC_LEN {
|
||||||
let read_port = unit_output_regs.new_read_port();
|
let read_port = unit_output_regs.new_read_port();
|
||||||
let p_reg_num = read_src_regs[src_index].cast_bits_to(config.p_reg_num());
|
let p_reg_num = read_src_regs[src_index].cast_bits_to(PRegNum[config]);
|
||||||
connect_any(read_port.addr, p_reg_num.unit_out_reg.value);
|
connect_any(read_port.addr, p_reg_num.unit_out_reg.value);
|
||||||
connect(read_port.en, false);
|
connect(read_port.en, false);
|
||||||
connect(read_port.clk, cd.clk);
|
connect(read_port.clk, cd.clk);
|
||||||
|
|
@ -336,7 +381,7 @@ pub fn unit_base<
|
||||||
|
|
||||||
for src_index in 0..COMMON_MOP_SRC_LEN {
|
for src_index in 0..COMMON_MOP_SRC_LEN {
|
||||||
let read_port = unit_output_regs_valid[unit_index].new_read_port();
|
let read_port = unit_output_regs_valid[unit_index].new_read_port();
|
||||||
let p_reg_num = input_src_regs[src_index].cast_bits_to(config.p_reg_num());
|
let p_reg_num = input_src_regs[src_index].cast_bits_to(PRegNum[config]);
|
||||||
connect_any(read_port.addr, p_reg_num.unit_out_reg.value);
|
connect_any(read_port.addr, p_reg_num.unit_out_reg.value);
|
||||||
connect(read_port.en, false);
|
connect(read_port.en, false);
|
||||||
connect(read_port.clk, cd.clk);
|
connect(read_port.clk, cd.clk);
|
||||||
|
|
@ -361,15 +406,15 @@ pub fn unit_base<
|
||||||
connect(ready_write_port.mask, true);
|
connect(ready_write_port.mask, true);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if let HdlSome(unit_output_write) = unit_output_writes[unit_index] {
|
if let HdlSome(unit_output_write) = unit_output_writes[unit_index] {
|
||||||
connect_any(write_port.addr, unit_output_write.which.value);
|
connect_any(write_port.addr, unit_output_write.dest.value);
|
||||||
connect(write_port.data, unit_output_write.value);
|
connect(write_port.data, unit_output_write.value);
|
||||||
connect(write_port.en, true);
|
connect(write_port.en, true);
|
||||||
connect_any(ready_write_port.addr, unit_output_write.which.value);
|
connect_any(ready_write_port.addr, unit_output_write.dest.value);
|
||||||
connect(ready_write_port.en, true);
|
connect(ready_write_port.en, true);
|
||||||
let p_reg_num = #[hdl]
|
let p_reg_num = #[hdl]
|
||||||
PRegNum::<_, _> {
|
PRegNum::<_> {
|
||||||
unit_num: config.unit_num().from_index(unit_index),
|
unit_num: UnitNum[config].from_index(unit_index),
|
||||||
unit_out_reg: unit_output_write.which,
|
unit_out_reg: unit_output_write.dest,
|
||||||
};
|
};
|
||||||
for src_index in 0..COMMON_MOP_SRC_LEN {
|
for src_index in 0..COMMON_MOP_SRC_LEN {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -399,9 +444,8 @@ pub fn unit_base<
|
||||||
execute_start.data,
|
execute_start.data,
|
||||||
HdlSome(
|
HdlSome(
|
||||||
#[hdl]
|
#[hdl]
|
||||||
ExecuteStart::<_> {
|
ExecuteStart::<_, _> {
|
||||||
mop: in_flight_op.mop,
|
insn: in_flight_op.insn,
|
||||||
pc: in_flight_op.pc,
|
|
||||||
src_values: read_src_values,
|
src_values: read_src_values,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
@ -420,12 +464,17 @@ pub fn unit_base<
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if let HdlSome(input) = ReadyValid::firing_data(unit_to_reg_alloc.input) {
|
if let HdlSome(input) = ReadyValid::firing_data(unit_to_reg_alloc.input) {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let UnitInput::<_> { mop, pc } = input;
|
let RenamedInsnData::<_, _, _> {
|
||||||
|
retire_queue_index,
|
||||||
|
pc: _,
|
||||||
|
dest: _,
|
||||||
|
mop,
|
||||||
|
} = input;
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let input_mop_src_regs = wire(mop_ty.src_regs_ty());
|
let input_mop_src_regs = wire(mop_ty.src_regs_ty());
|
||||||
connect(
|
connect(
|
||||||
input_mop_src_regs,
|
input_mop_src_regs,
|
||||||
repeat(config.p_reg_num().const_zero().cast_to_bits(), ConstUsize),
|
repeat(PRegNum[config].const_zero().cast_to_bits(), ConstUsize),
|
||||||
);
|
);
|
||||||
MOp::connect_src_regs(mop, input_mop_src_regs);
|
MOp::connect_src_regs(mop, input_mop_src_regs);
|
||||||
let src_ready_flags = wire_with_loc(
|
let src_ready_flags = wire_with_loc(
|
||||||
|
|
@ -436,20 +485,24 @@ pub fn unit_base<
|
||||||
connect(src_ready_flags, input_src_regs_valid);
|
connect(src_ready_flags, input_src_regs_valid);
|
||||||
connect(input_src_regs, input_mop_src_regs);
|
connect(input_src_regs, input_mop_src_regs);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if unit_to_reg_alloc.cancel_input.cmp_ne(HdlSome(
|
let input_is_canceled = wire();
|
||||||
#[hdl]
|
connect(input_is_canceled, false);
|
||||||
UnitCancelInput::<_> {
|
#[hdl]
|
||||||
which: MOp::dest_reg(mop),
|
if let HdlSome(cancel_input) = unit_to_reg_alloc.cancel_input {
|
||||||
},
|
connect(
|
||||||
)) {
|
input_is_canceled,
|
||||||
|
UnitCancelInput::is_canceled(cancel_input, retire_queue_index),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
if !input_is_canceled {
|
||||||
connect(
|
connect(
|
||||||
input_in_flight_op,
|
input_in_flight_op,
|
||||||
HdlSome(
|
HdlSome(
|
||||||
#[hdl]
|
#[hdl]
|
||||||
InFlightOp::<_> {
|
InFlightOp::<_, _> {
|
||||||
state: InFlightOpState.Ready(),
|
state: InFlightOpState.Ready(),
|
||||||
mop,
|
insn: input,
|
||||||
pc,
|
|
||||||
src_ready_flags,
|
src_ready_flags,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
@ -483,13 +536,11 @@ pub fn unit_base<
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if let HdlSome(in_flight_op) = in_flight_ops[in_flight_op_index] {
|
if let HdlSome(in_flight_op) = in_flight_ops[in_flight_op_index] {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let InFlightOp::<_> {
|
let InFlightOp::<_, _> {
|
||||||
state,
|
state,
|
||||||
mop,
|
insn,
|
||||||
pc,
|
|
||||||
src_ready_flags,
|
src_ready_flags,
|
||||||
} = in_flight_op;
|
} = in_flight_op;
|
||||||
let which = MOp::dest_reg(mop);
|
|
||||||
let src_regs = wire_with_loc(
|
let src_regs = wire_with_loc(
|
||||||
&format!("in_flight_op_src_regs_{in_flight_op_index}"),
|
&format!("in_flight_op_src_regs_{in_flight_op_index}"),
|
||||||
SourceLocation::caller(),
|
SourceLocation::caller(),
|
||||||
|
|
@ -497,9 +548,9 @@ pub fn unit_base<
|
||||||
);
|
);
|
||||||
connect(
|
connect(
|
||||||
src_regs,
|
src_regs,
|
||||||
repeat(config.p_reg_num().const_zero().cast_to_bits(), ConstUsize),
|
repeat(PRegNum[config].const_zero().cast_to_bits(), ConstUsize),
|
||||||
);
|
);
|
||||||
MOp::connect_src_regs(mop, src_regs);
|
MOp::connect_src_regs(insn.mop, src_regs);
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if in_flight_ops_summary.ready_op_index.cmp_eq(HdlSome(
|
if in_flight_ops_summary.ready_op_index.cmp_eq(HdlSome(
|
||||||
|
|
@ -517,12 +568,12 @@ pub fn unit_base<
|
||||||
if let HdlSome(unit_output_write) = unit_output_writes[unit_index] {
|
if let HdlSome(unit_output_write) = unit_output_writes[unit_index] {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let UnitOutputWrite::<_> {
|
let UnitOutputWrite::<_> {
|
||||||
which: unit_out_reg,
|
dest: unit_out_reg,
|
||||||
value: _,
|
value: _,
|
||||||
} = unit_output_write;
|
} = unit_output_write;
|
||||||
let p_reg_num = #[hdl]
|
let p_reg_num = #[hdl]
|
||||||
PRegNum::<_, _> {
|
PRegNum::<_> {
|
||||||
unit_num: config.unit_num().from_index(unit_index),
|
unit_num: UnitNum[config].from_index(unit_index),
|
||||||
unit_out_reg,
|
unit_out_reg,
|
||||||
};
|
};
|
||||||
for src_index in 0..COMMON_MOP_SRC_LEN {
|
for src_index in 0..COMMON_MOP_SRC_LEN {
|
||||||
|
|
@ -537,20 +588,21 @@ pub fn unit_base<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(
|
connect(in_flight_op_canceling[in_flight_op_index], false);
|
||||||
in_flight_op_canceling[in_flight_op_index],
|
#[hdl]
|
||||||
unit_to_reg_alloc.cancel_input.cmp_eq(HdlSome(
|
if let HdlSome(cancel_input) = unit_to_reg_alloc.cancel_input {
|
||||||
#[hdl]
|
connect(
|
||||||
UnitCancelInput::<_> { which },
|
in_flight_op_canceling[in_flight_op_index],
|
||||||
)),
|
UnitCancelInput::is_canceled(cancel_input, insn.retire_queue_index),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if let HdlSome(execute_end) = execute_end {
|
if let HdlSome(execute_end) = execute_end {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let ExecuteEnd::<_, _> { unit_output } = execute_end;
|
let ExecuteEnd::<_, _> { unit_output } = execute_end;
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if which.cmp_eq(unit_output.which) {
|
if insn.dest.cmp_eq(unit_output.dest) {
|
||||||
connect(in_flight_op_execute_ending[in_flight_op_index], true);
|
connect(in_flight_op_execute_ending[in_flight_op_index], true);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if !in_flight_op_canceling[in_flight_op_index] {
|
if !in_flight_op_canceling[in_flight_op_index] {
|
||||||
|
|
@ -567,7 +619,7 @@ pub fn unit_base<
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if let HdlSome(execute_start) = ReadyValid::firing_data(execute_start) {
|
if let HdlSome(execute_start) = ReadyValid::firing_data(execute_start) {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if which.cmp_eq(MOp::dest_reg(execute_start.mop)) {
|
if insn.dest.cmp_eq(execute_start.insn.dest) {
|
||||||
connect(in_flight_op_execute_starting[in_flight_op_index], true);
|
connect(in_flight_op_execute_starting[in_flight_op_index], true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -594,10 +646,9 @@ pub fn unit_base<
|
||||||
in_flight_ops[in_flight_op_index],
|
in_flight_ops[in_flight_op_index],
|
||||||
HdlSome(
|
HdlSome(
|
||||||
#[hdl]
|
#[hdl]
|
||||||
InFlightOp::<_> {
|
InFlightOp::<_, _> {
|
||||||
state,
|
state,
|
||||||
mop,
|
insn,
|
||||||
pc,
|
|
||||||
src_ready_flags: in_flight_op_next_src_ready_flags[in_flight_op_index],
|
src_ready_flags: in_flight_op_next_src_ready_flags[in_flight_op_index],
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
pub mod array_vec;
|
pub mod array_vec;
|
||||||
pub mod tree_reduce;
|
|
||||||
|
|
||||||
pub(crate) const fn range_u32_len(range: &std::ops::Range<u32>) -> usize {
|
pub(crate) const fn range_u32_len(range: &std::ops::Range<u32>) -> usize {
|
||||||
let retval = range.end.saturating_sub(range.start);
|
let retval = range.end.saturating_sub(range.start);
|
||||||
|
|
@ -25,3 +24,16 @@ 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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) const fn range_intersection(
|
||||||
|
a: &std::ops::Range<u32>,
|
||||||
|
b: &std::ops::Range<u32>,
|
||||||
|
) -> Option<std::ops::Range<u32>> {
|
||||||
|
let start = if a.start > b.start { a.start } else { b.start };
|
||||||
|
let end = if a.end < b.end { a.end } else { b.end };
|
||||||
|
if start < end {
|
||||||
|
Some(start..end)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,150 @@
|
||||||
// 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::{
|
||||||
|
expr::{
|
||||||
|
ops::{ExprCastTo, ExprIndex, ExprPartialEq, ExprPartialOrd},
|
||||||
|
ToLiteralBits,
|
||||||
|
},
|
||||||
|
int::{IntType, SizeType},
|
||||||
|
intern::{Intern, Interned},
|
||||||
|
prelude::*,
|
||||||
|
ty::{MatchVariantWithoutScope, StaticType, TypeProperties},
|
||||||
|
};
|
||||||
|
use std::{marker::PhantomData, ops::Index};
|
||||||
|
|
||||||
#[hdl]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||||
pub type Length<Max: Size> = UIntInRangeInclusiveType<ConstUsize<0>, Max>;
|
pub struct Length<Max: Size> {
|
||||||
|
ty: UInt,
|
||||||
|
_phantom: PhantomData<Max>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Max: Size> Length<Max> {
|
||||||
|
pub fn new(max: Max::SizeType) -> Self {
|
||||||
|
Self {
|
||||||
|
ty: UInt::range_inclusive(0..=Max::as_usize(max)),
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn ty(self) -> UInt {
|
||||||
|
self.ty
|
||||||
|
}
|
||||||
|
pub fn zero(self) -> Expr<Self> {
|
||||||
|
Self::from_uint_unchecked(self.ty.zero())
|
||||||
|
}
|
||||||
|
pub fn from_uint_unchecked(v: impl ToExpr<Type = UInt>) -> Expr<Self> {
|
||||||
|
Expr::from_canonical(Expr::canonical(v.to_expr()))
|
||||||
|
}
|
||||||
|
pub fn cast_from_uint_unchecked<SrcWidth: Size>(
|
||||||
|
self,
|
||||||
|
v: impl ToExpr<Type = UIntType<SrcWidth>>,
|
||||||
|
) -> Expr<Self> {
|
||||||
|
Self::from_uint_unchecked(v.to_expr().cast_to(self.ty))
|
||||||
|
}
|
||||||
|
pub fn as_uint(this: impl ToExpr<Type = Self>) -> Expr<UInt> {
|
||||||
|
let this = this.to_expr();
|
||||||
|
this.cast_to(Expr::ty(this).ty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Max: Size, DestWidth: Size> ExprCastTo<UIntType<DestWidth>> for Length<Max> {
|
||||||
|
fn cast_to(src: Expr<Self>, to_type: UIntType<DestWidth>) -> Expr<UIntType<DestWidth>> {
|
||||||
|
Expr::<UInt>::from_canonical(Expr::canonical(src)).cast_to(to_type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
pub const Length: __LengthWithoutGenerics = __LengthWithoutGenerics {};
|
||||||
|
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub struct __LengthWithoutGenerics {}
|
||||||
|
|
||||||
|
impl<M: SizeType> Index<M> for __LengthWithoutGenerics {
|
||||||
|
type Output = Length<M::Size>;
|
||||||
|
|
||||||
|
fn index(&self, max: M) -> &Self::Output {
|
||||||
|
Interned::into_inner(Length::new(max).intern_sized())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Max: Size> Type for Length<Max> {
|
||||||
|
type BaseType = UInt;
|
||||||
|
type MaskType = Bool;
|
||||||
|
type MatchVariant = Expr<Self>;
|
||||||
|
type MatchActiveScope = ();
|
||||||
|
type MatchVariantAndInactiveScope = MatchVariantWithoutScope<Self::MatchVariant>;
|
||||||
|
type MatchVariantsIter = std::iter::Once<Self::MatchVariantAndInactiveScope>;
|
||||||
|
fn match_variants(
|
||||||
|
this: Expr<Self>,
|
||||||
|
source_location: SourceLocation,
|
||||||
|
) -> Self::MatchVariantsIter {
|
||||||
|
let _ = source_location;
|
||||||
|
std::iter::once(MatchVariantWithoutScope(this))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mask_type(&self) -> Self::MaskType {
|
||||||
|
Bool
|
||||||
|
}
|
||||||
|
|
||||||
|
fn canonical(&self) -> CanonicalType {
|
||||||
|
self.ty.canonical()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_canonical(canonical_type: CanonicalType) -> Self {
|
||||||
|
let ty = <UInt>::from_canonical(canonical_type);
|
||||||
|
if let Some(known_max) = Max::KNOWN_VALUE {
|
||||||
|
assert_eq!(ty, UInt::range_inclusive(0..=known_max));
|
||||||
|
}
|
||||||
|
Self {
|
||||||
|
ty,
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn source_location() -> SourceLocation {
|
||||||
|
SourceLocation::caller()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Max: KnownSize> StaticType for Length<Max> {
|
||||||
|
const TYPE: Self = Self {
|
||||||
|
ty: UInt {
|
||||||
|
width: Max::VALUE.next_power_of_two().ilog2() as usize,
|
||||||
|
},
|
||||||
|
_phantom: PhantomData,
|
||||||
|
};
|
||||||
|
const MASK_TYPE: Self::MaskType = Bool;
|
||||||
|
const TYPE_PROPERTIES: TypeProperties = {
|
||||||
|
let mut p = <UInt<1>>::TYPE_PROPERTIES;
|
||||||
|
p.bit_width = Self::TYPE.ty.width;
|
||||||
|
p
|
||||||
|
};
|
||||||
|
const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Max: Size> ExprPartialEq<Self> for Length<Max> {
|
||||||
|
fn cmp_eq(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||||
|
Self::as_uint(lhs).cmp_eq(Self::as_uint(rhs))
|
||||||
|
}
|
||||||
|
fn cmp_ne(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||||
|
Self::as_uint(lhs).cmp_ne(Self::as_uint(rhs))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Max: Size> ExprPartialOrd<Self> for Length<Max> {
|
||||||
|
fn cmp_lt(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||||
|
Self::as_uint(lhs).cmp_lt(Self::as_uint(rhs))
|
||||||
|
}
|
||||||
|
fn cmp_le(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||||
|
Self::as_uint(lhs).cmp_le(Self::as_uint(rhs))
|
||||||
|
}
|
||||||
|
fn cmp_gt(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||||
|
Self::as_uint(lhs).cmp_gt(Self::as_uint(rhs))
|
||||||
|
}
|
||||||
|
fn cmp_ge(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||||
|
Self::as_uint(lhs).cmp_ge(Self::as_uint(rhs))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// like [`std::vec::Vec`], except with a [`Expr`] for [`len()`][`Self::len()`] and a fixed capacity
|
/// like [`std::vec::Vec`], except with a [`Expr`] for [`len()`][`Self::len()`] and a fixed capacity
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -19,7 +159,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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn element(self) -> T {
|
pub fn element(self) -> T {
|
||||||
|
|
@ -39,7 +179,7 @@ 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(Expr::ty(elements).len())],
|
Length::new(N::from_usize(Expr::ty(elements).len())),
|
||||||
Expr::ty(len),
|
Expr::ty(len),
|
||||||
"len type mismatch",
|
"len type mismatch",
|
||||||
);
|
);
|
||||||
|
|
@ -54,7 +194,7 @@ impl<T: Type, N: Size> ArrayVec<T, N> {
|
||||||
}
|
}
|
||||||
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()
|
||||||
|
|
@ -70,7 +210,7 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -112,6 +252,29 @@ impl<T: Type, N: Size> ArrayVec<T, N> {
|
||||||
});
|
});
|
||||||
array_vec_as_array_of_options
|
array_vec_as_array_of_options
|
||||||
}
|
}
|
||||||
|
#[hdl]
|
||||||
|
pub fn get<Idx: IntType<Dyn = UInt>>(
|
||||||
|
this: impl ToExpr<Type = Self>,
|
||||||
|
index: impl ToExpr<Type = Idx>,
|
||||||
|
) -> Expr<HdlOption<T>> {
|
||||||
|
let this = this.to_expr();
|
||||||
|
let index = Expr::as_dyn_int(index.to_expr());
|
||||||
|
let never_in_bounds = index.cmp_ge(Expr::ty(this).capacity());
|
||||||
|
if let Ok(never_in_bounds) = never_in_bounds.to_literal_bits() {
|
||||||
|
if never_in_bounds[0] {
|
||||||
|
// avoid error from out-of-bounds constant index
|
||||||
|
return HdlOption[Expr::ty(this).element()].HdlNone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
let array_vec_get = wire(HdlOption[Expr::ty(this).element()]);
|
||||||
|
connect(array_vec_get, Expr::ty(array_vec_get).HdlNone());
|
||||||
|
#[hdl]
|
||||||
|
if index.cmp_lt(Length::as_uint(Self::len(this))) {
|
||||||
|
connect(array_vec_get, HdlSome(this.elements[index]));
|
||||||
|
}
|
||||||
|
array_vec_get
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Type, N: Size, Idx, IdxWidth: Size> ExprIndex<Idx> for ArrayVec<T, N>
|
impl<T: Type, N: Size, Idx, IdxWidth: Size> ExprIndex<Idx> for ArrayVec<T, N>
|
||||||
|
|
@ -126,3 +289,35 @@ where
|
||||||
<ArrayType<T, N> as ExprIndex<Idx>>::expr_index(&this.elements, index)
|
<ArrayType<T, N> as ExprIndex<Idx>>::expr_index(&this.elements, index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
|
pub struct ReadyValidArray<T: Type, N: Size> {
|
||||||
|
pub data: ArrayVec<T, N>,
|
||||||
|
#[hdl(flip)]
|
||||||
|
pub ready: Length<N>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Type, N: Size> ReadyValidArray<T, N> {
|
||||||
|
#[hdl]
|
||||||
|
pub fn firing_len(this: impl ToExpr<Type = Self>) -> Expr<Length<N>> {
|
||||||
|
let this = this.to_expr();
|
||||||
|
assert_eq!(Expr::ty(this).data.len_ty(), Expr::ty(this).ready);
|
||||||
|
#[hdl]
|
||||||
|
let firing_len = wire(Expr::ty(this).data.len);
|
||||||
|
connect(firing_len, this.data.len);
|
||||||
|
#[hdl]
|
||||||
|
if this.data.len.cmp_gt(this.ready) {
|
||||||
|
connect(firing_len, this.ready);
|
||||||
|
}
|
||||||
|
firing_len
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
pub fn firing_data(this: impl ToExpr<Type = Self>) -> Expr<ArrayVec<T, N>> {
|
||||||
|
let this = this.to_expr();
|
||||||
|
#[hdl]
|
||||||
|
let firing_data = wire(Expr::ty(this).data);
|
||||||
|
connect(firing_data, this.data);
|
||||||
|
connect(firing_data.len, Self::firing_len(this));
|
||||||
|
firing_data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,152 +0,0 @@
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
||||||
// See Notices.txt for copyright information
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
|
||||||
pub enum TreeReduceOp {
|
|
||||||
Input,
|
|
||||||
Reduce,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
struct Entry {
|
|
||||||
start: usize,
|
|
||||||
depth: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct TreeReduceOps {
|
|
||||||
len: usize,
|
|
||||||
stack: Vec<Entry>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TreeReduceOps {
|
|
||||||
pub fn new(len: usize) -> Self {
|
|
||||||
TreeReduceOps {
|
|
||||||
len,
|
|
||||||
stack: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Iterator for TreeReduceOps {
|
|
||||||
type Item = TreeReduceOp;
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
match *self.stack {
|
|
||||||
[] if self.len != 0 => {
|
|
||||||
self.stack.push(Entry { start: 0, depth: 0 });
|
|
||||||
Some(TreeReduceOp::Input)
|
|
||||||
}
|
|
||||||
[.., ref mut second_last, last] if second_last.depth == last.depth => {
|
|
||||||
second_last.depth += 1;
|
|
||||||
self.stack.pop();
|
|
||||||
Some(TreeReduceOp::Reduce)
|
|
||||||
}
|
|
||||||
[.., last] if self.len - last.start > 1 << last.depth => {
|
|
||||||
let start = last.start + (1 << last.depth);
|
|
||||||
self.stack.push(Entry { start, depth: 0 });
|
|
||||||
Some(TreeReduceOp::Input)
|
|
||||||
}
|
|
||||||
[.., ref mut second_last, _] => {
|
|
||||||
second_last.depth += 1;
|
|
||||||
self.stack.pop();
|
|
||||||
Some(TreeReduceOp::Reduce)
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[track_caller]
|
|
||||||
pub fn tree_reduce_with_state<S, I, R>(
|
|
||||||
iter: impl IntoIterator<IntoIter: ExactSizeIterator, Item = I>,
|
|
||||||
state: &mut S,
|
|
||||||
mut input: impl FnMut(&mut S, I) -> R,
|
|
||||||
mut reduce: impl FnMut(&mut S, R, R) -> R,
|
|
||||||
) -> Option<R> {
|
|
||||||
let mut stack = Vec::new();
|
|
||||||
let mut iter = iter.into_iter();
|
|
||||||
for op in TreeReduceOps::new(iter.len()) {
|
|
||||||
match op {
|
|
||||||
TreeReduceOp::Input => stack.push(input(
|
|
||||||
state,
|
|
||||||
iter.next().expect("inconsistent iterator len() and next()"),
|
|
||||||
)),
|
|
||||||
TreeReduceOp::Reduce => {
|
|
||||||
let Some(r) = stack.pop() else {
|
|
||||||
unreachable!();
|
|
||||||
};
|
|
||||||
let Some(l) = stack.pop() else {
|
|
||||||
unreachable!();
|
|
||||||
};
|
|
||||||
stack.push(reduce(state, l, r));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stack.pop()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn tree_reduce<T>(
|
|
||||||
iter: impl IntoIterator<Item = T, IntoIter: ExactSizeIterator>,
|
|
||||||
mut reduce: impl FnMut(T, T) -> T,
|
|
||||||
) -> Option<T> {
|
|
||||||
tree_reduce_with_state(iter, &mut (), |_, v| v, move |_, l, r| reduce(l, r))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use std::ops::Range;
|
|
||||||
|
|
||||||
fn recursive_tree_reduce(range: Range<usize>, ops: &mut Vec<TreeReduceOp>) {
|
|
||||||
if range.len() == 1 {
|
|
||||||
ops.push(TreeReduceOp::Input);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if range.is_empty() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let pow2_len = range.len().next_power_of_two();
|
|
||||||
let split = range.start + pow2_len / 2;
|
|
||||||
recursive_tree_reduce(range.start..split, ops);
|
|
||||||
recursive_tree_reduce(split..range.end, ops);
|
|
||||||
ops.push(TreeReduceOp::Reduce);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_tree_reduce() {
|
|
||||||
const EXPECTED: &'static [&'static [TreeReduceOp]] = {
|
|
||||||
use TreeReduceOp::{Input as I, Reduce as R};
|
|
||||||
&[
|
|
||||||
&[],
|
|
||||||
&[I],
|
|
||||||
&[I, I, R],
|
|
||||||
&[I, I, R, I, R],
|
|
||||||
&[I, I, R, I, I, R, R],
|
|
||||||
&[I, I, R, I, I, R, R, I, R],
|
|
||||||
&[I, I, R, I, I, R, R, I, I, R, R],
|
|
||||||
&[I, I, R, I, I, R, R, I, I, R, I, R, R],
|
|
||||||
&[I, I, R, I, I, R, R, I, I, R, I, I, R, R, R],
|
|
||||||
]
|
|
||||||
};
|
|
||||||
for len in 0..64 {
|
|
||||||
let mut expected = vec![];
|
|
||||||
recursive_tree_reduce(0..len, &mut expected);
|
|
||||||
if let Some(&expected2) = EXPECTED.get(len) {
|
|
||||||
assert_eq!(*expected, *expected2, "len={len}");
|
|
||||||
}
|
|
||||||
assert_eq!(
|
|
||||||
TreeReduceOps::new(len).collect::<Vec<_>>(),
|
|
||||||
expected,
|
|
||||||
"len={len}"
|
|
||||||
);
|
|
||||||
let seq: Vec<_> = (0..len).collect();
|
|
||||||
assert_eq!(
|
|
||||||
seq,
|
|
||||||
tree_reduce(seq.iter().map(|&v| vec![v]), |mut l, r| {
|
|
||||||
l.extend_from_slice(&r);
|
|
||||||
l
|
|
||||||
})
|
|
||||||
.unwrap_or_default()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -16832,6 +16832,38 @@ $upscope $end
|
||||||
$upscope $end
|
$upscope $end
|
||||||
$enddefinitions $end
|
$enddefinitions $end
|
||||||
$dumpvars
|
$dumpvars
|
||||||
|
0vg
|
||||||
|
0wg
|
||||||
|
0xg
|
||||||
|
0yg
|
||||||
|
0zg
|
||||||
|
0{g
|
||||||
|
0|g
|
||||||
|
0}g
|
||||||
|
0~g
|
||||||
|
0!h
|
||||||
|
0"h
|
||||||
|
0#h
|
||||||
|
0$h
|
||||||
|
0%h
|
||||||
|
0&h
|
||||||
|
0'h
|
||||||
|
0(h
|
||||||
|
0)h
|
||||||
|
0*h
|
||||||
|
0+h
|
||||||
|
0,h
|
||||||
|
0-h
|
||||||
|
0.h
|
||||||
|
0/h
|
||||||
|
00h
|
||||||
|
01h
|
||||||
|
02h
|
||||||
|
03h
|
||||||
|
04h
|
||||||
|
05h
|
||||||
|
06h
|
||||||
|
07h
|
||||||
b0 (_
|
b0 (_
|
||||||
b0 ia
|
b0 ia
|
||||||
b0 )_
|
b0 )_
|
||||||
|
|
@ -17338,26 +17370,6 @@ b0 ga
|
||||||
b0 Jd
|
b0 Jd
|
||||||
b0 ha
|
b0 ha
|
||||||
b0 Kd
|
b0 Kd
|
||||||
b0 Ld
|
|
||||||
b0 Nd
|
|
||||||
b0 Md
|
|
||||||
b0 Od
|
|
||||||
0Pd
|
|
||||||
0Qd
|
|
||||||
0Rd
|
|
||||||
0Sd
|
|
||||||
0Td
|
|
||||||
0Ud
|
|
||||||
0Vd
|
|
||||||
0Wd
|
|
||||||
0Xd
|
|
||||||
0Yd
|
|
||||||
0Zd
|
|
||||||
0[d
|
|
||||||
0\d
|
|
||||||
0]d
|
|
||||||
0^d
|
|
||||||
0_d
|
|
||||||
0`d
|
0`d
|
||||||
0ad
|
0ad
|
||||||
0bd
|
0bd
|
||||||
|
|
@ -17374,326 +17386,6 @@ b0 Od
|
||||||
0md
|
0md
|
||||||
0nd
|
0nd
|
||||||
0od
|
0od
|
||||||
b0 pd
|
|
||||||
0"e
|
|
||||||
02e
|
|
||||||
0Be
|
|
||||||
0Re
|
|
||||||
0be
|
|
||||||
0re
|
|
||||||
0$f
|
|
||||||
04f
|
|
||||||
b0 qd
|
|
||||||
0#e
|
|
||||||
03e
|
|
||||||
0Ce
|
|
||||||
0Se
|
|
||||||
0ce
|
|
||||||
0se
|
|
||||||
0%f
|
|
||||||
05f
|
|
||||||
b0 rd
|
|
||||||
0$e
|
|
||||||
04e
|
|
||||||
0De
|
|
||||||
0Te
|
|
||||||
0de
|
|
||||||
0te
|
|
||||||
0&f
|
|
||||||
06f
|
|
||||||
b0 sd
|
|
||||||
0%e
|
|
||||||
05e
|
|
||||||
0Ee
|
|
||||||
0Ue
|
|
||||||
0ee
|
|
||||||
0ue
|
|
||||||
0'f
|
|
||||||
07f
|
|
||||||
b0 td
|
|
||||||
0&e
|
|
||||||
06e
|
|
||||||
0Fe
|
|
||||||
0Ve
|
|
||||||
0fe
|
|
||||||
0ve
|
|
||||||
0(f
|
|
||||||
08f
|
|
||||||
b0 ud
|
|
||||||
0'e
|
|
||||||
07e
|
|
||||||
0Ge
|
|
||||||
0We
|
|
||||||
0ge
|
|
||||||
0we
|
|
||||||
0)f
|
|
||||||
09f
|
|
||||||
b0 vd
|
|
||||||
0(e
|
|
||||||
08e
|
|
||||||
0He
|
|
||||||
0Xe
|
|
||||||
0he
|
|
||||||
0xe
|
|
||||||
0*f
|
|
||||||
0:f
|
|
||||||
b0 wd
|
|
||||||
0)e
|
|
||||||
09e
|
|
||||||
0Ie
|
|
||||||
0Ye
|
|
||||||
0ie
|
|
||||||
0ye
|
|
||||||
0+f
|
|
||||||
0;f
|
|
||||||
b0 xd
|
|
||||||
0*e
|
|
||||||
0:e
|
|
||||||
0Je
|
|
||||||
0Ze
|
|
||||||
0je
|
|
||||||
0ze
|
|
||||||
0,f
|
|
||||||
0<f
|
|
||||||
b0 yd
|
|
||||||
0+e
|
|
||||||
0;e
|
|
||||||
0Ke
|
|
||||||
0[e
|
|
||||||
0ke
|
|
||||||
0{e
|
|
||||||
0-f
|
|
||||||
0=f
|
|
||||||
b0 zd
|
|
||||||
0,e
|
|
||||||
0<e
|
|
||||||
0Le
|
|
||||||
0\e
|
|
||||||
0le
|
|
||||||
0|e
|
|
||||||
0.f
|
|
||||||
0>f
|
|
||||||
b0 {d
|
|
||||||
0-e
|
|
||||||
0=e
|
|
||||||
0Me
|
|
||||||
0]e
|
|
||||||
0me
|
|
||||||
0}e
|
|
||||||
0/f
|
|
||||||
0?f
|
|
||||||
b0 |d
|
|
||||||
0.e
|
|
||||||
0>e
|
|
||||||
0Ne
|
|
||||||
0^e
|
|
||||||
0ne
|
|
||||||
0~e
|
|
||||||
00f
|
|
||||||
0@f
|
|
||||||
b0 }d
|
|
||||||
0/e
|
|
||||||
0?e
|
|
||||||
0Oe
|
|
||||||
0_e
|
|
||||||
0oe
|
|
||||||
0!f
|
|
||||||
01f
|
|
||||||
0Af
|
|
||||||
b0 ~d
|
|
||||||
00e
|
|
||||||
0@e
|
|
||||||
0Pe
|
|
||||||
0`e
|
|
||||||
0pe
|
|
||||||
0"f
|
|
||||||
02f
|
|
||||||
0Bf
|
|
||||||
b0 !e
|
|
||||||
01e
|
|
||||||
0Ae
|
|
||||||
0Qe
|
|
||||||
0ae
|
|
||||||
0qe
|
|
||||||
0#f
|
|
||||||
03f
|
|
||||||
0Cf
|
|
||||||
b0 Df
|
|
||||||
0Tf
|
|
||||||
0df
|
|
||||||
0tf
|
|
||||||
0&g
|
|
||||||
06g
|
|
||||||
0Fg
|
|
||||||
0Vg
|
|
||||||
0fg
|
|
||||||
b0 Ef
|
|
||||||
0Uf
|
|
||||||
0ef
|
|
||||||
0uf
|
|
||||||
0'g
|
|
||||||
07g
|
|
||||||
0Gg
|
|
||||||
0Wg
|
|
||||||
0gg
|
|
||||||
b0 Ff
|
|
||||||
0Vf
|
|
||||||
0ff
|
|
||||||
0vf
|
|
||||||
0(g
|
|
||||||
08g
|
|
||||||
0Hg
|
|
||||||
0Xg
|
|
||||||
0hg
|
|
||||||
b0 Gf
|
|
||||||
0Wf
|
|
||||||
0gf
|
|
||||||
0wf
|
|
||||||
0)g
|
|
||||||
09g
|
|
||||||
0Ig
|
|
||||||
0Yg
|
|
||||||
0ig
|
|
||||||
b0 Hf
|
|
||||||
0Xf
|
|
||||||
0hf
|
|
||||||
0xf
|
|
||||||
0*g
|
|
||||||
0:g
|
|
||||||
0Jg
|
|
||||||
0Zg
|
|
||||||
0jg
|
|
||||||
b0 If
|
|
||||||
0Yf
|
|
||||||
0if
|
|
||||||
0yf
|
|
||||||
0+g
|
|
||||||
0;g
|
|
||||||
0Kg
|
|
||||||
0[g
|
|
||||||
0kg
|
|
||||||
b0 Jf
|
|
||||||
0Zf
|
|
||||||
0jf
|
|
||||||
0zf
|
|
||||||
0,g
|
|
||||||
0<g
|
|
||||||
0Lg
|
|
||||||
0\g
|
|
||||||
0lg
|
|
||||||
b0 Kf
|
|
||||||
0[f
|
|
||||||
0kf
|
|
||||||
0{f
|
|
||||||
0-g
|
|
||||||
0=g
|
|
||||||
0Mg
|
|
||||||
0]g
|
|
||||||
0mg
|
|
||||||
b0 Lf
|
|
||||||
0\f
|
|
||||||
0lf
|
|
||||||
0|f
|
|
||||||
0.g
|
|
||||||
0>g
|
|
||||||
0Ng
|
|
||||||
0^g
|
|
||||||
0ng
|
|
||||||
b0 Mf
|
|
||||||
0]f
|
|
||||||
0mf
|
|
||||||
0}f
|
|
||||||
0/g
|
|
||||||
0?g
|
|
||||||
0Og
|
|
||||||
0_g
|
|
||||||
0og
|
|
||||||
b0 Nf
|
|
||||||
0^f
|
|
||||||
0nf
|
|
||||||
0~f
|
|
||||||
00g
|
|
||||||
0@g
|
|
||||||
0Pg
|
|
||||||
0`g
|
|
||||||
0pg
|
|
||||||
b0 Of
|
|
||||||
0_f
|
|
||||||
0of
|
|
||||||
0!g
|
|
||||||
01g
|
|
||||||
0Ag
|
|
||||||
0Qg
|
|
||||||
0ag
|
|
||||||
0qg
|
|
||||||
b0 Pf
|
|
||||||
0`f
|
|
||||||
0pf
|
|
||||||
0"g
|
|
||||||
02g
|
|
||||||
0Bg
|
|
||||||
0Rg
|
|
||||||
0bg
|
|
||||||
0rg
|
|
||||||
b0 Qf
|
|
||||||
0af
|
|
||||||
0qf
|
|
||||||
0#g
|
|
||||||
03g
|
|
||||||
0Cg
|
|
||||||
0Sg
|
|
||||||
0cg
|
|
||||||
0sg
|
|
||||||
b0 Rf
|
|
||||||
0bf
|
|
||||||
0rf
|
|
||||||
0$g
|
|
||||||
04g
|
|
||||||
0Dg
|
|
||||||
0Tg
|
|
||||||
0dg
|
|
||||||
0tg
|
|
||||||
b0 Sf
|
|
||||||
0cf
|
|
||||||
0sf
|
|
||||||
0%g
|
|
||||||
05g
|
|
||||||
0Eg
|
|
||||||
0Ug
|
|
||||||
0eg
|
|
||||||
0ug
|
|
||||||
0vg
|
|
||||||
0wg
|
|
||||||
0xg
|
|
||||||
0yg
|
|
||||||
0zg
|
|
||||||
0{g
|
|
||||||
0|g
|
|
||||||
0}g
|
|
||||||
0~g
|
|
||||||
0!h
|
|
||||||
0"h
|
|
||||||
0#h
|
|
||||||
0$h
|
|
||||||
0%h
|
|
||||||
0&h
|
|
||||||
0'h
|
|
||||||
0(h
|
|
||||||
0)h
|
|
||||||
0*h
|
|
||||||
0+h
|
|
||||||
0,h
|
|
||||||
0-h
|
|
||||||
0.h
|
|
||||||
0/h
|
|
||||||
00h
|
|
||||||
01h
|
|
||||||
02h
|
|
||||||
03h
|
|
||||||
04h
|
|
||||||
05h
|
|
||||||
06h
|
|
||||||
07h
|
|
||||||
b0 8h
|
b0 8h
|
||||||
0Hh
|
0Hh
|
||||||
0Xh
|
0Xh
|
||||||
|
|
@ -17838,6 +17530,150 @@ b0 Gh
|
||||||
0Ii
|
0Ii
|
||||||
0Yi
|
0Yi
|
||||||
0ii
|
0ii
|
||||||
|
b0 Df
|
||||||
|
0Tf
|
||||||
|
0df
|
||||||
|
0tf
|
||||||
|
0&g
|
||||||
|
06g
|
||||||
|
0Fg
|
||||||
|
0Vg
|
||||||
|
0fg
|
||||||
|
b0 Ef
|
||||||
|
0Uf
|
||||||
|
0ef
|
||||||
|
0uf
|
||||||
|
0'g
|
||||||
|
07g
|
||||||
|
0Gg
|
||||||
|
0Wg
|
||||||
|
0gg
|
||||||
|
b0 Ff
|
||||||
|
0Vf
|
||||||
|
0ff
|
||||||
|
0vf
|
||||||
|
0(g
|
||||||
|
08g
|
||||||
|
0Hg
|
||||||
|
0Xg
|
||||||
|
0hg
|
||||||
|
b0 Gf
|
||||||
|
0Wf
|
||||||
|
0gf
|
||||||
|
0wf
|
||||||
|
0)g
|
||||||
|
09g
|
||||||
|
0Ig
|
||||||
|
0Yg
|
||||||
|
0ig
|
||||||
|
b0 Hf
|
||||||
|
0Xf
|
||||||
|
0hf
|
||||||
|
0xf
|
||||||
|
0*g
|
||||||
|
0:g
|
||||||
|
0Jg
|
||||||
|
0Zg
|
||||||
|
0jg
|
||||||
|
b0 If
|
||||||
|
0Yf
|
||||||
|
0if
|
||||||
|
0yf
|
||||||
|
0+g
|
||||||
|
0;g
|
||||||
|
0Kg
|
||||||
|
0[g
|
||||||
|
0kg
|
||||||
|
b0 Jf
|
||||||
|
0Zf
|
||||||
|
0jf
|
||||||
|
0zf
|
||||||
|
0,g
|
||||||
|
0<g
|
||||||
|
0Lg
|
||||||
|
0\g
|
||||||
|
0lg
|
||||||
|
b0 Kf
|
||||||
|
0[f
|
||||||
|
0kf
|
||||||
|
0{f
|
||||||
|
0-g
|
||||||
|
0=g
|
||||||
|
0Mg
|
||||||
|
0]g
|
||||||
|
0mg
|
||||||
|
b0 Lf
|
||||||
|
0\f
|
||||||
|
0lf
|
||||||
|
0|f
|
||||||
|
0.g
|
||||||
|
0>g
|
||||||
|
0Ng
|
||||||
|
0^g
|
||||||
|
0ng
|
||||||
|
b0 Mf
|
||||||
|
0]f
|
||||||
|
0mf
|
||||||
|
0}f
|
||||||
|
0/g
|
||||||
|
0?g
|
||||||
|
0Og
|
||||||
|
0_g
|
||||||
|
0og
|
||||||
|
b0 Nf
|
||||||
|
0^f
|
||||||
|
0nf
|
||||||
|
0~f
|
||||||
|
00g
|
||||||
|
0@g
|
||||||
|
0Pg
|
||||||
|
0`g
|
||||||
|
0pg
|
||||||
|
b0 Of
|
||||||
|
0_f
|
||||||
|
0of
|
||||||
|
0!g
|
||||||
|
01g
|
||||||
|
0Ag
|
||||||
|
0Qg
|
||||||
|
0ag
|
||||||
|
0qg
|
||||||
|
b0 Pf
|
||||||
|
0`f
|
||||||
|
0pf
|
||||||
|
0"g
|
||||||
|
02g
|
||||||
|
0Bg
|
||||||
|
0Rg
|
||||||
|
0bg
|
||||||
|
0rg
|
||||||
|
b0 Qf
|
||||||
|
0af
|
||||||
|
0qf
|
||||||
|
0#g
|
||||||
|
03g
|
||||||
|
0Cg
|
||||||
|
0Sg
|
||||||
|
0cg
|
||||||
|
0sg
|
||||||
|
b0 Rf
|
||||||
|
0bf
|
||||||
|
0rf
|
||||||
|
0$g
|
||||||
|
04g
|
||||||
|
0Dg
|
||||||
|
0Tg
|
||||||
|
0dg
|
||||||
|
0tg
|
||||||
|
b0 Sf
|
||||||
|
0cf
|
||||||
|
0sf
|
||||||
|
0%g
|
||||||
|
05g
|
||||||
|
0Eg
|
||||||
|
0Ug
|
||||||
|
0eg
|
||||||
|
0ug
|
||||||
b0 ji
|
b0 ji
|
||||||
0zi
|
0zi
|
||||||
0,j
|
0,j
|
||||||
|
|
@ -17982,6 +17818,170 @@ b0 yi
|
||||||
0{j
|
0{j
|
||||||
0-k
|
0-k
|
||||||
0=k
|
0=k
|
||||||
|
b0 pd
|
||||||
|
0"e
|
||||||
|
02e
|
||||||
|
0Be
|
||||||
|
0Re
|
||||||
|
0be
|
||||||
|
0re
|
||||||
|
0$f
|
||||||
|
04f
|
||||||
|
b0 qd
|
||||||
|
0#e
|
||||||
|
03e
|
||||||
|
0Ce
|
||||||
|
0Se
|
||||||
|
0ce
|
||||||
|
0se
|
||||||
|
0%f
|
||||||
|
05f
|
||||||
|
b0 rd
|
||||||
|
0$e
|
||||||
|
04e
|
||||||
|
0De
|
||||||
|
0Te
|
||||||
|
0de
|
||||||
|
0te
|
||||||
|
0&f
|
||||||
|
06f
|
||||||
|
b0 sd
|
||||||
|
0%e
|
||||||
|
05e
|
||||||
|
0Ee
|
||||||
|
0Ue
|
||||||
|
0ee
|
||||||
|
0ue
|
||||||
|
0'f
|
||||||
|
07f
|
||||||
|
b0 td
|
||||||
|
0&e
|
||||||
|
06e
|
||||||
|
0Fe
|
||||||
|
0Ve
|
||||||
|
0fe
|
||||||
|
0ve
|
||||||
|
0(f
|
||||||
|
08f
|
||||||
|
b0 ud
|
||||||
|
0'e
|
||||||
|
07e
|
||||||
|
0Ge
|
||||||
|
0We
|
||||||
|
0ge
|
||||||
|
0we
|
||||||
|
0)f
|
||||||
|
09f
|
||||||
|
b0 vd
|
||||||
|
0(e
|
||||||
|
08e
|
||||||
|
0He
|
||||||
|
0Xe
|
||||||
|
0he
|
||||||
|
0xe
|
||||||
|
0*f
|
||||||
|
0:f
|
||||||
|
b0 wd
|
||||||
|
0)e
|
||||||
|
09e
|
||||||
|
0Ie
|
||||||
|
0Ye
|
||||||
|
0ie
|
||||||
|
0ye
|
||||||
|
0+f
|
||||||
|
0;f
|
||||||
|
b0 xd
|
||||||
|
0*e
|
||||||
|
0:e
|
||||||
|
0Je
|
||||||
|
0Ze
|
||||||
|
0je
|
||||||
|
0ze
|
||||||
|
0,f
|
||||||
|
0<f
|
||||||
|
b0 yd
|
||||||
|
0+e
|
||||||
|
0;e
|
||||||
|
0Ke
|
||||||
|
0[e
|
||||||
|
0ke
|
||||||
|
0{e
|
||||||
|
0-f
|
||||||
|
0=f
|
||||||
|
b0 zd
|
||||||
|
0,e
|
||||||
|
0<e
|
||||||
|
0Le
|
||||||
|
0\e
|
||||||
|
0le
|
||||||
|
0|e
|
||||||
|
0.f
|
||||||
|
0>f
|
||||||
|
b0 {d
|
||||||
|
0-e
|
||||||
|
0=e
|
||||||
|
0Me
|
||||||
|
0]e
|
||||||
|
0me
|
||||||
|
0}e
|
||||||
|
0/f
|
||||||
|
0?f
|
||||||
|
b0 |d
|
||||||
|
0.e
|
||||||
|
0>e
|
||||||
|
0Ne
|
||||||
|
0^e
|
||||||
|
0ne
|
||||||
|
0~e
|
||||||
|
00f
|
||||||
|
0@f
|
||||||
|
b0 }d
|
||||||
|
0/e
|
||||||
|
0?e
|
||||||
|
0Oe
|
||||||
|
0_e
|
||||||
|
0oe
|
||||||
|
0!f
|
||||||
|
01f
|
||||||
|
0Af
|
||||||
|
b0 ~d
|
||||||
|
00e
|
||||||
|
0@e
|
||||||
|
0Pe
|
||||||
|
0`e
|
||||||
|
0pe
|
||||||
|
0"f
|
||||||
|
02f
|
||||||
|
0Bf
|
||||||
|
b0 !e
|
||||||
|
01e
|
||||||
|
0Ae
|
||||||
|
0Qe
|
||||||
|
0ae
|
||||||
|
0qe
|
||||||
|
0#f
|
||||||
|
03f
|
||||||
|
0Cf
|
||||||
|
0Pd
|
||||||
|
0Qd
|
||||||
|
0Rd
|
||||||
|
0Sd
|
||||||
|
0Td
|
||||||
|
0Ud
|
||||||
|
0Vd
|
||||||
|
0Wd
|
||||||
|
0Xd
|
||||||
|
0Yd
|
||||||
|
0Zd
|
||||||
|
0[d
|
||||||
|
0\d
|
||||||
|
0]d
|
||||||
|
0^d
|
||||||
|
0_d
|
||||||
|
b0 Ld
|
||||||
|
b0 Nd
|
||||||
|
b0 Md
|
||||||
|
b0 Od
|
||||||
0!
|
0!
|
||||||
1"
|
1"
|
||||||
sHdlSome\x20(1) #
|
sHdlSome\x20(1) #
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,20 @@
|
||||||
// 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
|
||||||
|
|
||||||
|
#![cfg(todo)]
|
||||||
|
|
||||||
use cpu::{
|
use cpu::{
|
||||||
config::{CpuConfig, UnitConfig},
|
config::{CpuConfig, UnitConfig},
|
||||||
instruction::{AddSubMOp, LogicalMOp, MOp, MOpDestReg, MOpRegNum, OutputIntegerMode},
|
instruction::{AddSubMOp, LogicalMOp, MOp, MOpDestReg, MOpRegNum, OutputIntegerMode},
|
||||||
reg_alloc::{FetchedDecodedMOp, reg_alloc},
|
reg_alloc::{reg_alloc, FetchedDecodedMOp},
|
||||||
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::{time::SimDuration, vcd::VcdWriterDecls, Simulation},
|
||||||
util::RcWriter,
|
util::RcWriter,
|
||||||
};
|
};
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
|
|
|
||||||
20
crates/name_mangling_serde/Cargo.toml
Normal file
20
crates/name_mangling_serde/Cargo.toml
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
# See Notices.txt for copyright information
|
||||||
|
[package]
|
||||||
|
name = "name_mangling_serde"
|
||||||
|
description = "serde serializer/deserializer for name mangling"
|
||||||
|
workspace = "../.."
|
||||||
|
readme = "README.md"
|
||||||
|
publish = false
|
||||||
|
edition.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
repository.workspace = true
|
||||||
|
rust-version.workspace = true
|
||||||
|
version.workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
serde.workspace = true
|
||||||
|
serde_json.workspace = true
|
||||||
|
|
||||||
|
[lints.rust]
|
||||||
|
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(todo)'] }
|
||||||
1
crates/name_mangling_serde/LICENSE.md
Symbolic link
1
crates/name_mangling_serde/LICENSE.md
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
../../LICENSE.md
|
||||||
1
crates/name_mangling_serde/Notices.txt
Symbolic link
1
crates/name_mangling_serde/Notices.txt
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
../../Notices.txt
|
||||||
470
crates/name_mangling_serde/src/lib.rs
Normal file
470
crates/name_mangling_serde/src/lib.rs
Normal file
|
|
@ -0,0 +1,470 @@
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
|
use serde::{de::DeserializeOwned, Serialize};
|
||||||
|
use serde_json::{Map, Number, Value};
|
||||||
|
use std::{
|
||||||
|
fmt::{self, Write},
|
||||||
|
num::ParseIntError,
|
||||||
|
};
|
||||||
|
|
||||||
|
macro_rules! byte_enum {
|
||||||
|
(
|
||||||
|
#[repr(u8)]
|
||||||
|
$(#[$meta:meta])*
|
||||||
|
$vis:vis enum $enum:ident {
|
||||||
|
$($Variant:ident = $value:expr,)*
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
#[repr(u8)]
|
||||||
|
$(#[$meta])*
|
||||||
|
$vis enum $enum {
|
||||||
|
$($Variant = $value,)*
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $enum {
|
||||||
|
$vis fn new(v: u8) -> Option<Self> {
|
||||||
|
struct Values;
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
impl Values {
|
||||||
|
$(const $Variant: u8 = $enum::$Variant as u8;)*
|
||||||
|
}
|
||||||
|
match v {
|
||||||
|
$(Values::$Variant => Some(Self::$Variant),)*
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[allow(dead_code)]
|
||||||
|
$vis fn as_char(self) -> char {
|
||||||
|
const {
|
||||||
|
$(assert!((Self::$Variant as u8).is_ascii());)*
|
||||||
|
};
|
||||||
|
self as u8 as char
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! string_escapes {
|
||||||
|
(
|
||||||
|
$key_vis:vis enum $StringEscapeKey:ident {}
|
||||||
|
$value_vis:vis enum $StringEscapeValue:ident {
|
||||||
|
$(
|
||||||
|
#[key = $key:expr]
|
||||||
|
$Variant:ident = $value:expr,
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
byte_enum! {
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
$key_vis enum $StringEscapeKey {
|
||||||
|
$($Variant = $key,)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
byte_enum! {
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
$value_vis enum $StringEscapeValue {
|
||||||
|
$($Variant = $value,)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<$StringEscapeKey> for $StringEscapeValue {
|
||||||
|
fn from(v: $StringEscapeKey) -> Self {
|
||||||
|
match v {
|
||||||
|
$($StringEscapeKey::$Variant => Self::$Variant,)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<$StringEscapeValue> for $StringEscapeKey {
|
||||||
|
fn from(v: $StringEscapeValue) -> Self {
|
||||||
|
match v {
|
||||||
|
$($StringEscapeValue::$Variant => Self::$Variant,)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
string_escapes! {
|
||||||
|
enum StringEscapeKey {}
|
||||||
|
enum StringEscapeValue {
|
||||||
|
#[key = b's']
|
||||||
|
Space = b' ',
|
||||||
|
#[key = b't']
|
||||||
|
Tab = b'\t',
|
||||||
|
#[key = b'r']
|
||||||
|
CR = b'\r',
|
||||||
|
#[key = b'n']
|
||||||
|
NewLine = b'\n',
|
||||||
|
#[key = b'_']
|
||||||
|
Underline = b'_',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn json_string_to_name_part(value: &str, out: &mut String) {
|
||||||
|
out.push(ValuePrefix::String.as_char());
|
||||||
|
write!(out, "{}_", value.len()).unwrap();
|
||||||
|
for b in value.bytes() {
|
||||||
|
if let Some(v) = StringEscapeValue::new(b) {
|
||||||
|
out.push('_');
|
||||||
|
out.push(StringEscapeKey::from(v).as_char());
|
||||||
|
} else if b.is_ascii_alphanumeric() {
|
||||||
|
out.push(b as char);
|
||||||
|
} else {
|
||||||
|
write!(out, "_{b:02x}").unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
byte_enum! {
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
enum ValuePrefix {
|
||||||
|
Null = b'z',
|
||||||
|
False = b'f',
|
||||||
|
True = b't',
|
||||||
|
Number = b'n',
|
||||||
|
String = b's',
|
||||||
|
Array = b'a',
|
||||||
|
Object = b'o',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn json_value_to_name_part(value: &Value, out: &mut String) {
|
||||||
|
match value {
|
||||||
|
Value::Null => out.push(ValuePrefix::Null.as_char()),
|
||||||
|
Value::Bool(false) => out.push(ValuePrefix::False.as_char()),
|
||||||
|
Value::Bool(true) => out.push(ValuePrefix::True.as_char()),
|
||||||
|
Value::Number(number) => {
|
||||||
|
out.push(ValuePrefix::Number.as_char());
|
||||||
|
let start = out.len();
|
||||||
|
write!(out, "{number}").unwrap();
|
||||||
|
for i in start..out.len() {
|
||||||
|
out.replace_range(
|
||||||
|
i..=i,
|
||||||
|
match out.as_bytes()[i] {
|
||||||
|
b'0'..=b'9' => continue,
|
||||||
|
b'+' => "",
|
||||||
|
b'-' => "n",
|
||||||
|
b'.' => "p",
|
||||||
|
b'e' | b'E' => "e",
|
||||||
|
_ => unreachable!("invalid character in JSON number"),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Value::String(string) => json_string_to_name_part(string, out),
|
||||||
|
Value::Array(array) => {
|
||||||
|
out.push(ValuePrefix::Array.as_char());
|
||||||
|
write!(out, "{}", array.len()).unwrap();
|
||||||
|
for element in array {
|
||||||
|
json_value_to_name_part(element, out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Value::Object(object) => {
|
||||||
|
out.push(ValuePrefix::Object.as_char());
|
||||||
|
write!(out, "{}", object.len()).unwrap();
|
||||||
|
for (k, v) in object {
|
||||||
|
json_string_to_name_part(k, out);
|
||||||
|
json_value_to_name_part(v, out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const NAME_PREFIX: &str = "__HDL";
|
||||||
|
|
||||||
|
pub fn json_value_to_name(value: &Value) -> String {
|
||||||
|
let mut retval = NAME_PREFIX.into();
|
||||||
|
json_value_to_name_part(value, &mut retval);
|
||||||
|
retval
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
Serde(serde_json::Error),
|
||||||
|
NameDoesNotStartWithKnownPrefix,
|
||||||
|
UnknownValuePrefix,
|
||||||
|
MissingValuePrefix,
|
||||||
|
InvalidLength(ParseIntError),
|
||||||
|
TrailingCharacters,
|
||||||
|
KeyMustBeAString,
|
||||||
|
StringMissingUnderline,
|
||||||
|
StringTruncated,
|
||||||
|
InvalidEscape,
|
||||||
|
InvalidString,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<serde_json::Error> for Error {
|
||||||
|
fn from(value: serde_json::Error) -> Self {
|
||||||
|
Self::Serde(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Error {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Serde(e) => e.fmt(f),
|
||||||
|
Self::NameDoesNotStartWithKnownPrefix => {
|
||||||
|
f.write_str("name does not start with the known prefix")
|
||||||
|
}
|
||||||
|
Self::UnknownValuePrefix => f.write_str("unknown value prefix"),
|
||||||
|
Self::MissingValuePrefix => f.write_str("missing value prefix"),
|
||||||
|
Self::InvalidLength(_) => f.write_str("invalid length"),
|
||||||
|
Self::TrailingCharacters => f.write_str("trailing characters"),
|
||||||
|
Self::KeyMustBeAString => f.write_str("key must be a string"),
|
||||||
|
Self::StringMissingUnderline => f.write_str("string missing `_` after length"),
|
||||||
|
Self::StringTruncated => f.write_str("string truncated"),
|
||||||
|
Self::InvalidEscape => f.write_str("invalid escape"),
|
||||||
|
Self::InvalidString => f.write_str("invalid string"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for Error {
|
||||||
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||||
|
match self {
|
||||||
|
Self::Serde(e) => e.source(),
|
||||||
|
Self::NameDoesNotStartWithKnownPrefix => None,
|
||||||
|
Self::UnknownValuePrefix => None,
|
||||||
|
Self::MissingValuePrefix => None,
|
||||||
|
Self::InvalidLength(e) => Some(e),
|
||||||
|
Self::TrailingCharacters => None,
|
||||||
|
Self::KeyMustBeAString => None,
|
||||||
|
Self::StringMissingUnderline => None,
|
||||||
|
Self::StringTruncated => None,
|
||||||
|
Self::InvalidEscape => None,
|
||||||
|
Self::InvalidString => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct NameParser<'a> {
|
||||||
|
name_part: &'a str,
|
||||||
|
number_buf: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NameParser<'_> {
|
||||||
|
fn parse_len(&mut self) -> Result<usize, Error> {
|
||||||
|
let len_end = self
|
||||||
|
.name_part
|
||||||
|
.bytes()
|
||||||
|
.position(|b| !b.is_ascii_digit())
|
||||||
|
.unwrap_or(self.name_part.len());
|
||||||
|
let (len, rest) = self.name_part.split_at(len_end);
|
||||||
|
self.name_part = rest;
|
||||||
|
len.parse().map_err(Error::InvalidLength)
|
||||||
|
}
|
||||||
|
fn parse_string_without_prefix(&mut self) -> Result<String, Error> {
|
||||||
|
let len = self.parse_len()?;
|
||||||
|
let Some(rest) = self.name_part.strip_prefix("_") else {
|
||||||
|
return Err(Error::StringMissingUnderline);
|
||||||
|
};
|
||||||
|
self.name_part = rest;
|
||||||
|
let mut bytes = Vec::new();
|
||||||
|
for _ in 0..len {
|
||||||
|
let b = self
|
||||||
|
.name_part
|
||||||
|
.bytes()
|
||||||
|
.next()
|
||||||
|
.ok_or(Error::StringTruncated)?;
|
||||||
|
if b.is_ascii_alphanumeric() {
|
||||||
|
bytes.push(b);
|
||||||
|
self.name_part = &self.name_part[1..];
|
||||||
|
} else if b == b'_' {
|
||||||
|
self.name_part = &self.name_part[1..];
|
||||||
|
let escape = self.name_part.bytes().next().ok_or(Error::InvalidEscape)?;
|
||||||
|
self.name_part = &self.name_part[1..];
|
||||||
|
if let Some(high) = (escape as char).to_digit(16) {
|
||||||
|
let low = self
|
||||||
|
.name_part
|
||||||
|
.bytes()
|
||||||
|
.next()
|
||||||
|
.ok_or(Error::StringTruncated)?;
|
||||||
|
let low = (low as char).to_digit(16).ok_or(Error::InvalidString)?;
|
||||||
|
self.name_part = &self.name_part[1..];
|
||||||
|
bytes.push((high * 16 + low) as u8);
|
||||||
|
} else {
|
||||||
|
let escape = StringEscapeKey::new(escape).ok_or(Error::InvalidEscape)?;
|
||||||
|
bytes.push(StringEscapeValue::from(escape) as u8);
|
||||||
|
}
|
||||||
|
} else if let Some(high) = (b as char).to_digit(16) {
|
||||||
|
self.name_part = &self.name_part[1..];
|
||||||
|
let low = self
|
||||||
|
.name_part
|
||||||
|
.bytes()
|
||||||
|
.next()
|
||||||
|
.ok_or(Error::StringTruncated)?;
|
||||||
|
let low = (low as char).to_digit(16).ok_or(Error::InvalidString)?;
|
||||||
|
self.name_part = &self.name_part[1..];
|
||||||
|
bytes.push((high * 16 + low) as u8);
|
||||||
|
} else {
|
||||||
|
return Err(Error::InvalidString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String::from_utf8(bytes).map_err(|_| Error::InvalidString)
|
||||||
|
}
|
||||||
|
fn parse_string(&mut self) -> Result<String, Error> {
|
||||||
|
if let ValuePrefix::String = self.parse_value_prefix()? {
|
||||||
|
self.parse_string_without_prefix()
|
||||||
|
} else {
|
||||||
|
Err(Error::KeyMustBeAString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn parse_number_without_prefix(&mut self) -> Result<Number, Error> {
|
||||||
|
let mut bytes = self.name_part.as_bytes().iter();
|
||||||
|
self.number_buf.clear();
|
||||||
|
if let Some(b'n') = bytes.clone().next() {
|
||||||
|
bytes.next();
|
||||||
|
self.number_buf.push('-');
|
||||||
|
}
|
||||||
|
while let Some(&b @ b'0'..=b'9') = bytes.clone().next() {
|
||||||
|
bytes.next();
|
||||||
|
self.number_buf.push(b as char);
|
||||||
|
}
|
||||||
|
if let Some(b'p') = bytes.clone().next() {
|
||||||
|
bytes.next();
|
||||||
|
self.number_buf.push('.');
|
||||||
|
while let Some(&b @ b'0'..=b'9') = bytes.clone().next() {
|
||||||
|
bytes.next();
|
||||||
|
self.number_buf.push(b as char);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(b'e') = bytes.clone().next() {
|
||||||
|
bytes.next();
|
||||||
|
self.number_buf.push('e');
|
||||||
|
if let Some(b'n') = bytes.clone().next() {
|
||||||
|
bytes.next();
|
||||||
|
self.number_buf.push('-');
|
||||||
|
}
|
||||||
|
while let Some(&b @ b'0'..=b'9') = bytes.clone().next() {
|
||||||
|
bytes.next();
|
||||||
|
self.number_buf.push(b as char);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.name_part = &self.name_part[self.name_part.len() - bytes.len()..];
|
||||||
|
Ok(self.number_buf.parse()?)
|
||||||
|
}
|
||||||
|
fn parse_value_prefix(&mut self) -> Result<ValuePrefix, Error> {
|
||||||
|
let value_prefix = self
|
||||||
|
.name_part
|
||||||
|
.bytes()
|
||||||
|
.next()
|
||||||
|
.ok_or(Error::MissingValuePrefix)?;
|
||||||
|
let value_prefix = ValuePrefix::new(value_prefix).ok_or(Error::UnknownValuePrefix)?;
|
||||||
|
self.name_part = &self.name_part[1..];
|
||||||
|
Ok(value_prefix)
|
||||||
|
}
|
||||||
|
fn parse_value(&mut self) -> Result<Value, Error> {
|
||||||
|
Ok(match self.parse_value_prefix()? {
|
||||||
|
ValuePrefix::Null => Value::Null,
|
||||||
|
ValuePrefix::False => Value::Bool(false),
|
||||||
|
ValuePrefix::True => Value::Bool(true),
|
||||||
|
ValuePrefix::Number => Value::Number(self.parse_number_without_prefix()?),
|
||||||
|
ValuePrefix::String => Value::String(self.parse_string_without_prefix()?),
|
||||||
|
ValuePrefix::Array => {
|
||||||
|
let len = self.parse_len()?;
|
||||||
|
let mut array = Vec::new();
|
||||||
|
for _ in 0..len {
|
||||||
|
array.push(self.parse_value()?);
|
||||||
|
}
|
||||||
|
Value::Array(array)
|
||||||
|
}
|
||||||
|
ValuePrefix::Object => {
|
||||||
|
let len = self.parse_len()?;
|
||||||
|
let mut object = Map::new();
|
||||||
|
for _ in 0..len {
|
||||||
|
let key = self.parse_string()?;
|
||||||
|
let value = self.parse_value()?;
|
||||||
|
object.insert(key, value);
|
||||||
|
}
|
||||||
|
Value::Object(object)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name_to_json_value(name: &str) -> Result<Value, Error> {
|
||||||
|
let Some(name_part) = name.strip_prefix(NAME_PREFIX) else {
|
||||||
|
return Err(Error::NameDoesNotStartWithKnownPrefix);
|
||||||
|
};
|
||||||
|
let mut parser = NameParser {
|
||||||
|
name_part,
|
||||||
|
number_buf: String::new(),
|
||||||
|
};
|
||||||
|
let retval = parser.parse_value()?;
|
||||||
|
if !parser.name_part.is_empty() {
|
||||||
|
Err(Error::TrailingCharacters)
|
||||||
|
} else {
|
||||||
|
Ok(retval)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_name<T: DeserializeOwned>(name: &str) -> Result<T, Error> {
|
||||||
|
Ok(serde_json::from_value(name_to_json_value(name)?)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_name<T: Serialize>(value: T) -> Result<String, Error> {
|
||||||
|
Ok(json_value_to_name(&serde_json::to_value(value)?))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_from_to_name() {
|
||||||
|
#[track_caller]
|
||||||
|
fn check_from_to_name(value: Value, name: &str) {
|
||||||
|
assert_eq!(name, json_value_to_name(&value));
|
||||||
|
assert_eq!(
|
||||||
|
Ok(value),
|
||||||
|
name_to_json_value(name).map_err(|e| e.to_string())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
check_from_to_name(json! { null }, "__HDLz");
|
||||||
|
check_from_to_name(json! { false }, "__HDLf");
|
||||||
|
check_from_to_name(json! { true }, "__HDLt");
|
||||||
|
check_from_to_name(json! { 0 }, "__HDLn0");
|
||||||
|
check_from_to_name(json! { 0.1 }, "__HDLn0p1");
|
||||||
|
check_from_to_name(json! { -0.1 }, "__HDLnn0p1");
|
||||||
|
check_from_to_name(json! { 1234567 }, "__HDLn1234567");
|
||||||
|
check_from_to_name(json! { -1.2345678e-20 }, "__HDLnn1p2345678en20");
|
||||||
|
check_from_to_name(json! { -1.2345e300 }, "__HDLnn1p2345e300");
|
||||||
|
check_from_to_name(json! { -5 }, "__HDLnn5");
|
||||||
|
check_from_to_name(json! { "" }, "__HDLs0_");
|
||||||
|
check_from_to_name(json! { "a" }, "__HDLs1_a");
|
||||||
|
check_from_to_name(json! { "A" }, "__HDLs1_A");
|
||||||
|
check_from_to_name(json! { "z" }, "__HDLs1_z");
|
||||||
|
check_from_to_name(json! { "Z" }, "__HDLs1_Z");
|
||||||
|
check_from_to_name(json! { "0" }, "__HDLs1_0");
|
||||||
|
check_from_to_name(json! { "9" }, "__HDLs1_9");
|
||||||
|
check_from_to_name(json! { "_" }, "__HDLs1___");
|
||||||
|
check_from_to_name(json! { " " }, "__HDLs1__s");
|
||||||
|
check_from_to_name(json! { "\t" }, "__HDLs1__t");
|
||||||
|
check_from_to_name(json! { "\r" }, "__HDLs1__r");
|
||||||
|
check_from_to_name(json! { "\n" }, "__HDLs1__n");
|
||||||
|
check_from_to_name(json! { "\u{25}" }, "__HDLs1__25");
|
||||||
|
check_from_to_name(json! { "\u{100}" }, "__HDLs2__c4_80");
|
||||||
|
check_from_to_name(json! { "\u{1000}" }, "__HDLs3__e1_80_80");
|
||||||
|
check_from_to_name(json! { "\u{10000}" }, "__HDLs4__f0_90_80_80");
|
||||||
|
check_from_to_name(json! { "foo" }, "__HDLs3_foo");
|
||||||
|
check_from_to_name(json! { { "foo": 123 } }, "__HDLo1s3_foon123");
|
||||||
|
check_from_to_name(
|
||||||
|
json! { { "foo": 123, "bar": null } },
|
||||||
|
"__HDLo2s3_foon123s3_barz",
|
||||||
|
);
|
||||||
|
check_from_to_name(json! { [1, 2, 3, 4] }, "__HDLa4n1n2n3n4");
|
||||||
|
check_from_to_name(
|
||||||
|
json! { { "a": [], "b": null, "c": 1234, "d": {} } },
|
||||||
|
"__HDLo4s1_aa0s1_bzs1_cn1234s1_do0",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue