Compare commits

..

23 commits

Author SHA1 Message Date
3b5104c8fa
fix vcd to match test output 2025-12-16 23:25:54 -08:00
2de4a67360
add link to other NLnet task and note lack of optimization 2025-12-16 23:10:07 -08:00
d5a7d9dd9e
next_pc works afaict 2025-12-16 23:06:32 -08:00
59da0aec06
WIP fixing bugs 2025-12-16 02:32:19 -08:00
5e1238b5c7
replace tests/next_pc's demo program with a simple expression parser as a better demo 2025-12-15 21:40:11 -08:00
bc9a3a5ce7
add missing copyright header and check-copyright.sh support for .mermaid 2025-12-15 03:00:37 -08:00
d42f010cda
WIP fixing bugs 2025-12-15 02:48:40 -08:00
84e4fde512
fix queueing errors 2025-12-15 00:47:53 -08:00
8ab63f3c6a
update fayalite 2025-12-14 21:05:59 -08:00
f39f40ce1f
fix next_pc::Queue and add test 2025-12-14 20:39:15 -08:00
cbd52c60a8
WIP: next_pc test fails 2025-12-14 01:26:18 -08:00
c87a1b8e1e
wrote out all of next_pc and tests/next_pc 2025-12-13 22:42:34 -08:00
cfd04469ce
WIP linking next_pc stages together 2025-12-10 20:31:04 -08:00
231f5e72ec
WIP: completed stages of next-pc logic, still need to combine them into a pipeline 2025-12-10 20:31:04 -08:00
033d5d4f34
WIP adding next_pc: add call stack 2025-12-10 20:31:04 -08:00
7a77c02cda
WIP adding next_pc: added mock_fetch_decode_pipe 2025-12-10 20:31:04 -08:00
61d52bd028
add Serialize/Deserialize impls for CpuConfig 2025-12-10 20:31:04 -08:00
554238c544
update for new fayalite 2025-12-10 20:31:04 -08:00
24d6537ffe
update Fayalite to get new features and bug fixes 2025-12-10 20:31:04 -08:00
c30bd0737f
add readme 2025-10-24 16:36:31 -07:00
291ad59b02
update CI to use new fayalite-deps container 2025-10-24 02:54:03 -07:00
5e8bc3e580
upgrade to Fayalite edcc5927a5f9ebca6
as part of this I switched to using Fayalite's UIntInRangeInclusive instead of using a custom Length struct
2025-10-24 02:53:35 -07:00
0e7a518bd0
switch to use server's new actions org 2025-10-10 00:03:53 -07:00
25 changed files with 308997 additions and 2209 deletions

View file

@ -1,77 +0,0 @@
# SPDX-License-Identifier: LGPL-3.0-or-later
# See Notices.txt for copyright information
on:
workflow_call:
outputs:
cache-primary-key:
value: ${{ jobs.deps.outputs.cache-primary-key }}
jobs:
deps:
runs-on: debian-12
outputs:
cache-primary-key: ${{ steps.restore-deps.outputs.cache-primary-key }}
steps:
- uses: https://git.libre-chip.org/mirrors/checkout@v3
with:
fetch-depth: 0
- uses: https://git.libre-chip.org/mirrors/cache/restore@v3
id: restore-deps
with:
path: deps
key: ${{ github.repository }}-deps-${{ runner.os }}-${{ hashFiles('.forgejo/workflows/deps.yml') }}
lookup-only: true
- name: Install Apt packages
if: steps.restore-deps.outputs.cache-hit != 'true'
run: |
apt-get update -qq
apt-get install -qq \
bison \
build-essential \
ccache \
clang \
cvc5 \
flex \
gawk \
g++ \
git \
libboost-filesystem-dev \
libboost-python-dev \
libboost-system-dev \
libffi-dev \
libreadline-dev \
lld \
pkg-config \
python3 \
python3-click \
tcl-dev \
zlib1g-dev
- name: Install Firtool
if: steps.restore-deps.outputs.cache-hit != 'true'
run: |
mkdir -p deps
wget -O deps/firrtl.tar.gz https://github.com/llvm/circt/releases/download/firtool-1.86.0/firrtl-bin-linux-x64.tar.gz
sha256sum -c - <<<'bf6f4ab18ae76f135c944efbd81e25391c31c1bd0617c58ab0592640abefee14 deps/firrtl.tar.gz'
tar -C deps -xvaf deps/firrtl.tar.gz
rm -rf deps/firtool
mv deps/firtool-1.86.0 deps/firtool
- name: Get SymbiYosys
if: steps.restore-deps.outputs.cache-hit != 'true'
run: |
git clone --depth=1 --branch=yosys-0.45 https://git.libre-chip.org/mirrors/sby deps/sby
- name: Build Z3
if: steps.restore-deps.outputs.cache-hit != 'true'
run: |
git clone --depth=1 --recursive --branch=z3-4.13.3 https://git.libre-chip.org/mirrors/z3 deps/z3
(cd deps/z3; PYTHON=python3 ./configure --prefix=/usr/local)
make -C deps/z3/build -j"$(nproc)"
- name: Build Yosys
if: steps.restore-deps.outputs.cache-hit != 'true'
run: |
git clone --depth=1 --recursive --branch=0.45 https://git.libre-chip.org/mirrors/yosys deps/yosys
make -C deps/yosys -j"$(nproc)"
- uses: https://git.libre-chip.org/mirrors/cache/save@v3
if: steps.restore-deps.outputs.cache-hit != 'true'
with:
path: deps
key: ${{ steps.restore-deps.outputs.cache-primary-key }}

View file

@ -3,56 +3,16 @@
on: [push, pull_request] on: [push, pull_request]
jobs: jobs:
deps:
runs-on: debian-12
uses: ./.forgejo/workflows/deps.yml
test: test:
runs-on: debian-12 runs-on: debian-12
needs: deps container:
image: git.libre-chip.org/libre-chip/fayalite-deps:latest
steps: steps:
- uses: https://git.libre-chip.org/mirrors/checkout@v3 - uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
- run: | - run: |
scripts/check-copyright.sh scripts/check-copyright.sh
- run: |
apt-get update -qq
apt-get install -qq \
bison \
build-essential \
ccache \
clang \
cvc5 \
flex \
gawk \
git \
libboost-filesystem-dev \
libboost-python-dev \
libboost-system-dev \
libffi-dev \
libreadline-dev \
lld \
pkg-config \
python3 \
python3-click \
tcl-dev \
z3 \
zlib1g-dev
- run: |
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.89.0
source "$HOME/.cargo/env"
echo "$PATH" >> "$GITHUB_PATH"
- uses: https://git.libre-chip.org/mirrors/cache/restore@v3
with:
path: deps
key: ${{ needs.deps.outputs.cache-primary-key }}
fail-on-cache-miss: true
- run: |
make -C deps/z3/build install
make -C deps/sby install
make -C deps/yosys install
export PATH="$(realpath deps/firtool/bin):$PATH"
echo "$PATH" >> "$GITHUB_PATH"
- uses: https://git.libre-chip.org/mirrors/rust-cache@v2 - uses: https://git.libre-chip.org/mirrors/rust-cache@v2
with: with:
save-if: ${{ github.ref == 'refs/heads/master' }} save-if: ${{ github.ref == 'refs/heads/master' }}

174
Cargo.lock generated
View file

@ -1,18 +1,6 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 4
[[package]]
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"
@ -93,6 +81,12 @@ 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"
@ -172,6 +166,15 @@ dependencies = [
"strsim", "strsim",
] ]
[[package]]
name = "clap_complete"
version = "4.5.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2348487adcd4631696ced64ccdb40d38ac4d31cae7f2eec8817fcea1b9d1c43c"
dependencies = [
"clap",
]
[[package]] [[package]]
name = "clap_derive" name = "clap_derive"
version = "4.5.18" version = "4.5.18"
@ -207,6 +210,8 @@ name = "cpu"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"fayalite", "fayalite",
"serde",
"simple-mermaid",
] ]
[[package]] [[package]]
@ -300,20 +305,22 @@ checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
[[package]] [[package]]
name = "fayalite" name = "fayalite"
version = "0.3.0" version = "0.3.0"
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#bd75fdfefd642f6dd2210cfb003fa63f9dce114e" source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#c97b44d9d646a4aa64fcc046538fc2354bb708ee"
dependencies = [ dependencies = [
"base64",
"bitvec", "bitvec",
"blake3", "blake3",
"clap", "clap",
"clap_complete",
"ctor", "ctor",
"eyre", "eyre",
"fayalite-proc-macros", "fayalite-proc-macros",
"fayalite-visit-gen", "fayalite-visit-gen",
"hashbrown", "hashbrown 0.15.5",
"jobslot", "jobslot",
"num-bigint", "num-bigint",
"num-traits", "num-traits",
"os_pipe", "ordered-float",
"petgraph", "petgraph",
"serde", "serde",
"serde_json", "serde_json",
@ -325,7 +332,7 @@ dependencies = [
[[package]] [[package]]
name = "fayalite-proc-macros" name = "fayalite-proc-macros"
version = "0.3.0" version = "0.3.0"
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#bd75fdfefd642f6dd2210cfb003fa63f9dce114e" source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#c97b44d9d646a4aa64fcc046538fc2354bb708ee"
dependencies = [ dependencies = [
"fayalite-proc-macros-impl", "fayalite-proc-macros-impl",
] ]
@ -333,7 +340,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#bd75fdfefd642f6dd2210cfb003fa63f9dce114e" source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#c97b44d9d646a4aa64fcc046538fc2354bb708ee"
dependencies = [ dependencies = [
"base16ct", "base16ct",
"num-bigint", "num-bigint",
@ -348,7 +355,7 @@ dependencies = [
[[package]] [[package]]
name = "fayalite-visit-gen" name = "fayalite-visit-gen"
version = "0.3.0" version = "0.3.0"
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#bd75fdfefd642f6dd2210cfb003fa63f9dce114e" source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#c97b44d9d646a4aa64fcc046538fc2354bb708ee"
dependencies = [ dependencies = [
"indexmap", "indexmap",
"prettyplease", "prettyplease",
@ -366,6 +373,12 @@ 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"
@ -384,13 +397,14 @@ dependencies = [
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.15" version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
"wasi", "r-efi",
"wasip2",
] ]
[[package]] [[package]]
@ -398,9 +412,16 @@ 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]]
@ -431,7 +452,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
dependencies = [ dependencies = [
"equivalent", "equivalent",
"hashbrown", "hashbrown 0.14.5",
"serde", "serde",
] ]
@ -449,16 +470,16 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]] [[package]]
name = "jobslot" name = "jobslot"
version = "0.2.19" version = "0.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe10868679d7a24c2c67d862d0e64a342ce9aef7cdde9ce8019bd35d353d458d" checksum = "58715c67c327da7f1558708348d68c207fd54900c4ae0529e29305d04d795b8c"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"derive_destructure2", "derive_destructure2",
"getrandom", "getrandom",
"libc", "libc",
"scopeguard", "scopeguard",
"windows-sys 0.59.0", "windows-sys 0.61.2",
] ]
[[package]] [[package]]
@ -514,22 +535,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
[[package]] [[package]]
name = "os_pipe" name = "ordered-float"
version = "1.2.1" version = "5.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982" checksum = "7f4779c6901a562440c3786d08192c6fbda7c1c2060edd10006b05ee35d10f2d"
dependencies = [ dependencies = [
"libc", "num-traits",
"windows-sys 0.59.0", "rand",
"serde",
] ]
[[package]] [[package]]
name = "petgraph" name = "petgraph"
version = "0.6.5" version = "0.8.3"
source = "git+https://github.com/programmerjake/petgraph.git?rev=258ea8071209a924b73fe96f9f87a3b7b45cbc9f#258ea8071209a924b73fe96f9f87a3b7b45cbc9f" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455"
dependencies = [ dependencies = [
"fixedbitset", "fixedbitset",
"hashbrown 0.15.5",
"indexmap", "indexmap",
"serde",
] ]
[[package]] [[package]]
@ -560,12 +585,37 @@ 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"
@ -641,6 +691,12 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "simple-mermaid"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589144a964b4b30fe3a83b4bb1a09e2475aac194ec832a046a23e75bddf9eb29"
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.11.1" version = "0.11.1"
@ -728,10 +784,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]] [[package]]
name = "wasi" name = "wasip2"
version = "0.11.0+wasi-snapshot-preview1" version = "1.0.1+wasi-0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7"
dependencies = [
"wit-bindgen",
]
[[package]] [[package]]
name = "which" name = "which"
@ -745,6 +804,12 @@ 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"
@ -763,6 +828,15 @@ dependencies = [
"windows-targets", "windows-targets",
] ]
[[package]]
name = "windows-sys"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [
"windows-link",
]
[[package]] [[package]]
name = "windows-targets" name = "windows-targets"
version = "0.52.6" version = "0.52.6"
@ -833,6 +907,12 @@ version = "0.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
[[package]]
name = "wit-bindgen"
version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
[[package]] [[package]]
name = "wyz" name = "wyz"
version = "0.5.1" version = "0.5.1"
@ -841,23 +921,3 @@ 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",
]

View file

@ -15,6 +15,8 @@ rust-version = "1.89.0"
[workspace.dependencies] [workspace.dependencies]
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"] }
simple-mermaid = "0.2.0"
[profile.dev] [profile.dev]
opt-level = 1 opt-level = 1

15
README.md Normal file
View file

@ -0,0 +1,15 @@
<!--
SPDX-License-Identifier: LGPL-3.0-or-later
See Notices.txt for copyright information
-->
# Libre-Chip's CPU
<https://libre-chip.org/first_arch/index.html>
# Funding
## NLnet Grants
* [Libre-Chip CPU with proof of No Spectre bugs](https://nlnet.nl/project/Libre-Chip-proof/) 2024-12-324 [(progress)](https://git.libre-chip.org/libre-chip/grant-tracking/src/branch/master/nlnet-2024-12-324/progress.md)
This project was funded through the [NGI0 Commons Fund](https://nlnet.nl/commonsfund), a fund established by [NLnet](https://nlnet.nl/) with financial support from the European Commission's [Next Generation Internet](https://ngi.eu) programme, under the aegis of [DG Communications Networks, Content and Technology](https://commission.europa.eu/about-european-commission/departments-and-executive-agencies/communications-networks-content-and-technology_en) under grant agreement &numero; [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).

View file

@ -16,3 +16,5 @@ version.workspace = true
[dependencies] [dependencies]
fayalite.workspace = true fayalite.workspace = true
serde.workspace = true
simple-mermaid.workspace = true

1
crates/cpu/README.md Symbolic link
View file

@ -0,0 +1 @@
../../README.md

View file

@ -8,9 +8,10 @@ use crate::{
}, },
}; };
use fayalite::prelude::*; use fayalite::prelude::*;
use serde::{Deserialize, Serialize};
use std::num::NonZeroUsize; use std::num::NonZeroUsize;
#[derive(Clone, Eq, PartialEq, Hash, Debug)] #[derive(Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
#[non_exhaustive] #[non_exhaustive]
pub struct UnitConfig { pub struct UnitConfig {
pub kind: UnitKind, pub kind: UnitKind,
@ -27,12 +28,15 @@ impl UnitConfig {
} }
} }
#[derive(Clone, Eq, PartialEq, Hash, Debug)] #[derive(Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
#[non_exhaustive] #[non_exhaustive]
pub struct CpuConfig { pub struct CpuConfig {
pub units: Vec<UnitConfig>, pub units: Vec<UnitConfig>,
pub out_reg_num_width: usize, pub out_reg_num_width: usize,
pub fetch_width: NonZeroUsize, pub fetch_width: NonZeroUsize,
pub max_branches_per_fetch: NonZeroUsize,
pub max_fetches_in_flight: NonZeroUsize,
pub log2_fetch_width_in_bytes: u8,
/// default value for [`UnitConfig::max_in_flight`] /// default value for [`UnitConfig::max_in_flight`]
pub default_unit_max_in_flight: NonZeroUsize, pub default_unit_max_in_flight: NonZeroUsize,
pub rob_size: NonZeroUsize, pub rob_size: NonZeroUsize,
@ -46,6 +50,19 @@ impl CpuConfig {
}; };
v v
}; };
pub const DEFAULT_MAX_BRANCHES_PER_FETCH: NonZeroUsize = {
let Some(v) = NonZeroUsize::new(1) else {
unreachable!();
};
v
};
pub const DEFAULT_MAX_FETCHES_IN_FLIGHT: NonZeroUsize = {
let Some(v) = NonZeroUsize::new(16) else {
unreachable!();
};
v
};
pub const DEFAULT_LOG2_FETCH_WIDTH_IN_BYTES: u8 = 3;
pub const DEFAULT_UNIT_MAX_IN_FLIGHT: NonZeroUsize = { pub const DEFAULT_UNIT_MAX_IN_FLIGHT: NonZeroUsize = {
let Some(v) = NonZeroUsize::new(8) else { let Some(v) = NonZeroUsize::new(8) else {
unreachable!(); unreachable!();
@ -57,6 +74,9 @@ impl CpuConfig {
units, units,
out_reg_num_width: Self::DEFAULT_OUT_REG_NUM_WIDTH, out_reg_num_width: Self::DEFAULT_OUT_REG_NUM_WIDTH,
fetch_width: Self::DEFAULT_FETCH_WIDTH, fetch_width: Self::DEFAULT_FETCH_WIDTH,
max_branches_per_fetch: Self::DEFAULT_MAX_BRANCHES_PER_FETCH,
max_fetches_in_flight: Self::DEFAULT_MAX_FETCHES_IN_FLIGHT,
log2_fetch_width_in_bytes: Self::DEFAULT_LOG2_FETCH_WIDTH_IN_BYTES,
default_unit_max_in_flight: Self::DEFAULT_UNIT_MAX_IN_FLIGHT, default_unit_max_in_flight: Self::DEFAULT_UNIT_MAX_IN_FLIGHT,
rob_size, rob_size,
} }
@ -116,4 +136,42 @@ impl CpuConfig {
UnitToRegAlloc[mop_ty][extra_out_ty][self.unit_num_width()][self.out_reg_num_width] UnitToRegAlloc[mop_ty][extra_out_ty][self.unit_num_width()][self.out_reg_num_width]
[self.non_const_unit_nums().len()] [self.non_const_unit_nums().len()]
} }
pub fn fetch_width_in_bytes(&self) -> usize {
1usize
.checked_shl(self.log2_fetch_width_in_bytes.into())
.expect("log2_fetch_width_in_bytes is too big")
}
} }
#[hdl(get(|c| c.fetch_width.get()))]
pub type CpuConfigFetchWidth<C: PhantomConstGet<CpuConfig>> = DynSize;
#[hdl(get(|c| c.fetch_width.get() * 2))]
pub type TwiceCpuConfigFetchWidth<C: PhantomConstGet<CpuConfig>> = DynSize;
#[hdl(get(|c| c.max_branches_per_fetch.get()))]
pub type CpuConfigMaxBranchesPerFetch<C: PhantomConstGet<CpuConfig>> = DynSize;
#[hdl(get(|c| c.max_fetches_in_flight.get()))]
pub type CpuConfigMaxFetchesInFlight<C: PhantomConstGet<CpuConfig>> = DynSize;
#[hdl(get(|c| c.log2_fetch_width_in_bytes.into()))]
pub type CpuConfigLog2FetchWidthInBytes<C: PhantomConstGet<CpuConfig>> = DynSize;
#[hdl(get(|c| c.fetch_width_in_bytes()))]
pub type CpuConfigFetchWidthInBytes<C: PhantomConstGet<CpuConfig>> = DynSize;
#[hdl(get(|c| c.rob_size.get()))]
pub type CpuConfigRobSize<C: PhantomConstGet<CpuConfig>> = DynSize;
pub trait PhantomConstCpuConfig:
PhantomConstGet<CpuConfig>
+ Into<PhantomConst<CpuConfig>>
+ From<PhantomConst<CpuConfig>>
+ Type
+ ToSimValue<Type = Self>
+ ToExpr<Type = Self>
{
}
impl PhantomConstCpuConfig for PhantomConst<CpuConfig> {}

View file

@ -2,11 +2,11 @@
// See Notices.txt for copyright information // See Notices.txt for copyright information
use crate::{unit::UnitMOp, util::range_u32_len}; use crate::{unit::UnitMOp, util::range_u32_len};
use fayalite::{ use fayalite::{
expr::ops::{ArrayLiteral, ExprPartialEq}, expr::{HdlPartialEqImpl, ops::ArrayLiteral},
intern::Interned, intern::Interned,
prelude::*, prelude::*,
}; };
use std::{fmt, marker::PhantomData, ops::Range}; use std::{borrow::Cow, fmt, marker::PhantomData, ops::Range};
pub mod power_isa; pub mod power_isa;
@ -171,13 +171,37 @@ pub enum OutputIntegerMode {
SignExt8, SignExt8,
} }
impl ExprPartialEq<Self> for OutputIntegerMode { impl HdlPartialEqImpl<Self> for OutputIntegerMode {
fn cmp_eq(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> { #[track_caller]
lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits()) fn cmp_value_eq(
lhs: Self,
lhs_value: Cow<'_, Self::SimValue>,
rhs: Self,
rhs_value: Cow<'_, Self::SimValue>,
) -> bool {
SimValue::opaque(&SimValue::from_value(lhs, lhs_value.into_owned()))
== SimValue::opaque(&SimValue::from_value(rhs, rhs_value.into_owned()))
} }
fn cmp_ne(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> { #[track_caller]
lhs.cast_to_bits().cmp_ne(rhs.cast_to_bits()) fn cmp_sim_value_eq(
lhs: Cow<'_, SimValue<Self>>,
rhs: Cow<'_, SimValue<Self>>,
) -> SimValue<Bool> {
(SimValue::opaque(&lhs) == SimValue::opaque(&rhs)).to_sim_value()
}
#[track_caller]
fn cmp_sim_value_ne(
lhs: Cow<'_, SimValue<Self>>,
rhs: Cow<'_, SimValue<Self>>,
) -> SimValue<Bool> {
(SimValue::opaque(&lhs) != SimValue::opaque(&rhs)).to_sim_value()
}
#[track_caller]
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits())
} }
} }
@ -289,8 +313,8 @@ impl<PrefixPad: KnownSize, DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize
let dest = dest.to_expr(); let dest = dest.to_expr();
let src_in = src.to_expr(); let src_in = src.to_expr();
let imm = imm.to_expr(); let imm = imm.to_expr();
assert_eq!(Expr::ty(imm), Self::imm_ty()); assert_eq!(imm.ty(), Self::imm_ty());
let src_reg_ty = Expr::ty(src_in).element(); let src_reg_ty = src_in.ty().element();
let imm_parts = imm.cast_to_bits().cast_bits_to(Self::imm_parts_ty()); let imm_parts = imm.cast_to_bits().cast_bits_to(Self::imm_parts_ty());
let mut src = [0_hdl_u0.cast_to(src_reg_ty); COMMON_MOP_SRC_LEN]; let mut src = [0_hdl_u0.cast_to(src_reg_ty); COMMON_MOP_SRC_LEN];
for i in 0..SrcCount::VALUE { for i in 0..SrcCount::VALUE {
@ -334,9 +358,9 @@ impl<PrefixPad: KnownSize, DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize
#[hdl] #[hdl]
pub fn connect_to_imm(expr: impl ToExpr<Type = Self>, imm: impl ToExpr<Type = SInt>) { pub fn connect_to_imm(expr: impl ToExpr<Type = Self>, imm: impl ToExpr<Type = SInt>) {
let expr = expr.to_expr(); let expr = expr.to_expr();
let src_reg_ty = Expr::ty(expr).src.element(); let src_reg_ty = expr.ty().src.element();
let imm = imm.to_expr(); let imm = imm.to_expr();
assert_eq!(Expr::ty(imm), Self::imm_ty()); assert_eq!(imm.ty(), Self::imm_ty());
let imm_parts = imm.cast_to_bits().cast_bits_to(Self::imm_parts_ty()); let imm_parts = imm.cast_to_bits().cast_bits_to(Self::imm_parts_ty());
let mut src = [Some(0_hdl_u0.cast_to(src_reg_ty)); COMMON_MOP_SRC_LEN]; let mut src = [Some(0_hdl_u0.cast_to(src_reg_ty)); COMMON_MOP_SRC_LEN];
for i in 0..SrcCount::VALUE { for i in 0..SrcCount::VALUE {
@ -489,7 +513,7 @@ macro_rules! mop_enum {
fn dest_reg(input: impl ToExpr<Type = Self>) -> Expr<Self::DestReg> { fn dest_reg(input: impl ToExpr<Type = Self>) -> Expr<Self::DestReg> {
let input = input.to_expr(); let input = input.to_expr();
#[hdl] #[hdl]
let dest_reg = wire(Expr::ty(input).dest_reg_ty()); let dest_reg = wire(input.ty().dest_reg_ty());
#[hdl] #[hdl]
match input { match input {
Self::$FirstVariant(v) => connect(dest_reg, <$first_ty as MOpTrait>::dest_reg(v)), Self::$FirstVariant(v) => connect(dest_reg, <$first_ty as MOpTrait>::dest_reg(v)),
@ -530,7 +554,7 @@ macro_rules! mop_enum {
) -> Expr<Self::Mapped<NewDestReg, NewSrcRegWidth>> { ) -> Expr<Self::Mapped<NewDestReg, NewSrcRegWidth>> {
let input = input.to_expr(); let input = input.to_expr();
let new_dest = new_dest.to_expr(); let new_dest = new_dest.to_expr();
let mapped_ty = Expr::ty(input).mapped_ty(Expr::ty(new_dest), new_src_reg_width); let mapped_ty = input.ty().mapped_ty(new_dest.ty(), new_src_reg_width);
#[hdl] #[hdl]
let mapped_regs = wire(mapped_ty); let mapped_regs = wire(mapped_ty);
#[hdl] #[hdl]
@ -577,7 +601,7 @@ macro_rules! mop_enum {
MOpInto::mop_into_ty($MOp[MOpTrait::dest_reg_ty(self)][MOpTrait::src_reg_width(self)]$([$sizes_get_size(self)])*) MOpInto::mop_into_ty($MOp[MOpTrait::dest_reg_ty(self)][MOpTrait::src_reg_width(self)]$([$sizes_get_size(self)])*)
} }
fn mop_into(this: Expr<Self>) -> Expr<Target> { fn mop_into(this: Expr<Self>) -> Expr<Target> {
MOpInto::mop_into(MOpInto::<$MOp<$DestReg, $SrcRegWidth, $($Sizes,)*>>::mop_into_ty(Expr::ty(this)).$Variant(this)) MOpInto::mop_into(MOpInto::<$MOp<$DestReg, $SrcRegWidth, $($Sizes,)*>>::mop_into_ty(this.ty()).$Variant(this))
} }
} }
}; };
@ -826,22 +850,19 @@ impl<Width: Size> UnitNum<Width> {
} }
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> {
let expr = expr.to_expr(); let expr = expr.to_expr();
Expr::ty(expr) expr.ty().from_index(index).adj_value.cmp_eq(expr.adj_value)
.from_index(index)
.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<Width>>> {
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().adj_value]);
connect(unit_index, Expr::ty(unit_index).HdlNone()); connect(unit_index, unit_index.ty().HdlNone());
#[hdl] #[hdl]
if expr.adj_value.cmp_ne(0u8) { if expr.adj_value.cmp_ne(0u8) {
connect( connect(
unit_index, unit_index,
HdlSome((expr.adj_value - 1u8).cast_to(Expr::ty(expr).adj_value)), HdlSome((expr.adj_value - 1u8).cast_to(expr.ty().adj_value)),
); );
} }
unit_index unit_index
@ -893,7 +914,7 @@ impl MOpRegNum {
pub fn const_zero() -> Expr<Self> { pub fn const_zero() -> Expr<Self> {
#[hdl] #[hdl]
MOpRegNum { MOpRegNum {
value: Self::CONST_ZERO_REG_NUM.cast_to_static(), value: Self::CONST_ZERO_REG_NUM.cast_to_static::<UInt<_>>(),
} }
} }
/// a lot of instructions write to flag registers that we want /// a lot of instructions write to flag registers that we want
@ -1070,7 +1091,7 @@ impl MOpDestReg {
flag_reg, flag_reg,
#[hdl] #[hdl]
MOpRegNum { MOpRegNum {
value: reg_num.cast_to_static(), value: reg_num.cast_to_static::<UInt<_>>(),
}, },
); );
} }

View file

@ -2,9 +2,8 @@
// 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 next_pc;
pub mod reg_alloc; pub mod reg_alloc;
pub mod register; pub mod register;
pub mod unit; pub mod unit;
pub mod util; pub mod util;
//TODO read other modules
pub mod main_memory;

View file

@ -1,60 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
// first copied code block -- changes needed
use crate::{
config::CpuConfig,
instruction::{
AluBranchMOp, LoadStoreMOp, MOp, MOpDestReg, MOpInto, MOpRegNum, MOpTrait, RenamedMOp,
UnitOutRegNum, mop_enum,
},
register::{FlagsMode, PRegValue},
unit::unit_base::UnitToRegAlloc,
};
use fayalite::{
bundle::{Bundle, BundleType},
intern::{Intern, Interned},
prelude::*,
};
//input address <32> bit ?
//output data word <8> bit for first test (read only)
#[hdl_module]
/// add a comment here
pub fn main_memory(config: &CpuConfig) {
#[hdl]
let addr: UInt<64> = m.input();
#[hdl]
let read_data: UInt<64> = m.output();
#[hdl]
let en: Bool = m.input();
//WIP: add write support
#[hdl]
let write_en: Bool = m.input();
#[hdl]
let write_data: UInt<64> = m.input();
#[hdl]
let cd: ClockDomain = m.input();
#[hdl] // FIXME: do not hardcode memory size and content --
//let mut my_memory = memory_with_init([0x12_hdl_u8, 0x34_hdl_u8, 0x56_hdl_u8, 0x78_hdl_u8]);
let mut my_memory = memory();
my_memory.depth(256); //TODO make configurable
let read_port = my_memory.new_read_port();
connect_any(read_port.addr, addr);
connect_any(read_port.en, addr.cmp_lt(256u64) & en); // and not write_en
connect(read_port.clk, cd.clk);
connect(read_data, read_port.data);
let write_port = my_memory.new_write_port();
connect_any(write_port.addr, addr);
connect_any(write_port.en, addr.cmp_lt(256u64) & en & write_en);
connect_any(write_port.data, write_data);
connect(write_port.clk, cd.clk);
connect_any(write_port.mask, true); //can only write 8 bits at a time
}

4862
crates/cpu/src/next_pc.rs Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,24 @@
%% SPDX-License-Identifier: LGPL-3.0-or-later
%% See Notices.txt for copyright information
stateDiagram-v2
direction LR
state "Next PC" as next_pc
[*] --> next_pc
state "Fetch/Decode" as fetch_decode
next_pc --> fetch_decode
state "Branch Predictor" as br_pred
next_pc --> br_pred
br_pred --> next_pc: cancel following
state "Post-decode" as post_decode
fetch_decode --> post_decode
br_pred --> post_decode
post_decode --> next_pc: cancel following
state "Execute/Retire" as execute_retire
post_decode --> execute_retire
execute_retire --> [*]
execute_retire --> next_pc: cancel following

View file

@ -241,7 +241,7 @@ pub fn reg_alloc(config: &CpuConfig) {
// TODO: finish // TODO: finish
connect( connect(
rob.renamed_insns_in[fetch_index].data, rob.renamed_insns_in[fetch_index].data,
Expr::ty(rob).renamed_insns_in.element().data.HdlNone(), rob.ty().renamed_insns_in.element().data.HdlNone(),
); );
// TODO: finish // TODO: finish
connect( connect(
@ -263,7 +263,7 @@ pub fn reg_alloc(config: &CpuConfig) {
); );
connect( connect(
renamed_mops[fetch_index], renamed_mops[fetch_index],
Expr::ty(renamed_mops).element().HdlNone(), renamed_mops.ty().element().HdlNone(),
); );
#[hdl] #[hdl]
struct RenameTableReadPort<T> { struct RenameTableReadPort<T> {
@ -332,7 +332,7 @@ pub fn reg_alloc(config: &CpuConfig) {
let write_port = wire_with_loc( let write_port = wire_with_loc(
&format!("{table_name}_{fetch_index}_{}", reg_kind.reg_name()), &format!("{table_name}_{fetch_index}_{}", reg_kind.reg_name()),
SourceLocation::caller(), SourceLocation::caller(),
Expr::ty(write_port_), write_port_.ty(),
); );
connect(write_port_, write_port); connect(write_port_, write_port);
write_ports.push_back(write_port); write_ports.push_back(write_port);
@ -343,7 +343,7 @@ pub fn reg_alloc(config: &CpuConfig) {
addr: 0_hdl_u0, addr: 0_hdl_u0,
en: false, en: false,
clk: cd.clk, clk: cd.clk,
data: Expr::ty(write_port.data).uninit(), data: write_port.data.ty().uninit(),
mask: splat_mask(config.p_reg_num(), true.to_expr()), mask: splat_mask(config.p_reg_num(), true.to_expr()),
}, },
); );
@ -375,7 +375,7 @@ pub fn reg_alloc(config: &CpuConfig) {
config.renamed_mop_in_unit().TransformedMove, config.renamed_mop_in_unit().TransformedMove,
|renamed_mop, renamed_move_op: Expr<MoveRegMOp<_, _>>| { |renamed_mop, renamed_move_op: Expr<MoveRegMOp<_, _>>| {
// TODO: finish handling MoveRegMOp // TODO: finish handling MoveRegMOp
connect(renamed_mop, Expr::ty(renamed_mop).HdlNone()); connect(renamed_mop, renamed_mop.ty().HdlNone());
}, },
); );
connect( connect(
@ -429,7 +429,7 @@ pub fn reg_alloc(config: &CpuConfig) {
); );
connect( connect(
selected_unit_index_leaf, selected_unit_index_leaf,
Expr::ty(selected_unit_index_leaf).HdlNone(), selected_unit_index_leaf.ty().HdlNone(),
); );
let unit_index_wire = wire_with_loc( let unit_index_wire = wire_with_loc(
&format!("unit_index_{fetch_index}_{unit_index}"), &format!("unit_index_{fetch_index}_{unit_index}"),
@ -447,7 +447,7 @@ pub fn reg_alloc(config: &CpuConfig) {
let selected_unit_index_node = wire_with_loc( let selected_unit_index_node = wire_with_loc(
&format!("selected_unit_index_node_{fetch_index}_{state}"), &format!("selected_unit_index_node_{fetch_index}_{state}"),
SourceLocation::caller(), SourceLocation::caller(),
Expr::ty(l), l.ty(),
); );
*state += 1; *state += 1;
connect(selected_unit_index_node, l); connect(selected_unit_index_node, l);
@ -516,7 +516,7 @@ pub fn reg_alloc(config: &CpuConfig) {
connect(unit_free_regs_tracker.alloc_out[0].ready, false); connect(unit_free_regs_tracker.alloc_out[0].ready, false);
connect( connect(
unit_to_reg_alloc.input.data, unit_to_reg_alloc.input.data,
Expr::ty(unit_to_reg_alloc.input).data.HdlNone(), unit_to_reg_alloc.input.ty().data.HdlNone(),
); );
for fetch_index in 0..config.fetch_width.get() { for fetch_index in 0..config.fetch_width.get() {
#[hdl] #[hdl]
@ -550,7 +550,7 @@ pub fn reg_alloc(config: &CpuConfig) {
} else { } else {
connect( connect(
unit_to_reg_alloc.input.data, unit_to_reg_alloc.input.data,
HdlSome(Expr::ty(unit_to_reg_alloc.input).data.HdlSome.uninit()), HdlSome(unit_to_reg_alloc.input.ty().data.HdlSome.uninit()),
); );
// FIXME: add hdl_assert(cd.clk, false.to_expr(), ""); // FIXME: add hdl_assert(cd.clk, false.to_expr(), "");
} }
@ -578,7 +578,8 @@ pub fn reg_alloc(config: &CpuConfig) {
connect(unit_to_reg_alloc.unit_forwarding_info, unit_forwarding_info); connect(unit_to_reg_alloc.unit_forwarding_info, unit_forwarding_info);
connect( connect(
unit_forwarding_info.unit_output_writes[unit_index], unit_forwarding_info.unit_output_writes[unit_index],
Expr::ty(unit_forwarding_info) unit_forwarding_info
.ty()
.unit_output_writes .unit_output_writes
.element() .element()
.HdlNone(), .HdlNone(),

View file

@ -73,7 +73,7 @@ pub fn unit_free_regs_tracker(
let reduced_alloc_nums = wire_with_loc( let reduced_alloc_nums = wire_with_loc(
&format!("reduced_alloc_nums_{}_{}", range.start, range.end), &format!("reduced_alloc_nums_{}_{}", range.start, range.end),
SourceLocation::caller(), SourceLocation::caller(),
Array[UInt[Expr::ty(l.alloc_nums).element().width() + 1]][alloc_at_once.get()], Array[UInt[l.alloc_nums.ty().element().width() + 1]][alloc_at_once.get()],
); );
for alloc_index in 0..alloc_at_once.get() { for alloc_index in 0..alloc_at_once.get() {
#[hdl] #[hdl]
@ -120,10 +120,7 @@ pub fn unit_free_regs_tracker(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use fayalite::{ use fayalite::{firrtl::ExportOptions, module::transform::simplify_enums::SimplifyEnumsKind};
cli::FormalMode, firrtl::ExportOptions,
module::transform::simplify_enums::SimplifyEnumsKind, testing::assert_formal,
};
use std::num::NonZero; use std::num::NonZero;
fn test_unit_free_regs_tracker( fn test_unit_free_regs_tracker(
@ -198,7 +195,7 @@ mod tests {
} }
} }
#[hdl] #[hdl]
let free_before_alloc_array = wire(Array[Expr::ty(free_reg)][alloc_at_once.get() + 1]); let free_before_alloc_array = wire(Array[free_reg.ty()][alloc_at_once.get() + 1]);
connect(free_before_alloc_array[0], free_reg); connect(free_before_alloc_array[0], free_reg);
#[hdl] #[hdl]
let expected_alloc = wire(Array[HdlOption[reg_num_ty]][alloc_at_once.get()]); let expected_alloc = wire(Array[HdlOption[reg_num_ty]][alloc_at_once.get()]);

View file

@ -15,6 +15,7 @@ use fayalite::{
intern::{Intern, Interned}, intern::{Intern, Interned},
prelude::*, prelude::*,
}; };
use serde::{Deserialize, Serialize};
pub mod alu_branch; pub mod alu_branch;
pub mod unit_base; pub mod unit_base;
@ -36,7 +37,7 @@ macro_rules! all_units {
} }
) => { ) => {
$(#[$enum_meta])* $(#[$enum_meta])*
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Serialize, Deserialize)]
$vis enum $UnitKind { $vis enum $UnitKind {
$( $(
$(#[$variant_meta])* $(#[$variant_meta])*
@ -52,9 +53,16 @@ macro_rules! all_units {
} }
} }
impl ToExpr for $UnitKind { impl ValueType for $UnitKind {
type Type = $HdlUnitKind; type Type = $HdlUnitKind;
type ValueCategory = fayalite::expr::value_category::ValueCategoryExpr;
fn ty(&self) -> Self::Type {
$HdlUnitKind
}
}
impl ToExpr for $UnitKind {
fn to_expr(&self) -> Expr<Self::Type> { fn to_expr(&self) -> Expr<Self::Type> {
match self { match self {
$($UnitKind::$Unit => $HdlUnitKind.$Unit(),)* $($UnitKind::$Unit => $HdlUnitKind.$Unit(),)*
@ -98,7 +106,7 @@ macro_rules! all_units {
#[hdl] #[hdl]
$vis fn $extract(expr: impl ToExpr<Type = Self>) -> Expr<HdlOption<$Op>> { $vis fn $extract(expr: impl ToExpr<Type = Self>) -> Expr<HdlOption<$Op>> {
let expr = expr.to_expr(); let expr = expr.to_expr();
let ty = Expr::ty(expr); let ty = expr.ty();
#[hdl] #[hdl]
let $extract = wire(HdlOption[ty.$Unit]); let $extract = wire(HdlOption[ty.$Unit]);
connect($extract, HdlOption[ty.$Unit].HdlNone()); connect($extract, HdlOption[ty.$Unit].HdlNone());
@ -164,10 +172,10 @@ macro_rules! all_units {
$TransformedMoveOp: MOpTrait<DestReg = $DestReg, SrcRegWidth = $SrcRegWidth>, $TransformedMoveOp: MOpTrait<DestReg = $DestReg, SrcRegWidth = $SrcRegWidth>,
{ {
let this = this.to_expr(); let this = this.to_expr();
let new_ty = Expr::ty(this).with_transformed_move_op_ty(new_transformed_move_op_ty); let new_ty = this.ty().with_transformed_move_op_ty(new_transformed_move_op_ty);
#[hdl] #[hdl]
let with_transformed_move_op = wire(HdlOption[new_ty]); let with_transformed_move_op = wire(HdlOption[new_ty]);
connect(with_transformed_move_op, Expr::ty(with_transformed_move_op).HdlNone()); connect(with_transformed_move_op, with_transformed_move_op.ty().HdlNone());
// workaround #[hdl] match expanding to a loop, so you can't move variables in it // workaround #[hdl] match expanding to a loop, so you can't move variables in it
let mut connect_transformed_move_op = Some(connect_transformed_move_op); let mut connect_transformed_move_op = Some(connect_transformed_move_op);
#[hdl] #[hdl]
@ -209,7 +217,7 @@ macro_rules! all_units {
RenamedMOp[MOpTrait::dest_reg_ty(self)][MOpTrait::src_reg_width(self)] RenamedMOp[MOpTrait::dest_reg_ty(self)][MOpTrait::src_reg_width(self)]
} }
fn mop_into(this: Expr<Self>) -> Expr<RenamedMOp<$DestReg, $SrcRegWidth>> { fn mop_into(this: Expr<Self>) -> Expr<RenamedMOp<$DestReg, $SrcRegWidth>> {
MOpInto::<RenamedMOp<$DestReg, $SrcRegWidth>>::mop_into_ty(Expr::ty(this)).$BeforeUnit(this) MOpInto::<RenamedMOp<$DestReg, $SrcRegWidth>>::mop_into_ty(this.ty()).$BeforeUnit(this)
} }
})* })*
@ -218,7 +226,7 @@ macro_rules! all_units {
RenamedMOp[MOpTrait::dest_reg_ty(self)][MOpTrait::src_reg_width(self)] RenamedMOp[MOpTrait::dest_reg_ty(self)][MOpTrait::src_reg_width(self)]
} }
fn mop_into(this: Expr<Self>) -> Expr<RenamedMOp<$DestReg, $SrcRegWidth>> { fn mop_into(this: Expr<Self>) -> Expr<RenamedMOp<$DestReg, $SrcRegWidth>> {
MOpInto::<RenamedMOp<$DestReg, $SrcRegWidth>>::mop_into_ty(Expr::ty(this)).$AfterUnit(this) MOpInto::<RenamedMOp<$DestReg, $SrcRegWidth>>::mop_into_ty(this.ty()).$AfterUnit(this)
} }
})* })*
}; };

View file

@ -266,16 +266,13 @@ pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
let unit_base = instance(unit_base( let unit_base = instance(unit_base(
config, config,
unit_index, unit_index,
Expr::ty(unit_to_reg_alloc).input.data.HdlSome.mop, unit_to_reg_alloc.ty().input.data.HdlSome.mop,
(), (),
)); ));
connect(unit_to_reg_alloc, unit_base.unit_to_reg_alloc); connect(unit_to_reg_alloc, unit_base.unit_to_reg_alloc);
connect(unit_base.cd, cd); connect(unit_base.cd, cd);
connect(unit_base.execute_start.ready, true); connect(unit_base.execute_start.ready, true);
connect( connect(unit_base.execute_end, unit_base.execute_end.ty().HdlNone());
unit_base.execute_end,
Expr::ty(unit_base.execute_end).HdlNone(),
);
#[hdl] #[hdl]
if let HdlSome(execute_start) = ReadyValid::firing_data(unit_base.execute_start) { if let HdlSome(execute_start) = ReadyValid::firing_data(unit_base.execute_start) {
#[hdl] #[hdl]

View file

@ -227,7 +227,7 @@ impl InFlightOpsSummary<DynSize> {
in_flight_ops: impl ToExpr<Type = ArrayType<HdlOption<InFlightOp<MOp>>, MaxInFlight>>, in_flight_ops: impl ToExpr<Type = ArrayType<HdlOption<InFlightOp<MOp>>, MaxInFlight>>,
) -> Expr<Self> { ) -> Expr<Self> {
let in_flight_ops = in_flight_ops.to_expr(); let in_flight_ops = in_flight_ops.to_expr();
let max_in_flight = Expr::ty(in_flight_ops).len(); let max_in_flight = in_flight_ops.ty().len();
let index_range = 0..max_in_flight; let index_range = 0..max_in_flight;
let index_ty = UInt::range(index_range.clone()); let index_ty = UInt::range(index_range.clone());
tree_reduce( tree_reduce(
@ -259,7 +259,7 @@ pub fn unit_base<
let execute_end: HdlOption<ExecuteEnd<DynSize, ExtraOut>> = let execute_end: HdlOption<ExecuteEnd<DynSize, ExtraOut>> =
m.input(HdlOption[ExecuteEnd[config.out_reg_num_width][extra_out_ty]]); m.input(HdlOption[ExecuteEnd[config.out_reg_num_width][extra_out_ty]]);
connect(execute_start.data, Expr::ty(execute_start).data.HdlNone()); connect(execute_start.data, execute_start.ty().data.HdlNone());
let max_in_flight = config.unit_max_in_flight(unit_index).get(); let max_in_flight = config.unit_max_in_flight(unit_index).get();
let in_flight_op_ty = InFlightOp[mop_ty]; let in_flight_op_ty = InFlightOp[mop_ty];
@ -270,7 +270,7 @@ pub fn unit_base<
let in_flight_ops_summary_value = InFlightOpsSummary::summarize(in_flight_ops); let in_flight_ops_summary_value = InFlightOpsSummary::summarize(in_flight_ops);
#[hdl] #[hdl]
let in_flight_ops_summary = wire(Expr::ty(in_flight_ops_summary_value)); let in_flight_ops_summary = wire(in_flight_ops_summary_value.ty());
connect(in_flight_ops_summary, in_flight_ops_summary_value); connect(in_flight_ops_summary, in_flight_ops_summary_value);
connect( connect(
@ -302,7 +302,7 @@ pub fn unit_base<
#[hdl] #[hdl]
let input_src_regs_valid = wire(); let input_src_regs_valid = wire();
connect(input_src_regs_valid, [true; COMMON_MOP_SRC_LEN]); connect(input_src_regs_valid, [true; COMMON_MOP_SRC_LEN]);
let mut unit_output_regs_valid: Vec<MemBuilder<Bool>> = (0..Expr::ty(unit_output_writes).len()) let mut unit_output_regs_valid: Vec<MemBuilder<Bool>> = (0..unit_output_writes.ty().len())
.map(|unit_index| { .map(|unit_index| {
let mut mem = memory_with_loc( let mut mem = memory_with_loc(
&format!("unit_{unit_index}_output_regs_valid"), &format!("unit_{unit_index}_output_regs_valid"),
@ -313,7 +313,7 @@ pub fn unit_base<
mem mem
}) })
.collect(); .collect();
for unit_index in 0..Expr::ty(unit_output_writes).len() { for unit_index in 0..unit_output_writes.ty().len() {
let mut unit_output_regs = memory_with_loc( let mut unit_output_regs = memory_with_loc(
&format!("unit_{unit_index}_output_regs"), &format!("unit_{unit_index}_output_regs"),
PRegValue, PRegValue,
@ -411,7 +411,7 @@ pub fn unit_base<
connect( connect(
unit_to_reg_alloc.output, unit_to_reg_alloc.output,
Expr::ty(unit_to_reg_alloc.output).HdlNone(), unit_to_reg_alloc.output.ty().HdlNone(),
); );
#[hdl] #[hdl]
@ -503,7 +503,7 @@ pub fn unit_base<
#[hdl] #[hdl]
if in_flight_ops_summary.ready_op_index.cmp_eq(HdlSome( if in_flight_ops_summary.ready_op_index.cmp_eq(HdlSome(
in_flight_op_index.cast_to(Expr::ty(in_flight_ops_summary).ready_op_index.HdlSome), in_flight_op_index.cast_to(in_flight_ops_summary.ty().ready_op_index.HdlSome),
)) { )) {
connect(read_src_regs, src_regs); connect(read_src_regs, src_regs);
} }
@ -512,7 +512,7 @@ pub fn unit_base<
in_flight_op_next_src_ready_flags[in_flight_op_index], in_flight_op_next_src_ready_flags[in_flight_op_index],
src_ready_flags, src_ready_flags,
); );
for unit_index in 0..Expr::ty(unit_output_writes).len() { for unit_index in 0..unit_output_writes.ty().len() {
#[hdl] #[hdl]
if let HdlSome(unit_output_write) = unit_output_writes[unit_index] { if let HdlSome(unit_output_write) = unit_output_writes[unit_index] {
#[hdl] #[hdl]

View file

@ -1,147 +1,10 @@
// SPDX-License-Identifier: LGPL-3.0-or-later // SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information // See Notices.txt for copyright information
use fayalite::{ use fayalite::{expr::ops::ExprIndex, int::UIntInRangeInclusiveType, prelude::*};
expr::ops::{ExprCastTo, ExprIndex, ExprPartialEq, ExprPartialOrd},
int::SizeType,
intern::{Intern, Interned},
prelude::*,
ty::{MatchVariantWithoutScope, StaticType, TypeProperties},
};
use std::{marker::PhantomData, ops::Index};
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[hdl]
pub struct Length<Max: Size> { pub type Length<Max: Size> = UIntInRangeInclusiveType<ConstUsize<0>, Max>;
ty: UInt,
_phantom: PhantomData<Max>,
}
impl<Max: Size> Length<Max> {
pub fn new(max: Max::SizeType) -> Self {
Self {
ty: UInt::range_inclusive(0..=Max::as_usize(max)),
_phantom: PhantomData,
}
}
pub fn ty(self) -> UInt {
self.ty
}
pub fn zero(self) -> Expr<Self> {
Self::from_uint_unchecked(self.ty.zero())
}
pub fn from_uint_unchecked(v: impl ToExpr<Type = UInt>) -> Expr<Self> {
Expr::from_canonical(Expr::canonical(v.to_expr()))
}
pub fn cast_from_uint_unchecked<SrcWidth: Size>(
self,
v: impl ToExpr<Type = UIntType<SrcWidth>>,
) -> Expr<Self> {
Self::from_uint_unchecked(v.to_expr().cast_to(self.ty))
}
pub fn as_uint(this: impl ToExpr<Type = Self>) -> Expr<UInt> {
let this = this.to_expr();
this.cast_to(Expr::ty(this).ty)
}
}
impl<Max: Size, DestWidth: Size> ExprCastTo<UIntType<DestWidth>> for Length<Max> {
fn cast_to(src: Expr<Self>, to_type: UIntType<DestWidth>) -> Expr<UIntType<DestWidth>> {
Expr::<UInt>::from_canonical(Expr::canonical(src)).cast_to(to_type)
}
}
#[allow(non_upper_case_globals)]
pub const Length: __LengthWithoutGenerics = __LengthWithoutGenerics {};
#[non_exhaustive]
pub struct __LengthWithoutGenerics {}
impl<M: SizeType> Index<M> for __LengthWithoutGenerics {
type Output = Length<M::Size>;
fn index(&self, max: M) -> &Self::Output {
Interned::into_inner(Length::new(max).intern_sized())
}
}
impl<Max: Size> Type for Length<Max> {
type BaseType = UInt;
type MaskType = Bool;
type MatchVariant = Expr<Self>;
type MatchActiveScope = ();
type MatchVariantAndInactiveScope = MatchVariantWithoutScope<Self::MatchVariant>;
type MatchVariantsIter = std::iter::Once<Self::MatchVariantAndInactiveScope>;
fn match_variants(
this: Expr<Self>,
source_location: SourceLocation,
) -> Self::MatchVariantsIter {
let _ = source_location;
std::iter::once(MatchVariantWithoutScope(this))
}
fn mask_type(&self) -> Self::MaskType {
Bool
}
fn canonical(&self) -> CanonicalType {
self.ty.canonical()
}
fn from_canonical(canonical_type: CanonicalType) -> Self {
let ty = <UInt>::from_canonical(canonical_type);
if let Some(known_max) = Max::KNOWN_VALUE {
assert_eq!(ty, UInt::range_inclusive(0..=known_max));
}
Self {
ty,
_phantom: PhantomData,
}
}
fn source_location() -> SourceLocation {
SourceLocation::caller()
}
}
impl<Max: KnownSize> StaticType for Length<Max> {
const TYPE: Self = Self {
ty: UInt {
width: Max::VALUE.next_power_of_two().ilog2() as usize,
},
_phantom: PhantomData,
};
const MASK_TYPE: Self::MaskType = Bool;
const TYPE_PROPERTIES: TypeProperties = {
let mut p = <UInt<1>>::TYPE_PROPERTIES;
p.bit_width = Self::TYPE.ty.width;
p
};
const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES;
}
impl<Max: Size> ExprPartialEq<Self> for Length<Max> {
fn cmp_eq(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
Self::as_uint(lhs).cmp_eq(Self::as_uint(rhs))
}
fn cmp_ne(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
Self::as_uint(lhs).cmp_ne(Self::as_uint(rhs))
}
}
impl<Max: Size> ExprPartialOrd<Self> for Length<Max> {
fn cmp_lt(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
Self::as_uint(lhs).cmp_lt(Self::as_uint(rhs))
}
fn cmp_le(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
Self::as_uint(lhs).cmp_le(Self::as_uint(rhs))
}
fn cmp_gt(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
Self::as_uint(lhs).cmp_gt(Self::as_uint(rhs))
}
fn cmp_ge(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
Self::as_uint(lhs).cmp_ge(Self::as_uint(rhs))
}
}
/// like [`std::vec::Vec`], except with a [`Expr`] for [`len()`][`Self::len()`] and a fixed capacity /// like [`std::vec::Vec`], except with a [`Expr`] for [`len()`][`Self::len()`] and a fixed capacity
#[hdl] #[hdl]
@ -156,7 +19,31 @@ impl<T: Type, N: Size> ArrayVec<T, N> {
#[hdl] #[hdl]
ArrayVec { ArrayVec {
elements: self.elements.uninit(), elements: self.elements.uninit(),
len: self.len.zero(), len: 0u8.cast_to(self.len),
}
}
#[hdl]
pub fn new_sim(self, uninit_element: impl ToSimValueWithType<T>) -> SimValue<Self> {
let uninit_element = uninit_element.into_sim_value_with_type(self.element());
#[hdl(sim)]
ArrayVec::<_, _> {
elements: SimValue::from_array_elements(
self.elements,
(0..self.elements.len()).map(|_| uninit_element.clone()),
),
len: 0u8.cast_to(self.len),
}
}
#[hdl]
pub fn new_full_sim(
self,
elements: impl ToSimValueWithType<ArrayType<T, N>>,
) -> SimValue<Self> {
let elements = elements.to_sim_value_with_type(self.elements);
#[hdl(sim)]
Self {
elements,
len: self.elements.len().to_sim_value_with_type(self.len),
} }
} }
pub fn element(self) -> T { pub fn element(self) -> T {
@ -176,8 +63,8 @@ impl<T: Type, N: Size> ArrayVec<T, N> {
let elements = elements.to_expr(); let elements = elements.to_expr();
let len = len.to_expr(); let len = len.to_expr();
assert_eq!( assert_eq!(
Length::new(N::from_usize(Expr::ty(elements).len())), Length[N::from_usize(elements.ty().len())],
Expr::ty(len), len.ty(),
"len type mismatch", "len type mismatch",
); );
#[hdl] #[hdl]
@ -189,9 +76,12 @@ impl<T: Type, N: Size> ArrayVec<T, N> {
pub fn len(this: impl ToExpr<Type = Self>) -> Expr<Length<N>> { pub fn len(this: impl ToExpr<Type = Self>) -> Expr<Length<N>> {
this.to_expr().len this.to_expr().len
} }
pub fn len_sim(this: &SimValue<Self>) -> &SimValue<Length<N>> {
&this.len
}
pub fn is_empty(this: impl ToExpr<Type = Self>) -> Expr<Bool> { pub fn is_empty(this: impl ToExpr<Type = Self>) -> Expr<Bool> {
let len = Self::len(this); let len = Self::len(this);
len.cmp_eq(Expr::ty(len).zero()) len.cmp_eq(0u8)
} }
pub fn capacity(self) -> usize { pub fn capacity(self) -> usize {
self.elements.len() self.elements.len()
@ -207,11 +97,77 @@ impl<T: Type, N: Size> ArrayVec<T, N> {
let this = this.to_expr(); let this = this.to_expr();
for (index, element) in this.elements.into_iter().enumerate() { for (index, element) in this.elements.into_iter().enumerate() {
#[hdl] #[hdl]
if index.cmp_lt(Length::as_uint(this.len)) { if index.cmp_lt(this.len) {
f(index, element); f(index, element);
} }
} }
} }
pub fn elements_sim_ref(this: &SimValue<Self>) -> &[SimValue<T>] {
&this.elements[..*this.len]
}
pub fn elements_sim_mut(this: &mut SimValue<Self>) -> &mut [SimValue<T>] {
let len = *this.len;
&mut this.elements[..len]
}
#[hdl]
pub async fn async_for_each_sim(
this: impl ToSimValue<Type = Self>,
mut f: impl AsyncFnMut(usize, SimValue<T>),
) {
#[hdl(sim)]
let ArrayVec::<_, _> { elements, len } = this.into_sim_value();
for (index, element) in elements.into_iter().enumerate() {
if index.cmp_lt(*len) {
f(index, element).await;
}
}
}
#[hdl]
pub async fn async_for_each_sim_ref<'a>(
this: &'a SimValue<Self>,
mut f: impl AsyncFnMut(usize, &'a SimValue<T>),
) {
#[hdl(sim)]
let ArrayVec::<_, _> { elements, len } = this;
for (index, element) in elements.iter().enumerate() {
if index.cmp_lt(**len) {
f(index, element).await;
}
}
}
#[hdl]
pub async fn async_for_each_sim_mut<'a>(
this: &'a mut SimValue<Self>,
mut f: impl AsyncFnMut(usize, &'a mut SimValue<T>),
) {
#[hdl(sim)]
let ArrayVec::<_, _> { elements, len } = this;
for (index, element) in elements.iter_mut().enumerate() {
if index.cmp_lt(**len) {
f(index, element).await;
}
}
}
#[hdl]
pub fn try_push_sim(
this: &mut SimValue<Self>,
value: impl ToSimValueWithType<T>,
) -> Result<(), SimValue<T>> {
let value = value.into_sim_value_with_type(this.ty().element());
let capacity = this.ty().capacity();
#[hdl(sim)]
let ArrayVec::<_, _> { elements, len } = this;
if **len < capacity {
elements[**len] = value;
**len += 1;
Ok(())
} else {
Err(value)
}
}
pub fn truncate_sim(this: &mut SimValue<Self>, len: usize) {
*this.len = len.min(*this.len);
}
pub fn mapped_ty<U: Type>(self, new_element_ty: U) -> ArrayVec<U, N> { pub fn mapped_ty<U: Type>(self, new_element_ty: U) -> ArrayVec<U, N> {
ArrayVec { ArrayVec {
elements: ArrayType[new_element_ty][N::from_usize(self.elements.len())], elements: ArrayType[new_element_ty][N::from_usize(self.elements.len())],
@ -226,7 +182,7 @@ impl<T: Type, N: Size> ArrayVec<T, N> {
) -> Expr<ArrayVec<U, N>> { ) -> Expr<ArrayVec<U, N>> {
let this = this.to_expr(); let this = this.to_expr();
#[hdl] #[hdl]
let mapped_array_vec = wire(Expr::ty(this).mapped_ty(new_element_ty)); let mapped_array_vec = wire(this.ty().mapped_ty(new_element_ty));
connect(mapped_array_vec.len, this.len); connect(mapped_array_vec.len, this.len);
Self::for_each(this, |index, element| { Self::for_each(this, |index, element| {
connect(mapped_array_vec[index], f(index, element)); connect(mapped_array_vec[index], f(index, element));
@ -234,15 +190,42 @@ impl<T: Type, N: Size> ArrayVec<T, N> {
mapped_array_vec mapped_array_vec
} }
#[hdl] #[hdl]
pub fn map_sim<U: Type>(
this: impl ToSimValue<Type = Self>,
uninit_element: impl ToSimValue<Type = U>,
mut f: impl FnMut(usize, SimValue<T>) -> SimValue<U>,
) -> SimValue<ArrayVec<U, N>> {
let this = this.into_sim_value();
let uninit_element = uninit_element.into_sim_value();
let ty = this.ty().mapped_ty(uninit_element.ty());
#[hdl(sim)]
let Self { elements, len } = this;
#[hdl(sim)]
ArrayVec::<_, _> {
elements: SimValue::from_array_elements(
ty.elements,
SimValue::into_value(elements)
.into_iter()
.enumerate()
.map(|(index, element)| {
if index < *len {
f(index, element)
} else {
uninit_element.clone()
}
}),
),
len,
}
}
#[hdl]
pub fn as_array_of_options(this: impl ToExpr<Type = Self>) -> Expr<ArrayType<HdlOption<T>, N>> { pub fn as_array_of_options(this: impl ToExpr<Type = Self>) -> Expr<ArrayType<HdlOption<T>, N>> {
let this = this.to_expr(); let this = this.to_expr();
#[hdl] #[hdl]
let array_vec_as_array_of_options = wire( let array_vec_as_array_of_options =
ArrayType[HdlOption[Expr::ty(this).element()]] wire(ArrayType[HdlOption[this.ty().element()]][N::from_usize(this.ty().capacity())]);
[N::from_usize(Expr::ty(this).capacity())],
);
for element in array_vec_as_array_of_options { for element in array_vec_as_array_of_options {
connect(element, Expr::ty(element).HdlNone()); connect(element, element.ty().HdlNone());
} }
Self::for_each(this, |index, element| { Self::for_each(this, |index, element| {
connect(array_vec_as_array_of_options[index], HdlSome(element)) connect(array_vec_as_array_of_options[index], HdlSome(element))
@ -263,3 +246,34 @@ where
<ArrayType<T, N> as ExprIndex<Idx>>::expr_index(&this.elements, index) <ArrayType<T, N> as ExprIndex<Idx>>::expr_index(&this.elements, index)
} }
} }
impl<T: Type> ArrayVec<T, ConstUsize<1>> {
#[hdl]
pub fn from_opt_sim(
opt: impl ToSimValue<Type = HdlOption<T>>,
uninit_element: impl ToSimValueWithType<T>,
) -> SimValue<Self> {
let opt = opt.into_sim_value();
let ty = ArrayVec[opt.ty().HdlSome][ConstUsize];
#[hdl(sim)]
match opt {
HdlSome(v) => ty.new_full_sim([v]),
HdlNone => ty.new_sim(uninit_element),
}
}
#[hdl]
pub fn into_opt_sim(this: impl ToSimValue<Type = Self>) -> SimValue<HdlOption<T>> {
let this = this.into_sim_value();
#[hdl(sim)]
let Self { elements, len } = this;
let [element] = SimValue::into_value(elements);
let ty = HdlOption[element.ty()];
if *len == 0 {
#[hdl(sim)]
ty.HdlNone()
} else {
#[hdl(sim)]
ty.HdlSome(element)
}
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,92 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use cpu::{
config::{CpuConfig, UnitConfig},
instruction::{AddSubMOp, LogicalMOp, MOp, MOpDestReg, MOpRegNum, OutputIntegerMode},
main_memory::main_memory,
reg_alloc::{FetchedDecodedMOp, reg_alloc},
register::{FlagsMode, PRegFlagsPowerISA},
unit::{GlobalState, UnitKind},
};
use fayalite::{
assert_export_firrtl,
firrtl::ExportOptions,
prelude::*,
sim::{Simulation, time::SimDuration, vcd::VcdWriterDecls},
util::RcWriter,
};
use std::num::NonZeroUsize;
//new test - much simpler
#[test]
fn test_main_memory() {
let mut config = CpuConfig::new(
vec![
UnitConfig::new(UnitKind::AluBranch),
UnitConfig::new(UnitKind::AluBranch),
],
NonZeroUsize::new(20).unwrap(),
);
// create a simulation from main_memory()
let mut sim = Simulation::new(main_memory(&config));
// add a .vcd writer that writes to main_memory.vcd -- this is simple for demo purposes,
// but for our actual code we should do better than just writing
// to main_memory.vcd in the repository's root
//WRONG: sim.add_trace_writer(std::fs::File::create("main_memory.vcd").unwrap());
let out_file = std::fs::File::create("main_memory.vcd").unwrap();
sim.add_trace_writer(VcdWriterDecls::new(out_file));
sim.write(sim.io().en, true);
sim.write(sim.io().cd.rst, false);
sim.write(sim.io().cd.clk, false);
sim.write(sim.io().write_en, false);
sim.write(sim.io().write_data, 0xFF00FF00FF00FF00u64);
// TODO convert to for loop
// you need to write an initial value to all inputs before you can start running the simulation
sim.write(sim.io().addr, 0x12345u64);
// now wait 1us because why not
sim.advance_time(SimDuration::from_micros(1)); //panic here at simulation
dbg!(sim.read(sim.io().read_data)); // dbg! macro just displays the value you pass to it
for n in 0u64..4u64 {
sim.write(sim.io().addr, n);
// now wait 1us because why not
sim.advance_time(SimDuration::from_micros(1));
}
sim.write(sim.io().write_en, true);
sim.write(sim.io().addr, 0u64);
sim.write(sim.io().write_data, 0xFFFFFFFFFFFFFFFFu64); //fill with ones
sim.write_clock(sim.io().cd.clk, true);
sim.advance_time(SimDuration::from_micros(1));
sim.write_clock(sim.io().cd.clk, false);
sim.advance_time(SimDuration::from_micros(1));
sim.write(sim.io().addr, 1u64);
sim.write_clock(sim.io().cd.clk, true);
sim.advance_time(SimDuration::from_micros(1));
sim.write_clock(sim.io().cd.clk, false);
sim.advance_time(SimDuration::from_micros(1));
sim.write(sim.io().addr, 2u64);
sim.write_clock(sim.io().cd.clk, true);
sim.advance_time(SimDuration::from_micros(1));
sim.write_clock(sim.io().cd.clk, false);
sim.advance_time(SimDuration::from_micros(1));
sim.write(sim.io().addr, 3u64);
sim.write_clock(sim.io().cd.clk, true);
sim.advance_time(SimDuration::from_micros(1));
sim.write_clock(sim.io().cd.clk, false);
sim.advance_time(SimDuration::from_micros(1));
sim.flush_traces().unwrap(); // make sure everything is written to the output file
}

1558
crates/cpu/tests/next_pc.rs Normal file

File diff suppressed because it is too large Load diff

View file

@ -9,8 +9,6 @@ use cpu::{
unit::{GlobalState, UnitKind}, unit::{GlobalState, UnitKind},
}; };
use fayalite::{ use fayalite::{
assert_export_firrtl,
firrtl::ExportOptions,
prelude::*, prelude::*,
sim::{Simulation, time::SimDuration, vcd::VcdWriterDecls}, sim::{Simulation, time::SimDuration, vcd::VcdWriterDecls},
util::RcWriter, util::RcWriter,
@ -61,7 +59,7 @@ fn test_reg_alloc() {
[HdlSome(()), HdlNone()], [HdlSome(()), HdlNone()],
}, },
[0u8; 2], [0u8; 2],
0x12345678u32.cast_to_static(), 0x12345678u32.cast_to_static::<SInt<_>>(),
OutputIntegerMode.DupLow32(), OutputIntegerMode.DupLow32(),
false, false,
false, false,
@ -83,7 +81,7 @@ fn test_reg_alloc() {
[HdlSome(()), HdlNone()], [HdlSome(()), HdlNone()],
}, },
[1u8, 0, 0], [1u8, 0, 0],
1.cast_to_static(), 1.cast_to_static::<SInt<_>>(),
OutputIntegerMode.Full64(), OutputIntegerMode.Full64(),
false, false,
false, false,
@ -101,7 +99,7 @@ fn test_reg_alloc() {
flag_regs: [HdlNone(), HdlSome(())], flag_regs: [HdlNone(), HdlSome(())],
}, },
[2u8, 4u8], [2u8, 4u8],
0.cast_to_static(), 0.cast_to_static::<SInt<_>>(),
OutputIntegerMode.Full64(), OutputIntegerMode.Full64(),
0b0110_hdl_u4, 0b0110_hdl_u4,
), ),

View file

@ -31,6 +31,7 @@ function check_file()
POUND_HEADER=('^"# SPDX-License-Identifier: LGPL-3.0-or-later"$' '^"# See Notices.txt for copyright information"$') POUND_HEADER=('^"# SPDX-License-Identifier: LGPL-3.0-or-later"$' '^"# See Notices.txt for copyright information"$')
SLASH_HEADER=('^"// SPDX-License-Identifier: LGPL-3.0-or-later"$' '^"// See Notices.txt for copyright information"$') SLASH_HEADER=('^"// SPDX-License-Identifier: LGPL-3.0-or-later"$' '^"// See Notices.txt for copyright information"$')
MD_HEADER=('^"<!--"$' '^"SPDX-License-Identifier: LGPL-3.0-or-later"$' '^"See Notices.txt for copyright information"$') MD_HEADER=('^"<!--"$' '^"SPDX-License-Identifier: LGPL-3.0-or-later"$' '^"See Notices.txt for copyright information"$')
MERMAID_HEADER=('^"%% SPDX-License-Identifier: LGPL-3.0-or-later"$' '^"%% See Notices.txt for copyright information"$')
function main() function main()
{ {
@ -51,6 +52,9 @@ function main()
/.forgejo/workflows/*.yml|*/.gitignore|*.toml) /.forgejo/workflows/*.yml|*/.gitignore|*.toml)
check_file "$file" "${POUND_HEADER[@]}" check_file "$file" "${POUND_HEADER[@]}"
;; ;;
*.mermaid)
check_file "$file" "${MERMAID_HEADER[@]}"
;;
*.md) *.md)
check_file "$file" "${MD_HEADER[@]}" check_file "$file" "${MD_HEADER[@]}"
;; ;;